2022-07-15 15:37:19 +00:00
# ifdef WIN32
// Why?
# define _WIN32_WINNT 0x0502
// The standard Windows includes.
# define WIN32_LEAN_AND_MEAN
# define NOMINMAX
# include <Windows.h>
# include <wchar.h>
# ifdef SLIC3R_GUI
extern " C "
{
// Let the NVIDIA and AMD know we want to use their graphics card
// on a dual graphics card system.
__declspec ( dllexport ) DWORD NvOptimusEnablement = 0x00000001 ;
__declspec ( dllexport ) int AmdPowerXpressRequestHighPerformance = 1 ;
}
# endif /* SLIC3R_GUI */
# endif /* WIN32 */
# include <cstdio>
# include <string>
# include <cstring>
# include <iostream>
# include <math.h>
2022-11-05 02:21:04 +00:00
# if defined(__linux__) || defined(__LINUX__)
# include <condition_variable>
# include <mutex>
# include <boost/thread.hpp>
# endif
2022-07-15 15:37:19 +00:00
# include <boost/algorithm/string/predicate.hpp>
# include <boost/filesystem.hpp>
# include <boost/nowide/args.hpp>
# include <boost/nowide/cenv.hpp>
# include <boost/nowide/iostream.hpp>
# include <boost/nowide/integration/filesystem.hpp>
# include <boost/dll/runtime_symbol_info.hpp>
# include <boost/log/trivial.hpp>
# include "unix/fhs.hpp" // Generated by CMake from ../platform/unix/fhs.hpp.in
# include "libslic3r/libslic3r.h"
# include "libslic3r/Config.hpp"
# include "libslic3r/Geometry.hpp"
# include "libslic3r/GCode/PostProcessor.hpp"
# include "libslic3r/Model.hpp"
# include "libslic3r/ModelArrange.hpp"
# include "libslic3r/Platform.hpp"
# include "libslic3r/Print.hpp"
# include "libslic3r/SLAPrint.hpp"
# include "libslic3r/TriangleMesh.hpp"
# include "libslic3r/Format/AMF.hpp"
# include "libslic3r/Format/3mf.hpp"
# include "libslic3r/Format/STL.hpp"
# include "libslic3r/Format/OBJ.hpp"
# include "libslic3r/Format/SL1.hpp"
# include "libslic3r/Utils.hpp"
# include "libslic3r/Thread.hpp"
# include "libslic3r/BlacklistedLibraryCheck.hpp"
# include "libslic3r/Orient.hpp"
# include "BambuStudio.hpp"
//BBS: add exception handler for win32
# include <wx/stdpaths.h>
# ifdef WIN32
# include "BaseException.h"
# endif
# include "slic3r/GUI/PartPlate.hpp"
# include "slic3r/GUI/BitmapCache.hpp"
# include "slic3r/GUI/OpenGLManager.hpp"
# include "slic3r/GUI/GLCanvas3D.hpp"
# include "slic3r/GUI/Camera.hpp"
# include <GLFW/glfw3.h>
# ifdef SLIC3R_GUI
# include "slic3r/GUI/GUI_Init.hpp"
# endif /* SLIC3R_GUI */
using namespace Slic3r ;
2022-11-02 12:42:37 +00:00
/*typedef struct _error_message{
int code ;
std : : string message ;
} error_message ; */
# define CLI_SUCCESS 0
# define CLI_ENVIRONMENT_ERROR -1
# define CLI_INVALID_PARAMS -2
# define CLI_FILE_NOTFOUND -3
# define CLI_FILELIST_INVALID_ORDER -4
# define CLI_CONFIG_FILE_ERROR -5
# define CLI_DATA_FILE_ERROR -6
# define CLI_INVALID_PRINTER_TECH -7
# define CLI_UNSUPPORTED_OPERATION -8
# define CLI_COPY_OBJECTS_ERROR -9
# define CLI_SCALE_TO_FIT_ERROR -10
# define CLI_EXPORT_STL_ERROR -11
# define CLI_EXPORT_OBJ_ERROR -12
# define CLI_EXPORT_3MF_ERROR -13
# define CLI_NO_SUITABLE_OBJECTS -50
# define CLI_VALIDATE_ERROR -51
2022-11-05 02:21:04 +00:00
# define CLI_OBJECTS_PARTLY_INSIDE -52
2022-11-02 12:42:37 +00:00
# define CLI_SLICING_ERROR -100
std : : map < int , std : : string > cli_errors = {
{ CLI_SUCCESS , " Success " } ,
{ CLI_ENVIRONMENT_ERROR , " Environment setup failed " } ,
{ CLI_INVALID_PARAMS , " Input param invalid " } ,
{ CLI_FILE_NOTFOUND , " Input file not found " } ,
{ CLI_FILELIST_INVALID_ORDER , " File list order invalid(please make sure 3mf in the first place) " } ,
{ CLI_CONFIG_FILE_ERROR , " Invalid config file, could not be parsed " } ,
{ CLI_DATA_FILE_ERROR , " Invalid model file, could not be loaded " } ,
{ CLI_INVALID_PRINTER_TECH , " Invalid printer technoledge " } ,
{ CLI_UNSUPPORTED_OPERATION , " Unsupported operation " } ,
{ CLI_COPY_OBJECTS_ERROR , " Copy objects error " } ,
{ CLI_SCALE_TO_FIT_ERROR , " Scale to fit error " } ,
{ CLI_EXPORT_STL_ERROR , " Export stl error " } ,
{ CLI_EXPORT_OBJ_ERROR , " Export obj error " } ,
{ CLI_EXPORT_3MF_ERROR , " Export 3mf error " } ,
{ CLI_NO_SUITABLE_OBJECTS , " Found no objects in print volume to slice " } ,
{ CLI_VALIDATE_ERROR , " Validate print error " } ,
{ CLI_SLICING_ERROR , " Slice error " }
} ;
2022-11-05 02:21:04 +00:00
# if defined(__linux__) || defined(__LINUX__)
# define PIPE_BUFFER_SIZE 64
typedef struct _cli_callback_mgr {
int m_plate_count { 0 } ;
int m_plate_index ;
int m_progress { 0 } ;
std : : string m_message ;
int m_warning_step ;
bool m_exit { false } ;
bool m_data_ready { false } ;
bool m_started { false } ;
boost : : thread m_thread ;
// Mutex and condition variable to synchronize m_thread with the UI thread.
std : : mutex m_mutex ;
std : : condition_variable m_condition ;
int m_pipe_fd { - 1 } ;
bool is_started ( )
{
bool result ;
std : : unique_lock < std : : mutex > lck ( m_mutex ) ;
result = m_started ;
lck . unlock ( ) ;
return result ;
}
void set_plate_info ( int index , int count )
{
std : : unique_lock < std : : mutex > lck ( m_mutex ) ;
m_plate_count = count ;
m_plate_index = index ;
lck . unlock ( ) ;
return ;
}
void notify ( )
{
if ( m_pipe_fd < 0 )
return ;
std : : string notify_message ;
notify_message = " Plate " + std : : to_string ( m_plate_index ) + " / " + std : : to_string ( m_plate_count ) + " : Percent " + std : : to_string ( m_progress ) + " : " + m_message ;
char pipe_message [ PIPE_BUFFER_SIZE ] = { 0 } ;
strncpy ( pipe_message , notify_message . c_str ( ) , PIPE_BUFFER_SIZE ) ;
int ret = write ( m_pipe_fd , pipe_message , PIPE_BUFFER_SIZE ) ;
BOOST_LOG_TRIVIAL ( debug ) < < __FUNCTION__ < < " : write returns " < < ret ;
return ;
}
void thread_proc ( )
{
std : : unique_lock < std : : mutex > lck ( m_mutex ) ;
m_started = true ;
m_data_ready = false ;
lck . unlock ( ) ;
m_condition . notify_one ( ) ;
BOOST_LOG_TRIVIAL ( info ) < < " cli_callback_mgr_t::thread_proc started. " ;
while ( 1 ) {
lck . lock ( ) ;
m_condition . wait ( lck , [ this ] ( ) { return m_data_ready | | m_exit ; } ) ;
BOOST_LOG_TRIVIAL ( debug ) < < __FUNCTION__ < < " : wakup. " ;
if ( m_exit ) {
BOOST_LOG_TRIVIAL ( info ) < < " cli_callback_mgr_t::thread_proc will exit. " ;
break ;
}
notify ( ) ;
m_data_ready = false ;
lck . unlock ( ) ;
m_condition . notify_one ( ) ;
}
lck . unlock ( ) ;
BOOST_LOG_TRIVIAL ( info ) < < " cli_callback_mgr_t::thread_proc exit. " ;
}
void update ( int percent , std : : string message , int warning_step )
{
BOOST_LOG_TRIVIAL ( debug ) < < __FUNCTION__ < < " : percent= " < < percent < < " , warning_step = " < < m_warning_step < < " , message= " < < message ;
std : : unique_lock < std : : mutex > lck ( m_mutex ) ;
if ( ! m_started ) {
lck . unlock ( ) ;
return ;
}
if ( m_progress > = percent ) {
//already update before
lck . unlock ( ) ;
return ;
}
m_message = message ;
m_progress = percent ;
m_warning_step = warning_step ;
m_data_ready = true ;
lck . unlock ( ) ;
m_condition . notify_one ( ) ;
return ;
}
bool start ( std : : string pipe_name )
{
BOOST_LOG_TRIVIAL ( info ) < < " cli_callback_mgr_t::start enter. " ;
m_pipe_fd = open ( pipe_name . c_str ( ) , O_WRONLY | O_NONBLOCK ) ;
if ( m_pipe_fd < 0 ) {
BOOST_LOG_TRIVIAL ( error ) < < " could not create pipe for " < < pipe_name ;
return false ;
}
std : : unique_lock < std : : mutex > lck ( m_mutex ) ;
m_thread = create_thread ( [ this ] {
this - > thread_proc ( ) ;
} ) ;
lck . unlock ( ) ;
BOOST_LOG_TRIVIAL ( info ) < < " cli_callback_mgr_t::start successfully. " ;
return true ;
}
void stop ( )
{
BOOST_LOG_TRIVIAL ( info ) < < " cli_callback_mgr_t::stop enter. " ;
std : : unique_lock < std : : mutex > lck ( m_mutex ) ;
if ( m_pipe_fd > 0 ) {
close ( m_pipe_fd ) ;
m_pipe_fd = - 1 ;
}
if ( ! m_started ) {
lck . unlock ( ) ;
return ;
}
m_exit = true ;
lck . unlock ( ) ;
m_condition . notify_one ( ) ;
// Wait until the worker thread exits.
m_thread . join ( ) ;
BOOST_LOG_TRIVIAL ( info ) < < " cli_callback_mgr_t::stop successfully. " ;
}
} cli_callback_mgr_t ;
cli_callback_mgr_t g_cli_callback_mgr ;
void cli_status_callback ( const PrintBase : : SlicingStatus & slicing_status )
{
g_cli_callback_mgr . update ( slicing_status . percent , slicing_status . text , slicing_status . warning_step ) ;
return ;
}
# endif
2022-11-02 12:42:37 +00:00
2022-07-15 15:37:19 +00:00
static PrinterTechnology get_printer_technology ( const DynamicConfig & config )
{
const ConfigOptionEnum < PrinterTechnology > * opt = config . option < ConfigOptionEnum < PrinterTechnology > > ( " printer_technology " ) ;
return ( opt = = nullptr ) ? ptUnknown : opt - > value ;
}
//BBS: add flush and exit
2022-11-05 02:21:04 +00:00
# if defined(__linux__) || defined(__LINUX__)
# define flush_and_exit(ret) { boost::nowide::cout << __FUNCTION__ << " found error, return "<<ret<<", exit..." << std::endl;\
g_cli_callback_mgr . stop ( ) ; \
boost : : nowide : : cout . flush ( ) ; \
boost : : nowide : : cerr . flush ( ) ; \
return ( ret ) ; }
# else
2022-07-15 15:37:19 +00:00
# define flush_and_exit(ret) { boost::nowide::cout << __FUNCTION__ << " found error, exit" << std::endl;\
boost : : nowide : : cout . flush ( ) ; \
boost : : nowide : : cerr . flush ( ) ; \
2022-11-02 12:42:37 +00:00
return ( ret ) ; }
2022-11-05 02:21:04 +00:00
# endif
2022-07-15 15:37:19 +00:00
static void glfw_callback ( int error_code , const char * description )
{
BOOST_LOG_TRIVIAL ( error ) < < " error_code " < < error_code < < " , description: " < < description < < std : : endl ;
}
int CLI : : run ( int argc , char * * argv )
{
// Mark the main thread for the debugger and for runtime checks.
2022-09-14 08:12:12 +00:00
set_current_thread_name ( " bambustu_main " ) ;
2022-07-15 15:37:19 +00:00
# ifdef __WXGTK__
// On Linux, wxGTK has no support for Wayland, and the app crashes on
// startup if gtk3 is used. This env var has to be set explicitly to
// instruct the window manager to fall back to X server mode.
: : setenv ( " GDK_BACKEND " , " x11 " , /* replace */ true ) ;
# endif
// Switch boost::filesystem to utf8.
try {
boost : : nowide : : nowide_filesystem ( ) ;
} catch ( const std : : runtime_error & ex ) {
std : : string caption = std : : string ( SLIC3R_APP_FULL_NAME ) + " Error " ;
std : : string text = std : : string ( " boost::nowide::nowide_filesystem Failed! \n " ) + (
SLIC3R_APP_FULL_NAME " will now terminate. \n \n " ) + ex . what ( ) ;
# if defined(_WIN32) && defined(SLIC3R_GUI)
if ( m_actions . empty ( ) )
// Empty actions means Slicer is executed in the GUI mode. Show a GUI message.
MessageBoxA ( NULL , text . c_str ( ) , caption . c_str ( ) , MB_OK | MB_ICONERROR ) ;
# endif
boost : : nowide : : cerr < < text . c_str ( ) < < std : : endl ;
2022-11-02 12:42:37 +00:00
return CLI_ENVIRONMENT_ERROR ;
2022-07-15 15:37:19 +00:00
}
BOOST_LOG_TRIVIAL ( info ) < < " Current BambuStudio Version " < < SLIC3R_VERSION < < std : : endl ;
/*BOOST_LOG_TRIVIAL(info) << "begin to setup params, argc="<< argc << std::endl;
for ( int index = 0 ; index < argc ; index + + )
BOOST_LOG_TRIVIAL ( info ) < < " index= " < < index < < " , arg is " < < argv [ index ] < < std : : endl ;
int debug_argc = 9 ;
char * debug_argv [ ] = {
2022-10-31 14:36:28 +00:00
" E: \ work \ projects \b ambu_release \b amboo_slicer \b uild_debug \ src \ Debug \b ambu-studio.exe " ,
2022-07-15 15:37:19 +00:00
" --slice " ,
" 0 " ,
" --export-3mf=output.3mf " ,
" test_thumbnail.3mf " ,
" --load-settings " ,
" machine.json;process.json " ,
" --load-filaments " ,
" filament.json;filament.json;filament.json;filament.json "
} ;
if ( ! this - > setup ( debug_argc , debug_argv ) ) */
if ( ! this - > setup ( argc , argv ) )
{
boost : : nowide : : cerr < < " setup params error " < < std : : endl ;
2022-11-02 12:42:37 +00:00
return CLI_INVALID_PARAMS ;
2022-07-15 15:37:19 +00:00
}
BOOST_LOG_TRIVIAL ( info ) < < " finished setup params, argc= " < < argc < < std : : endl ;
2022-08-05 06:38:19 +00:00
std : : string temp_path = wxFileName : : GetTempDir ( ) . utf8_str ( ) . data ( ) ;
2022-07-15 15:37:19 +00:00
set_temporary_dir ( temp_path ) ;
m_extra_config . apply ( m_config , true ) ;
m_extra_config . normalize_fdm ( ) ;
PrinterTechnology printer_technology = get_printer_technology ( m_config ) ;
bool start_gui = m_actions . empty ( ) ;
//BBS: remove GCodeViewer as seperate APP logic
/*bool start_as_gcodeviewer =
# ifdef _WIN32
false ;
# else
// On Unix systems, the prusa-slicer binary may be symlinked to give the application a different meaning.
boost : : algorithm : : iends_with ( boost : : filesystem : : path ( argv [ 0 ] ) . filename ( ) . string ( ) , " gcodeviewer " ) ;
# endif // _WIN32*/
const std : : vector < std : : string > & load_configs = m_config . option < ConfigOptionStrings > ( " load_settings " , true ) - > values ;
//BBS: always use ForwardCompatibilitySubstitutionRule::Enable
//const ForwardCompatibilitySubstitutionRule config_substitution_rule = m_config.option<ConfigOptionEnum<ForwardCompatibilitySubstitutionRule>>("config_compatibility", true)->value;
const ForwardCompatibilitySubstitutionRule config_substitution_rule = ForwardCompatibilitySubstitutionRule : : Enable ;
const std : : vector < std : : string > & load_filaments = m_config . option < ConfigOptionStrings > ( " load_filaments " , true ) - > values ;
if ( start_gui ) {
BOOST_LOG_TRIVIAL ( info ) < < " no action, start gui directly " < < std : : endl ;
2022-09-21 11:44:18 +00:00
: : Label : : initSysFont ( ) ;
2022-07-15 15:37:19 +00:00
# ifdef SLIC3R_GUI
/*#if !defined(_WIN32) && !defined(__APPLE__)
// likely some linux / unix system
const char * display = boost : : nowide : : getenv ( " DISPLAY " ) ;
// const char *wayland_display = boost::nowide::getenv("WAYLAND_DISPLAY");
//if (! ((display && *display) || (wayland_display && *wayland_display))) {
if ( ! ( display & & * display ) ) {
// DISPLAY not set.
boost : : nowide : : cerr < < " DISPLAY not set, GUI mode not available. " < < std : : endl < < std : : endl ;
this - > print_help ( false ) ;
// Indicate an error.
return 1 ;
}
# endif // some linux / unix system*/
Slic3r : : GUI : : GUI_InitParams params ;
params . argc = argc ;
params . argv = argv ;
params . load_configs = load_configs ;
params . extra_config = std : : move ( m_extra_config ) ;
2022-08-02 04:12:45 +00:00
std : : vector < std : : string > gcode_files ;
std : : vector < std : : string > non_gcode_files ;
for ( const auto & filename : m_input_files ) {
if ( is_gcode_file ( filename ) )
gcode_files . emplace_back ( filename ) ;
else {
non_gcode_files . emplace_back ( filename ) ;
}
}
if ( non_gcode_files . empty ( ) & & ! gcode_files . empty ( ) ) {
params . input_gcode = true ;
params . input_files = std : : move ( gcode_files ) ;
BOOST_LOG_TRIVIAL ( info ) < < __FUNCTION__ < < " , gcode only, gcode_files size = " < < params . input_files . size ( ) ;
}
else {
params . input_files = std : : move ( m_input_files ) ;
BOOST_LOG_TRIVIAL ( info ) < < __FUNCTION__ < < " , normal mode, input_files size = " < < params . input_files . size ( ) ;
}
2022-07-15 15:37:19 +00:00
//BBS: remove GCodeViewer as seperate APP logic
//params.start_as_gcodeviewer = start_as_gcodeviewer;
BOOST_LOG_TRIVIAL ( info ) < < " begin to launch BambuStudio GUI soon " ;
return Slic3r : : GUI : : GUI_Run ( params ) ;
# else // SLIC3R_GUI
// No GUI support. Just print out a help.
this - > print_help ( false ) ;
// If started without a parameter, consider it to be OK, otherwise report an error code (no action etc).
return ( argc = = 0 ) ? 0 : 1 ;
# endif // SLIC3R_GUI
}
BOOST_LOG_TRIVIAL ( info ) < < " before load settings, file count= " < < load_configs . size ( ) < < std : : endl ;
// load config files supplied via --load
for ( auto const & file : load_configs ) {
if ( ! boost : : filesystem : : exists ( file ) ) {
boost : : nowide : : cerr < < " can not find setting file: " < < file < < std : : endl ;
2022-11-02 12:42:37 +00:00
flush_and_exit ( CLI_FILE_NOTFOUND ) ;
2022-07-15 15:37:19 +00:00
}
DynamicPrintConfig config ;
ConfigSubstitutions config_substitutions ;
try {
BOOST_LOG_TRIVIAL ( info ) < < " load setting file " < < file < < " , with rule " < < config_substitution_rule < < std : : endl ;
std : : map < std : : string , std : : string > key_values ;
std : : string reason ;
config_substitutions = config . load_from_json ( file , config_substitution_rule , key_values , reason ) ;
if ( ! reason . empty ( ) ) {
BOOST_LOG_TRIVIAL ( error ) < < " Can not load config from file " < < file < < " \n " ;
2022-11-02 12:42:37 +00:00
flush_and_exit ( CLI_CONFIG_FILE_ERROR ) ;
2022-07-15 15:37:19 +00:00
}
//BOOST_LOG_TRIVIAL(info) << "got printable_area "<< config.option("printable_area")->serialize() << std::endl;
} catch ( std : : exception & ex ) {
boost : : nowide : : cerr < < " Loading setting file \" " < < file < < " \" failed: " < < ex . what ( ) < < std : : endl ;
2022-11-02 12:42:37 +00:00
flush_and_exit ( CLI_CONFIG_FILE_ERROR ) ;
2022-07-15 15:37:19 +00:00
}
if ( ! config_substitutions . empty ( ) ) {
BOOST_LOG_TRIVIAL ( info ) < < " Found legacy configuration values, substituted when loading " < < file < < " : \n " ;
for ( const ConfigSubstitution & subst : config_substitutions )
BOOST_LOG_TRIVIAL ( info ) < < " \t key = \" " < < subst . opt_def - > opt_key < < " \" \t old_value = \" " < < subst . old_value < < " \t new_value = \" " < < subst . new_value - > serialize ( ) < < " \" \n " ;
}
else {
BOOST_LOG_TRIVIAL ( info ) < < " no substitutions performed from file " < < file < < " \n " ;
}
config . normalize_fdm ( ) ;
PrinterTechnology other_printer_technology = get_printer_technology ( config ) ;
if ( printer_technology = = ptUnknown ) {
printer_technology = other_printer_technology ;
}
if ( ( printer_technology ! = other_printer_technology ) & & ( other_printer_technology ! = ptUnknown ) ) {
boost : : nowide : : cerr < < " invalid printer_technology " < < printer_technology < < " , from config " < < file < < std : : endl ;
2022-11-02 12:42:37 +00:00
flush_and_exit ( CLI_INVALID_PRINTER_TECH ) ;
2022-07-15 15:37:19 +00:00
}
m_print_config . apply ( config ) ;
}
//load filaments files
int filament_count = load_filaments . size ( ) ;
for ( int index = 0 ; index < filament_count ; index + + ) {
const std : : string & file = load_filaments [ index ] ;
if ( ! boost : : filesystem : : exists ( file ) ) {
boost : : nowide : : cerr < < " can not find filament file: " < < file < < std : : endl ;
2022-11-02 12:42:37 +00:00
flush_and_exit ( CLI_FILE_NOTFOUND ) ;
2022-07-15 15:37:19 +00:00
}
DynamicPrintConfig config ;
ConfigSubstitutions config_substitutions ;
std : : map < std : : string , std : : string > key_values ;
try {
BOOST_LOG_TRIVIAL ( info ) < < " load filament file " < < file < < " , with rule " < < config_substitution_rule < < std : : endl ;
std : : string reason ;
config_substitutions = config . load_from_json ( file , config_substitution_rule , key_values , reason ) ;
if ( ! reason . empty ( ) ) {
BOOST_LOG_TRIVIAL ( error ) < < " Can not load filament config from file " < < file < < " \n " ;
2022-11-02 12:42:37 +00:00
flush_and_exit ( CLI_CONFIG_FILE_ERROR ) ;
2022-07-15 15:37:19 +00:00
}
//BOOST_LOG_TRIVIAL(info) << "got printable_area "<< config.option("printable_area")->serialize() << std::endl;
} catch ( std : : exception & ex ) {
boost : : nowide : : cerr < < " Loading filament file \" " < < file < < " \" failed: " < < ex . what ( ) < < std : : endl ;
2022-11-02 12:42:37 +00:00
flush_and_exit ( CLI_CONFIG_FILE_ERROR ) ;
2022-07-15 15:37:19 +00:00
}
if ( ! config_substitutions . empty ( ) ) {
BOOST_LOG_TRIVIAL ( info ) < < " Found legacy configuration values, substituted when loading " < < file < < " : \n " ;
for ( const ConfigSubstitution & subst : config_substitutions )
BOOST_LOG_TRIVIAL ( info ) < < " \t key = \" " < < subst . opt_def - > opt_key < < " \" \t old_value = \" " < < subst . old_value < < " \t new_value = \" " < < subst . new_value - > serialize ( ) < < " \" \n " ;
}
else {
BOOST_LOG_TRIVIAL ( info ) < < " no substitutions performed from file " < < file < < " \n " ;
}
config . normalize_fdm ( ) ;
PrinterTechnology other_printer_technology = get_printer_technology ( config ) ;
if ( printer_technology = = ptUnknown ) {
printer_technology = other_printer_technology ;
}
if ( ( printer_technology ! = other_printer_technology ) & & ( other_printer_technology ! = ptUnknown ) ) {
boost : : nowide : : cerr < < " invalid printer_technology " < < printer_technology < < " , from filament file " < < file < < std : : endl ;
2022-11-02 12:42:37 +00:00
flush_and_exit ( CLI_INVALID_PRINTER_TECH ) ;
2022-07-15 15:37:19 +00:00
}
ConfigOptionStrings * opt_filament_settings = static_cast < ConfigOptionStrings * > ( m_print_config . option ( " filament_settings_id " , true ) ) ;
ConfigOptionStrings * opt_filament_settings_src = static_cast < ConfigOptionStrings * > ( config . option ( " filament_settings_id " , false ) ) ;
if ( opt_filament_settings_src )
opt_filament_settings - > set_at ( opt_filament_settings_src , index , 0 ) ;
else {
std : : string name = file ;
name . erase ( name . size ( ) - 5 ) ;
ConfigOptionString option ( name ) ;
opt_filament_settings - > set_at ( & option , index , 0 ) ;
}
std : : string filament_id ;
ConfigOptionStrings * opt_filament_ids = static_cast < ConfigOptionStrings * > ( m_print_config . option ( " filament_ids " , true ) ) ;
auto filament_id_iter = key_values . find ( BBL_JSON_KEY_FILAMENT_ID ) ;
if ( filament_id_iter ! = key_values . end ( ) )
filament_id = filament_id_iter - > second ;
ConfigOptionString * filament_id_setting = new ConfigOptionString ( filament_id ) ;
if ( opt_filament_ids - > size ( ) < filament_count )
opt_filament_ids - > resize ( filament_count , filament_id_setting ) ;
opt_filament_ids - > set_at ( filament_id_setting , index , 0 ) ;
//parse the filament value to index th
//loop through options and apply them
for ( const t_config_option_key & opt_key : config . keys ( ) ) {
// Create a new option with default value for the key.
// If the key is not in the parameter definition, or this ConfigBase is a static type and it does not support the parameter,
// an exception is thrown if not ignore_nonexistent.
const ConfigOption * source_opt = config . option ( opt_key ) ;
if ( source_opt = = nullptr ) {
// The key was not found in the source config, therefore it will not be initialized!
boost : : nowide : : cerr < < " can not found option " < < opt_key < < " from filament file " < < file < < std : : endl ;
2022-11-02 12:42:37 +00:00
flush_and_exit ( CLI_CONFIG_FILE_ERROR ) ;
2022-07-15 15:37:19 +00:00
}
if ( opt_key = = " compatible_prints " | | opt_key = = " compatible_printers " )
continue ;
else if ( source_opt - > is_scalar ( ) ) {
if ( opt_key = = " compatible_printers_condition " ) {
ConfigOption * opt = m_print_config . option ( " compatible_machine_expression_group " , true ) ;
ConfigOptionStrings * opt_vec_dst = static_cast < ConfigOptionStrings * > ( opt ) ;
if ( opt_vec_dst - > size ( ) = = 0 )
opt_vec_dst - > resize ( 1 , new ConfigOptionString ( ) ) ;
opt_vec_dst - > set_at ( source_opt , index + 1 , 0 ) ;
}
else if ( opt_key = = " compatible_prints_condition " ) {
ConfigOption * opt = m_print_config . option ( " compatible_process_expression_group " , true ) ;
ConfigOptionStrings * opt_vec_dst = static_cast < ConfigOptionStrings * > ( opt ) ;
if ( opt_vec_dst - > size ( ) = = 0 )
opt_vec_dst - > resize ( 1 , new ConfigOptionString ( ) ) ;
opt_vec_dst - > set_at ( source_opt , index , 0 ) ;
}
else {
//skip the scalar values
BOOST_LOG_TRIVIAL ( info ) < < " skip scalar option " < < opt_key < < " from filament file " < < file < < std : : endl ;
continue ;
}
}
else
{
ConfigOption * opt = m_print_config . option ( opt_key , true ) ;
if ( opt = = nullptr ) {
// opt_key does not exist in this ConfigBase and it cannot be created, because it is not defined by this->def().
// This is only possible if other is of DynamicConfig type.
boost : : nowide : : cerr < < " can not create option " < < opt_key < < " to config, from filament file " < < file < < std : : endl ;
2022-11-02 12:42:37 +00:00
flush_and_exit ( CLI_CONFIG_FILE_ERROR ) ;
2022-07-15 15:37:19 +00:00
}
ConfigOptionVectorBase * opt_vec_dst = static_cast < ConfigOptionVectorBase * > ( opt ) ;
const ConfigOptionVectorBase * opt_vec_src = static_cast < const ConfigOptionVectorBase * > ( source_opt ) ;
if ( opt_key = = " bed_temperature " | | opt_key = = " bed_temperature_initial_layer " ) {
const ConfigOptionInts * bed_temp_opt = dynamic_cast < const ConfigOptionInts * > ( opt_vec_src ) ;
for ( size_t type = 0 ; type < ( size_t ) BedType : : btCount ; type + + ) {
if ( type < bed_temp_opt - > size ( ) )
opt_vec_dst - > set_at ( bed_temp_opt , index * BedType : : btCount + type , type ) ;
else
// BBS FIXME: set bed temperature to 0 for new bed types
opt_vec_dst - > set_at ( new ConfigOptionInt ( 0 ) , index * BedType : : btCount + type , type ) ;
}
}
else if ( opt_key = = " compatible_prints " | | opt_key = = " compatible_printers " )
continue ;
else {
opt_vec_dst - > set_at ( opt_vec_src , index , 0 ) ;
}
}
}
}
// are we starting as gcodeviewer ?
/*for (auto it = m_actions.begin(); it != m_actions.end(); ++it) {
if ( * it = = " gcodeviewer " ) {
start_gui = true ;
start_as_gcodeviewer = true ;
m_actions . erase ( it ) ;
break ;
}
} */
BOOST_LOG_TRIVIAL ( info ) < < " start_gui= " < < start_gui < < std : : endl ;
//BBS: add plate data related logic
PlateDataPtrs plate_data ;
int arrange_option ;
bool first_file = true , is_bbl_3mf = false , need_arrange = true ;
Semver file_version ;
std : : map < size_t , bool > orients_requirement ;
std : : vector < Preset * > project_presets ;
// Read input file(s) if any.
BOOST_LOG_TRIVIAL ( info ) < < " Will start to read model file now, file count : " < < m_input_files . size ( ) < < " \n " ;
/*for (const std::string& file : m_input_files)
if ( is_gcode_file ( file ) & & boost : : filesystem : : exists ( file ) ) {
start_as_gcodeviewer = true ;
BOOST_LOG_TRIVIAL ( info ) < < " found a gcode file: " < < file < < " , will start as gcode viewer \n " ;
break ;
} */
//if (!start_as_gcodeviewer) {
for ( const std : : string & file : m_input_files ) {
if ( ! boost : : filesystem : : exists ( file ) ) {
boost : : nowide : : cerr < < " No such file: " < < file < < std : : endl ;
2022-11-02 12:42:37 +00:00
flush_and_exit ( CLI_FILE_NOTFOUND ) ;
2022-07-15 15:37:19 +00:00
}
Model model ;
//BBS: add plate related logic
//bool load_aux = false;
BOOST_LOG_TRIVIAL ( info ) < < " read model file: " < < file < < " \n " ;
try {
// When loading an AMF or 3MF, config is imported as well, including the printer technology.
DynamicPrintConfig config ;
ConfigSubstitutionContext config_substitutions ( config_substitution_rule ) ;
//FIXME should we check the version here? // | LoadStrategy::CheckVersion ?
is_bbl_3mf = false ;
LoadStrategy strategy ;
if ( boost : : algorithm : : iends_with ( file , " .3mf " ) & & first_file ) {
strategy = LoadStrategy : : LoadModel | LoadStrategy : : LoadConfig | LoadStrategy : : AddDefaultInstances | LoadStrategy : : LoadAuxiliary ;
//load_aux = true;
}
else
strategy = LoadStrategy : : LoadModel | LoadStrategy : : AddDefaultInstances ;
// BBS: adjust whebackup
//LoadStrategy strategy = LoadStrategy::LoadModel | LoadStrategy::LoadConfig|LoadStrategy::AddDefaultInstances;
//if (load_aux) strategy = strategy | LoadStrategy::LoadAuxiliary;
model = Model : : read_from_file ( file , & config , & config_substitutions , strategy , & plate_data , & project_presets , & is_bbl_3mf , & file_version ) ;
if ( is_bbl_3mf )
{
if ( ! first_file )
{
BOOST_LOG_TRIVIAL ( info ) < < " The BBL 3mf file should be placed at the first position, filename= " < < file < < " \n " ;
2022-11-02 12:42:37 +00:00
flush_and_exit ( CLI_FILELIST_INVALID_ORDER ) ;
2022-07-15 15:37:19 +00:00
}
BOOST_LOG_TRIVIAL ( info ) < < " the first file is a 3mf, got plate count: " < < plate_data . size ( ) < < " \n " ;
need_arrange = false ;
for ( ModelObject * o : model . objects )
{
orients_requirement . insert ( std : : pair < size_t , bool > ( o - > id ( ) . id , false ) ) ;
BOOST_LOG_TRIVIAL ( info ) < < " object " < < o - > name < < " , id : " < < o - > id ( ) . id < < " , from bbl 3mf \n " ;
}
/*for (ModelObject *model_object : model.objects)
for ( ModelInstance * model_instance : model_object - > instances )
{
const Vec3d & instance_offset = model_instance - > get_offset ( ) ;
BOOST_LOG_TRIVIAL ( info ) < < boost : : format ( " instance %1% transform {%2%,%3%,%4%} at %5%:%6% " ) % model_object - > name % instance_offset . x ( ) % instance_offset . y ( ) % instance_offset . z ( ) % __FUNCTION__ % __LINE__ < < std : : endl ;
} */
}
else
{
need_arrange = true ;
for ( ModelObject * o : model . objects )
{
orients_requirement . insert ( std : : pair < size_t , bool > ( o - > id ( ) . id , true ) ) ;
BOOST_LOG_TRIVIAL ( info ) < < " object " < < o - > name < < " , id : " < < o - > id ( ) . id < < " , from stl or other 3mf \n " ;
o - > ensure_on_bed ( ) ;
}
}
first_file = false ;
PrinterTechnology other_printer_technology = get_printer_technology ( config ) ;
if ( printer_technology = = ptUnknown ) {
printer_technology = other_printer_technology ;
}
if ( ( printer_technology ! = other_printer_technology ) & & ( other_printer_technology ! = ptUnknown ) ) {
boost : : nowide : : cerr < < " invalid printer_technology " < < printer_technology < < " , from source file " < < file < < std : : endl ;
2022-11-02 12:42:37 +00:00
flush_and_exit ( CLI_INVALID_PRINTER_TECH ) ;
2022-07-15 15:37:19 +00:00
}
if ( ! config_substitutions . substitutions . empty ( ) ) {
BOOST_LOG_TRIVIAL ( info ) < < " Found legacy configuration values, substituted when loading " < < file < < " : \n " ;
for ( const ConfigSubstitution & subst : config_substitutions . substitutions )
BOOST_LOG_TRIVIAL ( info ) < < " \t key = \" " < < subst . opt_def - > opt_key < < " \" \t old_value = \" " < < subst . old_value < < " \t new_value = \" " < < subst . new_value - > serialize ( ) < < " \" \n " ;
}
// config is applied to m_print_config before the current m_config values.
config + = std : : move ( m_print_config ) ;
m_print_config = std : : move ( config ) ;
}
catch ( std : : exception & e ) {
boost : : nowide : : cerr < < file < < " : " < < e . what ( ) < < std : : endl ;
2022-11-02 12:42:37 +00:00
flush_and_exit ( CLI_DATA_FILE_ERROR ) ;
2022-07-15 15:37:19 +00:00
}
if ( model . objects . empty ( ) ) {
boost : : nowide : : cerr < < " Error: file is empty: " < < file < < std : : endl ;
continue ;
}
m_models . push_back ( model ) ;
}
//}
//BBS: set default to ptFFF
if ( printer_technology = = ptUnknown )
printer_technology = ptFFF ;
//BBS: merge these models into one
BOOST_LOG_TRIVIAL ( info ) < < " total " < < m_models . size ( ) < < " models, " < < orients_requirement . size ( ) < < " objects " < < std : : endl ;
if ( m_models . size ( ) > 1 )
{
BOOST_LOG_TRIVIAL ( info ) < < " merge all the models into one \n " ;
Model m ;
m . set_backup_path ( m_models [ 0 ] . get_backup_path ( ) ) ;
for ( auto & model : m_models )
for ( ModelObject * o : model . objects )
{
ModelObject * new_object = m . add_object ( * o ) ;
//BOOST_LOG_TRIVIAL(info) << "object "<<o->name <<", id :" << o->id().id << "\n";
orients_requirement . emplace ( new_object - > id ( ) . id , orients_requirement [ o - > id ( ) . id ] ) ;
orients_requirement . erase ( o - > id ( ) . id ) ;
}
m . add_default_instances ( ) ;
m_models . clear ( ) ;
m_models . emplace_back ( std : : move ( m ) ) ;
}
// Apply command line options to a more specific DynamicPrintConfig which provides normalize()
// (command line options override --load files)
m_print_config . apply ( m_extra_config , true ) ;
// Normalizing after importing the 3MFs / AMFs
m_print_config . normalize_fdm ( ) ;
m_print_config . option < ConfigOptionEnum < PrinterTechnology > > ( " printer_technology " , true ) - > value = printer_technology ;
// Initialize full print configs for both the FFF and SLA technologies.
FullPrintConfig fff_print_config ;
//SLAFullPrintConfig sla_print_config;
// Synchronize the default parameters and the ones received on the command line.
if ( printer_technology = = ptFFF ) {
fff_print_config . apply ( m_print_config , true ) ;
m_print_config . apply ( fff_print_config , true ) ;
} else {
boost : : nowide : : cerr < < " invalid printer_technology " < < std : : endl ;
2022-11-05 02:21:04 +00:00
flush_and_exit ( CLI_INVALID_PRINTER_TECH ) ;
2022-07-15 15:37:19 +00:00
/*assert(printer_technology == ptSLA);
sla_print_config . filename_format . value = " [input_filename_base].sl1 " ;
// The default bed shape should reflect the default display parameters
// and not the fff defaults.
double w = sla_print_config . display_width . getFloat ( ) ;
double h = sla_print_config . display_height . getFloat ( ) ;
sla_print_config . printable_area . values = { Vec2d ( 0 , 0 ) , Vec2d ( w , 0 ) , Vec2d ( w , h ) , Vec2d ( 0 , h ) } ;
sla_print_config . apply ( m_print_config , true ) ;
m_print_config . apply ( sla_print_config , true ) ; */
}
std : : string validity = m_print_config . validate ( ) ;
if ( ! validity . empty ( ) ) {
boost : : nowide : : cerr < < " Error: The composite configation is not valid: " < < validity < < std : : endl ;
2022-11-02 12:42:37 +00:00
flush_and_exit ( CLI_INVALID_PRINTER_TECH ) ;
2022-07-15 15:37:19 +00:00
}
//BBS: partplate list
Slic3r : : GUI : : PartPlateList partplate_list ( NULL , m_models . data ( ) , printer_technology ) ;
//use Pointfs insteadof Points
Pointfs bedfs = m_print_config . opt < ConfigOptionPoints > ( " printable_area " ) - > values ;
Pointfs excluse_areas = m_print_config . opt < ConfigOptionPoints > ( " bed_exclude_area " ) - > values ;
//update part plate's size
double print_height = m_print_config . opt_float ( " printable_height " ) ;
double height_to_lid = m_print_config . opt_float ( " extruder_clearance_height_to_lid " ) ;
double height_to_rod = m_print_config . opt_float ( " extruder_clearance_height_to_rod " ) ;
double plate_stride ;
if ( m_models . size ( ) > 0 )
{
std : : string bed_texture ;
partplate_list . reset_size ( bedfs [ 2 ] . x ( ) - bedfs [ 0 ] . x ( ) , bedfs [ 2 ] . y ( ) - bedfs [ 0 ] . y ( ) , print_height ) ;
partplate_list . set_shapes ( bedfs , excluse_areas , bed_texture , height_to_lid , height_to_rod ) ;
plate_stride = partplate_list . plate_stride_x ( ) ;
BOOST_LOG_TRIVIAL ( info ) < < " bed size, x= " < < bedfs [ 2 ] . x ( ) - bedfs [ 0 ] . x ( ) < < " ,y= " < < bedfs [ 2 ] . y ( ) - bedfs [ 0 ] . y ( ) < < " ,z= " < < print_height < < " \n " ;
}
if ( plate_data . size ( ) > 0 )
{
partplate_list . load_from_3mf_structure ( plate_data ) ;
release_PlateData_list ( plate_data ) ;
}
/*for (ModelObject *model_object : m_models[0].objects)
for ( ModelInstance * model_instance : model_object - > instances )
{
const Vec3d & instance_offset = model_instance - > get_offset ( ) ;
BOOST_LOG_TRIVIAL ( info ) < < boost : : format ( " instance %1% transform {%2%,%3%,%4%} at %5%:%6% " ) % model_object - > name % instance_offset . x ( ) % instance_offset . y ( ) % instance_offset . z ( ) % __FUNCTION__ % __LINE__ < < std : : endl ;
} */
// Loop through transform options.
bool user_center_specified = false ;
Points beds = get_bed_shape ( m_print_config ) ;
ArrangeParams arrange_cfg ;
arrange_cfg . min_obj_distance = scaled ( min_object_distance ( m_print_config ) ) ;
BOOST_LOG_TRIVIAL ( info ) < < " will start transforms, commands count " < < m_transforms . size ( ) < < " \n " ;
for ( auto const & opt_key : m_transforms ) {
BOOST_LOG_TRIVIAL ( info ) < < " process transform " < < opt_key < < " \n " ;
if ( opt_key = = " merge " ) {
//BBS: always merge, do nothing here
/*Model m;
for ( auto & model : m_models )
for ( ModelObject * o : model . objects )
m . add_object ( * o ) ;
// Rearrange instances unless --dont-arrange is supplied
if ( ! m_config . opt_bool ( " dont_arrange " ) ) {
m . add_default_instances ( ) ;
if ( this - > has_print_action ( ) )
arrange_objects ( m , bed , arrange_cfg ) ;
else
arrange_objects ( m , InfiniteBed { } , arrange_cfg ) ;
}
m_models . clear ( ) ;
m_models . emplace_back ( std : : move ( m ) ) ; */
}
else if ( opt_key = = " convert_unit " ) {
for ( auto & model : m_models ) {
if ( model . looks_like_saved_in_meters ( ) ) {
BOOST_LOG_TRIVIAL ( info ) < < " convert from meter to millimeter \n " ;
model . convert_from_meters ( true ) ;
}
else if ( model . looks_like_imperial_units ( ) ) {
BOOST_LOG_TRIVIAL ( info ) < < " convert from inch to millimeter \n " ;
model . convert_from_imperial_units ( true ) ;
}
}
}
else if ( opt_key = = " orient " ) {
for ( auto & model : m_models )
for ( ModelObject * o : model . objects )
{
// coconut: always orient instance instead of object
for ( ModelInstance * mi : o - > instances )
{
orientation : : orient ( mi ) ;
}
BOOST_LOG_TRIVIAL ( info ) < < " orient object, name= " < < o - > name < < " ,id= " < < o - > id ( ) . id < < std : : endl ;
//BBS: clear the orient objects lists
orients_requirement [ o - > id ( ) . id ] = false ;
}
}
else if ( opt_key = = " copy " ) {
for ( auto & model : m_models ) {
const bool all_objects_have_instances = std : : none_of (
model . objects . begin ( ) , model . objects . end ( ) ,
[ ] ( ModelObject * o ) { return o - > instances . empty ( ) ; }
) ;
int dups = m_config . opt_int ( " copy " ) ;
if ( ! all_objects_have_instances ) model . add_default_instances ( ) ;
try {
if ( dups > 1 ) {
// if all input objects have defined position(s) apply duplication to the whole model
duplicate ( model , size_t ( dups ) , beds , arrange_cfg ) ;
} else {
arrange_objects ( model , beds , arrange_cfg ) ;
}
} catch ( std : : exception & ex ) {
boost : : nowide : : cerr < < " error: " < < ex . what ( ) < < std : : endl ;
2022-11-02 12:42:37 +00:00
flush_and_exit ( CLI_COPY_OBJECTS_ERROR ) ;
2022-07-15 15:37:19 +00:00
}
}
} else if ( opt_key = = " center " ) {
user_center_specified = true ;
for ( auto & model : m_models ) {
model . add_default_instances ( ) ;
// this affects instances:
model . center_instances_around_point ( m_config . option < ConfigOptionPoint > ( " center " ) - > value ) ;
// this affects volumes:
//FIXME Vojtech: Who knows why the complete model should be aligned with Z as a single rigid body?
//model.align_to_ground();
BoundingBoxf3 bbox ;
for ( ModelObject * model_object : model . objects )
// We are interested into the Z span only, therefore it is sufficient to measure the bounding box of the 1st instance only.
bbox . merge ( model_object - > instance_bounding_box ( 0 , false ) ) ;
for ( ModelObject * model_object : model . objects )
for ( ModelInstance * model_instance : model_object - > instances )
model_instance - > set_offset ( Z , model_instance - > get_offset ( Z ) - bbox . min . z ( ) ) ;
}
} else if ( opt_key = = " align_xy " ) {
const Vec2d & p = m_config . option < ConfigOptionPoint > ( " align_xy " ) - > value ;
for ( auto & model : m_models ) {
BoundingBoxf3 bb = model . bounding_box ( ) ;
// this affects volumes:
model . translate ( - ( bb . min . x ( ) - p . x ( ) ) , - ( bb . min . y ( ) - p . y ( ) ) , - bb . min . z ( ) ) ;
}
} else if ( opt_key = = " arrange " ) {
//BBS: arrange 0 means disable, 1 means force arrange, others means auto
int arrange_option = m_config . option < ConfigOptionInt > ( " arrange " ) - > value ;
if ( arrange_option = = 0 )
{
need_arrange = false ;
}
else if ( arrange_option = = 1 )
{
need_arrange = true ;
}
else
{
//auto arrange, keep the original logic
}
} else if ( opt_key = = " ensure_on_bed " ) {
// do nothing, the value is used later
} else if ( opt_key = = " rotate " ) {
for ( auto & model : m_models )
for ( auto & o : model . objects )
// this affects volumes:
o - > rotate ( Geometry : : deg2rad ( m_config . opt_float ( opt_key ) ) , Z ) ;
} else if ( opt_key = = " rotate_x " ) {
for ( auto & model : m_models )
for ( auto & o : model . objects )
// this affects volumes:
o - > rotate ( Geometry : : deg2rad ( m_config . opt_float ( opt_key ) ) , X ) ;
} else if ( opt_key = = " rotate_y " ) {
for ( auto & model : m_models )
for ( auto & o : model . objects )
// this affects volumes:
o - > rotate ( Geometry : : deg2rad ( m_config . opt_float ( opt_key ) ) , Y ) ;
} else if ( opt_key = = " scale " ) {
for ( auto & model : m_models )
for ( auto & o : model . objects )
// this affects volumes:
o - > scale ( m_config . get_abs_value ( opt_key , 1 ) ) ;
} else if ( opt_key = = " scale_to_fit " ) {
const Vec3d & opt = m_config . opt < ConfigOptionPoint3 > ( opt_key ) - > value ;
if ( opt . x ( ) < = 0 | | opt . y ( ) < = 0 | | opt . z ( ) < = 0 ) {
boost : : nowide : : cerr < < " --scale-to-fit requires a positive volume " < < std : : endl ;
2022-11-02 12:42:37 +00:00
flush_and_exit ( CLI_SCALE_TO_FIT_ERROR ) ;
2022-07-15 15:37:19 +00:00
}
for ( auto & model : m_models )
for ( auto & o : model . objects )
// this affects volumes:
o - > scale_to_fit ( opt ) ;
} else if ( opt_key = = " cut " | | opt_key = = " cut_x " | | opt_key = = " cut_y " ) {
std : : vector < Model > new_models ;
for ( auto & model : m_models ) {
model . translate ( 0 , 0 , - model . bounding_box ( ) . min . z ( ) ) ; // align to z = 0
size_t num_objects = model . objects . size ( ) ;
for ( size_t i = 0 ; i < num_objects ; + + i ) {
#if 0
if ( opt_key = = " cut_x " ) {
o - > cut ( X , m_config . opt_float ( " cut_x " ) , & out ) ;
} else if ( opt_key = = " cut_y " ) {
o - > cut ( Y , m_config . opt_float ( " cut_y " ) , & out ) ;
} else if ( opt_key = = " cut " ) {
o - > cut ( Z , m_config . opt_float ( " cut " ) , & out ) ;
}
# else
ModelObject * object = model . objects . front ( ) ;
const BoundingBoxf3 & box = object - > bounding_box ( ) ;
const float Margin = 20.0 ;
const float max_x = box . size ( ) ( 0 ) / 2.0 + Margin ;
const float min_x = - max_x ;
const float max_y = box . size ( ) ( 1 ) / 2.0 + Margin ;
const float min_y = - max_y ;
std : : array < Vec3d , 4 > plane_points ;
plane_points [ 0 ] = { min_x , min_y , 0 } ;
plane_points [ 1 ] = { max_x , min_y , 0 } ;
plane_points [ 2 ] = { max_x , max_y , 0 } ;
plane_points [ 3 ] = { min_x , max_y , 0 } ;
for ( Vec3d & point : plane_points ) {
point + = box . center ( ) ;
}
model . objects . front ( ) - > cut ( 0 , plane_points , ModelObjectCutAttribute : : KeepUpper | ModelObjectCutAttribute : : KeepLower ) ;
# endif
model . delete_object ( size_t ( 0 ) ) ;
}
}
// TODO: copy less stuff around using pointers
m_models = new_models ;
if ( m_actions . empty ( ) )
m_actions . push_back ( " export_stl " ) ;
}
#if 0
else if ( opt_key = = " cut_grid " ) {
std : : vector < Model > new_models ;
for ( auto & model : m_models ) {
TriangleMesh mesh = model . mesh ( ) ;
mesh . repair ( ) ;
std : : vector < TriangleMesh > meshes = mesh . cut_by_grid ( m_config . option < ConfigOptionPoint > ( " cut_grid " ) - > value ) ;
size_t i = 0 ;
for ( TriangleMesh * m : meshes ) {
Model out ;
auto o = out . add_object ( ) ;
o - > add_volume ( * m ) ;
o - > input_file + = " _ " + std : : to_string ( i + + ) ;
delete m ;
}
}
// TODO: copy less stuff around using pointers
m_models = new_models ;
if ( m_actions . empty ( ) )
m_actions . push_back ( " export_stl " ) ;
}
# endif
else if ( opt_key = = " split " ) {
for ( Model & model : m_models ) {
size_t num_objects = model . objects . size ( ) ;
for ( size_t i = 0 ; i < num_objects ; + + i ) {
ModelObjectPtrs new_objects ;
model . objects . front ( ) - > split ( & new_objects ) ;
model . delete_object ( size_t ( 0 ) ) ;
}
}
} else if ( opt_key = = " repair " ) {
// Models are repaired by default.
//for (auto &model : m_models)
// model.repair();
} else {
boost : : nowide : : cerr < < " error: option not implemented yet: " < < opt_key < < std : : endl ;
2022-11-02 12:42:37 +00:00
flush_and_exit ( CLI_UNSUPPORTED_OPERATION ) ;
2022-07-15 15:37:19 +00:00
}
}
BOOST_LOG_TRIVIAL ( info ) < < " finished model pre-process commands \n " ;
//BBS: add orient and arrange logic here
for ( auto & model : m_models )
{
for ( ModelObject * o : model . objects )
{
if ( orients_requirement [ o - > id ( ) . id ] )
{
BOOST_LOG_TRIVIAL ( info ) < < " Before process command, Orient object, name= " < < o - > name < < " ,id= " < < o - > id ( ) . id < < std : : endl ;
orientation : : orient ( o ) ;
}
else
{
BOOST_LOG_TRIVIAL ( info ) < < " Before process command, no need to orient, object id : " < < o - > id ( ) . id < < std : : endl ;
}
}
}
//BBS: clear the orient objects lists
orients_requirement . clear ( ) ;
if ( need_arrange )
{
ArrangePolygons selected , unselected , unprintable , locked_aps ;
BOOST_LOG_TRIVIAL ( info ) < < " Will arrange now, need_arrange= " < < need_arrange < < " \n " ;
for ( Model & model : m_models )
{
//Step-1: prepare arrange polygons
for ( size_t oidx = 0 ; oidx < model . objects . size ( ) ; + + oidx )
{
ModelObject * mo = model . objects [ oidx ] ;
for ( size_t inst_idx = 0 ; inst_idx < mo - > instances . size ( ) ; + + inst_idx )
{
ModelInstance * minst = mo - > instances [ inst_idx ] ;
ArrangePolygon ap = get_instance_arrange_poly ( minst , m_print_config ) ;
//preprocess by partplate list
//remove the locked plate's instances, neither in selected, nor in un-selected
bool locked = partplate_list . preprocess_arrange_polygon ( oidx , inst_idx , ap , true ) ;
if ( ! locked )
{
ap . itemid = selected . size ( ) ;
if ( minst - > printable )
selected . emplace_back ( ap ) ;
else
unprintable . emplace_back ( ap ) ;
}
else
{
//skip this object due to be locked in plate
ap . itemid = locked_aps . size ( ) ;
locked_aps . emplace_back ( ap ) ;
boost : : nowide : : cout < < __FUNCTION__ < < boost : : format ( " : skip locked instance, obj_id %1%, instance_id %2% " ) % oidx % inst_idx ;
}
}
}
//add the virtual object into unselect list if has
partplate_list . preprocess_exclude_areas ( unselected ) ;
//Step-2:prepare the arrange params
arrange_cfg . allow_rotations = true ;
arrange_cfg . min_obj_distance = scaled ( 6.0 ) ;
//BBS: add specific params
arrange_cfg . is_seq_print = false ;
arrange_cfg . bed_shrink_x = 0 ;
arrange_cfg . bed_shrink_y = 0 ;
double skirt_distance = m_print_config . opt_float ( " skirt_distance " ) ;
double brim_width = m_print_config . opt_float ( " brim_width " ) ;
arrange_cfg . brim_skirt_distance = skirt_distance + brim_width ;
BOOST_LOG_TRIVIAL ( info ) < < boost : : format ( " Arrange Params: brim_skirt_distance=%1%, min_obj_distance=%2%, is_seq_print=%3% \n " ) % arrange_cfg . brim_skirt_distance % arrange_cfg . min_obj_distance % arrange_cfg . is_seq_print ;
// Note: skirt_distance is now defined between outermost brim and skirt, not the object and skirt.
// So we can't do max but do adding instead.
arrange_cfg . bed_shrink_x + = arrange_cfg . brim_skirt_distance ;
arrange_cfg . bed_shrink_y + = arrange_cfg . brim_skirt_distance ;
// shrink bed
beds [ 0 ] + = Point ( scaled ( arrange_cfg . bed_shrink_x ) , scaled ( arrange_cfg . bed_shrink_y ) ) ;
beds [ 1 ] + = Point ( - scaled ( arrange_cfg . bed_shrink_x ) , scaled ( arrange_cfg . bed_shrink_y ) ) ;
beds [ 2 ] + = Point ( - scaled ( arrange_cfg . bed_shrink_x ) , - scaled ( arrange_cfg . bed_shrink_y ) ) ;
beds [ 3 ] + = Point ( scaled ( arrange_cfg . bed_shrink_x ) , - scaled ( arrange_cfg . bed_shrink_y ) ) ;
// do not inflate brim_width. Objects are allowed to have overlapped brim.
std : : for_each ( selected . begin ( ) , selected . end ( ) , [ & ] ( auto & ap ) { ap . inflation = arrange_cfg . min_obj_distance / 2 ; } ) ;
{
BOOST_LOG_TRIVIAL ( info ) < < " items selected before arranging: " ;
for ( auto selected : selected )
BOOST_LOG_TRIVIAL ( info ) < < selected . name < < " , extruder: " < < selected . extrude_ids . back ( ) < < " , bed: " < < selected . bed_idx
< < " , trans: " < < selected . translation . transpose ( ) ;
}
arrange_cfg . progressind = [ ] ( unsigned st , std : : string str = " " ) {
boost : : nowide : : cout < < " st= " < < st < < " , " < < str < < std : : endl ;
} ;
//Step-3:do the arrange
arrangement : : arrange ( selected , unselected , beds , arrange_cfg ) ;
arrangement : : arrange ( unprintable , { } , beds , arrange_cfg ) ;
//Step-4:postprocess by partplate list&&apply the result
int bed_idx_max = 0 ;
//clear all the relations before apply the arrangement results
partplate_list . clear ( ) ;
// Apply the arrange result to all selected objects
for ( ArrangePolygon & ap : selected ) {
//BBS: partplate postprocess
partplate_list . postprocess_bed_index_for_selected ( ap ) ;
bed_idx_max = std : : max ( ap . bed_idx , bed_idx_max ) ;
boost : : nowide : : cout < < " after arrange: name= " < < ap . name < < boost : : format ( " ,bed_id %1%, trans {%2%,%3%} " ) % ap . bed_idx % unscale < double > ( ap . translation ( X ) ) % unscale < double > ( ap . translation ( Y ) ) < < " \n " ;
}
for ( ArrangePolygon & ap : locked_aps ) {
bed_idx_max = std : : max ( ap . bed_idx , bed_idx_max ) ;
partplate_list . postprocess_arrange_polygon ( ap , false ) ;
ap . apply ( ) ;
}
// Apply the arrange result to all selected objects
for ( ArrangePolygon & ap : selected ) {
//BBS: partplate postprocess
partplate_list . postprocess_arrange_polygon ( ap , true ) ;
ap . apply ( ) ;
}
// Move the unprintable items to the last virtual bed.
for ( ArrangePolygon & ap : unprintable ) {
ap . bed_idx + = bed_idx_max + 1 ;
partplate_list . postprocess_arrange_polygon ( ap , true ) ;
ap . apply ( ) ;
}
//BBS: reload all objects due to arrange
partplate_list . rebuild_plates_after_arrangement ( ) ;
}
}
// All transforms have been dealt with. Now ensure that the objects are on bed.
// (Unless the user said otherwise.)
//BBS: current only support models on bed
//if (m_config.opt_bool("ensure_on_bed"))
for ( auto & model : m_models )
for ( auto & o : model . objects )
o - > ensure_on_bed ( ) ;
// loop through action options
bool export_to_3mf = false ;
int plate_to_slice = 0 ;
std : : string export_3mf_file ;
std : : string outfile_dir = m_config . opt_string ( " outputdir " ) ;
std : : vector < ThumbnailData * > calibration_thumbnails ;
for ( auto const & opt_key : m_actions ) {
if ( opt_key = = " help " ) {
this - > print_help ( ) ;
} else if ( opt_key = = " help_fff " ) {
this - > print_help ( true , ptFFF ) ;
} else if ( opt_key = = " help_sla " ) {
this - > print_help ( true , ptSLA ) ;
2022-11-05 02:21:04 +00:00
} else if ( opt_key = = " pipe " ) {
# if defined(__linux__) || defined(__LINUX__)
std : : string pipe_name = m_config . option < ConfigOptionString > ( " pipe " ) - > value ;
g_cli_callback_mgr . start ( pipe_name ) ;
# endif
2022-07-15 15:37:19 +00:00
} else if ( opt_key = = " export_settings " ) {
//FIXME check for mixing the FFF / SLA parameters.
// or better save fff_print_config vs. sla_print_config
//m_print_config.save(m_config.opt_string("save"));
m_print_config . save_to_json ( m_config . opt_string ( opt_key ) , std : : string ( " project_settings " ) , std : : string ( " project " ) , std : : string ( SLIC3R_VERSION ) ) ;
} else if ( opt_key = = " info " ) {
// --info works on unrepaired model
for ( Model & model : m_models ) {
model . add_default_instances ( ) ;
model . print_info ( ) ;
}
} else if ( opt_key = = " export_stl " ) {
for ( auto & model : m_models )
model . add_default_instances ( ) ;
if ( ! this - > export_models ( IO : : STL ) )
2022-11-02 12:42:37 +00:00
flush_and_exit ( CLI_EXPORT_STL_ERROR ) ;
} else if ( opt_key = = " expor1t_obj " ) {
2022-07-15 15:37:19 +00:00
for ( auto & model : m_models )
model . add_default_instances ( ) ;
if ( ! this - > export_models ( IO : : OBJ ) )
2022-11-02 12:42:37 +00:00
flush_and_exit ( CLI_EXPORT_OBJ_ERROR ) ;
2022-07-15 15:37:19 +00:00
} /* else if (opt_key == "export_amf") {
if ( ! this - > export_models ( IO : : AMF ) )
return 1 ;
} */ else if ( opt_key = = " export_3mf " ) {
export_to_3mf = true ;
export_3mf_file = m_config . opt_string ( opt_key ) ;
//} else if (opt_key == "export_gcode" || opt_key == "export_sla" || opt_key == "slice") {
} else if ( opt_key = = " slice " ) {
//BBS: slice 0 means all plates, i means plate i;
plate_to_slice = m_config . option < ConfigOptionInt > ( " slice " ) - > value ;
/*if (opt_key == "export_gcode" && printer_technology == ptSLA) {
boost : : nowide : : cerr < < " error: cannot export G-code for an FFF configuration " < < std : : endl ;
flush_and_exit ( 1 ) ;
} else if ( opt_key = = " export_sla " & & printer_technology = = ptFFF ) {
boost : : nowide : : cerr < < " error: cannot export SLA slices for a SLA configuration " < < std : : endl ;
flush_and_exit ( 1 ) ;
} */
BOOST_LOG_TRIVIAL ( info ) < < " Need to slice for plate " < < plate_to_slice < < " , total plate count " < < partplate_list . get_plate_count ( ) < < " partplates! " < < std : : endl ;
// Make a copy of the model if the current action is not the last action, as the model may be
// modified by the centering and such.
Model model_copy ;
bool make_copy = & opt_key ! = & m_actions . back ( ) ;
for ( Model & model_in : m_models ) {
if ( make_copy )
model_copy = model_in ;
Model & model = make_copy ? model_copy : model_in ;
// If all objects have defined instances, their relative positions will be
// honored when printing (they will be only centered, unless --dont-arrange
// is supplied); if any object has no instances, it will get a default one
// and all instances will be rearranged (unless --dont-arrange is supplied).
std : : string outfile ;
Print fff_print ;
/*SLAPrint sla_print;
SL1Archive sla_archive ( sla_print . printer_config ( ) ) ;
sla_print . set_printer ( & sla_archive ) ;
sla_print . set_status_callback (
[ ] ( const PrintBase : : SlicingStatus & s )
{
if ( s . percent > = 0 ) // FIXME: is this sufficient?
printf ( " %3d%s %s \n " , s . percent , " % => " , s . text . c_str ( ) ) ;
} ) ; */
//BBS: slice every partplate one by one
PrintBase * print = NULL ;
Slic3r : : GUI : : GCodeResult * gcode_result = NULL ;
int print_index ;
for ( int index = 0 ; index < partplate_list . get_plate_count ( ) ; index + + )
{
if ( ( plate_to_slice ! = 0 ) & & ( plate_to_slice ! = ( index + 1 ) ) ) {
BOOST_LOG_TRIVIAL ( info ) < < " Skip plate " < < index + 1 < < std : : endl ;
continue ;
}
//get the current partplate
Slic3r : : GUI : : PartPlate * part_plate = partplate_list . get_plate ( index ) ;
part_plate - > get_print ( & print , & gcode_result , & print_index ) ;
/*if (outfile_config.empty())
{
outfile = " plate_ " + std : : to_string ( index + 1 ) + " .gcode " ;
}
else
{
outfile = " plate_ " + std : : to_string ( index + 1 ) + " _ " + outfile_config + " .gcode " ;
} */
//update plate's bounding box to model
#if 0
BoundingBoxf3 print_volume = part_plate - > get_bounding_box ( false ) ;
print_volume . max ( 2 ) = z ;
print_volume . min ( 2 ) = - 1e10 ;
model . update_print_volume_state ( print_volume ) ;
BOOST_LOG_TRIVIAL ( info ) < < boost : : format ( " print_volume {%1%,%2%,%3%}->{%4%, %5%, %6%} " ) % print_volume . min ( 0 ) % print_volume . min ( 1 )
% print_volume . min ( 2 ) % print_volume . max ( 0 ) % print_volume . max ( 1 ) % print_volume . max ( 2 ) < < std : : endl ;
# else
BuildVolume build_volume ( part_plate - > get_shape ( ) , print_height ) ;
model . update_print_volume_state ( build_volume ) ;
unsigned int count = model . update_print_volume_state ( build_volume ) ;
2022-11-05 02:21:04 +00:00
if ( count = = 0 ) {
BOOST_LOG_TRIVIAL ( error ) < < " plate " < < index + 1 < < " : Nothing to be sliced, Either the print is empty or no object is fully inside the print volume before apply. " < < std : : endl ;
flush_and_exit ( CLI_NO_SUITABLE_OBJECTS ) ;
}
else {
for ( ModelObject * model_object : model . objects )
for ( ModelInstance * i : model_object - > instances )
if ( i - > print_volume_state = = ModelInstancePVS_Partly_Outside )
{
BOOST_LOG_TRIVIAL ( error ) < < " plate " < < index + 1 < < " : Found Object " < < model_object - > name < < " partly inside, can not be sliced. " < < std : : endl ;
flush_and_exit ( CLI_OBJECTS_PARTLY_INSIDE ) ;
}
}
2022-07-15 15:37:19 +00:00
// BBS: TODO
//BOOST_LOG_TRIVIAL(info) << boost::format("print_volume {%1%,%2%,%3%}->{%4%, %5%, %6%}, has %7% printables") % print_volume.min(0) % print_volume.min(1)
// % print_volume.min(2) % print_volume.max(0) % print_volume.max(1) % print_volume.max(2) % count << std::endl;
# endif
//PrintBase *print = (printer_technology == ptFFF) ? static_cast<PrintBase*>(&fff_print) : static_cast<PrintBase*>(&sla_print);
/*if (! m_config.opt_bool("dont_arrange")) {
if ( user_center_specified ) {
Vec2d c = m_config . option < ConfigOptionPoint > ( " center " ) - > value ;
arrange_objects ( model , InfiniteBed { scaled ( c ) } , arrange_cfg ) ;
} else
arrange_objects ( model , bed , arrange_cfg ) ;
} */
/*if (printer_technology == ptFFF) {
for ( auto * mo : model . objects )
( dynamic_cast < Print * > ( print ) ) - > auto_assign_extruders ( mo ) ;
} else {
// The default for "filename_format" is good for FDM: "[input_filename_base].gcode"
// Replace it with a reasonable SLA default.
std : : string & format = m_print_config . opt_string ( " filename_format " , true ) ;
if ( format = = static_cast < const ConfigOptionString * > ( m_print_config . def ( ) - > get ( " filename_format " ) - > default_value . get ( ) ) - > value )
format = " [input_filename_base].SL1 " ;
} */
print - > apply ( model , m_print_config ) ;
StringObjectException warning ;
auto err = print - > validate ( & warning ) ;
if ( ! err . string . empty ( ) ) {
BOOST_LOG_TRIVIAL ( info ) < < " got error when validate: " < < err . string < < std : : endl ;
boost : : nowide : : cerr < < err . string < < std : : endl ;
//BBS: continue for other plates
//continue;
2022-11-05 02:21:04 +00:00
flush_and_exit ( CLI_VALIDATE_ERROR ) ;
2022-07-15 15:37:19 +00:00
}
else if ( ! warning . string . empty ( ) )
BOOST_LOG_TRIVIAL ( info ) < < " got warnings: " < < warning . string < < std : : endl ;
if ( print - > empty ( ) ) {
2022-11-05 02:21:04 +00:00
BOOST_LOG_TRIVIAL ( error ) < < " plate " < < index + 1 < < " : Nothing to be sliced, Either the print is empty or no object is fully inside the print volume after apply. " < < std : : endl ;
2022-11-02 12:42:37 +00:00
flush_and_exit ( CLI_NO_SUITABLE_OBJECTS ) ;
2022-07-15 15:37:19 +00:00
}
else
try {
std : : string outfile_final ;
2022-11-05 02:21:04 +00:00
BOOST_LOG_TRIVIAL ( info ) < < " start Print::process for partplate " < < index + 1 < < std : : endl ;
# if defined(__linux__) || defined(__LINUX__)
BOOST_LOG_TRIVIAL ( info ) < < " cli callback mgr started: " < < g_cli_callback_mgr . m_started < < std : : endl ;
if ( g_cli_callback_mgr . is_started ( ) ) {
BOOST_LOG_TRIVIAL ( info ) < < " set print's callback to cli_status_callback. " ;
print - > set_status_callback ( cli_status_callback ) ;
g_cli_callback_mgr . set_plate_info ( index + 1 , ( plate_to_slice = = 0 ) ? partplate_list . get_plate_count ( ) : 1 ) ;
}
# endif
2022-07-15 15:37:19 +00:00
print - > process ( ) ;
if ( printer_technology = = ptFFF ) {
// The outfile is processed by a PlaceholderParser.
//outfile = part_plate->get_tmp_gcode_path();
if ( outfile_dir . empty ( ) ) {
outfile = part_plate - > get_tmp_gcode_path ( ) ;
}
else {
outfile = outfile_dir + " /plate_ " + std : : to_string ( index + 1 ) + " .gcode " ;
part_plate - > set_tmp_gcode_path ( outfile ) ;
}
BOOST_LOG_TRIVIAL ( info ) < < " process finished, will export gcode temporily to " < < outfile < < std : : endl ;
outfile = ( dynamic_cast < Print * > ( print ) ) - > export_gcode ( outfile , gcode_result , nullptr ) ;
//outfile_final = (dynamic_cast<Print*>(print))->print_statistics().finalize_output_path(outfile);
//m_fff_print->export_gcode(m_temp_output_path, m_gcode_result, [this](const ThumbnailsParams& params) { return this->render_thumbnails(params); });
} /* else {
outfile = sla_print . output_filepath ( outfile ) ;
// We need to finalize the filename beforehand because the export function sets the filename inside the zip metadata
outfile_final = sla_print . print_statistics ( ) . finalize_output_path ( outfile ) ;
sla_archive . export_print ( outfile_final , sla_print ) ;
} */
/*if (outfile != outfile_final) {
if ( Slic3r : : rename_file ( outfile , outfile_final ) ) {
boost : : nowide : : cerr < < " Renaming file " < < outfile < < " to " < < outfile_final < < " failed " < < std : : endl ;
flush_and_exit ( 1 ) ;
}
outfile = outfile_final ;
} */
// Run the post-processing scripts if defined.
//BBS: TODO, maybe need to open this function later
//run_post_process_scripts(outfile, print->full_print_config());
BOOST_LOG_TRIVIAL ( info ) < < " Slicing result exported to " < < outfile < < std : : endl ;
part_plate - > update_slice_result_valid_state ( true ) ;
} catch ( const std : : exception & ex ) {
2022-11-05 02:21:04 +00:00
BOOST_LOG_TRIVIAL ( info ) < < " found slicing or export error for partplate " < < index + 1 < < std : : endl ;
2022-07-15 15:37:19 +00:00
boost : : nowide : : cerr < < ex . what ( ) < < std : : endl ;
//continue;
2022-11-02 12:42:37 +00:00
flush_and_exit ( CLI_SLICING_ERROR ) ;
2022-07-15 15:37:19 +00:00
}
} //end for partplate
/*
print . center = ! m_config . has ( " center " )
& & ! m_config . has ( " align_xy " )
& & ! m_config . opt_bool ( " dont_arrange " ) ;
print . set_model ( model ) ;
// start chronometer
typedef std : : chrono : : high_resolution_clock clock_ ;
typedef std : : chrono : : duration < double , std : : ratio < 1 > > second_ ;
std : : chrono : : time_point < clock_ > t0 { clock_ : : now ( ) } ;
const std : : string outfile = this - > output_filepath ( model , IO : : Gcode ) ;
try {
print . export_gcode ( outfile ) ;
} catch ( std : : runtime_error & e ) {
boost : : nowide : : cerr < < e . what ( ) < < std : : endl ;
return 1 ;
}
BOOST_LOG_TRIVIAL ( info ) < < " G-code exported to " < < outfile < < std : : endl ;
// output some statistics
double duration { std : : chrono : : duration_cast < second_ > ( clock_ : : now ( ) - t0 ) . count ( ) } ;
BOOST_LOG_TRIVIAL ( info ) < < std : : fixed < < std : : setprecision ( 0 )
< < " Done. Process took " < < ( duration / 60 ) < < " minutes and "
< < std : : setprecision ( 3 )
< < std : : fmod ( duration , 60.0 ) < < " seconds. " < < std : : endl
< < std : : setprecision ( 2 )
< < " Filament required: " < < print . total_used_filament ( ) < < " mm "
< < " ( " < < print . total_extruded_volume ( ) / 1000 < < " cm3) " < < std : : endl ;
*/
}
} else {
boost : : nowide : : cerr < < " error: option not supported yet: " < < opt_key < < std : : endl ;
2022-11-02 12:42:37 +00:00
flush_and_exit ( CLI_UNSUPPORTED_OPERATION ) ;
2022-07-15 15:37:19 +00:00
}
}
if ( export_to_3mf ) {
//BBS: export as bbl 3mf
Slic3r : : GUI : : OpenGLManager opengl_mgr ;
std : : vector < ThumbnailData * > thumbnails ;
std : : vector < PlateBBoxData * > plate_bboxes ;
PlateDataPtrs plate_data_list ;
partplate_list . store_to_3mf_structure ( plate_data_list ) ;
std : : vector < Preset * > project_presets ;
if ( ! outfile_dir . empty ( ) ) {
export_3mf_file = outfile_dir + " / " + export_3mf_file ;
}
// get type and color for platedata
auto * filament_types = dynamic_cast < const ConfigOptionStrings * > ( m_print_config . option ( " filament_type " ) ) ;
const ConfigOptionStrings * filament_color = dynamic_cast < const ConfigOptionStrings * > ( m_print_config . option ( " filament_colour " ) ) ;
//auto* filament_id = dynamic_cast<const ConfigOptionStrings*>(m_print_config.option("filament_ids"));
for ( int i = 0 ; i < plate_data_list . size ( ) ; i + + ) {
PlateData * plate_data = plate_data_list [ i ] ;
2022-07-22 09:46:10 +00:00
for ( auto it = plate_data - > slice_filaments_info . begin ( ) ; it ! = plate_data - > slice_filaments_info . end ( ) ; it + + ) {
2022-07-15 15:37:19 +00:00
it - > type = filament_types ? filament_types - > get_at ( it - > id ) : " PLA " ;
it - > color = filament_color ? filament_color - > get_at ( it - > id ) : " #FFFFFF " ;
//it->filament_id = filament_id?filament_id->get_at(it->id):"unknown";
}
}
std : : vector < std : : string > colors ;
if ( filament_color ) {
colors = filament_color - > vserialize ( ) ;
}
else
colors . push_back ( " #FFFFFF " ) ;
std : : vector < std : : array < float , 4 > > colors_out ( colors . size ( ) ) ;
unsigned char rgb_color [ 3 ] = { } ;
for ( const std : : string & color : colors ) {
Slic3r : : GUI : : BitmapCache : : parse_color ( color , rgb_color ) ;
size_t color_idx = & color - & colors . front ( ) ;
colors_out [ color_idx ] = { float ( rgb_color [ 0 ] ) / 255.f , float ( rgb_color [ 1 ] ) / 255.f , float ( rgb_color [ 2 ] ) / 255.f , 1.f } ;
}
int gl_major , gl_minor , gl_verbos ;
glfwGetVersion ( & gl_major , & gl_minor , & gl_verbos ) ;
BOOST_LOG_TRIVIAL ( info ) < < boost : : format ( " opengl version %1%.%2%.%3% " ) % gl_major % gl_minor % gl_verbos ;
glfwSetErrorCallback ( glfw_callback ) ;
int ret = glfwInit ( ) ;
if ( ret = = GLFW_FALSE ) {
int code = glfwGetError ( NULL ) ;
BOOST_LOG_TRIVIAL ( error ) < < " glfwInit return error, code " < < code < < std : : endl ;
}
else {
BOOST_LOG_TRIVIAL ( info ) < < " glfwInit Success. " < < std : : endl ;
glfwWindowHint ( GLFW_CONTEXT_VERSION_MAJOR , gl_major ) ;
glfwWindowHint ( GLFW_CONTEXT_VERSION_MINOR , gl_minor ) ;
glfwWindowHint ( GLFW_RED_BITS , 8 ) ;
glfwWindowHint ( GLFW_GREEN_BITS , 8 ) ;
glfwWindowHint ( GLFW_BLUE_BITS , 8 ) ;
glfwWindowHint ( GLFW_ALPHA_BITS , 8 ) ;
glfwWindowHint ( GLFW_VISIBLE , false ) ;
//glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//glfwDisable(GLFW_AUTO_POLL_EVENTS);
# ifdef __WXMAC__
glfwWindowHint ( GLFW_OPENGL_PROFILE , GLFW_OPENGL_CORE_PROFILE ) ;
glfwWindowHint ( GLFW_OPENGL_FORWARD_COMPAT , GL_TRUE ) ;
# else
glfwWindowHint ( GLFW_OPENGL_PROFILE , GLFW_OPENGL_COMPAT_PROFILE ) ;
# endif
# ifdef __linux__
glfwWindowHint ( GLFW_CONTEXT_CREATION_API , GLFW_OSMESA_CONTEXT_API ) ;
# endif
GLFWwindow * window = glfwCreateWindow ( 640 , 480 , " base_window " , NULL , NULL ) ;
if ( window = = NULL )
{
BOOST_LOG_TRIVIAL ( error ) < < " Failed to create GLFW window " < < std : : endl ;
}
else
glfwMakeContextCurrent ( window ) ;
}
bool opengl_valid = opengl_mgr . init_gl ( ) ;
if ( ! opengl_valid ) {
BOOST_LOG_TRIVIAL ( error ) < < " init opengl failed! skip thumbnail generating " < < std : : endl ;
}
else {
BOOST_LOG_TRIVIAL ( info ) < < " glewInit Sucess. " < < std : : endl ;
GLVolumeCollection glvolume_collection ;
Model & model = m_models [ 0 ] ;
int extruder_id = 1 ;
for ( unsigned int obj_idx = 0 ; obj_idx < ( unsigned int ) model . objects . size ( ) ; + + obj_idx ) {
const ModelObject & model_object = * model . objects [ obj_idx ] ;
const ConfigOption * option = model_object . config . option ( " extruder " ) ;
if ( option )
extruder_id = ( dynamic_cast < const ConfigOptionInt * > ( option ) ) - > getInt ( ) ;
for ( int volume_idx = 0 ; volume_idx < ( int ) model_object . volumes . size ( ) ; + + volume_idx ) {
const ModelVolume & model_volume = * model_object . volumes [ volume_idx ] ;
option = model_volume . config . option ( " extruder " ) ;
if ( option ) extruder_id = ( dynamic_cast < const ConfigOptionInt * > ( option ) ) - > getInt ( ) ;
//if (!model_volume.is_model_part())
// continue;
for ( int instance_idx = 0 ; instance_idx < ( int ) model_object . instances . size ( ) ; + + instance_idx ) {
const ModelInstance & model_instance = * model_object . instances [ instance_idx ] ;
glvolume_collection . load_object_volume ( & model_object , obj_idx , volume_idx , instance_idx , " volume " , true ) ;
//glvolume_collection.volumes.back()->geometry_id = key.geometry_id;
std : : string color = filament_color ? filament_color - > get_at ( extruder_id - 1 ) : " #00FF00 " ;
unsigned char rgb_color [ 3 ] = { } ;
Slic3r : : GUI : : BitmapCache : : parse_color ( color , rgb_color ) ;
glvolume_collection . volumes . back ( ) - > set_render_color ( float ( rgb_color [ 0 ] ) / 255.f , float ( rgb_color [ 1 ] ) / 255.f , float ( rgb_color [ 2 ] ) / 255.f , 1.f ) ;
2022-10-31 14:36:28 +00:00
std : : array < float , 4 > new_color ;
new_color [ 0 ] = float ( rgb_color [ 0 ] ) / 255.f ;
new_color [ 1 ] = float ( rgb_color [ 1 ] ) / 255.f ;
new_color [ 2 ] = float ( rgb_color [ 2 ] ) / 255.f ;
new_color [ 3 ] = 1.f ;
glvolume_collection . volumes . back ( ) - > set_color ( new_color ) ;
2022-07-15 15:37:19 +00:00
}
}
}
ThumbnailsParams thumbnail_params ;
GLShaderProgram * shader = opengl_mgr . get_shader ( " gouraud_light " ) ;
if ( ! shader ) {
BOOST_LOG_TRIVIAL ( error ) < < boost : : format ( " can not get shader for rendering thumbnail " ) ;
}
else {
for ( int i = 0 ; i < partplate_list . get_plate_count ( ) ; i + + ) {
Slic3r : : GUI : : PartPlate * part_plate = partplate_list . get_plate ( i ) ;
ThumbnailData * thumbnail_data = new ThumbnailData ( ) ;
unsigned int thumbnail_width = 256 , thumbnail_height = 256 ;
const ThumbnailsParams thumbnail_params = { { } , false , true , true , true , i } ;
switch ( Slic3r : : GUI : : OpenGLManager : : get_framebuffers_type ( ) )
{
case Slic3r : : GUI : : OpenGLManager : : EFramebufferType : : Arb :
{
BOOST_LOG_TRIVIAL ( info ) < < boost : : format ( " framebuffer_type: ARB " ) ;
Slic3r : : GUI : : GLCanvas3D : : render_thumbnail_framebuffer ( * thumbnail_data ,
thumbnail_width , thumbnail_height , thumbnail_params ,
partplate_list , model . objects , glvolume_collection , colors_out , shader , Slic3r : : GUI : : Camera : : EType : : Ortho ) ;
break ;
}
case Slic3r : : GUI : : OpenGLManager : : EFramebufferType : : Ext :
{
BOOST_LOG_TRIVIAL ( info ) < < boost : : format ( " framebuffer_type: EXT " ) ;
Slic3r : : GUI : : GLCanvas3D : : render_thumbnail_framebuffer_ext ( * thumbnail_data ,
thumbnail_width , thumbnail_height , thumbnail_params ,
partplate_list , model . objects , glvolume_collection , colors_out , shader , Slic3r : : GUI : : Camera : : EType : : Ortho ) ;
break ;
}
default :
BOOST_LOG_TRIVIAL ( info ) < < boost : : format ( " framebuffer_type: unknown " ) ;
break ;
}
thumbnails . push_back ( thumbnail_data ) ;
//render calibration thumbnail
if ( ! part_plate - > get_slice_result ( ) | | ! part_plate - > is_slice_result_valid ( ) ) {
BOOST_LOG_TRIVIAL ( info ) < < boost : : format ( " plate %1% doesn't have a valid sliced result, skip it " ) % ( i + 1 ) ;
calibration_thumbnails . push_back ( new ThumbnailData ( ) ) ;
plate_bboxes . push_back ( new PlateBBoxData ( ) ) ;
continue ;
}
PrintBase * print_base = NULL ;
Slic3r : : GUI : : GCodeResult * gcode_result = NULL ;
int print_index ;
part_plate - > get_print ( & print_base , & gcode_result , & print_index ) ;
BuildVolume build_volume ( part_plate - > get_shape ( ) , print_height ) ;
const std : : vector < BoundingBoxf3 > & exclude_bounding_box = part_plate - > get_exclude_areas ( ) ;
Print * print = dynamic_cast < Print * > ( print_base ) ;
Slic3r : : GUI : : GCodeViewer gcode_viewer ;
gcode_viewer . init ( ConfigOptionMode : : comAdvanced , nullptr ) ;
gcode_viewer . load ( * gcode_result , * print , build_volume , exclude_bounding_box , false , ConfigOptionMode : : comAdvanced , false ) ;
std : : vector < std : : string > colors ;
if ( filament_color )
colors = filament_color - > values ;
gcode_viewer . refresh ( * gcode_result , colors ) ;
ThumbnailData * calibration_data = new ThumbnailData ( ) ;
const ThumbnailsParams calibration_params = { { } , false , true , true , true , i } ;
//BBS fixed size
const int cali_thumbnail_width = 2560 ;
const int cali_thumbnail_height = 2560 ;
gcode_viewer . render_calibration_thumbnail ( * calibration_data , cali_thumbnail_width , cali_thumbnail_height ,
calibration_params , partplate_list , opengl_mgr ) ;
//generate_calibration_thumbnail(*calibration_data, thumbnail_width, thumbnail_height, calibration_params);
//*plate_bboxes[index] = p->generate_first_layer_bbox();
calibration_thumbnails . push_back ( calibration_data ) ;
PlateBBoxData * plate_bbox = new PlateBBoxData ( ) ;
std : : vector < BBoxData > & id_bboxes = plate_bbox - > bbox_objs ;
BoundingBoxf bbox_all ;
auto seq_print = m_print_config . option < ConfigOptionEnum < PrintSequence > > ( " print_sequence " ) ;
if ( seq_print & & ( seq_print - > value = = PrintSequence : : ByObject ) )
plate_bbox - > is_seq_print = true ;
auto objects = print - > objects ( ) ;
auto orig = part_plate - > get_origin ( ) ;
Vec2d orig2d = { orig [ 0 ] , orig [ 1 ] } ;
for ( auto obj : objects )
{
BBoxData data ;
auto bb_scaled = obj - > get_first_layer_bbox ( data . area , data . layer_height , data . name ) ;
auto bb = unscaled ( bb_scaled ) ;
bb . min - = orig2d ;
bb . max - = orig2d ;
bbox_all . merge ( bb ) ;
data . area * = ( SCALING_FACTOR * SCALING_FACTOR ) ; // unscale area
data . id = obj - > id ( ) . id ;
data . bbox = { bb . min . x ( ) , bb . min . y ( ) , bb . max . x ( ) , bb . max . y ( ) } ;
id_bboxes . emplace_back ( std : : move ( data ) ) ;
}
plate_bbox - > bbox_all = { bbox_all . min . x ( ) , bbox_all . min . y ( ) , bbox_all . max . x ( ) , bbox_all . max . y ( ) } ;
plate_bboxes . push_back ( plate_bbox ) ;
}
}
}
BOOST_LOG_TRIVIAL ( info ) < < " will export 3mf to " < < export_3mf_file < < std : : endl ;
if ( ! this - > export_project ( & m_models [ 0 ] , export_3mf_file , plate_data_list , project_presets , thumbnails , calibration_thumbnails , plate_bboxes , & m_print_config ) )
{
release_PlateData_list ( plate_data_list ) ;
2022-11-02 12:42:37 +00:00
flush_and_exit ( CLI_EXPORT_3MF_ERROR ) ;
2022-07-15 15:37:19 +00:00
}
release_PlateData_list ( plate_data_list ) ;
for ( unsigned int i = 0 ; i < thumbnails . size ( ) ; i + + )
delete thumbnails [ i ] ;
for ( unsigned int i = 0 ; i < calibration_thumbnails . size ( ) ; i + + )
delete calibration_thumbnails [ i ] ;
for ( int i = 0 ; i < plate_bboxes . size ( ) ; i + + )
delete plate_bboxes [ i ] ;
}
//BBS: release glfw
if ( export_to_3mf ) {
glfwTerminate ( ) ;
}
2022-11-05 02:21:04 +00:00
# if defined(__linux__) || defined(__LINUX__)
g_cli_callback_mgr . stop ( ) ;
# endif
2022-07-15 15:37:19 +00:00
//BBS: flush logs
BOOST_LOG_TRIVIAL ( info ) < < __FUNCTION__ < < " , Finished " < < std : : endl ;
boost : : nowide : : cout . flush ( ) ;
boost : : nowide : : cerr . flush ( ) ;
return 0 ;
}
bool CLI : : setup ( int argc , char * * argv )
{
{
Slic3r : : set_logging_level ( 1 ) ;
const char * loglevel = boost : : nowide : : getenv ( " BBL_LOGLEVEL " ) ;
if ( loglevel ! = nullptr ) {
if ( loglevel [ 0 ] > = ' 0 ' & & loglevel [ 0 ] < = ' 9 ' & & loglevel [ 1 ] = = 0 )
set_logging_level ( loglevel [ 0 ] - ' 0 ' ) ;
else
boost : : nowide : : cerr < < " Invalid BBL_LOGLEVEL environment variable: " < < loglevel < < std : : endl ;
}
}
// Detect the operating system flavor after SLIC3R_LOGLEVEL is set.
detect_platform ( ) ;
# ifdef WIN32
// Notify user that a blacklisted DLL was injected into BambuStudio process (for example Nahimic, see GH #5573).
// We hope that if a DLL is being injected into a BambuStudio process, it happens at the very start of the application,
// thus we shall detect them now.
2022-10-21 13:28:18 +00:00
if ( BlacklistedLibraryCheck : : get_instance ( ) . perform_check ( ) ) {
std : : wstring text = L " Following DLLs have been injected into the BambuStudio process: \n \n " ;
text + = BlacklistedLibraryCheck : : get_instance ( ) . get_blacklisted_string ( ) ;
text + = L " \n \n "
L " BambuStudio is known to not run correctly with these DLLs injected. "
L " We suggest stopping or uninstalling these services if you experience "
L " crashes or unexpected behaviour while using BambuStudio. \n "
L " For example, ASUS Sonic Studio injects a Nahimic driver, which makes BambuStudio "
L " to crash on a secondary monitor " ;
MessageBoxW ( NULL , text . c_str ( ) , L " Warning " /*L"Incopatible library found"*/ , MB_OK ) ;
}
2022-07-15 15:37:19 +00:00
# endif
// See Invoking prusa-slicer from $PATH environment variable crashes #5542
// boost::filesystem::path path_to_binary = boost::filesystem::system_complete(argv[0]);
boost : : filesystem : : path path_to_binary = boost : : dll : : program_location ( ) ;
// Path from the Slic3r binary to its resources.
# ifdef __APPLE__
// The application is packed in the .dmg archive as 'Slic3r.app/Contents/MacOS/Slic3r'
// The resources are packed to 'Slic3r.app/Contents/Resources'
boost : : filesystem : : path path_resources = boost : : filesystem : : canonical ( path_to_binary ) . parent_path ( ) / " ../Resources " ;
# elif defined _WIN32
// The application is packed in the .zip archive in the root,
// The resources are packed to 'resources'
// Path from Slic3r binary to resources:
boost : : filesystem : : path path_resources = path_to_binary . parent_path ( ) / " resources " ;
# elif defined SLIC3R_FHS
// The application is packaged according to the Linux Filesystem Hierarchy Standard
// Resources are set to the 'Architecture-independent (shared) data', typically /usr/share or /usr/local/share
boost : : filesystem : : path path_resources = SLIC3R_FHS_RESOURCES ;
# else
// The application is packed in the .tar.bz archive (or in AppImage) as 'bin/slic3r',
// The resources are packed to 'resources'
// Path from Slic3r binary to resources:
boost : : filesystem : : path path_resources = boost : : filesystem : : canonical ( path_to_binary ) . parent_path ( ) / " ../resources " ;
# endif
set_resources_dir ( path_resources . string ( ) ) ;
set_var_dir ( ( path_resources / " images " ) . string ( ) ) ;
set_local_dir ( ( path_resources / " i18n " ) . string ( ) ) ;
set_sys_shapes_dir ( ( path_resources / " shapes " ) . string ( ) ) ;
// Parse all command line options into a DynamicConfig.
// If any option is unsupported, print usage and abort immediately.
t_config_option_keys opt_order ;
if ( ! m_config . read_cli ( argc , argv , & m_input_files , & opt_order ) ) {
// Separate error message reported by the CLI parser from the help.
boost : : nowide : : cerr < < std : : endl ;
this - > print_help ( ) ;
return false ;
}
// Parse actions and transform options.
for ( auto const & opt_key : opt_order ) {
if ( cli_actions_config_def . has ( opt_key ) )
m_actions . emplace_back ( opt_key ) ;
else if ( cli_transform_config_def . has ( opt_key ) )
m_transforms . emplace_back ( opt_key ) ;
}
# if !BBL_RELEASE_TO_PUBLIC
{
const ConfigOptionInt * opt_loglevel = m_config . opt < ConfigOptionInt > ( " debug " ) ;
if ( opt_loglevel ! = 0 )
set_logging_level ( opt_loglevel - > value ) ;
}
# endif
//FIXME Validating at this stage most likely does not make sense, as the config is not fully initialized yet.
std : : string validity = m_config . validate ( ) ;
// Initialize with defaults.
for ( const t_optiondef_map * options : { & cli_actions_config_def . options , & cli_transform_config_def . options , & cli_misc_config_def . options } )
for ( const t_optiondef_map : : value_type & optdef : * options )
m_config . option ( optdef . first , true ) ;
//set_data_dir(m_config.opt_string("datadir"));
//FIXME Validating at this stage most likely does not make sense, as the config is not fully initialized yet.
if ( ! validity . empty ( ) ) {
boost : : nowide : : cerr < < " error: " < < validity < < std : : endl ;
return false ;
}
return true ;
}
void CLI : : print_help ( bool include_print_options , PrinterTechnology printer_technology ) const
{
boost : : nowide : : cout
2022-11-05 02:21:04 +00:00
< < SLIC3R_APP_KEY < < " - " < < SLIC3R_VERSION < < " : "
2022-07-15 15:37:19 +00:00
< < std : : endl
< < " Usage: bambu-studio [ OPTIONS ] [ file.3mf/file.stl ... ] " < < std : : endl
< < std : : endl
< < " OPTIONS: " < < std : : endl ;
cli_misc_config_def . print_cli_help ( boost : : nowide : : cout , false ) ;
cli_transform_config_def . print_cli_help ( boost : : nowide : : cout , false ) ;
cli_actions_config_def . print_cli_help ( boost : : nowide : : cout , false ) ;
boost : : nowide : : cout
< < std : : endl
< < " Print settings priorites: " < < std : : endl
< < " \t 1) setting values from the command line (highest priority) " < < std : : endl
< < " \t 2) setting values loaded with --load_settings and --load_filaments " < < std : : endl
< < " \t 3) setting values loaded from 3mf(lowest priority) " < < std : : endl ;
/*if (include_print_options) {
boost : : nowide : : cout < < std : : endl ;
print_config_def . print_cli_help ( boost : : nowide : : cout , true , [ printer_technology ] ( const ConfigOptionDef & def )
{ return printer_technology = = ptAny | | def . printer_technology = = ptAny | | printer_technology = = def . printer_technology ; } ) ;
} else {
boost : : nowide : : cout
< < std : : endl
< < " Run --help-fff / --help-sla to see the full listing of print options. " < < std : : endl ;
} */
}
bool CLI : : export_models ( IO : : ExportFormat format )
{
for ( Model & model : m_models ) {
const std : : string path = this - > output_filepath ( model , format ) ;
bool success = false ;
switch ( format ) {
//case IO::AMF: success = Slic3r::store_amf(path.c_str(), &model, nullptr, false); break;
case IO : : OBJ : success = Slic3r : : store_obj ( path . c_str ( ) , & model ) ; break ;
case IO : : STL : success = Slic3r : : store_stl ( path . c_str ( ) , & model , true ) ; break ;
//BBS: use bbs 3mf instead of original
//case IO::TMF: success = Slic3r::store_bbs_3mf(path.c_str(), &model, nullptr, false); break;
default : assert ( false ) ; break ;
}
if ( success )
BOOST_LOG_TRIVIAL ( info ) < < " Model exported to " < < path < < std : : endl ;
else {
boost : : nowide : : cerr < < " Model export to " < < path < < " failed " < < std : : endl ;
return false ;
}
}
return true ;
}
//BBS: add export_project function
bool CLI : : export_project ( Model * model , std : : string & path , PlateDataPtrs & partplate_data ,
std : : vector < Preset * > & project_presets , std : : vector < ThumbnailData * > & thumbnails , std : : vector < ThumbnailData * > & calibration_thumbnails , std : : vector < PlateBBoxData * > & plate_bboxes , const DynamicPrintConfig * config )
{
//const std::string path = this->output_filepath(*model, IO::TMF);
bool success = false ;
StoreParams store_params ;
store_params . path = path . c_str ( ) ;
store_params . model = model ;
store_params . plate_data_list = partplate_data ;
store_params . project_presets = project_presets ;
store_params . config = ( DynamicPrintConfig * ) config ;
store_params . thumbnail_data = thumbnails ;
store_params . calibration_thumbnail_data = calibration_thumbnails ;
store_params . id_bboxes = plate_bboxes ;
2022-10-31 09:48:48 +00:00
store_params . strategy = SaveStrategy : : Silence | SaveStrategy : : WithGcode | SaveStrategy : : SplitModel ;
2022-07-15 15:37:19 +00:00
success = Slic3r : : store_bbs_3mf ( store_params ) ;
if ( success )
BOOST_LOG_TRIVIAL ( info ) < < " Project exported to " < < path < < std : : endl ;
else {
boost : : nowide : : cerr < < " Project export to " < < path < < " failed " < < std : : endl ;
return false ;
}
return true ;
}
std : : string CLI : : output_filepath ( const Model & model , IO : : ExportFormat format ) const
{
std : : string ext ;
switch ( format ) {
case IO : : AMF : ext = " .zip.amf " ; break ;
case IO : : OBJ : ext = " .obj " ; break ;
case IO : : STL : ext = " .stl " ; break ;
case IO : : TMF : ext = " .3mf " ; break ;
default : assert ( false ) ; break ;
} ;
auto proposed_path = boost : : filesystem : : path ( model . propose_export_file_name_and_path ( ext ) ) ;
// use --output when available
std : : string cmdline_param = m_config . opt_string ( " output " ) ;
if ( ! cmdline_param . empty ( ) ) {
// if we were supplied a directory, use it and append our automatically generated filename
boost : : filesystem : : path cmdline_path ( cmdline_param ) ;
if ( boost : : filesystem : : is_directory ( cmdline_path ) )
proposed_path = cmdline_path / proposed_path . filename ( ) ;
else
proposed_path = cmdline_param + ext ;
}
return proposed_path . string ( ) ;
}
//BBS: dump stack debug codes, don't delete currently
//#include <dbghelp.h>
//#pragma comment(lib, "version.lib")
//#pragma comment( lib, "dbghelp.lib" )
/*DWORD main_thread_id;
std : : string TraceStack ( )
{
static const int MAX_STACK_FRAMES = 16 ;
void * pStack [ MAX_STACK_FRAMES ] ;
HANDLE process = GetCurrentProcess ( ) ;
SymInitialize ( process , NULL , TRUE ) ;
WORD frames = CaptureStackBackTrace ( 0 , MAX_STACK_FRAMES , pStack , NULL ) ;
std : : ostringstream oss ;
oss < < " stack traceback: frames= " < < frames < < std : : endl ;
for ( WORD i = 0 ; i < frames ; + + i ) {
DWORD64 address = ( DWORD64 ) ( pStack [ i ] ) ;
DWORD64 displacementSym = 0 ;
char buffer [ sizeof ( SYMBOL_INFO ) + MAX_SYM_NAME * sizeof ( TCHAR ) ] ;
PSYMBOL_INFO pSymbol = ( PSYMBOL_INFO ) buffer ;
pSymbol - > SizeOfStruct = sizeof ( SYMBOL_INFO ) ;
pSymbol - > MaxNameLen = MAX_SYM_NAME ;
DWORD displacementLine = 0 ;
IMAGEHLP_LINE64 line ;
//SymSetOptions(SYMOPT_LOAD_LINES);
line . SizeOfStruct = sizeof ( IMAGEHLP_LINE64 ) ;
if ( SymFromAddr ( process , address , & displacementSym , pSymbol )
& & SymGetLineFromAddr64 ( process , address , & displacementLine , & line ) ) {
oss < < " \t " < < pSymbol - > Name < < " at " < < line . FileName < < " : " < < line . LineNumber < < " (0x " < < std : : hex < < pSymbol - > Address < < std : : dec < < " ) " < < std : : endl ;
}
else {
oss < < " \t error: " < < GetLastError ( ) < < std : : endl ;
}
}
return oss . str ( ) ;
}
LONG WINAPI VectoredExceptionHandler ( PEXCEPTION_POINTERS pExceptionInfo )
{
std : : ofstream f ;
DWORD cur_thread_id = GetCurrentThreadId ( ) ;
f . open ( " VectoredExceptionHandler.txt " , std : : ios : : out | std : : ios : : app ) ;
f < < " main thread id= " < < main_thread_id < < " , current thread_id= " < < cur_thread_id < < std : : endl ;
f < < std : : hex < < pExceptionInfo - > ExceptionRecord - > ExceptionCode < < std : : endl ;
f < < TraceStack ( ) ;
f . flush ( ) ;
f . close ( ) ;
return EXCEPTION_CONTINUE_SEARCH ;
} */
# if defined(_MSC_VER) || defined(__MINGW32__)
extern " C " {
2022-09-14 08:12:12 +00:00
__declspec ( dllexport ) int __stdcall bambustu_main ( int argc , wchar_t * * argv )
2022-07-15 15:37:19 +00:00
{
// Convert wchar_t arguments to UTF8.
std : : vector < std : : string > argv_narrow ;
std : : vector < char * > argv_ptrs ( argc + 1 , nullptr ) ;
for ( size_t i = 0 ; i < argc ; + + i )
argv_narrow . emplace_back ( boost : : nowide : : narrow ( argv [ i ] ) ) ;
for ( size_t i = 0 ; i < argc ; + + i )
argv_ptrs [ i ] = argv_narrow [ i ] . data ( ) ;
//BBS: register default exception handler
2022-07-22 09:46:10 +00:00
# if 1
2022-07-15 15:37:19 +00:00
SET_DEFULTER_HANDLER ( ) ;
# else
AddVectoredExceptionHandler ( 1 , CBaseException : : UnhandledExceptionFilter ) ;
# endif
// Call the UTF8 main.
return CLI ( ) . run ( argc , argv_ptrs . data ( ) ) ;
}
}
# else /* _MSC_VER */
int main ( int argc , char * * argv )
{
return CLI ( ) . run ( argc , argv ) ;
}
# endif /* _MSC_VER */