%module{Slic3r::XS};

#include <xsinit.h>
#include "slic3r/GUI/GLShader.hpp"
#include "slic3r/GUI/3DScene.hpp"

%name{Slic3r::GUI::_3DScene::GLShader} class GLShader {
    GLShader();
    ~GLShader();

    bool load_from_text(const char *fragment_shader, const char *vertex_shader);
    bool load_from_file(const char *fragment_shader, const char *vertex_shader);
    void release();

    int  get_attrib_location(const char *name) const;
    int  get_uniform_location(const char *name) const;

    bool set_uniform(const char *name, float value) const;

    void enable() const;
    void disable() const;

    int shader_program_id() const
        %code%{ RETVAL = THIS->shader_program_id; %};

    std::string last_error() const
        %code%{ RETVAL = THIS->last_error; %};
};

%name{Slic3r::GUI::_3DScene::GLVolume} class GLVolume {
    GLVolume();
    ~GLVolume();

    std::vector<double> color()
        %code%{ RETVAL.reserve(4); RETVAL.push_back(THIS->color[0]); RETVAL.push_back(THIS->color[1]); RETVAL.push_back(THIS->color[2]); RETVAL.push_back(THIS->color[3]); %};

    int                 select_group_id()
        %code%{ RETVAL = THIS->select_group_id; %};
    int                 drag_group_id()
        %code%{ RETVAL = THIS->drag_group_id; %};
    int                 selected()
        %code%{ RETVAL = THIS->selected; %};
    void                set_selected(int i)
        %code%{ THIS->selected = i; %};
    int                 hover()
        %code%{ RETVAL = THIS->hover; %};
    void                set_hover(int i)
        %code%{ THIS->hover = i; %};
    int                 zoom_to_volumes()
        %code%{ RETVAL = THIS->zoom_to_volumes; %};

    void set_layer_height_texture_data(unsigned int texture_id, unsigned int shader_id, PrintObject* print_object, float z_cursor_relative, float edit_band_width);
    void reset_layer_height_texture_data();

    int                 object_idx() const;
    int                 volume_idx() const;
    int                 instance_idx() const;
    Clone<Pointf3>      origin() const
        %code%{ RETVAL = THIS->get_origin(); %};
    void                translate(double x, double y, double z)
        %code%{
                Pointf3 o = THIS->get_origin();
                o.translate(x, y, z);
                THIS->set_origin(o);
             %};
    Clone<BoundingBoxf3> bounding_box() const
        %code%{ RETVAL = THIS->bounding_box; %};
    Clone<BoundingBoxf3> transformed_bounding_box() const;

    bool                empty() const;
    bool                indexed() const;

    void                render() const;

    bool                has_layer_height_texture();
    int                 layer_height_texture_width();
    int                 layer_height_texture_height();
    int                 layer_height_texture_cells();
    void*               layer_height_texture_data_ptr_level0();
    void*               layer_height_texture_data_ptr_level1();
    double              layer_height_texture_z_to_row_id() const; 
    void                generate_layer_height_texture(PrintObject *print_object, bool force);
};


%name{Slic3r::GUI::_3DScene::GLVolume::Collection} class GLVolumeCollection {
    GLVolumeCollection();
    ~GLVolumeCollection();

    std::vector<int> load_object(ModelObject *object, int obj_idx, std::vector<int> instance_idxs, std::string color_by, std::string select_by, std::string drag_by, bool use_VBOs);

    int load_wipe_tower_preview(int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs);

    void erase()
        %code{% THIS->clear(); %};

    int count()
        %code{% RETVAL = THIS->volumes.size(); %};
        
    void set_range(double low, double high);

    void render_VBOs() const;
    void render_legacy() const;
    void finalize_geometry(bool use_VBOs);
    void release_geometry();

    void set_print_box(float min_x, float min_y, float min_z, float max_x, float max_y, float max_z);
    
    void reset_outside_state();    
    void update_colors_by_extruder(DynamicPrintConfig* config);

    bool move_volume_up(int idx)
        %code%{ 
            if (idx > 0 && idx < int(THIS->volumes.size())) {
                std::swap(THIS->volumes[idx-1], THIS->volumes[idx]);
                std::swap(THIS->volumes[idx-1]->composite_id,    THIS->volumes[idx]->composite_id);
                std::swap(THIS->volumes[idx-1]->select_group_id, THIS->volumes[idx]->select_group_id);
                std::swap(THIS->volumes[idx-1]->drag_group_id,   THIS->volumes[idx]->drag_group_id);
                RETVAL = true;
            } else
                RETVAL = false;
        %};
    bool move_volume_down(int idx)
        %code%{ 
            if (idx >= 0 && idx + 1 < int(THIS->volumes.size())) {
                std::swap(THIS->volumes[idx+1], THIS->volumes[idx]);
                std::swap(THIS->volumes[idx+1]->composite_id,    THIS->volumes[idx]->composite_id);
                std::swap(THIS->volumes[idx+1]->select_group_id, THIS->volumes[idx]->select_group_id);
                std::swap(THIS->volumes[idx+1]->drag_group_id,   THIS->volumes[idx]->drag_group_id);
                RETVAL = true;
            } else
                RETVAL = false;
        %};

%{

SV*
GLVolumeCollection::arrayref()
    CODE:
        AV* av = newAV();
        av_fill(av, THIS->volumes.size()-1);
        int i = 0;
        for (GLVolume *v : THIS->volumes) {
            av_store(av, i++, perl_to_SV_ref(*v));
        }
        RETVAL = newRV_noinc((SV*)av);
    OUTPUT:
        RETVAL

%}
};

