Skip to content

WASM bindings in ACT (through emscripten) #225

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from

Conversation

vijaiaeroastro
Copy link

@vijaiaeroastro vijaiaeroastro commented Jun 17, 2025

  • This PR introduces WASM bindings for ACT.
  • The first version of this generator was originally implemented in Python: https://github.com/3MFConsortium/lib3mf_emscripten with the goal of creating WASM bindings for lib3mf.
  • The same functionality has now been ported and tested in ACT, and is designed to be generic and reusable.
  • All examples from the original lib3mf_emscripten repository work seamlessly with the bindings generated via ACT.

Key Features

  • Automatically generates wrapper structs for each native struct.
  • Creates wrapper methods when a struct is used as a method argument.
  • Handles non-const reference parameters by generating alternate wrapper methods that return a JavaScript object (since direct manipulation of non-const refs is not supported by Emscripten).
  • Most functions that take Pointers to class objects use a wrapper class called classParam in ACT. We detect these and automatically make it work inside bindings. However, users can simply use pointers in Javascript. Here is an example
const gyroidFunction = model.AddImplicitFunction();
gyroidFunction.SetDisplayName("gyroid");

// Add input position
const inputPos = gyroidFunction.AddInput("pos", "position", lib3mf.eImplicitPortType.Vector);

// Add decompose vector node
const decomposePos = gyroidFunction.AddDecomposeVectorNode("decomposePos", "decompose pos", "group_a");
  
// Link both
gyroidFunction.AddLink(inputPos, decomposePos.GetInputA()); // <--- Note this line

In the highlighted line above AddLink is actually supposed to have a signature like this in Cpp

void CImplicitFunction::AddLink(classParam<CImplicitPort> pSource, classParam<CImplicitPort> pTarget)
{
  Lib3MFHandle hSource = pSource.GetHandle();
  Lib3MFHandle hTarget = pTarget.GetHandle();
  CheckError(lib3mf_implicitfunction_addlink(m_pHandle, hSource, hTarget));
}

However, this cannot be implicitly constructor in WASM. So, we have a wrapper like this

static void wrap_ImplicitFunction_AddLink(CImplicitFunction &self, PImplicitPort& Source, PImplicitPort& Target) {
    self.AddLink(classParam(Source), classParam(Target));
}

This is automatically generated for all functions making it easy to write JS friendly code.

Known Issues

  • classParam<T> is used in many methods in the volumetric extension.
  • callBack functions are not supported yet

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant