Skip to content

Commit

Permalink
Merge pull request #155 from makc/wasm
Browse files Browse the repository at this point in the history
wasm
  • Loading branch information
elalish committed Jul 18, 2022
2 parents cea3d22 + fc79b07 commit a149732
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 3 deletions.
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ set(MANIFOLD_PAR "TBB" CACHE STRING "Parallel backend, either \"TBB\" or \"OpenM

if(EMSCRIPTEN)
message("Building for Emscripten")
set(MANIFOLD_FLAGS -fexceptions)
set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} -sALLOW_MEMORY_GROWTH=1)
set(MANIFOLD_USE_CUDA OFF)
set(MANIFOLD_PAR "NONE")
Expand Down Expand Up @@ -78,3 +79,7 @@ add_subdirectory(meshIO)
add_subdirectory(samples)
add_subdirectory(test)
add_subdirectory(tools)

if(EMSCRIPTEN)
add_subdirectory(wasm)
endif()
7 changes: 4 additions & 3 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@
nativeBuildInputs = (with pkgs; [ cmake python38 ]);
buildInputs = [ pkgs.nodejs ];
configurePhase = ''
mkdir -p .emscriptencache
export EM_CACHE=$(pwd)/.emscriptencache
mkdir build
cd build
mkdir cache
Expand All @@ -113,9 +115,8 @@
'';
installPhase = ''
mkdir -p $out
cd tools
cp *.js $out/
cp *.wasm $out/
cp {tools,wasm}/*.js $out/
cp {tools,wasm}/*.wasm $out/
'';
};
};
Expand Down
9 changes: 9 additions & 0 deletions wasm/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
project (wasm)

add_executable(manifoldjs bindings.cpp)
target_link_libraries(manifoldjs manifold)
target_compile_options(manifoldjs PRIVATE ${MANIFOLD_FLAGS} -fexceptions)
target_link_options(manifoldjs PUBLIC --bind)
target_compile_features(manifoldjs PUBLIC cxx_std_14)
set_target_properties(manifoldjs PROPERTIES OUTPUT_NAME "manifold")
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/index.html DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
63 changes: 63 additions & 0 deletions wasm/bindings.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#include <emscripten/bind.h>

using namespace emscripten;

#include <manifold.h>

using namespace manifold;

Manifold Union(Manifold& a, Manifold& b) { return a + b; }
void Add(Manifold& a, Manifold& b) { a += b; }

Manifold Difference(Manifold& a, Manifold& b) { return a - b; }
void Subtract(Manifold& a, Manifold& b) { a -= b; }

Manifold Intersection(Manifold& a, Manifold& b) { return a ^ b; }
void Intersect(Manifold& a, Manifold& b) { a ^= b; }

EMSCRIPTEN_BINDINGS(whatever) {

value_object<glm::ivec3>("ivec3")
.field("0", &glm::ivec3::x)
.field("1", &glm::ivec3::y)
.field("2", &glm::ivec3::z)
;

register_vector<glm::ivec3>("Vector_ivec3");

value_object<glm::vec3>("vec3")
.field("x", &glm::vec3::x)
.field("y", &glm::vec3::y)
.field("z", &glm::vec3::z)
;

register_vector<glm::vec3>("Vector_vec3");

value_object<glm::vec4>("vec4")
.field("x", &glm::vec4::x)
.field("y", &glm::vec4::y)
.field("z", &glm::vec4::z)
.field("w", &glm::vec4::w)
;

register_vector<glm::vec4>("Vector_vec4");

value_object<Mesh>("Mesh")
.field("vertPos", &Mesh::vertPos)
.field("triVerts", &Mesh::triVerts)
.field("vertNormal", &Mesh::vertNormal)
.field("halfedgeTangent", &Mesh::halfedgeTangent)
;

class_<Manifold>("Manifold")
.constructor<Mesh>()
.function("Add", &Add)
.function("Subtract", &Subtract)
.function("Intersect", &Intersect)
.function("GetMesh", &Manifold::GetMesh)
;

function("Union", &Union);
function("Difference", &Difference);
function("Intersection", &Intersection);
}
110 changes: 110 additions & 0 deletions wasm/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<!doctype html>
<html>
<script src="https://unpkg.com/three@0.142.0/build/three.js"></script>
<script src="https://unpkg.com/three@0.142.0/examples/js/utils/BufferGeometryUtils.js"></script>
<script>
var Module = {
onRuntimeInitialized: function() {
// we have manifold module, let's do some three.js
const camera = new THREE.PerspectiveCamera(30, 0.75, 0.01, 10);
camera.position.z = 1;

const scene = new THREE.Scene();
const mesh = new THREE.Mesh(undefined, new THREE.MeshNormalMaterial({
flatShading: true
}));
scene.add(mesh);

const geometry_1 = simplify(new THREE.BoxGeometry(0.2, 0.2, 0.2));
const geometry_2 = simplify(new THREE.IcosahedronGeometry(0.16));

const manifold_1 = new Module.Manifold(geometry2mesh(geometry_1));
const manifold_2 = new Module.Manifold(geometry2mesh(geometry_2));

const csg = function(operation) {
mesh.geometry?.dispose();
mesh.geometry = mesh2geometry(
Module[operation](manifold_1, manifold_2).GetMesh()
);
};

document.querySelector('select').onchange = function(event) {
csg(event.target.value);
};

csg('Difference');

const renderer = new THREE.WebGLRenderer({ antialias: true });
document.body.appendChild(renderer.domElement);
renderer.setSize(300, 400);
renderer.setAnimationLoop(function(time) {
mesh.rotation.x = time / 2000;
mesh.rotation.y = time / 1000;
renderer.render(scene, camera);
});

}
};

// functions to convert between three.js and wasm
function geometry2mesh(geometry) {
const mesh = {
vertPos: new Module.Vector_vec3(),
vertNormal: new Module.Vector_vec3(),
triVerts: new Module.Vector_ivec3(),
halfedgeTangent: new Module.Vector_vec4()
};
const temp = new THREE.Vector3();
const p = geometry.attributes.position;
const n = geometry.attributes.normal;
const x = geometry.index;
for(let i = 0; i < p.count; i++) {
temp.fromBufferAttribute(p, i);
mesh.vertPos.push_back(temp);
temp.fromBufferAttribute(n, i);
mesh.vertNormal.push_back(temp);
}
for(let i = 0; i < x.count; i+=3) {
mesh.triVerts.push_back(x.array.subarray(i, i + 3));
}
return mesh;
}

function mesh2geometry(mesh) {
const geometry = new THREE.BufferGeometry();
const p = [], n = [], x = [];
let i, s, v;
for(i = 0, s = mesh.vertPos.size(); i < s; i++) {
v = mesh.vertPos.get(i);
p.push(v.x, v.y, v.z);
v = mesh.vertNormal.get(i);
n.push(v.x, v.y, v.z);
}
for(i = 0, s = mesh.triVerts.size(); i < s; i++) {
v = mesh.triVerts.get(i);
x.push(v[0], v[1], v[2]);
}
geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(p), 3));
geometry.setAttribute('normal', new THREE.BufferAttribute(new Float32Array(n), 3));
geometry.setIndex(new THREE.BufferAttribute(new Uint8Array(x), 1));
return geometry;
}

// most of three.js geometries arent manifolds, so...
function simplify(geometry) {
delete geometry.attributes.normal;
delete geometry.attributes.uv;
const simplified = THREE.BufferGeometryUtils.mergeVertices(geometry);
simplified.computeVertexNormals();
return simplified;
}
</script>
<script src="manifold.js"></script>
<body>
<select>
<option value="Difference" selected>Difference</option>
<option value="Intersection">Intersection</option>
<option value="Union">Union</option>
</select>
</body>
</html>

0 comments on commit a149732

Please sign in to comment.