Skip to content

Commit

Permalink
NP- 327 emscripten communication (#2131)
Browse files Browse the repository at this point in the history
  • Loading branch information
HellAholic authored Aug 30, 2024
2 parents 1b78d4f + b719a42 commit 0270dce
Show file tree
Hide file tree
Showing 18 changed files with 317 additions and 104 deletions.
24 changes: 23 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ set(engine_SRCS # Except main.cpp.
src/communication/ArcusCommunication.cpp
src/communication/ArcusCommunicationPrivate.cpp
src/communication/CommandLine.cpp
src/communication/EmscriptenCommunication.cpp
src/communication/Listener.cpp

src/infill/ImageBasedDensityProvider.cpp
Expand Down Expand Up @@ -270,7 +271,28 @@ endif ()

if (CMAKE_CXX_PLATFORM_ID STREQUAL "emscripten")
message(STATUS "Building for Emscripten")
target_link_options(_CuraEngine PUBLIC -Wno-unused-command-line-argument -sINVOKE_RUN=0 -sEXPORT_NAME=CuraEngine -sEXPORTED_RUNTIME_METHODS=[callMain,FS] -sFORCE_FILESYSTEM=1 -sALLOW_MEMORY_GROWTH=1 -sEXPORT_ES6=1 -sMODULARIZE=1 -sSINGLE_FILE=1 -sENVIRONMENT=worker -sERROR_ON_UNDEFINED_SYMBOLS=0 -lembind --embind-emit-tsd CuraEngine.d.ts)
target_link_options(_CuraEngine
PUBLIC
"SHELL:-sINVOKE_RUN=0"
"SHELL:-sEXPORT_NAME=CuraEngine"
"SHELL:-sEXPORTED_RUNTIME_METHODS=[callMain,FS]"
"SHELL:-sFORCE_FILESYSTEM=1"
"SHELL:-sALLOW_MEMORY_GROWTH=1"
"SHELL:-sEXPORT_ES6=1"
"SHELL:-sMODULARIZE=1"
"SHELL:-sSINGLE_FILE=1"
"SHELL:-sENVIRONMENT=web"
"SHELL:-sERROR_ON_UNDEFINED_SYMBOLS=0"
"SHELL:-sWASM_BIGINT=1"
"SHELL:-sSTACK_SIZE=196608"
$<$<CONFIG:Debug>:SHELL:-sASSERTIONS=2>
$<$<CONFIG:Debug>:SHELL:-sSAFE_HEAP=1>
$<$<CONFIG:Debug>:SHELL:-sSTACK_OVERFLOW_CHECK=2>
$<$<CONFIG:Debug>:SHELL:-g3>
$<$<CONFIG:Debug>:SHELL:-gsource-map>
"SHELL:-lembind"
"SHELL:--embind-emit-tsd CuraEngine.d.ts"
)
endif ()

target_link_libraries(CuraEngine PRIVATE
Expand Down
5 changes: 3 additions & 2 deletions include/Application.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <cassert>
#include <cstddef>
#include <memory>
#include <string>

#include "utils/NoCopy.h"
Expand Down Expand Up @@ -38,14 +39,14 @@ class Application : NoCopy
* can assume that it is safe to access this without checking whether it is
* initialised.
*/
Communication* communication_ = nullptr;
std::shared_ptr<Communication> communication_;

/*
* \brief The slice that is currently ongoing.
*
* If no slice has started yet, this will be a nullptr.
*/
Slice* current_slice_ = nullptr;
std::shared_ptr<Slice> current_slice_;

/*!
* \brief ThreadPool with lifetime tied to Application
Expand Down
13 changes: 6 additions & 7 deletions include/communication/CommandLine.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ using container_setting_map = std::unordered_map<std::string, setting_map>;
class CommandLine : public Communication
{
public:
CommandLine() = default;

/*
* \brief Construct a new communicator that interprets the command line to
* start a slice.
Expand Down Expand Up @@ -155,18 +157,15 @@ class CommandLine : public Communication
*/
void sliceNext() override;

private:
#ifdef __EMSCRIPTEN__
std::string progressHandler;
#endif

std::vector<std::filesystem::path> search_directories_;

protected:
/*
* \brief The command line arguments that the application was called with.
*/
std::vector<std::string> arguments_;

private:
std::vector<std::filesystem::path> search_directories_;

/*
* The last progress update that we output to stdcerr.
*/
Expand Down
65 changes: 65 additions & 0 deletions include/communication/EmscriptenCommunication.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright (c) 2024 UltiMaker
// CuraEngine is released under the terms of the AGPLv3 or higher

#ifndef EMSCRIPTENCOMMUNICATION_H
#define EMSCRIPTENCOMMUNICATION_H
#ifdef __EMSCRIPTEN__

#include "communication/CommandLine.h"

namespace cura
{

/**
* \class EmscriptenCommunication
* \brief A class for handling communication in an Emscripten environment.
*
* This class extends the CommandLine class and provides specific implementations
* for sending progress and handling slice information in an Emscripten environment.
*/
class EmscriptenCommunication : public CommandLine
{
private:
std::string progress_handler_; ///< Handler for progress messages.
std::string gcode_header_handler_; ///< Handler for getting the GCode handler.
std::string slice_info_handler_; ///< Handler for slice information messages.

/**
* \brief Creates a message containing slice information.
* \return A string containing the slice information message.
*/
[[nodiscard]] static std::string createSliceInfoMessage();

public:
/**
* \brief Constructor for EmscriptenCommunication.
* \param arguments A vector of strings containing the command line arguments.
*/
EmscriptenCommunication(const std::vector<std::string>& arguments);

/**
* \brief Sends the progress of the current operation.
* \param progress A double representing the progress percentage.
*/
void sendProgress(double progress) const override;

/**
* \brief Sends GcodeHeader
*/
void sendGCodePrefix(const std::string& prefix) const override;

/**
* \brief Initiates the slicing of the next item.
*/
void sliceNext() override;

bool isSequential() const override
{
return false;
}
};

} // namespace cura

#endif // __EMSCRIPTEN__
#endif // EMSCRIPTENCOMMUNICATION_H
27 changes: 27 additions & 0 deletions include/utils/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
#include <ctype.h>
#include <sstream> // ostringstream

#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/ostream_iterator.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include <spdlog/spdlog.h>

namespace cura
Expand All @@ -27,6 +30,30 @@ static inline int stringcasecompare(const char* a, const char* b)
return *a - *b;
}

// Convert string to base64 string.
// This function is useful to forward string through javascript even if they contain any special strings
//
[[maybe_unused]] static std::string convertTobase64(const std::string& input)
{
using namespace boost::archive::iterators;
// prepare the stream to hold the encoded data
std::stringstream output;

// encode data
typedef base64_from_binary<transform_width<std::string::const_iterator, 6, 8>> base64_enc;
std::copy(base64_enc(input.begin()), base64_enc(input.end()), ostream_iterator<char>(output));

// Retrieve the encoded string
std::string output_encoded = output.str();

// ensure padding if needed
size_t num = (3 - input.length() % 3) % 3;
for (size_t i = 0; i < num; i++)
{
output_encoded.push_back('=');
}
return output_encoded;
}
/*!
* Efficient conversion of micron integer type to millimeter string.
*
Expand Down
12 changes: 8 additions & 4 deletions src/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/spdlog.h>

#include "Slice.h"
#include "communication/ArcusCommunication.h" //To connect via Arcus to the front-end.
#include "communication/CommandLine.h" //To use the command line to slice stuff.
#include "communication/EmscriptenCommunication.h" // To use Emscripten to slice stuff.
#include "progress/Progress.h"
#include "utils/ThreadPool.h"
#include "utils/string.h" //For stringcasecompare.
Expand All @@ -45,7 +47,6 @@ Application::Application()

Application::~Application()
{
delete communication_;
delete thread_pool_;
}

Expand Down Expand Up @@ -100,7 +101,7 @@ void Application::connect()
}
}

ArcusCommunication* arcus_communication = new ArcusCommunication();
auto arcus_communication = std::make_shared<ArcusCommunication>();
arcus_communication->connect(ip, port);
communication_ = arcus_communication;
}
Expand Down Expand Up @@ -214,8 +215,11 @@ void Application::slice()
{
arguments.emplace_back(argv_[argument_index]);
}

communication_ = new CommandLine(arguments);
#ifdef __EMSCRIPTEN__
communication_ = std::make_shared<EmscriptenCommunication>(arguments);
#else
communication_ = std::make_shared<CommandLine>(arguments);
#endif
}

void Application::run(const size_t argc, char** argv)
Expand Down
4 changes: 2 additions & 2 deletions src/LayerPlan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1982,7 +1982,7 @@ void LayerPlan::processFanSpeedAndMinimalLayerTime(Point2LL starting_position)

void LayerPlan::writeGCode(GCodeExport& gcode)
{
Communication* communication = Application::getInstance().communication_;
auto communication = Application::getInstance().communication_;
communication->setLayerForSend(layer_nr_);
communication->sendCurrentPosition(gcode.getPositionXY());
gcode.setLayerNr(layer_nr_);
Expand Down Expand Up @@ -2544,7 +2544,7 @@ bool LayerPlan::writePathWithCoasting(

Point2LL prev_pt = gcode.getPositionXY();
{ // write normal extrude path:
Communication* communication = Application::getInstance().communication_;
auto communication = Application::getInstance().communication_;
for (size_t point_idx = 0; point_idx <= point_idx_before_start; point_idx++)
{
auto [_, time] = extruder_plan.getPointToPointTime(prev_pt, path.points[point_idx], path);
Expand Down
16 changes: 8 additions & 8 deletions src/communication/ArcusCommunication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ void ArcusCommunication::sliceNext()

// Handle the main Slice message.
const cura::proto::Slice* slice_message = dynamic_cast<cura::proto::Slice*>(message.get()); // See if the message is of the message type Slice. Returns nullptr otherwise.
if (! slice_message)
if (slice_message == nullptr)
{
return;
}
Expand Down Expand Up @@ -553,15 +553,15 @@ void ArcusCommunication::sliceNext()
}
#endif // ENABLE_PLUGINS

Slice slice(slice_message->object_lists().size());
Application::getInstance().current_slice_ = &slice;
auto slice = std::make_shared<Slice>(slice_message->object_lists().size());
Application::getInstance().current_slice_ = slice;

private_data->readGlobalSettingsMessage(slice_message->global_settings());
private_data->readExtruderSettingsMessage(slice_message->extruders());

// Broadcast the settings to the plugins
slots::instance().broadcast<plugins::v0::SlotID::SETTINGS_BROADCAST>(*slice_message);
const size_t extruder_count = slice.scene.extruders.size();
const size_t extruder_count = slice->scene.extruders.size();

// For each setting, register what extruder it should be obtained from (if this is limited to an extruder).
for (const cura::proto::SettingExtruder& setting_extruder : slice_message->limit_to_extruder())
Expand All @@ -572,8 +572,8 @@ void ArcusCommunication::sliceNext()
// If it's -1 it should be ignored as per the spec. Let's also ignore it if it's beyond range.
continue;
}
ExtruderTrain& extruder = slice.scene.extruders[setting_extruder.extruder()];
slice.scene.limit_to_extruder.emplace(setting_extruder.name(), &extruder);
ExtruderTrain& extruder = slice->scene.extruders[setting_extruder.extruder()];
slice->scene.limit_to_extruder.emplace(setting_extruder.name(), &extruder);
}

// Load all mesh groups, meshes and their settings.
Expand All @@ -584,9 +584,9 @@ void ArcusCommunication::sliceNext()
}
spdlog::debug("Done reading Slice message.");

if (! slice.scene.mesh_groups.empty())
if (! slice->scene.mesh_groups.empty())
{
slice.compute();
slice->compute();
FffProcessor::getInstance()->finalize();
flushGCode();
sendPrintTimeMaterialEstimates();
Expand Down
4 changes: 2 additions & 2 deletions src/communication/ArcusCommunicationPrivate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ std::shared_ptr<proto::LayerOptimized> ArcusCommunication::Private::getOptimized

void ArcusCommunication::Private::readGlobalSettingsMessage(const proto::SettingList& global_settings_message)
{
Slice* slice = Application::getInstance().current_slice_;
auto slice = Application::getInstance().current_slice_;
for (const cura::proto::Setting& setting_message : global_settings_message.settings())
{
slice->scene.settings.add(setting_message.name(), setting_message.value());
Expand All @@ -57,7 +57,7 @@ void ArcusCommunication::Private::readGlobalSettingsMessage(const proto::Setting
void ArcusCommunication::Private::readExtruderSettingsMessage(const google::protobuf::RepeatedPtrField<proto::Extruder>& extruder_messages)
{
// Make sure we have enough extruders added currently.
Slice* slice = Application::getInstance().current_slice_;
auto slice = Application::getInstance().current_slice_;
const size_t extruder_count = slice->scene.settings.get<size_t>("machine_extruder_count");
for (size_t extruder_nr = 0; extruder_nr < extruder_count; extruder_nr++)
{
Expand Down
Loading

0 comments on commit 0270dce

Please sign in to comment.