diff --git a/examples/testbed/framework/test_entries.cpp b/examples/testbed/framework/test_entries.cpp index 99d7d9a..9598c7f 100644 --- a/examples/testbed/framework/test_entries.cpp +++ b/examples/testbed/framework/test_entries.cpp @@ -61,8 +61,9 @@ #include #include #include -#include -#include +#include +#include +#include #include #include #include @@ -113,11 +114,12 @@ TestEntry g_tests[] = { "Initial Overlap", &InitialOverlap::Create }, { "Multiple Pendulum", &MultiplePendulum::Create }, { "Cloth", &Cloth::Create }, - { "Mass-Spring System", &MassSpring::Create }, - { "Spring Cloth", &SpringCloth::Create }, - { "Spring Cloth Contact", &SpringClothContact::Create }, + { "Table Cloth", &TableCloth::Create }, + { "Pinned Cloth", &PinnedCloth::Create }, + { "Shirt", &Shirt::Create }, { "Mass Types", &MassTypes::Create }, { "Tension Mapping", &TensionMapping::Create }, + { "Mass-Spring System", &MassSpring::Create }, { "Single Pendulum", &SinglePendulum::Create }, { "Rope", &Rope::Create }, { NULL, NULL } diff --git a/examples/testbed/tests/mass_types.h b/examples/testbed/tests/mass_types.h index 21080a2..5bf5b42 100644 --- a/examples/testbed/tests/mass_types.h +++ b/examples/testbed/tests/mass_types.h @@ -19,36 +19,16 @@ #ifndef MASS_TYPES_H #define MASS_TYPES_H -class MassTypes : public SpringClothTest +class MassTypes : public PinnedCloth { public: MassTypes() { - b3SpringClothDef def; - def.allocator = &m_clothAllocator; - def.mesh = &m_clothMesh; - def.density = 0.2f; - def.ks = 100000.0f; - def.gravity.Set(0.0f, -10.0f, 0.0f); - - m_cloth.Initialize(def); - - b3AABB3 aabb; - aabb.m_lower.Set(-5.0f, -1.0f, -6.0f); - aabb.m_upper.Set(5.0f, 1.0f, -4.0f); - - for (u32 i = 0; i < def.mesh->vertexCount; ++i) - { - if (aabb.Contains(def.mesh->vertices[i])) - { - m_cloth.SetType(i, b3MassType::e_staticMass); - } - } } void Step() { - SpringClothTest::Step(); + PinnedCloth::Step(); g_draw->DrawString(b3Color_white, "S - Static"); g_draw->DrawString(b3Color_white, "D - Dynamic"); @@ -56,30 +36,29 @@ public: g_draw->DrawString(b3Color_white, "Arrows - Apply Force/Velocity/Position"); } + void SetClothType(b3MassType type) + { + for (u32 i = 0; i < m_cloth.GetMassCount(); ++i) + { + m_cloth.SetType(i, type); + } + } + void KeyDown(int button) { if (button == GLFW_KEY_S) { - for (u32 i = 0; i < m_cloth.GetMassCount(); ++i) - { - m_cloth.SetType(i, b3MassType::e_staticMass); - } + SetClothType(b3MassType::e_staticMass); } if (button == GLFW_KEY_K) { - for (u32 i = 0; i < m_cloth.GetMassCount(); ++i) - { - m_cloth.SetType(i, b3MassType::e_kinematicMass); - } + SetClothType(b3MassType::e_kinematicMass); } if (button == GLFW_KEY_D) { - for (u32 i = 0; i < m_cloth.GetMassCount(); ++i) - { - m_cloth.SetType(i, b3MassType::e_dynamicMass); - } + SetClothType(b3MassType::e_dynamicMass); } for (u32 i = 0; i < m_cloth.GetMassCount(); ++i) @@ -191,8 +170,6 @@ public: { return new MassTypes(); } - - b3GridMesh<10, 10> m_clothMesh; }; #endif \ No newline at end of file diff --git a/examples/testbed/tests/pinned_cloth.h b/examples/testbed/tests/pinned_cloth.h new file mode 100644 index 0000000..6dd3ebd --- /dev/null +++ b/examples/testbed/tests/pinned_cloth.h @@ -0,0 +1,79 @@ +/* +* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef PINNED_CLOTH_H +#define PINNED_CLOTH_H + +class PinnedCloth : public SpringClothTest +{ +public: + PinnedCloth() + { + m_gridClothMesh.vertexCount = m_gridMesh.vertexCount; + m_gridClothMesh.vertices = m_gridMesh.vertices; + + m_gridClothMesh.triangleCount = m_gridMesh.triangleCount; + m_gridClothMesh.triangles = (b3ClothMeshTriangle*)m_gridMesh.triangles; + + m_gridClothMeshMesh.vertexCount = m_gridClothMesh.vertexCount; + m_gridClothMeshMesh.startVertex = 0; + + m_gridClothMeshMesh.triangleCount = m_gridClothMesh.triangleCount; + m_gridClothMeshMesh.startTriangle = 0; + + m_gridClothMesh.meshCount = 1; + m_gridClothMesh.meshes = &m_gridClothMeshMesh; + + m_gridClothMesh.sewingLineCount = 0; + m_gridClothMesh.sewingLines = nullptr; + + b3SpringClothDef def; + def.allocator = &m_clothAllocator; + def.mesh = &m_gridClothMesh; + def.density = 0.2f; + def.ks = 10000.0f; + def.kd = 0.0f; + def.r = 0.05f; + def.gravity.Set(0.0f, -10.0f, 0.0f); + + m_cloth.Initialize(def); + + b3AABB3 aabb; + aabb.m_lower.Set(-5.0f, -1.0f, -6.0f); + aabb.m_upper.Set(5.0f, 1.0f, -4.0f); + + for (u32 i = 0; i < m_cloth.GetMassCount(); ++i) + { + if (aabb.Contains(m_cloth.GetPosition(i))) + { + m_cloth.SetType(i, b3MassType::e_staticMass); + } + } + } + + static Test* Create() + { + return new PinnedCloth(); + } + + b3GridMesh<10, 10> m_gridMesh; + b3ClothMeshMesh m_gridClothMeshMesh; + b3ClothMesh m_gridClothMesh; +}; + +#endif \ No newline at end of file diff --git a/examples/testbed/tests/shirt.h b/examples/testbed/tests/shirt.h new file mode 100644 index 0000000..2f371c5 --- /dev/null +++ b/examples/testbed/tests/shirt.h @@ -0,0 +1,80 @@ +/* +* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SHIRT_H +#define SHIRT_H + +#include +#include +#include + +class Shirt : public SpringClothTest +{ +public: + Shirt() + { + // Generate 2D mesh + m_shirtGarmentMesh.Set(&m_shirtGarment, 0.1f); + + // Create 3D mesh + m_shirtClothMesh.Set(&m_shirtGarmentMesh); + + // Perform fitting + for (u32 i = 0; i < 3; ++i) + { + b3ClothMeshMesh* front = m_shirtClothMesh.meshes + i; + for (u32 j = 0; j < front->vertexCount; ++j) + { + u32 v = front->startVertex + j; + m_shirtClothMesh.vertices[v].z = -1.0f; + } + } + + for (u32 i = 3; i < 6; ++i) + { + b3ClothMeshMesh* back = m_shirtClothMesh.meshes + i; + for (u32 j = 0; j < back->vertexCount; ++j) + { + u32 v = back->startVertex + j; + m_shirtClothMesh.vertices[v].z = 1.0f; + } + } + + // Create cloth + b3SpringClothDef def; + def.allocator = &m_clothAllocator; + def.mesh = &m_shirtClothMesh; + def.density = 0.2f; + def.ks = 10000.0f; + def.r = 0.2f; + def.gravity.Set(0.0f, -10.0f, 0.0f); + + m_cloth.Initialize(def); + } + + static Test* Create() + { + return new Shirt(); + } + + b3ShirtGarment m_shirtGarment; + b3GarmentMesh m_shirtGarmentMesh; + b3GarmentClothMesh m_shirtClothMesh; +}; + +#endif \ No newline at end of file diff --git a/examples/testbed/tests/spring_cloth_test.h b/examples/testbed/tests/spring_cloth_test.h index 51eebb5..e988186 100644 --- a/examples/testbed/tests/spring_cloth_test.h +++ b/examples/testbed/tests/spring_cloth_test.h @@ -43,8 +43,8 @@ public: { B3_ASSERT(m_isSelected); - b3Mesh* m = m_cloth->GetMesh(); - b3Triangle* t = m->triangles + m_selection; + b3ClothMesh* m = m_cloth->GetMesh(); + b3ClothMeshTriangle* t = m->triangles + m_selection; b3Vec3 A = m->vertices[t->v1]; b3Vec3 B = m->vertices[t->v2]; @@ -70,8 +70,8 @@ public: m_isSelected = true; - b3Mesh* m = m_cloth->GetMesh(); - b3Triangle* t = m->triangles + m_selection; + b3ClothMesh* m = m_cloth->GetMesh(); + b3ClothMeshTriangle* t = m->triangles + m_selection; m_t1 = m_cloth->GetType(t->v1); m_cloth->SetType(t->v1, b3MassType::e_staticMass); @@ -108,8 +108,8 @@ public: { B3_ASSERT(m_isSelected); - b3Mesh* m = m_cloth->GetMesh(); - b3Triangle* t = m->triangles + m_selection; + b3ClothMesh* m = m_cloth->GetMesh(); + b3ClothMeshTriangle* t = m->triangles + m_selection; b3Vec3 A = GetPointA(); b3Vec3 B = GetPointB(); @@ -135,8 +135,8 @@ public: m_isSelected = false; - b3Mesh* m = m_cloth->GetMesh(); - b3Triangle* t = m->triangles + m_selection; + b3ClothMesh* m = m_cloth->GetMesh(); + b3ClothMeshTriangle* t = m->triangles + m_selection; m_cloth->SetType(t->v1, m_t1); m_cloth->SetType(t->v2, m_t2); @@ -144,22 +144,99 @@ public: } private: + bool RayCast(b3RayCastOutput* output, u32 triangleIndex) const + { + b3ClothMesh* mesh = m_cloth->GetMesh(); + B3_ASSERT(triangleIndex < mesh->triangleCount); + b3ClothMeshTriangle* triangle = mesh->triangles + triangleIndex; + + b3Vec3 v1 = mesh->vertices[triangle->v1]; + b3Vec3 v2 = mesh->vertices[triangle->v2]; + b3Vec3 v3 = mesh->vertices[triangle->v3]; + + b3Vec3 p1 = m_ray->A(); + b3Vec3 p2 = m_ray->B(); + b3Vec3 d = p2 - p1; + float32 maxFraction = b3Length(d); + + b3Vec3 n = b3Cross(v2 - v1, v3 - v1); + n.Normalize(); + + float32 numerator = b3Dot(n, v1 - p1); + float32 denominator = b3Dot(n, d); + + if (denominator == 0.0f) + { + return false; + } + + float32 t = numerator / denominator; + + // Is the intersection not on the segment? + if (t < 0.0f || maxFraction < t) + { + return false; + } + + b3Vec3 q = p1 + t * d; + + // Barycentric coordinates for q + b3Vec3 Q = q; + b3Vec3 A = v1; + b3Vec3 B = v2; + b3Vec3 C = v3; + + b3Vec3 AB = B - A; + b3Vec3 AC = C - A; + + b3Vec3 QA = A - Q; + b3Vec3 QB = B - Q; + b3Vec3 QC = C - Q; + + b3Vec3 QB_x_QC = b3Cross(QB, QC); + b3Vec3 QC_x_QA = b3Cross(QC, QA); + b3Vec3 QA_x_QB = b3Cross(QA, QB); + + b3Vec3 AB_x_AC = b3Cross(AB, AC); + + float32 u = b3Dot(QB_x_QC, AB_x_AC); + float32 v = b3Dot(QC_x_QA, AB_x_AC); + float32 w = b3Dot(QA_x_QB, AB_x_AC); + + // This tolerance helps intersections lying on + // shared edges to not be missed. + const float32 kTol = -0.005f; + + // Is the intersection on the triangle? + if (u > kTol && v > kTol && w > kTol) + { + output->fraction = t; + + // Does the ray start from below or above the triangle? + if (numerator > 0.0f) + { + output->normal = -n; + } + else + { + output->normal = n; + } + + return true; + } + + return false; + } bool Select(u32& selection, float32& fraction) const { - b3Mesh* m = m_cloth->GetMesh(); - - b3MeshShape ms; - ms.m_mesh = m; + b3ClothMesh* m = m_cloth->GetMesh(); b3RayCastInput input; input.p1 = m_ray->A(); input.p2 = m_ray->B(); input.maxFraction = m_ray->fraction; - b3Transform transform; - transform.SetIdentity(); - float32 minFraction = B3_MAX_FLOAT; b3Vec3 minNormal(0.0f, 0.0f, 0.0f); u32 minIndex = ~0; @@ -167,7 +244,7 @@ private: for (u32 i = 0; i < m->triangleCount; ++i) { b3RayCastOutput subOutput; - if (ms.RayCast(&subOutput, input, transform, i) == true) + if (RayCast(&subOutput, i) == true) { if (subOutput.fraction < minFraction) { diff --git a/examples/testbed/tests/table_cloth.h b/examples/testbed/tests/table_cloth.h new file mode 100644 index 0000000..6717a2d --- /dev/null +++ b/examples/testbed/tests/table_cloth.h @@ -0,0 +1,85 @@ +/* +* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef TABLE_CLOTH_H +#define TABLE_CLOTH_H + +class TableCloth : public SpringClothTest +{ +public: + TableCloth() + { + // Shift vertices up + for (u32 i = 0; i < m_gridMesh.vertexCount; ++i) + { + m_gridMesh.vertices[i].y = 5.0f; + } + + m_gridClothMesh.vertexCount = m_gridMesh.vertexCount; + m_gridClothMesh.vertices = m_gridMesh.vertices; + + m_gridClothMesh.triangleCount = m_gridMesh.triangleCount; + m_gridClothMesh.triangles = (b3ClothMeshTriangle*)m_gridMesh.triangles; + + m_gridClothMeshMesh.vertexCount = m_gridClothMesh.vertexCount; + m_gridClothMeshMesh.startVertex = 0; + + m_gridClothMeshMesh.triangleCount = m_gridClothMesh.triangleCount; + m_gridClothMeshMesh.startTriangle = 0; + + m_gridClothMesh.meshCount = 1; + m_gridClothMesh.meshes = &m_gridClothMeshMesh; + + m_gridClothMesh.sewingLineCount = 0; + m_gridClothMesh.sewingLines = nullptr; + + b3SpringClothDef def; + def.allocator = &m_clothAllocator; + def.mesh = &m_gridClothMesh; + def.density = 0.2f; + def.ks = 10000.0f; + def.kd = 0.0f; + def.r = 0.05f; + def.gravity.Set(0.0f, -10.0f, 0.0f); + + m_cloth.Initialize(def); + + m_tableHull.SetAsCylinder(5.0f, 2.0f); + + m_tableShape.m_hull = &m_tableHull; + m_tableShape.m_radius = 0.2f; + + m_tableShape.SetFriction(1.0f); + + m_cloth.AddShape(&m_tableShape); + } + + static Test* Create() + { + return new TableCloth(); + } + + b3GridMesh<10, 10> m_gridMesh; + b3ClothMeshMesh m_gridClothMeshMesh; + b3ClothMesh m_gridClothMesh; + + b3QHull m_tableHull; + b3HullShape m_tableShape; +}; + +#endif \ No newline at end of file diff --git a/examples/testbed/tests/tension_mapping.h b/examples/testbed/tests/tension_mapping.h index eb4dbb7..f072de3 100644 --- a/examples/testbed/tests/tension_mapping.h +++ b/examples/testbed/tests/tension_mapping.h @@ -60,11 +60,31 @@ class TensionMapping : public SpringClothTest public: TensionMapping() { + m_gridClothMesh.vertexCount = m_gridMesh.vertexCount; + m_gridClothMesh.vertices = m_gridMesh.vertices; + + m_gridClothMesh.triangleCount = m_gridMesh.triangleCount; + m_gridClothMesh.triangles = (b3ClothMeshTriangle*)m_gridMesh.triangles; + + m_gridClothMeshMesh.vertexCount = m_gridClothMesh.vertexCount; + m_gridClothMeshMesh.startVertex = 0; + + m_gridClothMeshMesh.triangleCount = m_gridClothMesh.triangleCount; + m_gridClothMeshMesh.startTriangle = 0; + + m_gridClothMesh.meshCount = 1; + m_gridClothMesh.meshes = &m_gridClothMeshMesh; + + m_gridClothMesh.sewingLineCount = 0; + m_gridClothMesh.sewingLines = nullptr; + b3SpringClothDef def; def.allocator = &m_clothAllocator; - def.mesh = &m_clothMesh; + def.mesh = &m_gridClothMesh; def.density = 0.2f; - def.ks = 100000.0f; + def.ks = 10000.0f; + def.kd = 0.0f; + def.r = 0.2f; def.gravity.Set(0.0f, -10.0f, 0.0f); m_cloth.Initialize(def); @@ -73,9 +93,9 @@ public: aabb.m_lower.Set(-5.0f, -1.0f, -6.0f); aabb.m_upper.Set(5.0f, 1.0f, -4.0f); - for (u32 i = 0; i < def.mesh->vertexCount; ++i) + for (u32 i = 0; i < m_cloth.GetMassCount(); ++i) { - if (aabb.Contains(def.mesh->vertices[i])) + if (aabb.Contains(m_cloth.GetPosition(i))) { m_cloth.SetType(i, b3MassType::e_staticMass); } @@ -92,13 +112,13 @@ public: b3StackArray T; m_cloth.GetTension(T); - for (u32 i = 0; i < m_clothMesh.triangleCount; ++i) + for (u32 i = 0; i < m_gridClothMesh.triangleCount; ++i) { - b3Triangle* t = m_clothMesh.triangles + i; + b3ClothMeshTriangle* t = m_gridClothMesh.triangles + i; - b3Vec3 v1 = m_clothMesh.vertices[t->v1]; - b3Vec3 v2 = m_clothMesh.vertices[t->v2]; - b3Vec3 v3 = m_clothMesh.vertices[t->v3]; + b3Vec3 v1 = m_gridClothMesh.vertices[t->v1]; + b3Vec3 v2 = m_gridClothMesh.vertices[t->v2]; + b3Vec3 v3 = m_gridClothMesh.vertices[t->v3]; b3Draw_draw->DrawSegment(v1, v2, b3Color_black); b3Draw_draw->DrawSegment(v2, v3, b3Color_black); @@ -142,7 +162,9 @@ public: return new TensionMapping(); } - b3GridMesh<10, 10> m_clothMesh; + b3GridMesh<10, 10> m_gridMesh; + b3ClothMeshMesh m_gridClothMeshMesh; + b3ClothMesh m_gridClothMesh; }; #endif \ No newline at end of file diff --git a/include/bounce/bounce.h b/include/bounce/bounce.h index e991729..23ad763 100644 --- a/include/bounce/bounce.h +++ b/include/bounce/bounce.h @@ -57,8 +57,11 @@ #include #include + +#include #include #include + #include //#include diff --git a/examples/testbed/tests/spring_cloth_contact.h b/include/bounce/dynamics/cloth/cloth_mesh.h similarity index 52% rename from examples/testbed/tests/spring_cloth_contact.h rename to include/bounce/dynamics/cloth/cloth_mesh.h index db446ee..e198dd3 100644 --- a/examples/testbed/tests/spring_cloth_contact.h +++ b/include/bounce/dynamics/cloth/cloth_mesh.h @@ -16,41 +16,54 @@ * 3. This notice may not be removed or altered from any source distribution. */ -#ifndef SPRING_CLOTH_CONTACT_H -#define SPRING_CLOTH_CONTACT_H +#ifndef B3_CLOTH_MESH_H +#define B3_CLOTH_MESH_H -class SpringClothContact : public SpringClothTest +#include +#include + +struct b3ClothMeshTriangle { -public: - SpringClothContact() - { - b3SpringClothDef def; - def.allocator = &m_clothAllocator; - def.mesh = &m_clothMesh; - def.density = 0.2f; - def.ks = 1000.0f; - def.kd = 0.0f; - def.r = 0.2f; - def.gravity.Set(0.0f, -10.0f, 0.0f); + u32 v1, v2, v3; +}; - m_cloth.Initialize(def); +struct b3ClothMeshMesh +{ + u32 vertexCount; + u32 startVertex; + u32 triangleCount; + u32 startTriangle; +}; - m_clothCapsule.m_centers[0].Set(0.0f, -2.0f, 2.0f); - m_clothCapsule.m_centers[1].Set(0.0f, -2.0f, -2.0f); - m_clothCapsule.m_radius = 2.0f; - - m_clothCapsule.SetFriction(1.0f); +struct b3ClothMeshSewingLine +{ + u32 s1, s2; + u32 v1, v2; +}; - m_cloth.AddShape(&m_clothCapsule); - } +struct b3ClothMesh +{ + u32 vertexCount; + b3Vec3* vertices; + u32 triangleCount; + b3ClothMeshTriangle* triangles; + u32 meshCount; + b3ClothMeshMesh* meshes; + u32 sewingLineCount; + b3ClothMeshSewingLine* sewingLines; +}; - static Test* Create() - { - return new SpringClothContact(); - } +struct b3GarmentMesh; - b3GridMesh<10, 10> m_clothMesh; - b3CapsuleShape m_clothCapsule; +// Convenience structure. +struct b3GarmentClothMesh : public b3ClothMesh +{ + b3GarmentClothMesh(); + ~b3GarmentClothMesh(); + + // Maps a given garment mesh to this mesh. + // This garment mesh must be empty. + void Set(const b3GarmentMesh* garment); }; #endif \ No newline at end of file diff --git a/include/bounce/dynamics/cloth/spring_cloth.h b/include/bounce/dynamics/cloth/spring_cloth.h index ebcc032..7afc816 100644 --- a/include/bounce/dynamics/cloth/spring_cloth.h +++ b/include/bounce/dynamics/cloth/spring_cloth.h @@ -29,7 +29,7 @@ class b3StackAllocator; class b3Shape; -struct b3Mesh; +struct b3ClothMesh; struct b3SpringClothDef { @@ -49,7 +49,7 @@ struct b3SpringClothDef b3StackAllocator* allocator; // Cloth mesh - b3Mesh* mesh; + b3ClothMesh* mesh; // Cloth density in kg/m^3 float32 density; @@ -64,8 +64,8 @@ struct b3SpringClothDef float32 kd; // Mass radius - // Typically this is value is small and is intended for correcting visual artifacts when - // the cloth is colliding against a solid. + // This should be a small value. It can be used for correcting visual artifacts when + // the masses are colliding against a solid. float32 r; // Acceleration due to gravity (m/s^2) @@ -75,7 +75,8 @@ struct b3SpringClothDef enum b3SpringType { e_strechSpring, - e_bendSpring + e_bendSpring, + // e_sewingSpring }; struct b3Spring @@ -138,7 +139,7 @@ public: void Initialize(const b3SpringClothDef& def); // Return the cloth mesh used to initialize this cloth. - b3Mesh* GetMesh() const; + b3ClothMesh* GetMesh() const; // Set the gravitational acceleration applied to this cloth. // Units are m/s^2. @@ -210,7 +211,7 @@ protected: b3StackAllocator* m_allocator; - b3Mesh* m_mesh; + b3ClothMesh* m_mesh; float32 m_r; b3Vec3 m_gravity; @@ -237,7 +238,7 @@ protected: b3SpringClothStep m_step; }; -inline b3Mesh* b3SpringCloth::GetMesh() const +inline b3ClothMesh* b3SpringCloth::GetMesh() const { return m_mesh; } diff --git a/include/bounce/garment/garment.h b/include/bounce/garment/garment.h new file mode 100644 index 0000000..6631f43 --- /dev/null +++ b/include/bounce/garment/garment.h @@ -0,0 +1,132 @@ +/* +* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B3_GARMENT_H +#define B3_GARMENT_H + +#include + +struct b3SewingLine +{ + u32 p1, p2; + u32 v1, v2; +}; + +struct b3Garment +{ + u32 patternCount; + b3SewingPattern** patterns; + u32 sewingCount; + b3SewingLine* sewingLines; +}; + +struct b3ShirtGarment : public b3Garment +{ + b3RectanglePattern frontBody; + b3RectanglePattern frontRightSleeve; + b3RectanglePattern frontLeftSleeve; + + b3RectanglePattern backBody; + b3RectanglePattern backRightSleeve; + b3RectanglePattern backLeftSleeve; + + b3SewingLine shirtSewingLines[12]; + + b3SewingPattern* shirtPatterns[6]; + + b3ShirtGarment() : + frontBody(1.0f, 1.0f), + frontRightSleeve(0.2f, 0.2f), + frontLeftSleeve(0.2f, 0.2f), + backBody(1.0f, 1.0f), + backRightSleeve(0.2f, 0.2f), + backLeftSleeve(0.2f, 0.2f) + { + b3Vec2 etr; + etr.x = 1.2f; + etr.y = 0.8f; + + b3Vec2 etl; + etl.x = -1.2f; + etl.y = 0.8f; + + for (u32 i = 0; i < 4; ++i) + { + frontRightSleeve.vertices[i] += etr; + frontLeftSleeve.vertices[i] += etl; + backRightSleeve.vertices[i] += etr; + backLeftSleeve.vertices[i] += etl; + } + + // Perform sewing + u32 count = 0; + + // Sew bodies + for (u32 i = 0; i < frontBody.vertexCount; ++i) + { + b3SewingLine line; + line.p1 = 0; + line.p2 = 3; + line.v1 = i; + line.v2 = i; + + shirtSewingLines[count++] = line; + } + + // Sew sleeves + for (u32 i = 0; i < frontRightSleeve.vertexCount; ++i) + { + b3SewingLine line; + line.p1 = 1; + line.p2 = 4; + line.v1 = i; + line.v2 = i; + + shirtSewingLines[count++] = line; + } + + for (u32 i = 0; i < frontLeftSleeve.vertexCount; ++i) + { + b3SewingLine line; + line.p1 = 2; + line.p2 = 5; + line.v1 = i; + line.v2 = i; + + shirtSewingLines[count++] = line; + } + + B3_ASSERT(12 == count); + + shirtPatterns[0] = &frontBody; + shirtPatterns[1] = &frontRightSleeve; + shirtPatterns[2] = &frontLeftSleeve; + + shirtPatterns[3] = &backBody; + shirtPatterns[4] = &backRightSleeve; + shirtPatterns[5] = &backLeftSleeve; + + patternCount = 6; + patterns = shirtPatterns; + + sewingCount = 12; + sewingLines = shirtSewingLines; + } +}; + +#endif \ No newline at end of file diff --git a/examples/testbed/tests/spring_cloth.h b/include/bounce/garment/garment_mesh.h similarity index 56% rename from examples/testbed/tests/spring_cloth.h rename to include/bounce/garment/garment_mesh.h index fc99ed2..66e97ca 100644 --- a/examples/testbed/tests/spring_cloth.h +++ b/include/bounce/garment/garment_mesh.h @@ -16,42 +16,48 @@ * 3. This notice may not be removed or altered from any source distribution. */ -#ifndef SPRING_CLOTH_H -#define SPRING_CLOTH_H +#ifndef B3_GARMENT_MESH_H +#define B3_GARMENT_MESH_H -class SpringCloth : public SpringClothTest +#include +#include + +struct b3Garment; + +struct b3SewingPatternMeshTriangle { -public: - SpringCloth() - { - b3SpringClothDef def; - def.allocator = &m_clothAllocator; - def.mesh = &m_clothMesh; - def.density = 0.2f; - def.ks = 100000.0f; - def.gravity.Set(0.0f, -10.0f, 0.0f); + u32 v1, v2, v3; +}; - m_cloth.Initialize(def); +struct b3SewingPatternMesh +{ + u32 vertexCount; + b3Vec2* vertices; + u32 triangleCount; + b3SewingPatternMeshTriangle* triangles; +}; - b3AABB3 aabb; - aabb.m_lower.Set(-5.0f, -1.0f, -6.0f); - aabb.m_upper.Set(5.0f, 1.0f, -4.0f); +struct b3GarmentMeshSewingLine +{ + u32 s1, s2; + u32 v1, v2; +}; - for (u32 i = 0; i < def.mesh->vertexCount; ++i) - { - if (aabb.Contains(def.mesh->vertices[i])) - { - m_cloth.SetType(i, b3MassType::e_staticMass); - } - } - } +// A garment mesh is a triangulated version of a garment. +struct b3GarmentMesh +{ + u32 meshCount; + b3SewingPatternMesh* meshes; - static Test* Create() - { - return new SpringCloth(); - } + u32 sewingCount; + b3GarmentMeshSewingLine* sewingLines; + + b3Garment* garment; - b3GridMesh<10, 10> m_clothMesh; + b3GarmentMesh(); + ~b3GarmentMesh(); + + void Set(b3Garment* garment, float32 desiredArea); }; #endif \ No newline at end of file diff --git a/include/bounce/garment/sewing_pattern.h b/include/bounce/garment/sewing_pattern.h new file mode 100644 index 0000000..349b1ca --- /dev/null +++ b/include/bounce/garment/sewing_pattern.h @@ -0,0 +1,81 @@ +/* +* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef B3_SEWING_PATTERN_H +#define B3_SEWING_PATTERN_H + +#include + +struct b3SewingPattern +{ + u32 vertexCount; + b3Vec2* vertices; +}; + +struct b3RectanglePattern : public b3SewingPattern +{ + b3Vec2 rectangleVertices[4]; + + b3RectanglePattern(float32 ex = 1.0f, float32 ey = 1.0f) + { + B3_ASSERT(ex > 0.0f); + B3_ASSERT(ey > 0.0f); + + // R, CCW + rectangleVertices[0].Set(ex, -ey); + rectangleVertices[1].Set(ex, ey); + + // L, CW + rectangleVertices[2].Set(-ex, ey); + rectangleVertices[3].Set(-ex, -ey); + + vertexCount = 4; + vertices = rectangleVertices; + } +}; + +template +struct b3CirclePattern : public b3SewingPattern +{ + b3Vec2 circleVertices[E]; + + b3CirclePattern(b3Vec2 center = b3Vec2_zero, float32 radius = 1.0f) + { + float32 x = 2.0f * B3_PI / float32(E); + float32 c = cos(x); + float32 s = sin(x); + + b3Mat22 R; + R.x.Set(c, s); + R.y.Set(-s, c); + + b3Vec2 n(1.0f, 0.0f); + circleVertices[0] = center + radius * n; + for (u32 i = 1; i < E; ++i) + { + b3Vec2 ni = R * n; + circleVertices[i] = center + radius * n; + n = ni; + } + + vertexCount = E; + vertices = circleVertices; + } +}; + +#endif \ No newline at end of file diff --git a/src/bounce/dynamics/cloth/cloth_mesh.cpp b/src/bounce/dynamics/cloth/cloth_mesh.cpp new file mode 100644 index 0000000..755c9aa --- /dev/null +++ b/src/bounce/dynamics/cloth/cloth_mesh.cpp @@ -0,0 +1,120 @@ +/* +* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#include +#include +#include +#include + +b3GarmentClothMesh::b3GarmentClothMesh() +{ + vertexCount = 0; + vertices = nullptr; + triangleCount = 0; + triangles = nullptr; + meshCount = 0; + meshes = nullptr; + sewingLineCount = 0; + sewingLines = nullptr; +} + +b3GarmentClothMesh::~b3GarmentClothMesh() +{ + b3Free(vertices); + b3Free(triangles); + b3Free(meshes); + b3Free(sewingLines); +} + +void b3GarmentClothMesh::Set(const b3GarmentMesh* garment) +{ + B3_ASSERT(vertexCount == 0); + for (u32 i = 0; i < garment->meshCount; ++i) + { + vertexCount += garment->meshes[i].vertexCount; + } + vertices = (b3Vec3*)b3Alloc(vertexCount * sizeof(b3Vec3)); + + B3_ASSERT(triangleCount == 0); + for (u32 i = 0; i < garment->meshCount; ++i) + { + triangleCount += garment->meshes[i].triangleCount; + } + triangles = (b3ClothMeshTriangle*)b3Alloc(triangleCount * sizeof(b3ClothMeshTriangle)); + + B3_ASSERT(meshCount == 0); + meshCount = garment->meshCount; + meshes = (b3ClothMeshMesh*)b3Alloc(meshCount * sizeof(b3ClothMeshMesh)); + + B3_ASSERT(sewingLineCount == 0); + sewingLineCount = garment->sewingCount; + sewingLines = (b3ClothMeshSewingLine*)b3Alloc(sewingLineCount * sizeof(b3ClothMeshSewingLine)); + + u32 vertex_count = 0; + for (u32 pattern_index = 0; pattern_index < garment->meshCount; ++pattern_index) + { + u32 pattern_vertex_count = garment->meshes[pattern_index].vertexCount; + + meshes[pattern_index].vertexCount = pattern_vertex_count; + meshes[pattern_index].startVertex = vertex_count; + + for (u32 pattern_vertex = 0; pattern_vertex < pattern_vertex_count; ++pattern_vertex) + { + vertices[vertex_count].x = garment->meshes[pattern_index].vertices[pattern_vertex].x; + vertices[vertex_count].y = garment->meshes[pattern_index].vertices[pattern_vertex].y; + vertices[vertex_count].z = 0.0f; + + ++vertex_count; + } + } + + u32 triangle_count = 0; + for (u32 pattern_index = 0; pattern_index < garment->meshCount; ++pattern_index) + { + u32 pattern_triangle_count = garment->meshes[pattern_index].triangleCount; + + meshes[pattern_index].triangleCount = pattern_triangle_count; + meshes[pattern_index].startTriangle = triangle_count; + + for (u32 pattern_triangle = 0; pattern_triangle < pattern_triangle_count; ++pattern_triangle) + { + u32 pattern_v1 = garment->meshes[pattern_index].triangles[pattern_triangle].v1; + u32 pattern_v2 = garment->meshes[pattern_index].triangles[pattern_triangle].v2; + u32 pattern_v3 = garment->meshes[pattern_index].triangles[pattern_triangle].v3; + + u32 cloth_v1 = meshes[pattern_index].startVertex + pattern_v1; + u32 cloth_v2 = meshes[pattern_index].startVertex + pattern_v2; + u32 cloth_v3 = meshes[pattern_index].startVertex + pattern_v3; + + triangles[triangle_count].v1 = cloth_v1; + triangles[triangle_count].v2 = cloth_v2; + triangles[triangle_count].v3 = cloth_v3; + + ++triangle_count; + } + } + + for (u32 sewing_line_index = 0; sewing_line_index < garment->sewingCount; ++sewing_line_index) + { + sewingLines[sewing_line_index].s1 = garment->sewingLines[sewing_line_index].s1; + sewingLines[sewing_line_index].v1 = meshes[sewingLines[sewing_line_index].s1].startVertex + garment->sewingLines[sewing_line_index].v1; + + sewingLines[sewing_line_index].s2 = garment->sewingLines[sewing_line_index].s2; + sewingLines[sewing_line_index].v2 = meshes[sewingLines[sewing_line_index].s2].startVertex + garment->sewingLines[sewing_line_index].v2; + } +} \ No newline at end of file diff --git a/src/bounce/dynamics/cloth/spring_cloth.cpp b/src/bounce/dynamics/cloth/spring_cloth.cpp index 4cd7526..dbd5f91 100644 --- a/src/bounce/dynamics/cloth/spring_cloth.cpp +++ b/src/bounce/dynamics/cloth/spring_cloth.cpp @@ -20,8 +20,8 @@ #include #include #include +#include #include -#include #include #include @@ -29,7 +29,7 @@ #define B3_CLOTH_BENDING 0 -#define B3_CLOTH_FRICTION 0 +#define B3_CLOTH_FRICTION 1 b3SpringCloth::b3SpringCloth() { @@ -86,13 +86,13 @@ struct b3UniqueEdge u32 v1, v2; }; -static u32 b3FindUniqueEdges(b3UniqueEdge* uniqueEdges, const b3Mesh* m) +static u32 b3FindUniqueEdges(b3UniqueEdge* uniqueEdges, const b3ClothMesh* m) { u32 uniqueCount = 0; for (u32 i = 0; i < m->triangleCount; ++i) { - b3Triangle* t1 = m->triangles + i; + b3ClothMeshTriangle* t1 = m->triangles + i; u32 i1s[3] = { t1->v1, t1->v2, t1->v3 }; for (u32 j1 = 0; j1 < 3; ++j1) @@ -138,13 +138,13 @@ struct b3SharedEdge u32 nsv1, nsv2; }; -static u32 b3FindSharedEdges(b3SharedEdge* sharedEdges, const b3Mesh* m) +static u32 b3FindSharedEdges(b3SharedEdge* sharedEdges, const b3ClothMesh* m) { u32 sharedCount = 0; for (u32 i = 0; i < m->triangleCount; ++i) { - b3Triangle* t1 = m->triangles + i; + b3ClothMeshTriangle* t1 = m->triangles + i; u32 i1s[3] = { t1->v1, t1->v2, t1->v3 }; for (u32 j1 = 0; j1 < 3; ++j1) @@ -156,7 +156,7 @@ static u32 b3FindSharedEdges(b3SharedEdge* sharedEdges, const b3Mesh* m) for (u32 j = i + 1; j < m->triangleCount; ++j) { - b3Triangle* t2 = m->triangles + j; + b3ClothMeshTriangle* t2 = m->triangles + j; u32 i2s[3] = { t2->v1, t2->v2, t2->v3 }; for (u32 j2 = 0; j2 < 3; ++j2) @@ -207,7 +207,7 @@ void b3SpringCloth::Initialize(const b3SpringClothDef& def) m_gravity = def.gravity; - const b3Mesh* m = m_mesh; + const b3ClothMesh* m = m_mesh; m_massCount = m->vertexCount; m_x = (b3Vec3*)b3Alloc(m_massCount * sizeof(b3Vec3)); @@ -244,7 +244,7 @@ void b3SpringCloth::Initialize(const b3SpringClothDef& def) // Initialize mass for (u32 i = 0; i < m->triangleCount; ++i) { - b3Triangle* t = m->triangles + i; + b3ClothMeshTriangle* t = m->triangles + i; b3Vec3 p1 = m->vertices[t->v1]; b3Vec3 p2 = m->vertices[t->v2]; @@ -288,9 +288,11 @@ void b3SpringCloth::Initialize(const b3SpringClothDef& def) #endif + springCapacity += m->sewingLineCount; + m_springs = (b3Spring*)b3Alloc(springCapacity * sizeof(b3Spring)); - // Streching + // Tension for (u32 i = 0; i < uniqueCount; ++i) { b3UniqueEdge* e = uniqueEdges + i; @@ -336,6 +338,21 @@ void b3SpringCloth::Initialize(const b3SpringClothDef& def) m_allocator->Free(uniqueEdges); + // Sewing + for (u32 i = 0; i < m->sewingLineCount; ++i) + { + b3ClothMeshSewingLine* line = m->sewingLines + i; + + b3Spring* S = m_springs + m_springCount; + S->type = e_strechSpring; + S->i1 = line->v1; + S->i2 = line->v2; + S->L0 = 0.0f; + S->ks = def.ks; + S->kd = def.kd; + ++m_springCount; + } + B3_ASSERT(m_springCount <= springCapacity); } @@ -680,7 +697,7 @@ void b3SpringCloth::Apply() const void b3SpringCloth::Draw() const { - const b3Mesh* m = m_mesh; + const b3ClothMesh* m = m_mesh; for (u32 i = 0; i < m->vertexCount; ++i) { @@ -719,10 +736,20 @@ void b3SpringCloth::Draw() const b3Draw_draw->DrawSegment(x1, x2, b3Color_black); } } + + for (u32 i = 0; i < m->sewingLineCount; ++i) + { + b3ClothMeshSewingLine* s = m->sewingLines + i; + + b3Vec3 x1 = m_x[s->v1]; + b3Vec3 x2 = m_x[s->v2]; + + b3Draw_draw->DrawSegment(x1, x2, b3Color_white); + } for (u32 i = 0; i < m->triangleCount; ++i) { - b3Triangle* t = m->triangles + i; + b3ClothMeshTriangle* t = m->triangles + i; b3Vec3 v1 = m_x[t->v1]; b3Vec3 v2 = m_x[t->v2]; @@ -735,4 +762,4 @@ void b3SpringCloth::Draw() const b3Vec3 n2 = -n1; b3Draw_draw->DrawSolidTriangle(n2, v1, v3, v2, b3Color_blue); } -} +} \ No newline at end of file diff --git a/src/bounce/garment/garment_mesh.cpp b/src/bounce/garment/garment_mesh.cpp new file mode 100644 index 0000000..5688ffe --- /dev/null +++ b/src/bounce/garment/garment_mesh.cpp @@ -0,0 +1,187 @@ +/* +* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would be +* appreciated but is not required. +* 2. Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* 3. This notice may not be removed or altered from any source distribution. +*/ + +#include +#include +#include + +#define ANSI_DECLARATORS +#define REAL double +#define VOID void + +extern "C" +{ + #include +} + +b3GarmentMesh::b3GarmentMesh() +{ + meshCount = 0; + meshes = nullptr; + sewingCount = 0; + sewingLines = nullptr; + garment = nullptr; +} + +b3GarmentMesh::~b3GarmentMesh() +{ + for (u32 i = 0; i < meshCount; ++i) + { + b3Free(meshes[i].vertices); + b3Free(meshes[i].triangles); + } + + b3Free(meshes); + b3Free(sewingLines); +} + +// +static void b3Set(b3SewingPatternMesh* mesh, float32 desiredArea, const b3SewingPattern* pattern) +{ + B3_ASSERT(desiredArea > B3_EPSILON); + + struct triangulateio in, mid, out; + + // Prepare the input structure + in.pointlist = (REAL*)b3Alloc(pattern->vertexCount * 2 * sizeof(REAL)); + const float32* fp = (float32*)pattern->vertices; + for (u32 i = 0; i < 2 * pattern->vertexCount; ++i) + { + in.pointlist[i] = (REAL)fp[i]; + } + in.pointattributelist = NULL; + in.pointmarkerlist = NULL; + in.numberofpoints = pattern->vertexCount; + in.numberofpointattributes = 0; + + in.trianglelist = NULL; + in.triangleattributelist = NULL; + + in.trianglearealist = NULL; + + in.numberoftriangles = 0; + in.numberofcorners = 0; + in.numberoftriangleattributes = 0; + + in.segmentlist = NULL; + in.segmentmarkerlist = NULL; + in.numberofsegments = 0; + + in.holelist = NULL; + in.numberofholes = 0; + + in.regionlist = NULL; + in.numberofregions = 0; + + // Prepare the middle structure + mid.pointlist = NULL; + mid.pointmarkerlist = NULL; + + mid.trianglelist = NULL; + mid.triangleattributelist = NULL; + mid.trianglearealist = NULL; + mid.neighborlist = NULL; + + mid.segmentlist = NULL; + mid.segmentmarkerlist = NULL; + + // Run triangulation + // z - zero based indices + // p - PSLG + // c - preserve the convex hull + triangulate("zpc", &in, &mid, NULL); + + // Refine + + // Prepare middle structure + mid.trianglearealist = (REAL*)b3Alloc(mid.numberoftriangles * sizeof(REAL)); + for (int i = 0; i < mid.numberoftriangles; ++i) + { + mid.trianglearealist[i] = desiredArea; + } + + // Prepare output structure + out.pointlist = NULL; + out.pointmarkerlist = NULL; + + out.trianglelist = NULL; + out.trianglearealist = NULL; + + out.segmentlist = NULL; + out.segmentmarkerlist = NULL; + + // Run triangulation + // z - zero based indices + // p - PSLG + // c - preserve the convex hull + // r - read triangles + triangulate("zpcra", &mid, &out, NULL); + + // Convert the output structure + + // The mesh must be empty + mesh->vertices = (b3Vec2*)b3Alloc(out.numberofpoints * sizeof(b3Vec2)); + mesh->vertexCount = out.numberofpoints; + for (int i = 0; i < out.numberofpoints; ++i) + { + mesh->vertices[i].x = (float32)out.pointlist[2 * i + 0]; + mesh->vertices[i].y = (float32)out.pointlist[2 * i + 1]; + } + + mesh->triangles = (b3SewingPatternMeshTriangle*)b3Alloc(out.numberoftriangles * sizeof(b3SewingPatternMeshTriangle)); + mesh->triangleCount = out.numberoftriangles; + for (int i = 0; i < out.numberoftriangles; ++i) + { + b3SewingPatternMeshTriangle triangle; + triangle.v1 = out.trianglelist[3 * i + 0]; + triangle.v2 = out.trianglelist[3 * i + 1]; + triangle.v3 = out.trianglelist[3 * i + 2]; + + mesh->triangles[i] = triangle; + } + + // Free the input structure + b3Free(in.pointlist); + + // Free the middle structure + free(mid.pointlist); + free(mid.pointmarkerlist); + free(mid.trianglelist); + free(mid.triangleattributelist); + free(mid.trianglearealist); + free(mid.segmentlist); + free(mid.segmentmarkerlist); + + // Free the output structure + free(out.pointlist); + free(out.pointmarkerlist); + free(out.trianglelist); + free(out.segmentlist); + free(out.segmentmarkerlist); +} + +void b3GarmentMesh::Set(b3Garment* g, float32 desiredArea) +{ + garment = g; + meshCount = garment->patternCount; + meshes = (b3SewingPatternMesh*)b3Alloc(garment->patternCount * sizeof(b3SewingPatternMesh)); + for (u32 i = 0; i < garment->patternCount; ++i) + { + b3Set(meshes + i, desiredArea, garment->patterns[i]); + } +} \ No newline at end of file