%package{Slic3r::GUI::_3DScene};
%{

std::string
get_gl_info(format_as_html, extensions)
        bool format_as_html;
        bool extensions;
    CODE:
        RETVAL = _3DScene::get_gl_info(format_as_html, extensions);
    OUTPUT:
        RETVAL

bool
use_VBOs()
    CODE:
        RETVAL = _3DScene::use_VBOs();
    OUTPUT:
        RETVAL

bool
add_canvas(canvas)
        SV *canvas;
    CODE:
        RETVAL = _3DScene::add_canvas((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
    OUTPUT:
        RETVAL

bool
remove_canvas(canvas)
        SV *canvas;
    CODE:
        RETVAL = _3DScene::remove_canvas((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
    OUTPUT:
        RETVAL

void
remove_all_canvases()
    CODE:
        _3DScene::remove_all_canvases();

void
set_as_dirty(canvas)
        SV *canvas;
    CODE:
        _3DScene::set_as_dirty((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));

unsigned int
get_volumes_count(canvas)
        SV *canvas;
    CODE:
        RETVAL = _3DScene::get_volumes_count((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
    OUTPUT:
        RETVAL

void
reset_volumes(canvas)
        SV *canvas;
    CODE:
        _3DScene::reset_volumes((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));

void
deselect_volumes(canvas)
        SV *canvas;
    CODE:
        _3DScene::deselect_volumes((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));

void
select_volume(canvas, id)
        SV           *canvas;
        unsigned int id;
    CODE:
        _3DScene::select_volume((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), id);

void
update_volumes_selection(canvas, selections)
        SV               *canvas;
        std::vector<int> selections;
    CODE:
        _3DScene::update_volumes_selection((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), selections);

int
check_volumes_outside_state(canvas, config)
        SV                 *canvas;
        DynamicPrintConfig *config;
    CODE:
        RETVAL = _3DScene::check_volumes_outside_state((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), config);
    OUTPUT:
        RETVAL

bool
move_volume_up(canvas, id)
        SV           *canvas;
        unsigned int id;
    CODE:
        RETVAL = _3DScene::move_volume_up((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), id);
    OUTPUT:
        RETVAL

bool
move_volume_down(canvas, id)
        SV           *canvas;
        unsigned int id;
    CODE:
        RETVAL = _3DScene::move_volume_down((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), id);
    OUTPUT:
        RETVAL

void
set_objects_selections(canvas, selections)
        SV               *canvas;
        std::vector<int> selections;
    CODE:
        _3DScene::set_objects_selections((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), selections);

void
set_config(canvas, config)
        SV                 *canvas;
        DynamicPrintConfig *config;
    CODE:
        _3DScene::set_config((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), config);

void
set_print(canvas, print)
        SV    *canvas;
        Print *print;
    CODE:
        _3DScene::set_print((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), print);

void
set_model(canvas, model)
        SV    *canvas;
        Model *model;
    CODE:
        _3DScene::set_model((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), model);

void
set_bed_shape(canvas, shape)
        SV      *canvas;
        Pointfs shape;
    CODE:
        _3DScene::set_bed_shape((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), shape);

void
set_auto_bed_shape(canvas)
        SV *canvas;
    CODE:
        _3DScene::set_auto_bed_shape((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));

Clone<BoundingBoxf3>
get_volumes_bounding_box(canvas)
        SV *canvas;
    CODE:
        RETVAL = _3DScene::get_volumes_bounding_box((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
    OUTPUT:
        RETVAL

void
set_axes_length(canvas, length)
        SV    *canvas;
        float length;
    CODE:
        _3DScene::set_axes_length((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), length);

void
set_cutting_plane(canvas, z, polygons)
        SV         *canvas;
        float      z;
        ExPolygons polygons;
    CODE:
        _3DScene::set_cutting_plane((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), z, polygons);

void
set_color_by(canvas, value)
        SV          *canvas;
        std::string value;
    CODE:
        _3DScene::set_color_by((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), value);

void
set_select_by(canvas, value)
        SV          *canvas;
        std::string value;
    CODE:
        _3DScene::set_select_by((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), value);

void
set_drag_by(canvas, value)
        SV          *canvas;
        std::string value;
    CODE:
        _3DScene::set_drag_by((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), value);

bool
is_layers_editing_enabled(canvas)
        SV *canvas;
    CODE:
        RETVAL = _3DScene::is_layers_editing_enabled((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
    OUTPUT:
        RETVAL

bool
is_layers_editing_allowed(canvas)
        SV *canvas;
    CODE:
        RETVAL = _3DScene::is_layers_editing_allowed((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
    OUTPUT:
        RETVAL

bool
is_shader_enabled(canvas)
        SV *canvas;
    CODE:
        RETVAL = _3DScene::is_shader_enabled((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
    OUTPUT:
        RETVAL

bool
is_reload_delayed(canvas)
        SV *canvas;
    CODE:
        RETVAL = _3DScene::is_reload_delayed((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
    OUTPUT:
        RETVAL

void
enable_layers_editing(canvas, enable)
        SV   *canvas;
        bool enable;
    CODE:
        _3DScene::enable_layers_editing((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), enable);
    
void
enable_warning_texture(canvas, enable)
        SV   *canvas;
        bool enable;
    CODE:
        _3DScene::enable_warning_texture((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), enable);
    
void
enable_legend_texture(canvas, enable)
        SV   *canvas;
        bool enable;
    CODE:
        _3DScene::enable_legend_texture((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), enable);

void
enable_picking(canvas, enable)
        SV   *canvas;
        bool enable;
    CODE:
        _3DScene::enable_picking((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), enable);

void
enable_moving(canvas, enable)
        SV   *canvas;
        bool enable;
    CODE:
        _3DScene::enable_moving((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), enable);

void
enable_gizmos(canvas, enable)
        SV   *canvas;
        bool enable;
    CODE:
        _3DScene::enable_gizmos((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), enable);

void
enable_shader(canvas, enable)
        SV   *canvas;
        bool enable;
    CODE:
        _3DScene::enable_shader((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), enable);

void
enable_force_zoom_to_bed(canvas, enable)
        SV   *canvas;
        bool enable;
    CODE:
        _3DScene::enable_force_zoom_to_bed((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), enable);

void
allow_multisample(canvas, allow)
        SV   *canvas;
        bool allow;
    CODE:
        _3DScene::allow_multisample((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), allow);

void
zoom_to_bed(canvas)
        SV *canvas;
    CODE:
        _3DScene::zoom_to_bed((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));

void
zoom_to_volumes(canvas)
        SV *canvas;
    CODE:
        _3DScene::zoom_to_volumes((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
    
void
select_view(canvas, direction)
        SV          *canvas;
        std::string direction;
    CODE:
        _3DScene::select_view((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), direction);

void
set_viewport_from_scene(canvas, other)
        SV *canvas;
        SV *other;
    CODE:
        _3DScene::set_viewport_from_scene((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (wxGLCanvas*)wxPli_sv_2_object(aTHX_ other, "Wx::GLCanvas"));

void
update_volumes_colors_by_extruder(canvas)
        SV *canvas;
    CODE:
        _3DScene::update_volumes_colors_by_extruder((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));

void
update_gizmos_data(canvas)
        SV *canvas;
    CODE:
        _3DScene::update_gizmos_data((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));

void
render(canvas)
        SV *canvas;
    CODE:
        _3DScene::render((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));

std::vector<double>
get_current_print_zs(canvas, active_only)
        SV   *canvas;
        bool active_only;
    CODE:
        RETVAL = _3DScene::get_current_print_zs((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), active_only);
    OUTPUT:
        RETVAL

void
set_toolpaths_range(canvas, low, high)
        SV *canvas;
        double low;
        double high;
    CODE:
        _3DScene::set_toolpaths_range((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), low, high);

void
register_on_viewport_changed_callback(canvas, callback)
        SV *canvas;
        SV *callback;
    CODE:
        _3DScene::register_on_viewport_changed_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);

void
register_on_double_click_callback(canvas, callback)
        SV *canvas;
        SV *callback;
    CODE:
        _3DScene::register_on_double_click_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);

void
register_on_right_click_callback(canvas, callback)
        SV *canvas;
        SV *callback;
    CODE:
        _3DScene::register_on_right_click_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);

void
register_on_select_object_callback(canvas, callback)
        SV *canvas;
        SV *callback;
    CODE:
        _3DScene::register_on_select_object_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);

void
register_on_model_update_callback(canvas, callback)
        SV *canvas;
        SV *callback;
    CODE:
        _3DScene::register_on_model_update_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);

void
register_on_remove_object_callback(canvas, callback)
        SV *canvas;
        SV *callback;
    CODE:
        _3DScene::register_on_remove_object_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);

void
register_on_arrange_callback(canvas, callback)
        SV *canvas;
        SV *callback;
    CODE:
        _3DScene::register_on_arrange_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);

void
register_on_rotate_object_left_callback(canvas, callback)
        SV *canvas;
        SV *callback;
    CODE:
        _3DScene::register_on_rotate_object_left_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);

void
register_on_rotate_object_right_callback(canvas, callback)
        SV *canvas;
        SV *callback;
    CODE:
        _3DScene::register_on_rotate_object_right_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);
        
void
register_on_scale_object_uniformly_callback(canvas, callback)
        SV *canvas;
        SV *callback;
    CODE:
        _3DScene::register_on_scale_object_uniformly_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);

void
register_on_increase_objects_callback(canvas, callback)
        SV *canvas;
        SV *callback;
    CODE:
        _3DScene::register_on_increase_objects_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);

void
register_on_decrease_objects_callback(canvas, callback)
        SV *canvas;
        SV *callback;
    CODE:
        _3DScene::register_on_decrease_objects_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);

void
register_on_instance_moved_callback(canvas, callback)
        SV *canvas;
        SV *callback;
    CODE:
        _3DScene::register_on_instance_moved_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);

void
register_on_wipe_tower_moved_callback(canvas, callback)
        SV *canvas;
        SV *callback;
    CODE:
        _3DScene::register_on_wipe_tower_moved_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);

void
register_on_enable_action_buttons_callback(canvas, callback)
        SV *canvas;
        SV *callback;
    CODE:
        _3DScene::register_on_enable_action_buttons_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);

void
register_on_gizmo_scale_uniformly_callback(canvas, callback)
        SV *canvas;
        SV *callback;
    CODE:
        _3DScene::register_on_gizmo_scale_uniformly_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);

void
register_on_gizmo_rotate_callback(canvas, callback)
        SV *canvas;
        SV *callback;
    CODE:
        _3DScene::register_on_gizmo_rotate_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);

void
register_on_update_geometry_info_callback(canvas, callback)
        SV *canvas;
        SV *callback;
    CODE:
        _3DScene::register_on_update_geometry_info_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);
             
void
reset_legend_texture()
    CODE:
        _3DScene::reset_legend_texture();

std::vector<int>
load_model_object(canvas, model_object, obj_idx, instance_idxs)
        SV               *canvas;
        ModelObject      *model_object;
        int              obj_idx;
        std::vector<int> instance_idxs;
    CODE:
        RETVAL = _3DScene::load_object((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), model_object, obj_idx, instance_idxs);
    OUTPUT:
        RETVAL

std::vector<int>
load_model(canvas, model, obj_idx)
        SV               *canvas;
        Model            *model;
        int              obj_idx;
    CODE:
        RETVAL = _3DScene::load_object((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), model, obj_idx);
    OUTPUT:
        RETVAL

void
reload_scene(canvas, force)
        SV   *canvas;
        bool force;
    CODE:
        _3DScene::reload_scene((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), force);

void
load_print_toolpaths(canvas)
        SV *canvas;
    CODE:
        _3DScene::load_print_toolpaths((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));

void 
load_print_object_toolpaths(canvas, print_object, tool_colors)
        SV                       *canvas;
        PrintObject              *print_object;
        std::vector<std::string> tool_colors;
    CODE:
        _3DScene::load_print_object_toolpaths((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), print_object, tool_colors);

void
load_wipe_tower_toolpaths(canvas, tool_colors)
        SV                       *canvas;
        std::vector<std::string> tool_colors;
    CODE:
        _3DScene::load_wipe_tower_toolpaths((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), tool_colors);

void 
load_gcode_preview(canvas, preview_data, str_tool_colors)
        SV                       *canvas;
        GCodePreviewData         *preview_data;
        std::vector<std::string> str_tool_colors;
    CODE:
        _3DScene::load_gcode_preview((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), preview_data, str_tool_colors);
        
%}
