Compare commits
	
		
			9 Commits
		
	
	
		
			upstream_f
			...
			bounce-upg
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | e5897d433d | ||
|  | 1509b9bd0e | ||
|  | d728d45d70 | ||
|  | d7010a99f9 | ||
|  | 795bef7394 | ||
|  | 950de0854b | ||
|  | 5522df60b0 | ||
|  | 77fb26b578 | ||
|  | 3992eb8cc4 | 
							
								
								
									
										2
									
								
								bat/premake_vs2019.bat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								bat/premake_vs2019.bat
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | |||||||
|  | cd ..\ | ||||||
|  | premake5 solution_vs2019 | ||||||
| @@ -58,7 +58,7 @@ PROJECT_LOGO           = | |||||||
| # entered, it will be relative to the location where doxygen was started. If | # entered, it will be relative to the location where doxygen was started. If | ||||||
| # left blank the current directory will be used. | # left blank the current directory will be used. | ||||||
| 
 | 
 | ||||||
| OUTPUT_DIRECTORY       = doc/api | OUTPUT_DIRECTORY       = api | ||||||
| 
 | 
 | ||||||
| # If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- | # If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- | ||||||
| # directories (in 2 levels) under the output directory of each output format and | # directories (in 2 levels) under the output directory of each output format and | ||||||
										
											Binary file not shown.
										
									
								
							| @@ -45,7 +45,7 @@ int main(int argc, char** argv) | |||||||
| 	world->SetGravity(gravity); | 	world->SetGravity(gravity); | ||||||
| 	 | 	 | ||||||
| 	// The fixed time step size. | 	// The fixed time step size. | ||||||
| 	const float32 timeStep = 1.0f / 60.0f; | 	const scalar timeStep = 1.0f / 60.0f; | ||||||
| 	 | 	 | ||||||
| 	// Number of iterations for the velocity constraint solver. | 	// Number of iterations for the velocity constraint solver. | ||||||
| 	const u32 velocityIterations = 8; | 	const u32 velocityIterations = 8; | ||||||
| @@ -59,13 +59,7 @@ int main(int argc, char** argv) | |||||||
|  |  | ||||||
| 	// Create a box positioned at the world origin and  | 	// Create a box positioned at the world origin and  | ||||||
| 	// aligned with the world frame. | 	// aligned with the world frame. | ||||||
| 	b3BoxHull groundBox; | 	b3BoxHull groundBox(10.0f, 1.0f, 10.0f); | ||||||
| 	 |  | ||||||
| 	// Set the ground box dimensions using a linear scale transform. |  | ||||||
| 	b3Transform scale; |  | ||||||
| 	scale.position.SetZero(); |  | ||||||
| 	scale.rotation = b3Diagonal(10.0f, 1.0f, 10.0f); |  | ||||||
| 	groundBox.SetTransform(scale); |  | ||||||
|  |  | ||||||
| 	// Create the box physics wrapper. | 	// Create the box physics wrapper. | ||||||
| 	b3HullShape groundShape; | 	b3HullShape groundShape; | ||||||
| @@ -115,7 +109,7 @@ int main(int argc, char** argv) | |||||||
| 		 | 		 | ||||||
| 		// Decode the axis and angle of rotation about it from the quaternion. | 		// Decode the axis and angle of rotation about it from the quaternion. | ||||||
| 		b3Vec3 axis; | 		b3Vec3 axis; | ||||||
| 		float32 angle; | 		scalar angle; | ||||||
| 		orientation.GetAxisAngle(&axis, &angle); | 		orientation.GetAxisAngle(&axis, &angle); | ||||||
|  |  | ||||||
| 		// Visualize the body state in this frame. | 		// Visualize the body state in this frame. | ||||||
|   | |||||||
							
								
								
									
										17656
									
								
								examples/testbed/data/octopus.ele
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17656
									
								
								examples/testbed/data/octopus.ele
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										9546
									
								
								examples/testbed/data/octopus.face
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9546
									
								
								examples/testbed/data/octopus.face
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										4776
									
								
								examples/testbed/data/octopus.node
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4776
									
								
								examples/testbed/data/octopus.node
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								examples/testbed/data/teapot.cdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								examples/testbed/data/teapot.cdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -35,8 +35,19 @@ bool b3BodyDragger::StartDragging() | |||||||
| { | { | ||||||
| 	B3_ASSERT(IsDragging() == false); | 	B3_ASSERT(IsDragging() == false); | ||||||
|  |  | ||||||
|  | 	class RayCastFilter : public b3RayCastFilter | ||||||
|  | 	{ | ||||||
|  | 	public: | ||||||
|  | 		bool ShouldRayCast(b3Shape* shape) | ||||||
|  | 		{ | ||||||
|  | 			return true; | ||||||
|  | 		} | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	RayCastFilter filter; | ||||||
|  |  | ||||||
| 	b3RayCastSingleOutput out; | 	b3RayCastSingleOutput out; | ||||||
| 	if (m_world->RayCastSingle(&out, m_ray->A(), m_ray->B()) == false) | 	if (m_world->RayCastSingle(&out, &filter, m_ray->A(), m_ray->B()) == false) | ||||||
| 	{ | 	{ | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
| @@ -54,7 +65,7 @@ bool b3BodyDragger::StartDragging() | |||||||
| 	jd.bodyA = groundBody; | 	jd.bodyA = groundBody; | ||||||
| 	jd.bodyB = body; | 	jd.bodyB = body; | ||||||
| 	jd.target = out.point; | 	jd.target = out.point; | ||||||
| 	jd.maxForce = 2000.0f * body->GetMass(); | 	jd.maxForce = 1000.0f * body->GetMass(); | ||||||
|  |  | ||||||
| 	m_mouseJoint = (b3MouseJoint*)m_world->CreateJoint(jd); | 	m_mouseJoint = (b3MouseJoint*)m_world->CreateJoint(jd); | ||||||
|  |  | ||||||
| @@ -79,10 +90,10 @@ void b3BodyDragger::StopDragging() | |||||||
| 	m_shape = nullptr; | 	m_shape = nullptr; | ||||||
| } | } | ||||||
|  |  | ||||||
| b3Body* b3BodyDragger::GetBody() const | b3Shape* b3BodyDragger::GetShape() const | ||||||
| { | { | ||||||
| 	B3_ASSERT(IsDragging() == true); | 	B3_ASSERT(IsDragging() == true); | ||||||
| 	return m_shape->GetBody(); | 	return m_shape; | ||||||
| } | } | ||||||
|  |  | ||||||
| b3Vec3 b3BodyDragger::GetPointA() const | b3Vec3 b3BodyDragger::GetPointA() const | ||||||
|   | |||||||
| @@ -24,6 +24,7 @@ | |||||||
| #include <bounce/dynamics/shapes/shape.h> | #include <bounce/dynamics/shapes/shape.h> | ||||||
| #include <bounce/dynamics/body.h> | #include <bounce/dynamics/body.h> | ||||||
| #include <bounce/dynamics/world.h> | #include <bounce/dynamics/world.h> | ||||||
|  | #include <bounce/dynamics/world_listeners.h> | ||||||
| #include <bounce/dynamics/joints/mouse_joint.h> | #include <bounce/dynamics/joints/mouse_joint.h> | ||||||
|  |  | ||||||
| // A body shape dragger. | // A body shape dragger. | ||||||
| @@ -43,14 +44,14 @@ public: | |||||||
|  |  | ||||||
| 	b3Ray3* GetRay() const; | 	b3Ray3* GetRay() const; | ||||||
|  |  | ||||||
| 	b3Body* GetBody() const; | 	b3Shape* GetShape() const; | ||||||
|  |  | ||||||
| 	b3Vec3 GetPointA() const; | 	b3Vec3 GetPointA() const; | ||||||
|  |  | ||||||
| 	b3Vec3 GetPointB() const; | 	b3Vec3 GetPointB() const; | ||||||
| private: | private: | ||||||
| 	b3Ray3 * m_ray; | 	b3Ray3 * m_ray; | ||||||
| 	float32 m_x; | 	scalar m_x; | ||||||
|  |  | ||||||
| 	b3World* m_world; | 	b3World* m_world; | ||||||
| 	 | 	 | ||||||
|   | |||||||
| @@ -23,9 +23,9 @@ b3ClothDragger::b3ClothDragger(b3Ray3* ray, b3Cloth* cloth) | |||||||
| 	m_staticDrag = true; | 	m_staticDrag = true; | ||||||
| 	m_ray = ray; | 	m_ray = ray; | ||||||
| 	m_cloth = cloth; | 	m_cloth = cloth; | ||||||
| 	m_triangle = nullptr; | 	m_isDragging = false; | ||||||
| 	m_km = 10000.0f; | 	m_km = 100000.0f; | ||||||
| 	m_kd = 0.0f; | 	m_kd = 1000.0f; | ||||||
| } | } | ||||||
|  |  | ||||||
| b3ClothDragger::~b3ClothDragger() | b3ClothDragger::~b3ClothDragger() | ||||||
| @@ -43,22 +43,20 @@ bool b3ClothDragger::StartDragging() | |||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	m_mesh = m_cloth->GetMesh(); | 	m_isDragging = true; | ||||||
| 	m_triangleIndex = rayOut.triangle; |  | ||||||
| 	m_triangle = m_mesh->triangles + m_triangleIndex; |  | ||||||
| 	m_x = rayOut.fraction; | 	m_x = rayOut.fraction; | ||||||
|  |  | ||||||
| 	b3Particle* p1 = m_cloth->GetParticle(m_triangle->v1); | 	m_p1 = rayOut.triangle->GetParticle1(); | ||||||
| 	b3Particle* p2 = m_cloth->GetParticle(m_triangle->v2); | 	m_p2 = rayOut.triangle->GetParticle2(); | ||||||
| 	b3Particle* p3 = m_cloth->GetParticle(m_triangle->v3); | 	m_p3 = rayOut.triangle->GetParticle3(); | ||||||
|  |  | ||||||
| 	b3Vec3 v1 = p1->GetPosition(); | 	b3Vec3 v1 = m_p1->GetPosition(); | ||||||
| 	b3Vec3 v2 = p2->GetPosition(); | 	b3Vec3 v2 = m_p2->GetPosition(); | ||||||
| 	b3Vec3 v3 = p3->GetPosition(); | 	b3Vec3 v3 = m_p3->GetPosition(); | ||||||
|  |  | ||||||
| 	b3Vec3 B = GetPointB(); | 	b3Vec3 B = GetPointB(); | ||||||
|  |  | ||||||
| 	float32 wABC[4]; | 	scalar wABC[4]; | ||||||
| 	b3BarycentricCoordinates(wABC, v1, v2, v3, B); | 	b3BarycentricCoordinates(wABC, v1, v2, v3, B); | ||||||
|  |  | ||||||
| 	if (wABC[3] > B3_EPSILON) | 	if (wABC[3] > B3_EPSILON) | ||||||
| @@ -73,33 +71,34 @@ bool b3ClothDragger::StartDragging() | |||||||
|  |  | ||||||
| 	if (m_staticDrag) | 	if (m_staticDrag) | ||||||
| 	{ | 	{ | ||||||
| 		m_t1 = p1->GetType(); | 		m_t1 = m_p1->GetType(); | ||||||
| 		p1->SetType(e_staticParticle); | 		m_p1->SetType(e_staticClothParticle); | ||||||
|  |  | ||||||
| 		m_t2 = p2->GetType(); | 		m_t2 = m_p2->GetType(); | ||||||
| 		p2->SetType(e_staticParticle); | 		m_p2->SetType(e_staticClothParticle); | ||||||
|  |  | ||||||
| 		m_t3 = p3->GetType(); | 		m_t3 = m_p3->GetType(); | ||||||
| 		p3->SetType(e_staticParticle); | 		m_p3->SetType(e_staticClothParticle); | ||||||
| 	} | 	} | ||||||
| 	else | 	else | ||||||
| 	{ | 	{ | ||||||
| 		b3ParticleDef pd; | 		b3ClothParticleDef pd; | ||||||
| 		pd.type = e_staticParticle; | 		pd.type = e_staticClothParticle; | ||||||
| 		pd.position = GetPointA(); | 		pd.position = GetPointA(); | ||||||
|  |  | ||||||
| 		m_particle = m_cloth->CreateParticle(pd); | 		m_particle = m_cloth->CreateParticle(pd); | ||||||
|  |  | ||||||
| 		b3ClothTriangle* triangle = m_cloth->GetTriangle(m_triangleIndex); |  | ||||||
|  |  | ||||||
| 		b3MouseForceDef def; | 		b3MouseForceDef def; | ||||||
| 		def.particle = m_particle; | 		def.p1 = m_particle; | ||||||
| 		def.triangle = triangle; | 		def.p2 = m_p1; | ||||||
|  | 		def.p3 = m_p2; | ||||||
|  | 		def.p4 = m_p3; | ||||||
| 		def.w2 = m_u; | 		def.w2 = m_u; | ||||||
| 		def.w3 = m_v; | 		def.w3 = m_v; | ||||||
| 		def.w4 = (1.0f - m_u - m_v); | 		def.w4 = 1.0f - m_u - m_v; | ||||||
| 		def.mouse = m_km; | 		def.mouse = m_km; | ||||||
| 		def.damping = m_kd; | 		def.damping = m_kd; | ||||||
|  | 		def.restLength = 0.0f; | ||||||
|  |  | ||||||
| 		m_mf = (b3MouseForce*)m_cloth->CreateForce(def); | 		m_mf = (b3MouseForce*)m_cloth->CreateForce(def); | ||||||
| 	} | 	} | ||||||
| @@ -111,24 +110,23 @@ void b3ClothDragger::Drag() | |||||||
| { | { | ||||||
| 	B3_ASSERT(IsDragging() == true); | 	B3_ASSERT(IsDragging() == true); | ||||||
|  |  | ||||||
| 	b3Vec3 A = GetPointA(); |  | ||||||
| 	b3Vec3 B = GetPointB(); | 	b3Vec3 B = GetPointB(); | ||||||
|  |  | ||||||
| 	b3Vec3 dx = B - A; |  | ||||||
|  |  | ||||||
| 	if (m_staticDrag) | 	if (m_staticDrag) | ||||||
| 	{ | 	{ | ||||||
| 		b3Particle* p1 = m_cloth->GetParticle(m_triangle->v1); | 		b3Vec3 A = GetPointA(); | ||||||
| 		p1->ApplyTranslation(dx); |  | ||||||
|  |  | ||||||
| 		b3Particle* p2 = m_cloth->GetParticle(m_triangle->v2); | 		b3Vec3 dx = B - A; | ||||||
| 		p2->ApplyTranslation(dx); |  | ||||||
|  |  | ||||||
| 		b3Particle* p3 = m_cloth->GetParticle(m_triangle->v3); | 		m_p1->ApplyTranslation(dx); | ||||||
| 		p3->ApplyTranslation(dx); | 		m_p2->ApplyTranslation(dx); | ||||||
|  | 		m_p3->ApplyTranslation(dx); | ||||||
| 	} | 	} | ||||||
| 	else | 	else | ||||||
| 	{ | 	{ | ||||||
|  | 		//b3Vec3 A = m_particle->GetPosition(); | ||||||
|  | 		//b3Vec3 dx = B - A;		 | ||||||
|  | 		//m_particle->ApplyTranslation(dx); | ||||||
| 		m_particle->SetPosition(B); | 		m_particle->SetPosition(B); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @@ -154,9 +152,9 @@ void b3ClothDragger::StopDragging() | |||||||
|  |  | ||||||
| 	if (m_staticDrag) | 	if (m_staticDrag) | ||||||
| 	{ | 	{ | ||||||
| 		m_cloth->GetParticle(m_triangle->v1)->SetType(m_t1); | 		m_p1->SetType(m_t1); | ||||||
| 		m_cloth->GetParticle(m_triangle->v2)->SetType(m_t2); | 		m_p2->SetType(m_t2); | ||||||
| 		m_cloth->GetParticle(m_triangle->v3)->SetType(m_t3); | 		m_p3->SetType(m_t3); | ||||||
| 	} | 	} | ||||||
| 	else | 	else | ||||||
| 	{ | 	{ | ||||||
| @@ -164,18 +162,18 @@ void b3ClothDragger::StopDragging() | |||||||
| 		m_cloth->DestroyParticle(m_particle); | 		m_cloth->DestroyParticle(m_particle); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	m_triangle = nullptr; | 	m_isDragging = false; | ||||||
| } | } | ||||||
|  |  | ||||||
| b3Vec3 b3ClothDragger::GetPointA() const | b3Vec3 b3ClothDragger::GetPointA() const | ||||||
| { | { | ||||||
| 	B3_ASSERT(IsDragging() == true); | 	B3_ASSERT(IsDragging() == true); | ||||||
|  |  | ||||||
| 	b3Vec3 A = m_cloth->GetParticle(m_triangle->v1)->GetPosition(); | 	b3Vec3 v1 = m_p1->GetPosition() + m_p1->GetTranslation(); | ||||||
| 	b3Vec3 B = m_cloth->GetParticle(m_triangle->v2)->GetPosition(); | 	b3Vec3 v2 = m_p2->GetPosition() + m_p2->GetTranslation(); | ||||||
| 	b3Vec3 C = m_cloth->GetParticle(m_triangle->v3)->GetPosition(); | 	b3Vec3 v3 = m_p3->GetPosition() + m_p3->GetTranslation(); | ||||||
|  |  | ||||||
| 	return m_u * A + m_v * B + (1.0f - m_u - m_v) * C; | 	return m_u * v1 + m_v * v2 + (1.0f - m_u - m_v) * v3; | ||||||
| } | } | ||||||
|  |  | ||||||
| b3Vec3 b3ClothDragger::GetPointB() const | b3Vec3 b3ClothDragger::GetPointB() const | ||||||
|   | |||||||
| @@ -21,9 +21,8 @@ | |||||||
|  |  | ||||||
| #include <bounce/common/geometry.h> | #include <bounce/common/geometry.h> | ||||||
| #include <bounce/cloth/cloth.h> | #include <bounce/cloth/cloth.h> | ||||||
| #include <bounce/cloth/cloth_mesh.h> | #include <bounce/cloth/cloth_particle.h> | ||||||
| #include <bounce/cloth/particle.h> | #include <bounce/cloth/shapes/cloth_triangle_shape.h> | ||||||
| #include <bounce/cloth/cloth_triangle.h> |  | ||||||
| #include <bounce/cloth/forces/mouse_force.h> | #include <bounce/cloth/forces/mouse_force.h> | ||||||
|  |  | ||||||
| // A cloth triangle dragger. | // A cloth triangle dragger. | ||||||
| @@ -37,13 +36,13 @@ public: | |||||||
|  |  | ||||||
| 	bool GetStaticDrag() const; | 	bool GetStaticDrag() const; | ||||||
|  |  | ||||||
| 	void SetMouseStiffness(float32 k); | 	void SetMouseStiffness(scalar k); | ||||||
|  |  | ||||||
| 	float32 GetMouseStiffness(); | 	scalar GetMouseStiffness(); | ||||||
|  |  | ||||||
| 	void SetMouseDamping(float32 k); | 	void SetMouseDamping(scalar k); | ||||||
|  |  | ||||||
| 	float32 GetMouseDamping(); | 	scalar GetMouseDamping(); | ||||||
| 	 | 	 | ||||||
| 	bool IsDragging() const; | 	bool IsDragging() const; | ||||||
|  |  | ||||||
| @@ -58,21 +57,23 @@ public: | |||||||
| 	b3Vec3 GetPointB() const; | 	b3Vec3 GetPointB() const; | ||||||
| private: | private: | ||||||
| 	b3Ray3* m_ray; | 	b3Ray3* m_ray; | ||||||
| 	float32 m_x; | 	scalar m_x; | ||||||
|  |  | ||||||
| 	b3Cloth* m_cloth; | 	b3Cloth* m_cloth; | ||||||
| 	const b3ClothMesh* m_mesh; |  | ||||||
| 	u32 m_triangleIndex; |  | ||||||
| 	b3ClothMeshTriangle* m_triangle; |  | ||||||
| 	float32 m_u, m_v; |  | ||||||
| 	 | 	 | ||||||
| 	float32 m_km; | 	bool m_isDragging; | ||||||
| 	float32 m_kd; | 	b3ClothParticle* m_p1; | ||||||
| 	b3Particle* m_particle; | 	b3ClothParticle* m_p2; | ||||||
|  | 	b3ClothParticle* m_p3; | ||||||
|  | 	scalar m_u, m_v; | ||||||
|  |  | ||||||
|  | 	scalar m_km; | ||||||
|  | 	scalar m_kd; | ||||||
|  | 	b3ClothParticle* m_particle; | ||||||
| 	b3MouseForce* m_mf; | 	b3MouseForce* m_mf; | ||||||
|  |  | ||||||
| 	bool m_staticDrag; | 	bool m_staticDrag; | ||||||
| 	b3ParticleType m_t1, m_t2, m_t3; | 	b3ClothParticleType m_t1, m_t2, m_t3; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| inline bool b3ClothDragger::GetStaticDrag() const | inline bool b3ClothDragger::GetStaticDrag() const | ||||||
| @@ -80,29 +81,29 @@ inline bool b3ClothDragger::GetStaticDrag() const | |||||||
| 	return m_staticDrag; | 	return m_staticDrag; | ||||||
| } | } | ||||||
|  |  | ||||||
| inline void b3ClothDragger::SetMouseStiffness(float32 k) | inline void b3ClothDragger::SetMouseStiffness(scalar k) | ||||||
| { | { | ||||||
| 	m_km = k; | 	m_km = k; | ||||||
| } | } | ||||||
|  |  | ||||||
| inline float32 b3ClothDragger::GetMouseStiffness() | inline scalar b3ClothDragger::GetMouseStiffness() | ||||||
| { | { | ||||||
| 	return m_km; | 	return m_km; | ||||||
| } | } | ||||||
|  |  | ||||||
| inline void b3ClothDragger::SetMouseDamping(float32 k) | inline void b3ClothDragger::SetMouseDamping(scalar k) | ||||||
| { | { | ||||||
| 	m_kd = k; | 	m_kd = k; | ||||||
| } | } | ||||||
|  |  | ||||||
| inline float32 b3ClothDragger::GetMouseDamping() | inline scalar b3ClothDragger::GetMouseDamping() | ||||||
| { | { | ||||||
| 	return m_kd; | 	return m_kd; | ||||||
| } | } | ||||||
|  |  | ||||||
| inline bool b3ClothDragger::IsDragging() const | inline bool b3ClothDragger::IsDragging() const | ||||||
| { | { | ||||||
| 	return m_triangle != nullptr; | 	return m_isDragging; | ||||||
| } | } | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
| @@ -50,17 +50,17 @@ Camera::Camera() | |||||||
|  |  | ||||||
| b3Mat44 Camera::BuildProjectionMatrix() const | b3Mat44 Camera::BuildProjectionMatrix() const | ||||||
| { | { | ||||||
| 	float32 w = m_width, h = m_height; | 	scalar w = m_width, h = m_height; | ||||||
| 	 | 	 | ||||||
| 	float32 t = tan(0.5f * m_fovy); | 	scalar t = tan(0.5f * m_fovy); | ||||||
| 	float32 ratio = w / h; | 	scalar ratio = w / h; | ||||||
| 	float32 sx = 1.0f / (ratio * t); | 	scalar sx = 1.0f / (ratio * t); | ||||||
| 	float32 sy = 1.0f / t; | 	scalar sy = 1.0f / t; | ||||||
| 	 | 	 | ||||||
| 	float32 inv_range = 1.0f / (m_zNear - m_zFar); | 	scalar inv_range = 1.0f / (m_zNear - m_zFar); | ||||||
| 	float32 sz = inv_range * (m_zNear + m_zFar); | 	scalar sz = inv_range * (m_zNear + m_zFar); | ||||||
| 	 | 	 | ||||||
| 	float32 tz = inv_range * m_zNear * m_zFar; | 	scalar tz = inv_range * m_zNear * m_zFar; | ||||||
|  |  | ||||||
| 	b3Mat44 m; | 	b3Mat44 m; | ||||||
| 	m.x = b3Vec4(sx, 0.0f, 0.0f, 0.0f); | 	m.x = b3Vec4(sx, 0.0f, 0.0f, 0.0f); | ||||||
| @@ -73,8 +73,8 @@ b3Mat44 Camera::BuildProjectionMatrix() const | |||||||
| b3Transform Camera::BuildWorldTransform() const | b3Transform Camera::BuildWorldTransform() const | ||||||
| { | { | ||||||
| 	b3Transform xf; | 	b3Transform xf; | ||||||
| 	xf.rotation = b3QuatMat33(m_q); | 	xf.rotation = m_q; | ||||||
| 	xf.position = (m_zoom * xf.rotation.z) - m_center; | 	xf.translation = (m_zoom * m_q.GetZAxis()) - m_center; | ||||||
| 	return xf; | 	return xf; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -87,8 +87,8 @@ b3Mat44 Camera::BuildWorldMatrix() const | |||||||
| b3Transform Camera::BuildViewTransform() const | b3Transform Camera::BuildViewTransform() const | ||||||
| { | { | ||||||
| 	b3Transform xf; | 	b3Transform xf; | ||||||
| 	xf.rotation = b3QuatMat33(m_q); | 	xf.rotation = m_q; | ||||||
| 	xf.position = (m_zoom * xf.rotation.z) - m_center; | 	xf.translation = (m_zoom * m_q.GetZAxis()) - m_center; | ||||||
| 	return b3Inverse(xf); | 	return b3Inverse(xf); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -100,7 +100,7 @@ b3Mat44 Camera::BuildViewMatrix() const | |||||||
|  |  | ||||||
| b3Vec2 Camera::ConvertWorldToScreen(const b3Vec3& pw3) const | b3Vec2 Camera::ConvertWorldToScreen(const b3Vec3& pw3) const | ||||||
| { | { | ||||||
| 	float32 w = m_width, h = m_height; | 	scalar w = m_width, h = m_height; | ||||||
| 	b3Mat44 P = BuildProjectionMatrix(); | 	b3Mat44 P = BuildProjectionMatrix(); | ||||||
| 	b3Mat44 V = BuildViewMatrix(); | 	b3Mat44 V = BuildViewMatrix(); | ||||||
|  |  | ||||||
| @@ -109,11 +109,11 @@ b3Vec2 Camera::ConvertWorldToScreen(const b3Vec3& pw3) const | |||||||
| 	b3Vec4 pp = P * V * pw; | 	b3Vec4 pp = P * V * pw; | ||||||
|  |  | ||||||
| 	b3Vec3 pn(pp.x, pp.y, pp.z); | 	b3Vec3 pn(pp.x, pp.y, pp.z); | ||||||
| 	float32 inv_w = pp.w != 0.0f ? 1.0f / pp.w : 1.0f; | 	scalar inv_w = pp.w != 0.0f ? 1.0f / pp.w : 1.0f; | ||||||
| 	pn *= inv_w; | 	pn *= inv_w; | ||||||
|  |  | ||||||
| 	float32 u = 0.5f * (pn.x + 1.0f); | 	scalar u = 0.5f * (pn.x + 1.0f); | ||||||
| 	float32 v = 0.5f * (pn.y + 1.0f); | 	scalar v = 0.5f * (pn.y + 1.0f); | ||||||
|  |  | ||||||
| 	b3Vec2 ps; | 	b3Vec2 ps; | ||||||
| 	ps.x = u * w; | 	ps.x = u * w; | ||||||
| @@ -123,10 +123,10 @@ b3Vec2 Camera::ConvertWorldToScreen(const b3Vec3& pw3) const | |||||||
|  |  | ||||||
| b3Ray3 Camera::ConvertScreenToWorld(const b3Vec2& ps) const | b3Ray3 Camera::ConvertScreenToWorld(const b3Vec2& ps) const | ||||||
| { | { | ||||||
| 	float32 w = m_width, h = m_height; | 	scalar w = m_width, h = m_height; | ||||||
| 	 | 	 | ||||||
| 	float32 t = tan(0.5f * m_fovy); | 	scalar t = tan(0.5f * m_fovy); | ||||||
| 	float32 ratio = w / h; | 	scalar ratio = w / h; | ||||||
| 	 | 	 | ||||||
| 	b3Vec3 vv; | 	b3Vec3 vv; | ||||||
| 	vv.x = 2.0f * ratio * ps.x / w - ratio; | 	vv.x = 2.0f * ratio * ps.x / w - ratio; | ||||||
| @@ -135,12 +135,12 @@ b3Ray3 Camera::ConvertScreenToWorld(const b3Vec2& ps) const | |||||||
|  |  | ||||||
| 	b3Transform xf = BuildWorldTransform(); | 	b3Transform xf = BuildWorldTransform(); | ||||||
| 	 | 	 | ||||||
| 	b3Vec3 vw = xf.rotation * vv; | 	b3Vec3 vw = b3Mul(xf.rotation, vv); | ||||||
| 	vw.Normalize(); | 	vw.Normalize(); | ||||||
|  |  | ||||||
| 	b3Ray3 rw; | 	b3Ray3 rw; | ||||||
| 	rw.direction = vw; | 	rw.direction = vw; | ||||||
| 	rw.origin = xf.position; | 	rw.origin = xf.translation; | ||||||
| 	rw.fraction = m_zFar; | 	rw.fraction = m_zFar; | ||||||
| 	return rw; | 	return rw; | ||||||
| } | } | ||||||
| @@ -194,7 +194,7 @@ void Draw::EnableDrawTriangles(bool flag) | |||||||
| 	g_glDrawTriangles = flag; | 	g_glDrawTriangles = flag; | ||||||
| } | } | ||||||
|  |  | ||||||
| void Draw::DrawPoint(const b3Vec3& p, float32 size, const b3Color& color) | void Draw::DrawPoint(const b3Vec3& p, scalar size, const b3Color& color) | ||||||
| { | { | ||||||
| 	m_points->Vertex(p, size, color); | 	m_points->Vertex(p, size, color); | ||||||
| } | } | ||||||
| @@ -249,14 +249,15 @@ void Draw::DrawSolidPolygon(const b3Vec3& normal, const b3Vec3* vertices, u32 co | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| void Draw::DrawCircle(const b3Vec3& normal, const b3Vec3& center, float32 radius, const b3Color& color) | void Draw::DrawCircle(const b3Vec3& normal, const b3Vec3& center, scalar radius, const b3Color& color) | ||||||
| { | { | ||||||
| 	b3Vec3 n1, n3; | 	b3Vec3 n1, n3; | ||||||
| 	b3ComputeBasis(normal, n1, n3); | 	b3ComputeBasis(normal, n1, n3); | ||||||
|  |  | ||||||
| 	u32 kEdgeCount = 20; | 	u32 kEdgeCount = 20; | ||||||
| 	float32 kAngleInc = 2.0f * B3_PI / float32(kEdgeCount); | 	scalar kAngleInc = 2.0f * B3_PI / scalar(kEdgeCount); | ||||||
| 	b3Quat q(normal, kAngleInc); | 	b3Quat q; | ||||||
|  | 	q.SetAxisAngle(normal, kAngleInc); | ||||||
|  |  | ||||||
| 	b3Vec3 p1 = center + radius * n1; | 	b3Vec3 p1 = center + radius * n1; | ||||||
| 	for (u32 i = 0; i < kEdgeCount; ++i) | 	for (u32 i = 0; i < kEdgeCount; ++i) | ||||||
| @@ -272,7 +273,7 @@ void Draw::DrawCircle(const b3Vec3& normal, const b3Vec3& center, float32 radius | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| void Draw::DrawSolidCircle(const b3Vec3& normal, const b3Vec3& center, float32 radius, const b3Color& color) | void Draw::DrawSolidCircle(const b3Vec3& normal, const b3Vec3& center, scalar radius, const b3Color& color) | ||||||
| { | { | ||||||
| 	b3Color fillColor(color.r, color.g, color.b, color.a); | 	b3Color fillColor(color.r, color.g, color.b, color.a); | ||||||
| 	b3Color frameColor(0.5f * color.r, 0.5f * color.g, 0.5f * color.b, 1.0f); | 	b3Color frameColor(0.5f * color.r, 0.5f * color.g, 0.5f * color.b, 1.0f); | ||||||
| @@ -281,8 +282,10 @@ void Draw::DrawSolidCircle(const b3Vec3& normal, const b3Vec3& center, float32 r | |||||||
| 	b3ComputeBasis(normal, n1, n3); | 	b3ComputeBasis(normal, n1, n3); | ||||||
|  |  | ||||||
| 	const u32 kEdgeCount = 20; | 	const u32 kEdgeCount = 20; | ||||||
| 	const float32 kAngleInc = 2.0f * B3_PI / float32(kEdgeCount); | 	const scalar kAngleInc = 2.0f * B3_PI / scalar(kEdgeCount); | ||||||
| 	b3Quat q(normal, kAngleInc); | 	 | ||||||
|  | 	b3Quat q; | ||||||
|  | 	q.SetAxisAngle(normal, kAngleInc); | ||||||
|  |  | ||||||
| 	b3Vec3 p1 = center + radius * n1; | 	b3Vec3 p1 = center + radius * n1; | ||||||
| 	for (u32 i = 0; i < kEdgeCount; ++i) | 	for (u32 i = 0; i < kEdgeCount; ++i) | ||||||
| @@ -299,32 +302,32 @@ void Draw::DrawSolidCircle(const b3Vec3& normal, const b3Vec3& center, float32 r | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| void Draw::DrawSphere(const b3Vec3& center, float32 radius, const b3Color& color) | void Draw::DrawSphere(const b3Vec3& center, scalar radius, const b3Color& color) | ||||||
| { | { | ||||||
| 	b3Transform xf; | 	b3Transform xf; | ||||||
| 	xf.rotation.SetIdentity(); | 	xf.rotation.SetIdentity(); | ||||||
| 	xf.position = center; | 	xf.translation = center; | ||||||
|  |  | ||||||
| 	m_wire->DrawSphere(radius, color, xf); | 	m_wire->DrawSphere(radius, color, xf); | ||||||
| } | } | ||||||
|  |  | ||||||
| void Draw::DrawSolidSphere(const b3Vec3& center, float32 radius, const b3Mat33& rotation, const b3Color& color) | void Draw::DrawSolidSphere(const b3Vec3& center, scalar radius, const b3Quat& rotation, const b3Color& color) | ||||||
| { | { | ||||||
| 	b3Transform xf; | 	b3Transform xf; | ||||||
| 	xf.rotation = rotation; | 	xf.rotation = rotation; | ||||||
| 	xf.position = center; | 	xf.translation = center; | ||||||
|  |  | ||||||
| 	m_solid->DrawSphere(radius, color, xf); | 	m_solid->DrawSphere(radius, color, xf); | ||||||
| } | } | ||||||
|  |  | ||||||
| void Draw::DrawCapsule(const b3Vec3& c1, const b3Vec3& c2, float32 radius, const b3Color& color) | void Draw::DrawCapsule(const b3Vec3& c1, const b3Vec3& c2, scalar radius, const b3Color& color) | ||||||
| { | { | ||||||
| 	float32 height = b3Length(c1 - c2); | 	scalar height = b3Length(c1 - c2); | ||||||
|  |  | ||||||
| 	{ | 	{ | ||||||
| 		b3Transform xf; | 		b3Transform xf; | ||||||
| 		xf.rotation.SetIdentity(); | 		xf.rotation.SetIdentity(); | ||||||
| 		xf.position = c1; | 		xf.translation = c1; | ||||||
| 		m_wire->DrawSphere(radius, color, xf); | 		m_wire->DrawSphere(radius, color, xf); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -335,20 +338,20 @@ void Draw::DrawCapsule(const b3Vec3& c1, const b3Vec3& c2, float32 radius, const | |||||||
| 		{ | 		{ | ||||||
| 			b3Transform xf; | 			b3Transform xf; | ||||||
| 			xf.rotation.SetIdentity(); | 			xf.rotation.SetIdentity(); | ||||||
| 			xf.position = c2; | 			xf.translation = c2; | ||||||
| 			m_wire->DrawSphere(radius, color, xf); | 			m_wire->DrawSphere(radius, color, xf); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| void Draw::DrawSolidCapsule(const b3Vec3& c1, const b3Vec3& c2, float32 radius, const b3Mat33& rotation, const b3Color& c) | void Draw::DrawSolidCapsule(const b3Vec3& c1, const b3Vec3& c2, scalar radius, const b3Quat& rotation, const b3Color& c) | ||||||
| { | { | ||||||
| 	float32 height = b3Length(c1 - c2); | 	scalar height = b3Length(c1 - c2); | ||||||
|  |  | ||||||
| 	{ | 	{ | ||||||
| 		b3Transform xf; | 		b3Transform xf; | ||||||
| 		xf.rotation = rotation; | 		xf.rotation = rotation; | ||||||
| 		xf.position = c1; | 		xf.translation = c1; | ||||||
| 		m_solid->DrawSphere(radius, c, xf); | 		m_solid->DrawSphere(radius, c, xf); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -359,9 +362,11 @@ void Draw::DrawSolidCapsule(const b3Vec3& c1, const b3Vec3& c2, float32 radius, | |||||||
| 			R.y = (1.0f / height) * (c1 - c2); | 			R.y = (1.0f / height) * (c1 - c2); | ||||||
| 			b3ComputeBasis(R.y, R.z, R.x); | 			b3ComputeBasis(R.y, R.z, R.x); | ||||||
|  |  | ||||||
|  | 			b3Quat Q = b3Mat33Quat(R); | ||||||
|  |  | ||||||
| 			b3Transform xf; | 			b3Transform xf; | ||||||
| 			xf.position = 0.5f * (c1 + c2); | 			xf.translation = 0.5f * (c1 + c2); | ||||||
| 			xf.rotation = R; | 			xf.rotation = Q; | ||||||
|  |  | ||||||
| 			m_solid->DrawCylinder(radius, height, c, xf); | 			m_solid->DrawCylinder(radius, height, c, xf); | ||||||
| 		} | 		} | ||||||
| @@ -369,7 +374,7 @@ void Draw::DrawSolidCapsule(const b3Vec3& c1, const b3Vec3& c2, float32 radius, | |||||||
| 		{ | 		{ | ||||||
| 			b3Transform xf; | 			b3Transform xf; | ||||||
| 			xf.rotation = rotation; | 			xf.rotation = rotation; | ||||||
| 			xf.position = c2; | 			xf.translation = c2; | ||||||
| 			m_solid->DrawSphere(radius, c, xf); | 			m_solid->DrawSphere(radius, c, xf); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -377,24 +382,24 @@ void Draw::DrawSolidCapsule(const b3Vec3& c1, const b3Vec3& c2, float32 radius, | |||||||
|  |  | ||||||
| void Draw::DrawTransform(const b3Transform& xf) | void Draw::DrawTransform(const b3Transform& xf) | ||||||
| { | { | ||||||
| 	float32 lenght = 1.0f; | 	scalar lenght = 1.0f; | ||||||
|  |  | ||||||
| 	b3Vec3 position = xf.position; | 	b3Vec3 translation = xf.translation; | ||||||
| 	b3Mat33 rotation = xf.rotation; | 	b3Mat33 rotation = b3QuatMat33(xf.rotation); | ||||||
|  |  | ||||||
| 	b3Vec3 A = position + lenght * rotation.x; | 	b3Vec3 A = translation + lenght * rotation.x; | ||||||
| 	b3Vec3 B = position + lenght * rotation.y; | 	b3Vec3 B = translation + lenght * rotation.y; | ||||||
| 	b3Vec3 C = position + lenght * rotation.z; | 	b3Vec3 C = translation + lenght * rotation.z; | ||||||
|  |  | ||||||
| 	DrawSegment(position, A, b3Color_red); | 	DrawSegment(translation, A, b3Color_red); | ||||||
| 	DrawSegment(position, B, b3Color_green); | 	DrawSegment(translation, B, b3Color_green); | ||||||
| 	DrawSegment(position, C, b3Color_blue); | 	DrawSegment(translation, C, b3Color_blue); | ||||||
| } | } | ||||||
|  |  | ||||||
| void Draw::DrawAABB(const b3AABB3& aabb, const b3Color& color) | void Draw::DrawAABB(const b3AABB& aabb, const b3Color& color) | ||||||
| { | { | ||||||
| 	b3Vec3 lower = aabb.m_lower; | 	b3Vec3 lower = aabb.lowerBound; | ||||||
| 	b3Vec3 upper = aabb.m_upper; | 	b3Vec3 upper = aabb.upperBound; | ||||||
|  |  | ||||||
| 	b3Vec3 vs[8]; | 	b3Vec3 vs[8]; | ||||||
|  |  | ||||||
| @@ -425,12 +430,12 @@ void Draw::DrawAABB(const b3AABB3& aabb, const b3Color& color) | |||||||
| 	DrawSegment(vs[1], vs[7], color); | 	DrawSegment(vs[1], vs[7], color); | ||||||
| } | } | ||||||
|  |  | ||||||
| void Draw::DrawPlane(const b3Vec3& normal, const b3Vec3& center, float32 radius, const b3Color& color) | void Draw::DrawPlane(const b3Vec3& normal, const b3Vec3& center, scalar radius, const b3Color& color) | ||||||
| { | { | ||||||
| 	b3Vec3 n1, n2; | 	b3Vec3 n1, n2; | ||||||
| 	b3ComputeBasis(normal, n1, n2); | 	b3ComputeBasis(normal, n1, n2); | ||||||
|  |  | ||||||
| 	float32 scale = 2.0f * radius; | 	scalar scale = 2.0f * radius; | ||||||
| 	 | 	 | ||||||
| 	// v1__v4 | 	// v1__v4 | ||||||
| 	// |    | | 	// |    | | ||||||
| @@ -448,14 +453,14 @@ void Draw::DrawPlane(const b3Vec3& normal, const b3Vec3& center, float32 radius, | |||||||
| 	DrawSegment(center, center + normal, color); | 	DrawSegment(center, center + normal, color); | ||||||
| } | } | ||||||
|  |  | ||||||
| void Draw::DrawSolidPlane(const b3Vec3& normal, const b3Vec3& center, float32 radius, const b3Color& color) | void Draw::DrawSolidPlane(const b3Vec3& normal, const b3Vec3& center, scalar radius, const b3Color& color) | ||||||
| { | { | ||||||
| 	b3Color frameColor(0.5f * color.r, 0.5f * color.g, 0.5f * color.b, 1.0f); | 	b3Color frameColor(0.5f * color.r, 0.5f * color.g, 0.5f * color.b, 1.0f); | ||||||
|  |  | ||||||
| 	b3Vec3 n1, n2; | 	b3Vec3 n1, n2; | ||||||
| 	b3ComputeBasis(normal, n1, n2); | 	b3ComputeBasis(normal, n1, n2); | ||||||
|  |  | ||||||
| 	float32 scale = 2.0f * radius; | 	scalar scale = 2.0f * radius; | ||||||
|  |  | ||||||
| 	b3Vec3 v1 = center - scale * n1 - scale * n2; | 	b3Vec3 v1 = center - scale * n1 - scale * n2; | ||||||
| 	b3Vec3 v2 = center + scale * n1 - scale * n2; | 	b3Vec3 v2 = center + scale * n1 - scale * n2; | ||||||
|   | |||||||
| @@ -42,13 +42,13 @@ public: | |||||||
| 	b3Vec2 ConvertWorldToScreen(const b3Vec3& pw) const; | 	b3Vec2 ConvertWorldToScreen(const b3Vec3& pw) const; | ||||||
| 	b3Ray3 ConvertScreenToWorld(const b3Vec2& ps) const; | 	b3Ray3 ConvertScreenToWorld(const b3Vec2& ps) const; | ||||||
|  |  | ||||||
| 	float32 m_zoom; | 	scalar m_zoom; | ||||||
| 	b3Vec3 m_center; | 	b3Vec3 m_center; | ||||||
| 	b3Quat m_q; | 	b3Quat m_q; | ||||||
| 	float32 m_width, m_height; | 	scalar m_width, m_height; | ||||||
| 	float32 m_fovy; | 	scalar m_fovy; | ||||||
| 	float32 m_zNear; | 	scalar m_zNear; | ||||||
| 	float32 m_zFar; | 	scalar m_zFar; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| class Draw : public b3Draw | class Draw : public b3Draw | ||||||
| @@ -67,7 +67,7 @@ public: | |||||||
| 	 | 	 | ||||||
| 	void EnableDrawTriangles(bool flag); | 	void EnableDrawTriangles(bool flag); | ||||||
|  |  | ||||||
| 	void DrawPoint(const b3Vec3& p, float32 size, const b3Color& color); | 	void DrawPoint(const b3Vec3& p, scalar size, const b3Color& color); | ||||||
|  |  | ||||||
| 	void DrawSegment(const b3Vec3& p1, const b3Vec3& p2, const b3Color& color); | 	void DrawSegment(const b3Vec3& p1, const b3Vec3& p2, const b3Color& color); | ||||||
| 	 | 	 | ||||||
| @@ -79,23 +79,23 @@ public: | |||||||
| 	 | 	 | ||||||
| 	void DrawSolidPolygon(const b3Vec3& normal, const b3Vec3* vertices, u32 count, const b3Color& color); | 	void DrawSolidPolygon(const b3Vec3& normal, const b3Vec3* vertices, u32 count, const b3Color& color); | ||||||
|  |  | ||||||
| 	void DrawCircle(const b3Vec3& normal, const b3Vec3& center, float32 radius, const b3Color& color); | 	void DrawCircle(const b3Vec3& normal, const b3Vec3& center, scalar radius, const b3Color& color); | ||||||
|  |  | ||||||
| 	void DrawSolidCircle(const b3Vec3& normal, const b3Vec3& center, float32 radius, const b3Color& color); | 	void DrawSolidCircle(const b3Vec3& normal, const b3Vec3& center, scalar radius, const b3Color& color); | ||||||
|  |  | ||||||
| 	void DrawSphere(const b3Vec3& center, float32 radius, const b3Color& color); | 	void DrawSphere(const b3Vec3& center, scalar radius, const b3Color& color); | ||||||
| 	 | 	 | ||||||
| 	void DrawSolidSphere(const b3Vec3& center, float32 radius, const b3Mat33& rotation, const b3Color& color); | 	void DrawSolidSphere(const b3Vec3& center, scalar radius, const b3Quat& rotation, const b3Color& color); | ||||||
|  |  | ||||||
| 	void DrawCapsule(const b3Vec3& p1, const b3Vec3& p2, float32 radius, const b3Color& color); | 	void DrawCapsule(const b3Vec3& p1, const b3Vec3& p2, scalar radius, const b3Color& color); | ||||||
|  |  | ||||||
| 	void DrawSolidCapsule(const b3Vec3& p1, const b3Vec3& p2, float32 radius, const b3Mat33& rotation, const b3Color& color); | 	void DrawSolidCapsule(const b3Vec3& p1, const b3Vec3& p2, scalar radius, const b3Quat& rotation, const b3Color& color); | ||||||
|  |  | ||||||
| 	void DrawPlane(const b3Vec3& normal, const b3Vec3& center, float32 radius, const b3Color& color); | 	void DrawPlane(const b3Vec3& normal, const b3Vec3& center, scalar radius, const b3Color& color); | ||||||
|  |  | ||||||
| 	void DrawSolidPlane(const b3Vec3& normal, const b3Vec3& center, float32 radius, const b3Color& color); | 	void DrawSolidPlane(const b3Vec3& normal, const b3Vec3& center, scalar radius, const b3Color& color); | ||||||
|  |  | ||||||
| 	void DrawAABB(const b3AABB3& aabb, const b3Color& color); | 	void DrawAABB(const b3AABB& aabb, const b3Color& color); | ||||||
|  |  | ||||||
| 	void DrawTransform(const b3Transform& xf); | 	void DrawTransform(const b3Transform& xf); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -166,7 +166,7 @@ struct DrawPoints | |||||||
| 		glBufferData(GL_ARRAY_BUFFER, e_vertexCapacity * sizeof(b3Color), m_colors, GL_DYNAMIC_DRAW); | 		glBufferData(GL_ARRAY_BUFFER, e_vertexCapacity * sizeof(b3Color), m_colors, GL_DYNAMIC_DRAW); | ||||||
|  |  | ||||||
| 		glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[2]); | 		glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[2]); | ||||||
| 		glBufferData(GL_ARRAY_BUFFER, e_vertexCapacity * sizeof(float32), m_sizes, GL_DYNAMIC_DRAW); | 		glBufferData(GL_ARRAY_BUFFER, e_vertexCapacity * sizeof(scalar), m_sizes, GL_DYNAMIC_DRAW); | ||||||
|  |  | ||||||
| 		AssertGL(); | 		AssertGL(); | ||||||
|  |  | ||||||
| @@ -181,7 +181,7 @@ struct DrawPoints | |||||||
| 		glDeleteBuffers(3, m_vboIds); | 		glDeleteBuffers(3, m_vboIds); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	void Vertex(const b3Vec3& v, float32 size, const b3Color& color) | 	void Vertex(const b3Vec3& v, scalar size, const b3Color& color) | ||||||
| 	{ | 	{ | ||||||
| 		if (m_count == e_vertexCapacity) | 		if (m_count == e_vertexCapacity) | ||||||
| 		{ | 		{ | ||||||
| @@ -226,7 +226,7 @@ struct DrawPoints | |||||||
| 		glVertexAttribPointer(m_colorAttribute, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0)); | 		glVertexAttribPointer(m_colorAttribute, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0)); | ||||||
|  |  | ||||||
| 		glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[2]); | 		glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[2]); | ||||||
| 		glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(float32), m_sizes); | 		glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(scalar), m_sizes); | ||||||
| 		glEnableVertexAttribArray(m_sizeAttribute); | 		glEnableVertexAttribArray(m_sizeAttribute); | ||||||
| 		glVertexAttribPointer(m_sizeAttribute, 1, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0)); | 		glVertexAttribPointer(m_sizeAttribute, 1, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0)); | ||||||
|  |  | ||||||
| @@ -255,7 +255,7 @@ struct DrawPoints | |||||||
|  |  | ||||||
| 	b3Vec3 m_vertices[e_vertexCapacity]; | 	b3Vec3 m_vertices[e_vertexCapacity]; | ||||||
| 	b3Color m_colors[e_vertexCapacity]; | 	b3Color m_colors[e_vertexCapacity]; | ||||||
| 	float32 m_sizes[e_vertexCapacity]; | 	scalar m_sizes[e_vertexCapacity]; | ||||||
| 	u32 m_count; | 	u32 m_count; | ||||||
|  |  | ||||||
| 	GLuint m_programId; | 	GLuint m_programId; | ||||||
| @@ -365,7 +365,7 @@ struct DrawLines | |||||||
|  |  | ||||||
| 		glDisableVertexAttribArray(m_colorAttribute); | 		glDisableVertexAttribArray(m_colorAttribute); | ||||||
| 		 | 		 | ||||||
| 		glEnableVertexAttribArray(m_vertexAttribute); | 		glDisableVertexAttribArray(m_vertexAttribute); | ||||||
|  |  | ||||||
| 		glBindBuffer(GL_ARRAY_BUFFER, 0); | 		glBindBuffer(GL_ARRAY_BUFFER, 0); | ||||||
| 		glUseProgram(0); | 		glUseProgram(0); | ||||||
| @@ -608,7 +608,7 @@ struct DrawWire | |||||||
| 		glDeleteProgram(m_programId); | 		glDeleteProgram(m_programId); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	void DrawSphere(float32 radius, const b3Color& c, const b3Transform& xf) | 	void DrawSphere(scalar radius, const b3Color& c, const b3Transform& xf) | ||||||
| 	{ | 	{ | ||||||
| 		if (!g_glDrawLines) | 		if (!g_glDrawLines) | ||||||
| 		{ | 		{ | ||||||
| @@ -777,7 +777,7 @@ struct DrawSolid | |||||||
| 	{ | 	{ | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	void DrawCylinder(float32 radius, float32 height, const b3Color& c, const b3Transform& xf) | 	void DrawCylinder(scalar radius, scalar height, const b3Color& c, const b3Transform& xf) | ||||||
| 	{ | 	{ | ||||||
| 		if (!g_glDrawTriangles) | 		if (!g_glDrawTriangles) | ||||||
| 		{ | 		{ | ||||||
| @@ -820,7 +820,7 @@ struct DrawSolid | |||||||
| 		glUseProgram(0); | 		glUseProgram(0); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	void DrawSphere(float32 radius, const b3Color& c, const b3Transform& xf) | 	void DrawSphere(scalar radius, const b3Color& c, const b3Transform& xf) | ||||||
| 	{ | 	{ | ||||||
| 		if (!g_glDrawTriangles) | 		if (!g_glDrawTriangles) | ||||||
| 		{ | 		{ | ||||||
|   | |||||||
| @@ -178,7 +178,7 @@ struct DrawPoints | |||||||
|  |  | ||||||
| 		glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[2]); | 		glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[2]); | ||||||
| 		glVertexAttribPointer(m_sizeAttribute, 1, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0)); | 		glVertexAttribPointer(m_sizeAttribute, 1, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0)); | ||||||
| 		glBufferData(GL_ARRAY_BUFFER, e_vertexCapacity * sizeof(float32), m_sizes, GL_DYNAMIC_DRAW); | 		glBufferData(GL_ARRAY_BUFFER, e_vertexCapacity * sizeof(scalar), m_sizes, GL_DYNAMIC_DRAW); | ||||||
|  |  | ||||||
| 		AssertGL(); | 		AssertGL(); | ||||||
|  |  | ||||||
| @@ -195,7 +195,7 @@ struct DrawPoints | |||||||
| 		glDeleteBuffers(3, m_vboIds); | 		glDeleteBuffers(3, m_vboIds); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	void Vertex(const b3Vec3& v, float32 size, const b3Color& color) | 	void Vertex(const b3Vec3& v, scalar size, const b3Color& color) | ||||||
| 	{ | 	{ | ||||||
| 		if (m_count == e_vertexCapacity) | 		if (m_count == e_vertexCapacity) | ||||||
| 		{ | 		{ | ||||||
| @@ -238,7 +238,7 @@ struct DrawPoints | |||||||
| 		glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(b3Color), m_colors); | 		glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(b3Color), m_colors); | ||||||
|  |  | ||||||
| 		glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[2]); | 		glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[2]); | ||||||
| 		glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(float32), m_sizes); | 		glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(scalar), m_sizes); | ||||||
|  |  | ||||||
| 		glEnable(GL_PROGRAM_POINT_SIZE); | 		glEnable(GL_PROGRAM_POINT_SIZE); | ||||||
| 		glDrawArrays(GL_POINTS, 0, m_count); | 		glDrawArrays(GL_POINTS, 0, m_count); | ||||||
| @@ -260,7 +260,7 @@ struct DrawPoints | |||||||
|  |  | ||||||
| 	b3Vec3 m_vertices[e_vertexCapacity]; | 	b3Vec3 m_vertices[e_vertexCapacity]; | ||||||
| 	b3Color m_colors[e_vertexCapacity]; | 	b3Color m_colors[e_vertexCapacity]; | ||||||
| 	float32 m_sizes[e_vertexCapacity]; | 	scalar m_sizes[e_vertexCapacity]; | ||||||
| 	u32 m_count; | 	u32 m_count; | ||||||
|  |  | ||||||
| 	GLuint m_programId; | 	GLuint m_programId; | ||||||
| @@ -625,7 +625,7 @@ struct DrawWire | |||||||
| 		glDeleteProgram(m_programId); | 		glDeleteProgram(m_programId); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	void DrawSphere(float32 radius, const b3Color& c, const b3Transform& xf) | 	void DrawSphere(scalar radius, const b3Color& c, const b3Transform& xf) | ||||||
| 	{ | 	{ | ||||||
| 		if (!g_glDrawLines) | 		if (!g_glDrawLines) | ||||||
| 		{ | 		{ | ||||||
| @@ -792,7 +792,7 @@ struct DrawSolid | |||||||
| 	{ | 	{ | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	void DrawCylinder(float32 radius, float32 height, const b3Color& c, const b3Transform& xf) | 	void DrawCylinder(scalar radius, scalar height, const b3Color& c, const b3Transform& xf) | ||||||
| 	{ | 	{ | ||||||
| 		if (!g_glDrawTriangles) | 		if (!g_glDrawTriangles) | ||||||
| 		{ | 		{ | ||||||
| @@ -831,7 +831,7 @@ struct DrawSolid | |||||||
| 		glUseProgram(0); | 		glUseProgram(0); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	void DrawSphere(float32 radius, const b3Color& c, const b3Transform& xf) | 	void DrawSphere(scalar radius, const b3Color& c, const b3Transform& xf) | ||||||
| 	{ | 	{ | ||||||
| 		if (!g_glDrawTriangles) | 		if (!g_glDrawTriangles) | ||||||
| 		{ | 		{ | ||||||
|   | |||||||
| @@ -77,7 +77,7 @@ void JsonProfiler::EndEvents() | |||||||
| 	m_file = nullptr; | 	m_file = nullptr; | ||||||
| } | } | ||||||
|  |  | ||||||
| void JsonProfiler::BeginEvent(const char* name, float64 t) | void JsonProfiler::BeginEvent(const char* name, scalar64 t) | ||||||
| { | { | ||||||
| 	if (!m_writer) | 	if (!m_writer) | ||||||
| 	{ | 	{ | ||||||
| @@ -86,7 +86,7 @@ void JsonProfiler::BeginEvent(const char* name, float64 t) | |||||||
|  |  | ||||||
| 	const char* phase = "B"; | 	const char* phase = "B"; | ||||||
|  |  | ||||||
| 	float64 scale = 1000.0; | 	scalar64 scale = 1000.0; | ||||||
|  |  | ||||||
| 	m_writer->StartObject(); | 	m_writer->StartObject(); | ||||||
| 	m_writer->STRING("pid");  m_writer->Int(0); | 	m_writer->STRING("pid");  m_writer->Int(0); | ||||||
| @@ -99,7 +99,7 @@ void JsonProfiler::BeginEvent(const char* name, float64 t) | |||||||
| 	m_writer->EndObject(); | 	m_writer->EndObject(); | ||||||
| } | } | ||||||
|  |  | ||||||
| void JsonProfiler::EndEvent(const char* name, float64 t) | void JsonProfiler::EndEvent(const char* name, scalar64 t) | ||||||
| { | { | ||||||
| 	if (!m_writer) | 	if (!m_writer) | ||||||
| 	{ | 	{ | ||||||
| @@ -108,7 +108,7 @@ void JsonProfiler::EndEvent(const char* name, float64 t) | |||||||
|  |  | ||||||
| 	const char* phase = "E"; | 	const char* phase = "E"; | ||||||
|  |  | ||||||
| 	float64 scale = 1000.0; | 	scalar64 scale = 1000.0; | ||||||
|  |  | ||||||
| 	m_writer->StartObject(); | 	m_writer->StartObject(); | ||||||
| 	m_writer->STRING("pid");  m_writer->Int(0); | 	m_writer->STRING("pid");  m_writer->Int(0); | ||||||
|   | |||||||
| @@ -43,9 +43,9 @@ public: | |||||||
|  |  | ||||||
| 	void EndEvents(); | 	void EndEvents(); | ||||||
|  |  | ||||||
| 	void BeginEvent(const char* name, float64 time); | 	void BeginEvent(const char* name, scalar64 time); | ||||||
|  |  | ||||||
| 	void EndEvent(const char* name, float64 time); | 	void EndEvent(const char* name, scalar64 time); | ||||||
| private: | private: | ||||||
| 	FILE* m_file; | 	FILE* m_file; | ||||||
| 	FileWriteStream* m_stream; | 	FileWriteStream* m_stream; | ||||||
|   | |||||||
| @@ -24,6 +24,8 @@ | |||||||
| 	// error | 	// error | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #include <stdio.h> | ||||||
|  |  | ||||||
| #include <glfw/glfw3.h> | #include <glfw/glfw3.h> | ||||||
|  |  | ||||||
| #include <testbed/framework/model.h> | #include <testbed/framework/model.h> | ||||||
| @@ -103,14 +105,12 @@ static void Run() | |||||||
|  |  | ||||||
| 	while (glfwWindowShouldClose(g_window) == 0) | 	while (glfwWindowShouldClose(g_window) == 0) | ||||||
| 	{ | 	{ | ||||||
|  | 		g_frameAllocator->Reset(); | ||||||
|  |  | ||||||
| 		g_profiler->Begin(); | 		g_profiler->Begin(); | ||||||
|  |  | ||||||
| 		g_profilerSt->Begin(); |  | ||||||
|  |  | ||||||
| 		g_profiler->BeginScope("Frame"); | 		g_profiler->BeginScope("Frame"); | ||||||
|  |  | ||||||
| 		g_profilerSt->BeginScope("Frame"); |  | ||||||
|  |  | ||||||
| 		g_view->BeginInterface(); | 		g_view->BeginInterface(); | ||||||
|  |  | ||||||
| 		if (g_model->IsPaused()) | 		if (g_model->IsPaused()) | ||||||
| @@ -126,22 +126,13 @@ static void Run() | |||||||
|  |  | ||||||
| 		g_model->Update(); | 		g_model->Update(); | ||||||
|  |  | ||||||
| 		g_profilerSt->EndScope(); |  | ||||||
| 		 |  | ||||||
| 		g_profiler->EndScope(); | 		g_profiler->EndScope(); | ||||||
| 		 | 		 | ||||||
| 		if (g_settings->drawProfileTree) | 		if (g_settings->drawProfiler) | ||||||
| 		{ | 		{ | ||||||
| 			g_view->InterfaceProfileTree(); | 			g_view->InterfaceProfiler(); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (g_settings->drawProfileTreeStats) |  | ||||||
| 		{ |  | ||||||
| 			g_view->InterfaceProfileTreeStats(); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		g_profilerSt->End(); |  | ||||||
|  |  | ||||||
| #if PROFILE_JSON == 1 | #if PROFILE_JSON == 1 | ||||||
| 		g_model->UpdateJson(); | 		g_model->UpdateJson(); | ||||||
| #endif | #endif | ||||||
| @@ -160,7 +151,7 @@ int main(int argc, char** args) | |||||||
| #if defined(_WIN32) | #if defined(_WIN32) | ||||||
| 	// Report memory leaks | 	// Report memory leaks | ||||||
| 	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)); | 	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)); | ||||||
| 	//_CrtSetBreakAlloc(0); | 	//_CrtSetBreakAlloc(); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| 	if (glfwInit() == 0) | 	if (glfwInit() == 0) | ||||||
|   | |||||||
| @@ -20,13 +20,16 @@ | |||||||
| #include <testbed/framework/view_model.h> | #include <testbed/framework/view_model.h> | ||||||
| #include <testbed/framework/test.h> | #include <testbed/framework/test.h> | ||||||
|  |  | ||||||
|  | b3FrameAllocator* g_frameAllocator = nullptr; | ||||||
|  | b3Profiler* g_profiler = nullptr; | ||||||
|  |  | ||||||
| Model::Model() | Model::Model() | ||||||
| { | { | ||||||
| 	m_viewModel = nullptr; | 	m_viewModel = nullptr; | ||||||
| 	g_draw = &m_draw; | 	g_draw = &m_draw; | ||||||
| 	g_camera = &m_camera; | 	g_camera = &m_camera; | ||||||
| 	g_profiler = &m_profiler; | 	g_profiler = &m_profiler; | ||||||
| 	g_profilerSt = &m_profilerSt; | 	g_frameAllocator = &m_frame; | ||||||
|  |  | ||||||
| #if (PROFILE_JSON == 1) | #if (PROFILE_JSON == 1) | ||||||
| 	g_jsonProfiler = &m_jsonProfiler; | 	g_jsonProfiler = &m_jsonProfiler; | ||||||
| @@ -41,7 +44,7 @@ Model::Model() | |||||||
| 	glEnable(GL_BLEND); | 	glEnable(GL_BLEND); | ||||||
| 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||||||
|  |  | ||||||
| 	glClearColor(0.3f, 0.3f, 0.3f, 1.0f); | 	glClearColor(0.2f, 0.2f, 0.2f, 1.0f); | ||||||
| 	glClearDepth(1.0f); | 	glClearDepth(1.0f); | ||||||
|  |  | ||||||
| 	Action_ResetCamera(); | 	Action_ResetCamera(); | ||||||
| @@ -56,7 +59,7 @@ Model::~Model() | |||||||
| 	g_draw = nullptr; | 	g_draw = nullptr; | ||||||
| 	g_camera = nullptr; | 	g_camera = nullptr; | ||||||
| 	g_profiler = nullptr; | 	g_profiler = nullptr; | ||||||
| 	g_profilerSt = nullptr; | 	g_frameAllocator = nullptr; | ||||||
|  |  | ||||||
| #if (PROFILE_JSON == 1) | #if (PROFILE_JSON == 1) | ||||||
| 	g_jsonProfiler = nullptr; | 	g_jsonProfiler = nullptr; | ||||||
| @@ -114,11 +117,11 @@ void Model::Update() | |||||||
|  |  | ||||||
| 	if (m_setTest) | 	if (m_setTest) | ||||||
| 	{ | 	{ | ||||||
|  | 		Action_ResetCamera(); | ||||||
| 		delete m_test; | 		delete m_test; | ||||||
| 		m_test = g_tests[g_settings->testID].create(); | 		m_test = g_tests[g_settings->testID].create(); | ||||||
| 		m_setTest = false; | 		m_setTest = false; | ||||||
| 		m_pause = true; | 		m_pause = true; | ||||||
| 		Action_ResetCamera(); |  | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	if (g_settings->drawGrid) | 	if (g_settings->drawGrid) | ||||||
| @@ -129,9 +132,9 @@ void Model::Update() | |||||||
| 		b3Vec3 vs[h * w]; | 		b3Vec3 vs[h * w]; | ||||||
|  |  | ||||||
| 		b3Vec3 t; | 		b3Vec3 t; | ||||||
| 		t.x = -0.5f * float32(w) + 0.5f; | 		t.x = -0.5f * scalar(w) + 0.5f; | ||||||
| 		t.y = 0.0f; | 		t.y = 0.0f; | ||||||
| 		t.z = -0.5f * float32(h) + 0.5f; | 		t.z = -0.5f * scalar(h) + 0.5f; | ||||||
|  |  | ||||||
| 		for (u32 i = 0; i < h; ++i) | 		for (u32 i = 0; i < h; ++i) | ||||||
| 		{ | 		{ | ||||||
| @@ -140,9 +143,9 @@ void Model::Update() | |||||||
| 				u32 iv = i * w + j; | 				u32 iv = i * w + j; | ||||||
|  |  | ||||||
| 				b3Vec3 v; | 				b3Vec3 v; | ||||||
| 				v.x = float32(j); | 				v.x = scalar(j); | ||||||
| 				v.y = 0.0f; | 				v.y = 0.0f; | ||||||
| 				v.z = float32(i); | 				v.z = scalar(i); | ||||||
|  |  | ||||||
| 				v += t; | 				v += t; | ||||||
| 				 | 				 | ||||||
| @@ -150,57 +153,55 @@ void Model::Update() | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		b3Color color(0.2f, 0.2f, 0.2f, 1.0f); | 		b3Color borderColor(0.0f, 0.0f, 0.0f, 1.0f); | ||||||
|  | 		b3Color centerColor(0.8f, 0.8f, 0.8f, 1.0f); | ||||||
| 		// Left-Right Lines | 		b3Color color(0.4f, 0.4f, 0.4f, 1.0f); | ||||||
| 		u32 hv1 = (h - 1) / 2 * w + 0; |  | ||||||
| 		u32 hv2 = (h - 1) / 2 * w + (w - 1); |  | ||||||
| 		{ |  | ||||||
| 			b3Vec3 v1 = vs[hv1]; |  | ||||||
| 			b3Vec3 v2 = vs[hv2]; |  | ||||||
|  |  | ||||||
| 			b3Draw_draw->DrawSegment(v1, v2, b3Color_black); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
|  | 		// Left to right lines | ||||||
| 		for (u32 i = 0; i < h; ++i) | 		for (u32 i = 0; i < h; ++i) | ||||||
| 		{ | 		{ | ||||||
| 			if (i == hv1) |  | ||||||
| 			{ |  | ||||||
| 				continue; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			u32 iv1 = i * w + 0; | 			u32 iv1 = i * w + 0; | ||||||
| 			u32 iv2 = i * w + (w - 1); | 			u32 iv2 = i * w + (w - 1); | ||||||
|  |  | ||||||
| 			b3Vec3 v1 = vs[iv1]; | 			b3Vec3 v1 = vs[iv1]; | ||||||
| 			b3Vec3 v2 = vs[iv2]; | 			b3Vec3 v2 = vs[iv2]; | ||||||
|  |  | ||||||
| 			b3Draw_draw->DrawSegment(v1, v2, color); | 			if (i == 0 || i == (h - 1)) | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// Up-Bottom Lines |  | ||||||
| 		u32 wv1 = 0 * w + (w - 1) / 2; |  | ||||||
| 		u32 wv2 = (h - 1) * w + (w - 1) / 2; |  | ||||||
| 		{ |  | ||||||
| 			b3Vec3 v1 = vs[wv1]; |  | ||||||
| 			b3Vec3 v2 = vs[wv2]; |  | ||||||
|  |  | ||||||
| 			b3Draw_draw->DrawSegment(v1, v2, b3Color_black); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		for (u32 j = 0; j < w; ++j) |  | ||||||
| 		{ |  | ||||||
| 			if (j == wv1) |  | ||||||
| 			{ | 			{ | ||||||
|  | 				b3Draw_draw->DrawSegment(v1, v2, borderColor); | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|  | 			if (i == (h - 1) / 2) | ||||||
|  | 			{ | ||||||
|  | 				b3Draw_draw->DrawSegment(v1, v2, centerColor); | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			b3Draw_draw->DrawSegment(v1, v2, color); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Up to bottom lines | ||||||
|  | 		for (u32 j = 0; j < w; ++j) | ||||||
|  | 		{ | ||||||
| 			u32 iv1 = 0 * w + j; | 			u32 iv1 = 0 * w + j; | ||||||
| 			u32 iv2 = (h - 1) * w + j; | 			u32 iv2 = (h - 1) * w + j; | ||||||
|  |  | ||||||
| 			b3Vec3 v1 = vs[iv1]; | 			b3Vec3 v1 = vs[iv1]; | ||||||
| 			b3Vec3 v2 = vs[iv2]; | 			b3Vec3 v2 = vs[iv2]; | ||||||
|  |  | ||||||
|  | 			if (j == 0 || j == (w - 1)) | ||||||
|  | 			{ | ||||||
|  | 				b3Draw_draw->DrawSegment(v1, v2, borderColor); | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (j == (w - 1) / 2) | ||||||
|  | 			{ | ||||||
|  | 				b3Draw_draw->DrawSegment(v1, v2, centerColor); | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  |  | ||||||
| 			b3Draw_draw->DrawSegment(v1, v2, color); | 			b3Draw_draw->DrawSegment(v1, v2, color); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -233,15 +234,17 @@ void Model::Update() | |||||||
|  |  | ||||||
| #if (PROFILE_JSON == 1) | #if (PROFILE_JSON == 1) | ||||||
|  |  | ||||||
| static inline void RecurseEvents(ProfilerNode* node) | static inline void RecurseEvents(b3ProfilerNode* node) | ||||||
| { | { | ||||||
| 	g_jsonProfiler->BeginEvent(node->name, node->t0); | 	g_jsonProfiler->BeginEvent(node->name, node->t0); | ||||||
| 	 | 	 | ||||||
| 	g_jsonProfiler->EndEvent(node->name, node->t1); | 	g_jsonProfiler->EndEvent(node->name, node->t1); | ||||||
|  |  | ||||||
| 	for (u32 i = 0; i < node->children.Count(); ++i) | 	b3ProfilerNode* child = node->head; | ||||||
|  | 	while (child) | ||||||
| 	{ | 	{ | ||||||
| 		RecurseEvents(node->children[i]); | 		RecurseEvents(child); | ||||||
|  | 		child = child->next; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -249,7 +252,7 @@ void Model::UpdateJson() | |||||||
| { | { | ||||||
| 	m_jsonProfiler.BeginEvents(); | 	m_jsonProfiler.BeginEvents(); | ||||||
|  |  | ||||||
| 	ProfilerNode* root = m_profiler.GetRoot(); | 	b3ProfilerNode* root = m_profiler.GetRoot(); | ||||||
|  |  | ||||||
| 	if (root) | 	if (root) | ||||||
| 	{ | 	{ | ||||||
|   | |||||||
| @@ -20,8 +20,11 @@ | |||||||
| #define MODEL_H | #define MODEL_H | ||||||
|  |  | ||||||
| #include <testbed/framework/draw.h> | #include <testbed/framework/draw.h> | ||||||
| #include <testbed/framework/profiler.h> | #include <bounce/common/profiler.h> | ||||||
| #include <testbed/framework/profiler_st.h> |  | ||||||
|  | extern b3FrameAllocator* g_frameAllocator; | ||||||
|  |  | ||||||
|  | extern b3Profiler* g_profiler; | ||||||
|  |  | ||||||
| // Set to 1 to write profile events into a .json file. Set to 0 otherwise. | // Set to 1 to write profile events into a .json file. Set to 0 otherwise. | ||||||
| #define PROFILE_JSON 0 | #define PROFILE_JSON 0 | ||||||
| @@ -53,12 +56,12 @@ public: | |||||||
| 	void Command_Release_Mouse_Left(const b3Vec2& ps); | 	void Command_Release_Mouse_Left(const b3Vec2& ps); | ||||||
| 	void Command_Move_Cursor(const b3Vec2& ps); | 	void Command_Move_Cursor(const b3Vec2& ps); | ||||||
|  |  | ||||||
| 	void Command_ResizeCamera(float32 w, float32 h); | 	void Command_ResizeCamera(scalar w, scalar h); | ||||||
| 	void Command_RotateCameraX(float32 angle); | 	void Command_RotateCameraX(scalar angle); | ||||||
| 	void Command_RotateCameraY(float32 angle); | 	void Command_RotateCameraY(scalar angle); | ||||||
| 	void Command_TranslateCameraX(float32 d); | 	void Command_TranslateCameraX(scalar d); | ||||||
| 	void Command_TranslateCameraY(float32 d); | 	void Command_TranslateCameraY(scalar d); | ||||||
| 	void Command_ZoomCamera(float32 d); | 	void Command_ZoomCamera(scalar d); | ||||||
|  |  | ||||||
| 	void Update(); | 	void Update(); | ||||||
|  |  | ||||||
| @@ -74,8 +77,8 @@ private: | |||||||
|  |  | ||||||
| 	Draw m_draw; | 	Draw m_draw; | ||||||
| 	Camera m_camera; | 	Camera m_camera; | ||||||
| 	Profiler m_profiler; | 	b3FrameAllocator m_frame; | ||||||
| 	ProfilerSt m_profilerSt; | 	b3Profiler m_profiler; | ||||||
|  |  | ||||||
| #if (PROFILE_JSON == 1) | #if (PROFILE_JSON == 1) | ||||||
| 	JsonProfiler m_jsonProfiler; | 	JsonProfiler m_jsonProfiler; | ||||||
| @@ -115,13 +118,13 @@ inline void Model::Action_ResetCamera() | |||||||
| 	m_camera.m_zoom = 50.0f; | 	m_camera.m_zoom = 50.0f; | ||||||
| } | } | ||||||
|  |  | ||||||
| inline void Model::Command_ResizeCamera(float32 w, float32 h) | inline void Model::Command_ResizeCamera(scalar w, scalar h) | ||||||
| { | { | ||||||
| 	m_camera.m_width = w; | 	m_camera.m_width = w; | ||||||
| 	m_camera.m_height = h; | 	m_camera.m_height = h; | ||||||
| } | } | ||||||
|  |  | ||||||
| inline void Model::Command_RotateCameraX(float32 angle) | inline void Model::Command_RotateCameraX(scalar angle) | ||||||
| { | { | ||||||
| 	b3Quat d = b3QuatRotationX(angle); | 	b3Quat d = b3QuatRotationX(angle); | ||||||
|  |  | ||||||
| @@ -129,7 +132,7 @@ inline void Model::Command_RotateCameraX(float32 angle) | |||||||
| 	m_camera.m_q.Normalize(); | 	m_camera.m_q.Normalize(); | ||||||
| } | } | ||||||
|  |  | ||||||
| inline void Model::Command_RotateCameraY(float32 angle) | inline void Model::Command_RotateCameraY(scalar angle) | ||||||
| { | { | ||||||
| 	b3Quat d = b3QuatRotationY(angle); | 	b3Quat d = b3QuatRotationY(angle); | ||||||
|  |  | ||||||
| @@ -137,21 +140,21 @@ inline void Model::Command_RotateCameraY(float32 angle) | |||||||
| 	m_camera.m_q.Normalize(); | 	m_camera.m_q.Normalize(); | ||||||
| } | } | ||||||
|  |  | ||||||
| inline void Model::Command_TranslateCameraX(float32 d) | inline void Model::Command_TranslateCameraX(scalar d) | ||||||
| { | { | ||||||
| 	b3Transform transform = m_camera.BuildWorldTransform(); | 	b3Transform transform = m_camera.BuildWorldTransform(); | ||||||
|  |  | ||||||
| 	m_camera.m_center += d * transform.rotation.x; | 	m_camera.m_center += d * transform.rotation.GetXAxis(); | ||||||
| } | } | ||||||
|  |  | ||||||
| inline void Model::Command_TranslateCameraY(float32 d) | inline void Model::Command_TranslateCameraY(scalar d) | ||||||
| { | { | ||||||
| 	b3Transform transform = m_camera.BuildWorldTransform(); | 	b3Transform transform = m_camera.BuildWorldTransform(); | ||||||
|  |  | ||||||
| 	m_camera.m_center += d * transform.rotation.y; | 	m_camera.m_center += d * transform.rotation.GetYAxis(); | ||||||
| } | } | ||||||
|  |  | ||||||
| inline void Model::Command_ZoomCamera(float32 d) | inline void Model::Command_ZoomCamera(scalar d) | ||||||
| { | { | ||||||
| 	m_camera.m_zoom += d; | 	m_camera.m_zoom += d; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,110 +0,0 @@ | |||||||
| /* |  | ||||||
| * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io |  | ||||||
| * |  | ||||||
| * 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 <testbed/framework/profiler.h> |  | ||||||
|  |  | ||||||
| Profiler* g_profiler = nullptr; |  | ||||||
|  |  | ||||||
| Profiler::Profiler() : m_pool(sizeof(ProfilerNode)) |  | ||||||
| { |  | ||||||
| 	m_root = nullptr; |  | ||||||
| 	m_top = nullptr; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| Profiler::~Profiler() |  | ||||||
| { |  | ||||||
| 	assert(m_root == nullptr); |  | ||||||
| 	assert(m_top == nullptr); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| ProfilerNode* Profiler::CreateNode() |  | ||||||
| { |  | ||||||
| 	void* block = m_pool.Allocate(); |  | ||||||
| 	ProfilerNode* n = new (block) ProfilerNode(); |  | ||||||
| 	return n; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void Profiler::DestroyNode(ProfilerNode* node) |  | ||||||
| { |  | ||||||
| 	node->~ProfilerNode(); |  | ||||||
| 	m_pool.Free(node); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void Profiler::BeginScope(const char* name) |  | ||||||
| { |  | ||||||
| 	m_time.Update(); |  | ||||||
|  |  | ||||||
| 	ProfilerNode* n = CreateNode(); |  | ||||||
| 	n->name = name; |  | ||||||
| 	n->t0 = m_time.GetCurrentMilis(); |  | ||||||
| 	n->t1 = 0.0; |  | ||||||
| 	n->parent = m_top; |  | ||||||
|  |  | ||||||
| 	if (m_root == nullptr) |  | ||||||
| 	{ |  | ||||||
| 		m_root = n; |  | ||||||
| 		m_top = n; |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (m_top) |  | ||||||
| 	{ |  | ||||||
| 		m_top->children.PushBack(n); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	m_top = n; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void Profiler::EndScope() |  | ||||||
| { |  | ||||||
| 	m_time.Update(); |  | ||||||
| 	 |  | ||||||
| 	assert(m_top != nullptr); |  | ||||||
| 	m_top->t1 = m_time.GetCurrentMilis(); |  | ||||||
| 	assert(m_top->t1 > m_top->t0); |  | ||||||
|  |  | ||||||
| 	m_top = m_top->parent; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void Profiler::Begin() |  | ||||||
| { |  | ||||||
| 	// If this assert is hit then it means Profiler::End hasn't been called. |  | ||||||
| 	assert(m_root == nullptr); |  | ||||||
| 	assert(m_top == nullptr); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void Profiler::RecurseDestroyNode(ProfilerNode* node) |  | ||||||
| { |  | ||||||
| 	for (u32 i = 0; i < node->children.Count(); ++i) |  | ||||||
| 	{ |  | ||||||
| 		RecurseDestroyNode(node->children[i]); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	DestroyNode(node); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void Profiler::End() |  | ||||||
| { |  | ||||||
| 	assert(m_top == nullptr); |  | ||||||
|  |  | ||||||
| 	if (m_root) |  | ||||||
| 	{ |  | ||||||
| 		RecurseDestroyNode(m_root); |  | ||||||
| 		m_root = nullptr; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,73 +0,0 @@ | |||||||
| /* |  | ||||||
| * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io |  | ||||||
| * |  | ||||||
| * 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 PROFILER_H |  | ||||||
| #define PROFILER_H |  | ||||||
|  |  | ||||||
| #include <bounce/common/math/math.h> |  | ||||||
| #include <bounce/common/memory/block_pool.h> |  | ||||||
| #include <bounce/common/template/array.h> |  | ||||||
| #include <bounce/common/time.h> |  | ||||||
|  |  | ||||||
| // Profiler node |  | ||||||
| struct ProfilerNode |  | ||||||
| { |  | ||||||
| 	const char* name; |  | ||||||
| 	float64 t0; |  | ||||||
| 	float64 t1; |  | ||||||
| 	ProfilerNode* parent; |  | ||||||
| 	b3StackArray<ProfilerNode*, 32> children; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| // A single-threaded profiler. |  | ||||||
| class Profiler |  | ||||||
| { |  | ||||||
| public: |  | ||||||
| 	Profiler(); |  | ||||||
| 	 |  | ||||||
| 	~Profiler(); |  | ||||||
|  |  | ||||||
| 	// Must be called before profiling.  |  | ||||||
| 	void Begin(); |  | ||||||
|  |  | ||||||
| 	// Must be called after profiling. |  | ||||||
| 	void End(); |  | ||||||
|  |  | ||||||
| 	// Begin a new scope. |  | ||||||
| 	void BeginScope(const char* name); |  | ||||||
| 	 |  | ||||||
| 	// End the top scope. |  | ||||||
| 	void EndScope(); |  | ||||||
|  |  | ||||||
| 	// Get the root profiler node. |  | ||||||
| 	ProfilerNode* GetRoot() { return m_root; } |  | ||||||
| private: |  | ||||||
| 	ProfilerNode* CreateNode(); |  | ||||||
| 	void DestroyNode(ProfilerNode* node); |  | ||||||
| 	 |  | ||||||
| 	void RecurseDestroyNode(ProfilerNode* node); |  | ||||||
|  |  | ||||||
| 	b3BlockPool m_pool; // pool of nodes |  | ||||||
| 	b3Time m_time; // timer |  | ||||||
| 	ProfilerNode* m_root; // tree root node |  | ||||||
| 	ProfilerNode* m_top; // top node |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| extern Profiler* g_profiler; |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
| @@ -1,197 +0,0 @@ | |||||||
| /* |  | ||||||
| * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io |  | ||||||
| * |  | ||||||
| * 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 <testbed/framework/profiler_st.h> |  | ||||||
|  |  | ||||||
| ProfilerSt* g_profilerSt = nullptr; |  | ||||||
|  |  | ||||||
| ProfilerSt::ProfilerSt() : m_pool(sizeof(ProfilerStNode)) |  | ||||||
| { |  | ||||||
| 	m_root = nullptr; |  | ||||||
| 	m_top = nullptr; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| ProfilerSt::~ProfilerSt() |  | ||||||
| { |  | ||||||
| 	assert(m_root == nullptr); |  | ||||||
| 	assert(m_top == nullptr); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| ProfilerStNodeStat* ProfilerSt::FindStat(const char* name) |  | ||||||
| { |  | ||||||
| 	for (u32 i = 0; i < m_stats.Count(); ++i) |  | ||||||
| 	{ |  | ||||||
| 		if (m_stats[i].name == name) |  | ||||||
| 		{ |  | ||||||
| 			return &m_stats[i]; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nullptr; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| ProfilerStNodeStat* ProfilerSt::CreateStat() |  | ||||||
| { |  | ||||||
| 	m_stats.PushBack(ProfilerStNodeStat()); |  | ||||||
| 	return &m_stats.Back(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| ProfilerStNode* ProfilerSt::CreateNode() |  | ||||||
| { |  | ||||||
| 	void* block = m_pool.Allocate(); |  | ||||||
| 	return new (block) ProfilerStNode(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ProfilerSt::DestroyNode(ProfilerStNode* node) |  | ||||||
| { |  | ||||||
| 	node->~ProfilerStNode(); |  | ||||||
| 	m_pool.Free(node); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ProfilerSt::RecurseDestroyNode(ProfilerStNode* node) |  | ||||||
| { |  | ||||||
| 	for (u32 i = 0; i < node->children.Count(); ++i) |  | ||||||
| 	{ |  | ||||||
| 		return RecurseDestroyNode(node->children[i]); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	DestroyNode(node); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static ProfilerStNode* RecurseFindNode(ProfilerStNode* node, const char* name) |  | ||||||
| { |  | ||||||
| 	if (node->name == name) |  | ||||||
| 	{ |  | ||||||
| 		return node; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	ProfilerStNode* result = nullptr; |  | ||||||
| 	for (u32 i = 0; result == nullptr && i < node->children.Count(); ++i) |  | ||||||
| 	{ |  | ||||||
| 		result = RecurseFindNode(node->children[i], name); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return result; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| ProfilerStNode* ProfilerSt::FindNode(const char* name) |  | ||||||
| { |  | ||||||
| 	if (m_top) |  | ||||||
| 	{ |  | ||||||
| 		return RecurseFindNode(m_top, name); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (m_root) |  | ||||||
| 	{ |  | ||||||
| 		return RecurseFindNode(m_root, name); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nullptr; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ProfilerSt::BeginScope(const char* name) |  | ||||||
| { |  | ||||||
| 	ProfilerStNode* fn = FindNode(name); |  | ||||||
|  |  | ||||||
| 	if (fn) |  | ||||||
| 	{ |  | ||||||
| 		m_time.Update(); |  | ||||||
| 		fn->t0 = m_time.GetCurrentMilis(); |  | ||||||
| 		++fn->callCount; |  | ||||||
| 		m_top = fn; |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	m_time.Update(); |  | ||||||
|  |  | ||||||
| 	ProfilerStNode* n = CreateNode(); |  | ||||||
| 	n->name = name; |  | ||||||
| 	n->t0 = m_time.GetCurrentMilis(); |  | ||||||
| 	n->elapsed = 0.0f; |  | ||||||
| 	n->callCount = 1; |  | ||||||
| 	n->parent = m_top; |  | ||||||
| 	n->stat = nullptr; |  | ||||||
|  |  | ||||||
| 	if (m_root == nullptr) |  | ||||||
| 	{ |  | ||||||
| 		m_root = n; |  | ||||||
| 		m_top = n; |  | ||||||
|  |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (m_top) |  | ||||||
| 	{ |  | ||||||
| 		m_top->children.PushBack(n); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	m_top = n; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ProfilerSt::EndScope() |  | ||||||
| { |  | ||||||
| 	assert(m_top != nullptr); |  | ||||||
|  |  | ||||||
| 	m_time.Update(); |  | ||||||
|  |  | ||||||
| 	m_top->t1 = m_time.GetCurrentMilis(); |  | ||||||
| 	 |  | ||||||
| 	float64 elapsedTime = m_top->t1 - m_top->t0; |  | ||||||
|  |  | ||||||
| 	m_top->elapsed += elapsedTime; |  | ||||||
| 	 |  | ||||||
| 	ProfilerStNodeStat* stat = FindStat(m_top->name); |  | ||||||
|  |  | ||||||
| 	if (stat == nullptr) |  | ||||||
| 	{ |  | ||||||
| 		stat = CreateStat(); |  | ||||||
| 		stat->name = m_top->name; |  | ||||||
| 		stat->minElapsed = elapsedTime; |  | ||||||
| 		stat->maxElapsed = elapsedTime;	 |  | ||||||
| 	} |  | ||||||
| 	else |  | ||||||
| 	{ |  | ||||||
| 		stat->minElapsed = b3Min(stat->minElapsed, elapsedTime); |  | ||||||
| 		stat->maxElapsed = b3Max(stat->maxElapsed, elapsedTime); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (m_top->stat == nullptr) |  | ||||||
| 	{ |  | ||||||
| 		m_top->stat = stat; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	assert(m_top->stat == stat); |  | ||||||
|  |  | ||||||
| 	m_top = m_top->parent; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ProfilerSt::Begin() |  | ||||||
| { |  | ||||||
| 	assert(m_top == nullptr); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ProfilerSt::End() |  | ||||||
| { |  | ||||||
| 	assert(m_top == nullptr); |  | ||||||
| 	 |  | ||||||
| 	if (m_root) |  | ||||||
| 	{ |  | ||||||
| 		RecurseDestroyNode(m_root); |  | ||||||
| 		m_root = nullptr; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,94 +0,0 @@ | |||||||
| /* |  | ||||||
| * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io |  | ||||||
| * |  | ||||||
| * 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 PROFILER_ST_H |  | ||||||
| #define PROFILER_ST_H |  | ||||||
|  |  | ||||||
| #include <bounce/common/math/math.h> |  | ||||||
| #include <bounce/common/memory/block_pool.h> |  | ||||||
| #include <bounce/common/template/array.h> |  | ||||||
| #include <bounce/common/time.h> |  | ||||||
|  |  | ||||||
| // Profiler tree node statistics |  | ||||||
| struct ProfilerStNodeStat |  | ||||||
| { |  | ||||||
| 	const char* name; |  | ||||||
| 	float64 minElapsed; |  | ||||||
| 	float64 maxElapsed; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| // A profiler tree node |  | ||||||
| struct ProfilerStNode |  | ||||||
| { |  | ||||||
| 	const char* name;  |  | ||||||
| 	float64 t0; |  | ||||||
| 	float64 t1;  |  | ||||||
| 	 |  | ||||||
| 	float64 elapsed; |  | ||||||
| 	u32 callCount; |  | ||||||
| 	 |  | ||||||
| 	ProfilerStNode* parent; |  | ||||||
| 	b3StackArray<ProfilerStNode*, 32> children; |  | ||||||
|  |  | ||||||
| 	ProfilerStNodeStat* stat; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| // A profiler tree  |  | ||||||
| class ProfilerSt |  | ||||||
| { |  | ||||||
| public: |  | ||||||
| 	ProfilerSt(); |  | ||||||
| 	 |  | ||||||
| 	~ProfilerSt(); |  | ||||||
|  |  | ||||||
| 	// Must be called before profiling.  |  | ||||||
| 	void Begin(); |  | ||||||
|  |  | ||||||
| 	// Must be called after profiling. |  | ||||||
| 	void End(); |  | ||||||
|  |  | ||||||
| 	// Begin a new scope. |  | ||||||
| 	void BeginScope(const char* name); |  | ||||||
|  |  | ||||||
| 	// End the top scope. |  | ||||||
| 	void EndScope(); |  | ||||||
|  |  | ||||||
| 	ProfilerStNode* GetRoot() { return m_root; } |  | ||||||
| private: |  | ||||||
| 	ProfilerStNode* CreateNode(); |  | ||||||
| 	void DestroyNode(ProfilerStNode* node); |  | ||||||
| 	 |  | ||||||
| 	void RecurseDestroyNode(ProfilerStNode* node); |  | ||||||
|  |  | ||||||
| 	ProfilerStNode* FindNode(const char* name); |  | ||||||
|  |  | ||||||
| 	ProfilerStNodeStat* CreateStat(); |  | ||||||
|  |  | ||||||
| 	ProfilerStNodeStat* FindStat(const char* name); |  | ||||||
|  |  | ||||||
| 	b3BlockPool m_pool; // pool of nodes |  | ||||||
| 	b3Time m_time; // timer |  | ||||||
| 	ProfilerStNode* m_root; // tree root node |  | ||||||
| 	ProfilerStNode* m_top; // top node |  | ||||||
|  |  | ||||||
| 	b3StackArray<ProfilerStNodeStat, 256> m_stats; // node statistics |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| extern ProfilerSt* g_profilerSt; |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
| @@ -22,7 +22,7 @@ b3SoftBodyDragger::b3SoftBodyDragger(b3Ray3* ray, b3SoftBody* body) | |||||||
| { | { | ||||||
| 	m_ray = ray; | 	m_ray = ray; | ||||||
| 	m_body = body; | 	m_body = body; | ||||||
| 	m_tetrahedron = nullptr; | 	m_isDragging = false; | ||||||
| } | } | ||||||
|  |  | ||||||
| b3SoftBodyDragger::~b3SoftBodyDragger() | b3SoftBodyDragger::~b3SoftBodyDragger() | ||||||
| @@ -40,41 +40,45 @@ bool b3SoftBodyDragger::StartDragging() | |||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	m_mesh = m_body->GetMesh(); | 	m_isDragging = true; | ||||||
| 	m_tetrahedron = m_mesh->tetrahedrons + rayOut.tetrahedron; |  | ||||||
| 	m_v1 = m_tetrahedron->v1; |  | ||||||
| 	m_v2 = m_tetrahedron->v2; |  | ||||||
| 	m_v3 = m_tetrahedron->v3; |  | ||||||
| 	m_v4 = m_tetrahedron->v4; |  | ||||||
| 	m_x = rayOut.fraction; | 	m_x = rayOut.fraction; | ||||||
|  |  | ||||||
| 	b3SoftBodyNode* n1 = m_body->GetVertexNode(m_v1); | 	const b3SoftBodyMesh* mesh = m_body->GetMesh(); | ||||||
| 	b3SoftBodyNode* n2 = m_body->GetVertexNode(m_v2); | 	const b3SoftBodyMeshTriangle* triangle = mesh->triangles + rayOut.triangle; | ||||||
| 	b3SoftBodyNode* n3 = m_body->GetVertexNode(m_v3); |  | ||||||
| 	b3SoftBodyNode* n4 = m_body->GetVertexNode(m_v4); |  | ||||||
|  |  | ||||||
| 	b3Vec3 v1 = n1->GetPosition(); | 	m_n1 = m_body->GetNode(triangle->v1); | ||||||
| 	b3Vec3 v2 = n2->GetPosition(); | 	m_n2 = m_body->GetNode(triangle->v2); | ||||||
| 	b3Vec3 v3 = n3->GetPosition(); | 	m_n3 = m_body->GetNode(triangle->v3); | ||||||
| 	b3Vec3 v4 = n4->GetPosition(); |  | ||||||
|  | 	b3Vec3 v1 = m_n1->GetPosition(); | ||||||
|  | 	b3Vec3 v2 = m_n2->GetPosition(); | ||||||
|  | 	b3Vec3 v3 = m_n3->GetPosition(); | ||||||
|  |  | ||||||
| 	b3Vec3 B = GetPointB(); | 	b3Vec3 B = GetPointB(); | ||||||
|  |  | ||||||
| 	float32 wABCD[5]; | 	scalar wABC[4]; | ||||||
| 	b3BarycentricCoordinates(wABCD, v1, v2, v3, v4, B); | 	b3BarycentricCoordinates(wABC, v1, v2, v3, B); | ||||||
|  |  | ||||||
| 	if (wABCD[4] > B3_EPSILON) | 	if (wABC[3] > B3_EPSILON) | ||||||
| 	{ | 	{ | ||||||
| 		m_tu = wABCD[0] / wABCD[4]; | 		m_tu = wABC[0] / wABC[3]; | ||||||
| 		m_tv = wABCD[1] / wABCD[4]; | 		m_tv = wABC[1] / wABC[3]; | ||||||
| 		m_tw = wABCD[2] / wABCD[4]; | 		m_tw = wABC[2] / wABC[3]; | ||||||
| 		m_tx = wABCD[3] / wABCD[4]; |  | ||||||
| 	} | 	} | ||||||
| 	else | 	else | ||||||
| 	{ | 	{ | ||||||
| 		m_tu = m_tv = m_tw = m_tx = 0.0f; | 		m_tu = m_tv = m_tw = 0.0f; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	m_t1 = m_n1->GetType(); | ||||||
|  | 	m_n1->SetType(e_staticSoftBodyNode); | ||||||
|  |  | ||||||
|  | 	m_t2 = m_n2->GetType(); | ||||||
|  | 	m_n2->SetType(e_staticSoftBodyNode); | ||||||
|  |  | ||||||
|  | 	m_t3 = m_n3->GetType(); | ||||||
|  | 	m_n3->SetType(e_staticSoftBodyNode); | ||||||
|  |  | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -87,38 +91,31 @@ void b3SoftBodyDragger::Drag() | |||||||
|  |  | ||||||
| 	b3Vec3 dx = B - A; | 	b3Vec3 dx = B - A; | ||||||
|  |  | ||||||
| 	const float32 k = 100.0f; | 	m_n1->ApplyTranslation(dx); | ||||||
|  | 	m_n2->ApplyTranslation(dx); | ||||||
| 	b3Vec3 f = k * dx; | 	m_n3->ApplyTranslation(dx); | ||||||
|  |  | ||||||
| 	b3Vec3 f1 = m_tu * f; |  | ||||||
| 	b3Vec3 f2 = m_tv * f; |  | ||||||
| 	b3Vec3 f3 = m_tw * f; |  | ||||||
| 	b3Vec3 f4 = m_tx * f; |  | ||||||
|  |  | ||||||
| 	m_body->GetVertexNode(m_v1)->ApplyForce(f1); |  | ||||||
| 	m_body->GetVertexNode(m_v2)->ApplyForce(f2); |  | ||||||
| 	m_body->GetVertexNode(m_v3)->ApplyForce(f3); |  | ||||||
| 	m_body->GetVertexNode(m_v4)->ApplyForce(f4); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void b3SoftBodyDragger::StopDragging() | void b3SoftBodyDragger::StopDragging() | ||||||
| { | { | ||||||
| 	B3_ASSERT(IsDragging() == true); | 	B3_ASSERT(IsDragging() == true); | ||||||
| 	 | 	 | ||||||
| 	m_tetrahedron = nullptr; | 	m_n1->SetType(m_t1); | ||||||
|  | 	m_n2->SetType(m_t2); | ||||||
|  | 	m_n3->SetType(m_t3); | ||||||
|  | 	 | ||||||
|  | 	m_isDragging = false; | ||||||
| } | } | ||||||
|  |  | ||||||
| b3Vec3 b3SoftBodyDragger::GetPointA() const | b3Vec3 b3SoftBodyDragger::GetPointA() const | ||||||
| { | { | ||||||
| 	B3_ASSERT(IsDragging() == true); | 	B3_ASSERT(IsDragging() == true); | ||||||
|  |  | ||||||
| 	b3Vec3 A = m_body->GetVertexNode(m_v1)->GetPosition(); | 	b3Vec3 A = m_n1->GetPosition() + m_n1->GetTranslation(); | ||||||
| 	b3Vec3 B = m_body->GetVertexNode(m_v2)->GetPosition(); | 	b3Vec3 B = m_n2->GetPosition() + m_n2->GetTranslation(); | ||||||
| 	b3Vec3 C = m_body->GetVertexNode(m_v3)->GetPosition(); | 	b3Vec3 C = m_n3->GetPosition() + m_n3->GetTranslation(); | ||||||
| 	b3Vec3 D = m_body->GetVertexNode(m_v4)->GetPosition(); |  | ||||||
|  |  | ||||||
| 	return m_tu * A + m_tv * B + m_tw * C + m_tx * D; | 	return m_tu * A + m_tv * B + m_tw * C; | ||||||
| } | } | ||||||
|  |  | ||||||
| b3Vec3 b3SoftBodyDragger::GetPointB() const | b3Vec3 b3SoftBodyDragger::GetPointB() const | ||||||
|   | |||||||
| @@ -44,18 +44,18 @@ public: | |||||||
| 	b3Vec3 GetPointB() const; | 	b3Vec3 GetPointB() const; | ||||||
| private: | private: | ||||||
| 	b3Ray3* m_ray; | 	b3Ray3* m_ray; | ||||||
| 	float32 m_x; |  | ||||||
|  |  | ||||||
| 	b3SoftBody* m_body; | 	b3SoftBody* m_body; | ||||||
| 	const b3SoftBodyMesh* m_mesh; |  | ||||||
| 	const b3SoftBodyMeshTetrahedron* m_tetrahedron; | 	bool m_isDragging; | ||||||
| 	u32 m_v1, m_v2, m_v3, m_v4; | 	scalar m_x; | ||||||
| 	float32 m_tu, m_tv, m_tw, m_tx; | 	scalar m_tu, m_tv, m_tw; | ||||||
|  | 	b3SoftBodyNode * m_n1, * m_n2, * m_n3; | ||||||
|  | 	b3SoftBodyNodeType m_t1, m_t2, m_t3; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| inline bool b3SoftBodyDragger::IsDragging() const | inline bool b3SoftBodyDragger::IsDragging() const | ||||||
| { | { | ||||||
| 	return m_tetrahedron != nullptr; | 	return m_isDragging; | ||||||
| } | } | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
| @@ -17,8 +17,10 @@ | |||||||
| */ | */ | ||||||
|  |  | ||||||
| #include <testbed/framework/test.h> | #include <testbed/framework/test.h> | ||||||
| #include <testbed/framework/profiler.h> | #include <bounce/common/profiler.h> | ||||||
| #include <testbed/framework/profiler_st.h> |  | ||||||
|  | extern b3FrameAllocator* g_frameAllocator; | ||||||
|  | extern b3Profiler* g_profiler; | ||||||
|  |  | ||||||
| extern u32 b3_allocCalls, b3_maxAllocCalls; | extern u32 b3_allocCalls, b3_maxAllocCalls; | ||||||
| extern u32 b3_convexCalls, b3_convexCacheHits; | extern u32 b3_convexCalls, b3_convexCacheHits; | ||||||
| @@ -28,19 +30,18 @@ extern bool b3_convexCache; | |||||||
| void b3BeginProfileScope(const char* name) | void b3BeginProfileScope(const char* name) | ||||||
| { | { | ||||||
| 	g_profiler->BeginScope(name); | 	g_profiler->BeginScope(name); | ||||||
| 	g_profilerSt->BeginScope(name); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void b3EndProfileScope() | void b3EndProfileScope() | ||||||
| { | { | ||||||
| 	g_profiler->EndScope(); | 	g_profiler->EndScope(); | ||||||
| 	g_profilerSt->EndScope(); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| Test::Test() :  | Test::Test() :  | ||||||
| 	m_bodyDragger(&m_ray, &m_world) | 	m_bodyDragger(&m_ray, &m_world) | ||||||
| { | { | ||||||
| 	b3Draw_draw = g_draw; | 	b3Draw_draw = g_draw; | ||||||
|  | 	b3FrameAllocator_sparseAllocator = g_frameAllocator; | ||||||
| 	b3_convexCache = g_testSettings->convexCache; | 	b3_convexCache = g_testSettings->convexCache; | ||||||
|  |  | ||||||
| 	m_world.SetContactListener(this); | 	m_world.SetContactListener(this); | ||||||
| @@ -49,13 +50,16 @@ Test::Test() : | |||||||
| 	m_ray.direction.Set(0.0f, 0.0f, -1.0f); | 	m_ray.direction.Set(0.0f, 0.0f, -1.0f); | ||||||
| 	m_ray.fraction = g_camera->m_zFar; | 	m_ray.fraction = g_camera->m_zFar; | ||||||
|  |  | ||||||
| 	m_groundHull.Set(50.0f, 1.0f, 50.0f); | 	m_groundHull.SetExtents(50.0f, 1.0f, 50.0f); | ||||||
|  | 	 | ||||||
| 	m_groundMesh.BuildTree(); | 	m_groundMesh.BuildTree(); | ||||||
|  | 	m_groundMesh.BuildAdjacency(); | ||||||
| } | } | ||||||
|  |  | ||||||
| Test::~Test() | Test::~Test() | ||||||
| { | { | ||||||
| 	b3Draw_draw = nullptr; | 	b3Draw_draw = nullptr; | ||||||
|  | 	b3FrameAllocator_sparseAllocator = nullptr; | ||||||
| } | } | ||||||
|  |  | ||||||
| void Test::Step() | void Test::Step() | ||||||
| @@ -63,7 +67,7 @@ void Test::Step() | |||||||
| 	b3_convexCache = g_testSettings->convexCache; | 	b3_convexCache = g_testSettings->convexCache; | ||||||
|  |  | ||||||
| 	// Step | 	// Step | ||||||
| 	float32 dt = g_testSettings->inv_hertz; | 	scalar dt = g_testSettings->inv_hertz; | ||||||
|  |  | ||||||
| 	m_world.SetSleeping(g_testSettings->sleep); | 	m_world.SetSleeping(g_testSettings->sleep); | ||||||
| 	m_world.SetWarmStart(g_testSettings->warmStart); | 	m_world.SetWarmStart(g_testSettings->warmStart); | ||||||
| @@ -97,19 +101,19 @@ void Test::Step() | |||||||
| 		g_draw->DrawString(b3Color_white, "Joints %d", m_world.GetJointList().m_count); | 		g_draw->DrawString(b3Color_white, "Joints %d", m_world.GetJointList().m_count); | ||||||
| 		g_draw->DrawString(b3Color_white, "Contacts %d", m_world.GetContactList().m_count); | 		g_draw->DrawString(b3Color_white, "Contacts %d", m_world.GetContactList().m_count); | ||||||
|  |  | ||||||
| 		float32 avgGjkIters = 0.0f; | 		scalar avgGjkIters = 0.0f; | ||||||
| 		if (b3_gjkCalls > 0) | 		if (b3_gjkCalls > 0) | ||||||
| 		{ | 		{ | ||||||
| 			avgGjkIters = float32(b3_gjkIters) / float32(b3_gjkCalls); | 			avgGjkIters = scalar(b3_gjkIters) / scalar(b3_gjkCalls); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		g_draw->DrawString(b3Color_white, "GJK Calls %d", b3_gjkCalls); | 		g_draw->DrawString(b3Color_white, "GJK Calls %d", b3_gjkCalls); | ||||||
| 		g_draw->DrawString(b3Color_white, "GJK Iterations %d (%d) (%f)", b3_gjkIters, b3_gjkMaxIters, avgGjkIters); | 		g_draw->DrawString(b3Color_white, "GJK Iterations %d (%d) (%f)", b3_gjkIters, b3_gjkMaxIters, avgGjkIters); | ||||||
|  |  | ||||||
| 		float32 convexCacheHitRatio = 0.0f; | 		scalar convexCacheHitRatio = 0.0f; | ||||||
| 		if (b3_convexCalls > 0) | 		if (b3_convexCalls > 0) | ||||||
| 		{ | 		{ | ||||||
| 			convexCacheHitRatio = float32(b3_convexCacheHits) / float32(b3_convexCalls); | 			convexCacheHitRatio = scalar(b3_convexCacheHits) / scalar(b3_convexCalls); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		g_draw->DrawString(b3Color_white, "Convex Calls %d", b3_convexCalls); | 		g_draw->DrawString(b3Color_white, "Convex Calls %d", b3_convexCalls); | ||||||
|   | |||||||
| @@ -24,15 +24,16 @@ | |||||||
|  |  | ||||||
| #include <testbed/framework/body_dragger.h> | #include <testbed/framework/body_dragger.h> | ||||||
| #include <testbed/framework/cloth_dragger.h> | #include <testbed/framework/cloth_dragger.h> | ||||||
|  | #include <testbed/framework/softbody_dragger.h> | ||||||
|  |  | ||||||
| #include <testbed/framework/draw.h> | #include <testbed/framework/draw.h> | ||||||
| #include <testbed/framework/view_model.h> | #include <testbed/framework/view_model.h> | ||||||
|  |  | ||||||
| inline float32 RandomFloat(float32 a, float32 b) | inline float RandomFloat(scalar a, scalar b) | ||||||
| { | { | ||||||
| 	float32 x = float32(rand()) / float32(RAND_MAX); | 	float x = float(rand()) / float(RAND_MAX); | ||||||
| 	float32 diff = b - a; | 	float diff = b - a; | ||||||
| 	float32 r = x * diff; | 	float r = x * diff; | ||||||
| 	return a + r; | 	return a + r; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -20,12 +20,13 @@ | |||||||
| #include <testbed/tests/convex_hull.h> | #include <testbed/tests/convex_hull.h> | ||||||
| #include <testbed/tests/cluster.h> | #include <testbed/tests/cluster.h> | ||||||
| #include <testbed/tests/distance_test.h> | #include <testbed/tests/distance_test.h> | ||||||
| #include <testbed/tests/shape_cast.h> | #include <testbed/tests/linear_time_of_impact.h> | ||||||
|  | #include <testbed/tests/time_of_impact.h> | ||||||
|  | #include <testbed/tests/aabb_time_of_impact.h> | ||||||
| #include <testbed/tests/collide_test.h> | #include <testbed/tests/collide_test.h> | ||||||
| #include <testbed/tests/capsule_collision.h> | #include <testbed/tests/capsule_collision.h> | ||||||
| #include <testbed/tests/hull_collision.h> | #include <testbed/tests/hull_collision.h> | ||||||
| #include <testbed/tests/deep_capsule.h> | #include <testbed/tests/deep_capsule.h> | ||||||
| #include <testbed/tests/degenerate_capsule.h> |  | ||||||
| #include <testbed/tests/box_face_contact.h> | #include <testbed/tests/box_face_contact.h> | ||||||
| #include <testbed/tests/box_edge_contact.h> | #include <testbed/tests/box_edge_contact.h> | ||||||
| #include <testbed/tests/linear_motion.h> | #include <testbed/tests/linear_motion.h> | ||||||
| @@ -35,14 +36,18 @@ | |||||||
| #include <testbed/tests/capsule_spin.h> | #include <testbed/tests/capsule_spin.h> | ||||||
| #include <testbed/tests/quadric_shapes.h> | #include <testbed/tests/quadric_shapes.h> | ||||||
| #include <testbed/tests/compound_body.h> | #include <testbed/tests/compound_body.h> | ||||||
| #include <testbed/tests/spring.h> | #include <testbed/tests/spring_test.h> | ||||||
|  | #include <testbed/tests/motor_test.h> | ||||||
| #include <testbed/tests/weld_test.h> | #include <testbed/tests/weld_test.h> | ||||||
| #include <testbed/tests/cone_test.h> | #include <testbed/tests/cone_test.h> | ||||||
| #include <testbed/tests/hinge_motor.h> | #include <testbed/tests/revolute_test.h> | ||||||
|  | #include <testbed/tests/prismatic_test.h> | ||||||
|  | #include <testbed/tests/wheel_test.h> | ||||||
| #include <testbed/tests/hinge_chain.h> | #include <testbed/tests/hinge_chain.h> | ||||||
| #include <testbed/tests/newton_cradle.h> | #include <testbed/tests/newton_cradle.h> | ||||||
| #include <testbed/tests/ragdoll.h> | #include <testbed/tests/ragdoll.h> | ||||||
| #include <testbed/tests/mesh_contact_test.h> | #include <testbed/tests/mesh_contact_test.h> | ||||||
|  | #include <testbed/tests/triangle_contact_test.h> | ||||||
| #include <testbed/tests/hull_contact_test.h> | #include <testbed/tests/hull_contact_test.h> | ||||||
| #include <testbed/tests/sphere_stack.h> | #include <testbed/tests/sphere_stack.h> | ||||||
| #include <testbed/tests/capsule_stack.h> | #include <testbed/tests/capsule_stack.h> | ||||||
| @@ -53,46 +58,61 @@ | |||||||
| #include <testbed/tests/pyramid.h> | #include <testbed/tests/pyramid.h> | ||||||
| #include <testbed/tests/pyramids.h> | #include <testbed/tests/pyramids.h> | ||||||
| #include <testbed/tests/ray_cast.h> | #include <testbed/tests/ray_cast.h> | ||||||
|  | #include <testbed/tests/convex_cast.h> | ||||||
| #include <testbed/tests/sensor_test.h> | #include <testbed/tests/sensor_test.h> | ||||||
| #include <testbed/tests/body_types.h> | #include <testbed/tests/body_types.h> | ||||||
| #include <testbed/tests/varying_friction.h> | #include <testbed/tests/varying_friction.h> | ||||||
| #include <testbed/tests/varying_restitution.h> | #include <testbed/tests/varying_restitution.h> | ||||||
| #include <testbed/tests/tumbler.h> | #include <testbed/tests/tumbler.h> | ||||||
| #include <testbed/tests/multiple_pendulum.h> | #include <testbed/tests/multiple_pendulum.h> | ||||||
|  | #include <testbed/tests/conveyor_belt.h> | ||||||
| #include <testbed/tests/table_cloth.h> | #include <testbed/tests/table_cloth.h> | ||||||
|  | #include <testbed/tests/cloth_sdf.h> | ||||||
| #include <testbed/tests/pinned_cloth.h> | #include <testbed/tests/pinned_cloth.h> | ||||||
| #include <testbed/tests/particle_types.h> | #include <testbed/tests/particle_types.h> | ||||||
| #include <testbed/tests/tension_mapping.h> | #include <testbed/tests/tension_mapping.h> | ||||||
| #include <testbed/tests/cloth_self_collision.h> | #include <testbed/tests/cloth_self_collision.h> | ||||||
|  | #include <testbed/tests/cape.h> | ||||||
|  | #include <testbed/tests/cloth_tearing.h> | ||||||
|  | #include <testbed/tests/cloth_element_test.h> | ||||||
| #include <testbed/tests/rope_test.h> | #include <testbed/tests/rope_test.h> | ||||||
| #include <testbed/tests/beam.h> | #include <testbed/tests/beam.h> | ||||||
|  | #include <testbed/tests/sheet.h> | ||||||
|  | #include <testbed/tests/node_types.h> | ||||||
| #include <testbed/tests/pinned_softbody.h> | #include <testbed/tests/pinned_softbody.h> | ||||||
|  | #include <testbed/tests/softbody_anchor.h> | ||||||
| #include <testbed/tests/smash_softbody.h> | #include <testbed/tests/smash_softbody.h> | ||||||
|  | #include <testbed/tests/tetgen_softbody.h> | ||||||
|  |  | ||||||
| TestEntry g_tests[] = | TestEntry g_tests[] = | ||||||
| { | { | ||||||
| 	{ "Convex Hull", &ConvexHull::Create }, | 	{ "Convex Hull", &ConvexHull::Create }, | ||||||
| 	{ "Cluster", &Cluster::Create }, | 	{ "Cluster", &Cluster::Create }, | ||||||
| 	{ "Distance", &Distance::Create }, | 	{ "Distance", &Distance::Create }, | ||||||
| 	{ "Shape Cast", &ShapeCast::Create }, | 	{ "Linear Time of Impact", &LinearTimeOfImpact::Create }, | ||||||
|  | 	{ "Time of Impact", &TimeOfImpact::Create }, | ||||||
|  | 	{ "AABB Time of Impact", &AABBTimeOfImpact::Create }, | ||||||
| 	{ "Capsule Collision", &CapsuleCollision::Create }, | 	{ "Capsule Collision", &CapsuleCollision::Create }, | ||||||
| 	{ "Hull Collision", &HullCollision::Create }, | 	{ "Hull Collision", &HullCollision::Create }, | ||||||
| 	{ "Deep Capsule", &DeepCapsule::Create }, | 	{ "Deep Capsule", &DeepCapsule::Create }, | ||||||
| 	{ "Degenerate Capsule", &DegenerateCapsule::Create }, |  | ||||||
| 	{ "Box Face Contact", &BoxFaceContact::Create }, | 	{ "Box Face Contact", &BoxFaceContact::Create }, | ||||||
| 	{ "Box Edge Contact", &BoxEdgeContact::Create }, | 	{ "Box Edge Contact", &BoxEdgeContact::Create }, | ||||||
| 	{ "Capsule Spin", &CapsuleSpin::Create }, | 	{ "Capsule Spin", &CapsuleSpin::Create }, | ||||||
| 	{ "Hull Contact Test", &HullContactTest::Create }, | 	{ "Hull Contact Test", &HullContactTest::Create }, | ||||||
|  | 	{ "Triangle Contact Test", &TriangleContactTest::Create }, | ||||||
| 	{ "Mesh Contact Test", &MeshContactTest::Create }, | 	{ "Mesh Contact Test", &MeshContactTest::Create }, | ||||||
| 	{ "Linear Motion", &LinearMotion::Create }, | 	{ "Linear Motion", &LinearMotion::Create }, | ||||||
| 	{ "Angular Motion", &AngularMotion::Create }, | 	{ "Angular Motion", &AngularMotion::Create }, | ||||||
| 	{ "Gyroscopic Motion", &GyroMotion::Create }, | 	{ "Gyroscopic Motion", &GyroMotion::Create }, | ||||||
| 	{ "Compound Body", &CompoundBody::Create }, | 	{ "Compound Body", &CompoundBody::Create }, | ||||||
| 	{ "Quadric Shapes", &QuadricShapes::Create }, | 	{ "Quadric Shapes", &QuadricShapes::Create }, | ||||||
| 	{ "Springs", &Spring::Create }, | 	{ "Spring Test", &SpringTest::Create }, | ||||||
|  | 	{ "Prismatic Test", &PrismaticTest::Create }, | ||||||
|  | 	{ "Wheel Test", &WheelTest::Create }, | ||||||
| 	{ "Weld Test", &WeldTest::Create }, | 	{ "Weld Test", &WeldTest::Create }, | ||||||
| 	{ "Cone Test", &ConeTest::Create }, | 	{ "Cone Test", &ConeTest::Create }, | ||||||
| 	{ "Hinge Motor", &HingeMotor::Create }, | 	{ "Motor Test", &MotorTest::Create }, | ||||||
|  | 	{ "Revolute Test", &RevoluteTest::Create }, | ||||||
| 	{ "Hinge Chain", &HingeChain::Create }, | 	{ "Hinge Chain", &HingeChain::Create }, | ||||||
| 	{ "Ragdoll", &Ragdoll::Create }, | 	{ "Ragdoll", &Ragdoll::Create }, | ||||||
| 	{ "Newton's Cradle", &NewtonCradle::Create }, | 	{ "Newton's Cradle", &NewtonCradle::Create }, | ||||||
| @@ -105,6 +125,7 @@ TestEntry g_tests[] = | |||||||
| 	{ "Box Pyramid", &Pyramid::Create }, | 	{ "Box Pyramid", &Pyramid::Create }, | ||||||
| 	{ "Box Pyramid Rows", &Pyramids::Create }, | 	{ "Box Pyramid Rows", &Pyramids::Create }, | ||||||
| 	{ "Ray Cast", &RayCast::Create }, | 	{ "Ray Cast", &RayCast::Create }, | ||||||
|  | 	{ "Convex Cast", &ConvexCast::Create }, | ||||||
| 	{ "Sensor Test", &SensorTest::Create }, | 	{ "Sensor Test", &SensorTest::Create }, | ||||||
| 	{ "Body Types", &BodyTypes::Create }, | 	{ "Body Types", &BodyTypes::Create }, | ||||||
| 	{ "Varying Friction", &VaryingFriction::Create }, | 	{ "Varying Friction", &VaryingFriction::Create }, | ||||||
| @@ -112,14 +133,23 @@ TestEntry g_tests[] = | |||||||
| 	{ "Tumbler", &Tumbler::Create }, | 	{ "Tumbler", &Tumbler::Create }, | ||||||
| 	{ "Initial Overlap", &InitialOverlap::Create }, | 	{ "Initial Overlap", &InitialOverlap::Create }, | ||||||
| 	{ "Multiple Pendulum", &MultiplePendulum::Create }, | 	{ "Multiple Pendulum", &MultiplePendulum::Create }, | ||||||
|  | 	{ "Conveyor Belt", &ConveyorBelt::Create }, | ||||||
| 	{ "Table Cloth", &TableCloth::Create }, | 	{ "Table Cloth", &TableCloth::Create }, | ||||||
|  | 	{ "Cloth SDF", &ClothSDF::Create }, | ||||||
| 	{ "Pinned Cloth", &PinnedCloth::Create }, | 	{ "Pinned Cloth", &PinnedCloth::Create }, | ||||||
| 	{ "Particle Types", &ParticleTypes::Create }, | 	{ "Particle Types", &ParticleTypes::Create }, | ||||||
| 	{ "Tension Mapping", &TensionMapping::Create }, | 	{ "Tension Mapping", &TensionMapping::Create }, | ||||||
| 	{ "Cloth Self-Collision", &ClothSelfCollision::Create }, | 	{ "Cloth Self-Collision", &ClothSelfCollision::Create }, | ||||||
|  | 	{ "Cloth Tearing", &ClothTearing::Create }, | ||||||
|  | 	{ "Cloth Element Test", &ClothElementTest::Create }, | ||||||
|  | 	{ "Cape", &Cape::Create }, | ||||||
| 	{ "Beam", &Beam::Create }, | 	{ "Beam", &Beam::Create }, | ||||||
|  | 	{ "Sheet", &Sheet::Create }, | ||||||
|  | 	{ "Node Types", &NodeTypes::Create }, | ||||||
| 	{ "Pinned Soft Body", &PinnedSoftBody::Create }, | 	{ "Pinned Soft Body", &PinnedSoftBody::Create }, | ||||||
|  | 	{ "Soft Body Anchor", &SoftBodyAnchor::Create }, | ||||||
| 	{ "Smash Soft Body", &SmashSoftBody::Create }, | 	{ "Smash Soft Body", &SmashSoftBody::Create }, | ||||||
|  | 	{ "TetGen Soft Body", &TetGenSoftBody::Create }, | ||||||
| 	{ "Rope", &Rope::Create }, | 	{ "Rope", &Rope::Create }, | ||||||
| 	{ NULL, NULL } | 	{ NULL, NULL } | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -19,14 +19,18 @@ | |||||||
| #include <testbed/framework/view.h> | #include <testbed/framework/view.h> | ||||||
| #include <testbed/framework/view_model.h> | #include <testbed/framework/view_model.h> | ||||||
| #include <testbed/framework/test.h> | #include <testbed/framework/test.h> | ||||||
| #include <testbed/framework/profiler.h> | #include <bounce/common/profiler.h> | ||||||
| #include <testbed/framework/profiler_st.h> |  | ||||||
|  | extern b3Profiler* g_profiler; | ||||||
|  |  | ||||||
| #include <imgui/imgui.h> | #include <imgui/imgui.h> | ||||||
|  |  | ||||||
|  | #include <imgui/imgui_impl_glfw.h> | ||||||
|  |  | ||||||
| #if defined (U_OPENGL_2) | #if defined (U_OPENGL_2) | ||||||
| #include <imgui/imgui_impl_glfw_gl2.h> | #include <imgui/imgui_impl_opengl2.h> | ||||||
| #elif defined (U_OPENGL_4) | #elif defined (U_OPENGL_4) | ||||||
| #include <imgui/imgui_impl_glfw_gl3.h> | #include <imgui/imgui_impl_opengl3.h> | ||||||
| #else | #else | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| @@ -39,16 +43,15 @@ static inline bool GetTestName(void* userData, int idx, const char** name) | |||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| static inline bool ImGui_GLFW_GL_Init(GLFWwindow* w, bool install_callbacks) | static inline bool ImGui_OpenGL_Init() | ||||||
| { | { | ||||||
|  |  | ||||||
| #if defined(U_OPENGL_2) | #if defined(U_OPENGL_2) | ||||||
|  |  | ||||||
| 	return ImGui_ImplGlfwGL2_Init(w, install_callbacks); | 	return ImGui_ImplOpenGL2_Init(); | ||||||
|  |  | ||||||
| #elif defined(U_OPENGL_4) | #elif defined(U_OPENGL_4) | ||||||
|  |  | ||||||
| 	return ImGui_ImplGlfwGL3_Init(w, install_callbacks); | 	return ImGui_ImplOpenGL3_Init(); | ||||||
|  |  | ||||||
| #else | #else | ||||||
|  |  | ||||||
| @@ -56,16 +59,16 @@ static inline bool ImGui_GLFW_GL_Init(GLFWwindow* w, bool install_callbacks) | |||||||
| 	return false; | 	return false; | ||||||
| } | } | ||||||
|  |  | ||||||
| static inline void ImGui_GLFW_GL_Shutdown() | static inline void ImGui_OpenGL_Shutdown() | ||||||
| { | { | ||||||
|  |  | ||||||
| #if defined(U_OPENGL_2) | #if defined(U_OPENGL_2) | ||||||
|  |  | ||||||
| 	ImGui_ImplGlfwGL2_Shutdown(); | 	ImGui_ImplOpenGL2_Shutdown(); | ||||||
|  |  | ||||||
| #elif defined(U_OPENGL_4) | #elif defined(U_OPENGL_4) | ||||||
|  |  | ||||||
| 	ImGui_ImplGlfwGL3_Shutdown(); | 	ImGui_ImplOpenGL3_Shutdown(); | ||||||
|  |  | ||||||
| #else | #else | ||||||
|  |  | ||||||
| @@ -75,16 +78,16 @@ static inline void ImGui_GLFW_GL_Shutdown() | |||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static inline void ImGui_GLFW_GL_NewFrame() | static inline void ImGui_OpenGL_NewFrame() | ||||||
| { | { | ||||||
|  |  | ||||||
| #if defined(U_OPENGL_2) | #if defined(U_OPENGL_2) | ||||||
|  |  | ||||||
| 	ImGui_ImplGlfwGL2_NewFrame(); | 	ImGui_ImplOpenGL2_NewFrame(); | ||||||
|  |  | ||||||
| #elif defined(U_OPENGL_4) | #elif defined(U_OPENGL_4) | ||||||
|  |  | ||||||
| 	ImGui_ImplGlfwGL3_NewFrame(); | 	ImGui_ImplOpenGL3_NewFrame(); | ||||||
|  |  | ||||||
| #else | #else | ||||||
|  |  | ||||||
| @@ -94,16 +97,16 @@ static inline void ImGui_GLFW_GL_NewFrame() | |||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static inline void ImGui_GLFW_GL_RenderDrawData(ImDrawData* draw_data) | static inline void ImGui_OpenGL_RenderDrawData(ImDrawData* draw_data) | ||||||
| { | { | ||||||
|  |  | ||||||
| #if defined(U_OPENGL_2) | #if defined(U_OPENGL_2) | ||||||
|  |  | ||||||
| 	ImGui_ImplGlfwGL2_RenderDrawData(draw_data); | 	ImGui_ImplOpenGL2_RenderDrawData(draw_data); | ||||||
|  |  | ||||||
| #elif defined(U_OPENGL_4) | #elif defined(U_OPENGL_4) | ||||||
|  |  | ||||||
| 	ImGui_ImplGlfwGL3_RenderDrawData(draw_data); | 	ImGui_ImplOpenGL3_RenderDrawData(draw_data); | ||||||
|  |  | ||||||
| #else | #else | ||||||
|  |  | ||||||
| @@ -124,9 +127,9 @@ View::View(GLFWwindow* window) | |||||||
| 	ImGuiIO& io = ImGui::GetIO(); | 	ImGuiIO& io = ImGui::GetIO(); | ||||||
|  |  | ||||||
| 	io.IniFilename = NULL; | 	io.IniFilename = NULL; | ||||||
| 	io.Fonts[0].AddFontDefault(); |  | ||||||
|  |  | ||||||
| 	ImGui_GLFW_GL_Init(m_window, false); | 	ImGui_ImplGlfw_InitForOpenGL(m_window, false); | ||||||
|  | 	ImGui_OpenGL_Init(); | ||||||
|  |  | ||||||
| 	ImGui::StyleColorsDark(); | 	ImGui::StyleColorsDark(); | ||||||
|  |  | ||||||
| @@ -136,7 +139,8 @@ View::View(GLFWwindow* window) | |||||||
| View::~View() | View::~View() | ||||||
| { | { | ||||||
| 	// Destroy UI | 	// Destroy UI | ||||||
| 	ImGui_GLFW_GL_Shutdown(); | 	ImGui_OpenGL_Shutdown(); | ||||||
|  | 	ImGui_ImplGlfw_Shutdown(); | ||||||
|  |  | ||||||
| 	ImGui::DestroyContext(); | 	ImGui::DestroyContext(); | ||||||
| } | } | ||||||
| @@ -145,7 +149,7 @@ b3Vec2 View::GetCursorPosition() const | |||||||
| { | { | ||||||
| 	double x, y; | 	double x, y; | ||||||
| 	glfwGetCursorPos(m_window, &x, &y); | 	glfwGetCursorPos(m_window, &x, &y); | ||||||
| 	return b3Vec2(float32(x), float32(y)); | 	return b3Vec2(scalar(x), scalar(y)); | ||||||
| } | } | ||||||
|  |  | ||||||
| void View::Event_SetWindowSize(int w, int h) | void View::Event_SetWindowSize(int w, int h) | ||||||
| @@ -186,7 +190,9 @@ void View::Event_Scroll(float dx, float dy) | |||||||
|  |  | ||||||
| void View::BeginInterface() | void View::BeginInterface() | ||||||
| { | { | ||||||
| 	ImGui_GLFW_GL_NewFrame(); | 	ImGui_OpenGL_NewFrame(); | ||||||
|  | 	ImGui_ImplGlfw_NewFrame(); | ||||||
|  | 	ImGui::NewFrame(); | ||||||
|  |  | ||||||
| 	ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); | 	ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); | ||||||
| } | } | ||||||
| @@ -219,9 +225,8 @@ void View::Interface() | |||||||
|  |  | ||||||
| 		if (ImGui::BeginMenu("View")) | 		if (ImGui::BeginMenu("View")) | ||||||
| 		{ | 		{ | ||||||
| 			ImGui::MenuItem("Profile Tree", "", &settings.drawProfileTree); |  | ||||||
| 			ImGui::MenuItem("Profile Tree Statistics", "", &settings.drawProfileTreeStats); |  | ||||||
| 			ImGui::MenuItem("Statistics", "", &settings.drawStats); | 			ImGui::MenuItem("Statistics", "", &settings.drawStats); | ||||||
|  | 			ImGui::MenuItem("Profiler", "", &settings.drawProfiler); | ||||||
|  |  | ||||||
| 			ImGui::Separator(); | 			ImGui::Separator(); | ||||||
|  |  | ||||||
| @@ -403,54 +408,7 @@ void View::Interface() | |||||||
| 	ImGui::End(); | 	ImGui::End(); | ||||||
| } | } | ||||||
|  |  | ||||||
| static void TreeNode(ProfilerNode* node, u32& index) | static void TreeNode(b3ProfilerNode* node, u32& index) | ||||||
| { |  | ||||||
| 	ImGui::PushID(index); |  | ||||||
| 	++index; |  | ||||||
|  |  | ||||||
| 	if (ImGui::TreeNode(node->name)) |  | ||||||
| 	{ |  | ||||||
| 		float64 elapsedTime = node->t1 - node->t0; |  | ||||||
| 		ImGui::Text("%.4f [ms]", elapsedTime); |  | ||||||
|  |  | ||||||
| 		for (u32 i = 0; i < node->children.Count(); ++i) |  | ||||||
| 		{ |  | ||||||
| 			TreeNode(node->children[i], index); |  | ||||||
| 		} |  | ||||||
| 		ImGui::TreePop(); |  | ||||||
| 	}	 |  | ||||||
| 	 |  | ||||||
| 	ImGui::PopID(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void View::InterfaceProfileTree() |  | ||||||
| { |  | ||||||
| 	ImGui::Begin("Overlay", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoScrollbar); |  | ||||||
| 	ImVec2 ws = ImGui::GetWindowSize(); |  | ||||||
| 	ImVec2 wp = ImGui::GetWindowPos(); |  | ||||||
| 	ImGui::End(); |  | ||||||
|  |  | ||||||
| 	ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); |  | ||||||
| 	 |  | ||||||
| 	ImGui::SetNextWindowBgAlpha(0.0f); |  | ||||||
| 	ImGui::SetNextWindowPos(ImVec2(0.0f, wp.y + ws.y)); |  | ||||||
| 	ImGui::SetNextWindowSize(ImVec2(g_camera->m_width - 250.0f, 0.0f)); |  | ||||||
|  |  | ||||||
| 	ImGui::Begin("Profile Tree", NULL, ImGuiWindowFlags_AlwaysAutoResize); |  | ||||||
|  |  | ||||||
| 	ProfilerNode* root = g_profiler->GetRoot(); |  | ||||||
| 	if (root) |  | ||||||
| 	{ |  | ||||||
| 		u32 index = 0; |  | ||||||
| 		TreeNode(root, index); |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	ImGui::End(); |  | ||||||
| 	 |  | ||||||
| 	ImGui::PopStyleVar(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void TreeNode(ProfilerStNode* node, u32& index) |  | ||||||
| { | { | ||||||
| 	ImGui::PushID(index); | 	ImGui::PushID(index); | ||||||
| 	++index; | 	++index; | ||||||
| @@ -459,9 +417,11 @@ static void TreeNode(ProfilerStNode* node, u32& index) | |||||||
| 	{ | 	{ | ||||||
| 		ImGui::Text("%.4f (min = %.4f) (max = %.4f) (calls = %d) [ms]", node->elapsed, node->stat->minElapsed, node->stat->maxElapsed, node->callCount); | 		ImGui::Text("%.4f (min = %.4f) (max = %.4f) (calls = %d) [ms]", node->elapsed, node->stat->minElapsed, node->stat->maxElapsed, node->callCount); | ||||||
|  |  | ||||||
| 		for (u32 i = 0; i < node->children.Count(); ++i) | 		b3ProfilerNode* n = node->head; | ||||||
|  | 		while(n) | ||||||
| 		{ | 		{ | ||||||
| 			TreeNode(node->children[i], index); | 			TreeNode(n, index); | ||||||
|  | 			n = n->next; | ||||||
| 		} | 		} | ||||||
| 		ImGui::TreePop(); | 		ImGui::TreePop(); | ||||||
| 	} | 	} | ||||||
| @@ -469,7 +429,7 @@ static void TreeNode(ProfilerStNode* node, u32& index) | |||||||
| 	ImGui::PopID(); | 	ImGui::PopID(); | ||||||
| } | } | ||||||
|  |  | ||||||
| void View::InterfaceProfileTreeStats() | void View::InterfaceProfiler() | ||||||
| { | { | ||||||
| 	ImGui::Begin("Overlay", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoScrollbar); | 	ImGui::Begin("Overlay", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoScrollbar); | ||||||
| 	ImVec2 wp = ImGui::GetWindowPos(); | 	ImVec2 wp = ImGui::GetWindowPos(); | ||||||
| @@ -478,25 +438,15 @@ void View::InterfaceProfileTreeStats() | |||||||
|  |  | ||||||
| 	wp.y = wp.y + ws.y; | 	wp.y = wp.y + ws.y; | ||||||
|  |  | ||||||
| 	if (g_settings->drawProfileTree) |  | ||||||
| 	{ |  | ||||||
| 		ImGui::Begin("Profile Tree", NULL, ImGuiWindowFlags_AlwaysAutoResize); |  | ||||||
| 		ImVec2 ptwp = ImGui::GetWindowPos(); |  | ||||||
| 		ImVec2 ptws = ImGui::GetWindowSize(); |  | ||||||
| 		ImGui::End(); |  | ||||||
|  |  | ||||||
| 		wp.y = ptwp.y + ptws.y; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); | 	ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); | ||||||
|  |  | ||||||
| 	ImGui::SetNextWindowBgAlpha(0.0f); | 	ImGui::SetNextWindowBgAlpha(0.0f); | ||||||
| 	ImGui::SetNextWindowPos(ImVec2(0.0f, wp.y)); | 	ImGui::SetNextWindowPos(ImVec2(0.0f, wp.y)); | ||||||
| 	ImGui::SetNextWindowSize(ImVec2(g_camera->m_width - 250.0f, 0.0f)); | 	ImGui::SetNextWindowSize(ImVec2(g_camera->m_width - 250.0f, 0.0f)); | ||||||
|  |  | ||||||
| 	ImGui::Begin("Profile Tree Statistics", NULL, ImGuiWindowFlags_AlwaysAutoResize); | 	ImGui::Begin("Profiler", NULL, ImGuiWindowFlags_AlwaysAutoResize); | ||||||
|  |  | ||||||
| 	ProfilerStNode* root = g_profilerSt->GetRoot(); | 	b3ProfilerNode* root = g_profiler->GetRoot(); | ||||||
| 	if (root) | 	if (root) | ||||||
| 	{ | 	{ | ||||||
| 		u32 index = 0; | 		u32 index = 0; | ||||||
| @@ -514,5 +464,5 @@ void View::EndInterface() | |||||||
|  |  | ||||||
| 	ImGui::Render(); | 	ImGui::Render(); | ||||||
|  |  | ||||||
| 	ImGui_GLFW_GL_RenderDrawData(ImGui::GetDrawData()); | 	ImGui_OpenGL_RenderDrawData(ImGui::GetDrawData()); | ||||||
| } | } | ||||||
| @@ -41,8 +41,7 @@ public: | |||||||
|  |  | ||||||
| 	void BeginInterface(); | 	void BeginInterface(); | ||||||
| 	void Interface(); | 	void Interface(); | ||||||
| 	void InterfaceProfileTree(); | 	void InterfaceProfiler(); | ||||||
| 	void InterfaceProfileTreeStats(); |  | ||||||
| 	void EndInterface(); | 	void EndInterface(); | ||||||
| private: | private: | ||||||
| 	friend class ViewModel; | 	friend class ViewModel; | ||||||
|   | |||||||
| @@ -84,7 +84,7 @@ void ViewModel::Action_ResetCamera() | |||||||
|  |  | ||||||
| void ViewModel::Event_SetWindowSize(int w, int h) | void ViewModel::Event_SetWindowSize(int w, int h) | ||||||
| { | { | ||||||
| 	m_model->Command_ResizeCamera(float32(w), float32(h)); | 	m_model->Command_ResizeCamera(scalar(w), scalar(h)); | ||||||
| } | } | ||||||
|  |  | ||||||
| void ViewModel::Event_Press_Key(int button) | void ViewModel::Event_Press_Key(int button) | ||||||
| @@ -148,8 +148,7 @@ void ViewModel::Event_Move_Cursor(float x, float y) | |||||||
|  |  | ||||||
| 	b3Vec2 dp = ps - m_view->m_ps0; | 	b3Vec2 dp = ps - m_view->m_ps0; | ||||||
|  |  | ||||||
| 	float32 ndx = b3Clamp(dp.x, -1.0f, 1.0f); | 	b3Vec2 n = b3Normalize(dp); | ||||||
| 	float32 ndy = b3Clamp(dp.y, -1.0f, 1.0f); |  | ||||||
|  |  | ||||||
| 	bool shiftDown = glfwGetKey(m_view->m_window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS; | 	bool shiftDown = glfwGetKey(m_view->m_window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS; | ||||||
| 	bool leftDown = glfwGetMouseButton(m_view->m_window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS; | 	bool leftDown = glfwGetMouseButton(m_view->m_window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS; | ||||||
| @@ -159,8 +158,8 @@ void ViewModel::Event_Move_Cursor(float x, float y) | |||||||
| 	{ | 	{ | ||||||
| 		if (leftDown) | 		if (leftDown) | ||||||
| 		{ | 		{ | ||||||
| 			float32 ax = -0.005f * B3_PI * ndx; | 			scalar ax = -0.005f * B3_PI * n.x; | ||||||
| 			float32 ay = -0.005f * B3_PI * ndy; | 			scalar ay = -0.005f * B3_PI * n.y; | ||||||
|  |  | ||||||
| 			m_model->Command_RotateCameraY(ax); | 			m_model->Command_RotateCameraY(ax); | ||||||
| 			m_model->Command_RotateCameraX(ay); | 			m_model->Command_RotateCameraX(ay); | ||||||
| @@ -168,8 +167,8 @@ void ViewModel::Event_Move_Cursor(float x, float y) | |||||||
|  |  | ||||||
| 		if (rightDown) | 		if (rightDown) | ||||||
| 		{ | 		{ | ||||||
| 			float32 tx = 0.2f * ndx; | 			scalar tx = 0.2f * n.x; | ||||||
| 			float32 ty = -0.2f * ndy; | 			scalar ty = -0.2f * n.y; | ||||||
|  |  | ||||||
| 			m_model->Command_TranslateCameraX(tx); | 			m_model->Command_TranslateCameraX(tx); | ||||||
| 			m_model->Command_TranslateCameraY(ty); | 			m_model->Command_TranslateCameraY(ty); | ||||||
| @@ -177,16 +176,18 @@ void ViewModel::Event_Move_Cursor(float x, float y) | |||||||
| 	} | 	} | ||||||
| 	else | 	else | ||||||
| 	{ | 	{ | ||||||
| 		m_model->Command_Move_Cursor(m_view->GetCursorPosition()); | 		m_model->Command_Move_Cursor(ps); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| void ViewModel::Event_Scroll(float dx, float dy) | void ViewModel::Event_Scroll(float dx, float dy) | ||||||
| { | { | ||||||
|  | 	b3Vec2 n(dx, dy); | ||||||
|  | 	n.Normalize(); | ||||||
|  |  | ||||||
| 	bool shiftDown = glfwGetKey(m_view->m_window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS; | 	bool shiftDown = glfwGetKey(m_view->m_window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS; | ||||||
| 	if (shiftDown) | 	if (shiftDown) | ||||||
| 	{ | 	{ | ||||||
| 		float32 ny = b3Clamp(dy, -1.0f, 1.0f); | 		m_model->Command_ZoomCamera(1.0f * n.y); | ||||||
| 		m_model->Command_ZoomCamera(1.0f * ny); |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -32,9 +32,8 @@ struct Settings | |||||||
| 		drawLines = true; | 		drawLines = true; | ||||||
| 		drawTriangles = true; | 		drawTriangles = true; | ||||||
| 		drawGrid = true; | 		drawGrid = true; | ||||||
| 		drawProfileTree = false; |  | ||||||
| 		drawProfileTreeStats = false; |  | ||||||
| 		drawStats = false; | 		drawStats = false; | ||||||
|  | 		drawProfiler = false; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	int testID; | 	int testID; | ||||||
| @@ -43,9 +42,8 @@ struct Settings | |||||||
| 	bool drawLines; | 	bool drawLines; | ||||||
| 	bool drawTriangles; | 	bool drawTriangles; | ||||||
| 	bool drawGrid; | 	bool drawGrid; | ||||||
| 	bool drawProfileTree; |  | ||||||
| 	bool drawProfileTreeStats; |  | ||||||
| 	bool drawStats; | 	bool drawStats; | ||||||
|  | 	bool drawProfiler; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| // | // | ||||||
|   | |||||||
							
								
								
									
										178
									
								
								examples/testbed/tests/aabb_time_of_impact.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								examples/testbed/tests/aabb_time_of_impact.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,178 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * 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 AABB_TIME_OF_IMPACT_H | ||||||
|  | #define AABB_TIME_OF_IMPACT_H | ||||||
|  |  | ||||||
|  | class AABBTimeOfImpact : public Test | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	AABBTimeOfImpact() | ||||||
|  | 	{ | ||||||
|  | 		b3Vec3 cA = b3Vec3_zero; | ||||||
|  | 		b3Vec3 eA(1.0f, 1.0f, 1.0f); | ||||||
|  | 		m_aabbA.Set(cA, eA); | ||||||
|  |  | ||||||
|  | 		b3Vec3 cB(-2.0f, -2.0f, 0.0f); | ||||||
|  | 		b3Vec3 eB(1.0f, 1.0f, 1.0f); | ||||||
|  | 		m_aabbB.Set(cB, eB); | ||||||
|  |  | ||||||
|  | 		m_dB.Set(1.0f, 1.0f, 0.0f); | ||||||
|  |  | ||||||
|  | 		m_time = 0.0f; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void Step() | ||||||
|  | 	{ | ||||||
|  | 		g_draw->DrawString(b3Color_white, "Arrows - Translate AABB"); | ||||||
|  |  | ||||||
|  | 		g_draw->DrawAABB(m_aabbA, b3Color_white); | ||||||
|  | 		g_draw->DrawAABB(m_aabbB, b3Color_white); | ||||||
|  |  | ||||||
|  | 		b3Vec3 cA = m_aabbA.GetCenter(); | ||||||
|  | 		b3Vec3 cB = m_aabbB.GetCenter(); | ||||||
|  |  | ||||||
|  | 		b3Vec3 eA = m_aabbA.GetExtents(); | ||||||
|  | 		b3Vec3 eB = m_aabbB.GetExtents(); | ||||||
|  |  | ||||||
|  | 		b3Vec3 dA = b3Vec3_zero; | ||||||
|  | 		b3Vec3 dB = m_dB; | ||||||
|  |  | ||||||
|  | 		g_draw->DrawSegment(cA, cA + dA, b3Color_white); | ||||||
|  | 		g_draw->DrawSegment(cB, cB + dB, b3Color_white); | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3Vec3 cBt = cB + m_time * dB; | ||||||
|  |  | ||||||
|  | 			b3AABB B; | ||||||
|  | 			B.Set(cBt, eB); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawAABB(B, b3Color_red); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		b3TOIOutput out = b3TimeOfImpact(m_aabbA, dA, m_aabbB, dB); | ||||||
|  |  | ||||||
|  | 		b3TOIOutput::State state = out.state; | ||||||
|  | 		scalar t = out.t; | ||||||
|  |  | ||||||
|  | 		if (state == b3TOIOutput::e_touching) | ||||||
|  | 		{ | ||||||
|  | 			b3Vec3 cAt = cA + t * dA; | ||||||
|  | 			b3Vec3 cBt = cB + t * dB; | ||||||
|  |  | ||||||
|  | 			b3AABB A; | ||||||
|  | 			A.Set(cAt, eA); | ||||||
|  |  | ||||||
|  | 			b3AABB B; | ||||||
|  | 			B.Set(cBt, eB); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawAABB(A, b3Color_black); | ||||||
|  | 			g_draw->DrawAABB(B, b3Color_black); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (state == b3TOIOutput::e_failed) | ||||||
|  | 		{ | ||||||
|  | 			g_draw->DrawString(b3Color_white, "State = Failed"); | ||||||
|  | 		} | ||||||
|  | 		else if (state == b3TOIOutput::e_overlapped) | ||||||
|  | 		{ | ||||||
|  | 			g_draw->DrawString(b3Color_white, "State = Overlapped"); | ||||||
|  | 		} | ||||||
|  | 		else if (state == b3TOIOutput::e_separated) | ||||||
|  | 		{ | ||||||
|  | 			g_draw->DrawString(b3Color_white, "State = Separated!"); | ||||||
|  | 		} | ||||||
|  | 		else if (state == b3TOIOutput::e_touching) | ||||||
|  | 		{ | ||||||
|  | 			g_draw->DrawString(b3Color_white, "State = Touching!"); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void KeyDown(int key) | ||||||
|  | 	{ | ||||||
|  | 		const scalar dt = 0.01f; | ||||||
|  | 		const scalar d = 0.1f; | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_F) | ||||||
|  | 		{ | ||||||
|  | 			m_time += dt; | ||||||
|  | 			if (m_time > 1.0f) | ||||||
|  | 			{ | ||||||
|  | 				m_time = 0.0f; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_B) | ||||||
|  | 		{ | ||||||
|  | 			m_time -= dt; | ||||||
|  | 			if (m_time < 0.0f) | ||||||
|  | 			{ | ||||||
|  | 				m_time = 1.0f; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_LEFT) | ||||||
|  | 		{ | ||||||
|  | 			m_aabbB.lowerBound.x -= d; | ||||||
|  | 			m_aabbB.upperBound.x -= d; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_RIGHT) | ||||||
|  | 		{ | ||||||
|  | 			m_aabbB.lowerBound.x += d; | ||||||
|  | 			m_aabbB.upperBound.x += d; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_UP) | ||||||
|  | 		{ | ||||||
|  | 			m_aabbB.lowerBound.y += d; | ||||||
|  | 			m_aabbB.upperBound.y += d; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_DOWN) | ||||||
|  | 		{ | ||||||
|  | 			m_aabbB.lowerBound.y -= d; | ||||||
|  | 			m_aabbB.upperBound.y -= d; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		if (key == GLFW_KEY_W) | ||||||
|  | 		{ | ||||||
|  | 			m_aabbB.lowerBound.z += d; | ||||||
|  | 			m_aabbB.upperBound.z += d; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_S) | ||||||
|  | 		{ | ||||||
|  | 			m_aabbB.lowerBound.z -= d; | ||||||
|  | 			m_aabbB.upperBound.z -= d; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	static Test* Create() | ||||||
|  | 	{ | ||||||
|  | 		return new AABBTimeOfImpact(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	scalar m_time; | ||||||
|  |  | ||||||
|  | 	b3AABB m_aabbA; | ||||||
|  | 	b3AABB m_aabbB; | ||||||
|  | 	b3Vec3 m_dB; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
| @@ -32,8 +32,8 @@ public: | |||||||
| 		b3Body* body = m_world.CreateBody(bd); | 		b3Body* body = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
| 		b3CapsuleShape shape; | 		b3CapsuleShape shape; | ||||||
| 		shape.m_centers[0].Set(0.0f, 0.0f, -1.0f); | 		shape.m_vertex1.Set(0.0f, 0.0f, -1.0f); | ||||||
| 		shape.m_centers[1].Set(0.0f, 0.0f, 1.0f); | 		shape.m_vertex2.Set(0.0f, 0.0f, 1.0f); | ||||||
| 		shape.m_radius = 1.0f; | 		shape.m_radius = 1.0f; | ||||||
|  |  | ||||||
| 		b3ShapeDef sdef; | 		b3ShapeDef sdef; | ||||||
|   | |||||||
| @@ -19,33 +19,34 @@ | |||||||
| #ifndef BEAM_H | #ifndef BEAM_H | ||||||
| #define BEAM_H | #define BEAM_H | ||||||
|  |  | ||||||
| #include <testbed/framework/softbody_dragger.h> |  | ||||||
|  |  | ||||||
| class Beam : public Test | class Beam : public Test | ||||||
| { | { | ||||||
| public: | public: | ||||||
|  | 	enum | ||||||
|  | 	{ | ||||||
|  | 		e_w = 5, | ||||||
|  | 		e_h = 2, | ||||||
|  | 		e_d = 2 | ||||||
|  | 	}; | ||||||
|  |  | ||||||
| 	Beam() | 	Beam() | ||||||
| 	{ | 	{ | ||||||
|  | 		m_E0 = 1000.0f; | ||||||
|  | 		m_E = m_E0; | ||||||
|  |  | ||||||
| 		// Create soft body | 		// Create soft body | ||||||
| 		b3SoftBodyDef def; | 		b3SoftBodyDef def; | ||||||
| 		def.mesh = &m_mesh; | 		def.mesh = &m_mesh; | ||||||
| 		def.density = 0.2f; | 		def.density = 0.2f; | ||||||
| 		def.E = 1000.0f; | 		def.E = m_E0; | ||||||
| 		def.nu = 0.33f; | 		def.nu = 0.33f; | ||||||
|  | 		def.radius = 0.2f; | ||||||
|  | 		def.friction = 0.6f; | ||||||
|  |  | ||||||
| 		m_body = new b3SoftBody(def); | 		m_body = new b3SoftBody(def); | ||||||
|  |  | ||||||
| 		b3Vec3 gravity(0.0f, -9.8f, 0.0f); | 		b3Vec3 gravity(0.0f, -9.8f, 0.0f); | ||||||
| 		m_body->SetGravity(gravity); | 		m_body->SetGravity(gravity); | ||||||
| 		m_body->SetWorld(&m_world); |  | ||||||
|  |  | ||||||
| 		for (u32 i = 0; i < m_mesh.vertexCount; ++i) |  | ||||||
| 		{ |  | ||||||
| 			b3SoftBodyNode* n = m_body->GetVertexNode(i); |  | ||||||
|  |  | ||||||
| 			n->SetRadius(0.05f); |  | ||||||
| 			n->SetFriction(0.2f); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// Create body | 		// Create body | ||||||
| 		{ | 		{ | ||||||
| @@ -55,7 +56,7 @@ public: | |||||||
|  |  | ||||||
| 			b3Body* b = m_world.CreateBody(bd); | 			b3Body* b = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
| 			m_wallHull.Set(1.0f, 5.0f, 5.0f); | 			m_wallHull.SetExtents(1.0f, 5.0f, 5.0f); | ||||||
|  |  | ||||||
| 			b3HullShape wallShape; | 			b3HullShape wallShape; | ||||||
| 			wallShape.m_hull = &m_wallHull; | 			wallShape.m_hull = &m_wallHull; | ||||||
| @@ -64,18 +65,20 @@ public: | |||||||
| 			sd.shape = &wallShape; | 			sd.shape = &wallShape; | ||||||
|  |  | ||||||
| 			b3Shape* wall = b->CreateShape(sd); | 			b3Shape* wall = b->CreateShape(sd); | ||||||
|  |  | ||||||
|  | 			b3SoftBodyWorldShapeDef ssd; | ||||||
|  | 			ssd.shape = wall; | ||||||
|  |  | ||||||
|  | 			m_body->CreateWorldShape(ssd); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		b3AABB3 aabb; | 		for (u32 i = 0; i < e_h + 1; ++i) | ||||||
| 		aabb.m_lower.Set(-3.0f, -5.0f, -5.0f); | 		{ | ||||||
| 		aabb.m_upper.Set(-2.0f, 5.0f, 5.0f); | 			for (u32 k = 0; k < e_d + 1; ++k) | ||||||
|  | 			{ | ||||||
|  | 				u32 v = m_mesh.GetVertex(i, 0, k); | ||||||
|  |  | ||||||
| 		for (u32 i = 0; i < m_mesh.vertexCount; ++i) | 				b3SoftBodyNode* n = m_body->GetNode(v); | ||||||
| 		{ |  | ||||||
| 			b3SoftBodyNode* n = m_body->GetVertexNode(i); |  | ||||||
| 			b3Vec3 p = n->GetPosition(); |  | ||||||
| 			if (aabb.Contains(p)) |  | ||||||
| 			{ |  | ||||||
| 				n->SetType(e_staticSoftBodyNode); | 				n->SetType(e_staticSoftBodyNode); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @@ -107,9 +110,9 @@ public: | |||||||
| 			b3Vec3 pA = m_bodyDragger->GetPointA(); | 			b3Vec3 pA = m_bodyDragger->GetPointA(); | ||||||
| 			b3Vec3 pB = m_bodyDragger->GetPointB(); | 			b3Vec3 pB = m_bodyDragger->GetPointB(); | ||||||
|  |  | ||||||
| 			g_draw->DrawPoint(pA, 2.0f, b3Color_green); | 			g_draw->DrawPoint(pA, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
| 			g_draw->DrawPoint(pB, 2.0f, b3Color_green); | 			g_draw->DrawPoint(pB, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
| 			g_draw->DrawSegment(pA, pB, b3Color_white); | 			g_draw->DrawSegment(pA, pB, b3Color_white); | ||||||
| 		} | 		} | ||||||
| @@ -117,8 +120,10 @@ public: | |||||||
| 		extern u32 b3_softBodySolverIterations; | 		extern u32 b3_softBodySolverIterations; | ||||||
| 		g_draw->DrawString(b3Color_white, "Iterations = %d", b3_softBodySolverIterations); | 		g_draw->DrawString(b3Color_white, "Iterations = %d", b3_softBodySolverIterations); | ||||||
|  |  | ||||||
| 		float32 E = m_body->GetEnergy(); | 		scalar E = m_body->GetEnergy(); | ||||||
| 		g_draw->DrawString(b3Color_white, "E = %f", E); | 		g_draw->DrawString(b3Color_white, "E = %f", E); | ||||||
|  | 		 | ||||||
|  | 		g_draw->DrawString(b3Color_white, "Up/Down - Young Modulus (%f)", m_E); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	void MouseMove(const b3Ray3& pw) | 	void MouseMove(const b3Ray3& pw) | ||||||
| @@ -146,12 +151,36 @@ public: | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	void KeyDown(int button) | ||||||
|  | 	{ | ||||||
|  | 		if (button == GLFW_KEY_UP) | ||||||
|  | 		{ | ||||||
|  | 			m_E = b3Clamp(m_E + scalar(10), scalar(0), m_E0); | ||||||
|  | 			for (u32 i = 0; i < m_mesh.tetrahedronCount; ++i) | ||||||
|  | 			{ | ||||||
|  | 				m_body->GetElement(i)->SetE(m_E); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		if (button == GLFW_KEY_DOWN) | ||||||
|  | 		{ | ||||||
|  | 			m_E = b3Clamp(m_E - scalar(10), scalar(10), m_E0); | ||||||
|  | 			for (u32 i = 0; i < m_mesh.tetrahedronCount; ++i) | ||||||
|  | 			{ | ||||||
|  | 				m_body->GetElement(i)->SetE(m_E); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	static Test* Create() | 	static Test* Create() | ||||||
| 	{ | 	{ | ||||||
| 		return new Beam(); | 		return new Beam(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	b3BlockSoftBodyMesh<5, 2, 2> m_mesh; | 	b3BlockSoftBodyMesh<e_w, e_h, e_d> m_mesh; | ||||||
|  | 	 | ||||||
|  | 	scalar m_E0; | ||||||
|  | 	scalar m_E; | ||||||
|  |  | ||||||
| 	b3SoftBody* m_body; | 	b3SoftBody* m_body; | ||||||
| 	b3SoftBodyDragger* m_bodyDragger; | 	b3SoftBodyDragger* m_bodyDragger; | ||||||
|   | |||||||
| @@ -47,8 +47,8 @@ public: | |||||||
| 			m_body = m_world.CreateBody(bd); | 			m_body = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
| 			b3CapsuleShape cap; | 			b3CapsuleShape cap; | ||||||
| 			cap.m_centers[0].Set(0.0f, 2.0f, 0.0f); | 			cap.m_vertex1.Set(0.0f, 2.0f, 0.0f); | ||||||
| 			cap.m_centers[1].Set(0.0f, -2.0f, 0.0f); | 			cap.m_vertex2.Set(0.0f, -2.0f, 0.0f); | ||||||
| 			cap.m_radius = 0.5f; | 			cap.m_radius = 0.5f; | ||||||
|  |  | ||||||
| 			b3ShapeDef sd; | 			b3ShapeDef sd; | ||||||
| @@ -94,7 +94,7 @@ public: | |||||||
| 			bd.type = b3BodyType::e_dynamicBody; | 			bd.type = b3BodyType::e_dynamicBody; | ||||||
| 			bd.position.Set(RandomFloat(-20.0f, 20.0f), RandomFloat(10.0f, 20.0f), RandomFloat(-20.0f, 20.0f)); | 			bd.position.Set(RandomFloat(-20.0f, 20.0f), RandomFloat(10.0f, 20.0f), RandomFloat(-20.0f, 20.0f)); | ||||||
|  |  | ||||||
| 			b3Vec3 n = m_body->GetTransform().position - bd.position; | 			b3Vec3 n = m_body->GetTransform().translation - bd.position; | ||||||
| 			n.Normalize(); | 			n.Normalize(); | ||||||
|  |  | ||||||
| 			bd.linearVelocity = 100.0f * n; | 			bd.linearVelocity = 100.0f * n; | ||||||
| @@ -122,7 +122,7 @@ public: | |||||||
| 				 | 				 | ||||||
| 				p.x -= 1.0f; | 				p.x -= 1.0f; | ||||||
|  |  | ||||||
| 				m_body->SetTransform(p, b3Vec3(q.x, q.y, q.z), q.w); | 				m_body->SetTransform(p, q); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			if (button == GLFW_KEY_RIGHT) | 			if (button == GLFW_KEY_RIGHT) | ||||||
| @@ -132,7 +132,7 @@ public: | |||||||
|  |  | ||||||
| 				p.x += 1.0f; | 				p.x += 1.0f; | ||||||
|  |  | ||||||
| 				m_body->SetTransform(p, b3Vec3(q.x, q.y, q.z), q.w); | 				m_body->SetTransform(p, q); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			if (button == GLFW_KEY_UP) | 			if (button == GLFW_KEY_UP) | ||||||
| @@ -142,7 +142,7 @@ public: | |||||||
|  |  | ||||||
| 				p.z += 1.0f; | 				p.z += 1.0f; | ||||||
|  |  | ||||||
| 				m_body->SetTransform(p, b3Vec3(q.x, q.y, q.z), q.w); | 				m_body->SetTransform(p, q); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			if (button == GLFW_KEY_DOWN) | 			if (button == GLFW_KEY_DOWN) | ||||||
| @@ -152,7 +152,7 @@ public: | |||||||
|  |  | ||||||
| 				p.z -= 1.0f; | 				p.z -= 1.0f; | ||||||
|  |  | ||||||
| 				m_body->SetTransform(p, b3Vec3(q.x, q.y, q.z), q.w); | 				m_body->SetTransform(p, q); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -24,27 +24,19 @@ class BoxEdgeContact : public Collide | |||||||
| public: | public: | ||||||
| 	BoxEdgeContact() | 	BoxEdgeContact() | ||||||
| 	{ | 	{ | ||||||
| 		b3Transform xf; | 		m_box.SetExtents(1.0f, 2.0f, 1.0f); | ||||||
| 		xf.position.SetZero(); |  | ||||||
| 		xf.rotation = b3Diagonal(1.0f, 2.0f, 1.0f); |  | ||||||
| 		m_box.SetTransform(xf); |  | ||||||
|  |  | ||||||
| 		m_sA.m_hull = &m_box; | 		m_sA.m_hull = &m_box; | ||||||
|  | 		m_xfA.translation.Set(1.500000, 1.000000, 0.000000); | ||||||
|  | 		m_xfA.rotation.SetIdentity(); | ||||||
|  | 		m_shapeA = &m_sA; | ||||||
|  |  | ||||||
| 		m_sB.m_hull = &m_box; | 		m_sB.m_hull = &m_box; | ||||||
| 		 | 		m_xfB.translation.Set(-1.29999995, 1.34999979, 0.000000000); | ||||||
| 		m_xfA.position.Set(1.500000, 1.000000, 0.000000); | 		m_xfB.rotation.Set(0.810514629, 0.342624813, 0.334119707, 0.337692767); | ||||||
| 		m_xfA.rotation.x.Set(0.707107, 0.000000, -0.707107); | 		m_shapeB = &m_sB; | ||||||
| 		m_xfA.rotation.y.Set(0.000000, 1.000000, 0.000000); |  | ||||||
| 		m_xfA.rotation.z.Set(0.707107, 0.000000, 0.707107); |  | ||||||
|  |  | ||||||
| 		m_xfB.position.Set(-1.300000, 0.000000, 0.000000); |  | ||||||
| 		m_xfB.rotation.x.Set(0.809017, 0.266849, -0.523721); |  | ||||||
| 		m_xfB.rotation.y.Set(0.000000, 0.891007, 0.453991); |  | ||||||
| 		m_xfB.rotation.z.Set(0.587785, -0.367286, 0.720840); |  | ||||||
|  |  | ||||||
| 		m_cache.count = 0; | 		m_cache.count = 0; | ||||||
| 		m_shapeA = &m_sA; |  | ||||||
| 		m_shapeB = &m_sB; |  | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	static Test* Create() | 	static Test* Create() | ||||||
|   | |||||||
| @@ -24,28 +24,24 @@ class BoxFaceContact : public Collide | |||||||
| public: | public: | ||||||
| 	BoxFaceContact() | 	BoxFaceContact() | ||||||
| 	{ | 	{ | ||||||
| 		b3Transform m; | 		m_boxA.SetExtents(1.0f, 2.0f, 1.0f); | ||||||
| 		m.rotation = b3Diagonal(1.0f, 2.0f, 1.0f); | 		b3Vec3 translation(0.0f, 2.0f, 0.0f); | ||||||
| 		m.position.Set(0.0f, 2.0f, 0.0f); | 		m_boxA.Translate(translation); | ||||||
| 		m_box1.SetTransform(m); |  | ||||||
|  |  | ||||||
| 		m.rotation = b3Diagonal(1.0f, 1.0f, 1.0f); | 		m_sA.m_hull = &m_boxA; | ||||||
| 		m.position.Set(0.0f, 0.0f, 0.0f); |  | ||||||
| 		m_box2.SetTransform(m); |  | ||||||
| 		 | 		 | ||||||
| 		m_xfA.SetIdentity(); | 		m_xfA.SetIdentity(); | ||||||
| 		m_xfA.position.SetZero(); |  | ||||||
| 		m_xfA.rotation.SetIdentity(); | 		m_shapeA = &m_sA; | ||||||
| 		m_sA.m_hull = &m_box1; | 		 | ||||||
|  | 		m_boxB.SetExtents(1.0f, 1.0f, 1.0f); | ||||||
|  |  | ||||||
| 		m_xfB.SetIdentity(); | 		m_xfB.SetIdentity(); | ||||||
| 		m_xfB.position.Set(0.0f, 0.0f, 0.0f); | 		m_sB.m_hull = &m_boxB; | ||||||
| 		m_xfB.rotation.SetIdentity(); |  | ||||||
| 		m_sB.m_hull = &m_box2; | 		m_shapeB = &m_sB; | ||||||
| 		 | 		 | ||||||
| 		m_cache.count = 0; | 		m_cache.count = 0; | ||||||
| 		m_shapeA = &m_sA; |  | ||||||
| 		m_shapeB = &m_sB; |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	static Test* Create() | 	static Test* Create() | ||||||
| @@ -53,8 +49,8 @@ public: | |||||||
| 		return new BoxFaceContact(); | 		return new BoxFaceContact(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	b3BoxHull m_box1; | 	b3BoxHull m_boxA; | ||||||
| 	b3BoxHull m_box2; | 	b3BoxHull m_boxB; | ||||||
| 	b3HullShape m_sA; | 	b3HullShape m_sA; | ||||||
| 	b3HullShape m_sB; | 	b3HullShape m_sB; | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -24,17 +24,15 @@ class BoxStack : public Test | |||||||
| public: | public: | ||||||
| 	enum | 	enum | ||||||
| 	{ | 	{ | ||||||
| 		e_rowCount = 1, | 		e_h = 5, | ||||||
| 		e_columnCount = 5, | 		e_w = 1, | ||||||
| 		e_depthCount = 1 | 		e_d = 1 | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	BoxStack() | 	BoxStack() | ||||||
| 	{ | 	{ | ||||||
| 		{ | 		{ | ||||||
| 			b3BodyDef bdef; | 			b3BodyDef bdef; | ||||||
| 			bdef.type = b3BodyType::e_staticBody; |  | ||||||
|  |  | ||||||
| 			b3Body* body = m_world.CreateBody(bdef); | 			b3Body* body = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
| 			b3HullShape hs; | 			b3HullShape hs; | ||||||
| @@ -47,30 +45,53 @@ public: | |||||||
| 			body->CreateShape(sdef); | 			body->CreateShape(sdef); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		b3Vec3 boxScale(1.0f, 1.0f, 1.0f); | 		b3Vec3 e(1.0f, 1.0f, 1.0f); | ||||||
|  |  | ||||||
| 		b3Vec3 stackOrigin(0.0f, 4.05f, 0.0f); | 		m_boxHull.SetExtents(e.x, e.y, e.z); | ||||||
|  |  | ||||||
| 		for (u32 i = 0; i < e_rowCount; ++i) | 		b3Vec3 separation; | ||||||
|  | 		separation.x = 1.0f; | ||||||
|  | 		separation.y = 1.0f; | ||||||
|  | 		separation.z = 1.0f; | ||||||
|  |  | ||||||
|  | 		b3Vec3 scale; | ||||||
|  | 		scale.x = 2.0f * e.x + separation.x; | ||||||
|  | 		scale.y = 2.0f * e.y + separation.y; | ||||||
|  | 		scale.z = 2.0f * e.z + separation.z; | ||||||
|  |  | ||||||
|  | 		b3Vec3 size; | ||||||
|  | 		size.x = 2.0f * e.x + scale.x * scalar(e_w - 1); | ||||||
|  | 		size.y = 2.0f * e.y + scale.y * scalar(e_h - 1); | ||||||
|  | 		size.z = 2.0f * e.z + scale.z * scalar(e_d - 1); | ||||||
|  |  | ||||||
|  | 		b3Vec3 translation; | ||||||
|  | 		translation.x = e.x - 0.5f * size.x; | ||||||
|  | 		translation.y = e.y - 0.5f * size.y; | ||||||
|  | 		translation.z = e.z - 0.5f * size.z; | ||||||
|  |  | ||||||
|  | 		translation.y += 9.0f; | ||||||
|  |  | ||||||
|  | 		for (u32 i = 0; i < e_h; ++i) | ||||||
| 		{ | 		{ | ||||||
| 			for (u32 j = 0; j < e_columnCount; ++j) | 			for (u32 j = 0; j < e_w; ++j) | ||||||
| 			{ | 			{ | ||||||
| 				for (u32 k = 0; k < e_depthCount; ++k) | 				for (u32 k = 0; k < e_d; ++k) | ||||||
| 				{ | 				{ | ||||||
| 					b3BodyDef bdef; | 					b3BodyDef bdef; | ||||||
| 					bdef.type = b3BodyType::e_dynamicBody; | 					bdef.type = e_dynamicBody; | ||||||
| 					bdef.orientation.Set(b3Vec3(0.0f, 1.0f, 0.0f), 0.5f * B3_PI); |  | ||||||
|  |  | ||||||
| 					bdef.position.x = float32(i) * boxScale.x; | 					bdef.position.Set(scalar(j), scalar(i), scalar(k)); | ||||||
| 					bdef.position.y = 2.5f * float32(j) * boxScale.y; |  | ||||||
| 					bdef.position.z = float32(k) * boxScale.z; |  | ||||||
|  |  | ||||||
| 					bdef.position += stackOrigin; | 					bdef.position.x *= scale.x; | ||||||
|  | 					bdef.position.y *= scale.y; | ||||||
|  | 					bdef.position.z *= scale.z; | ||||||
|  |  | ||||||
|  | 					bdef.position += translation; | ||||||
|  |  | ||||||
| 					b3Body* body = m_world.CreateBody(bdef); | 					b3Body* body = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
| 					b3HullShape hs; | 					b3HullShape hs; | ||||||
| 					hs.m_hull = &b3BoxHull_identity; | 					hs.m_hull = &m_boxHull; | ||||||
|  |  | ||||||
| 					b3ShapeDef sdef; | 					b3ShapeDef sdef; | ||||||
| 					sdef.density = 0.1f; | 					sdef.density = 0.1f; | ||||||
| @@ -78,15 +99,30 @@ public: | |||||||
| 					sdef.shape = &hs; | 					sdef.shape = &hs; | ||||||
|  |  | ||||||
| 					body->CreateShape(sdef); | 					body->CreateShape(sdef); | ||||||
|  |  | ||||||
|  | 					u32 bodyIndex = GetBodyIndex(i, j, k); | ||||||
|  |  | ||||||
|  | 					m_bodies[bodyIndex] = body; | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	u32 GetBodyIndex(u32 i, u32 j, u32 k) | ||||||
|  | 	{ | ||||||
|  | 		B3_ASSERT(i < e_h); | ||||||
|  | 		B3_ASSERT(j < e_w); | ||||||
|  | 		B3_ASSERT(k < e_d); | ||||||
|  | 		return k + e_d * (j + e_w * i); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	static Test* Create() | 	static Test* Create() | ||||||
| 	{ | 	{ | ||||||
| 		return new BoxStack(); | 		return new BoxStack(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	b3BoxHull m_boxHull; | ||||||
|  | 	b3Body* m_bodies[e_h * e_w * e_d]; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
							
								
								
									
										215
									
								
								examples/testbed/tests/cape.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										215
									
								
								examples/testbed/tests/cape.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,215 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * 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 CAPE_H | ||||||
|  | #define CAPE_H | ||||||
|  |  | ||||||
|  | class Cape : public Test | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	enum | ||||||
|  | 	{ | ||||||
|  | 		e_w = 5, | ||||||
|  | 		e_h = 10 | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	Cape() | ||||||
|  | 	{ | ||||||
|  | 		// Translate the cloth mesh | ||||||
|  | 		for (u32 i = 0; i < m_clothMesh.vertexCount; ++i) | ||||||
|  | 		{ | ||||||
|  | 			m_clothMesh.vertices[i].y += 5.0f; | ||||||
|  | 			m_clothMesh.vertices[i].z -= 6.0f; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Create cloth | ||||||
|  | 		b3ClothDef def; | ||||||
|  | 		def.mesh = &m_clothMesh; | ||||||
|  | 		def.density = 0.2f; | ||||||
|  | 		def.streching = 100000.0f; | ||||||
|  |  | ||||||
|  | 		m_cloth = new b3Cloth(def); | ||||||
|  |  | ||||||
|  | 		m_cloth->SetGravity(b3Vec3(0.0f, -9.8f, 0.0f)); | ||||||
|  |  | ||||||
|  | 		// Freeze some particles | ||||||
|  | 		for (u32 j = 0; j < e_w + 1; ++j) | ||||||
|  | 		{ | ||||||
|  | 			u32 vj = m_clothMesh.GetVertex(e_h, j); | ||||||
|  |  | ||||||
|  | 			b3ClothParticle* p = m_cloth->GetParticle(vj); | ||||||
|  | 			p->SetType(e_kinematicClothParticle); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		m_clothDragger = new b3ClothDragger(&m_ray, m_cloth); | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			// Create body | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.type = b3BodyType::e_kinematicBody; | ||||||
|  |  | ||||||
|  | 			m_body = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			static b3BoxHull box(1.0f, 5.0f, 1.0f); | ||||||
|  | 			 | ||||||
|  | 			b3HullShape hs; | ||||||
|  | 			hs.m_hull = &box; | ||||||
|  | 			hs.m_radius = 0.25f; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.density = 0.1f; | ||||||
|  | 			sdef.friction = 0.3f; | ||||||
|  | 			sdef.shape = &hs; | ||||||
|  |  | ||||||
|  | 			m_body->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Store cloth vertices in body space | ||||||
|  | 		for (u32 j = 0; j < e_w + 1; ++j) | ||||||
|  | 		{ | ||||||
|  | 			u32 vj = m_clothMesh.GetVertex(e_h, j); | ||||||
|  |  | ||||||
|  | 			b3ClothParticle* p = m_cloth->GetParticle(vj); | ||||||
|  | 			b3Vec3 position = p->GetPosition(); | ||||||
|  | 			 | ||||||
|  | 			m_localPoints[j] = m_body->GetLocalPoint(position); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	~Cape() | ||||||
|  | 	{ | ||||||
|  | 		delete m_clothDragger; | ||||||
|  | 		delete m_cloth; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	void KeyDown(int button) | ||||||
|  | 	{ | ||||||
|  | 		b3Vec3 v = m_body->GetLinearVelocity(); | ||||||
|  | 		 | ||||||
|  | 		if (button == GLFW_KEY_LEFT) | ||||||
|  | 		{ | ||||||
|  | 			v.x -= 5.0f; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (button == GLFW_KEY_RIGHT) | ||||||
|  | 		{ | ||||||
|  | 			v.x += 5.0f; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (button == GLFW_KEY_UP) | ||||||
|  | 		{ | ||||||
|  | 			v.z -= 5.0f; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (button == GLFW_KEY_DOWN) | ||||||
|  | 		{ | ||||||
|  | 			v.z += 5.0f; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		m_body->SetLinearVelocity(v); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void Step() | ||||||
|  | 	{ | ||||||
|  | 		Test::Step(); | ||||||
|  |  | ||||||
|  | 		scalar inv_h = g_testSettings->hertz; | ||||||
|  |  | ||||||
|  | 		for (u32 j = 0; j < e_w + 1; ++j) | ||||||
|  | 		{ | ||||||
|  | 			u32 vj = m_clothMesh.GetVertex(e_h, j); | ||||||
|  |  | ||||||
|  | 			b3ClothParticle* p = m_cloth->GetParticle(vj); | ||||||
|  | 			b3Vec3 x0 = p->GetPosition(); | ||||||
|  |  | ||||||
|  | 			b3Vec3 x = m_body->GetWorldPoint(m_localPoints[j]); | ||||||
|  |  | ||||||
|  | 			// Apply finite difference method | ||||||
|  | 			b3Vec3 v = inv_h * (x - x0); | ||||||
|  |  | ||||||
|  | 			p->SetVelocity(v); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		m_cloth->Step(g_testSettings->inv_hertz, g_testSettings->velocityIterations, g_testSettings->positionIterations); | ||||||
|  |  | ||||||
|  | 		m_cloth->Draw(); | ||||||
|  |  | ||||||
|  | 		if (m_clothDragger->IsDragging()) | ||||||
|  | 		{ | ||||||
|  | 			b3Vec3 pA = m_clothDragger->GetPointA(); | ||||||
|  | 			b3Vec3 pB = m_clothDragger->GetPointB(); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawPoint(pA, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawPoint(pB, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawSegment(pA, pB, b3Color_white); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		extern u32 b3_clothSolverIterations; | ||||||
|  | 		g_draw->DrawString(b3Color_white, "Iterations = %d", b3_clothSolverIterations); | ||||||
|  |  | ||||||
|  | 		scalar E = m_cloth->GetEnergy(); | ||||||
|  | 		g_draw->DrawString(b3Color_white, "E = %f", E); | ||||||
|  | 		 | ||||||
|  | 		g_draw->DrawString(b3Color_white, "Arrows - Apply Velocity"); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void MouseMove(const b3Ray3& pw) | ||||||
|  | 	{ | ||||||
|  | 		Test::MouseMove(pw); | ||||||
|  |  | ||||||
|  | 		if (m_clothDragger->IsDragging() == true) | ||||||
|  | 		{ | ||||||
|  | 			m_clothDragger->Drag(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void MouseLeftDown(const b3Ray3& pw) | ||||||
|  | 	{ | ||||||
|  | 		Test::MouseLeftDown(pw); | ||||||
|  |  | ||||||
|  | 		if (m_clothDragger->IsDragging() == false) | ||||||
|  | 		{ | ||||||
|  | 			m_clothDragger->StartDragging(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void MouseLeftUp(const b3Ray3& pw) | ||||||
|  | 	{ | ||||||
|  | 		Test::MouseLeftUp(pw); | ||||||
|  |  | ||||||
|  | 		if (m_clothDragger->IsDragging() == true) | ||||||
|  | 		{ | ||||||
|  | 			m_clothDragger->StopDragging(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	static Test* Create() | ||||||
|  | 	{ | ||||||
|  | 		return new Cape(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b3GridClothMesh<e_w, e_h> m_clothMesh; | ||||||
|  | 	b3Cloth* m_cloth; | ||||||
|  | 	b3ClothDragger* m_clothDragger; | ||||||
|  | 	b3Body* m_body; | ||||||
|  | 	b3Vec3 m_localPoints[e_w + 1]; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
| @@ -24,25 +24,21 @@ class CapsuleCollision : public Collide | |||||||
| public: | public: | ||||||
| 	CapsuleCollision() | 	CapsuleCollision() | ||||||
| 	{ | 	{ | ||||||
| 		m_xfA.SetIdentity(); | 		m_sA.m_vertex1.Set(0.0f, -5.0f, 0.0f); | ||||||
| 		m_xfA.position.Set(0.0f, 0.0f, 0.0f); | 		m_sA.m_vertex2.Set(0.0f, 5.0f, 0.0f); | ||||||
| 		//m_xfA.rotation = b3ConvertQuatToRot(b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), 0.25f * B3_PI)); |  | ||||||
| 		m_xfA.rotation.SetIdentity(); |  | ||||||
| 		m_sA.m_centers[0].Set(0.0f, -5.0f, 0.0f); |  | ||||||
| 		m_sA.m_centers[1].Set(0.0f, 5.0f, 0.0f); |  | ||||||
| 		m_sA.m_radius = 1.0f; | 		m_sA.m_radius = 1.0f; | ||||||
|  |  | ||||||
| 		m_xfB.SetIdentity(); | 		m_xfA.SetIdentity(); | ||||||
| 		m_xfB.position.Set(0.f, 0.0f, 0.0f); | 		 | ||||||
| 		//m_xfB.rotation = b3ConvertQuatToRot(b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), 0.251f * B3_PI)); | 		m_sB.m_vertex1.Set(0.0f, -1.0f, 0.0f); | ||||||
| 		m_xfB.rotation.SetIdentity(); | 		m_sB.m_vertex2.Set(0.0f, 1.0f, 0.0f); | ||||||
| 		m_sB.m_centers[0].Set(0.0f, -1.0f, 0.0f); |  | ||||||
| 		m_sB.m_centers[1].Set(0.0f, 1.0f, 0.0f); |  | ||||||
| 		m_sB.m_radius = 1.0f; | 		m_sB.m_radius = 1.0f; | ||||||
|  |  | ||||||
| 		m_cache.count = 0; | 		m_xfB.SetIdentity(); | ||||||
|  |  | ||||||
| 		m_shapeA = &m_sA; | 		m_shapeA = &m_sA; | ||||||
| 		m_shapeB = &m_sB; | 		m_shapeB = &m_sB; | ||||||
|  | 		m_cache.count = 0; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	static Test* Create() | 	static Test* Create() | ||||||
|   | |||||||
| @@ -40,16 +40,15 @@ public: | |||||||
| 		{ | 		{ | ||||||
| 			b3BodyDef bdef; | 			b3BodyDef bdef; | ||||||
| 			bdef.type = e_dynamicBody; | 			bdef.type = e_dynamicBody; | ||||||
|  | 			 | ||||||
| 			bdef.position.Set(0.0f, 10.0f, 0.0f); | 			bdef.position.Set(0.0f, 10.0f, 0.0f); | ||||||
| 			bdef.orientation.Set(b3Vec3(0.0f, 0.0f, -1.0f), 1.5f * B3_PI); | 			bdef.angularVelocity.Set(0.5f * B3_PI, 10.0f * B3_PI, 0.0f); | ||||||
| 			bdef.linearVelocity.Set(0.005f, -10.0f, 0.005f); |  | ||||||
| 			bdef.angularVelocity.Set(2000.0f * B3_PI, 2000.0f * B3_PI, 10000.0f * B3_PI); |  | ||||||
| 			 | 			 | ||||||
| 			b3Body* body = m_world.CreateBody(bdef); | 			b3Body* body = m_world.CreateBody(bdef); | ||||||
| 	 | 	 | ||||||
| 			b3CapsuleShape capsule; | 			b3CapsuleShape capsule; | ||||||
| 			capsule.m_centers[0].Set(0.0f, 4.0f, 0.0f); | 			capsule.m_vertex1.Set(0.0f, 4.0f, 0.0f); | ||||||
| 			capsule.m_centers[1].Set(0.0f, -4.0f, 0.0f); | 			capsule.m_vertex2.Set(0.0f, -4.0f, 0.0f); | ||||||
| 			capsule.m_radius = 0.5f; | 			capsule.m_radius = 0.5f; | ||||||
|  |  | ||||||
| 			b3ShapeDef sd; | 			b3ShapeDef sd; | ||||||
|   | |||||||
| @@ -24,104 +24,110 @@ class CapsuleStack : public Test | |||||||
| public: | public: | ||||||
| 	enum | 	enum | ||||||
| 	{ | 	{ | ||||||
| 		e_rowCount = 1, | 		e_h = 5, | ||||||
| 		e_columnCount = 5, | 		e_w = 1, | ||||||
| 		e_depthCount = 1 | 		e_d = 1 | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	CapsuleStack() | 	CapsuleStack() | ||||||
| 	{ | 	{ | ||||||
| 		{ | 		{ | ||||||
| 			b3BodyDef bd; | 			b3BodyDef bdef; | ||||||
| 			bd.type = b3BodyType::e_staticBody; | 			b3Body* body = m_world.CreateBody(bdef); | ||||||
| 			 |  | ||||||
| 			b3Body* body = m_world.CreateBody(bd); |  | ||||||
|  |  | ||||||
| 			b3HullShape hs; | 			b3HullShape hs; | ||||||
| 			hs.m_hull = &m_groundHull; | 			hs.m_hull = &m_groundHull; | ||||||
|  |  | ||||||
| 			b3ShapeDef sd; | 			b3ShapeDef sdef; | ||||||
| 			sd.shape = &hs; | 			sdef.shape = &hs; | ||||||
|  | 			sdef.friction = 1.0f; | ||||||
|  |  | ||||||
| 			body->CreateShape(sd); | 			body->CreateShape(sdef); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		float32 height = 3.0f; | 		scalar rx = 1.0f; | ||||||
| 		float32 radius = 1.0f; | 		scalar r = 1.0f; | ||||||
| 		float32 separation = 0.0f; |  | ||||||
|  |  | ||||||
| 		b3CapsuleShape capsule; | 		b3CapsuleShape capsule; | ||||||
| 		capsule.m_centers[0].Set(0.0f, -0.5f * height, 0.0f); | 		capsule.m_vertex1.Set(-rx, 0.0f, 0.0f); | ||||||
| 		capsule.m_centers[1].Set(0.0f, 0.5f * height, 0.0f); | 		capsule.m_vertex2.Set(rx, 0.0f, 0.0f); | ||||||
| 		capsule.m_radius = radius; | 		capsule.m_radius = r; | ||||||
|  |  | ||||||
| 		b3ShapeDef sdef; | 		b3Vec3 e; | ||||||
| 		sdef.shape = &capsule; | 		e.x = rx + r; | ||||||
| 		sdef.density = 0.1f; | 		e.y = r; | ||||||
| 		sdef.friction = 0.4f; | 		e.z = r; | ||||||
|  |  | ||||||
| 		const u32 c = e_rowCount * e_columnCount * e_depthCount; | 		b3Vec3 separation; | ||||||
| 		b3Body* bs[c]; | 		separation.x = 1.0f; | ||||||
| 		u32 n = 0; | 		separation.y = 1.0f; | ||||||
|  | 		separation.z = 1.0f; | ||||||
|  |  | ||||||
| 		b3AABB3 aabb; | 		b3Vec3 scale; | ||||||
| 		aabb.m_lower.Set(0.0f, 0.0f, 0.0f); | 		scale.x = 2.0f * e.x + separation.x; | ||||||
| 		aabb.m_upper.Set(0.0f, 0.0f, 0.0f); | 		scale.y = 2.0f * e.y + separation.y; | ||||||
|  | 		scale.z = 2.0f * e.z + separation.z; | ||||||
|  |  | ||||||
| 		for (u32 i = 0; i < e_rowCount; ++i) | 		b3Vec3 size; | ||||||
|  | 		size.x = 2.0f * e.x + scale.x * scalar(e_w - 1); | ||||||
|  | 		size.y = 2.0f * e.y + scale.y * scalar(e_h - 1); | ||||||
|  | 		size.z = 2.0f * e.z + scale.z * scalar(e_d - 1); | ||||||
|  |  | ||||||
|  | 		b3Vec3 translation; | ||||||
|  | 		translation.x = e.x - 0.5f * size.x; | ||||||
|  | 		translation.y = e.y - 0.5f * size.y; | ||||||
|  | 		translation.z = e.z - 0.5f * size.z; | ||||||
|  |  | ||||||
|  | 		translation.y += 9.0f; | ||||||
|  |  | ||||||
|  | 		for (u32 i = 0; i < e_h; ++i) | ||||||
| 		{ | 		{ | ||||||
| 			for (u32 j = 0; j < e_columnCount; ++j) | 			for (u32 j = 0; j < e_w; ++j) | ||||||
| 			{ | 			{ | ||||||
| 				for (u32 k = 0; k < e_depthCount; ++k) | 				for (u32 k = 0; k < e_d; ++k) | ||||||
| 				{ | 				{ | ||||||
| 					b3BodyDef bdef; | 					b3BodyDef bdef; | ||||||
| 					bdef.type = b3BodyType::e_dynamicBody; | 					bdef.type = e_dynamicBody; | ||||||
|  |  | ||||||
| 					bdef.position.x = (2.0f + separation) * float32(i) * (0.5f * height + radius); | 					bdef.position.Set(scalar(j), scalar(i), scalar(k)); | ||||||
| 					bdef.position.y = 2.0f + (2.0f + separation) * float32(j) * radius; |  | ||||||
| 					bdef.position.z = (2.0f + separation) * float32(k) * radius; |  | ||||||
|  |  | ||||||
| 					bdef.orientation = b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), 0.5f * B3_PI); | 					bdef.position.x *= scale.x; | ||||||
|  | 					bdef.position.y *= scale.y; | ||||||
|  | 					bdef.position.z *= scale.z; | ||||||
|  |  | ||||||
|  | 					bdef.position += translation; | ||||||
|  |  | ||||||
| 					b3Body* body = m_world.CreateBody(bdef); | 					b3Body* body = m_world.CreateBody(bdef); | ||||||
| 					bs[n++] = body; |  | ||||||
|  |  | ||||||
| 					b3Shape* shape = body->CreateShape(sdef); | 					b3ShapeDef sdef; | ||||||
|  | 					sdef.density = 0.1f; | ||||||
|  | 					sdef.friction = 0.3f; | ||||||
|  | 					sdef.shape = &capsule; | ||||||
|  |  | ||||||
| 					b3AABB3 aabb2; | 					body->CreateShape(sdef); | ||||||
| 					shape->ComputeAABB(&aabb2, body->GetTransform()); |  | ||||||
|  |  | ||||||
| 					aabb = b3Combine(aabb, aabb2); | 					u32 bodyIndex = GetBodyIndex(i, j, k); | ||||||
|  |  | ||||||
|  | 					m_bodies[bodyIndex] = body; | ||||||
|  | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 		b3Vec3 center = aabb.Centroid(); | 	u32 GetBodyIndex(u32 i, u32 j, u32 k) | ||||||
| 		 |  | ||||||
| 		for (u32 i = 0; i < n; ++i) |  | ||||||
| 	{ | 	{ | ||||||
| 			b3Body* b = bs[i]; | 		B3_ASSERT(i < e_h); | ||||||
| 			const b3Vec3& p = b->GetSweep().worldCenter; | 		B3_ASSERT(j < e_w); | ||||||
| 			const b3Quat& q = b->GetSweep().orientation; | 		B3_ASSERT(k < e_d); | ||||||
|  | 		return k + e_d * (j + e_w * i); | ||||||
| 			// centralize |  | ||||||
| 			b3Vec3 position = p - center; |  | ||||||
| 			 |  | ||||||
| 			// move up |  | ||||||
| 			position.y += 5.0f + 0.5f * aabb.Height() + radius; |  | ||||||
|  |  | ||||||
| 			// maintain orientation |  | ||||||
| 			b3Vec3 axis; |  | ||||||
| 			float32 angle; |  | ||||||
| 			q.GetAxisAngle(&axis, &angle); |  | ||||||
| 			b->SetTransform(position, axis, angle); |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	static Test* Create() | 	static Test* Create() | ||||||
| 	{ | 	{ | ||||||
| 		return new CapsuleStack(); | 		return new CapsuleStack(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	b3Body* m_bodies[e_h * e_w * e_d]; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
							
								
								
									
										181
									
								
								examples/testbed/tests/cloth_element_test.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								examples/testbed/tests/cloth_element_test.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,181 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * 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 CLOTH_ELEMENT_TEST_H | ||||||
|  | #define CLOTH_ELEMENT_TEST_H | ||||||
|  |  | ||||||
|  | class ClothElementTest : public Test | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	enum | ||||||
|  | 	{ | ||||||
|  | 		e_w = 10, | ||||||
|  | 		e_h = 10 | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	ClothElementTest() | ||||||
|  | 	{ | ||||||
|  | 		g_camera->m_zoom = 20.0f; | ||||||
|  |  | ||||||
|  | 		b3GridClothMesh<e_w, e_h> m; | ||||||
|  |  | ||||||
|  | 		b3ClothParticle** particles = (b3ClothParticle * *)b3Alloc(m.vertexCount * sizeof(b3ClothParticle*)); | ||||||
|  | 		for (u32 i = 0; i < m.vertexCount; ++i) | ||||||
|  | 		{ | ||||||
|  | 			b3ClothParticleDef pd; | ||||||
|  | 			pd.type = e_dynamicClothParticle; | ||||||
|  | 			pd.position = m.vertices[i]; | ||||||
|  |  | ||||||
|  | 			b3ClothParticle* p = m_cloth.CreateParticle(pd); | ||||||
|  | 			particles[i] = p; | ||||||
|  |  | ||||||
|  | 			b3ClothSphereShapeDef sd; | ||||||
|  | 			sd.p = p; | ||||||
|  | 			sd.radius = 0.2f; | ||||||
|  | 			sd.friction = 0.4f; | ||||||
|  |  | ||||||
|  | 			m_cloth.CreateSphereShape(sd); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		for (u32 i = 0; i < m.triangleCount; ++i) | ||||||
|  | 		{ | ||||||
|  | 			u32 v1 = m.triangles[i].v1; | ||||||
|  | 			u32 v2 = m.triangles[i].v2; | ||||||
|  | 			u32 v3 = m.triangles[i].v3; | ||||||
|  |  | ||||||
|  | 			b3Vec3 x1 = m.vertices[v1]; | ||||||
|  | 			b3Vec3 x2 = m.vertices[v2]; | ||||||
|  | 			b3Vec3 x3 = m.vertices[v3]; | ||||||
|  |  | ||||||
|  | 			b3ClothParticle* p1 = particles[v1]; | ||||||
|  | 			b3ClothParticle* p2 = particles[v2]; | ||||||
|  | 			b3ClothParticle* p3 = particles[v3]; | ||||||
|  |  | ||||||
|  | 			b3ClothTriangleShapeDef tsd; | ||||||
|  | 			tsd.p1 = p1; | ||||||
|  | 			tsd.p2 = p2; | ||||||
|  | 			tsd.p3 = p3; | ||||||
|  | 			tsd.v1 = x1; | ||||||
|  | 			tsd.v2 = x2; | ||||||
|  | 			tsd.v3 = x3; | ||||||
|  | 			tsd.density = 0.1f; | ||||||
|  |  | ||||||
|  | 			m_cloth.CreateTriangleShape(tsd); | ||||||
|  |  | ||||||
|  | 			b3ElementForceDef fd; | ||||||
|  | 			fd.p1 = p1; | ||||||
|  | 			fd.p2 = p2; | ||||||
|  | 			fd.p3 = p3; | ||||||
|  | 			fd.E_x = 500.0f; | ||||||
|  | 			fd.E_y = 500.0f; | ||||||
|  | 			fd.E_s = 500.0f; | ||||||
|  | 			fd.nu_xy = 0.3f; | ||||||
|  | 			fd.nu_yx = 0.3f; | ||||||
|  | 			fd.v1 = x1; | ||||||
|  | 			fd.v2 = x2; | ||||||
|  | 			fd.v3 = x3; | ||||||
|  |  | ||||||
|  | 			m_cloth.CreateForce(fd); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		for (u32 i = 0; i < e_w + 1; ++i) | ||||||
|  | 		{ | ||||||
|  | 			u32 vertex = m.GetVertex(0, i); | ||||||
|  | 			particles[vertex]->SetType(e_staticClothParticle); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		b3Free(particles); | ||||||
|  |  | ||||||
|  | 		m_cloth.SetGravity(b3Vec3(0.0f, -9.8f, 0.0f)); | ||||||
|  |  | ||||||
|  | 		m_clothDragger = new b3ClothDragger(&m_ray, &m_cloth); | ||||||
|  | 		m_clothDragger->SetStaticDrag(false); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	~ClothElementTest() | ||||||
|  | 	{ | ||||||
|  | 		delete m_clothDragger; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void Step() | ||||||
|  | 	{ | ||||||
|  | 		Test::Step(); | ||||||
|  |  | ||||||
|  | 		m_cloth.Step(g_testSettings->inv_hertz, g_testSettings->velocityIterations, g_testSettings->positionIterations); | ||||||
|  |  | ||||||
|  | 		m_cloth.Draw(); | ||||||
|  |  | ||||||
|  | 		if (m_clothDragger->IsDragging()) | ||||||
|  | 		{ | ||||||
|  | 			b3Vec3 pA = m_clothDragger->GetPointA(); | ||||||
|  | 			b3Vec3 pB = m_clothDragger->GetPointB(); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawPoint(pA, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawPoint(pB, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawSegment(pA, pB, b3Color_white); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		extern u32 b3_clothSolverIterations; | ||||||
|  | 		g_draw->DrawString(b3Color_white, "Iterations = %d", b3_clothSolverIterations); | ||||||
|  |  | ||||||
|  | 		scalar E = m_cloth.GetEnergy(); | ||||||
|  | 		g_draw->DrawString(b3Color_white, "E = %f", E); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void MouseMove(const b3Ray3& pw) | ||||||
|  | 	{ | ||||||
|  | 		Test::MouseMove(pw); | ||||||
|  |  | ||||||
|  | 		if (m_clothDragger->IsDragging() == true) | ||||||
|  | 		{ | ||||||
|  | 			m_clothDragger->Drag(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void MouseLeftDown(const b3Ray3& pw) | ||||||
|  | 	{ | ||||||
|  | 		Test::MouseLeftDown(pw); | ||||||
|  |  | ||||||
|  | 		if (m_clothDragger->IsDragging() == false) | ||||||
|  | 		{ | ||||||
|  | 			m_clothDragger->StartDragging(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void MouseLeftUp(const b3Ray3& pw) | ||||||
|  | 	{ | ||||||
|  | 		Test::MouseLeftUp(pw); | ||||||
|  |  | ||||||
|  | 		if (m_clothDragger->IsDragging() == true) | ||||||
|  | 		{ | ||||||
|  | 			m_clothDragger->StopDragging(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	static Test* Create() | ||||||
|  | 	{ | ||||||
|  | 		return new ClothElementTest(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b3Cloth m_cloth; | ||||||
|  | 	b3ClothDragger* m_clothDragger; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										268
									
								
								examples/testbed/tests/cloth_sdf.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										268
									
								
								examples/testbed/tests/cloth_sdf.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,268 @@ | |||||||
|  | /*  | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * 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 CLOTH_SDF_H | ||||||
|  | #define CLOTH_SDF_H | ||||||
|  |  | ||||||
|  | #define TINYOBJLOADER_IMPLEMENTATION  | ||||||
|  | #include <tinyobjloader/tiny_obj_loader.h> | ||||||
|  |  | ||||||
|  | struct SDFMesh | ||||||
|  | { | ||||||
|  | 	u32 vertexCount; | ||||||
|  | 	b3Vec3* vertices; | ||||||
|  | 	u32 indexCount; | ||||||
|  | 	u32* indices; | ||||||
|  |  | ||||||
|  | 	SDFMesh() | ||||||
|  | 	{ | ||||||
|  | 		vertexCount = 0; | ||||||
|  | 		vertices = nullptr; | ||||||
|  | 		indexCount = 0; | ||||||
|  | 		indices = nullptr; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	~SDFMesh() | ||||||
|  | 	{ | ||||||
|  | 		free(vertices); | ||||||
|  | 		free(indices); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	bool Load(const char* filename) | ||||||
|  | 	{ | ||||||
|  | 		tinyobj::attrib_t attributes; | ||||||
|  | 		std::vector<tinyobj::shape_t> shapes; | ||||||
|  | 		std::vector<tinyobj::material_t> materials; | ||||||
|  |  | ||||||
|  | 		std::string warning; | ||||||
|  | 		std::string error; | ||||||
|  | 		bool ok = tinyobj::LoadObj(&attributes, &shapes, &materials, &warning, &error, filename); | ||||||
|  | 		if (!ok) | ||||||
|  | 		{ | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		assert(vertexCount == 0); | ||||||
|  | 		vertexCount = attributes.vertices.size() / 3; | ||||||
|  | 		vertices = (b3Vec3*)malloc(vertexCount * sizeof(b3Vec3)); | ||||||
|  | 		for (size_t i = 0; i < attributes.vertices.size() / 3; ++i) | ||||||
|  | 		{ | ||||||
|  | 			tinyobj::real_t x = attributes.vertices[3 * i + 0]; | ||||||
|  | 			tinyobj::real_t y = attributes.vertices[3 * i + 1]; | ||||||
|  | 			tinyobj::real_t z = attributes.vertices[3 * i + 2]; | ||||||
|  |  | ||||||
|  | 			b3Vec3 v(x, y, z); | ||||||
|  |  | ||||||
|  | 			vertices[i] = v; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		assert(indexCount == 0); | ||||||
|  | 		for (size_t s = 0; s < shapes.size(); s++) | ||||||
|  | 		{ | ||||||
|  | 			tinyobj::shape_t& shape = shapes[s]; | ||||||
|  | 			for (size_t f = 0; f < shapes[s].mesh.num_face_vertices.size(); f++) | ||||||
|  | 			{ | ||||||
|  | 				indexCount += 3; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		indices = (u32*)malloc(indexCount * sizeof(u32)); | ||||||
|  |  | ||||||
|  | 		indexCount = 0; | ||||||
|  | 		for (size_t s = 0; s < shapes.size(); s++)  | ||||||
|  | 		{ | ||||||
|  | 			tinyobj::shape_t& shape = shapes[s]; | ||||||
|  |  | ||||||
|  | 			size_t index_offset = 0; | ||||||
|  | 			for (size_t f = 0; f < shapes[s].mesh.num_face_vertices.size(); f++)  | ||||||
|  | 			{ | ||||||
|  | 				unsigned char fv = shapes[s].mesh.num_face_vertices[f]; | ||||||
|  |  | ||||||
|  | 				for (size_t v = 0; v < 3; v++)  | ||||||
|  | 				{ | ||||||
|  | 					tinyobj::index_t idx = shapes[s].mesh.indices[index_offset + v]; | ||||||
|  | 					 | ||||||
|  | 					size_t vi = idx.vertex_index; | ||||||
|  |  | ||||||
|  | 					indices[indexCount++] = vi; | ||||||
|  | 				} | ||||||
|  | 				 | ||||||
|  | 				index_offset += fv; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void Draw(const b3Transform& xf, const b3Vec3& scale, const b3Color& color) const | ||||||
|  | 	{ | ||||||
|  | 		for (u32 i = 0; i < indexCount / 3; ++i) | ||||||
|  | 		{ | ||||||
|  | 			u32 i1 = indices[3 * i + 0]; | ||||||
|  | 			u32 i2 = indices[3 * i + 1]; | ||||||
|  | 			u32 i3 = indices[3 * i + 2]; | ||||||
|  |  | ||||||
|  | 			b3Vec3 v1 = xf * b3MulCW(scale, vertices[i1]); | ||||||
|  | 			b3Vec3 v2 = xf * b3MulCW(scale, vertices[i2]); | ||||||
|  | 			b3Vec3 v3 = xf * b3MulCW(scale, vertices[i3]); | ||||||
|  |  | ||||||
|  | 			b3Vec3 n = b3Cross(v2 - v1, v3 - v1); | ||||||
|  | 			n.Normalize(); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawSolidTriangle(n, v1, v2, v3, color); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class ClothSDF : public Test | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	ClothSDF() | ||||||
|  | 	{ | ||||||
|  | 		// Translate the cloth mesh | ||||||
|  | 		for (u32 i = 0; i < m_clothMesh.vertexCount; ++i) | ||||||
|  | 		{ | ||||||
|  | 			m_clothMesh.vertices[i].y += 5.0f; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Create cloth | ||||||
|  | 		b3ClothDef def; | ||||||
|  | 		def.mesh = &m_clothMesh; | ||||||
|  | 		def.density = 0.2f; | ||||||
|  | 		def.streching = 10000.0f; | ||||||
|  | 		def.strechDamping = 100.0f; | ||||||
|  | 		def.thickness = 0.2f; | ||||||
|  | 		def.friction = 0.2f; | ||||||
|  |  | ||||||
|  | 		m_cloth = new b3Cloth(def); | ||||||
|  |  | ||||||
|  | 		m_cloth->SetGravity(b3Vec3(0.0f, -9.8f, 0.0f)); | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			bool ok = m_sdfMesh.Load("data/teapot.obj"); | ||||||
|  | 			assert(ok); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bd; | ||||||
|  | 			bd.type = e_staticBody; | ||||||
|  |  | ||||||
|  | 			b3Body* b = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
|  | 			bool ok = m_sdf.Load("data/teapot.cdf"); | ||||||
|  | 			assert(ok); | ||||||
|  |  | ||||||
|  | 			b3SDFShape sdfShape; | ||||||
|  | 			sdfShape.m_sdf = &m_sdf; | ||||||
|  | 			sdfShape.m_radius = 0.2f; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sd; | ||||||
|  | 			sd.shape = &sdfShape; | ||||||
|  | 			sd.friction = 1.0f; | ||||||
|  | 			 | ||||||
|  | 			m_sdfShape = (b3SDFShape*)b->CreateShape(sd); | ||||||
|  |  | ||||||
|  | 			b3ClothWorldShapeDef csd; | ||||||
|  | 			csd.shape = m_sdfShape; | ||||||
|  |  | ||||||
|  | 			m_cloth->CreateWorldShape(csd); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		m_clothDragger = new b3ClothDragger(&m_ray, m_cloth); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	~ClothSDF() | ||||||
|  | 	{ | ||||||
|  | 		delete m_clothDragger; | ||||||
|  | 		delete m_cloth; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void Step() | ||||||
|  | 	{ | ||||||
|  | 		Test::Step(); | ||||||
|  |  | ||||||
|  | 		m_cloth->Step(g_testSettings->inv_hertz, g_testSettings->velocityIterations, g_testSettings->positionIterations); | ||||||
|  |  | ||||||
|  | 		m_cloth->Draw(); | ||||||
|  |  | ||||||
|  | 		if (m_clothDragger->IsDragging()) | ||||||
|  | 		{ | ||||||
|  | 			b3Vec3 pA = m_clothDragger->GetPointA(); | ||||||
|  | 			b3Vec3 pB = m_clothDragger->GetPointB(); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawPoint(pA, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawPoint(pB, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawSegment(pA, pB, b3Color_white); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		b3Body* sdfBody = m_sdfShape->GetBody(); | ||||||
|  | 		m_sdfMesh.Draw(sdfBody->GetTransform(), m_sdfShape->m_scale, b3Color_white); | ||||||
|  |  | ||||||
|  | 		extern u32 b3_clothSolverIterations; | ||||||
|  | 		g_draw->DrawString(b3Color_white, "Iterations = %d", b3_clothSolverIterations); | ||||||
|  |  | ||||||
|  | 		scalar E = m_cloth->GetEnergy(); | ||||||
|  | 		g_draw->DrawString(b3Color_white, "E = %f", E); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void MouseMove(const b3Ray3& pw) | ||||||
|  | 	{ | ||||||
|  | 		Test::MouseMove(pw); | ||||||
|  |  | ||||||
|  | 		if (m_clothDragger->IsDragging() == true) | ||||||
|  | 		{ | ||||||
|  | 			m_clothDragger->Drag(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void MouseLeftDown(const b3Ray3& pw) | ||||||
|  | 	{ | ||||||
|  | 		Test::MouseLeftDown(pw); | ||||||
|  |  | ||||||
|  | 		if (m_clothDragger->IsDragging() == false) | ||||||
|  | 		{ | ||||||
|  | 			m_clothDragger->StartDragging(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void MouseLeftUp(const b3Ray3& pw) | ||||||
|  | 	{ | ||||||
|  | 		Test::MouseLeftUp(pw); | ||||||
|  |  | ||||||
|  | 		if (m_clothDragger->IsDragging() == true) | ||||||
|  | 		{ | ||||||
|  | 			m_clothDragger->StopDragging(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	static Test* Create() | ||||||
|  | 	{ | ||||||
|  | 		return new ClothSDF(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b3GridClothMesh<10, 10> m_clothMesh; | ||||||
|  | 	b3Cloth* m_cloth; | ||||||
|  | 	b3ClothDragger* m_clothDragger; | ||||||
|  |  | ||||||
|  | 	SDFMesh m_sdfMesh; | ||||||
|  | 	b3SDF m_sdf; | ||||||
|  | 	b3SDFShape* m_sdfShape; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
| @@ -22,15 +22,82 @@ | |||||||
| class ClothSelfCollision : public Test | class ClothSelfCollision : public Test | ||||||
| { | { | ||||||
| public: | public: | ||||||
|  | 	enum | ||||||
|  | 	{ | ||||||
|  | 		e_w1 = 5, | ||||||
|  | 		e_h1 = 5, | ||||||
|  | 		e_w2 = 5, | ||||||
|  | 		e_h2 = 5 | ||||||
|  | 	}; | ||||||
|  |  | ||||||
| 	ClothSelfCollision() | 	ClothSelfCollision() | ||||||
| 	{ | 	{ | ||||||
| 		// Translate the mesh | 		b3GridClothMesh<e_w1, e_h1> mesh1; | ||||||
| 		for (u32 i = 0; i < m_clothMesh.vertexCount; ++i) | 		b3Quat qX = b3QuatRotationX(0.5f * B3_PI); | ||||||
|  | 		for (u32 i = 0; i < mesh1.vertexCount; ++i) | ||||||
| 		{ | 		{ | ||||||
| 			m_clothMesh.vertices[i].y += 5.0f; | 			mesh1.vertices[i] = b3Mul(qX, mesh1.vertices[i]); | ||||||
|  | 			mesh1.vertices[i].y += 5.0f; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// Create cloth | 		b3GridClothMesh<e_w2, e_h2> mesh2; | ||||||
|  | 		b3Quat qY = b3QuatRotationY(0.5f * B3_PI); | ||||||
|  | 		for (u32 i = 0; i < mesh2.vertexCount; ++i) | ||||||
|  | 		{ | ||||||
|  | 			mesh2.vertices[i] = b3Mul(qY * qX, mesh2.vertices[i]); | ||||||
|  | 			mesh2.vertices[i].y += 12.0f; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Merge the meshes | ||||||
|  | 		m_clothMesh.vertexCount = mesh1.vertexCount + mesh2.vertexCount; | ||||||
|  | 		m_clothMesh.vertices = (b3Vec3*)b3Alloc(m_clothMesh.vertexCount * sizeof(b3Vec3)); | ||||||
|  | 		 | ||||||
|  | 		u32* newVertices1 = (u32*)b3Alloc(mesh1.vertexCount * sizeof(u32)); | ||||||
|  | 		u32 vertexIndex = 0; | ||||||
|  | 		for (u32 i = 0; i < mesh1.vertexCount; ++i) | ||||||
|  | 		{ | ||||||
|  | 			newVertices1[i] = vertexIndex; | ||||||
|  | 			m_clothMesh.vertices[vertexIndex++] = mesh1.vertices[i]; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		u32* newVertices2 = (u32*)b3Alloc(mesh2.vertexCount * sizeof(u32)); | ||||||
|  | 		for (u32 i = 0; i < mesh2.vertexCount; ++i) | ||||||
|  | 		{ | ||||||
|  | 			newVertices2[i] = vertexIndex; | ||||||
|  | 			m_clothMesh.vertices[vertexIndex++] = mesh2.vertices[i]; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		m_clothMesh.triangleCount = mesh1.triangleCount + mesh2.triangleCount; | ||||||
|  | 		m_clothMesh.triangles = (b3ClothMeshTriangle*)b3Alloc(m_clothMesh.triangleCount * sizeof(b3ClothMeshTriangle)); | ||||||
|  | 		u32 triangleIndex = 0; | ||||||
|  | 		for (u32 i = 0; i < mesh1.triangleCount; ++i) | ||||||
|  | 		{ | ||||||
|  | 			m_clothMesh.triangles[triangleIndex].v1 = newVertices1[mesh1.triangles[i].v1]; | ||||||
|  | 			m_clothMesh.triangles[triangleIndex].v2 = newVertices1[mesh1.triangles[i].v2]; | ||||||
|  | 			m_clothMesh.triangles[triangleIndex].v3 = newVertices1[mesh1.triangles[i].v3]; | ||||||
|  | 			++triangleIndex; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		for (u32 i = 0; i < mesh2.triangleCount; ++i) | ||||||
|  | 		{ | ||||||
|  | 			m_clothMesh.triangles[triangleIndex].v1 = newVertices2[mesh2.triangles[i].v1]; | ||||||
|  | 			m_clothMesh.triangles[triangleIndex].v2 = newVertices2[mesh2.triangles[i].v2]; | ||||||
|  | 			m_clothMesh.triangles[triangleIndex].v3 = newVertices2[mesh2.triangles[i].v3]; | ||||||
|  | 			++triangleIndex; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		m_clothMesh.meshCount = 1; | ||||||
|  | 		m_clothMesh.meshes = (b3ClothMeshMesh*)b3Alloc(sizeof(b3ClothMeshMesh)); | ||||||
|  | 		m_clothMesh.meshes->startTriangle = 0; | ||||||
|  | 		m_clothMesh.meshes->triangleCount = m_clothMesh.triangleCount; | ||||||
|  | 		m_clothMesh.meshes->startVertex = 0; | ||||||
|  | 		m_clothMesh.meshes->vertexCount = m_clothMesh.vertexCount; | ||||||
|  |  | ||||||
|  | 		m_clothMesh.shearingLineCount = 0; | ||||||
|  | 		m_clothMesh.bendingLineCount = 0; | ||||||
|  | 		m_clothMesh.sewingLineCount = 0; | ||||||
|  |  | ||||||
|  | 		// Create the cloth | ||||||
| 		b3ClothDef def; | 		b3ClothDef def; | ||||||
| 		def.mesh = &m_clothMesh; | 		def.mesh = &m_clothMesh; | ||||||
| 		def.density = 1.0f; | 		def.density = 1.0f; | ||||||
| @@ -41,24 +108,37 @@ public: | |||||||
| 		m_cloth = new b3Cloth(def); | 		m_cloth = new b3Cloth(def); | ||||||
|  |  | ||||||
| 		m_cloth->SetGravity(b3Vec3(0.0f, -9.8f, 0.0f)); | 		m_cloth->SetGravity(b3Vec3(0.0f, -9.8f, 0.0f)); | ||||||
| 		m_cloth->SetWorld(&m_world); | 		m_cloth->EnableSelfCollision(true); | ||||||
|  |  | ||||||
|  | 		for (u32 i = 0; i < mesh1.vertexCount; ++i) | ||||||
|  | 		{ | ||||||
|  | 			u32 newVertex = newVertices1[i]; | ||||||
|  |  | ||||||
|  | 			m_cloth->GetParticle(newVertex)->SetType(e_staticClothParticle); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		b3Free(newVertices1); | ||||||
|  | 		b3Free(newVertices2); | ||||||
|  |  | ||||||
| 		{ | 		{ | ||||||
| 			b3BodyDef bd; | 			b3BodyDef bd; | ||||||
| 			bd.type = e_staticBody; |  | ||||||
|  |  | ||||||
| 			b3Body* b = m_world.CreateBody(bd); | 			b3Body* b = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
| 			b3CapsuleShape capsuleShape; | 			b3HullShape hullShape; | ||||||
| 			capsuleShape.m_centers[0].Set(0.0f, 0.0f, -5.0f); | 			hullShape.m_hull = &m_groundHull; | ||||||
| 			capsuleShape.m_centers[1].Set(0.0f, 0.0f, 5.0f); | 			hullShape.m_radius = 0.0f;; | ||||||
| 			capsuleShape.m_radius = 1.0f;; |  | ||||||
|  |  | ||||||
| 			b3ShapeDef sd; | 			b3ShapeDef sd; | ||||||
| 			sd.shape = &capsuleShape; | 			sd.shape = &hullShape; | ||||||
| 			sd.friction = 1.0f; | 			sd.friction = 1.0f; | ||||||
|  |  | ||||||
| 			b->CreateShape(sd); | 			b3Shape* s = b->CreateShape(sd); | ||||||
|  |  | ||||||
|  | 			b3ClothWorldShapeDef csd; | ||||||
|  | 			csd.shape = s; | ||||||
|  |  | ||||||
|  | 			m_cloth->CreateWorldShape(csd); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		m_clothDragger = new b3ClothDragger(&m_ray, m_cloth); | 		m_clothDragger = new b3ClothDragger(&m_ray, m_cloth); | ||||||
| @@ -66,6 +146,10 @@ public: | |||||||
|  |  | ||||||
| 	~ClothSelfCollision() | 	~ClothSelfCollision() | ||||||
| 	{ | 	{ | ||||||
|  | 		b3Free(m_clothMesh.vertices); | ||||||
|  | 		b3Free(m_clothMesh.triangles); | ||||||
|  | 		b3Free(m_clothMesh.meshes); | ||||||
|  |  | ||||||
| 		delete m_cloth; | 		delete m_cloth; | ||||||
| 		delete m_clothDragger; | 		delete m_clothDragger; | ||||||
| 	} | 	} | ||||||
| @@ -83,17 +167,27 @@ public: | |||||||
| 			b3Vec3 pA = m_clothDragger->GetPointA(); | 			b3Vec3 pA = m_clothDragger->GetPointA(); | ||||||
| 			b3Vec3 pB = m_clothDragger->GetPointB(); | 			b3Vec3 pB = m_clothDragger->GetPointB(); | ||||||
|  |  | ||||||
| 			g_draw->DrawPoint(pA, 2.0f, b3Color_green); | 			g_draw->DrawPoint(pA, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
| 			g_draw->DrawPoint(pB, 2.0f, b3Color_green); | 			g_draw->DrawPoint(pB, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
| 			g_draw->DrawSegment(pA, pB, b3Color_white); | 			g_draw->DrawSegment(pA, pB, b3Color_white); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		g_draw->DrawString(b3Color_white, "S - Turn on/off self collision"); | ||||||
|  | 		if (m_cloth->IsSelfCollisionEnabled()) | ||||||
|  | 		{ | ||||||
|  | 			g_draw->DrawString(b3Color_white, "Self collision enabled"); | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			g_draw->DrawString(b3Color_white, "Self collision disabled"); | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		extern u32 b3_clothSolverIterations; | 		extern u32 b3_clothSolverIterations; | ||||||
| 		g_draw->DrawString(b3Color_white, "Iterations = %d", b3_clothSolverIterations); | 		g_draw->DrawString(b3Color_white, "Iterations = %d", b3_clothSolverIterations); | ||||||
|  |  | ||||||
| 		float32 E = m_cloth->GetEnergy(); | 		scalar E = m_cloth->GetEnergy(); | ||||||
| 		g_draw->DrawString(b3Color_white, "E = %f", E); | 		g_draw->DrawString(b3Color_white, "E = %f", E); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -127,12 +221,20 @@ public: | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	void KeyDown(int key) | ||||||
|  | 	{ | ||||||
|  | 		if (key == GLFW_KEY_S) | ||||||
|  | 		{ | ||||||
|  | 			m_cloth->EnableSelfCollision(!m_cloth->IsSelfCollisionEnabled()); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	static Test* Create() | 	static Test* Create() | ||||||
| 	{ | 	{ | ||||||
| 		return new ClothSelfCollision(); | 		return new ClothSelfCollision(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	b3GridClothMesh<10, 10> m_clothMesh; | 	b3ClothMesh m_clothMesh; | ||||||
| 	b3Cloth* m_cloth; | 	b3Cloth* m_cloth; | ||||||
| 	b3ClothDragger* m_clothDragger;  | 	b3ClothDragger* m_clothDragger;  | ||||||
| }; | }; | ||||||
|   | |||||||
							
								
								
									
										571
									
								
								examples/testbed/tests/cloth_tearing.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										571
									
								
								examples/testbed/tests/cloth_tearing.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,571 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * 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 CLOTH_TEARING_H | ||||||
|  | #define CLOTH_TEARING_H | ||||||
|  |  | ||||||
|  | class ClothTearing : public Test | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	enum | ||||||
|  | 	{ | ||||||
|  | 		e_w = 10, | ||||||
|  | 		e_h = 10 | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	ClothTearing() | ||||||
|  | 	{ | ||||||
|  | 		g_camera->m_zoom = 20.0f; | ||||||
|  |  | ||||||
|  | 		b3GridClothMesh<e_w, e_h> m; | ||||||
|  |  | ||||||
|  | 		b3ClothParticle** particles = (b3ClothParticle * *)b3Alloc(m.vertexCount * sizeof(b3ClothParticle*)); | ||||||
|  | 		for (u32 i = 0; i < m.vertexCount; ++i) | ||||||
|  | 		{ | ||||||
|  | 			b3ClothParticleDef pd; | ||||||
|  | 			pd.type = e_dynamicClothParticle; | ||||||
|  | 			pd.position = m.vertices[i]; | ||||||
|  |  | ||||||
|  | 			b3ClothParticle* p = m_cloth.CreateParticle(pd); | ||||||
|  | 			particles[i] = p; | ||||||
|  |  | ||||||
|  | 			b3ClothSphereShapeDef sd; | ||||||
|  | 			sd.p = p; | ||||||
|  | 			sd.radius = 0.2f; | ||||||
|  | 			sd.friction = 0.4f; | ||||||
|  |  | ||||||
|  | 			m_cloth.CreateSphereShape(sd); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		for (u32 i = 0; i < m.triangleCount; ++i) | ||||||
|  | 		{ | ||||||
|  | 			u32 v1 = m.triangles[i].v1; | ||||||
|  | 			u32 v2 = m.triangles[i].v2; | ||||||
|  | 			u32 v3 = m.triangles[i].v3; | ||||||
|  |  | ||||||
|  | 			b3ClothParticle* p1 = particles[v1]; | ||||||
|  | 			b3ClothParticle* p2 = particles[v2]; | ||||||
|  | 			b3ClothParticle* p3 = particles[v3]; | ||||||
|  |  | ||||||
|  | 			b3ClothTriangleShapeDef tsd; | ||||||
|  | 			tsd.p1 = p1; | ||||||
|  | 			tsd.p2 = p2; | ||||||
|  | 			tsd.p3 = p3; | ||||||
|  | 			tsd.v1 = m.vertices[v1]; | ||||||
|  | 			tsd.v2 = m.vertices[v2]; | ||||||
|  | 			tsd.v3 = m.vertices[v3]; | ||||||
|  | 			tsd.density = 0.1f; | ||||||
|  |  | ||||||
|  | 			m_cloth.CreateTriangleShape(tsd); | ||||||
|  |  | ||||||
|  | 			{ | ||||||
|  | 				b3SpringForceDef sfd; | ||||||
|  | 				sfd.Initialize(p1, p2, 1000.0f, 10.0f); | ||||||
|  |  | ||||||
|  | 				CreateSpringForce(sfd); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			{ | ||||||
|  | 				b3SpringForceDef sfd; | ||||||
|  | 				sfd.Initialize(p2, p3, 1000.0f, 10.0f); | ||||||
|  |  | ||||||
|  | 				CreateSpringForce(sfd); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			{ | ||||||
|  | 				b3SpringForceDef sfd; | ||||||
|  | 				sfd.Initialize(p3, p1, 1000.0f, 10.0f); | ||||||
|  |  | ||||||
|  | 				CreateSpringForce(sfd); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		for (u32 i = 0; i < e_w + 1; ++i) | ||||||
|  | 		{ | ||||||
|  | 			u32 vertex = m.GetVertex(0, i); | ||||||
|  | 			particles[vertex]->SetType(e_staticClothParticle); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		b3Free(particles); | ||||||
|  |  | ||||||
|  | 		m_cloth.SetGravity(b3Vec3(0.0f, -9.8f, 0.0f)); | ||||||
|  |  | ||||||
|  | 		m_clothDragger = new b3ClothDragger(&m_ray, &m_cloth); | ||||||
|  | 		m_clothDragger->SetStaticDrag(false); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	~ClothTearing() | ||||||
|  | 	{ | ||||||
|  | 		delete m_clothDragger; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b3SpringForce* FindSpringForce(b3ClothParticle* p1, b3ClothParticle* p2) | ||||||
|  | 	{ | ||||||
|  | 		for (b3Force* f = m_cloth.GetForceList().m_head; f; f = f->GetNext()) | ||||||
|  | 		{ | ||||||
|  | 			if (f->GetType() != e_springForce) | ||||||
|  | 			{ | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			b3SpringForce* sf = (b3SpringForce*)f; | ||||||
|  |  | ||||||
|  | 			b3ClothParticle* sp1 = sf->GetParticle1(); | ||||||
|  | 			b3ClothParticle* sp2 = sf->GetParticle2(); | ||||||
|  |  | ||||||
|  | 			if (sp1 == p1 && sp2 == p2) | ||||||
|  | 			{ | ||||||
|  | 				return sf; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (sp1 == p2 && sp2 == p1) | ||||||
|  | 			{ | ||||||
|  | 				return sf; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return nullptr; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b3SpringForce* CreateSpringForce(const b3SpringForceDef& def) | ||||||
|  | 	{ | ||||||
|  | 		b3SpringForce* sf = FindSpringForce(def.p1, def.p2); | ||||||
|  | 		if (sf != nullptr) | ||||||
|  | 		{ | ||||||
|  | 			return sf; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return (b3SpringForce*)m_cloth.CreateForce(def); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void DrawSpringForces() | ||||||
|  | 	{ | ||||||
|  | 		for (b3Force* f = m_cloth.GetForceList().m_head; f; f = f->GetNext()) | ||||||
|  | 		{ | ||||||
|  | 			if (f->GetType() != e_springForce) | ||||||
|  | 			{ | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			b3SpringForce* s = (b3SpringForce*)f; | ||||||
|  |  | ||||||
|  | 			b3ClothParticle* p1 = s->GetParticle1(); | ||||||
|  | 			b3ClothParticle* p2 = s->GetParticle2(); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawSegment(p1->GetPosition(), p2->GetPosition(), b3Color_black); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void Partition(b3ClothParticle* p, const b3Plane& plane, | ||||||
|  | 		b3Array<b3ClothTriangleShape*>& above, | ||||||
|  | 		b3Array<b3ClothTriangleShape*>& below) | ||||||
|  | 	{ | ||||||
|  | 		for (b3ClothTriangleShape* t = m_cloth.GetTriangleShapeList().m_head; t; t = t->GetNext()) | ||||||
|  | 		{ | ||||||
|  | 			b3ClothParticle* p1 = t->GetParticle1(); | ||||||
|  | 			b3ClothParticle* p2 = t->GetParticle2(); | ||||||
|  | 			b3ClothParticle* p3 = t->GetParticle3(); | ||||||
|  |  | ||||||
|  | 			if (p1 != p && p2 != p && p3 != p) | ||||||
|  | 			{ | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			b3Vec3 x1 = p1->GetPosition(); | ||||||
|  | 			b3Vec3 x2 = p2->GetPosition(); | ||||||
|  | 			b3Vec3 x3 = p3->GetPosition(); | ||||||
|  |  | ||||||
|  | 			b3Vec3 center = (x1 + x2 + x3) / 3.0f; | ||||||
|  |  | ||||||
|  | 			scalar distance = b3Distance(center, plane); | ||||||
|  | 			if (distance > 0.0f) | ||||||
|  | 			{ | ||||||
|  | 				above.PushBack(t); | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				below.PushBack(t); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	bool HasSpring(const b3Array<b3ClothTriangleShape*>& triangles, | ||||||
|  | 		b3ClothParticle* pOld, b3ClothParticle* pOther) | ||||||
|  | 	{ | ||||||
|  | 		for (u32 i = 0; i < triangles.Count(); ++i) | ||||||
|  | 		{ | ||||||
|  | 			b3ClothTriangleShape* triangle = triangles[i]; | ||||||
|  |  | ||||||
|  | 			b3ClothParticle* tp1 = triangle->GetParticle1(); | ||||||
|  | 			b3ClothParticle* tp2 = triangle->GetParticle2(); | ||||||
|  | 			b3ClothParticle* tp3 = triangle->GetParticle3(); | ||||||
|  |  | ||||||
|  | 			// 1, 2 | ||||||
|  | 			if (tp1 == pOld && tp2 == pOther) | ||||||
|  | 			{ | ||||||
|  | 				return true; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// 2, 1 | ||||||
|  | 			if (tp2 == pOld && tp1 == pOther) | ||||||
|  | 			{ | ||||||
|  | 				return true; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// 2, 3 | ||||||
|  | 			if (tp2 == pOld && tp3 == pOther) | ||||||
|  | 			{ | ||||||
|  | 				return true; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// 3, 2 | ||||||
|  | 			if (tp3 == pOld && tp2 == pOther) | ||||||
|  | 			{ | ||||||
|  | 				return true; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// 3, 1 | ||||||
|  | 			if (tp3 == pOld && tp1 == pOther) | ||||||
|  | 			{ | ||||||
|  | 				return true; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// 1, 3 | ||||||
|  | 			if (tp1 == pOld && tp3 == pOther) | ||||||
|  | 			{ | ||||||
|  | 				return true; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	bool SplitParticle(b3ClothParticle* pOld, const b3Plane& plane) | ||||||
|  | 	{ | ||||||
|  | 		// Collect triangles. | ||||||
|  | 		b3StackArray<b3ClothTriangleShape*, 32> trianglesAbove, trianglesBelow; | ||||||
|  | 		Partition(pOld, plane, trianglesAbove, trianglesBelow); | ||||||
|  |  | ||||||
|  | 		// There must be at least one triangle on each side of the plane. | ||||||
|  | 		if (trianglesAbove.Count() == 0 || trianglesBelow.Count() == 0) | ||||||
|  | 		{ | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		b3ClothParticleDef pdNew; | ||||||
|  | 		pdNew.type = pOld->GetType(); | ||||||
|  | 		pdNew.position = pOld->GetPosition() - 0.2f * plane.normal; | ||||||
|  |  | ||||||
|  | 		b3ClothParticle* pNew = m_cloth.CreateParticle(pdNew); | ||||||
|  |  | ||||||
|  | 		b3ClothSphereShapeDef ssdNew; | ||||||
|  | 		ssdNew.p = pNew; | ||||||
|  | 		ssdNew.radius = 0.2f; | ||||||
|  | 		ssdNew.friction = 0.4f; | ||||||
|  | 		 | ||||||
|  | 		m_cloth.CreateSphereShape(ssdNew); | ||||||
|  |  | ||||||
|  | 		for (u32 i = 0; i < trianglesBelow.Count(); ++i) | ||||||
|  | 		{ | ||||||
|  | 			b3ClothTriangleShape* triangle = trianglesBelow[i]; | ||||||
|  |  | ||||||
|  | 			b3ClothParticle* p1 = triangle->GetParticle1(); | ||||||
|  | 			b3ClothParticle* p2 = triangle->GetParticle2(); | ||||||
|  | 			b3ClothParticle* p3 = triangle->GetParticle3(); | ||||||
|  |  | ||||||
|  | 			m_cloth.DestroyTriangleShape(triangle); | ||||||
|  |  | ||||||
|  | 			if (p1 == pOld) | ||||||
|  | 			{ | ||||||
|  | 				b3ClothTriangleShapeDef tdNew; | ||||||
|  | 				tdNew.p1 = pNew; | ||||||
|  | 				tdNew.p2 = p2; | ||||||
|  | 				tdNew.p3 = p3; | ||||||
|  | 				tdNew.v1 = pNew->GetPosition(); | ||||||
|  | 				tdNew.v2 = p2->GetPosition(); | ||||||
|  | 				tdNew.v3 = p3->GetPosition(); | ||||||
|  |  | ||||||
|  | 				m_cloth.CreateTriangleShape(tdNew); | ||||||
|  |  | ||||||
|  | 				b3SpringForce* sf1 = FindSpringForce(p1, p2); | ||||||
|  | 				if (sf1) | ||||||
|  | 				{ | ||||||
|  | 					b3SpringForceDef sNew; | ||||||
|  | 					sNew.p1 = pNew; | ||||||
|  | 					sNew.p2 = p2; | ||||||
|  | 					sNew.restLength = sf1->GetRestLenght(); | ||||||
|  | 					sNew.structural = sf1->GetStructuralStiffness(); | ||||||
|  | 					sNew.damping = sf1->GetDampingStiffness(); | ||||||
|  |  | ||||||
|  | 					m_cloth.CreateForce(sNew); | ||||||
|  |  | ||||||
|  | 					if (HasSpring(trianglesAbove, p1, p2) == false) | ||||||
|  | 					{ | ||||||
|  | 						m_cloth.DestroyForce(sf1); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				b3SpringForce* sf2 = FindSpringForce(p3, p1); | ||||||
|  | 				if (sf2) | ||||||
|  | 				{ | ||||||
|  | 					b3SpringForceDef sNew; | ||||||
|  | 					sNew.p1 = p3; | ||||||
|  | 					sNew.p2 = pNew; | ||||||
|  | 					sNew.restLength = sf2->GetRestLenght(); | ||||||
|  | 					sNew.structural = sf2->GetStructuralStiffness(); | ||||||
|  | 					sNew.damping = sf2->GetDampingStiffness(); | ||||||
|  | 					 | ||||||
|  | 					m_cloth.CreateForce(sNew); | ||||||
|  | 					 | ||||||
|  | 					if (HasSpring(trianglesAbove, p3, p1) == false) | ||||||
|  | 					{ | ||||||
|  | 						m_cloth.DestroyForce(sf2); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			if (p2 == pOld) | ||||||
|  | 			{ | ||||||
|  | 				b3ClothTriangleShapeDef tdNew; | ||||||
|  | 				tdNew.p1 = p1; | ||||||
|  | 				tdNew.p2 = pNew; | ||||||
|  | 				tdNew.p3 = p3; | ||||||
|  | 				tdNew.v1 = p1->GetPosition(); | ||||||
|  | 				tdNew.v2 = pNew->GetPosition(); | ||||||
|  | 				tdNew.v3 = p3->GetPosition(); | ||||||
|  |  | ||||||
|  | 				m_cloth.CreateTriangleShape(tdNew); | ||||||
|  |  | ||||||
|  | 				b3SpringForce* sf1 = FindSpringForce(p1, p2); | ||||||
|  | 				if (sf1) | ||||||
|  | 				{ | ||||||
|  | 					b3SpringForceDef sNew; | ||||||
|  | 					sNew.p1 = p1; | ||||||
|  | 					sNew.p2 = pNew; | ||||||
|  | 					sNew.restLength = sf1->GetRestLenght(); | ||||||
|  | 					sNew.structural = sf1->GetStructuralStiffness(); | ||||||
|  | 					sNew.damping = sf1->GetDampingStiffness(); | ||||||
|  |  | ||||||
|  | 					m_cloth.CreateForce(sNew); | ||||||
|  | 					 | ||||||
|  | 					if (HasSpring(trianglesAbove, p1, p2) == false) | ||||||
|  | 					{ | ||||||
|  | 						m_cloth.DestroyForce(sf1); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				b3SpringForce* sf2 = FindSpringForce(p2, p3); | ||||||
|  | 				if (sf2) | ||||||
|  | 				{ | ||||||
|  | 					b3SpringForceDef sNew; | ||||||
|  | 					sNew.p1 = pNew; | ||||||
|  | 					sNew.p2 = p3; | ||||||
|  | 					sNew.restLength = sf2->GetRestLenght(); | ||||||
|  | 					sNew.structural = sf2->GetStructuralStiffness(); | ||||||
|  | 					sNew.damping = sf2->GetDampingStiffness(); | ||||||
|  | 					 | ||||||
|  | 					m_cloth.CreateForce(sNew); | ||||||
|  | 					 | ||||||
|  | 					if (HasSpring(trianglesAbove, p2, p3) == false) | ||||||
|  | 					{ | ||||||
|  | 						m_cloth.DestroyForce(sf2); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			if (p3 == pOld) | ||||||
|  | 			{ | ||||||
|  | 				b3ClothTriangleShapeDef tdNew; | ||||||
|  | 				tdNew.p1 = p1; | ||||||
|  | 				tdNew.p2 = p2; | ||||||
|  | 				tdNew.p3 = pNew; | ||||||
|  | 				tdNew.v1 = p1->GetPosition(); | ||||||
|  | 				tdNew.v2 = p2->GetPosition(); | ||||||
|  | 				tdNew.v3 = pNew->GetPosition(); | ||||||
|  |  | ||||||
|  | 				m_cloth.CreateTriangleShape(tdNew); | ||||||
|  | 				 | ||||||
|  | 				b3SpringForce* sf1 = FindSpringForce(p2, p3); | ||||||
|  | 				if (sf1) | ||||||
|  | 				{ | ||||||
|  | 					b3SpringForceDef sNew; | ||||||
|  | 					sNew.p1 = p2; | ||||||
|  | 					sNew.p2 = pNew; | ||||||
|  | 					sNew.restLength = sf1->GetRestLenght(); | ||||||
|  | 					sNew.structural = sf1->GetStructuralStiffness(); | ||||||
|  | 					sNew.damping = sf1->GetDampingStiffness(); | ||||||
|  | 					 | ||||||
|  | 					m_cloth.CreateForce(sNew); | ||||||
|  | 					 | ||||||
|  | 					if (HasSpring(trianglesAbove, p2, p3) == false) | ||||||
|  | 					{ | ||||||
|  | 						m_cloth.DestroyForce(sf1); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				b3SpringForce* sf2 = FindSpringForce(p3, p1); | ||||||
|  | 				if (sf2) | ||||||
|  | 				{ | ||||||
|  | 					b3SpringForceDef sNew; | ||||||
|  | 					sNew.p1 = pNew; | ||||||
|  | 					sNew.p2 = p1; | ||||||
|  | 					sNew.restLength = sf2->GetRestLenght(); | ||||||
|  | 					sNew.structural = sf2->GetStructuralStiffness(); | ||||||
|  | 					sNew.damping = sf2->GetDampingStiffness(); | ||||||
|  | 					 | ||||||
|  | 					m_cloth.CreateForce(sNew); | ||||||
|  | 					 | ||||||
|  | 					if (HasSpring(trianglesAbove, p3, p1) == false) | ||||||
|  | 					{ | ||||||
|  | 						m_cloth.DestroyForce(sf2); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	bool Tear() | ||||||
|  | 	{ | ||||||
|  | 		b3Force* f = m_cloth.GetForceList().m_head; | ||||||
|  | 		while (f) | ||||||
|  | 		{ | ||||||
|  | 			if (f->GetType() != e_springForce) | ||||||
|  | 			{ | ||||||
|  | 				f = f->GetNext(); | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			b3SpringForce* s = (b3SpringForce*)f; | ||||||
|  | 			f = f->GetNext(); | ||||||
|  |  | ||||||
|  | 			b3Vec3 tension = s->GetActionForce(); | ||||||
|  |  | ||||||
|  | 			const scalar kMaxTension = 1000.0f; | ||||||
|  |  | ||||||
|  | 			if (b3LengthSquared(tension) <= kMaxTension * kMaxTension) | ||||||
|  | 			{ | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			b3ClothParticle* p1 = s->GetParticle1(); | ||||||
|  | 			b3ClothParticle* p2 = s->GetParticle2(); | ||||||
|  |  | ||||||
|  | 			b3Vec3 x1 = p1->GetPosition(); | ||||||
|  | 			b3Vec3 x2 = p2->GetPosition(); | ||||||
|  |  | ||||||
|  | 			if (p1->GetType() == e_dynamicClothParticle) | ||||||
|  | 			{ | ||||||
|  | 				b3Vec3 n = b3Normalize(x2 - x1); | ||||||
|  | 				b3Plane plane(n, x1); | ||||||
|  |  | ||||||
|  | 				bool wasSplit = SplitParticle(p1, plane); | ||||||
|  | 				if (wasSplit) | ||||||
|  | 				{ | ||||||
|  | 					return true; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (p2->GetType() == e_dynamicClothParticle) | ||||||
|  | 			{ | ||||||
|  | 				b3Vec3 n = b3Normalize(x1 - x2); | ||||||
|  | 				b3Plane plane(n, x2); | ||||||
|  |  | ||||||
|  | 				bool wasSplit = SplitParticle(p2, plane); | ||||||
|  | 				if (wasSplit) | ||||||
|  | 				{ | ||||||
|  | 					return true; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void Step() | ||||||
|  | 	{ | ||||||
|  | 		Test::Step(); | ||||||
|  |  | ||||||
|  | 		m_cloth.Step(g_testSettings->inv_hertz, g_testSettings->velocityIterations, g_testSettings->positionIterations); | ||||||
|  |  | ||||||
|  | 		while (Tear()); | ||||||
|  |  | ||||||
|  | 		m_cloth.Draw(); | ||||||
|  |  | ||||||
|  | 		DrawSpringForces(); | ||||||
|  |  | ||||||
|  | 		if (m_clothDragger->IsDragging()) | ||||||
|  | 		{ | ||||||
|  | 			b3Vec3 pA = m_clothDragger->GetPointA(); | ||||||
|  | 			b3Vec3 pB = m_clothDragger->GetPointB(); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawPoint(pA, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawPoint(pB, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawSegment(pA, pB, b3Color_white); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		extern u32 b3_clothSolverIterations; | ||||||
|  | 		g_draw->DrawString(b3Color_white, "Iterations = %d", b3_clothSolverIterations); | ||||||
|  |  | ||||||
|  | 		scalar E = m_cloth.GetEnergy(); | ||||||
|  | 		g_draw->DrawString(b3Color_white, "E = %f", E); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void MouseMove(const b3Ray3& pw) | ||||||
|  | 	{ | ||||||
|  | 		Test::MouseMove(pw); | ||||||
|  |  | ||||||
|  | 		if (m_clothDragger->IsDragging() == true) | ||||||
|  | 		{ | ||||||
|  | 			m_clothDragger->Drag(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void MouseLeftDown(const b3Ray3& pw) | ||||||
|  | 	{ | ||||||
|  | 		Test::MouseLeftDown(pw); | ||||||
|  |  | ||||||
|  | 		if (m_clothDragger->IsDragging() == false) | ||||||
|  | 		{ | ||||||
|  | 			m_clothDragger->StartDragging(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void MouseLeftUp(const b3Ray3& pw) | ||||||
|  | 	{ | ||||||
|  | 		Test::MouseLeftUp(pw); | ||||||
|  |  | ||||||
|  | 		if (m_clothDragger->IsDragging() == true) | ||||||
|  | 		{ | ||||||
|  | 			m_clothDragger->StopDragging(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	static Test* Create() | ||||||
|  | 	{ | ||||||
|  | 		return new ClothTearing(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b3Cloth m_cloth; | ||||||
|  | 	b3ClothDragger* m_clothDragger; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
| @@ -38,9 +38,9 @@ public: | |||||||
| 	{ | 	{ | ||||||
| 		for (u32 i = 0; i < e_count; ++i) | 		for (u32 i = 0; i < e_count; ++i) | ||||||
| 		{ | 		{ | ||||||
| 			float32 x = 3.0f * RandomFloat(-1.0f, 1.0f); | 			scalar x = 3.0f * RandomFloat(-1.0f, 1.0f); | ||||||
| 			float32 y = 3.0f * RandomFloat(-1.0f, 1.0f); | 			scalar y = 3.0f * RandomFloat(-1.0f, 1.0f); | ||||||
| 			float32 z = 3.0f * RandomFloat(-1.0f, 1.0f); | 			scalar z = 3.0f * RandomFloat(-1.0f, 1.0f); | ||||||
|  |  | ||||||
| 			b3Vec3 p(x, y, z); | 			b3Vec3 p(x, y, z); | ||||||
| 			m_points[i] = p; | 			m_points[i] = p; | ||||||
| @@ -48,9 +48,9 @@ public: | |||||||
|  |  | ||||||
| 		for (u32 i = 0; i < B3_MAX_MANIFOLDS; ++i) | 		for (u32 i = 0; i < B3_MAX_MANIFOLDS; ++i) | ||||||
| 		{ | 		{ | ||||||
| 			float32 r = RandomFloat(0.0f, 1.0f); | 			scalar r = RandomFloat(0.0f, 1.0f); | ||||||
| 			float32 g = RandomFloat(0.0f, 1.0f); | 			scalar g = RandomFloat(0.0f, 1.0f); | ||||||
| 			float32 b = RandomFloat(0.0f, 1.0f); | 			scalar b = RandomFloat(0.0f, 1.0f); | ||||||
|  |  | ||||||
| 			b3Color c(r, g, b); | 			b3Color c(r, g, b); | ||||||
| 			m_colors[i] = c; | 			m_colors[i] = c; | ||||||
|   | |||||||
| @@ -68,46 +68,43 @@ public: | |||||||
| 	{ | 	{ | ||||||
| 		if (key == GLFW_KEY_LEFT) | 		if (key == GLFW_KEY_LEFT) | ||||||
| 		{ | 		{ | ||||||
| 			m_xfB.position.x -= 0.05f; | 			m_xfB.translation.x -= 0.05f; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (key == GLFW_KEY_RIGHT) | 		if (key == GLFW_KEY_RIGHT) | ||||||
| 		{ | 		{ | ||||||
| 			m_xfB.position.x += 0.05f; | 			m_xfB.translation.x += 0.05f; | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		if (key == GLFW_KEY_UP) | 		if (key == GLFW_KEY_UP) | ||||||
| 		{ | 		{ | ||||||
| 			m_xfB.position.y += 0.05f; | 			m_xfB.translation.y += 0.05f; | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		if (key == GLFW_KEY_DOWN) | 		if (key == GLFW_KEY_DOWN) | ||||||
| 		{ | 		{ | ||||||
| 			m_xfB.position.y -= 0.05f; | 			m_xfB.translation.y -= 0.05f; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (key == GLFW_KEY_X) | 		if (key == GLFW_KEY_X) | ||||||
| 		{ | 		{ | ||||||
| 			b3Quat qx(b3Vec3(1.0f, 0.0f, 0.0f), 0.05f * B3_PI); | 			b3Quat qx = b3QuatRotationX(0.05f * B3_PI); | ||||||
| 			b3Mat33 xfx = b3QuatMat33(qx); |  | ||||||
|  |  | ||||||
| 			m_xfB.rotation = m_xfB.rotation * xfx; | 			m_xfB.rotation = m_xfB.rotation * qx; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (key == GLFW_KEY_Y) | 		if (key == GLFW_KEY_Y) | ||||||
| 		{ | 		{ | ||||||
| 			b3Quat qy(b3Vec3(0.0f, 1.0f, 0.0f), 0.05f * B3_PI); | 			b3Quat qy = b3QuatRotationY(0.05f * B3_PI); | ||||||
| 			b3Mat33 xfy = b3QuatMat33(qy); |  | ||||||
|  |  | ||||||
| 			m_xfB.rotation = m_xfB.rotation * xfy; | 			m_xfB.rotation = m_xfB.rotation * qy; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (key == GLFW_KEY_Z) | 		if (key == GLFW_KEY_Z) | ||||||
| 		{ | 		{ | ||||||
| 			b3Quat qy(b3Vec3(0.0f, 0.0f, 1.0f), 0.05f * B3_PI); | 			b3Quat qz = b3QuatRotationZ(0.05f * B3_PI); | ||||||
| 			b3Mat33 xfz = b3QuatMat33(qy); |  | ||||||
|  |  | ||||||
| 			m_xfB.rotation = m_xfB.rotation * xfz; | 			m_xfB.rotation = m_xfB.rotation * qz; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -38,38 +38,33 @@ public: | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		{ | 		{ | ||||||
| 			b3Transform xf; | 			m_box1.SetExtents(1.0f, 1.0f, 1.0f); | ||||||
| 			xf.SetIdentity(); | 			b3Vec3 translation(-5.0f, 10.0f, 0.0f); | ||||||
| 			xf.position.Set(-5.0f, 10.0f, 0.0f); | 			m_box1.Translate(translation); | ||||||
| 			m_box1.SetTransform(xf); |  | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		{ | 		{ | ||||||
| 			b3Transform xf; | 			b3Vec3 translation(5.0f, 10.0f, 0.0f); | ||||||
| 			xf.SetIdentity(); | 			m_box2.SetExtents(1.0f, 1.0f, 1.0f); | ||||||
| 			xf.position.Set(5.0f, 10.0f, 0.0f); | 			m_box2.Translate(translation); | ||||||
| 			m_box2.SetTransform(xf); |  | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		{ | 		{ | ||||||
| 			b3Transform xf; | 			b3Vec3 translation(0.0f, 2.0f, 0.0f); | ||||||
| 			xf.SetIdentity(); | 			m_box3.SetExtents(1.0f, 1.0f, 1.0f); | ||||||
| 			xf.position.Set(0.0f, 2.0f, 0.0f); | 			m_box3.Translate(translation); | ||||||
| 			m_box3.SetTransform(xf); |  | ||||||
| 		} | 		} | ||||||
| 		  | 		  | ||||||
| 		{ | 		{ | ||||||
| 			b3Transform xf; | 			b3Vec3 translation(0.0f, 6.0f, 0.0f); | ||||||
| 			xf.SetIdentity(); | 			m_box4.SetExtents(1.0f, 1.0f, 1.0f); | ||||||
| 			xf.position.Set(0.0f, 6.0f, 0.0f); | 			m_box4.Translate(translation); | ||||||
| 			m_box4.SetTransform(xf); |  | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		{ | 		{ | ||||||
| 			b3Transform xf; | 			b3Vec3 translation(0.0f, 10.0f, 0.0f); | ||||||
| 			xf.SetIdentity(); | 			m_box5.SetExtents(1.0f, 1.0f, 1.0f); | ||||||
| 			xf.position.Set(0.0f, 10.0f, 0.0f); | 			m_box5.Translate(translation); | ||||||
| 			m_box5.SetTransform(xf); |  | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		{ | 		{ | ||||||
|   | |||||||
| @@ -42,8 +42,8 @@ public: | |||||||
| 			head = m_world.CreateBody(bd); | 			head = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
| 			b3CapsuleShape cs; | 			b3CapsuleShape cs; | ||||||
| 			cs.m_centers[0].Set(0.0f, 0.15f, 0.0f); | 			cs.m_vertex1.Set(0.0f, 0.15f, 0.0f); | ||||||
| 			cs.m_centers[1].Set(0.0f, -0.15f, 0.0f); | 			cs.m_vertex2.Set(0.0f, -0.15f, 0.0f); | ||||||
| 			cs.m_radius = 0.5f; | 			cs.m_radius = 0.5f; | ||||||
|  |  | ||||||
| 			b3ShapeDef sd; | 			b3ShapeDef sd; | ||||||
| @@ -55,19 +55,22 @@ public: | |||||||
| 		{ | 		{ | ||||||
| 			b3Vec3 anchor(0.0f, 0.0f, 0.0f); | 			b3Vec3 anchor(0.0f, 0.0f, 0.0f); | ||||||
| 			b3Vec3 axis(0.0f, 1.0f, 0.0f); | 			b3Vec3 axis(0.0f, 1.0f, 0.0f); | ||||||
| 			float32 coneAngle = 0.5f * B3_PI; | 			scalar coneAngle = 0.5f * B3_PI; | ||||||
|  |  | ||||||
| 			b3ConeJointDef cd; | 			b3ConeJointDef cd; | ||||||
| 			cd.Initialize(ref, head, axis, anchor, coneAngle); | 			cd.Initialize(ref, head, axis, anchor, coneAngle); | ||||||
| 			cd.enableLimit = true; | 			cd.enableConeLimit = true; | ||||||
|  | 			 | ||||||
|  | 			cd.enableTwistLimit = true; | ||||||
|  | 			cd.lowerAngle = 0.0f; | ||||||
|  | 			cd.upperAngle = B3_PI; | ||||||
|  |  | ||||||
| 			b3ConeJoint* cj = (b3ConeJoint*)m_world.CreateJoint(cd); | 			b3ConeJoint* cj = (b3ConeJoint*)m_world.CreateJoint(cd); | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		// Invalidate the orientation | 		// Invalidate the orientation | ||||||
| 		b3Vec3 axis(1.0f, 0.0f, 0.0f); | 		b3Quat q = b3QuatRotationX(B3_PI); | ||||||
| 		float32 angle = B3_PI; | 		head->SetTransform(head->GetPosition(), q); | ||||||
| 		head->SetTransform(head->GetPosition(), axis, angle); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	static Test* Create() | 	static Test* Create() | ||||||
|   | |||||||
							
								
								
									
										282
									
								
								examples/testbed/tests/convex_cast.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										282
									
								
								examples/testbed/tests/convex_cast.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,282 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * 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 CONVEX_CAST_H | ||||||
|  | #define CONVEX_CAST_H | ||||||
|  |  | ||||||
|  | class ConvexCast : public Test | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	ConvexCast() | ||||||
|  | 	{ | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			b3Body* body = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			b3HullShape hs; | ||||||
|  | 			hs.m_hull = &m_groundHull; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.shape = &hs; | ||||||
|  |  | ||||||
|  | 			b3Shape* shape = body->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.position.Set(0.0f, 2.0f, 0.0f); | ||||||
|  |  | ||||||
|  | 			b3Body* body = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			b3HullShape hs; | ||||||
|  | 			hs.m_hull = &b3BoxHull_identity; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.shape = &hs; | ||||||
|  |  | ||||||
|  | 			m_shape = body->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		{ | ||||||
|  | 			m_grid.BuildTree(); | ||||||
|  | 			m_grid.BuildAdjacency(); | ||||||
|  |  | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.position.Set(-10.0f, 5.0f, -2.0f); | ||||||
|  | 			bdef.orientation = b3QuatRotationZ(0.25f * B3_PI); | ||||||
|  |  | ||||||
|  | 			b3Body* body = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			b3MeshShape hs; | ||||||
|  | 			hs.m_mesh = &m_grid; | ||||||
|  | 			hs.m_scale.Set(-1.0f, -1.0f, -2.0f); | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.shape = &hs; | ||||||
|  |  | ||||||
|  | 			b3Shape* shape = body->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.position.Set(0.0f, 2.0f, 10.0f); | ||||||
|  | 			bdef.orientation = b3QuatRotationY(0.25f * B3_PI); | ||||||
|  |  | ||||||
|  | 			b3Body* body = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			b3HullShape hs; | ||||||
|  | 			hs.m_hull = &b3BoxHull_identity; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.shape = &hs; | ||||||
|  |  | ||||||
|  | 			b3Shape* shape = body->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.position.Set(-10.0f, 6.0f, -10.0f); | ||||||
|  | 			bdef.orientation = b3QuatRotationY(0.25f * B3_PI); | ||||||
|  |  | ||||||
|  | 			b3Body* body = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			static b3BoxHull boxHull(2.0f, 4.0f, 0.5f); | ||||||
|  |  | ||||||
|  | 			b3HullShape hs; | ||||||
|  | 			hs.m_hull = &boxHull; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.shape = &hs; | ||||||
|  |  | ||||||
|  | 			b3Shape* shape = body->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.position.Set(10.0f, 2.0f, 0.0f); | ||||||
|  | 			bdef.orientation = b3QuatRotationY(0.20f * B3_PI); | ||||||
|  |  | ||||||
|  | 			b3Body* body = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			b3HullShape hs; | ||||||
|  | 			hs.m_hull = &b3BoxHull_identity; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.shape = &hs; | ||||||
|  |  | ||||||
|  | 			b3Shape* shape = body->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.position.Set(-10.0f, 2.0f, 14.0f); | ||||||
|  | 			bdef.orientation = b3QuatRotationY(0.05f * B3_PI); | ||||||
|  |  | ||||||
|  | 			b3Body* body = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			b3HullShape hs; | ||||||
|  | 			hs.m_hull = &b3BoxHull_identity; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.shape = &hs; | ||||||
|  |  | ||||||
|  | 			b3Shape* shape = body->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.position.Set(-14.0f, 2.0f, 5.0f); | ||||||
|  | 			bdef.orientation = b3QuatRotationY(-0.05f * B3_PI); | ||||||
|  |  | ||||||
|  | 			b3Body* body = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			b3HullShape hs; | ||||||
|  | 			hs.m_hull = &b3BoxHull_identity; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.shape = &hs; | ||||||
|  |  | ||||||
|  | 			b3Shape* shape = body->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.position.Set(20.0f, 2.0f, 5.0f); | ||||||
|  | 			bdef.orientation = b3QuatRotationY(-0.05f * B3_PI); | ||||||
|  |  | ||||||
|  | 			b3Body* body = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			b3HullShape hs; | ||||||
|  | 			hs.m_hull = &b3BoxHull_identity; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.shape = &hs; | ||||||
|  |  | ||||||
|  | 			b3Shape* shape = body->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.position.Set(12.0f, 2.0f, 5.0f); | ||||||
|  | 			bdef.orientation = b3QuatRotationY(-0.35f * B3_PI); | ||||||
|  |  | ||||||
|  | 			b3Body* body = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			b3SphereShape hs; | ||||||
|  | 			hs.m_center.SetZero(); | ||||||
|  | 			hs.m_radius = 2.5f; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.shape = &hs; | ||||||
|  |  | ||||||
|  | 			b3Shape* shape = body->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.position.Set(0.0f, 1.0f, -12.0f); | ||||||
|  |  | ||||||
|  | 			b3Body* body = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			b3CapsuleShape hs; | ||||||
|  | 			hs.m_vertex1.Set(0.0f, 1.0f, 0.0f); | ||||||
|  | 			hs.m_vertex2.Set(0.0f, -1.0f, 0.0f); | ||||||
|  | 			hs.m_radius = 3.0f; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.shape = &hs; | ||||||
|  |  | ||||||
|  | 			b3Shape* shape = body->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		m_d.Set(-50.0f, 2.0f, 0.0f); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void CastConvex() const | ||||||
|  | 	{ | ||||||
|  | 		class ConvexCastFilter : public b3ConvexCastFilter | ||||||
|  | 		{ | ||||||
|  | 		public: | ||||||
|  | 			bool ShouldConvexCast(b3Shape* shape) | ||||||
|  | 			{ | ||||||
|  | 				return true; | ||||||
|  | 			} | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		ConvexCastFilter filter; | ||||||
|  | 		 | ||||||
|  | 		b3Body* body = m_shape->GetBody(); | ||||||
|  | 		b3Transform xf = body->GetTransform(); | ||||||
|  |  | ||||||
|  | 		m_world.DrawSolidShape(xf, m_shape, b3Color_red); | ||||||
|  |  | ||||||
|  | 		b3Vec3 p1 = xf.translation; | ||||||
|  |  | ||||||
|  | 		b3Vec3 p2 = p1 + m_d; | ||||||
|  | 		 | ||||||
|  | 		b3ConvexCastSingleOutput out; | ||||||
|  | 		if (m_world.ConvexCastSingle(&out, &filter, m_shape, m_d)) | ||||||
|  | 		{ | ||||||
|  | 			g_draw->DrawPoint(out.point, 4.0f, b3Color_red); | ||||||
|  | 			g_draw->DrawSegment(out.point, out.point + out.normal, b3Color_white); | ||||||
|  | 			 | ||||||
|  | 			b3Transform xft; | ||||||
|  | 			xft.rotation = xf.rotation; | ||||||
|  | 			xft.translation = xf.translation + out.fraction * m_d; | ||||||
|  |  | ||||||
|  | 			m_world.DrawShape(xft, m_shape, b3Color_red); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawSegment(p1, xft.translation, b3Color_green); | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			g_draw->DrawSegment(p1, p2, b3Color_green); | ||||||
|  | 			 | ||||||
|  | 			b3Transform xf1; | ||||||
|  | 			xf1.rotation = xf.rotation; | ||||||
|  | 			xf1.translation = xf.translation + m_d; | ||||||
|  | 			 | ||||||
|  | 			m_world.DrawShape(xf1, m_shape, b3Color_red); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void Step() | ||||||
|  | 	{ | ||||||
|  | 		scalar dt = g_testSettings->inv_hertz; | ||||||
|  | 		 | ||||||
|  | 		b3Quat q = b3QuatRotationY(0.05f * B3_PI * dt); | ||||||
|  |  | ||||||
|  | 		m_d = b3Mul(q, m_d); | ||||||
|  | 		 | ||||||
|  | 		CastConvex(); | ||||||
|  |  | ||||||
|  | 		Test::Step(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	static Test* Create() | ||||||
|  | 	{ | ||||||
|  | 		return new ConvexCast(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b3GridMesh<5, 5> m_grid; | ||||||
|  |  | ||||||
|  | 	b3Shape* m_shape; | ||||||
|  | 	b3Vec3 m_d; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
| @@ -66,9 +66,9 @@ public: | |||||||
| 		m_count = 0; | 		m_count = 0; | ||||||
| 		for (u32 i = 0; i < e_count; ++i) | 		for (u32 i = 0; i < e_count; ++i) | ||||||
| 		{ | 		{ | ||||||
| 			float32 x = 3.0f * RandomFloat(-1.0f, 1.0f); | 			float x = 3.0f * RandomFloat(-1.0f, 1.0f); | ||||||
| 			float32 y = 3.0f * RandomFloat(-1.0f, 1.0f); | 			float y = 3.0f * RandomFloat(-1.0f, 1.0f); | ||||||
| 			float32 z = 3.0f * RandomFloat(-1.0f, 1.0f); | 			float z = 3.0f * RandomFloat(-1.0f, 1.0f); | ||||||
| 			 | 			 | ||||||
| 			// Clamp to force coplanarities. | 			// Clamp to force coplanarities. | ||||||
| 			// This will stress the convex hull creation code. | 			// This will stress the convex hull creation code. | ||||||
| @@ -135,7 +135,7 @@ public: | |||||||
| 				edge = m_hull.GetEdge(edge->next); | 				edge = m_hull.GetEdge(edge->next); | ||||||
| 			} while (edge != begin); | 			} while (edge != begin); | ||||||
|  |  | ||||||
| 			c /= float32(vn); | 			c /= scalar(vn); | ||||||
| 			g_draw->DrawSegment(c, c + n, b3Color_white); | 			g_draw->DrawSegment(c, c + n, b3Color_white); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										119
									
								
								examples/testbed/tests/conveyor_belt.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								examples/testbed/tests/conveyor_belt.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,119 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * 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 CONVEYOR_BELT_H | ||||||
|  | #define CONVEYOR_BELT_H | ||||||
|  |  | ||||||
|  | class ConveyorBelt : public Test | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |  | ||||||
|  | 	ConveyorBelt() | ||||||
|  | 	{ | ||||||
|  | 		{ | ||||||
|  | 			// Ground | ||||||
|  | 			b3BodyDef bd; | ||||||
|  | 			b3Body* body = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
|  | 			b3HullShape hs; | ||||||
|  | 			hs.m_hull = &m_groundHull; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sd; | ||||||
|  | 			sd.shape = &hs; | ||||||
|  |  | ||||||
|  | 			body->CreateShape(sd); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			// Platform | ||||||
|  | 			b3BodyDef bd; | ||||||
|  | 			bd.position.Set(0.0f, 5.0f, 0.0f); | ||||||
|  | 			b3Body* body = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
|  | 			m_platformHull.SetExtents(10.0f, 0.5f, 2.0f); | ||||||
|  |  | ||||||
|  | 			b3HullShape hs; | ||||||
|  | 			hs.m_hull = &m_platformHull; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sd; | ||||||
|  | 			sd.shape = &hs; | ||||||
|  | 			sd.friction = 0.8f; | ||||||
|  | 			m_platform = body->CreateShape(sd); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Boxes | ||||||
|  | 		m_boxHull.SetExtents(0.5f, 0.5f, 0.5f); | ||||||
|  | 		for (u32 i = 0; i < 5; ++i) | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bd; | ||||||
|  | 			bd.type = e_dynamicBody; | ||||||
|  | 			bd.position.Set(2.0f * i, 7.0f, 0.0f); | ||||||
|  | 			b3Body* body = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
|  | 			b3HullShape hs; | ||||||
|  | 			hs.m_hull = &m_boxHull; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sd; | ||||||
|  | 			sd.shape = &hs; | ||||||
|  | 			sd.density = 0.2f; | ||||||
|  | 			 | ||||||
|  | 			body->CreateShape(sd); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void PreSolve(b3Contact* contact) | ||||||
|  | 	{ | ||||||
|  | 		Test::PreSolve(contact); | ||||||
|  |  | ||||||
|  | 		b3Shape* shapeA = contact->GetShapeA(); | ||||||
|  | 		b3Shape* shapeB = contact->GetShapeB(); | ||||||
|  |  | ||||||
|  | 		if (shapeA == m_platform) | ||||||
|  | 		{ | ||||||
|  | 			for (u32 i = 0; i < contact->GetManifoldCount(); ++i) | ||||||
|  | 			{ | ||||||
|  | 				b3Manifold* manifold = contact->GetManifold(i); | ||||||
|  |  | ||||||
|  | 				manifold->motorSpeed = 0.25f * B3_PI; | ||||||
|  | 				manifold->tangentSpeed2 = -2.0f; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (shapeB == m_platform) | ||||||
|  | 		{ | ||||||
|  | 			for (u32 i = 0; i < contact->GetManifoldCount(); ++i) | ||||||
|  | 			{ | ||||||
|  | 				b3Manifold* manifold = contact->GetManifold(i); | ||||||
|  |  | ||||||
|  | 				manifold->motorSpeed = -0.25f * B3_PI; | ||||||
|  | 				manifold->tangentSpeed2 = 2.0f; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	static Test* Create() | ||||||
|  | 	{ | ||||||
|  | 		return new ConveyorBelt(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b3BoxHull m_platformHull; | ||||||
|  | 	b3Shape* m_platform; | ||||||
|  | 	b3BoxHull m_boxHull; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
| @@ -24,23 +24,17 @@ class DeepCapsule : public Collide | |||||||
| public: | public: | ||||||
| 	DeepCapsule() | 	DeepCapsule() | ||||||
| 	{ | 	{ | ||||||
| 		m_xfA.position.Set(0.0f, 0.0f, 0.0f); | 		m_box.SetExtents(4.0f, 1.0f, 4.0f); | ||||||
| 		m_xfA.rotation = b3QuatMat33(b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), 0.55f * B3_PI)); | 		m_sA.m_hull = &m_box; | ||||||
|  |  | ||||||
| 		m_sA.m_centers[0].Set(1.0f, -1.0f, 0.0f); | 		m_xfA.SetIdentity(); | ||||||
| 		m_sA.m_centers[1].Set(0.0f, 1.0f, 0.0f); |  | ||||||
| 		m_sA.m_radius = 2.0f; |  | ||||||
|  |  | ||||||
| 		m_xfB.position.Set(0.f, 0.0f, 0.0f); | 		m_sB.m_vertex1.Set(1.0f, -1.0f, 0.0f); | ||||||
| 		m_xfB.rotation = b3QuatMat33(b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), 0.0f * B3_PI)); | 		m_sB.m_vertex2.Set(0.0f, 1.0f, 0.0f); | ||||||
|  | 		m_sB.m_radius = 2.0f; | ||||||
|  |  | ||||||
| 		b3Transform xf; | 		m_xfB.translation.Set(0.0f, 0.0f, 0.0f); | ||||||
| 		xf.SetIdentity(); | 		m_xfB.rotation = b3QuatRotationZ(0.55f * B3_PI); | ||||||
| 		xf.rotation = b3Diagonal(4.0f, 1.0f, 4.0f); |  | ||||||
|  |  | ||||||
| 		m_box.SetTransform(xf); |  | ||||||
|  |  | ||||||
| 		m_sB.m_hull = &m_box; |  | ||||||
|  |  | ||||||
| 		m_shapeA = &m_sA; | 		m_shapeA = &m_sA; | ||||||
| 		m_shapeB = &m_sB; | 		m_shapeB = &m_sB; | ||||||
| @@ -52,8 +46,8 @@ public: | |||||||
| 		return new DeepCapsule(); | 		return new DeepCapsule(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	b3CapsuleShape m_sA; | 	b3HullShape m_sA; | ||||||
| 	b3HullShape m_sB; | 	b3CapsuleShape m_sB; | ||||||
| 	b3BoxHull m_box; | 	b3BoxHull m_box; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -24,15 +24,11 @@ class Distance : public Test | |||||||
| public: | public: | ||||||
| 	Distance() | 	Distance() | ||||||
| 	{	 | 	{	 | ||||||
| 		m_xfA.SetIdentity(); | 		m_xfA.translation.Set(-5.0f, 0.0f, 0.0f); | ||||||
| 		m_xfA.position.Set(-5.0f, 0.0f, 0.0f); |  | ||||||
| 		m_xfA.rotation.SetIdentity(); | 		m_xfA.rotation.SetIdentity(); | ||||||
| 		m_shapeA.m_centers[0].Set(0.0f, -2.0f, 0.0f); | 		m_shapeA.m_hull = &b3BoxHull_identity; | ||||||
| 		m_shapeA.m_centers[1].Set(0.0f, 2.0f, 0.0f); |  | ||||||
| 		m_shapeA.m_radius = 1.0f; |  | ||||||
|  |  | ||||||
| 		m_xfB.SetIdentity(); | 		m_xfB.translation.Set(5.0f, 0.0f, 0.0f); | ||||||
| 		m_xfB.position.Set(5.0f, 0.0f, 0.0f); |  | ||||||
| 		m_xfB.rotation.SetIdentity(); | 		m_xfB.rotation.SetIdentity(); | ||||||
| 		m_shapeB.m_hull = &b3BoxHull_identity; | 		m_shapeB.m_hull = &b3BoxHull_identity; | ||||||
|  |  | ||||||
| @@ -79,46 +75,43 @@ public: | |||||||
| 	{ | 	{ | ||||||
| 		if (key == GLFW_KEY_LEFT) | 		if (key == GLFW_KEY_LEFT) | ||||||
| 		{ | 		{ | ||||||
| 			m_xfB.position.x -= 0.05f; | 			m_xfB.translation.x -= 0.05f; | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		if (key == GLFW_KEY_RIGHT) | 		if (key == GLFW_KEY_RIGHT) | ||||||
| 		{ | 		{ | ||||||
| 			m_xfB.position.x += 0.05f; | 			m_xfB.translation.x += 0.05f; | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		if (key == GLFW_KEY_UP) | 		if (key == GLFW_KEY_UP) | ||||||
| 		{ | 		{ | ||||||
| 			m_xfB.position.y += 0.05f; | 			m_xfB.translation.y += 0.05f; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (key == GLFW_KEY_DOWN) | 		if (key == GLFW_KEY_DOWN) | ||||||
| 		{ | 		{ | ||||||
| 			m_xfB.position.y -= 0.05f; | 			m_xfB.translation.y -= 0.05f; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (key == GLFW_KEY_X) | 		if (key == GLFW_KEY_X) | ||||||
| 		{ | 		{ | ||||||
| 			b3Quat qx(b3Vec3(1.0f, 0.0f, 0.0f), 0.05f * B3_PI); | 			b3Quat qx = b3QuatRotationX(0.05f * B3_PI); | ||||||
| 			b3Mat33 xfx = b3QuatMat33(qx); |  | ||||||
|  |  | ||||||
| 			m_xfB.rotation = m_xfB.rotation * xfx; | 			m_xfB.rotation = m_xfB.rotation * qx; | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		if (key == GLFW_KEY_Y) | 		if (key == GLFW_KEY_Y) | ||||||
| 		{ | 		{ | ||||||
| 			b3Quat qy(b3Vec3(0.0f, 1.0f, 0.0f), 0.05f * B3_PI); | 			b3Quat qy = b3QuatRotationY(0.05f * B3_PI); | ||||||
| 			b3Mat33 xfy = b3QuatMat33(qy); |  | ||||||
|  |  | ||||||
| 			m_xfB.rotation = m_xfB.rotation * xfy; | 			m_xfB.rotation = m_xfB.rotation * qy; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (key == GLFW_KEY_Z) | 		if (key == GLFW_KEY_Z) | ||||||
| 		{ | 		{ | ||||||
| 			b3Quat qy(b3Vec3(0.0f, 0.0f, 1.0f), 0.05f * B3_PI); | 			b3Quat qz = b3QuatRotationZ(0.05f * B3_PI); | ||||||
| 			b3Mat33 xfz = b3QuatMat33(qy); |  | ||||||
|  |  | ||||||
| 			m_xfB.rotation = m_xfB.rotation * xfz; | 			m_xfB.rotation = m_xfB.rotation * qz; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -127,7 +120,7 @@ public: | |||||||
| 		return new Distance(); | 		return new Distance(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	b3CapsuleShape m_shapeA; | 	b3HullShape m_shapeA; | ||||||
| 	b3Transform m_xfA; | 	b3Transform m_xfA; | ||||||
| 	b3ShapeGJKProxy m_proxyA; | 	b3ShapeGJKProxy m_proxyA; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -40,14 +40,14 @@ public: | |||||||
| 		{ | 		{ | ||||||
| 			b3BodyDef bdef; | 			b3BodyDef bdef; | ||||||
| 			bdef.type = e_dynamicBody; | 			bdef.type = e_dynamicBody; | ||||||
| 			bdef.orientation.Set(b3Vec3(1.0f, 0.0f, 0.0f), 0.5f * B3_PI); | 			bdef.orientation.SetAxisAngle(b3Vec3(1.0f, 0.0f, 0.0f), 0.5f * B3_PI); | ||||||
| 			bdef.position.Set(0.0f, 10.0f, 0.0f); | 			bdef.position.Set(0.0f, 10.0f, 0.0f); | ||||||
| 			bdef.angularVelocity.Set(0.0f, 0.0f, 4.0f * B3_PI); | 			bdef.angularVelocity.Set(0.0f, 0.0f, 4.0f * B3_PI); | ||||||
|  |  | ||||||
| 			b3Body* body = m_world.CreateBody(bdef); | 			b3Body* body = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
| 			{ | 			{ | ||||||
| 				m_rotorBox.Set(1.0f, 0.5f, 7.0f); | 				m_rotorBox.SetExtents(1.0f, 0.5f, 7.0f); | ||||||
|  |  | ||||||
| 				b3HullShape hull; | 				b3HullShape hull; | ||||||
| 				hull.m_hull = &m_rotorBox; | 				hull.m_hull = &m_rotorBox; | ||||||
| @@ -60,7 +60,7 @@ public: | |||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			{ | 			{ | ||||||
| 				m_cylinderHull.SetAsCylinder(0.95f, 4.0f); | 				m_cylinderHull.SetExtents(0.95f, 4.0f); | ||||||
|  |  | ||||||
| 				b3HullShape hull; | 				b3HullShape hull; | ||||||
| 				hull.m_hull = &m_cylinderHull; | 				hull.m_hull = &m_cylinderHull; | ||||||
| @@ -86,7 +86,7 @@ public: | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	b3BoxHull m_rotorBox; | 	b3BoxHull m_rotorBox; | ||||||
| 	b3QHull m_cylinderHull; | 	b3CylinderHull m_cylinderHull; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
| @@ -24,16 +24,10 @@ class HingeChain : public Test | |||||||
| public: | public: | ||||||
| 	HingeChain() | 	HingeChain() | ||||||
| 	{ | 	{ | ||||||
| 		static b3BoxHull doorHull; | 		static b3BoxHull box(2.0f, 4.0f, 0.5f); | ||||||
| 		{ |  | ||||||
| 			b3Transform xf; |  | ||||||
| 			xf.position.SetZero(); |  | ||||||
| 			xf.rotation = b3Diagonal(2.0f, 4.0f, 0.5f); |  | ||||||
| 			doorHull.SetTransform(xf); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		float32 x = -50.0f; | 		scalar x = -50.0f; | ||||||
| 		float32 y = 0.0f; | 		scalar y = 0.0f; | ||||||
|  |  | ||||||
| 		b3Body* lastHinge; | 		b3Body* lastHinge; | ||||||
| 		{ | 		{ | ||||||
| @@ -42,7 +36,7 @@ public: | |||||||
| 			lastHinge = m_world.CreateBody(bd); | 			lastHinge = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
| 			b3HullShape hull; | 			b3HullShape hull; | ||||||
| 			hull.m_hull = &doorHull; | 			hull.m_hull = &box; | ||||||
|  |  | ||||||
| 			b3ShapeDef sdef; | 			b3ShapeDef sdef; | ||||||
| 			sdef.shape = &hull; | 			sdef.shape = &hull; | ||||||
| @@ -60,7 +54,7 @@ public: | |||||||
| 			b3Body* hinge = m_world.CreateBody(bd); | 			b3Body* hinge = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
| 			b3HullShape hull; | 			b3HullShape hull; | ||||||
| 			hull.m_hull = &doorHull; | 			hull.m_hull = &box; | ||||||
| 			 | 			 | ||||||
| 			b3ShapeDef sdef; | 			b3ShapeDef sdef; | ||||||
| 			sdef.shape = &hull; | 			sdef.shape = &hull; | ||||||
|   | |||||||
| @@ -29,7 +29,7 @@ public: | |||||||
|  |  | ||||||
| 	HullCollision() | 	HullCollision() | ||||||
| 	{ | 	{ | ||||||
| 		m_xfA.position.Set(0.0f, 1.5f, 0.0f); | 		m_xfA.translation.Set(0.0f, 1.5f, 0.0f); | ||||||
| 		m_xfA.rotation.SetIdentity(); | 		m_xfA.rotation.SetIdentity(); | ||||||
|  |  | ||||||
| 		m_xfB.SetIdentity(); | 		m_xfB.SetIdentity(); | ||||||
| @@ -53,9 +53,9 @@ public: | |||||||
| 	{ | 	{ | ||||||
| 		for (u32 i = 0; i < e_count; ++i) | 		for (u32 i = 0; i < e_count; ++i) | ||||||
| 		{ | 		{ | ||||||
| 			float32 x = 3.0f * RandomFloat(-1.0f, 1.0f); | 			float x = 3.0f * RandomFloat(-1.0f, 1.0f); | ||||||
| 			float32 y = 3.0f * RandomFloat(-1.0f, 1.0f); | 			float y = 3.0f * RandomFloat(-1.0f, 1.0f); | ||||||
| 			float32 z = 3.0f * RandomFloat(-1.0f, 1.0f); | 			float z = 3.0f * RandomFloat(-1.0f, 1.0f); | ||||||
|  |  | ||||||
| 			x = b3Clamp(x, -2.5f, 2.5f); | 			x = b3Clamp(x, -2.5f, 2.5f); | ||||||
| 			y = b3Clamp(y, -2.5f, 2.5f); | 			y = b3Clamp(y, -2.5f, 2.5f); | ||||||
| @@ -68,9 +68,9 @@ public: | |||||||
|  |  | ||||||
| 		for (u32 i = 0; i < e_count; ++i) | 		for (u32 i = 0; i < e_count; ++i) | ||||||
| 		{ | 		{ | ||||||
| 			float32 x = 3.0f * RandomFloat(-1.0f, 1.0f); | 			float x = 3.0f * RandomFloat(-1.0f, 1.0f); | ||||||
| 			float32 y = 3.0f * RandomFloat(-1.0f, 1.0f); | 			float y = 3.0f * RandomFloat(-1.0f, 1.0f); | ||||||
| 			float32 z = 3.0f * RandomFloat(-1.0f, 1.0f); | 			float z = 3.0f * RandomFloat(-1.0f, 1.0f); | ||||||
|  |  | ||||||
| 			x = b3Clamp(x, -2.5f, 2.5f); | 			x = b3Clamp(x, -2.5f, 2.5f); | ||||||
| 			y = b3Clamp(y, -2.5f, 2.5f); | 			y = b3Clamp(y, -2.5f, 2.5f); | ||||||
| @@ -98,7 +98,7 @@ public: | |||||||
| 		sB.m_hull = &hull2; | 		sB.m_hull = &hull2; | ||||||
| 		m_shapeB = &sB; | 		m_shapeB = &sB; | ||||||
|  |  | ||||||
| 		g_draw->DrawString(b3Color_white, "G - Generate a random convex hull pair"); | 		g_draw->DrawString(b3Color_white, "G - Generate random convex hulls"); | ||||||
| 		 | 		 | ||||||
| 		Collide::Step(); | 		Collide::Step(); | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -53,9 +53,9 @@ public: | |||||||
| 			{ | 			{ | ||||||
| 				// Clamp to force coplanarities. | 				// Clamp to force coplanarities. | ||||||
| 				// This will stress the generation code. | 				// This will stress the generation code. | ||||||
| 				float32 x = 3.0f * RandomFloat(-1.0f, 1.0f); | 				float x = 3.0f * RandomFloat(-1.0f, 1.0f); | ||||||
| 				float32 y = 3.0f * RandomFloat(-1.0f, 1.0f); | 				float y = 3.0f * RandomFloat(-1.0f, 1.0f); | ||||||
| 				float32 z = 3.0f * RandomFloat(-1.0f, 1.0f); | 				float z = 3.0f * RandomFloat(-1.0f, 1.0f); | ||||||
|  |  | ||||||
| 				x = b3Clamp(x, -1.5f, 1.5f); | 				x = b3Clamp(x, -1.5f, 1.5f); | ||||||
| 				y = b3Clamp(y, -1.5f, 1.5f); | 				y = b3Clamp(y, -1.5f, 1.5f); | ||||||
|   | |||||||
| @@ -38,14 +38,7 @@ public: | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		b3Vec3 boxScale(1.0f, 0.5f, 2.0f); | 		b3Vec3 boxScale(1.0f, 0.5f, 2.0f); | ||||||
|  | 		static b3BoxHull boxHull(boxScale.x, boxScale.y, boxScale.z); | ||||||
| 		static b3BoxHull boxHull; |  | ||||||
|  |  | ||||||
| 		b3Transform m; |  | ||||||
| 		m.rotation = b3Diagonal(boxScale.x, boxScale.y, boxScale.z); |  | ||||||
| 		m.position.SetZero(); |  | ||||||
|  |  | ||||||
| 		boxHull.SetTransform(m); |  | ||||||
|  |  | ||||||
| 		{ | 		{ | ||||||
| 			b3BodyDef bd; | 			b3BodyDef bd; | ||||||
| @@ -70,8 +63,8 @@ public: | |||||||
| 			bd.type = e_dynamicBody; | 			bd.type = e_dynamicBody; | ||||||
| 			bd.position.Set(0.0f, 1.5f, 0.0f); | 			bd.position.Set(0.0f, 1.5f, 0.0f); | ||||||
|  |  | ||||||
| 			b3Quat q_y(b3Vec3(0.0f, 1.0f, 0.0f), 0.4f * B3_PI); | 			b3Quat q_y = b3QuatRotationY(0.4f * B3_PI); | ||||||
| 			b3Quat q_z(b3Vec3(0.0f, 0.0f, 1.0f), 0.04f * B3_PI); | 			b3Quat q_z = b3QuatRotationZ(0.04f * B3_PI); | ||||||
| 			b3Quat q = q_z * q_y; | 			b3Quat q = q_z * q_y; | ||||||
|  |  | ||||||
| 			bd.orientation = q; | 			bd.orientation = q; | ||||||
|   | |||||||
| @@ -45,15 +45,9 @@ public: | |||||||
|  |  | ||||||
| 		b3Vec3 boxScale(1.0f, 0.5f, 3.0f); | 		b3Vec3 boxScale(1.0f, 0.5f, 3.0f); | ||||||
|  |  | ||||||
| 		static b3BoxHull boxHull; | 		static b3BoxHull boxHull(boxScale.x, boxScale.y, boxScale.z); | ||||||
|  |  | ||||||
| 		b3Transform m; | 		scalar y = 2.0f; | ||||||
| 		m.rotation = b3Diagonal(boxScale.x, boxScale.y, boxScale.z); |  | ||||||
| 		m.position.SetZero(); |  | ||||||
|  |  | ||||||
| 		boxHull.SetTransform(m); |  | ||||||
|  |  | ||||||
| 		float32 y = 2.0f; |  | ||||||
|  |  | ||||||
| 		for (u32 i = 0; i < e_layerCount / 2; ++i) | 		for (u32 i = 0; i < e_layerCount / 2; ++i) | ||||||
| 		{ | 		{ | ||||||
| @@ -62,7 +56,7 @@ public: | |||||||
| 				b3BodyDef bd; | 				b3BodyDef bd; | ||||||
| 				bd.type = b3BodyType::e_dynamicBody; | 				bd.type = b3BodyType::e_dynamicBody; | ||||||
|  |  | ||||||
| 				bd.position.x = 2.0f * float32(j) * boxScale.x; | 				bd.position.x = 2.0f * scalar(j) * boxScale.x; | ||||||
| 				bd.position.y = y; | 				bd.position.y = y; | ||||||
| 				bd.position.z = 0.0f; | 				bd.position.z = 0.0f; | ||||||
| 				 | 				 | ||||||
| @@ -86,11 +80,11 @@ public: | |||||||
| 				b3BodyDef bd; | 				b3BodyDef bd; | ||||||
| 				bd.type = b3BodyType::e_dynamicBody; | 				bd.type = b3BodyType::e_dynamicBody; | ||||||
|  |  | ||||||
| 				bd.orientation.Set(b3Vec3(0.0f, 1.0f, 0.0f), 0.5f * B3_PI); | 				bd.orientation = b3QuatRotationY(0.5f * B3_PI); | ||||||
|  |  | ||||||
| 				bd.position.x = 2.0f * boxScale.x; | 				bd.position.x = 2.0f * boxScale.x; | ||||||
| 				bd.position.y = y; | 				bd.position.y = y; | ||||||
| 				bd.position.z = -2.0f * boxScale.x + 2.0f * float32(j) * boxScale.x; | 				bd.position.z = -2.0f * boxScale.x + 2.0f * scalar(j) * boxScale.x; | ||||||
| 				 | 				 | ||||||
| 				b3Body* body = m_world.CreateBody(bd); | 				b3Body* body = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -34,8 +34,8 @@ public: | |||||||
| 		m_body = m_world.CreateBody(bdef); | 		m_body = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
| 		b3CapsuleShape shape; | 		b3CapsuleShape shape; | ||||||
| 		shape.m_centers[0].Set(0.0f, 1.0f, 0.0f); | 		shape.m_vertex1.Set(0.0f, 1.0f, 0.0f); | ||||||
| 		shape.m_centers[1].Set(0.0f, -1.0f, 0.0f); | 		shape.m_vertex2.Set(0.0f, -1.0f, 0.0f); | ||||||
| 		shape.m_radius = 1.0f; | 		shape.m_radius = 1.0f; | ||||||
|  |  | ||||||
| 		b3ShapeDef sdef; | 		b3ShapeDef sdef; | ||||||
| @@ -55,16 +55,11 @@ public: | |||||||
| 	{ | 	{ | ||||||
| 		Test::Step(); | 		Test::Step(); | ||||||
|  |  | ||||||
| 		b3Vec3 q(0.0f, 0.0f, 0.0f); | 		b3Vec3 p(0.0f, 0.0f, 0.0f); | ||||||
| 		b3Vec3 p = m_body->GetTransform().position; | 		if (b3Distance(m_body->GetPosition(), p) > 50.0f) | ||||||
| 		if (b3Distance(p, q) > 50.0f) |  | ||||||
| 		{ | 		{ | ||||||
| 			b3Quat quat = m_body->GetSweep().orientation; | 			b3Quat q = m_body->GetOrientation(); | ||||||
|  | 			m_body->SetTransform(p, q); | ||||||
| 			b3Vec3 axis; |  | ||||||
| 			float32 angle; |  | ||||||
| 			quat.GetAxisAngle(&axis, &angle); |  | ||||||
| 			m_body->SetTransform(q, axis, angle); |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										171
									
								
								examples/testbed/tests/linear_time_of_impact.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								examples/testbed/tests/linear_time_of_impact.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,171 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * 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 LINEAR_TIME_OF_IMPACT_H | ||||||
|  | #define LINEAR_TIME_OF_IMPACT_H | ||||||
|  |  | ||||||
|  | class LinearTimeOfImpact : public Test | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	LinearTimeOfImpact() | ||||||
|  | 	{ | ||||||
|  | 		m_shapeA.m_hull = &b3BoxHull_identity; | ||||||
|  | 		m_shapeA.m_radius = 0.0f; | ||||||
|  |  | ||||||
|  | 		m_shapeB.m_hull = &b3BoxHull_identity; | ||||||
|  | 		m_shapeB.m_radius = 0.0f; | ||||||
|  |  | ||||||
|  | 		m_xfA.translation.Set(0.0f, 0.0f, 0.0f); | ||||||
|  | 		m_xfA.rotation.SetIdentity(); | ||||||
|  |  | ||||||
|  | 		m_xfB.translation.Set(5.0f, 1.0f, 0.0f); | ||||||
|  | 		m_xfB.rotation.SetIdentity(); | ||||||
|  | 		 | ||||||
|  | 		m_proxyA.Set(&m_shapeA, 0); | ||||||
|  | 		m_proxyB.Set(&m_shapeB, 0); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void Step() | ||||||
|  | 	{ | ||||||
|  | 		b3Vec3 dA = b3Vec3_zero; | ||||||
|  | 		b3Vec3 dB(-10.0f, 0.0f, 0.0f); | ||||||
|  | 		 | ||||||
|  | 		b3TOIOutput out = b3TimeOfImpact(m_xfA, m_proxyA, dA, m_xfB, m_proxyB, dB); | ||||||
|  |  | ||||||
|  | 		b3TOIOutput::State state = out.state; | ||||||
|  | 		scalar t = out.t; | ||||||
|  | 		u32 iterations = out.iterations; | ||||||
|  |  | ||||||
|  | 		if (state == b3TOIOutput::e_touching) | ||||||
|  | 		{ | ||||||
|  | 			b3Transform xfA; | ||||||
|  | 			xfA.rotation = m_xfA.rotation; | ||||||
|  | 			xfA.translation = m_xfA.translation + t * dA; | ||||||
|  |  | ||||||
|  | 			b3Transform xfB; | ||||||
|  | 			xfB.rotation = m_xfB.rotation; | ||||||
|  | 			xfB.translation = m_xfB.translation + t * dB; | ||||||
|  |  | ||||||
|  | 			b3GJKOutput query = b3GJK(xfA, m_proxyA, xfB, m_proxyB, false); | ||||||
|  | 			 | ||||||
|  | 			b3Vec3 p1 = query.point1; | ||||||
|  | 			b3Vec3 p2 = query.point2; | ||||||
|  | 			b3Vec3 n1 = b3Normalize(p2 - p1); | ||||||
|  | 			b3Vec3 p = 0.5f * (p1 + p2); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawPoint(p, 4.0f, b3Color_green); | ||||||
|  | 			g_draw->DrawSegment(p1, p1 + n1, b3Color_green); | ||||||
|  |  | ||||||
|  | 			m_world.DrawShape(xfA, &m_shapeA, b3Color_black); | ||||||
|  | 			m_world.DrawShape(xfB, &m_shapeB, b3Color_black); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		if (state == b3TOIOutput::e_failed) | ||||||
|  | 		{ | ||||||
|  | 			g_draw->DrawString(b3Color_white, "State = Failed"); | ||||||
|  | 		} | ||||||
|  | 		else if (state == b3TOIOutput::e_overlapped) | ||||||
|  | 		{ | ||||||
|  | 			g_draw->DrawString(b3Color_white, "State = Overlapped"); | ||||||
|  | 		} | ||||||
|  | 		else if (state == b3TOIOutput::e_separated) | ||||||
|  | 		{ | ||||||
|  | 			g_draw->DrawString(b3Color_white, "State = Separated!"); | ||||||
|  | 		} | ||||||
|  | 		else if (state == b3TOIOutput::e_touching) | ||||||
|  | 		{ | ||||||
|  | 			g_draw->DrawString(b3Color_white, "State = Touching!"); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		g_draw->DrawString(b3Color_white, "Iterations = %d", out.iterations); | ||||||
|  |  | ||||||
|  | 		g_draw->DrawString(b3Color_white, "Left/Right/Up/Down Arrow - Translate shape"); | ||||||
|  | 		g_draw->DrawString(b3Color_white, "X/Y/Z - Rotate shape"); | ||||||
|  |  | ||||||
|  | 		g_draw->DrawTransform(m_xfA); | ||||||
|  | 		g_draw->DrawTransform(m_xfB); | ||||||
|  |  | ||||||
|  | 		m_world.DrawShape(m_xfA, &m_shapeA, b3Color_black); | ||||||
|  | 		m_world.DrawShape(m_xfB, &m_shapeB, b3Color_black); | ||||||
|  |  | ||||||
|  | 		m_world.DrawSolidShape(m_xfA, &m_shapeA, b3Color_white); | ||||||
|  | 		m_world.DrawSolidShape(m_xfB, &m_shapeB, b3Color_white); | ||||||
|  |  | ||||||
|  | 		g_draw->DrawSegment(m_xfA.translation, m_xfA.translation + dA, b3Color_white); | ||||||
|  | 		g_draw->DrawSegment(m_xfB.translation, m_xfB.translation + dB, b3Color_white); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void KeyDown(int key) | ||||||
|  | 	{ | ||||||
|  | 		if (key == GLFW_KEY_LEFT) | ||||||
|  | 		{ | ||||||
|  | 			m_xfB.translation.x -= 0.105f; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_RIGHT) | ||||||
|  | 		{ | ||||||
|  | 			m_xfB.translation.x += 0.105f; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_UP) | ||||||
|  | 		{ | ||||||
|  | 			m_xfB.translation.y += 0.105f; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_DOWN) | ||||||
|  | 		{ | ||||||
|  | 			m_xfB.translation.y -= 0.105f; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_X) | ||||||
|  | 		{ | ||||||
|  | 			b3Quat qx = b3QuatRotationX(0.05f * B3_PI); | ||||||
|  |  | ||||||
|  | 			m_xfB.rotation = m_xfB.rotation * qx; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_Y) | ||||||
|  | 		{ | ||||||
|  | 			b3Quat qy = b3QuatRotationY(0.05f * B3_PI); | ||||||
|  |  | ||||||
|  | 			m_xfB.rotation = m_xfB.rotation * qy; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_Z) | ||||||
|  | 		{ | ||||||
|  | 			b3Quat qz = b3QuatRotationZ(0.05f * B3_PI); | ||||||
|  |  | ||||||
|  | 			m_xfB.rotation = m_xfB.rotation * qz; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	static Test* Create() | ||||||
|  | 	{ | ||||||
|  | 		return new LinearTimeOfImpact(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b3HullShape m_shapeA; | ||||||
|  | 	b3Transform m_xfA; | ||||||
|  | 	b3ShapeGJKProxy m_proxyA; | ||||||
|  |  | ||||||
|  | 	b3HullShape m_shapeB; | ||||||
|  | 	b3Transform m_xfB; | ||||||
|  | 	b3ShapeGJKProxy m_proxyB; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
| @@ -25,6 +25,7 @@ public: | |||||||
| 	MeshContactTest() | 	MeshContactTest() | ||||||
| 	{ | 	{ | ||||||
| 		m_gridMesh.BuildTree(); | 		m_gridMesh.BuildTree(); | ||||||
|  | 		m_gridMesh.BuildAdjacency(); | ||||||
|  |  | ||||||
| 		// Transform grid into a terrain | 		// Transform grid into a terrain | ||||||
| 		for (u32 i = 0; i < m_terrainMesh.vertexCount; ++i) | 		for (u32 i = 0; i < m_terrainMesh.vertexCount; ++i) | ||||||
| @@ -33,18 +34,22 @@ public: | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		m_terrainMesh.BuildTree(); | 		m_terrainMesh.BuildTree(); | ||||||
|  | 		m_terrainMesh.BuildAdjacency(); | ||||||
|  |  | ||||||
| 		{ | 		{ | ||||||
| 			b3BodyDef bd; | 			b3BodyDef bd; | ||||||
| 			m_ground = m_world.CreateBody(bd); | 			b3Body* groundBody = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
| 			b3MeshShape ms; | 			b3MeshShape ms; | ||||||
| 			ms.m_mesh = &m_gridMesh; | 			ms.m_mesh = &m_gridMesh; | ||||||
|  | 			ms.m_scale.Set(2.0f, 1.0f, 2.0f); | ||||||
|  |  | ||||||
| 			b3ShapeDef sd; | 			b3ShapeDef sd; | ||||||
| 			sd.shape = &ms; | 			sd.shape = &ms; | ||||||
|  |  | ||||||
| 			m_ground->CreateShape(sd); | 			m_groundShape = (b3MeshShape*)groundBody->CreateShape(sd); | ||||||
|  | 			 | ||||||
|  | 			m_selection = m_groundShape->m_mesh->triangleCount / 2; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		{ | 		{ | ||||||
| @@ -52,7 +57,7 @@ public: | |||||||
| 			bd.type = b3BodyType::e_dynamicBody; | 			bd.type = b3BodyType::e_dynamicBody; | ||||||
| 			bd.position.Set(0.0f, 5.0f, 0.0f); | 			bd.position.Set(0.0f, 5.0f, 0.0f); | ||||||
|  |  | ||||||
| 			m_body = m_world.CreateBody(bd); | 			b3Body* body = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
| 			{ | 			{ | ||||||
| 				b3SphereShape sphere; | 				b3SphereShape sphere; | ||||||
| @@ -64,25 +69,43 @@ public: | |||||||
| 				sd.density = 1.0f; | 				sd.density = 1.0f; | ||||||
| 				sd.friction = 0.5f; | 				sd.friction = 0.5f; | ||||||
|  |  | ||||||
| 				m_body->CreateShape(sd); | 				m_bodyShape = body->CreateShape(sd); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		m_drawEdgeTypes = true; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	void KeyDown(int key) | 	void KeyDown(int key) | ||||||
| 	{ | 	{ | ||||||
|  | 		u32 minSelection = 0; | ||||||
|  | 		if (key == GLFW_KEY_LEFT) | ||||||
|  | 		{ | ||||||
|  | 			m_selection = m_selection == minSelection ? minSelection : m_selection - 1; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		u32 maxSelection = m_groundShape->m_mesh->triangleCount - 1; | ||||||
|  | 		if (key == GLFW_KEY_RIGHT) | ||||||
|  | 		{ | ||||||
|  | 			m_selection = m_selection == maxSelection ? maxSelection : m_selection + 1; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_E) | ||||||
|  | 		{ | ||||||
|  | 			m_drawEdgeTypes = !m_drawEdgeTypes; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		if (key == GLFW_KEY_S || key == GLFW_KEY_C || key == GLFW_KEY_H) | 		if (key == GLFW_KEY_S || key == GLFW_KEY_C || key == GLFW_KEY_H) | ||||||
| 		{ | 		{ | ||||||
| 			if (m_body) | 			b3Body* body = m_bodyShape->GetBody(); | ||||||
| 			{ |  | ||||||
| 				m_world.DestroyBody(m_body); | 			m_world.DestroyBody(body); | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			b3BodyDef bd; | 			b3BodyDef bd; | ||||||
| 			bd.type = b3BodyType::e_dynamicBody; | 			bd.type = b3BodyType::e_dynamicBody; | ||||||
| 			bd.position.Set(0.0f, 5.0f, 0.0f); | 			bd.position.Set(0.0f, 5.0f, 0.0f); | ||||||
|  |  | ||||||
| 			m_body = m_world.CreateBody(bd); | 			body = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
| 			if (key == GLFW_KEY_S) | 			if (key == GLFW_KEY_S) | ||||||
| 			{ | 			{ | ||||||
| @@ -95,14 +118,14 @@ public: | |||||||
| 				sd.density = 1.0f; | 				sd.density = 1.0f; | ||||||
| 				sd.friction = 0.5f; | 				sd.friction = 0.5f; | ||||||
|  |  | ||||||
| 				m_body->CreateShape(sd); | 				m_bodyShape = body->CreateShape(sd); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			if (key == GLFW_KEY_C) | 			if (key == GLFW_KEY_C) | ||||||
| 			{ | 			{ | ||||||
| 				b3CapsuleShape capsule; | 				b3CapsuleShape capsule; | ||||||
| 				capsule.m_centers[0].Set(0.0f, -1.0f, 0.0f); | 				capsule.m_vertex1.Set(0.0f, -1.0f, 0.0f); | ||||||
| 				capsule.m_centers[1].Set(0.0f, 1.0f, 0.0f); | 				capsule.m_vertex2.Set(0.0f, 1.0f, 0.0f); | ||||||
| 				capsule.m_radius = 1.0f; | 				capsule.m_radius = 1.0f; | ||||||
|  |  | ||||||
| 				b3ShapeDef sd; | 				b3ShapeDef sd; | ||||||
| @@ -110,7 +133,7 @@ public: | |||||||
| 				sd.density = 1.0f; | 				sd.density = 1.0f; | ||||||
| 				sd.friction = 0.5f; | 				sd.friction = 0.5f; | ||||||
|  |  | ||||||
| 				m_body->CreateShape(sd); | 				m_bodyShape = body->CreateShape(sd); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			if (key == GLFW_KEY_H) | 			if (key == GLFW_KEY_H) | ||||||
| @@ -123,41 +146,43 @@ public: | |||||||
| 				sd.density = 1.0f; | 				sd.density = 1.0f; | ||||||
| 				sd.friction = 0.5f; | 				sd.friction = 0.5f; | ||||||
|  |  | ||||||
| 				m_body->CreateShape(sd); | 				m_bodyShape = body->CreateShape(sd); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (key == GLFW_KEY_G || key == GLFW_KEY_T) | 		if (key == GLFW_KEY_G || key == GLFW_KEY_T) | ||||||
| 		{ | 		{ | ||||||
| 			if (m_ground) | 			b3Body* groundBody = m_groundShape->GetBody(); | ||||||
| 			{ | 			m_world.DestroyBody(groundBody); | ||||||
| 				m_world.DestroyBody(m_ground); |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			b3BodyDef bd; | 			b3BodyDef bd; | ||||||
| 			m_ground = m_world.CreateBody(bd); | 			groundBody = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
| 			if (key == GLFW_KEY_G) | 			if (key == GLFW_KEY_G) | ||||||
| 			{ | 			{ | ||||||
| 				b3MeshShape ms; | 				b3MeshShape ms; | ||||||
| 				ms.m_mesh = &m_gridMesh; | 				ms.m_mesh = &m_gridMesh; | ||||||
|  | 				ms.m_scale.Set(2.0f, 1.0f, 2.0f); | ||||||
|  |  | ||||||
| 				b3ShapeDef sd; | 				b3ShapeDef sd; | ||||||
| 				sd.shape = &ms; | 				sd.shape = &ms; | ||||||
|  |  | ||||||
| 				m_ground->CreateShape(sd); | 				m_groundShape = (b3MeshShape*)groundBody->CreateShape(sd); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			if (key == GLFW_KEY_T) | 			if (key == GLFW_KEY_T) | ||||||
| 			{ | 			{ | ||||||
| 				b3MeshShape ms; | 				b3MeshShape ms; | ||||||
| 				ms.m_mesh = &m_terrainMesh; | 				ms.m_mesh = &m_terrainMesh; | ||||||
|  | 				ms.m_scale.Set(2.0f, 1.5f, 2.0f); | ||||||
|  |  | ||||||
| 				b3ShapeDef sd; | 				b3ShapeDef sd; | ||||||
| 				sd.shape = &ms; | 				sd.shape = &ms; | ||||||
|  |  | ||||||
| 				m_ground->CreateShape(sd); | 				m_groundShape = (b3MeshShape*)groundBody->CreateShape(sd); | ||||||
| 			} | 			} | ||||||
|  | 			 | ||||||
|  | 			m_selection = m_groundShape->m_mesh->triangleCount / 2; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -165,6 +190,108 @@ public: | |||||||
| 	{ | 	{ | ||||||
| 		Test::Step(); | 		Test::Step(); | ||||||
|  |  | ||||||
|  | 		const b3Mesh* mesh = m_groundShape->m_mesh; | ||||||
|  | 		b3Vec3 scale = m_groundShape->m_scale; | ||||||
|  | 		b3Body* body = m_groundShape->GetBody(); | ||||||
|  | 		b3Transform xf = body->GetTransform(); | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			const b3MeshTriangle* triangle = mesh->triangles + m_selection; | ||||||
|  | 			const b3MeshTriangleWings* triangleWings = mesh->triangleWings + m_selection; | ||||||
|  |  | ||||||
|  | 			for (u32 i = 0; i < 3; ++i) | ||||||
|  | 			{ | ||||||
|  | 				u32 j = i + 1 < 3 ? i + 1 : 0; | ||||||
|  |  | ||||||
|  | 				u32 v1 = triangle->GetVertex(i); | ||||||
|  | 				u32 v2 = triangle->GetVertex(j); | ||||||
|  |  | ||||||
|  | 				b3Vec3 p1 = xf * b3MulCW(scale, mesh->vertices[v1]); | ||||||
|  | 				b3Vec3 p2 = xf * b3MulCW(scale, mesh->vertices[v2]); | ||||||
|  |  | ||||||
|  | 				b3Vec3 center = scalar(0.5) * (p1 + p2); | ||||||
|  | 				g_draw->DrawString(b3Color_white, center, "e%d", i); | ||||||
|  |  | ||||||
|  | 				u32 wingVertex = triangleWings->GetVertex(i); | ||||||
|  |  | ||||||
|  | 				if (wingVertex != B3_NULL_VERTEX) | ||||||
|  | 				{ | ||||||
|  | 					b3Vec3 vertex = xf * b3MulCW(scale, mesh->vertices[wingVertex]); | ||||||
|  | 					g_draw->DrawString(b3Color_white, vertex, "u%d", i); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (m_drawEdgeTypes) | ||||||
|  | 		{ | ||||||
|  | 			b3Vec3 eyePoint(0.0f, 10.0f, 0.0f); | ||||||
|  |  | ||||||
|  | 			for (u32 i = 0; i < mesh->triangleCount; ++i) | ||||||
|  | 			{ | ||||||
|  | 				b3MeshTriangle* triangle = mesh->triangles + i; | ||||||
|  | 				b3MeshTriangleWings* triangleWings = mesh->triangleWings + i; | ||||||
|  |  | ||||||
|  | 				b3Vec3 A = xf * b3MulCW(scale, mesh->vertices[triangle->v1]); | ||||||
|  | 				b3Vec3 B = xf * b3MulCW(scale, mesh->vertices[triangle->v2]); | ||||||
|  | 				b3Vec3 C = xf * b3MulCW(scale, mesh->vertices[triangle->v3]); | ||||||
|  |  | ||||||
|  | 				b3Vec3 N = b3Cross(B - A, C - A); | ||||||
|  | 				N.Normalize(); | ||||||
|  |  | ||||||
|  | 				b3Plane plane(N, A); | ||||||
|  | 				if (b3Distance(eyePoint, plane) < 0.0f) | ||||||
|  | 				{ | ||||||
|  | 					plane = b3Plane(-N, A); | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				for (u32 j = 0; j < 3; ++j) | ||||||
|  | 				{ | ||||||
|  | 					u32 k = j + 1 < 3 ? j + 1 : 0; | ||||||
|  |  | ||||||
|  | 					u32 v1 = triangle->GetVertex(j); | ||||||
|  | 					u32 v2 = triangle->GetVertex(k); | ||||||
|  |  | ||||||
|  | 					u32 u = triangleWings->GetVertex(j); | ||||||
|  |  | ||||||
|  | 					b3Vec3 p1 = xf * b3MulCW(scale, mesh->vertices[v1]); | ||||||
|  | 					b3Vec3 p2 = xf * b3MulCW(scale, mesh->vertices[v2]); | ||||||
|  |  | ||||||
|  | 					b3Vec3 center = scalar(0.5) * (p1 + p2); | ||||||
|  |  | ||||||
|  | 					if (u == B3_NULL_VERTEX) | ||||||
|  | 					{ | ||||||
|  | 						g_draw->DrawPoint(center, scalar(4), b3Color_white); | ||||||
|  | 						continue; | ||||||
|  | 					} | ||||||
|  |  | ||||||
|  | 					b3Vec3 wingVertex = xf * b3MulCW(scale, mesh->vertices[u]); | ||||||
|  |  | ||||||
|  | 					scalar d = b3Distance(wingVertex, plane); | ||||||
|  |  | ||||||
|  | 					const scalar kCoplanarTol = 0.005f; | ||||||
|  |  | ||||||
|  | 					if (d < -kCoplanarTol) | ||||||
|  | 					{ | ||||||
|  | 						// Below <=> Convex | ||||||
|  | 						g_draw->DrawPoint(center, scalar(4), b3Color_green); | ||||||
|  | 					} | ||||||
|  | 					else if (d > kCoplanarTol) | ||||||
|  | 					{ | ||||||
|  | 						// Above <=> Concave | ||||||
|  | 						g_draw->DrawPoint(center, scalar(4), b3Color_yellow); | ||||||
|  | 					} | ||||||
|  | 					else | ||||||
|  | 					{ | ||||||
|  | 						// d > -e && d < e | ||||||
|  | 						// On <=> Coplanar | ||||||
|  | 						g_draw->DrawPoint(center, scalar(4), b3Color_red); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		g_draw->DrawString(b3Color_white, "E - View Edge Types"); | ||||||
|  | 		g_draw->DrawString(b3Color_white, "Arrows - Select Face Wings"); | ||||||
| 		g_draw->DrawString(b3Color_white, "S - Sphere"); | 		g_draw->DrawString(b3Color_white, "S - Sphere"); | ||||||
| 		g_draw->DrawString(b3Color_white, "C - Capsule"); | 		g_draw->DrawString(b3Color_white, "C - Capsule"); | ||||||
| 		g_draw->DrawString(b3Color_white, "H - Hull"); | 		g_draw->DrawString(b3Color_white, "H - Hull"); | ||||||
| @@ -177,11 +304,14 @@ public: | |||||||
| 		return new MeshContactTest(); | 		return new MeshContactTest(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	bool m_drawEdgeTypes; | ||||||
|  | 	u32 m_selection; | ||||||
|  |  | ||||||
| 	b3GridMesh<25, 25> m_terrainMesh; | 	b3GridMesh<25, 25> m_terrainMesh; | ||||||
| 	b3GridMesh<25, 25> m_gridMesh; | 	b3GridMesh<25, 25> m_gridMesh; | ||||||
|  |  | ||||||
| 	b3Body* m_ground; | 	b3MeshShape* m_groundShape; | ||||||
| 	b3Body* m_body; | 	b3Shape* m_bodyShape; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
							
								
								
									
										123
									
								
								examples/testbed/tests/motor_test.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								examples/testbed/tests/motor_test.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,123 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * 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 MOTOR_TEST_H | ||||||
|  | #define MOTOR_TEST_H | ||||||
|  |  | ||||||
|  | class MotorTest : public Test | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |  | ||||||
|  | 	MotorTest() | ||||||
|  | 	{ | ||||||
|  | 		b3Body* ground = nullptr; | ||||||
|  | 		{ | ||||||
|  | 			// Ground | ||||||
|  | 			b3BodyDef bd; | ||||||
|  | 			ground = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
|  | 			b3HullShape hs; | ||||||
|  | 			hs.m_hull = &m_groundHull; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sd; | ||||||
|  | 			sd.shape = &hs; | ||||||
|  |  | ||||||
|  | 			ground->CreateShape(sd); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			// Motorized body | ||||||
|  | 			b3BodyDef bd; | ||||||
|  | 			bd.type = e_dynamicBody; | ||||||
|  | 			bd.position.Set(0.0f, 8.0f, 0.0f); | ||||||
|  | 			b3Body* body = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
|  | 			m_boxHull.SetExtents(2.0f, 0.5f, 0.5f); | ||||||
|  |  | ||||||
|  | 			b3HullShape shape; | ||||||
|  | 			shape.m_hull = &m_boxHull; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sd; | ||||||
|  | 			sd.shape = &shape; | ||||||
|  | 			sd.friction = 0.3f; | ||||||
|  | 			sd.density = 2.0f; | ||||||
|  | 			body->CreateShape(sd); | ||||||
|  |  | ||||||
|  | 			b3MotorJointDef mjd; | ||||||
|  | 			mjd.Initialize(ground, body); | ||||||
|  | 			mjd.maxForce = 1000.0f; | ||||||
|  | 			mjd.maxTorque = 1000.0f; | ||||||
|  | 			m_joint = (b3MotorJoint*)m_world.CreateJoint(mjd); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		m_play = false; | ||||||
|  | 		m_x = 0.0f; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	void KeyDown(int key) | ||||||
|  | 	{ | ||||||
|  | 		if (key == GLFW_KEY_S) | ||||||
|  | 		{ | ||||||
|  | 			m_play = !m_play; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void Step() | ||||||
|  | 	{ | ||||||
|  | 		if (m_play) | ||||||
|  | 		{ | ||||||
|  | 			m_x += g_testSettings->inv_hertz; | ||||||
|  |  | ||||||
|  | 			if (m_x >= 2.0f * B3_PI) | ||||||
|  | 			{ | ||||||
|  | 				m_x = 0.0f; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		b3Vec3 linearOffset; | ||||||
|  | 		linearOffset.x = 8.0f * sinf(2.0f * m_x); | ||||||
|  | 		linearOffset.y = 8.0f + sinf(m_x); | ||||||
|  | 		linearOffset.z = 0.0f; | ||||||
|  |  | ||||||
|  | 		m_joint->SetLinearOffset(linearOffset); | ||||||
|  |  | ||||||
|  | 		b3Quat angularOffset; | ||||||
|  | 		angularOffset.SetAxisAngle(b3Vec3_z, m_x); | ||||||
|  | 		angularOffset.Normalize(); | ||||||
|  |  | ||||||
|  | 		m_joint->SetAngularOffset(angularOffset); | ||||||
|  |  | ||||||
|  | 		Test::Step(); | ||||||
|  |  | ||||||
|  | 		g_draw->DrawPoint(linearOffset, 4.0f, b3Color(0.9f, 0.9f, 0.9f)); | ||||||
|  |  | ||||||
|  | 		g_draw->DrawString(b3Color_white, "S - Play/Pause"); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	static Test* Create() | ||||||
|  | 	{ | ||||||
|  | 		return new MotorTest(); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	b3BoxHull m_boxHull; | ||||||
|  | 	b3MotorJoint* m_joint; | ||||||
|  | 	bool m_play; | ||||||
|  | 	scalar m_x; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
| @@ -39,8 +39,8 @@ public: | |||||||
| 			bs[1] = m_world.CreateBody(bd); | 			bs[1] = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
| 			b3CapsuleShape s; | 			b3CapsuleShape s; | ||||||
| 			s.m_centers[0].Set(0.5f, 0.0f, 0.0f); | 			s.m_vertex1.Set(0.5f, 0.0f, 0.0f); | ||||||
| 			s.m_centers[1].Set(-0.5f, 0.0f, 0.0f); | 			s.m_vertex2.Set(-0.5f, 0.0f, 0.0f); | ||||||
| 			s.m_radius = 0.05f; | 			s.m_radius = 0.05f; | ||||||
|  |  | ||||||
| 			b3ShapeDef sd; | 			b3ShapeDef sd; | ||||||
| @@ -60,8 +60,8 @@ public: | |||||||
| 			bs[2] = m_world.CreateBody(bd); | 			bs[2] = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
| 			b3CapsuleShape s; | 			b3CapsuleShape s; | ||||||
| 			s.m_centers[0].Set(0.5f, 0.0f, 0.0f); | 			s.m_vertex1.Set(0.5f, 0.0f, 0.0f); | ||||||
| 			s.m_centers[1].Set(-0.5f, 0.0f, 0.0f); | 			s.m_vertex2.Set(-0.5f, 0.0f, 0.0f); | ||||||
| 			s.m_radius = 0.05f; | 			s.m_radius = 0.05f; | ||||||
|  |  | ||||||
| 			b3ShapeDef sd; | 			b3ShapeDef sd; | ||||||
| @@ -81,8 +81,8 @@ public: | |||||||
| 			bs[3] = m_world.CreateBody(bd); | 			bs[3] = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
| 			b3CapsuleShape s; | 			b3CapsuleShape s; | ||||||
| 			s.m_centers[0].Set(0.5f, 0.0f, 0.0f); | 			s.m_vertex1.Set(0.5f, 0.0f, 0.0f); | ||||||
| 			s.m_centers[1].Set(-0.5f, 0.0f, 0.0f); | 			s.m_vertex2.Set(-0.5f, 0.0f, 0.0f); | ||||||
| 			s.m_radius = 0.05f; | 			s.m_radius = 0.05f; | ||||||
|  |  | ||||||
| 			b3ShapeDef sd; | 			b3ShapeDef sd; | ||||||
| @@ -102,8 +102,8 @@ public: | |||||||
| 			bs[4] = m_world.CreateBody(bd); | 			bs[4] = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
| 			b3CapsuleShape s; | 			b3CapsuleShape s; | ||||||
| 			s.m_centers[0].Set(0.5f, 0.0f, 0.0f); | 			s.m_vertex1.Set(0.5f, 0.0f, 0.0f); | ||||||
| 			s.m_centers[1].Set(-0.5f, 0.0f, 0.0f); | 			s.m_vertex2.Set(-0.5f, 0.0f, 0.0f); | ||||||
| 			s.m_radius = 0.05f; | 			s.m_radius = 0.05f; | ||||||
|  |  | ||||||
| 			b3ShapeDef sd; | 			b3ShapeDef sd; | ||||||
| @@ -123,8 +123,8 @@ public: | |||||||
| 			bs[5] = m_world.CreateBody(bd); | 			bs[5] = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
| 			b3CapsuleShape s; | 			b3CapsuleShape s; | ||||||
| 			s.m_centers[0].Set(0.5f, 0.0f, 0.0f); | 			s.m_vertex1.Set(0.5f, 0.0f, 0.0f); | ||||||
| 			s.m_centers[1].Set(-0.5f, 0.0f, 0.0f); | 			s.m_vertex2.Set(-0.5f, 0.0f, 0.0f); | ||||||
| 			s.m_radius = 0.05f; | 			s.m_radius = 0.05f; | ||||||
|  |  | ||||||
| 			b3ShapeDef sd; | 			b3ShapeDef sd; | ||||||
|   | |||||||
| @@ -38,15 +38,15 @@ public: | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		b3CapsuleShape edge; | 		b3CapsuleShape edge; | ||||||
| 		edge.m_centers[0].Set(0.0f, -10.0f, 0.0f); | 		edge.m_vertex1.Set(0.0f, -10.0f, 0.0f); | ||||||
| 		edge.m_centers[1].Set(0.0f, 10.0f, 0.0f); | 		edge.m_vertex2.Set(0.0f, 10.0f, 0.0f); | ||||||
| 		edge.m_radius = 0.5f; | 		edge.m_radius = 0.5f; | ||||||
|  |  | ||||||
| 		b3Body* frame1, *frame2; | 		b3Body* frame1, *frame2; | ||||||
|  |  | ||||||
| 		{ | 		{ | ||||||
| 			b3BodyDef bd; | 			b3BodyDef bd; | ||||||
| 			bd.orientation = b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), 0.5f * B3_PI); | 			bd.orientation = b3QuatRotationZ(0.5f * B3_PI); | ||||||
| 			bd.position.Set(0.0f, 10.0f, -5.0f); | 			bd.position.Set(0.0f, 10.0f, -5.0f); | ||||||
|  |  | ||||||
| 			frame1 = m_world.CreateBody(bd); | 			frame1 = m_world.CreateBody(bd); | ||||||
| @@ -59,7 +59,7 @@ public: | |||||||
|  |  | ||||||
| 		{ | 		{ | ||||||
| 			b3BodyDef bd; | 			b3BodyDef bd; | ||||||
| 			bd.orientation = b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), 0.5f * B3_PI); | 			bd.orientation = b3QuatRotationZ(0.5f * B3_PI); | ||||||
| 			bd.position.Set(0.0f, 10.0f, 5.0f); | 			bd.position.Set(0.0f, 10.0f, 5.0f); | ||||||
|  |  | ||||||
| 			frame2 = m_world.CreateBody(bd); | 			frame2 = m_world.CreateBody(bd); | ||||||
|   | |||||||
							
								
								
									
										222
									
								
								examples/testbed/tests/node_types.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										222
									
								
								examples/testbed/tests/node_types.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,222 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * 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 NODE_TYPES_H | ||||||
|  | #define NODE_TYPES_H | ||||||
|  |  | ||||||
|  | class NodeTypes : public Test | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	enum | ||||||
|  | 	{ | ||||||
|  | 		e_w = 5, | ||||||
|  | 		e_h = 2, | ||||||
|  | 		e_d = 2 | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	NodeTypes() | ||||||
|  | 	{ | ||||||
|  | 		// Create soft body | ||||||
|  | 		b3SoftBodyDef def; | ||||||
|  | 		def.mesh = &m_mesh; | ||||||
|  | 		def.density = 0.2f; | ||||||
|  | 		def.E = 1000.0f; | ||||||
|  | 		def.nu = 0.33f; | ||||||
|  | 		def.radius = 0.2f; | ||||||
|  | 		def.friction = 0.6f; | ||||||
|  |  | ||||||
|  | 		m_body = new b3SoftBody(def); | ||||||
|  |  | ||||||
|  | 		b3Vec3 gravity(0.0f, -9.8f, 0.0f); | ||||||
|  | 		m_body->SetGravity(gravity); | ||||||
|  |  | ||||||
|  | 		for (u32 i = 0; i < e_h + 1; ++i) | ||||||
|  | 		{ | ||||||
|  | 			for (u32 k = 0; k < e_d + 1; ++k) | ||||||
|  | 			{ | ||||||
|  | 				u32 v = m_mesh.GetVertex(i, 0, k); | ||||||
|  |  | ||||||
|  | 				b3SoftBodyNode* n = m_body->GetNode(v); | ||||||
|  | 				n->SetType(e_staticSoftBodyNode); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		m_bodyDragger = new b3SoftBodyDragger(&m_ray, m_body); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	~NodeTypes() | ||||||
|  | 	{ | ||||||
|  | 		delete m_bodyDragger; | ||||||
|  | 		delete m_body; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void Step() | ||||||
|  | 	{ | ||||||
|  | 		Test::Step(); | ||||||
|  |  | ||||||
|  | 		if (m_bodyDragger->IsDragging()) | ||||||
|  | 		{ | ||||||
|  | 			m_bodyDragger->Drag(); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		m_body->Step(g_testSettings->inv_hertz, g_testSettings->velocityIterations, g_testSettings->positionIterations); | ||||||
|  |  | ||||||
|  | 		m_body->Draw(); | ||||||
|  |  | ||||||
|  | 		if (m_bodyDragger->IsDragging()) | ||||||
|  | 		{ | ||||||
|  | 			b3Vec3 pA = m_bodyDragger->GetPointA(); | ||||||
|  | 			b3Vec3 pB = m_bodyDragger->GetPointB(); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawPoint(pA, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawPoint(pB, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawSegment(pA, pB, b3Color_white); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		extern u32 b3_softBodySolverIterations; | ||||||
|  | 		g_draw->DrawString(b3Color_white, "Iterations = %d", b3_softBodySolverIterations); | ||||||
|  |  | ||||||
|  | 		scalar E = m_body->GetEnergy(); | ||||||
|  | 		g_draw->DrawString(b3Color_white, "E = %f", E); | ||||||
|  |  | ||||||
|  | 		g_draw->DrawString(b3Color_white, "S - Static"); | ||||||
|  | 		g_draw->DrawString(b3Color_white, "D - Dynamic"); | ||||||
|  | 		g_draw->DrawString(b3Color_white, "K - Kinematic"); | ||||||
|  | 		g_draw->DrawString(b3Color_white, "Arrows - Apply Force/Velocity/Position"); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void MouseLeftDown(const b3Ray3& pw) | ||||||
|  | 	{ | ||||||
|  | 		Test::MouseLeftDown(pw); | ||||||
|  |  | ||||||
|  | 		if (m_bodyDragger->IsDragging() == false) | ||||||
|  | 		{ | ||||||
|  | 			m_bodyDragger->StartDragging(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void MouseLeftUp(const b3Ray3& pw) | ||||||
|  | 	{ | ||||||
|  | 		Test::MouseLeftUp(pw); | ||||||
|  |  | ||||||
|  | 		if (m_bodyDragger->IsDragging() == true) | ||||||
|  | 		{ | ||||||
|  | 			m_bodyDragger->StopDragging(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void SetBodyType(b3SoftBodyNodeType type) | ||||||
|  | 	{ | ||||||
|  | 		for (u32 i = 0; i < e_h + 1; ++i) | ||||||
|  | 		{ | ||||||
|  | 			for (u32 k = 0; k < e_d + 1; ++k) | ||||||
|  | 			{ | ||||||
|  | 				u32 v = m_mesh.GetVertex(i, 0, k); | ||||||
|  |  | ||||||
|  | 				b3SoftBodyNode* n = m_body->GetNode(v); | ||||||
|  | 				n->SetType(type); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void KeyDown(int button) | ||||||
|  | 	{ | ||||||
|  | 		if (button == GLFW_KEY_S) | ||||||
|  | 		{ | ||||||
|  | 			SetBodyType(e_staticSoftBodyNode); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (button == GLFW_KEY_K) | ||||||
|  | 		{ | ||||||
|  | 			SetBodyType(e_kinematicSoftBodyNode); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (button == GLFW_KEY_D) | ||||||
|  | 		{ | ||||||
|  | 			SetBodyType(e_dynamicSoftBodyNode); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		for (u32 i = 0; i < m_mesh.vertexCount; ++i) | ||||||
|  | 		{ | ||||||
|  | 			b3SoftBodyNode* n = m_body->GetNode(i); | ||||||
|  |  | ||||||
|  | 			b3Vec3 d; | ||||||
|  | 			d.SetZero(); | ||||||
|  |  | ||||||
|  | 			if (button == GLFW_KEY_LEFT) | ||||||
|  | 			{ | ||||||
|  | 				d.x = -1.0f; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (button == GLFW_KEY_RIGHT) | ||||||
|  | 			{ | ||||||
|  | 				d.x = 1.0f; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (button == GLFW_KEY_UP) | ||||||
|  | 			{ | ||||||
|  | 				d.y = 1.0f; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (button == GLFW_KEY_DOWN) | ||||||
|  | 			{ | ||||||
|  | 				d.y = -1.0f; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (button == GLFW_KEY_LEFT || | ||||||
|  | 				button == GLFW_KEY_RIGHT || | ||||||
|  | 				button == GLFW_KEY_UP || | ||||||
|  | 				button == GLFW_KEY_DOWN) | ||||||
|  | 			{ | ||||||
|  | 				if (n->GetType() == e_staticSoftBodyNode) | ||||||
|  | 				{ | ||||||
|  | 					n->ApplyTranslation(d); | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				if (n->GetType() == e_kinematicSoftBodyNode) | ||||||
|  | 				{ | ||||||
|  | 					b3Vec3 v = n->GetVelocity(); | ||||||
|  |  | ||||||
|  | 					v += 5.0f * d; | ||||||
|  |  | ||||||
|  | 					n->SetVelocity(v); | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				if (n->GetType() == e_dynamicSoftBodyNode) | ||||||
|  | 				{ | ||||||
|  | 					b3Vec3 f = 100.0f * d; | ||||||
|  |  | ||||||
|  | 					n->ApplyForce(f); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	static Test* Create() | ||||||
|  | 	{ | ||||||
|  | 		return new NodeTypes(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b3BlockSoftBodyMesh<e_w, e_h, e_d> m_mesh; | ||||||
|  | 	b3SoftBody* m_body; | ||||||
|  | 	b3SoftBodyDragger* m_bodyDragger; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
| @@ -36,10 +36,21 @@ public: | |||||||
| 		g_draw->DrawString(b3Color_white, "Arrows - Apply Force/Velocity/Position"); | 		g_draw->DrawString(b3Color_white, "Arrows - Apply Force/Velocity/Position"); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	void SetClothType(b3ParticleType type) | 	void SetClothType(b3ClothParticleType type) | ||||||
| 	{ | 	{ | ||||||
| 		for (b3Particle* p = m_cloth->GetParticleList().m_head; p; p = p->GetNext()) | 		for (u32 j = 0; j < e_w + 1; ++j) | ||||||
| 		{ | 		{ | ||||||
|  | 			u32 v = m_clothMesh.GetVertex(0, j); | ||||||
|  |  | ||||||
|  | 			b3ClothParticle* p = m_cloth->GetParticle(v); | ||||||
|  | 			p->SetType(type); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		for (u32 j = 0; j < e_w + 1; ++j) | ||||||
|  | 		{ | ||||||
|  | 			u32 v = m_clothMesh.GetVertex(e_h, j); | ||||||
|  |  | ||||||
|  | 			b3ClothParticle* p = m_cloth->GetParticle(v); | ||||||
| 			p->SetType(type); | 			p->SetType(type); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -48,20 +59,20 @@ public: | |||||||
| 	{ | 	{ | ||||||
| 		if (button == GLFW_KEY_S) | 		if (button == GLFW_KEY_S) | ||||||
| 		{ | 		{ | ||||||
| 			SetClothType(e_staticParticle); | 			SetClothType(e_staticClothParticle); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (button == GLFW_KEY_K) | 		if (button == GLFW_KEY_K) | ||||||
| 		{ | 		{ | ||||||
| 			SetClothType(e_kinematicParticle); | 			SetClothType(e_kinematicClothParticle); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (button == GLFW_KEY_D) | 		if (button == GLFW_KEY_D) | ||||||
| 		{ | 		{ | ||||||
| 			SetClothType(e_dynamicParticle); | 			SetClothType(e_dynamicClothParticle); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		for (b3Particle* p = m_cloth->GetParticleList().m_head; p; p = p->GetNext()) | 		for (b3ClothParticle* p = m_cloth->GetParticleList().m_head; p; p = p->GetNext()) | ||||||
| 		{ | 		{ | ||||||
| 			b3Vec3 d; | 			b3Vec3 d; | ||||||
| 			d.SetZero(); | 			d.SetZero(); | ||||||
| @@ -91,12 +102,12 @@ public: | |||||||
| 				button == GLFW_KEY_UP || | 				button == GLFW_KEY_UP || | ||||||
| 				button == GLFW_KEY_DOWN) | 				button == GLFW_KEY_DOWN) | ||||||
| 			{ | 			{ | ||||||
| 				if (p->GetType() == e_staticParticle) | 				if (p->GetType() == e_staticClothParticle) | ||||||
| 				{ | 				{ | ||||||
| 					p->ApplyTranslation(d); | 					p->ApplyTranslation(d); | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
| 				if (p->GetType() == e_kinematicParticle) | 				if (p->GetType() == e_kinematicClothParticle) | ||||||
| 				{ | 				{ | ||||||
| 					b3Vec3 v = p->GetVelocity(); | 					b3Vec3 v = p->GetVelocity(); | ||||||
|  |  | ||||||
| @@ -105,7 +116,7 @@ public: | |||||||
| 					p->SetVelocity(v); | 					p->SetVelocity(v); | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
| 				if (p->GetType() == e_dynamicParticle) | 				if (p->GetType() == e_dynamicClothParticle) | ||||||
| 				{ | 				{ | ||||||
| 					b3Vec3 f = 100.0f * d; | 					b3Vec3 f = 100.0f * d; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -22,6 +22,12 @@ | |||||||
| class PinnedCloth : public Test | class PinnedCloth : public Test | ||||||
| { | { | ||||||
| public: | public: | ||||||
|  | 	enum | ||||||
|  | 	{ | ||||||
|  | 		e_w = 10, | ||||||
|  | 		e_h = 10 | ||||||
|  | 	}; | ||||||
|  |  | ||||||
| 	PinnedCloth() | 	PinnedCloth() | ||||||
| 	{ | 	{ | ||||||
| 		// Create cloth | 		// Create cloth | ||||||
| @@ -33,28 +39,22 @@ public: | |||||||
| 		m_cloth = new b3Cloth(def); | 		m_cloth = new b3Cloth(def); | ||||||
|  |  | ||||||
| 		m_cloth->SetGravity(b3Vec3(0.0f, -9.8f, 0.0f)); | 		m_cloth->SetGravity(b3Vec3(0.0f, -9.8f, 0.0f)); | ||||||
| 		m_cloth->SetWorld(&m_world); |  | ||||||
|  |  | ||||||
| 		// Freeze some particles | 		// Freeze some particles | ||||||
| 		b3AABB3 aabb1; | 		for (u32 j = 0; j < e_w + 1; ++j) | ||||||
| 		aabb1.m_lower.Set(-5.0f, -1.0f, -6.0f); |  | ||||||
| 		aabb1.m_upper.Set(5.0f, 1.0f, -4.0f); |  | ||||||
|  |  | ||||||
| 		b3AABB3 aabb2; |  | ||||||
| 		aabb2.m_lower.Set(-5.0f, -1.0f, 4.0f); |  | ||||||
| 		aabb2.m_upper.Set(5.0f, 1.0f, 6.0f); |  | ||||||
|  |  | ||||||
| 		for (b3Particle* p = m_cloth->GetParticleList().m_head; p; p = p->GetNext()) |  | ||||||
| 		{ | 		{ | ||||||
| 			if (aabb1.Contains(p->GetPosition())) | 			u32 v = m_clothMesh.GetVertex(0, j); | ||||||
| 			{ |  | ||||||
| 				p->SetType(e_staticParticle); | 			b3ClothParticle* p = m_cloth->GetParticle(v); | ||||||
|  | 			p->SetType(e_staticClothParticle); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 			if (aabb2.Contains(p->GetPosition())) | 		for (u32 j = 0; j < e_w + 1; ++j) | ||||||
| 		{ | 		{ | ||||||
| 				p->SetType(e_staticParticle); | 			u32 v = m_clothMesh.GetVertex(e_h, j); | ||||||
| 			} |  | ||||||
|  | 			b3ClothParticle* p = m_cloth->GetParticle(v); | ||||||
|  | 			p->SetType(e_staticClothParticle); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		m_clothDragger = new b3ClothDragger(&m_ray, m_cloth); | 		m_clothDragger = new b3ClothDragger(&m_ray, m_cloth); | ||||||
| @@ -79,9 +79,9 @@ public: | |||||||
| 			b3Vec3 pA = m_clothDragger->GetPointA(); | 			b3Vec3 pA = m_clothDragger->GetPointA(); | ||||||
| 			b3Vec3 pB = m_clothDragger->GetPointB(); | 			b3Vec3 pB = m_clothDragger->GetPointB(); | ||||||
|  |  | ||||||
| 			g_draw->DrawPoint(pA, 2.0f, b3Color_green); | 			g_draw->DrawPoint(pA, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
| 			g_draw->DrawPoint(pB, 2.0f, b3Color_green); | 			g_draw->DrawPoint(pB, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
| 			g_draw->DrawSegment(pA, pB, b3Color_white); | 			g_draw->DrawSegment(pA, pB, b3Color_white); | ||||||
| 		} | 		} | ||||||
| @@ -89,7 +89,7 @@ public: | |||||||
| 		extern u32 b3_clothSolverIterations; | 		extern u32 b3_clothSolverIterations; | ||||||
| 		g_draw->DrawString(b3Color_white, "Iterations = %d", b3_clothSolverIterations); | 		g_draw->DrawString(b3Color_white, "Iterations = %d", b3_clothSolverIterations); | ||||||
|  |  | ||||||
| 		float32 E = m_cloth->GetEnergy(); | 		scalar E = m_cloth->GetEnergy(); | ||||||
| 		g_draw->DrawString(b3Color_white, "E = %f", E); | 		g_draw->DrawString(b3Color_white, "E = %f", E); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -128,7 +128,7 @@ public: | |||||||
| 		return new PinnedCloth(); | 		return new PinnedCloth(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	b3GridClothMesh<10, 10> m_clothMesh; | 	b3GridClothMesh<e_w, e_h> m_clothMesh; | ||||||
| 	b3Cloth* m_cloth; | 	b3Cloth* m_cloth; | ||||||
| 	b3ClothDragger* m_clothDragger; | 	b3ClothDragger* m_clothDragger; | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -19,14 +19,12 @@ | |||||||
| #ifndef PINNED_SOFTBODY_H | #ifndef PINNED_SOFTBODY_H | ||||||
| #define PINNED_SOFTBODY_H | #define PINNED_SOFTBODY_H | ||||||
|  |  | ||||||
| #include <testbed/framework/softbody_dragger.h> |  | ||||||
|  |  | ||||||
| class PinnedSoftBody : public Test | class PinnedSoftBody : public Test | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	PinnedSoftBody() | 	PinnedSoftBody() | ||||||
| 	{ | 	{ | ||||||
| 		m_mesh.SetAsSphere(5.0f, 0); | 		m_mesh.SetAsSphere(4.0f, 0); | ||||||
|  |  | ||||||
| 		// Create soft body | 		// Create soft body | ||||||
| 		b3SoftBodyDef def; | 		b3SoftBodyDef def; | ||||||
| @@ -37,20 +35,15 @@ public: | |||||||
| 		def.c_yield = 0.1f; | 		def.c_yield = 0.1f; | ||||||
| 		def.c_creep = 0.5f; | 		def.c_creep = 0.5f; | ||||||
| 		def.c_max = 1.0f; | 		def.c_max = 1.0f; | ||||||
|  | 		def.massDamping = 0.2f; | ||||||
|  |  | ||||||
| 		m_body = new b3SoftBody(def); | 		m_body = new b3SoftBody(def); | ||||||
|  |  | ||||||
| 		for (u32 i = 0; i < m_mesh.vertexCount; ++i) |  | ||||||
| 		{ |  | ||||||
| 			b3SoftBodyNode* n = m_body->GetVertexNode(i); |  | ||||||
| 			n->SetMassDamping(0.2f); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		u32 pinIndex = ~0; | 		u32 pinIndex = ~0; | ||||||
| 		float32 pinDot = -B3_MAX_FLOAT; | 		scalar pinDot = -B3_MAX_SCALAR; | ||||||
| 		for (u32 i = 0; i < m_mesh.vertexCount; ++i) | 		for (u32 i = 0; i < m_mesh.vertexCount; ++i) | ||||||
| 		{ | 		{ | ||||||
| 			float32 dot = b3Dot(m_mesh.vertices[i], b3Vec3_y); | 			scalar dot = b3Dot(m_mesh.vertices[i], b3Vec3_y); | ||||||
| 			if (dot > pinDot) | 			if (dot > pinDot) | ||||||
| 			{ | 			{ | ||||||
| 				pinDot = dot; | 				pinDot = dot; | ||||||
| @@ -58,7 +51,7 @@ public: | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		b3SoftBodyNode* pinNode = m_body->GetVertexNode(pinIndex); | 		b3SoftBodyNode* pinNode = m_body->GetNode(pinIndex); | ||||||
| 		pinNode->SetType(e_staticSoftBodyNode); | 		pinNode->SetType(e_staticSoftBodyNode); | ||||||
|  |  | ||||||
| 		b3Vec3 gravity(0.0f, -9.8f, 0.0f); | 		b3Vec3 gravity(0.0f, -9.8f, 0.0f); | ||||||
| @@ -91,9 +84,9 @@ public: | |||||||
| 			b3Vec3 pA = m_bodyDragger->GetPointA(); | 			b3Vec3 pA = m_bodyDragger->GetPointA(); | ||||||
| 			b3Vec3 pB = m_bodyDragger->GetPointB(); | 			b3Vec3 pB = m_bodyDragger->GetPointB(); | ||||||
|  |  | ||||||
| 			g_draw->DrawPoint(pA, 2.0f, b3Color_green); | 			g_draw->DrawPoint(pA, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
| 			g_draw->DrawPoint(pB, 2.0f, b3Color_green); | 			g_draw->DrawPoint(pB, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
| 			g_draw->DrawSegment(pA, pB, b3Color_white); | 			g_draw->DrawSegment(pA, pB, b3Color_white); | ||||||
| 		} | 		} | ||||||
| @@ -101,7 +94,7 @@ public: | |||||||
| 		extern u32 b3_softBodySolverIterations; | 		extern u32 b3_softBodySolverIterations; | ||||||
| 		g_draw->DrawString(b3Color_white, "Iterations = %d", b3_softBodySolverIterations); | 		g_draw->DrawString(b3Color_white, "Iterations = %d", b3_softBodySolverIterations); | ||||||
|  |  | ||||||
| 		float32 E = m_body->GetEnergy(); | 		scalar E = m_body->GetEnergy(); | ||||||
| 		g_draw->DrawString(b3Color_white, "E = %f", E); | 		g_draw->DrawString(b3Color_white, "E = %f", E); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										135
									
								
								examples/testbed/tests/prismatic_test.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								examples/testbed/tests/prismatic_test.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,135 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * 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 PRISMATIC_TEST_H | ||||||
|  | #define PRISMATIC_TEST_H | ||||||
|  |  | ||||||
|  | class PrismaticTest : public Test | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	PrismaticTest() | ||||||
|  | 	{ | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bd; | ||||||
|  | 			b3Body* ground = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
|  | 			b3HullShape shape; | ||||||
|  | 			shape.m_hull = &m_groundHull; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sd; | ||||||
|  | 			sd.shape = &shape; | ||||||
|  |  | ||||||
|  | 			ground->CreateShape(sd); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		b3Body* bA, * bB; | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bd; | ||||||
|  | 			bd.type = e_dynamicBody; | ||||||
|  | 			bd.position.Set(-5.0f, 5.0f, 0.0f); | ||||||
|  |  | ||||||
|  | 			bA = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
|  | 			m_hullA.SetExtents(2.0f, 2.0f, 0.5f); | ||||||
|  |  | ||||||
|  | 			b3HullShape hull; | ||||||
|  | 			hull.m_hull = &m_hullA; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.shape = &hull; | ||||||
|  | 			sdef.density = 1.0f; | ||||||
|  |  | ||||||
|  | 			bA->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bd; | ||||||
|  | 			bd.type = e_dynamicBody; | ||||||
|  | 			bd.position.Set(5.0f, 5.0f, 0.0f); | ||||||
|  |  | ||||||
|  | 			bB = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
|  | 			m_hullB.SetExtents(2.0f, 2.0f, 0.5f); | ||||||
|  |  | ||||||
|  | 			b3HullShape hull; | ||||||
|  | 			hull.m_hull = &m_hullB; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.shape = &hull; | ||||||
|  | 			sdef.density = 1.0f; | ||||||
|  |  | ||||||
|  | 			bB->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Create prismatic joint | ||||||
|  | 		{ | ||||||
|  | 			b3Vec3 anchor(0.0f, 5.0f, 0.0f); | ||||||
|  | 			b3Vec3 axis(1.0f, 0.0f, 0.0f); | ||||||
|  |  | ||||||
|  | 			b3PrismaticJointDef jd; | ||||||
|  | 			jd.Initialize(bA, bB, anchor, axis); | ||||||
|  | 			jd.motorSpeed = 10.0f; | ||||||
|  | 			jd.maxMotorForce = 10000.0f; | ||||||
|  | 			jd.enableMotor = true; | ||||||
|  | 			jd.lowerTranslation = 0.0f; | ||||||
|  | 			jd.upperTranslation = 10.0f; | ||||||
|  | 			jd.enableLimit = true; | ||||||
|  |  | ||||||
|  | 			m_joint = (b3PrismaticJoint*)m_world.CreateJoint(jd); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void Step() | ||||||
|  | 	{ | ||||||
|  | 		Test::Step(); | ||||||
|  |  | ||||||
|  | 		g_draw->DrawString(b3Color_white, "L - Enable Limit"); | ||||||
|  | 		g_draw->DrawString(b3Color_white, "M - Enable Motor"); | ||||||
|  | 		g_draw->DrawString(b3Color_white, "S - Flip Motor Speed"); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void KeyDown(int button) | ||||||
|  | 	{ | ||||||
|  | 		if (button == GLFW_KEY_L) | ||||||
|  | 		{ | ||||||
|  | 			m_joint->EnableLimit(!m_joint->IsLimitEnabled()); | ||||||
|  | 		} | ||||||
|  | 	 | ||||||
|  | 		if (button == GLFW_KEY_M) | ||||||
|  | 		{ | ||||||
|  | 			m_joint->EnableMotor(!m_joint->IsMotorEnabled()); | ||||||
|  | 		} | ||||||
|  | 	 | ||||||
|  | 		if (button == GLFW_KEY_S) | ||||||
|  | 		{ | ||||||
|  | 			m_joint->SetMotorSpeed(-m_joint->GetMotorSpeed()); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	static Test* Create() | ||||||
|  | 	{ | ||||||
|  | 		return new PrismaticTest(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b3BoxHull m_hullA; | ||||||
|  | 	b3BoxHull m_hullB; | ||||||
|  | 	b3PrismaticJoint* m_joint; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
| @@ -47,9 +47,9 @@ public: | |||||||
|  |  | ||||||
| 		// shift to ground center | 		// shift to ground center | ||||||
| 		b3Vec3 translation; | 		b3Vec3 translation; | ||||||
| 		translation.x = -0.5f * float32(e_count) * boxSize.x; | 		translation.x = -0.5f * scalar(e_count) * boxSize.x; | ||||||
| 		translation.y = 1.5f * boxSize.y; | 		translation.y = 1.5f * boxSize.y; | ||||||
| 		translation.z = -0.5f * float32(e_count) * boxSize.z; | 		translation.z = -0.5f * scalar(e_count) * boxSize.z; | ||||||
|  |  | ||||||
| 		u32 count = e_count; | 		u32 count = e_count; | ||||||
| 		for (u32 i = 0; i < e_count; ++i) | 		for (u32 i = 0; i < e_count; ++i) | ||||||
| @@ -61,9 +61,9 @@ public: | |||||||
| 				{ | 				{ | ||||||
| 					b3BodyDef bd; | 					b3BodyDef bd; | ||||||
| 					bd.type = b3BodyType::e_dynamicBody; | 					bd.type = b3BodyType::e_dynamicBody; | ||||||
| 					bd.position.x = 1.05f * float32(j) * boxSize.x; | 					bd.position.x = 1.05f * scalar(j) * boxSize.x; | ||||||
| 					bd.position.y = 0.0f; | 					bd.position.y = 0.0f; | ||||||
| 					bd.position.z = 1.05f * float32(k) * boxSize.z; | 					bd.position.z = 1.05f * scalar(k) * boxSize.z; | ||||||
| 					bd.position += translation; | 					bd.position += translation; | ||||||
|  |  | ||||||
| 					b3Body* body = m_world.CreateBody(bd); | 					b3Body* body = m_world.CreateBody(bd); | ||||||
|   | |||||||
| @@ -48,15 +48,15 @@ public: | |||||||
|  |  | ||||||
| 		// shift to ground center | 		// shift to ground center | ||||||
| 		b3Vec3 translation; | 		b3Vec3 translation; | ||||||
| 		translation.x = -0.5f * float32(e_count - 1) * 4.0f * boxSize.x; | 		translation.x = -0.5f * scalar(e_count - 1) * 4.0f * boxSize.x; | ||||||
| 		translation.y = 1.5f * boxSize.y; | 		translation.y = 1.5f * boxSize.y; | ||||||
| 		translation.z = -0.5f * float32(e_depthCount) * boxSize.z; | 		translation.z = -0.5f * scalar(e_depthCount) * boxSize.z; | ||||||
| 		 | 		 | ||||||
| 		for (u32 i = 0; i < e_count; ++i) | 		for (u32 i = 0; i < e_count; ++i) | ||||||
| 		{ | 		{ | ||||||
| 			// reset  | 			// reset  | ||||||
| 			translation.y = 1.5f * boxSize.y; | 			translation.y = 1.5f * boxSize.y; | ||||||
| 			translation.z = -0.5f * float32(e_depthCount) * boxSize.z; | 			translation.z = -0.5f * scalar(e_depthCount) * boxSize.z; | ||||||
|  |  | ||||||
| 			for (u32 j = 0; j < e_depthCount; ++j) | 			for (u32 j = 0; j < e_depthCount; ++j) | ||||||
| 			{ | 			{ | ||||||
| @@ -66,7 +66,7 @@ public: | |||||||
| 					bd.type = e_dynamicBody; | 					bd.type = e_dynamicBody; | ||||||
| 					bd.position.x = 0.0f; | 					bd.position.x = 0.0f; | ||||||
| 					bd.position.y = 0.0f; | 					bd.position.y = 0.0f; | ||||||
| 					bd.position.z = 1.05f * float32(k) * boxSize.z; | 					bd.position.z = 1.05f * scalar(k) * boxSize.z; | ||||||
| 					bd.position += translation; | 					bd.position += translation; | ||||||
|  |  | ||||||
| 					b3Body* body = m_world.CreateBody(bd); | 					b3Body* body = m_world.CreateBody(bd); | ||||||
|   | |||||||
| @@ -64,8 +64,8 @@ public: | |||||||
| 			b3Body* body = m_world.CreateBody(bdef); | 			b3Body* body = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
| 			b3CapsuleShape capsule; | 			b3CapsuleShape capsule; | ||||||
| 			capsule.m_centers[0].Set(0.0f, 0.0f, -1.0f); | 			capsule.m_vertex1.Set(0.0f, 0.0f, -1.0f); | ||||||
| 			capsule.m_centers[1].Set(0.0f, 0.0f, 1.0f); | 			capsule.m_vertex2.Set(0.0f, 0.0f, 1.0f); | ||||||
| 			capsule.m_radius = 1.0f; | 			capsule.m_radius = 1.0f; | ||||||
|  |  | ||||||
| 			b3ShapeDef sdef; | 			b3ShapeDef sdef; | ||||||
| @@ -83,7 +83,7 @@ public: | |||||||
|  |  | ||||||
| 			b3Body* body = m_world.CreateBody(bdef); | 			b3Body* body = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
| 			m_coneHull.SetAsCone(); | 			m_coneHull.SetExtents(1.0f, 1.0f); | ||||||
|  |  | ||||||
| 			b3HullShape hull; | 			b3HullShape hull; | ||||||
| 			hull.m_hull = &m_coneHull; | 			hull.m_hull = &m_coneHull; | ||||||
| @@ -103,7 +103,7 @@ public: | |||||||
|  |  | ||||||
| 			b3Body* body = m_world.CreateBody(bdef); | 			b3Body* body = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
| 			m_cylinderHull.SetAsCylinder(); | 			m_cylinderHull.SetExtents(1.0f, 1.0f); | ||||||
|  |  | ||||||
| 			b3HullShape hull; | 			b3HullShape hull; | ||||||
| 			hull.m_hull = &m_cylinderHull; | 			hull.m_hull = &m_cylinderHull; | ||||||
| @@ -126,8 +126,8 @@ public: | |||||||
| 		return new QuadricShapes(); | 		return new QuadricShapes(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	b3QHull m_coneHull; | 	b3ConeHull m_coneHull; | ||||||
| 	b3QHull m_cylinderHull; | 	b3CylinderHull m_cylinderHull; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
| @@ -52,8 +52,8 @@ public: | |||||||
| 			hip->ApplyForceToCenter(b3Vec3(0.0f, 0.0f, -5000.0f), true); | 			hip->ApplyForceToCenter(b3Vec3(0.0f, 0.0f, -5000.0f), true); | ||||||
|  |  | ||||||
| 			b3CapsuleShape cs; | 			b3CapsuleShape cs; | ||||||
| 			cs.m_centers[0].Set(0.0f, 0.5f, 0.0f); | 			cs.m_vertex1.Set(0.0f, 0.5f, 0.0f); | ||||||
| 			cs.m_centers[1].Set(0.0f, -0.5f, 0.0f); | 			cs.m_vertex2.Set(0.0f, -0.5f, 0.0f); | ||||||
| 			cs.m_radius = 1.0f; | 			cs.m_radius = 1.0f; | ||||||
|  |  | ||||||
| 			b3ShapeDef sd; | 			b3ShapeDef sd; | ||||||
| @@ -70,8 +70,8 @@ public: | |||||||
| 			head = m_world.CreateBody(bd); | 			head = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
| 			b3CapsuleShape cs; | 			b3CapsuleShape cs; | ||||||
| 			cs.m_centers[0].Set(0.0f, 0.15f, 0.0f); | 			cs.m_vertex1.Set(0.0f, 0.15f, 0.0f); | ||||||
| 			cs.m_centers[1].Set(0.0f, -0.15f, 0.0f); | 			cs.m_vertex2.Set(0.0f, -0.15f, 0.0f); | ||||||
| 			cs.m_radius = 0.5f; | 			cs.m_radius = 0.5f; | ||||||
|  |  | ||||||
| 			b3ShapeDef sd; | 			b3ShapeDef sd; | ||||||
| @@ -86,7 +86,7 @@ public: | |||||||
| 			cd.bodyA = hip; | 			cd.bodyA = hip; | ||||||
| 			cd.bodyB = head; | 			cd.bodyB = head; | ||||||
| 			cd.collideLinked = false; | 			cd.collideLinked = false; | ||||||
| 			cd.enableLimit = true; | 			cd.enableConeLimit = true; | ||||||
| 			cd.Initialize(hip, head, b3Vec3(0.0f, 1.0f, 0.0f), b3Vec3(0.0f, 11.55f, 0.0f), 0.25f * B3_PI); | 			cd.Initialize(hip, head, b3Vec3(0.0f, 1.0f, 0.0f), b3Vec3(0.0f, 11.55f, 0.0f), 0.25f * B3_PI); | ||||||
| 			b3ConeJoint* cj = (b3ConeJoint*)m_world.CreateJoint(cd); | 			b3ConeJoint* cj = (b3ConeJoint*)m_world.CreateJoint(cd); | ||||||
| 		} | 		} | ||||||
| @@ -95,12 +95,12 @@ public: | |||||||
| 			b3BodyDef bd; | 			b3BodyDef bd; | ||||||
| 			bd.type = e_dynamicBody; | 			bd.type = e_dynamicBody; | ||||||
| 			bd.position.Set(-2.5f, 11.0f, 0.0f); | 			bd.position.Set(-2.5f, 11.0f, 0.0f); | ||||||
| 			bd.orientation.Set(b3Vec3(0.0f, 0.0f, 1.0f), 0.5f * B3_PI); | 			bd.orientation = b3QuatRotationZ(0.5f * B3_PI); | ||||||
| 			lArm = m_world.CreateBody(bd); | 			lArm = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
| 			b3CapsuleShape cs; | 			b3CapsuleShape cs; | ||||||
| 			cs.m_centers[0].Set(0.0f, 1.0f, 0.0f); | 			cs.m_vertex1.Set(0.0f, 1.0f, 0.0f); | ||||||
| 			cs.m_centers[1].Set(0.0f, -1.0f, 0.0f); | 			cs.m_vertex2.Set(0.0f, -1.0f, 0.0f); | ||||||
| 			cs.m_radius = 0.5f; | 			cs.m_radius = 0.5f; | ||||||
|  |  | ||||||
| 			b3ShapeDef sd; | 			b3ShapeDef sd; | ||||||
| @@ -116,7 +116,7 @@ public: | |||||||
| 			cd.bodyA = hip; | 			cd.bodyA = hip; | ||||||
| 			cd.bodyB = lArm; | 			cd.bodyB = lArm; | ||||||
| 			cd.collideLinked = false; | 			cd.collideLinked = false; | ||||||
| 			cd.enableLimit = true; | 			cd.enableConeLimit = true; | ||||||
| 			cd.Initialize(hip, lArm, b3Vec3(-1.0f, 0.0f, 0.0f), b3Vec3(-1.0f, 11.0f, 0.0f), B3_PI); | 			cd.Initialize(hip, lArm, b3Vec3(-1.0f, 0.0f, 0.0f), b3Vec3(-1.0f, 11.0f, 0.0f), B3_PI); | ||||||
| 			b3ConeJoint* cj = (b3ConeJoint*)m_world.CreateJoint(cd); | 			b3ConeJoint* cj = (b3ConeJoint*)m_world.CreateJoint(cd); | ||||||
| 		} | 		} | ||||||
| @@ -125,12 +125,12 @@ public: | |||||||
| 			b3BodyDef bd; | 			b3BodyDef bd; | ||||||
| 			bd.type = e_dynamicBody; | 			bd.type = e_dynamicBody; | ||||||
| 			bd.position.Set(2.5f, 11.0f, 0.0f); | 			bd.position.Set(2.5f, 11.0f, 0.0f); | ||||||
| 			bd.orientation.Set(b3Vec3(0.0f, 0.0f, 1.0f), 0.5f * B3_PI); | 			bd.orientation.SetAxisAngle(b3Vec3(0.0f, 0.0f, 1.0f), 0.5f * B3_PI); | ||||||
| 			rArm = m_world.CreateBody(bd); | 			rArm = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
| 			b3CapsuleShape cs; | 			b3CapsuleShape cs; | ||||||
| 			cs.m_centers[0].Set(0.0f, 1.0f, 0.0f); | 			cs.m_vertex1.Set(0.0f, 1.0f, 0.0f); | ||||||
| 			cs.m_centers[1].Set(0.0f, -1.0f, 0.0f); | 			cs.m_vertex2.Set(0.0f, -1.0f, 0.0f); | ||||||
| 			cs.m_radius = 0.5f; | 			cs.m_radius = 0.5f; | ||||||
|  |  | ||||||
| 			b3ShapeDef sd; | 			b3ShapeDef sd; | ||||||
| @@ -146,7 +146,7 @@ public: | |||||||
| 			cd.bodyA = hip; | 			cd.bodyA = hip; | ||||||
| 			cd.bodyB = rArm; | 			cd.bodyB = rArm; | ||||||
| 			cd.collideLinked = false; | 			cd.collideLinked = false; | ||||||
| 			cd.enableLimit = true; | 			cd.enableConeLimit = true; | ||||||
| 			cd.Initialize(hip, rArm, b3Vec3(1.0f, 0.0f, 0.0f), b3Vec3(1.0f, 11.0f, 0.0f), B3_PI); | 			cd.Initialize(hip, rArm, b3Vec3(1.0f, 0.0f, 0.0f), b3Vec3(1.0f, 11.0f, 0.0f), B3_PI); | ||||||
| 			b3ConeJoint* cj = (b3ConeJoint*)m_world.CreateJoint(cd); | 			b3ConeJoint* cj = (b3ConeJoint*)m_world.CreateJoint(cd); | ||||||
| 		} | 		} | ||||||
| @@ -158,8 +158,8 @@ public: | |||||||
| 			lLeg = m_world.CreateBody(bd); | 			lLeg = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
| 			b3CapsuleShape cs; | 			b3CapsuleShape cs; | ||||||
| 			cs.m_centers[0].Set(0.0f, 2.0f, 0.0f); | 			cs.m_vertex1.Set(0.0f, 2.0f, 0.0f); | ||||||
| 			cs.m_centers[1].Set(0.0f, -2.0f, 0.0f); | 			cs.m_vertex2.Set(0.0f, -2.0f, 0.0f); | ||||||
| 			cs.m_radius = 0.45f; | 			cs.m_radius = 0.45f; | ||||||
|  |  | ||||||
| 			b3ShapeDef sd; | 			b3ShapeDef sd; | ||||||
| @@ -175,7 +175,7 @@ public: | |||||||
| 			cd.bodyA = hip; | 			cd.bodyA = hip; | ||||||
| 			cd.bodyB = lLeg; | 			cd.bodyB = lLeg; | ||||||
| 			cd.collideLinked = false; | 			cd.collideLinked = false; | ||||||
| 			cd.enableLimit = true; | 			cd.enableConeLimit = true; | ||||||
| 			cd.Initialize(hip, lLeg, b3Vec3(0.0f, -1.0f, 0.0f), b3Vec3(-0.5f, 8.5f, 0.0f), 0.25f * B3_PI); | 			cd.Initialize(hip, lLeg, b3Vec3(0.0f, -1.0f, 0.0f), b3Vec3(-0.5f, 8.5f, 0.0f), 0.25f * B3_PI); | ||||||
| 			b3ConeJoint* cj = (b3ConeJoint*)m_world.CreateJoint(cd); | 			b3ConeJoint* cj = (b3ConeJoint*)m_world.CreateJoint(cd); | ||||||
| 		} | 		} | ||||||
| @@ -187,8 +187,8 @@ public: | |||||||
| 			rLeg = m_world.CreateBody(bd); | 			rLeg = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
| 			b3CapsuleShape cs; | 			b3CapsuleShape cs; | ||||||
| 			cs.m_centers[0].Set(0.0f, 2.0f, 0.0f); | 			cs.m_vertex1.Set(0.0f, 2.0f, 0.0f); | ||||||
| 			cs.m_centers[1].Set(0.0f, -2.0f, 0.0f); | 			cs.m_vertex2.Set(0.0f, -2.0f, 0.0f); | ||||||
| 			cs.m_radius = 0.45f; | 			cs.m_radius = 0.45f; | ||||||
|  |  | ||||||
| 			b3ShapeDef sd; | 			b3ShapeDef sd; | ||||||
| @@ -204,7 +204,7 @@ public: | |||||||
| 			cd.bodyA = hip; | 			cd.bodyA = hip; | ||||||
| 			cd.bodyB = rLeg; | 			cd.bodyB = rLeg; | ||||||
| 			cd.collideLinked = false; | 			cd.collideLinked = false; | ||||||
| 			cd.enableLimit = true; | 			cd.enableConeLimit = true; | ||||||
| 			cd.Initialize(hip, rLeg, b3Vec3(0.0f, -1.0f, 0.0f), b3Vec3(0.5f, 8.5f, 0.0f), 0.25f * B3_PI); | 			cd.Initialize(hip, rLeg, b3Vec3(0.0f, -1.0f, 0.0f), b3Vec3(0.5f, 8.5f, 0.0f), 0.25f * B3_PI); | ||||||
| 			b3ConeJoint* cj = (b3ConeJoint*)m_world.CreateJoint(cd); | 			b3ConeJoint* cj = (b3ConeJoint*)m_world.CreateJoint(cd); | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -159,8 +159,8 @@ public: | |||||||
| 			b3Body* body = m_world.CreateBody(bdef); | 			b3Body* body = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
| 			b3CapsuleShape hs; | 			b3CapsuleShape hs; | ||||||
| 			hs.m_centers[0].Set(0.0f, 1.0f, 0.0f); | 			hs.m_vertex1.Set(0.0f, 1.0f, 0.0f); | ||||||
| 			hs.m_centers[1].Set(0.0f, -1.0f, 0.0f); | 			hs.m_vertex2.Set(0.0f, -1.0f, 0.0f); | ||||||
| 			hs.m_radius = 3.0f; | 			hs.m_radius = 3.0f; | ||||||
|  |  | ||||||
| 			b3ShapeDef sdef; | 			b3ShapeDef sdef; | ||||||
| @@ -178,8 +178,19 @@ public: | |||||||
| 	 | 	 | ||||||
| 	void CastRay(const b3Vec3 p1, const b3Vec3 p2) const | 	void CastRay(const b3Vec3 p1, const b3Vec3 p2) const | ||||||
| 	{ | 	{ | ||||||
|  | 		class RayCastFilter : public b3RayCastFilter | ||||||
|  | 		{ | ||||||
|  | 		public: | ||||||
|  | 			bool ShouldRayCast(b3Shape* shape) | ||||||
|  | 			{ | ||||||
|  | 				return true; | ||||||
|  | 			} | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		RayCastFilter filter; | ||||||
|  |  | ||||||
| 		b3RayCastSingleOutput out; | 		b3RayCastSingleOutput out; | ||||||
| 		if (m_world.RayCastSingle(&out, p1, p2)) | 		if (m_world.RayCastSingle(&out, &filter, p1, p2)) | ||||||
| 		{ | 		{ | ||||||
| 			g_draw->DrawSegment(p1, out.point, b3Color_green); | 			g_draw->DrawSegment(p1, out.point, b3Color_green); | ||||||
| 			 | 			 | ||||||
| @@ -194,7 +205,7 @@ public: | |||||||
|  |  | ||||||
| 	void Step() | 	void Step() | ||||||
| 	{ | 	{ | ||||||
| 		float32 dt = g_testSettings->inv_hertz; | 		scalar dt = g_testSettings->inv_hertz; | ||||||
| 		b3Quat dq = b3QuatRotationY(0.05f * B3_PI * dt); | 		b3Quat dq = b3QuatRotationY(0.05f * B3_PI * dt); | ||||||
| 		 | 		 | ||||||
| 		m_p1 = b3Mul(dq, m_p1); | 		m_p1 = b3Mul(dq, m_p1); | ||||||
|   | |||||||
| @@ -16,13 +16,13 @@ | |||||||
| * 3. This notice may not be removed or altered from any source distribution. | * 3. This notice may not be removed or altered from any source distribution. | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| #ifndef HINGE_MOTOR_H | #ifndef REVOLUTE_TEST_H | ||||||
| #define HINGE_MOTOR_H | #define REVOLUTE_TEST_H | ||||||
| 
 | 
 | ||||||
| class HingeMotor : public Test | class RevoluteTest : public Test | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	HingeMotor() | 	RevoluteTest() | ||||||
| 	{ | 	{ | ||||||
| 		{ | 		{ | ||||||
| 			b3BodyDef bd; | 			b3BodyDef bd; | ||||||
| @@ -46,8 +46,8 @@ public: | |||||||
| 			hinge = m_world.CreateBody(bd); | 			hinge = m_world.CreateBody(bd); | ||||||
| 
 | 
 | ||||||
| 			b3CapsuleShape shape; | 			b3CapsuleShape shape; | ||||||
| 			shape.m_centers[0].Set(0.0f, 0.0f, -4.0f); | 			shape.m_vertex1.Set(0.0f, 0.0f, -4.0f); | ||||||
| 			shape.m_centers[1].Set(0.0f, 0.0f, 4.0f); | 			shape.m_vertex2.Set(0.0f, 0.0f, 4.0f); | ||||||
| 			shape.m_radius = 0.5f; | 			shape.m_radius = 0.5f; | ||||||
| 			 | 			 | ||||||
| 			b3ShapeDef sd; | 			b3ShapeDef sd; | ||||||
| @@ -66,7 +66,7 @@ public: | |||||||
| 
 | 
 | ||||||
| 			door = m_world.CreateBody(bd); | 			door = m_world.CreateBody(bd); | ||||||
| 
 | 
 | ||||||
| 			m_doorBox.Set(1.0f, 0.5f, 4.0f); | 			m_doorBox.SetExtents(1.0f, 0.5f, 4.0f); | ||||||
| 
 | 
 | ||||||
| 			b3HullShape hull; | 			b3HullShape hull; | ||||||
| 			hull.m_hull = &m_doorBox; | 			hull.m_hull = &m_doorBox; | ||||||
| @@ -78,23 +78,34 @@ public: | |||||||
| 			door->CreateShape(sdef); | 			door->CreateShape(sdef); | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
|  | 
 | ||||||
| 		{ | 		{ | ||||||
| 			b3Vec3 axis(0.0f, 0.0f, 1.0f); | 			b3Vec3 axis(0.0f, 0.0f, 1.0f); | ||||||
| 			b3Vec3 anchor(0.0f, 7.0f, 0.0f); | 			b3Vec3 anchor(0.0f, 7.0f, 0.0f); | ||||||
| 			 | 			 | ||||||
| 			b3RevoluteJointDef jd; | 			b3RevoluteJointDef jd; | ||||||
| 			jd.Initialize(hinge, door, axis, anchor, 0.0f, B3_PI); | 			jd.Initialize(hinge, door, axis, anchor, -0.25f * B3_PI, 0.5f * B3_PI); | ||||||
|  | 			jd.maxMotorTorque = 1000.0f; | ||||||
|  | 			jd.enableMotor = false; | ||||||
|  | 			jd.enableLimit = true; | ||||||
| 			jd.motorSpeed = B3_PI; | 			jd.motorSpeed = B3_PI; | ||||||
| 			jd.maxMotorTorque = door->GetMass() * 10000.0f; |  | ||||||
| 			jd.enableMotor = true; |  | ||||||
| 
 | 
 | ||||||
| 			m_rj = (b3RevoluteJoint*)m_world.CreateJoint(jd); | 			m_rj = (b3RevoluteJoint*)m_world.CreateJoint(jd); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// Invalidate the orientation
 | 		// Invalidate the orientation
 | ||||||
| 		b3Vec3 axis(1.0f, 0.0f, 0.0f); | 		b3Quat q = b3QuatRotationX(B3_PI); | ||||||
| 		float32 angle = B3_PI; | 		door->SetTransform(door->GetPosition(), q);		 | ||||||
| 		door->SetTransform(door->GetPosition(), axis, angle);		 | 	} | ||||||
|  | 
 | ||||||
|  | 	void Step() | ||||||
|  | 	{ | ||||||
|  | 		Test::Step(); | ||||||
|  | 
 | ||||||
|  | 		g_draw->DrawString(b3Color_white, "M - Motor"); | ||||||
|  | 		g_draw->DrawString(b3Color_white, "L - Limits"); | ||||||
|  | 		g_draw->DrawString(b3Color_white, "S/K/D - Static/kinematic/dynamic body"); | ||||||
|  | 
 | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void KeyDown(int button) | 	void KeyDown(int button) | ||||||
| @@ -127,7 +138,7 @@ public: | |||||||
| 
 | 
 | ||||||
| 	static Test* Create() | 	static Test* Create() | ||||||
| 	{ | 	{ | ||||||
| 		return new HingeMotor(); | 		return new RevoluteTest(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	b3BoxHull m_doorBox; | 	b3BoxHull m_doorBox; | ||||||
| @@ -30,7 +30,7 @@ public: | |||||||
| 	Rope() | 	Rope() | ||||||
| 	{ | 	{ | ||||||
| 		b3Vec3 vs[e_count]; | 		b3Vec3 vs[e_count]; | ||||||
| 		float32 ms[e_count]; | 		scalar ms[e_count]; | ||||||
| 		 | 		 | ||||||
| 		vs[0].Set(0.0f, 0.0f, 0.0f); | 		vs[0].Set(0.0f, 0.0f, 0.0f); | ||||||
| 		ms[0] = 0.0f; | 		ms[0] = 0.0f; | ||||||
| @@ -38,7 +38,7 @@ public: | |||||||
| 		for (u32 i = 1; i < e_count; ++i) | 		for (u32 i = 1; i < e_count; ++i) | ||||||
| 		{ | 		{ | ||||||
| 			ms[i] = 1.0f; | 			ms[i] = 1.0f; | ||||||
| 			vs[i].Set(float32(i), 0.0f, 0.0f); | 			vs[i].Set(scalar(i), 0.0f, 0.0f); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		b3RopeDef rd; | 		b3RopeDef rd; | ||||||
|   | |||||||
| @@ -63,8 +63,8 @@ public: | |||||||
| 			m_character = m_world.CreateBody(bd); | 			m_character = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
| 			b3CapsuleShape cap; | 			b3CapsuleShape cap; | ||||||
| 			cap.m_centers[0].Set(0.0f, 2.0f, 0.0f); | 			cap.m_vertex1.Set(0.0f, 2.0f, 0.0f); | ||||||
| 			cap.m_centers[1].Set(0.0f, -2.0f, 0.0f); | 			cap.m_vertex2.Set(0.0f, -2.0f, 0.0f); | ||||||
| 			cap.m_radius = 0.5f; | 			cap.m_radius = 0.5f; | ||||||
|  |  | ||||||
| 			b3ShapeDef sd; | 			b3ShapeDef sd; | ||||||
| @@ -129,7 +129,7 @@ public: | |||||||
| 			bd.type = b3BodyType::e_dynamicBody; | 			bd.type = b3BodyType::e_dynamicBody; | ||||||
| 			bd.position.Set(RandomFloat(-20.0f, 20.0f), RandomFloat(10.0f, 20.0f), RandomFloat(-20.0f, 20.0f)); | 			bd.position.Set(RandomFloat(-20.0f, 20.0f), RandomFloat(10.0f, 20.0f), RandomFloat(-20.0f, 20.0f)); | ||||||
|  |  | ||||||
| 			b3Vec3 n = m_character->GetTransform().position - bd.position; | 			b3Vec3 n = m_character->GetTransform().translation - bd.position; | ||||||
| 			n.Normalize(); | 			n.Normalize(); | ||||||
|  |  | ||||||
| 			bd.linearVelocity = 60.0f * n; | 			bd.linearVelocity = 60.0f * n; | ||||||
|   | |||||||
| @@ -1,121 +0,0 @@ | |||||||
| #ifndef SHAPE_CAST_H |  | ||||||
| #define SHAPE_CAST_H |  | ||||||
|  |  | ||||||
| class ShapeCast : public Test |  | ||||||
| { |  | ||||||
| public: |  | ||||||
| 	ShapeCast() |  | ||||||
| 	{ |  | ||||||
| 		m_shapeA.m_hull = &b3BoxHull_identity; |  | ||||||
| 		m_shapeA.m_radius = 0.0f; |  | ||||||
|  |  | ||||||
| 		m_shapeB.m_hull = &b3BoxHull_identity; |  | ||||||
| 		m_shapeB.m_radius = 0.0f; |  | ||||||
|  |  | ||||||
| 		m_xfA.position.Set(-5.0f, 0.0f, 0.0f); |  | ||||||
| 		m_xfA.rotation.SetIdentity(); |  | ||||||
|  |  | ||||||
| 		m_xfB.position.Set(10.0f, 0.0f, 0.0f); |  | ||||||
| 		m_xfB.rotation.SetIdentity(); |  | ||||||
| 		 |  | ||||||
| 		m_proxyA.Set(&m_shapeA, 0); |  | ||||||
| 		m_proxyB.Set(&m_shapeB, 0); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	void Step() |  | ||||||
| 	{ |  | ||||||
| 		g_draw->DrawString(b3Color_white, "Left/Right/Up/Down Arrow - Translate shape"); |  | ||||||
| 		g_draw->DrawString(b3Color_white, "X/Y/Z - Rotate shape"); |  | ||||||
|  |  | ||||||
| 		g_draw->DrawTransform(m_xfA); |  | ||||||
| 		g_draw->DrawTransform(m_xfB); |  | ||||||
|  |  | ||||||
| 		m_world.DrawShape(m_xfA, &m_shapeA, b3Color_black); |  | ||||||
| 		m_world.DrawShape(m_xfB, &m_shapeB, b3Color_black); |  | ||||||
|  |  | ||||||
| 		m_world.DrawSolidShape(m_xfA, &m_shapeA, b3Color_white); |  | ||||||
| 		m_world.DrawSolidShape(m_xfB, &m_shapeB, b3Color_white); |  | ||||||
|  |  | ||||||
| 		b3Vec3 translationB = -100.0f * b3Vec3_x; |  | ||||||
| 		g_draw->DrawSegment(m_xfB.position, m_xfB.position + translationB, b3Color_white); |  | ||||||
|  |  | ||||||
| 		b3GJKShapeCastOutput out; |  | ||||||
| 		bool hit = b3GJKShapeCast(&out, m_xfA, m_proxyA, m_xfB, m_proxyB, translationB); |  | ||||||
|  |  | ||||||
| 		g_draw->DrawString(b3Color_white, "Iterations = %d", out.iterations); |  | ||||||
|  |  | ||||||
| 		if (hit) |  | ||||||
| 		{ |  | ||||||
| 			g_draw->DrawPoint(out.point, 4.0f, b3Color_green); |  | ||||||
| 			g_draw->DrawSegment(out.point, out.point + out.normal, b3Color_green); |  | ||||||
|  |  | ||||||
| 			b3Transform xfB; |  | ||||||
| 			xfB.rotation = m_xfB.rotation; |  | ||||||
| 			xfB.position = m_xfB.position + out.t * translationB; |  | ||||||
|  |  | ||||||
| 			m_world.DrawShape(xfB, &m_shapeB, b3Color_black); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	void KeyDown(int key) |  | ||||||
| 	{ |  | ||||||
| 		if (key == GLFW_KEY_LEFT) |  | ||||||
| 		{ |  | ||||||
| 			m_xfB.position.x -= 0.105f; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (key == GLFW_KEY_RIGHT) |  | ||||||
| 		{ |  | ||||||
| 			m_xfB.position.x += 0.105f; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (key == GLFW_KEY_UP) |  | ||||||
| 		{ |  | ||||||
| 			m_xfB.position.y += 0.105f; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (key == GLFW_KEY_DOWN) |  | ||||||
| 		{ |  | ||||||
| 			m_xfB.position.y -= 0.105f; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (key == GLFW_KEY_X) |  | ||||||
| 		{ |  | ||||||
| 			b3Quat qx(b3Vec3(1.0f, 0.0f, 0.0f), 0.05f * B3_PI); |  | ||||||
| 			b3Mat33 xfx = b3QuatMat33(qx); |  | ||||||
|  |  | ||||||
| 			m_xfB.rotation = m_xfB.rotation * xfx; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (key == GLFW_KEY_Y) |  | ||||||
| 		{ |  | ||||||
| 			b3Quat qy(b3Vec3(0.0f, 1.0f, 0.0f), 0.05f * B3_PI); |  | ||||||
| 			b3Mat33 xfy = b3QuatMat33(qy); |  | ||||||
|  |  | ||||||
| 			m_xfB.rotation = m_xfB.rotation * xfy; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (key == GLFW_KEY_Z) |  | ||||||
| 		{ |  | ||||||
| 			b3Quat qy(b3Vec3(0.0f, 0.0f, 1.0f), 0.05f * B3_PI); |  | ||||||
| 			b3Mat33 xfz = b3QuatMat33(qy); |  | ||||||
|  |  | ||||||
| 			m_xfB.rotation = m_xfB.rotation * xfz; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	static Test* Create() |  | ||||||
| 	{ |  | ||||||
| 		return new ShapeCast(); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	b3HullShape m_shapeA; |  | ||||||
| 	b3Transform m_xfA; |  | ||||||
| 	b3ShapeGJKProxy m_proxyA; |  | ||||||
|  |  | ||||||
| 	b3HullShape m_shapeB; |  | ||||||
| 	b3Transform m_xfB; |  | ||||||
| 	b3ShapeGJKProxy m_proxyB; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
| @@ -26,7 +26,6 @@ public: | |||||||
| 	{ | 	{ | ||||||
| 		{ | 		{ | ||||||
| 			b3BodyDef bd; | 			b3BodyDef bd; | ||||||
| 			bd.orientation.Set(b3Vec3(0.0f, 1.0f, 0.0f), 0.18f * B3_PI); |  | ||||||
| 			b3Body* ground = m_world.CreateBody(bd); | 			b3Body* ground = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
| 			b3MeshShape ms; | 			b3MeshShape ms; | ||||||
| @@ -39,7 +38,7 @@ public: | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  |  | ||||||
| 		for (float32 y = 2.5f; y < 20.0f; y += 2.5f) | 		for (scalar y = 2.5f; y < 20.0f; y += 2.5f) | ||||||
| 		{ | 		{ | ||||||
| 			b3BodyDef bd; | 			b3BodyDef bd; | ||||||
| 			bd.type = b3BodyType::e_dynamicBody; | 			bd.type = b3BodyType::e_dynamicBody; | ||||||
| @@ -59,18 +58,18 @@ public: | |||||||
| 			body->CreateShape(sdef); | 			body->CreateShape(sdef); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		for (float32 y = 2.5f; y < 20.0f; y += 2.5f) | 		for (scalar y = 2.5f; y < 20.0f; y += 2.5f) | ||||||
| 		{ | 		{ | ||||||
| 			b3BodyDef bd; | 			b3BodyDef bd; | ||||||
| 			bd.type = b3BodyType::e_dynamicBody; | 			bd.type = b3BodyType::e_dynamicBody; | ||||||
| 			bd.position.Set(0.0f, y, 0.0f); | 			bd.position.Set(0.0f, y, 0.0f); | ||||||
| 			bd.orientation = b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), 0.5f * B3_PI); | 			bd.orientation = b3QuatRotationZ(0.5f * B3_PI); | ||||||
|  |  | ||||||
| 			b3Body* body = m_world.CreateBody(bd); | 			b3Body* body = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
| 			b3CapsuleShape capsule; | 			b3CapsuleShape capsule; | ||||||
| 			capsule.m_centers[0].Set(0.0f, -1.0f, 0.0f); | 			capsule.m_vertex1.Set(0.0f, -1.0f, 0.0f); | ||||||
| 			capsule.m_centers[1].Set(0.0f, 1.0f, 0.0f); | 			capsule.m_vertex2.Set(0.0f, 1.0f, 0.0f); | ||||||
| 			capsule.m_radius = 1.0f; | 			capsule.m_radius = 1.0f; | ||||||
|  |  | ||||||
| 			b3ShapeDef sd; | 			b3ShapeDef sd; | ||||||
| @@ -81,7 +80,7 @@ public: | |||||||
| 			body->CreateShape(sd); | 			body->CreateShape(sd); | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		for (float32 y = 2.5f; y < 20.0f; y += 2.5f) | 		for (scalar y = 2.5f; y < 20.0f; y += 2.5f) | ||||||
| 		{ | 		{ | ||||||
| 			b3BodyDef bd; | 			b3BodyDef bd; | ||||||
| 			bd.type = b3BodyType::e_dynamicBody; | 			bd.type = b3BodyType::e_dynamicBody; | ||||||
|   | |||||||
							
								
								
									
										136
									
								
								examples/testbed/tests/sheet.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								examples/testbed/tests/sheet.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,136 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * 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 SHEET_H | ||||||
|  | #define SHEET_H | ||||||
|  |  | ||||||
|  | class Sheet : public Test | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	enum | ||||||
|  | 	{ | ||||||
|  | 		e_w = 10, | ||||||
|  | 		e_h = 1, | ||||||
|  | 		e_d = 10 | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	Sheet() | ||||||
|  | 	{ | ||||||
|  | 		// Downscale the block along the y axis | ||||||
|  | 		for (u32 i = 0; i < m_mesh.vertexCount; ++i) | ||||||
|  | 		{ | ||||||
|  | 			m_mesh.vertices[i].y *= 0.5f; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Create soft body | ||||||
|  | 		b3SoftBodyDef def; | ||||||
|  | 		def.mesh = &m_mesh; | ||||||
|  | 		def.density = 0.3f; | ||||||
|  | 		def.E = 200.0f; | ||||||
|  | 		def.nu = 0.3f; | ||||||
|  |  | ||||||
|  | 		m_body = new b3SoftBody(def); | ||||||
|  |  | ||||||
|  | 		b3Vec3 gravity(0.0f, -9.8f, 0.0f); | ||||||
|  | 		m_body->SetGravity(gravity); | ||||||
|  |  | ||||||
|  | 		for (u32 j = 0; j < e_w + 1; ++j) | ||||||
|  | 		{ | ||||||
|  | 				u32 v = m_mesh.GetVertex(0, j, 0); | ||||||
|  |  | ||||||
|  | 				b3SoftBodyNode* n = m_body->GetNode(v); | ||||||
|  | 				n->SetType(e_staticSoftBodyNode); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		m_bodyDragger = new b3SoftBodyDragger(&m_ray, m_body); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	~Sheet() | ||||||
|  | 	{ | ||||||
|  | 		delete m_bodyDragger; | ||||||
|  | 		delete m_body; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void Step() | ||||||
|  | 	{ | ||||||
|  | 		Test::Step(); | ||||||
|  |  | ||||||
|  | 		if (m_bodyDragger->IsDragging()) | ||||||
|  | 		{ | ||||||
|  | 			m_bodyDragger->Drag(); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		m_body->Step(g_testSettings->inv_hertz, g_testSettings->velocityIterations, g_testSettings->positionIterations); | ||||||
|  |  | ||||||
|  | 		m_body->Draw(); | ||||||
|  |  | ||||||
|  | 		if (m_bodyDragger->IsDragging()) | ||||||
|  | 		{ | ||||||
|  | 			b3Vec3 pA = m_bodyDragger->GetPointA(); | ||||||
|  | 			b3Vec3 pB = m_bodyDragger->GetPointB(); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawPoint(pA, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawPoint(pB, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawSegment(pA, pB, b3Color_white); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		extern u32 b3_softBodySolverIterations; | ||||||
|  | 		g_draw->DrawString(b3Color_white, "Iterations = %d", b3_softBodySolverIterations); | ||||||
|  |  | ||||||
|  | 		scalar E = m_body->GetEnergy(); | ||||||
|  | 		g_draw->DrawString(b3Color_white, "E = %f", E); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void MouseMove(const b3Ray3& pw) | ||||||
|  | 	{ | ||||||
|  | 		Test::MouseMove(pw); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void MouseLeftDown(const b3Ray3& pw) | ||||||
|  | 	{ | ||||||
|  | 		Test::MouseLeftDown(pw); | ||||||
|  |  | ||||||
|  | 		if (m_bodyDragger->IsDragging() == false) | ||||||
|  | 		{ | ||||||
|  | 			m_bodyDragger->StartDragging(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void MouseLeftUp(const b3Ray3& pw) | ||||||
|  | 	{ | ||||||
|  | 		Test::MouseLeftUp(pw); | ||||||
|  |  | ||||||
|  | 		if (m_bodyDragger->IsDragging() == true) | ||||||
|  | 		{ | ||||||
|  | 			m_bodyDragger->StopDragging(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	static Test* Create() | ||||||
|  | 	{ | ||||||
|  | 		return new Sheet(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b3BlockSoftBodyMesh<e_w, e_h, e_d> m_mesh; | ||||||
|  | 	b3SoftBody* m_body; | ||||||
|  | 	b3SoftBodyDragger* m_bodyDragger; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
| @@ -24,17 +24,15 @@ class SheetStack : public Test | |||||||
| public: | public: | ||||||
| 	enum | 	enum | ||||||
| 	{ | 	{ | ||||||
| 		e_rowCount = 1, | 		e_h = 5, | ||||||
| 		e_columnCount = 10, | 		e_w = 1, | ||||||
| 		e_depthCount = 1 | 		e_d = 1 | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	SheetStack() | 	SheetStack() | ||||||
| 	{ | 	{ | ||||||
| 		{ | 		{ | ||||||
| 			b3BodyDef bdef; | 			b3BodyDef bdef; | ||||||
| 			bdef.type = b3BodyType::e_staticBody; |  | ||||||
|  |  | ||||||
| 			b3Body* body = m_world.CreateBody(bdef); | 			b3Body* body = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
| 			b3HullShape hs; | 			b3HullShape hs; | ||||||
| @@ -44,49 +42,87 @@ public: | |||||||
| 			sdef.shape = &hs; | 			sdef.shape = &hs; | ||||||
| 			sdef.friction = 1.0f; | 			sdef.friction = 1.0f; | ||||||
|  |  | ||||||
| 			b3Shape* shape = body->CreateShape(sdef); | 			body->CreateShape(sdef); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		static b3Vec3 sheetExtents(4.05f, 2.0f * B3_LINEAR_SLOP, 4.05f); | 		b3Vec3 e(4.0f, 2.0f * B3_LINEAR_SLOP, 4.0f); | ||||||
| 		static b3BoxHull sheetHull(sheetExtents.x, sheetExtents.y, sheetExtents.z); |  | ||||||
|  |  | ||||||
| 		b3Vec3 stackOrigin; | 		m_boxHull.SetExtents(e.x, e.y, e.z); | ||||||
| 		stackOrigin.Set(0.0f, 4.05f, 0.0f); |  | ||||||
|  |  | ||||||
| 		for (u32 i = 0; i < e_rowCount; ++i) | 		b3Vec3 separation; | ||||||
|  | 		separation.x = 1.0f; | ||||||
|  | 		separation.y = 1.0f; | ||||||
|  | 		separation.z = 1.0f; | ||||||
|  |  | ||||||
|  | 		b3Vec3 scale; | ||||||
|  | 		scale.x = 2.0f * e.x + separation.x; | ||||||
|  | 		scale.y = 2.0f * e.y + separation.y; | ||||||
|  | 		scale.z = 2.0f * e.z + separation.z; | ||||||
|  |  | ||||||
|  | 		b3Vec3 size; | ||||||
|  | 		size.x = 2.0f * e.x + scale.x * scalar(e_w - 1); | ||||||
|  | 		size.y = 2.0f * e.y + scale.y * scalar(e_h - 1); | ||||||
|  | 		size.z = 2.0f * e.z + scale.z * scalar(e_d - 1); | ||||||
|  |  | ||||||
|  | 		b3Vec3 translation; | ||||||
|  | 		translation.x = e.x - 0.5f * size.x; | ||||||
|  | 		translation.y = e.y - 0.5f * size.y; | ||||||
|  | 		translation.z = e.z - 0.5f * size.z; | ||||||
|  |  | ||||||
|  | 		translation.y += 9.0f; | ||||||
|  |  | ||||||
|  | 		for (u32 i = 0; i < e_h; ++i) | ||||||
| 		{ | 		{ | ||||||
| 			for (u32 j = 0; j < e_columnCount; ++j) | 			for (u32 j = 0; j < e_w; ++j) | ||||||
| 			{ | 			{ | ||||||
| 				for (u32 k = 0; k < e_depthCount; ++k) | 				for (u32 k = 0; k < e_d; ++k) | ||||||
| 				{ | 				{ | ||||||
| 					b3BodyDef bdef; | 					b3BodyDef bdef; | ||||||
| 					bdef.type = b3BodyType::e_dynamicBody; | 					bdef.type = e_dynamicBody; | ||||||
|  |  | ||||||
| 					bdef.position.x = float32(i) * sheetExtents.x; | 					bdef.position.Set(scalar(j), scalar(i), scalar(k)); | ||||||
| 					bdef.position.y = float32(j) * 50.0f * sheetExtents.y; |  | ||||||
| 					bdef.position.z = float32(k) * sheetExtents.z; | 					bdef.position.x *= scale.x; | ||||||
| 					bdef.position += stackOrigin; | 					bdef.position.y *= scale.y; | ||||||
|  | 					bdef.position.z *= scale.z; | ||||||
|  |  | ||||||
|  | 					bdef.position += translation; | ||||||
|  |  | ||||||
| 					b3Body* body = m_world.CreateBody(bdef); | 					b3Body* body = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
| 					b3HullShape hs; | 					b3HullShape hs; | ||||||
| 					hs.m_hull = &sheetHull; | 					hs.m_hull = &m_boxHull; | ||||||
|  |  | ||||||
| 					b3ShapeDef sdef; | 					b3ShapeDef sdef; | ||||||
|  | 					sdef.density = 0.1f; | ||||||
|  | 					sdef.friction = 0.3f; | ||||||
| 					sdef.shape = &hs; | 					sdef.shape = &hs; | ||||||
| 					sdef.density = 0.5f; |  | ||||||
| 					sdef.friction = 0.2f; |  | ||||||
|  |  | ||||||
| 					body->CreateShape(sdef); | 					body->CreateShape(sdef); | ||||||
|  |  | ||||||
|  | 					u32 bodyIndex = GetBodyIndex(i, j, k); | ||||||
|  |  | ||||||
|  | 					m_bodies[bodyIndex] = body; | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	u32 GetBodyIndex(u32 i, u32 j, u32 k) | ||||||
|  | 	{ | ||||||
|  | 		B3_ASSERT(i < e_h); | ||||||
|  | 		B3_ASSERT(j < e_w); | ||||||
|  | 		B3_ASSERT(k < e_d); | ||||||
|  | 		return k + e_d * (j + e_w * i); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	static Test* Create() | 	static Test* Create() | ||||||
| 	{ | 	{ | ||||||
| 		return new SheetStack(); | 		return new SheetStack(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	b3BoxHull m_boxHull; | ||||||
|  | 	b3Body* m_bodies[e_h * e_w * e_d]; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
| @@ -19,8 +19,6 @@ | |||||||
| #ifndef SMASH_SOFTBODY_H | #ifndef SMASH_SOFTBODY_H | ||||||
| #define SMASH_SOFTBODY_H | #define SMASH_SOFTBODY_H | ||||||
|  |  | ||||||
| #include <testbed/framework/softbody_dragger.h> |  | ||||||
|  |  | ||||||
| class SmashSoftBody : public Test | class SmashSoftBody : public Test | ||||||
| { | { | ||||||
| public: | public: | ||||||
| @@ -42,20 +40,13 @@ public: | |||||||
| 		def.c_yield = 0.6f; | 		def.c_yield = 0.6f; | ||||||
| 		def.c_creep = 1.0f; | 		def.c_creep = 1.0f; | ||||||
| 		def.c_max = 1.0f; | 		def.c_max = 1.0f; | ||||||
|  | 		def.radius = 0.05f; | ||||||
|  | 		def.friction = 0.2f; | ||||||
|  |  | ||||||
| 		m_body = new b3SoftBody(def); | 		m_body = new b3SoftBody(def); | ||||||
|  |  | ||||||
| 		b3Vec3 gravity(0.0f, -9.8f, 0.0f); | 		b3Vec3 gravity(0.0f, -9.8f, 0.0f); | ||||||
| 		m_body->SetGravity(gravity); | 		m_body->SetGravity(gravity); | ||||||
| 		m_body->SetWorld(&m_world); |  | ||||||
|  |  | ||||||
| 		for (u32 i = 0; i < m_mesh.vertexCount; ++i) |  | ||||||
| 		{ |  | ||||||
| 			b3SoftBodyNode* n = m_body->GetVertexNode(i); |  | ||||||
|  |  | ||||||
| 			n->SetRadius(0.05f); |  | ||||||
| 			n->SetFriction(0.2f); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// Create ground | 		// Create ground | ||||||
| 		{ | 		{ | ||||||
| @@ -71,28 +62,12 @@ public: | |||||||
| 			sd.shape = &groundShape; | 			sd.shape = &groundShape; | ||||||
| 			sd.friction = 0.3f; | 			sd.friction = 0.3f; | ||||||
|  |  | ||||||
| 			b->CreateShape(sd); | 			b3Shape* s = b->CreateShape(sd); | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// Create body | 			b3SoftBodyWorldShapeDef ssd; | ||||||
| 		{ | 			ssd.shape = s; | ||||||
| 			b3BodyDef bd; |  | ||||||
| 			bd.type = e_dynamicBody; |  | ||||||
| 			bd.position.y = 10.0f; |  | ||||||
|  |  | ||||||
| 			b3Body* b = m_world.CreateBody(bd); | 			m_body->CreateWorldShape(ssd);  | ||||||
|  |  | ||||||
| 			static b3BoxHull boxHull(5.0f, 1.0f, 5.0f); |  | ||||||
|  |  | ||||||
| 			b3HullShape boxShape; |  | ||||||
| 			boxShape.m_hull = &boxHull; |  | ||||||
|  |  | ||||||
| 			b3ShapeDef sd; |  | ||||||
| 			sd.shape = &boxShape; |  | ||||||
| 			sd.density = 0.1f; |  | ||||||
| 			sd.friction = 0.3f; |  | ||||||
|  |  | ||||||
| 			b->CreateShape(sd); |  | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		m_bodyDragger = new b3SoftBodyDragger(&m_ray, m_body); | 		m_bodyDragger = new b3SoftBodyDragger(&m_ray, m_body); | ||||||
| @@ -122,9 +97,9 @@ public: | |||||||
| 			b3Vec3 pA = m_bodyDragger->GetPointA(); | 			b3Vec3 pA = m_bodyDragger->GetPointA(); | ||||||
| 			b3Vec3 pB = m_bodyDragger->GetPointB(); | 			b3Vec3 pB = m_bodyDragger->GetPointB(); | ||||||
|  |  | ||||||
| 			g_draw->DrawPoint(pA, 2.0f, b3Color_green); | 			g_draw->DrawPoint(pA, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
| 			g_draw->DrawPoint(pB, 2.0f, b3Color_green); | 			g_draw->DrawPoint(pB, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
| 			g_draw->DrawSegment(pA, pB, b3Color_white); | 			g_draw->DrawSegment(pA, pB, b3Color_white); | ||||||
| 		} | 		} | ||||||
| @@ -132,7 +107,7 @@ public: | |||||||
| 		extern u32 b3_softBodySolverIterations; | 		extern u32 b3_softBodySolverIterations; | ||||||
| 		g_draw->DrawString(b3Color_white, "Iterations = %d", b3_softBodySolverIterations); | 		g_draw->DrawString(b3Color_white, "Iterations = %d", b3_softBodySolverIterations); | ||||||
|  |  | ||||||
| 		float32 E = m_body->GetEnergy(); | 		scalar E = m_body->GetEnergy(); | ||||||
| 		g_draw->DrawString(b3Color_white, "E = %f", E); | 		g_draw->DrawString(b3Color_white, "E = %f", E); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										177
									
								
								examples/testbed/tests/softbody_anchor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								examples/testbed/tests/softbody_anchor.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,177 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * 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 SOFTBODY_ANCHOR_H | ||||||
|  | #define SOFTBODY_ANCHOR_H | ||||||
|  |  | ||||||
|  | class SoftBodyAnchor : public Test | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	SoftBodyAnchor() | ||||||
|  | 	{ | ||||||
|  | 		m_mesh.SetAsSphere(4.0f, 0); | ||||||
|  |  | ||||||
|  | 		// Create soft body | ||||||
|  | 		b3SoftBodyDef def; | ||||||
|  | 		def.mesh = &m_mesh; | ||||||
|  | 		def.density = 0.2f; | ||||||
|  | 		def.E = 1000.0f; | ||||||
|  | 		def.nu = 0.33f; | ||||||
|  | 		def.c_yield = 0.1f; | ||||||
|  | 		def.c_creep = 0.5f; | ||||||
|  | 		def.c_max = 1.0f; | ||||||
|  | 		def.massDamping = 0.2f; | ||||||
|  |  | ||||||
|  | 		m_body = new b3SoftBody(def); | ||||||
|  |  | ||||||
|  | 		u32 pinIndex = ~0; | ||||||
|  | 		scalar pinDot = -B3_MAX_SCALAR; | ||||||
|  | 		for (u32 i = 0; i < m_mesh.vertexCount; ++i) | ||||||
|  | 		{ | ||||||
|  | 			scalar dot = b3Dot(m_mesh.vertices[i], b3Vec3_y); | ||||||
|  | 			if (dot > pinDot) | ||||||
|  | 			{ | ||||||
|  | 				pinDot = dot; | ||||||
|  | 				pinIndex = i; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		b3SoftBodyNode* pinNode = m_body->GetNode(pinIndex); | ||||||
|  | 		pinNode->SetType(e_staticSoftBodyNode); | ||||||
|  |  | ||||||
|  | 		u32 anchorIndex = ~0; | ||||||
|  | 		scalar anchorDot = -B3_MAX_SCALAR; | ||||||
|  | 		for (u32 i = 0; i < m_mesh.vertexCount; ++i) | ||||||
|  | 		{ | ||||||
|  | 			scalar dot = b3Dot(m_mesh.vertices[i], -b3Vec3_y); | ||||||
|  | 			if (dot > anchorDot) | ||||||
|  | 			{ | ||||||
|  | 				anchorDot = dot; | ||||||
|  | 				anchorIndex = i; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		b3SoftBodyNode* anchorNode = m_body->GetNode(anchorIndex); | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bd; | ||||||
|  | 			bd.type = e_dynamicBody; | ||||||
|  | 			bd.position.y = -10.0f; | ||||||
|  | 			 | ||||||
|  | 			b3Body* b = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
|  | 			b3CapsuleShape cs; | ||||||
|  | 			cs.m_vertex1.Set(0.0f, -1.0f, 0.0f); | ||||||
|  | 			cs.m_vertex2.Set(0.0f, 1.0f, 0.0f); | ||||||
|  | 			cs.m_radius = 1.0f; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sd; | ||||||
|  | 			sd.shape = &cs; | ||||||
|  | 			sd.density = 0.1f; | ||||||
|  |  | ||||||
|  | 			m_shape = b->CreateShape(sd); | ||||||
|  |  | ||||||
|  | 			// Create anchor | ||||||
|  | 			b3SoftBodyAnchorDef ad; | ||||||
|  | 			ad.Initialize(b, anchorNode, anchorNode->GetPosition()); | ||||||
|  | 			 | ||||||
|  | 			m_body->CreateAnchor(ad); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		b3Vec3 gravity(0.0f, -9.8f, 0.0f); | ||||||
|  | 		m_body->SetGravity(gravity); | ||||||
|  |  | ||||||
|  | 		m_bodyDragger = new b3SoftBodyDragger(&m_ray, m_body); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	~SoftBodyAnchor() | ||||||
|  | 	{ | ||||||
|  | 		delete m_bodyDragger; | ||||||
|  | 		delete m_body; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void Step() | ||||||
|  | 	{ | ||||||
|  | 		Test::Step(); | ||||||
|  |  | ||||||
|  | 		if (m_bodyDragger->IsDragging()) | ||||||
|  | 		{ | ||||||
|  | 			m_bodyDragger->Drag(); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		m_body->Step(g_testSettings->inv_hertz, g_testSettings->velocityIterations, g_testSettings->positionIterations); | ||||||
|  |  | ||||||
|  | 		m_body->Draw(); | ||||||
|  |  | ||||||
|  | 		if (m_bodyDragger->IsDragging()) | ||||||
|  | 		{ | ||||||
|  | 			b3Vec3 pA = m_bodyDragger->GetPointA(); | ||||||
|  | 			b3Vec3 pB = m_bodyDragger->GetPointB(); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawPoint(pA, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawPoint(pB, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawSegment(pA, pB, b3Color_white); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		extern u32 b3_softBodySolverIterations; | ||||||
|  | 		g_draw->DrawString(b3Color_white, "Iterations = %d", b3_softBodySolverIterations); | ||||||
|  |  | ||||||
|  | 		scalar E = m_body->GetEnergy(); | ||||||
|  | 		g_draw->DrawString(b3Color_white, "E = %f", E); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void MouseMove(const b3Ray3& pw) | ||||||
|  | 	{ | ||||||
|  | 		Test::MouseMove(pw); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void MouseLeftDown(const b3Ray3& pw) | ||||||
|  | 	{ | ||||||
|  | 		Test::MouseLeftDown(pw); | ||||||
|  |  | ||||||
|  | 		if (m_bodyDragger->IsDragging() == false) | ||||||
|  | 		{ | ||||||
|  | 			m_bodyDragger->StartDragging(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void MouseLeftUp(const b3Ray3& pw) | ||||||
|  | 	{ | ||||||
|  | 		Test::MouseLeftUp(pw); | ||||||
|  |  | ||||||
|  | 		if (m_bodyDragger->IsDragging() == true) | ||||||
|  | 		{ | ||||||
|  | 			m_bodyDragger->StopDragging(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	static Test* Create() | ||||||
|  | 	{ | ||||||
|  | 		return new SoftBodyAnchor(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b3QSoftBodyMesh m_mesh; | ||||||
|  |  | ||||||
|  | 	b3SoftBody* m_body; | ||||||
|  | 	b3SoftBodyDragger* m_bodyDragger; | ||||||
|  | 	b3Shape* m_shape; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
| @@ -24,70 +24,103 @@ class SphereStack : public Test | |||||||
| public: | public: | ||||||
| 	enum | 	enum | ||||||
| 	{ | 	{ | ||||||
| 		e_rowCount = 1, | 		e_h = 5, | ||||||
| 		e_columnCount = 5, | 		e_w = 1, | ||||||
| 		e_depthCount = 1 | 		e_d = 1 | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	SphereStack() | 	SphereStack() | ||||||
| 	{ | 	{ | ||||||
| 		{ | 		{ | ||||||
| 			b3BodyDef bd; | 			b3BodyDef bdef; | ||||||
| 			bd.type = e_staticBody; | 			b3Body* body = m_world.CreateBody(bdef); | ||||||
| 			b3Body* ground = m_world.CreateBody(bd); |  | ||||||
|  |  | ||||||
| 			b3HullShape hs; | 			b3HullShape hs; | ||||||
| 			hs.m_hull = &m_groundHull; | 			hs.m_hull = &m_groundHull; | ||||||
|  |  | ||||||
| 			b3ShapeDef sd; | 			b3ShapeDef sdef; | ||||||
| 			sd.shape = &hs; | 			sdef.shape = &hs; | ||||||
| 			sd.density = 0.0f; | 			sdef.friction = 1.0f; | ||||||
| 			sd.friction = 1.0f; |  | ||||||
| 			sd.restitution = 0.0f; |  | ||||||
|  |  | ||||||
| 			b3Shape* groundShape = ground->CreateShape(sd); | 			body->CreateShape(sdef); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		b3Vec3 stackOrigin; | 		scalar e = 1.0f; | ||||||
| 		stackOrigin.Set(0.0f, 5.0f, 0.0f); |  | ||||||
| 		float32 radius = 1.0f; |  | ||||||
| 		float32 diameter = 2.0f * radius; |  | ||||||
|  |  | ||||||
| 		for (u32 i = 0; i < e_rowCount; ++i) |  | ||||||
| 		{ |  | ||||||
| 			for (u32 j = 0; j < e_columnCount; ++j) |  | ||||||
| 			{ |  | ||||||
| 				for (u32 k = 0; k < e_depthCount; ++k) |  | ||||||
| 				{ |  | ||||||
| 					b3BodyDef bdef; |  | ||||||
| 					bdef.type = b3BodyType::e_dynamicBody; |  | ||||||
| 					bdef.position.x = float32(i) * diameter; |  | ||||||
| 					bdef.position.y = float32(j) * diameter; |  | ||||||
| 					bdef.position.z = float32(k) * diameter; |  | ||||||
| 					bdef.position += stackOrigin; |  | ||||||
| 					bdef.linearVelocity.Set(0.0f, -50.0f, 0.0f); |  | ||||||
|  |  | ||||||
| 					b3Body* body = m_world.CreateBody(bdef); |  | ||||||
|  |  | ||||||
| 		b3SphereShape sphere; | 		b3SphereShape sphere; | ||||||
| 		sphere.m_center.SetZero(); | 		sphere.m_center.SetZero(); | ||||||
| 					sphere.m_radius = radius; | 		sphere.m_radius = e; | ||||||
|  |  | ||||||
|  | 		b3Vec3 separation; | ||||||
|  | 		separation.x = 1.0f; | ||||||
|  | 		separation.y = 1.0f; | ||||||
|  | 		separation.z = 1.0f; | ||||||
|  |  | ||||||
|  | 		b3Vec3 scale; | ||||||
|  | 		scale.x = 2.0f * e + separation.x; | ||||||
|  | 		scale.y = 2.0f * e + separation.y; | ||||||
|  | 		scale.z = 2.0f * e + separation.z; | ||||||
|  |  | ||||||
|  | 		b3Vec3 size; | ||||||
|  | 		size.x = 2.0f * e + scale.x * scalar(e_w - 1); | ||||||
|  | 		size.y = 2.0f * e + scale.y * scalar(e_h - 1); | ||||||
|  | 		size.z = 2.0f * e + scale.z * scalar(e_d - 1); | ||||||
|  |  | ||||||
|  | 		b3Vec3 translation; | ||||||
|  | 		translation.x = e - 0.5f * size.x; | ||||||
|  | 		translation.y = e - 0.5f * size.y; | ||||||
|  | 		translation.z = e - 0.5f * size.z; | ||||||
|  |  | ||||||
|  | 		translation.y += 9.0f; | ||||||
|  |  | ||||||
|  | 		for (u32 i = 0; i < e_h; ++i) | ||||||
|  | 		{ | ||||||
|  | 			for (u32 j = 0; j < e_w; ++j) | ||||||
|  | 			{ | ||||||
|  | 				for (u32 k = 0; k < e_d; ++k) | ||||||
|  | 				{ | ||||||
|  | 					b3BodyDef bdef; | ||||||
|  | 					bdef.type = e_dynamicBody; | ||||||
|  |  | ||||||
|  | 					bdef.position.Set(scalar(j), scalar(i), scalar(k)); | ||||||
|  |  | ||||||
|  | 					bdef.position.x *= scale.x; | ||||||
|  | 					bdef.position.y *= scale.y; | ||||||
|  | 					bdef.position.z *= scale.z; | ||||||
|  |  | ||||||
|  | 					bdef.position += translation; | ||||||
|  |  | ||||||
|  | 					b3Body* body = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
| 					b3ShapeDef sdef; | 					b3ShapeDef sdef; | ||||||
| 					sdef.shape = &sphere; | 					sdef.density = 0.1f; | ||||||
| 					sdef.density = 1.0f; |  | ||||||
| 					sdef.friction = 0.3f; | 					sdef.friction = 0.3f; | ||||||
|  | 					sdef.shape = &sphere; | ||||||
|  |  | ||||||
| 					b3Shape* shape = body->CreateShape(sdef); | 					body->CreateShape(sdef); | ||||||
|  |  | ||||||
|  | 					u32 bodyIndex = GetBodyIndex(i, j, k); | ||||||
|  |  | ||||||
|  | 					m_bodies[bodyIndex] = body; | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	u32 GetBodyIndex(u32 i, u32 j, u32 k) | ||||||
|  | 	{ | ||||||
|  | 		B3_ASSERT(i < e_h); | ||||||
|  | 		B3_ASSERT(j < e_w); | ||||||
|  | 		B3_ASSERT(k < e_d); | ||||||
|  | 		return k + e_d * (j + e_w * i); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	static Test* Create() | 	static Test* Create() | ||||||
| 	{ | 	{ | ||||||
| 		return new SphereStack(); | 		return new SphereStack(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	b3Body* m_bodies[e_h * e_w * e_d]; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
| @@ -16,13 +16,13 @@ | |||||||
| * 3. This notice may not be removed or altered from any source distribution. | * 3. This notice may not be removed or altered from any source distribution. | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| #ifndef SPRING_H | #ifndef SPRING_TEST_H | ||||||
| #define SPRING_H | #define SPRING_TEST_H | ||||||
| 
 | 
 | ||||||
| class Spring : public Test | class SpringTest : public Test | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	Spring() | 	SpringTest() | ||||||
| 	{ | 	{ | ||||||
| 		{ | 		{ | ||||||
| 			b3BodyDef bd; | 			b3BodyDef bd; | ||||||
| @@ -38,13 +38,7 @@ public: | |||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// Car frame shape
 | 		// Car frame shape
 | ||||||
| 		{ | 		m_frameHull.SetExtents(2.0f, 0.5f, 5.0f); | ||||||
| 			b3Transform xf; |  | ||||||
| 			xf.SetIdentity(); |  | ||||||
| 			xf.rotation = b3Diagonal(2.0f, 0.5f, 5.0f); |  | ||||||
| 
 |  | ||||||
| 			m_frameHull.SetTransform(xf); |  | ||||||
| 		} |  | ||||||
| 
 | 
 | ||||||
| 		b3HullShape box; | 		b3HullShape box; | ||||||
| 		box.m_hull = &m_frameHull; | 		box.m_hull = &m_frameHull; | ||||||
| @@ -75,7 +69,7 @@ public: | |||||||
| 		{ | 		{ | ||||||
| 			b3BodyDef bdef; | 			b3BodyDef bdef; | ||||||
| 			bdef.type = e_dynamicBody; | 			bdef.type = e_dynamicBody; | ||||||
| 			bdef.position.Set(-1.0f, 7.0f, -4.5f); | 			bdef.position.Set(-1.0f, 7.0f, 4.5f); | ||||||
| 			bdef.fixedRotationY = true; | 			bdef.fixedRotationY = true; | ||||||
| 
 | 
 | ||||||
| 			wheelLF = m_world.CreateBody(bdef); | 			wheelLF = m_world.CreateBody(bdef); | ||||||
| @@ -90,7 +84,7 @@ public: | |||||||
| 
 | 
 | ||||||
| 		{ | 		{ | ||||||
| 			b3SpringJointDef def; | 			b3SpringJointDef def; | ||||||
| 			def.Initialize(frame, wheelLF, b3Vec3(-1.0f, 9.0f, -4.5), b3Vec3(-1.0f, 9.0f, -4.5f)); | 			def.Initialize(frame, wheelLF, b3Vec3(-1.0f, 9.0f, 4.5), b3Vec3(-1.0f, 9.0f, 4.5f)); | ||||||
| 			def.collideLinked = true; | 			def.collideLinked = true; | ||||||
| 			def.dampingRatio = 0.5f; | 			def.dampingRatio = 0.5f; | ||||||
| 			def.frequencyHz = 4.0f; | 			def.frequencyHz = 4.0f; | ||||||
| @@ -102,7 +96,7 @@ public: | |||||||
| 		{ | 		{ | ||||||
| 			b3BodyDef bdef; | 			b3BodyDef bdef; | ||||||
| 			bdef.type = e_dynamicBody; | 			bdef.type = e_dynamicBody; | ||||||
| 			bdef.position.Set(1.0f, 7.0, -4.5f); | 			bdef.position.Set(1.0f, 7.0, 4.5f); | ||||||
| 			bdef.fixedRotationY = true; | 			bdef.fixedRotationY = true; | ||||||
| 
 | 
 | ||||||
| 			wheelRF = m_world.CreateBody(bdef); | 			wheelRF = m_world.CreateBody(bdef); | ||||||
| @@ -117,7 +111,7 @@ public: | |||||||
| 
 | 
 | ||||||
| 		{ | 		{ | ||||||
| 			b3SpringJointDef def; | 			b3SpringJointDef def; | ||||||
| 			def.Initialize(frame, wheelRF, b3Vec3(1.0f, 9.0, -4.5), b3Vec3(1.0f, 9.0, -4.5f)); | 			def.Initialize(frame, wheelRF, b3Vec3(1.0f, 9.0, 4.5), b3Vec3(1.0f, 9.0, 4.5f)); | ||||||
| 			def.collideLinked = true; | 			def.collideLinked = true; | ||||||
| 			def.dampingRatio = 0.5f; | 			def.dampingRatio = 0.5f; | ||||||
| 			def.frequencyHz = 4.0f; | 			def.frequencyHz = 4.0f; | ||||||
| @@ -129,7 +123,7 @@ public: | |||||||
| 		{ | 		{ | ||||||
| 			b3BodyDef bdef; | 			b3BodyDef bdef; | ||||||
| 			bdef.type = e_dynamicBody; | 			bdef.type = e_dynamicBody; | ||||||
| 			bdef.position.Set(-1.0f, 7.0f, 4.5f); | 			bdef.position.Set(-1.0f, 7.0f, -4.5f); | ||||||
| 			bdef.fixedRotationY = true; | 			bdef.fixedRotationY = true; | ||||||
| 
 | 
 | ||||||
| 			wheelLB = m_world.CreateBody(bdef); | 			wheelLB = m_world.CreateBody(bdef); | ||||||
| @@ -144,7 +138,7 @@ public: | |||||||
| 
 | 
 | ||||||
| 		{ | 		{ | ||||||
| 			b3SpringJointDef def; | 			b3SpringJointDef def; | ||||||
| 			def.Initialize(frame, wheelLB, b3Vec3(-1.0f, 9.0f, 4.5f), b3Vec3(-1.0f, 9.0f, 4.5f)); | 			def.Initialize(frame, wheelLB, b3Vec3(-1.0f, 9.0f, -4.5f), b3Vec3(-1.0f, 9.0f, -4.5f)); | ||||||
| 			def.collideLinked = true; | 			def.collideLinked = true; | ||||||
| 			def.dampingRatio = 0.8f; | 			def.dampingRatio = 0.8f; | ||||||
| 			def.frequencyHz = 4.0f; | 			def.frequencyHz = 4.0f; | ||||||
| @@ -156,7 +150,7 @@ public: | |||||||
| 		{ | 		{ | ||||||
| 			b3BodyDef bdef; | 			b3BodyDef bdef; | ||||||
| 			bdef.type = e_dynamicBody; | 			bdef.type = e_dynamicBody; | ||||||
| 			bdef.position.Set(1.0f, 7.0f, 4.5f); | 			bdef.position.Set(1.0f, 7.0f, -4.5f); | ||||||
| 			bdef.fixedRotationY = true; | 			bdef.fixedRotationY = true; | ||||||
| 
 | 
 | ||||||
| 			wheelRB = m_world.CreateBody(bdef); | 			wheelRB = m_world.CreateBody(bdef); | ||||||
| @@ -171,7 +165,7 @@ public: | |||||||
| 
 | 
 | ||||||
| 		{ | 		{ | ||||||
| 			b3SpringJointDef def; | 			b3SpringJointDef def; | ||||||
| 			def.Initialize(frame, wheelRB, b3Vec3(1.0f, 9.0f, 4.5f), b3Vec3(1.0f, 9.0f, 4.5f)); | 			def.Initialize(frame, wheelRB, b3Vec3(1.0f, 9.0f, -4.5f), b3Vec3(1.0f, 9.0f, -4.5f)); | ||||||
| 			def.collideLinked = true; | 			def.collideLinked = true; | ||||||
| 			def.frequencyHz = 4.0f; | 			def.frequencyHz = 4.0f; | ||||||
| 			def.dampingRatio = 0.8f; | 			def.dampingRatio = 0.8f; | ||||||
| @@ -182,7 +176,7 @@ public: | |||||||
| 
 | 
 | ||||||
| 	static Test* Create() | 	static Test* Create() | ||||||
| 	{ | 	{ | ||||||
| 		return new Spring(); | 		return new SpringTest(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	b3BoxHull m_frameHull; | 	b3BoxHull m_frameHull; | ||||||
| @@ -22,6 +22,12 @@ | |||||||
| class TableCloth : public Test | class TableCloth : public Test | ||||||
| { | { | ||||||
| public: | public: | ||||||
|  | 	enum | ||||||
|  | 	{ | ||||||
|  | 		e_w = 10, | ||||||
|  | 		e_h = 10 | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
| 	TableCloth() | 	TableCloth() | ||||||
| 	{ | 	{ | ||||||
| 		// Translate the mesh | 		// Translate the mesh | ||||||
| @@ -35,15 +41,13 @@ public: | |||||||
| 		def.mesh = &m_clothMesh; | 		def.mesh = &m_clothMesh; | ||||||
| 		def.density = 0.2f; | 		def.density = 0.2f; | ||||||
| 		def.streching = 10000.0f; | 		def.streching = 10000.0f; | ||||||
| 		//def.shearing = 10000.0f; | 		def.strechDamping = 100.0f; | ||||||
| 		def.damping = 100.0f; |  | ||||||
| 		def.thickness = 0.2f; | 		def.thickness = 0.2f; | ||||||
| 		def.friction = 0.1f; | 		def.friction = 0.1f; | ||||||
|  |  | ||||||
| 		m_cloth = new b3Cloth(def); | 		m_cloth = new b3Cloth(def); | ||||||
|  |  | ||||||
| 		m_cloth->SetGravity(b3Vec3(0.0f, -9.8f, 0.0f)); | 		m_cloth->SetGravity(b3Vec3(0.0f, -9.8f, 0.0f)); | ||||||
| 		m_cloth->SetWorld(&m_world); |  | ||||||
|  |  | ||||||
| 		{ | 		{ | ||||||
| 			b3BodyDef bd; | 			b3BodyDef bd; | ||||||
| @@ -51,7 +55,7 @@ public: | |||||||
|  |  | ||||||
| 			b3Body* b = m_world.CreateBody(bd); | 			b3Body* b = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
| 			m_tableHull.SetAsCylinder(5.0f, 2.0f); | 			m_tableHull.SetExtents(5.0f, 2.0f); | ||||||
|  |  | ||||||
| 			b3HullShape tableShape; | 			b3HullShape tableShape; | ||||||
| 			tableShape.m_hull = &m_tableHull; | 			tableShape.m_hull = &m_tableHull; | ||||||
| @@ -60,7 +64,12 @@ public: | |||||||
| 			sd.shape = &tableShape; | 			sd.shape = &tableShape; | ||||||
| 			sd.friction = 1.0f; | 			sd.friction = 1.0f; | ||||||
|  |  | ||||||
| 			b->CreateShape(sd); | 			b3Shape* shape = b->CreateShape(sd); | ||||||
|  |  | ||||||
|  | 			b3ClothWorldShapeDef csd; | ||||||
|  | 			csd.shape = shape; | ||||||
|  |  | ||||||
|  | 			m_cloth->CreateWorldShape(csd); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		m_clothDragger = new b3ClothDragger(&m_ray, m_cloth); | 		m_clothDragger = new b3ClothDragger(&m_ray, m_cloth); | ||||||
| @@ -85,9 +94,9 @@ public: | |||||||
| 			b3Vec3 pA = m_clothDragger->GetPointA(); | 			b3Vec3 pA = m_clothDragger->GetPointA(); | ||||||
| 			b3Vec3 pB = m_clothDragger->GetPointB(); | 			b3Vec3 pB = m_clothDragger->GetPointB(); | ||||||
|  |  | ||||||
| 			g_draw->DrawPoint(pA, 2.0f, b3Color_green); | 			g_draw->DrawPoint(pA, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
| 			g_draw->DrawPoint(pB, 2.0f, b3Color_green); | 			g_draw->DrawPoint(pB, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
| 			g_draw->DrawSegment(pA, pB, b3Color_white); | 			g_draw->DrawSegment(pA, pB, b3Color_white); | ||||||
| 		} | 		} | ||||||
| @@ -95,7 +104,7 @@ public: | |||||||
| 		extern u32 b3_clothSolverIterations; | 		extern u32 b3_clothSolverIterations; | ||||||
| 		g_draw->DrawString(b3Color_white, "Iterations = %d", b3_clothSolverIterations); | 		g_draw->DrawString(b3Color_white, "Iterations = %d", b3_clothSolverIterations); | ||||||
|  |  | ||||||
| 		float32 E = m_cloth->GetEnergy(); | 		scalar E = m_cloth->GetEnergy(); | ||||||
| 		g_draw->DrawString(b3Color_white, "E = %f", E); | 		g_draw->DrawString(b3Color_white, "E = %f", E); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -134,11 +143,11 @@ public: | |||||||
| 		return new TableCloth(); | 		return new TableCloth(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	b3GridClothMesh<10, 10> m_clothMesh; | 	b3GridClothMesh<e_w, e_h> m_clothMesh; | ||||||
| 	b3Cloth* m_cloth; | 	b3Cloth* m_cloth; | ||||||
| 	b3ClothDragger* m_clothDragger; | 	b3ClothDragger* m_clothDragger; | ||||||
|  |  | ||||||
| 	b3QHull m_tableHull; | 	b3CylinderHull m_tableHull; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
| @@ -21,11 +21,11 @@ | |||||||
|  |  | ||||||
| // Hot/Cold color map | // Hot/Cold color map | ||||||
| // See http://paulbourke.net/miscellaneous/colourspace/ | // See http://paulbourke.net/miscellaneous/colourspace/ | ||||||
| static inline b3Color Color(float32 x, float32 a, float32 b) | static inline b3Color Color(scalar x, scalar a, scalar b) | ||||||
| { | { | ||||||
| 	x = b3Clamp(x, a, b); | 	x = b3Clamp(x, a, b); | ||||||
|  |  | ||||||
| 	float32 d = b - a; | 	scalar d = b - a; | ||||||
|  |  | ||||||
| 	b3Color c(1.0f, 1.0f, 1.0f);  | 	b3Color c(1.0f, 1.0f, 1.0f);  | ||||||
|  |  | ||||||
| @@ -58,6 +58,12 @@ static inline b3Color Color(float32 x, float32 a, float32 b) | |||||||
| class TensionMapping : public Test | class TensionMapping : public Test | ||||||
| { | { | ||||||
| public: | public: | ||||||
|  | 	enum | ||||||
|  | 	{ | ||||||
|  | 		e_w = 10, | ||||||
|  | 		e_h = 10 | ||||||
|  | 	}; | ||||||
|  |  | ||||||
| 	TensionMapping() | 	TensionMapping() | ||||||
| 	{ | 	{ | ||||||
| 		// Create cloth | 		// Create cloth | ||||||
| @@ -65,24 +71,25 @@ public: | |||||||
| 		def.mesh = &m_clothMesh; | 		def.mesh = &m_clothMesh; | ||||||
| 		def.density = 0.2f; | 		def.density = 0.2f; | ||||||
| 		def.streching = 10000.0f; | 		def.streching = 10000.0f; | ||||||
| 		def.shearing = 5000.0f; | 		def.strechDamping = 100.0f; | ||||||
| 		def.damping = 100.0f; | 		def.shearing = 1000.0f; | ||||||
|  | 		def.shearDamping = 10.0f; | ||||||
|  | 		def.bending = 1000.0f; | ||||||
|  | 		def.bendDamping = 10.0f; | ||||||
|  |  | ||||||
| 		m_cloth = new b3Cloth(def); | 		m_cloth = new b3Cloth(def); | ||||||
|  |  | ||||||
| 		m_cloth->SetGravity(b3Vec3(0.0f, -9.8f, 0.0f)); | 		m_cloth->SetGravity(b3Vec3(0.0f, -9.8f, 0.0f)); | ||||||
| 		m_cloth->SetWorld(&m_world); |  | ||||||
|  |  | ||||||
| 		// Freeze some particles | 		// Freeze some particles | ||||||
| 		b3AABB3 aabb; | 		for (u32 i = 0; i < 2; ++i) | ||||||
| 		aabb.m_lower.Set(-5.0f, -1.0f, -6.0f); | 		{ | ||||||
| 		aabb.m_upper.Set(5.0f, 1.0f, -4.0f); | 			for (u32 j = 0; j < e_w + 1; ++j) | ||||||
|  | 			{ | ||||||
|  | 				u32 v = m_clothMesh.GetVertex(i, j); | ||||||
| 				 | 				 | ||||||
| 		for (b3Particle* p = m_cloth->GetParticleList().m_head; p; p = p->GetNext()) | 				b3ClothParticle* p = m_cloth->GetParticle(v); | ||||||
| 		{ | 				p->SetType(e_staticClothParticle); | ||||||
| 			if (aabb.Contains(p->GetPosition())) |  | ||||||
| 			{ |  | ||||||
| 				p->SetType(e_staticParticle); |  | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @@ -103,8 +110,7 @@ public: | |||||||
|  |  | ||||||
| 		const b3ClothMesh* mesh = m_cloth->GetMesh(); | 		const b3ClothMesh* mesh = m_cloth->GetMesh(); | ||||||
|  |  | ||||||
| 		b3StackArray<b3Vec3, 256> tension; | 		b3Vec3 tension[(e_h + 1) * (e_w + 1)]; | ||||||
| 		tension.Resize(mesh->vertexCount); |  | ||||||
| 		for (u32 i = 0; i < mesh->vertexCount; ++i) | 		for (u32 i = 0; i < mesh->vertexCount; ++i) | ||||||
| 		{ | 		{ | ||||||
| 			tension[i].SetZero(); | 			tension[i].SetZero(); | ||||||
| @@ -112,66 +118,100 @@ public: | |||||||
|  |  | ||||||
| 		for (b3Force* f = m_cloth->GetForceList().m_head; f; f = f->GetNext()) | 		for (b3Force* f = m_cloth->GetForceList().m_head; f; f = f->GetNext()) | ||||||
| 		{ | 		{ | ||||||
| 			if (f->GetType() == e_strechForce) | 			if (f->GetType() == e_stretchForce) | ||||||
| 			{ | 			{ | ||||||
| 				b3StrechForce* s = (b3StrechForce*)f; | 				b3StretchForce* s = (b3StretchForce*)f; | ||||||
| 				 |  | ||||||
| 				b3ClothTriangle* triangle = s->GetTriangle(); |  | ||||||
| 				u32 triangleIndex = triangle->GetTriangle(); |  | ||||||
| 				b3ClothMeshTriangle* mesh_triangle = m_clothMesh.triangles + triangleIndex; |  | ||||||
| 				 |  | ||||||
| 				u32 v1 = mesh_triangle->v1; |  | ||||||
| 				u32 v2 = mesh_triangle->v2; |  | ||||||
| 				u32 v3 = mesh_triangle->v3; |  | ||||||
|  |  | ||||||
| 				b3Vec3 f1 = s->GetActionForce1(); | 				b3Vec3 f1 = s->GetActionForce1(); | ||||||
| 				b3Vec3 f2 = s->GetActionForce2(); | 				b3Vec3 f2 = s->GetActionForce2(); | ||||||
| 				b3Vec3 f3 = s->GetActionForce3(); | 				b3Vec3 f3 = s->GetActionForce3(); | ||||||
|  |  | ||||||
|  | 				b3ClothParticle* p1 = s->GetParticle1(); | ||||||
|  | 				b3ClothParticle* p2 = s->GetParticle2(); | ||||||
|  | 				b3ClothParticle* p3 = s->GetParticle3(); | ||||||
|  |  | ||||||
|  | 				u32 v1 = p1->GetMeshIndex(); | ||||||
|  | 				u32 v2 = p2->GetMeshIndex(); | ||||||
|  | 				u32 v3 = p3->GetMeshIndex(); | ||||||
|  |  | ||||||
| 				tension[v1] += f1; | 				tension[v1] += f1; | ||||||
| 				tension[v2] += f2; | 				tension[v2] += f2; | ||||||
| 				tension[v3] += f3; | 				tension[v3] += f3; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
|  | 		for (b3ClothParticle* p = m_cloth->GetParticleList().m_head; p; p = p->GetNext()) | ||||||
|  | 		{ | ||||||
|  | 			if (p->GetType() == e_staticClothParticle) | ||||||
|  | 			{ | ||||||
|  | 				b3Draw_draw->DrawPoint(p->GetPosition(), 4.0f, b3Color_white); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (p->GetType() == e_kinematicClothParticle) | ||||||
|  | 			{ | ||||||
|  | 				b3Draw_draw->DrawPoint(p->GetPosition(), 4.0f, b3Color_blue); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (p->GetType() == e_dynamicClothParticle) | ||||||
|  | 			{ | ||||||
|  | 				b3Draw_draw->DrawPoint(p->GetPosition(), 4.0f, b3Color_green); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		for (u32 i = 0; i < mesh->triangleCount; ++i) | 		for (u32 i = 0; i < mesh->triangleCount; ++i) | ||||||
| 		{ | 		{ | ||||||
| 			b3ClothMeshTriangle* t = mesh->triangles + i; | 			b3ClothMeshTriangle* triangle = mesh->triangles + i; | ||||||
|  |  | ||||||
| 			b3Vec3 v1 = m_cloth->GetParticle(t->v1)->GetPosition(); | 			b3Vec3 v1 = m_cloth->GetParticle(triangle->v1)->GetPosition(); | ||||||
| 			b3Vec3 v2 = m_cloth->GetParticle(t->v2)->GetPosition(); | 			b3Vec3 v2 = m_cloth->GetParticle(triangle->v2)->GetPosition(); | ||||||
| 			b3Vec3 v3 = m_cloth->GetParticle(t->v3)->GetPosition(); | 			b3Vec3 v3 = m_cloth->GetParticle(triangle->v3)->GetPosition(); | ||||||
|  |  | ||||||
| 			g_draw->DrawTriangle(v1, v2, v3, b3Color_black); | 			g_draw->DrawTriangle(v1, v2, v3, b3Color_black); | ||||||
|  |  | ||||||
| 			b3Vec3 c = (v1 + v2 + v3) / 3.0f; | 			b3Vec3 c = (v1 + v2 + v3) / 3.0f; | ||||||
|  |  | ||||||
| 			float32 s = 0.9f; | 			scalar s = 0.9f; | ||||||
|  |  | ||||||
| 			v1 = s * (v1 - c) + c; | 			v1 = s * (v1 - c) + c; | ||||||
| 			v2 = s * (v2 - c) + c; | 			v2 = s * (v2 - c) + c; | ||||||
| 			v3 = s * (v3 - c) + c; | 			v3 = s * (v3 - c) + c; | ||||||
|  |  | ||||||
| 			b3Vec3 f1 = tension[t->v1]; | 			b3Vec3 f1 = tension[triangle->v1]; | ||||||
| 			float32 L1 = b3Length(f1); | 			scalar L1 = b3Length(f1); | ||||||
|  |  | ||||||
| 			b3Vec3 f2 = tension[t->v2]; | 			b3Vec3 f2 = tension[triangle->v2]; | ||||||
| 			float32 L2 = b3Length(f2); | 			scalar L2 = b3Length(f2); | ||||||
|  |  | ||||||
| 			b3Vec3 f3 = tension[t->v3]; | 			b3Vec3 f3 = tension[triangle->v3]; | ||||||
| 			float32 L3 = b3Length(f3); | 			scalar L3 = b3Length(f3); | ||||||
|  |  | ||||||
| 			float32 L = (L1 + L2 + L3) / 3.0f; | 			scalar L = (L1 + L2 + L3) / 3.0f; | ||||||
|  |  | ||||||
| 			const float32 kMaxT = 10000.0f; | 			const scalar kMaxT = 10000.0f; | ||||||
| 			b3Color color = Color(L, 0.0f, kMaxT); | 			b3Color color = Color(L, 0.0f, kMaxT); | ||||||
| 			 | 			 | ||||||
| 			b3Vec3 n1 = b3Cross(v2 - v1, v3 - v1); | 			b3Vec3 n1 = b3Cross(v2 - v1, v3 - v1); | ||||||
| 			n1.Normalize(); | 			n1.Normalize(); | ||||||
| 			g_draw->DrawSolidTriangle(n1, v1, v2, v3, color); |  | ||||||
|  |  | ||||||
|  | 			scalar r = 0.05f; | ||||||
|  |  | ||||||
|  | 			{ | ||||||
|  | 				b3Vec3 x1 = v1 + r * n1; | ||||||
|  | 				b3Vec3 x2 = v2 + r * n1; | ||||||
|  | 				b3Vec3 x3 = v3 + r * n1; | ||||||
|  |  | ||||||
|  | 				g_draw->DrawSolidTriangle(n1, x1, x2, x3, color); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			{ | ||||||
| 				b3Vec3 n2 = -n1; | 				b3Vec3 n2 = -n1; | ||||||
| 			g_draw->DrawSolidTriangle(n2, v3, v2, v1, color); |  | ||||||
|  | 				b3Vec3 x1 = v1 + r * n2; | ||||||
|  | 				b3Vec3 x2 = v2 + r * n2; | ||||||
|  | 				b3Vec3 x3 = v3 + r * n2; | ||||||
|  |  | ||||||
|  | 				g_draw->DrawSolidTriangle(n2, x3, x2, x1, color); | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (m_clothDragger->IsDragging()) | 		if (m_clothDragger->IsDragging()) | ||||||
| @@ -179,9 +219,9 @@ public: | |||||||
| 			b3Vec3 pA = m_clothDragger->GetPointA(); | 			b3Vec3 pA = m_clothDragger->GetPointA(); | ||||||
| 			b3Vec3 pB = m_clothDragger->GetPointB(); | 			b3Vec3 pB = m_clothDragger->GetPointB(); | ||||||
|  |  | ||||||
| 			g_draw->DrawPoint(pA, 2.0f, b3Color_green); | 			g_draw->DrawPoint(pA, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
| 			g_draw->DrawPoint(pB, 2.0f, b3Color_green); | 			g_draw->DrawPoint(pB, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
| 			g_draw->DrawSegment(pA, pB, b3Color_white); | 			g_draw->DrawSegment(pA, pB, b3Color_white); | ||||||
| 		} | 		} | ||||||
| @@ -189,7 +229,7 @@ public: | |||||||
| 		extern u32 b3_clothSolverIterations; | 		extern u32 b3_clothSolverIterations; | ||||||
| 		g_draw->DrawString(b3Color_white, "Iterations = %d", b3_clothSolverIterations); | 		g_draw->DrawString(b3Color_white, "Iterations = %d", b3_clothSolverIterations); | ||||||
|  |  | ||||||
| 		float32 E = m_cloth->GetEnergy(); | 		scalar E = m_cloth->GetEnergy(); | ||||||
| 		g_draw->DrawString(b3Color_white, "E = %f", E); | 		g_draw->DrawString(b3Color_white, "E = %f", E); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -228,7 +268,7 @@ public: | |||||||
| 		return new TensionMapping(); | 		return new TensionMapping(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	b3GridClothMesh<10, 10> m_clothMesh; | 	b3GridClothMesh<e_w, e_h> m_clothMesh; | ||||||
| 	b3Cloth* m_cloth; | 	b3Cloth* m_cloth; | ||||||
| 	b3ClothDragger* m_clothDragger;  | 	b3ClothDragger* m_clothDragger;  | ||||||
| }; | }; | ||||||
|   | |||||||
							
								
								
									
										413
									
								
								examples/testbed/tests/tetgen_softbody.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										413
									
								
								examples/testbed/tests/tetgen_softbody.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,413 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * 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 TETGEN_SOFTBODY_H | ||||||
|  | #define TETGEN_SOFTBODY_H | ||||||
|  |  | ||||||
|  | #include <fstream> | ||||||
|  |  | ||||||
|  | struct TetGenMesh : public b3SoftBodyMesh | ||||||
|  | { | ||||||
|  | 	TetGenMesh() | ||||||
|  | 	{ | ||||||
|  | 		vertexCount = 0; | ||||||
|  | 		vertices = nullptr; | ||||||
|  | 		triangleCount = 0; | ||||||
|  | 		triangles = nullptr; | ||||||
|  | 		tetrahedronCount = 0; | ||||||
|  | 		tetrahedrons = nullptr; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	~TetGenMesh() | ||||||
|  | 	{ | ||||||
|  | 		free(vertices); | ||||||
|  | 		free(triangles); | ||||||
|  | 		free(tetrahedrons); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	bool Load(const char* node_filename, const char* face_filename, const char* ele_filename) | ||||||
|  | 	{ | ||||||
|  | 		{ | ||||||
|  | 			std::ifstream file(node_filename); | ||||||
|  | 			if (!file.good()) | ||||||
|  | 			{ | ||||||
|  | 				printf("Could not open %s \n", node_filename); | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			int nodeCount, nodeDimensions, attributeCount, boundaryMarkCount; | ||||||
|  |  | ||||||
|  | 			std::string line; | ||||||
|  | 			while (std::getline(file, line)) | ||||||
|  | 			{ | ||||||
|  | 				if (line[0] == '#') | ||||||
|  | 				{ | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				if (line[0] == 0) | ||||||
|  | 				{ | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				std::stringstream line_stream(line); | ||||||
|  |  | ||||||
|  | 				line_stream >> nodeCount >> nodeDimensions >> attributeCount >> boundaryMarkCount; | ||||||
|  |  | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (nodeDimensions != 3) | ||||||
|  | 			{ | ||||||
|  | 				printf(".node file: Only 3 dimensional nodes supported\n"); | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (attributeCount != 0) | ||||||
|  | 			{ | ||||||
|  | 				printf(".node file: Only nodes with 0 attributes supported\n"); | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (boundaryMarkCount != 0) | ||||||
|  | 			{ | ||||||
|  | 				printf(".node file: Only nodes with 0 markers supported\n"); | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			assert(vertexCount == 0); | ||||||
|  | 			vertices = (b3Vec3*)malloc(sizeof(b3Vec3) * nodeCount); | ||||||
|  |  | ||||||
|  | 			while (std::getline(file, line)) | ||||||
|  | 			{ | ||||||
|  | 				if (line[0] == '#') | ||||||
|  | 				{ | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				if (line[0] == 0) | ||||||
|  | 				{ | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				int nodeId; | ||||||
|  | 				float x, y, z; | ||||||
|  |  | ||||||
|  | 				std::stringstream line_stream(line); | ||||||
|  |  | ||||||
|  | 				line_stream >> nodeId >> x >> y >> z; | ||||||
|  |  | ||||||
|  | 				assert(nodeId > 0); | ||||||
|  | 				assert(nodeId <= nodeCount); | ||||||
|  |  | ||||||
|  | 				assert(b3IsValid(x)); | ||||||
|  | 				assert(b3IsValid(y)); | ||||||
|  | 				assert(b3IsValid(z)); | ||||||
|  |  | ||||||
|  | 				vertices[vertexCount].x = x; | ||||||
|  | 				vertices[vertexCount].y = y; | ||||||
|  | 				vertices[vertexCount].z = z; | ||||||
|  |  | ||||||
|  | 				++vertexCount; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			assert(vertexCount == nodeCount); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		{ | ||||||
|  | 			std::ifstream file(face_filename); | ||||||
|  | 			if (!file.good()) | ||||||
|  | 			{ | ||||||
|  | 				printf("Could not open %s \n", face_filename); | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			int faceCount, boundaryMarkerCount; | ||||||
|  |  | ||||||
|  | 			std::string line; | ||||||
|  | 			while (std::getline(file, line)) | ||||||
|  | 			{ | ||||||
|  | 				if (line[0] == '#') | ||||||
|  | 				{ | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				if (line[0] == 0) | ||||||
|  | 				{ | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				std::stringstream line_stream(line); | ||||||
|  |  | ||||||
|  | 				line_stream >> faceCount >> boundaryMarkerCount; | ||||||
|  |  | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			assert(triangleCount == 0); | ||||||
|  | 			triangles = (b3SoftBodyMeshTriangle*)malloc(sizeof(b3SoftBodyMeshTriangle) * faceCount); | ||||||
|  |  | ||||||
|  | 			while (std::getline(file, line)) | ||||||
|  | 			{ | ||||||
|  | 				if (line[0] == '#') | ||||||
|  | 				{ | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				if (line[0] == 0) | ||||||
|  | 				{ | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				int faceId; | ||||||
|  | 				int v1, v2, v3; | ||||||
|  | 				int corner; | ||||||
|  |  | ||||||
|  | 				std::stringstream line_stream(line); | ||||||
|  |  | ||||||
|  | 				line_stream >> faceId >> v1 >> v2 >> v3 >> corner; | ||||||
|  |  | ||||||
|  | 				assert(faceId > 0); | ||||||
|  | 				assert(faceId <= faceCount); | ||||||
|  |  | ||||||
|  | 				// Make CCW | ||||||
|  | 				b3Swap(v2, v3); | ||||||
|  |  | ||||||
|  | 				triangles[triangleCount].v1 = u32(v1 - 1); | ||||||
|  | 				triangles[triangleCount].v2 = u32(v2 - 1); | ||||||
|  | 				triangles[triangleCount].v3 = u32(v3 - 1); | ||||||
|  |  | ||||||
|  | 				++triangleCount; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			assert(triangleCount == faceCount); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			std::ifstream file(ele_filename); | ||||||
|  | 			if (!file.good()) | ||||||
|  | 			{ | ||||||
|  | 				printf("Could not open %s \n", ele_filename); | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			int tetCount, nodesPerTet, attributeCount; | ||||||
|  |  | ||||||
|  | 			std::string line; | ||||||
|  | 			while (std::getline(file, line)) | ||||||
|  | 			{ | ||||||
|  | 				if (line[0] == '#') | ||||||
|  | 				{ | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				if (line[0] == 0) | ||||||
|  | 				{ | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				std::stringstream line_stream(line); | ||||||
|  |  | ||||||
|  | 				line_stream >> tetCount >> nodesPerTet >> attributeCount; | ||||||
|  |  | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (nodesPerTet != 4) | ||||||
|  | 			{ | ||||||
|  | 				printf(".ele file: Only 4 nodes per tetrahedran supported\n"); | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (attributeCount != 0) | ||||||
|  | 			{ | ||||||
|  | 				printf(".ele file: Only elements with 0 attributes supported\n"); | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			assert(tetrahedronCount == 0); | ||||||
|  | 			tetrahedrons = (b3SoftBodyMeshTetrahedron*)malloc(sizeof(b3SoftBodyMeshTetrahedron) * tetCount); | ||||||
|  |  | ||||||
|  | 			while (std::getline(file, line)) | ||||||
|  | 			{ | ||||||
|  | 				if (line[0] == '#') | ||||||
|  | 				{ | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				if (line[0] == 0) | ||||||
|  | 				{ | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				int tetId; | ||||||
|  | 				int v1, v2, v3, v4; | ||||||
|  |  | ||||||
|  | 				std::stringstream line_stream(line); | ||||||
|  |  | ||||||
|  | 				line_stream >> tetId >> v1 >> v2 >> v3 >> v4; | ||||||
|  |  | ||||||
|  | 				assert(tetId > 0); | ||||||
|  | 				assert(tetId <= tetCount); | ||||||
|  |  | ||||||
|  | 				// Make CCW | ||||||
|  | 				b3Swap(v2, v3); | ||||||
|  |  | ||||||
|  | 				tetrahedrons[tetrahedronCount].v1 = u32(v1 - 1); | ||||||
|  | 				tetrahedrons[tetrahedronCount].v2 = u32(v2 - 1); | ||||||
|  | 				tetrahedrons[tetrahedronCount].v3 = u32(v3 - 1); | ||||||
|  | 				tetrahedrons[tetrahedronCount].v4 = u32(v4 - 1); | ||||||
|  |  | ||||||
|  | 				++tetrahedronCount; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			assert(tetrahedronCount == tetCount); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class TetGenSoftBody : public Test | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	TetGenSoftBody() | ||||||
|  | 	{ | ||||||
|  | 		{ | ||||||
|  | 			bool ok = m_mesh.Load("data/octopus.node", "data/octopus.face", "data/octopus.ele"); | ||||||
|  | 			assert(ok); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		for (u32 i = 0; i < m_mesh.vertexCount; ++i) | ||||||
|  | 		{ | ||||||
|  | 			m_mesh.vertices[i].y += 10.0f; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Create soft body | ||||||
|  | 		b3SoftBodyDef def; | ||||||
|  | 		def.mesh = &m_mesh; | ||||||
|  | 		def.density = 0.2f; | ||||||
|  | 		def.E = 1000.0f; | ||||||
|  | 		def.nu = 0.3f; | ||||||
|  | 		def.radius = 0.05f; | ||||||
|  | 		def.friction = 0.2f; | ||||||
|  |  | ||||||
|  | 		m_body = new b3SoftBody(def); | ||||||
|  |  | ||||||
|  | 		b3Vec3 gravity(0.0f, -9.8f, 0.0f); | ||||||
|  | 		m_body->SetGravity(gravity); | ||||||
|  |  | ||||||
|  | 		// Create ground | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bd; | ||||||
|  | 			bd.type = e_staticBody; | ||||||
|  |  | ||||||
|  | 			b3Body* b = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
|  | 			b3HullShape groundShape; | ||||||
|  | 			groundShape.m_hull = &m_groundHull; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sd; | ||||||
|  | 			sd.shape = &groundShape; | ||||||
|  | 			sd.friction = 0.3f; | ||||||
|  |  | ||||||
|  | 			b3Shape* s = b->CreateShape(sd); | ||||||
|  |  | ||||||
|  | 			b3SoftBodyWorldShapeDef ssd; | ||||||
|  | 			ssd.shape = s; | ||||||
|  |  | ||||||
|  | 			m_body->CreateWorldShape(ssd);  | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		m_bodyDragger = new b3SoftBodyDragger(&m_ray, m_body); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	~TetGenSoftBody() | ||||||
|  | 	{ | ||||||
|  | 		delete m_bodyDragger; | ||||||
|  | 		delete m_body; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void Step() | ||||||
|  | 	{ | ||||||
|  | 		Test::Step(); | ||||||
|  |  | ||||||
|  | 		if (m_bodyDragger->IsDragging()) | ||||||
|  | 		{ | ||||||
|  | 			m_bodyDragger->Drag(); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		m_body->Step(g_testSettings->inv_hertz, g_testSettings->velocityIterations, g_testSettings->positionIterations); | ||||||
|  |  | ||||||
|  | 		m_body->Draw(); | ||||||
|  |  | ||||||
|  | 		if (m_bodyDragger->IsDragging()) | ||||||
|  | 		{ | ||||||
|  | 			b3Vec3 pA = m_bodyDragger->GetPointA(); | ||||||
|  | 			b3Vec3 pB = m_bodyDragger->GetPointB(); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawPoint(pA, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawPoint(pB, 4.0f, b3Color_green); | ||||||
|  |  | ||||||
|  | 			g_draw->DrawSegment(pA, pB, b3Color_white); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		extern u32 b3_softBodySolverIterations; | ||||||
|  | 		g_draw->DrawString(b3Color_white, "Iterations = %d", b3_softBodySolverIterations); | ||||||
|  |  | ||||||
|  | 		scalar E = m_body->GetEnergy(); | ||||||
|  | 		g_draw->DrawString(b3Color_white, "E = %f", E); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void MouseMove(const b3Ray3& pw) | ||||||
|  | 	{ | ||||||
|  | 		Test::MouseMove(pw); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void MouseLeftDown(const b3Ray3& pw) | ||||||
|  | 	{ | ||||||
|  | 		Test::MouseLeftDown(pw); | ||||||
|  |  | ||||||
|  | 		if (m_bodyDragger->IsDragging() == false) | ||||||
|  | 		{ | ||||||
|  | 			m_bodyDragger->StartDragging(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void MouseLeftUp(const b3Ray3& pw) | ||||||
|  | 	{ | ||||||
|  | 		Test::MouseLeftUp(pw); | ||||||
|  |  | ||||||
|  | 		if (m_bodyDragger->IsDragging() == true) | ||||||
|  | 		{ | ||||||
|  | 			m_bodyDragger->StopDragging(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	static Test* Create() | ||||||
|  | 	{ | ||||||
|  | 		return new TetGenSoftBody(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	TetGenMesh m_mesh; | ||||||
|  | 	b3SoftBody* m_body; | ||||||
|  | 	b3SoftBodyDragger* m_bodyDragger; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										237
									
								
								examples/testbed/tests/time_of_impact.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										237
									
								
								examples/testbed/tests/time_of_impact.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,237 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * 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 TIME_OF_IMPACT_H | ||||||
|  | #define TIME_OF_IMPACT_H | ||||||
|  |  | ||||||
|  | class TimeOfImpact : public Test | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	TimeOfImpact() | ||||||
|  | 	{ | ||||||
|  | 		m_shapeA.m_hull = &b3BoxHull_identity; | ||||||
|  | 		m_shapeA.m_radius = 0.0f; | ||||||
|  |  | ||||||
|  | 		m_shapeB.m_hull = &b3BoxHull_identity; | ||||||
|  | 		m_shapeB.m_radius = 0.0f; | ||||||
|  |  | ||||||
|  | 		m_sweepA.localCenter.SetZero(); | ||||||
|  | 		m_sweepA.worldCenter0.Set(0.0f, 0.0f, 5.0f); | ||||||
|  | 		m_sweepA.worldCenter.Set(0.0f, 0.0f, -5.0f); | ||||||
|  | 		m_sweepA.orientation0.SetIdentity(); | ||||||
|  | 		m_sweepA.orientation.SetIdentity(); | ||||||
|  |  | ||||||
|  | 		m_sweepB.localCenter.SetZero(); | ||||||
|  | 		m_sweepB.worldCenter0.Set(5.0f, 0.0f, 0.0f); | ||||||
|  | 		m_sweepB.worldCenter.Set(-5.0f, 0.0f, 0.0f); | ||||||
|  | 		m_sweepB.orientation0.SetIdentity(); | ||||||
|  | 		m_sweepB.orientation.SetIdentity(); | ||||||
|  | 		 | ||||||
|  | 		m_proxyA.Set(&m_shapeA, 0); | ||||||
|  | 		m_proxyB.Set(&m_shapeB, 0); | ||||||
|  |  | ||||||
|  | 		m_time = 0.0f; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void Step() | ||||||
|  | 	{ | ||||||
|  | 		b3Color colorA0(1.0f, 0.0f, 0.0f, 1.0f); | ||||||
|  | 		b3Color colorB0(0.0f, 1.0f, 0.0f, 1.0f); | ||||||
|  |  | ||||||
|  | 		// t0 | ||||||
|  | 		b3Transform xfA0 = m_sweepA.GetTransform(0.0f); | ||||||
|  | 		b3Transform xfB0 = m_sweepB.GetTransform(0.0f); | ||||||
|  |  | ||||||
|  | 		g_draw->DrawTransform(xfA0); | ||||||
|  | 		g_draw->DrawTransform(xfB0); | ||||||
|  |  | ||||||
|  | 		m_world.DrawShape(xfA0, &m_shapeA, b3Color_black); | ||||||
|  | 		m_world.DrawShape(xfB0, &m_shapeB, b3Color_black); | ||||||
|  |  | ||||||
|  | 		m_world.DrawSolidShape(xfA0, &m_shapeA, colorA0); | ||||||
|  | 		m_world.DrawSolidShape(xfB0, &m_shapeB, colorB0); | ||||||
|  |  | ||||||
|  | 		// t1 | ||||||
|  | 		b3Transform xfA1 = m_sweepA.GetTransform(1.0f); | ||||||
|  | 		b3Transform xfB1 = m_sweepB.GetTransform(1.0f); | ||||||
|  |  | ||||||
|  | 		g_draw->DrawTransform(xfA1); | ||||||
|  | 		g_draw->DrawTransform(xfB1); | ||||||
|  |  | ||||||
|  | 		m_world.DrawShape(xfA1, &m_shapeA, b3Color_black); | ||||||
|  | 		m_world.DrawShape(xfB1, &m_shapeB, b3Color_black); | ||||||
|  |  | ||||||
|  | 		m_world.DrawSolidShape(xfA1, &m_shapeA, colorA0); | ||||||
|  | 		m_world.DrawSolidShape(xfB1, &m_shapeB, colorB0); | ||||||
|  |  | ||||||
|  | 		// time | ||||||
|  | 		b3Color colorAt(1.0f, 0.0f, 0.0f, 0.5f); | ||||||
|  | 		b3Color colorBt(0.0f, 1.0f, 0.0f, 0.5f); | ||||||
|  |  | ||||||
|  | 		b3Transform xfAx = m_sweepA.GetTransform(m_time); | ||||||
|  | 		b3Transform xfBx = m_sweepB.GetTransform(m_time); | ||||||
|  |  | ||||||
|  | 		g_draw->DrawTransform(xfAx); | ||||||
|  | 		g_draw->DrawTransform(xfBx); | ||||||
|  |  | ||||||
|  | 		m_world.DrawShape(xfAx, &m_shapeA, b3Color_black); | ||||||
|  | 		m_world.DrawShape(xfBx, &m_shapeB, b3Color_black); | ||||||
|  |  | ||||||
|  | 		m_world.DrawSolidShape(xfAx, &m_shapeA, colorAt); | ||||||
|  | 		m_world.DrawSolidShape(xfBx, &m_shapeB, colorBt); | ||||||
|  |  | ||||||
|  | 		b3TOIInput input; | ||||||
|  | 		input.proxyA = m_proxyA; | ||||||
|  | 		input.sweepA = m_sweepA; | ||||||
|  | 		input.proxyB = m_proxyB; | ||||||
|  | 		input.sweepB = m_sweepB; | ||||||
|  | 		input.tMax = 1.0f; | ||||||
|  |  | ||||||
|  | 		b3TOIOutput output = b3TimeOfImpact(input); | ||||||
|  |  | ||||||
|  | 		if (output.state == b3TOIOutput::e_touching) | ||||||
|  | 		{ | ||||||
|  | 			b3Transform xfAt = m_sweepA.GetTransform(output.t); | ||||||
|  | 			b3Transform xfBt = m_sweepB.GetTransform(output.t); | ||||||
|  |  | ||||||
|  | 			m_world.DrawShape(xfAt, &m_shapeA, b3Color_black); | ||||||
|  | 			m_world.DrawShape(xfBt, &m_shapeB, b3Color_black); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		g_draw->DrawString(b3Color_white, "Left/Right/Up/Down Arrow/W/S - Translate shape"); | ||||||
|  | 		g_draw->DrawString(b3Color_white, "X/Y/Z - Rotate shape"); | ||||||
|  | 		g_draw->DrawString(b3Color_white, "F/B - Advance Time Forwards/Backwards"); | ||||||
|  | 		g_draw->DrawString(b3Color_white, "Iterations = %d", output.iterations); | ||||||
|  |  | ||||||
|  | 		if (output.state == b3TOIOutput::e_failed) | ||||||
|  | 		{ | ||||||
|  | 			g_draw->DrawString(b3Color_white, "State = Failed"); | ||||||
|  | 		} | ||||||
|  | 		else if (output.state == b3TOIOutput::e_overlapped) | ||||||
|  | 		{ | ||||||
|  | 			g_draw->DrawString(b3Color_white, "State = Overlapped"); | ||||||
|  | 		} | ||||||
|  | 		else if (output.state == b3TOIOutput::e_separated) | ||||||
|  | 		{ | ||||||
|  | 			g_draw->DrawString(b3Color_white, "State = Separated!"); | ||||||
|  | 		} | ||||||
|  | 		else if (output.state == b3TOIOutput::e_touching) | ||||||
|  | 		{ | ||||||
|  | 			g_draw->DrawString(b3Color_white, "State = Touching!"); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		g_draw->DrawString(b3Color_white, m_sweepA.worldCenter0, "t0"); | ||||||
|  | 		g_draw->DrawString(b3Color_white, m_sweepA.worldCenter, "t1"); | ||||||
|  |  | ||||||
|  | 		g_draw->DrawString(b3Color_white, m_sweepB.worldCenter0, "t0"); | ||||||
|  | 		g_draw->DrawString(b3Color_white, m_sweepB.worldCenter, "t1"); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void KeyDown(int key) | ||||||
|  | 	{ | ||||||
|  | 		const scalar dt = 0.01f; | ||||||
|  | 		const scalar d = 0.15f; | ||||||
|  | 		const scalar theta = 0.05f * B3_PI; | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_F) | ||||||
|  | 		{ | ||||||
|  | 			m_time += dt; | ||||||
|  | 			if (m_time > 1.0f) | ||||||
|  | 			{ | ||||||
|  | 				m_time = 0.0f; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_B) | ||||||
|  | 		{ | ||||||
|  | 			m_time -= dt; | ||||||
|  | 			if (m_time < 0.0f) | ||||||
|  | 			{ | ||||||
|  | 				m_time = 1.0f; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		if (key == GLFW_KEY_LEFT) | ||||||
|  | 		{ | ||||||
|  | 			m_sweepB.worldCenter0.x -= d; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_RIGHT) | ||||||
|  | 		{ | ||||||
|  | 			m_sweepB.worldCenter0.x += d; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_UP) | ||||||
|  | 		{ | ||||||
|  | 			m_sweepB.worldCenter0.y += d; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_DOWN) | ||||||
|  | 		{ | ||||||
|  | 			m_sweepB.worldCenter0.y -= d; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_S) | ||||||
|  | 		{ | ||||||
|  | 			m_sweepB.worldCenter0.z += d; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_W) | ||||||
|  | 		{ | ||||||
|  | 			m_sweepB.worldCenter0.z -= d; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		if (key == GLFW_KEY_X) | ||||||
|  | 		{ | ||||||
|  | 			b3Quat qx = b3QuatRotationX(theta); | ||||||
|  |  | ||||||
|  | 			m_sweepB.orientation0 = m_sweepB.orientation0 * qx; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_Y) | ||||||
|  | 		{ | ||||||
|  | 			b3Quat qy = b3QuatRotationY(theta); | ||||||
|  |  | ||||||
|  | 			m_sweepB.orientation0 = m_sweepB.orientation0 * qy; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_Z) | ||||||
|  | 		{ | ||||||
|  | 			b3Quat qz = b3QuatRotationZ(theta); | ||||||
|  |  | ||||||
|  | 			m_sweepB.orientation0 = m_sweepB.orientation0 * qz; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	static Test* Create() | ||||||
|  | 	{ | ||||||
|  | 		return new TimeOfImpact(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	scalar m_time; | ||||||
|  |  | ||||||
|  | 	b3HullShape m_shapeA; | ||||||
|  | 	b3Sweep m_sweepA; | ||||||
|  | 	b3ShapeGJKProxy m_proxyA; | ||||||
|  |  | ||||||
|  | 	b3HullShape m_shapeB; | ||||||
|  | 	b3Sweep m_sweepB; | ||||||
|  | 	b3ShapeGJKProxy m_proxyB; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
| @@ -16,45 +16,55 @@ | |||||||
| * 3. This notice may not be removed or altered from any source distribution. | * 3. This notice may not be removed or altered from any source distribution. | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| #ifndef DEGENERATE_CAPSULE_H | #ifndef TRIANGLE_CONTACT_TEST_H | ||||||
| #define DEGENERATE_CAPSULE_H | #define TRIANGLE_CONTACT_TEST_H | ||||||
| 
 | 
 | ||||||
| class DegenerateCapsule : public Collide | class TriangleContactTest : public Test | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	DegenerateCapsule() | 	TriangleContactTest() | ||||||
| 	{ | 	{ | ||||||
| 		m_xfA.position.Set(0.0f, 0.0f, 0.0f); | 		{ | ||||||
| 		m_xfA.rotation = b3QuatMat33(b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), 0.55f * B3_PI)); | 			b3BodyDef bdef; | ||||||
|  | 			bdef.type = b3BodyType::e_staticBody; | ||||||
| 
 | 
 | ||||||
| 		m_sA.m_centers[0].Set(0.0f, 0.0f, 0.0f); | 			b3Body* body = m_world.CreateBody(bdef); | ||||||
| 		m_sA.m_centers[1].Set(0.0f, 0.0f, 0.0f); |  | ||||||
| 		m_sA.m_radius = 0.05f; |  | ||||||
| 
 | 
 | ||||||
| 		m_xfB.position.Set(0.f, 0.0f, 0.0f); | 			b3TriangleShape ts; | ||||||
| 		m_xfB.rotation = b3QuatMat33(b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), 0.0f * B3_PI)); | 			ts.m_vertex1.Set(-5.0f, 0.0f, 5.0f); | ||||||
|  | 			ts.m_vertex2.Set(5.0f, 0.0f, 5.0f); | ||||||
|  | 			ts.m_vertex3.Set(0.0f, 0.0f, -5.0f); | ||||||
| 
 | 
 | ||||||
| 		b3Transform xf; | 			b3ShapeDef sdef; | ||||||
| 		xf.SetIdentity(); | 			sdef.shape = &ts; | ||||||
| 		xf.rotation = b3Diagonal(4.0f, 1.0f, 4.0f); | 			sdef.friction = 1.0f; | ||||||
| 
 | 
 | ||||||
| 		m_box.SetTransform(xf); | 			body->CreateShape(sdef); | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		m_sB.m_hull = &m_box; | 		{ | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.type = b3BodyType::e_dynamicBody; | ||||||
|  | 			bdef.position.Set(0.0f, 5.0f, 0.0f); | ||||||
| 
 | 
 | ||||||
| 		m_shapeA = &m_sA; | 			b3Body* body = m_world.CreateBody(bdef); | ||||||
| 		m_shapeB = &m_sB; | 
 | ||||||
| 		m_cache.count = 0; | 			b3HullShape hs; | ||||||
|  | 			hs.m_hull = &b3BoxHull_identity; | ||||||
|  | 
 | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.density = 0.1f; | ||||||
|  | 			sdef.friction = 0.1f; | ||||||
|  | 			sdef.shape = &hs; | ||||||
|  | 
 | ||||||
|  | 			body->CreateShape(sdef); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	static Test* Create() | 	static Test* Create() | ||||||
| 	{ | 	{ | ||||||
| 		return new DegenerateCapsule(); | 		return new TriangleContactTest(); | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	b3CapsuleShape m_sA; |  | ||||||
| 	b3HullShape m_sB; |  | ||||||
| 	b3BoxHull m_box; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
| @@ -39,11 +39,10 @@ public: | |||||||
| 			{ | 			{ | ||||||
| 				static b3BoxHull box; | 				static b3BoxHull box; | ||||||
|  |  | ||||||
| 				b3Transform m; | 				box.SetExtents(50.0f, 1.0f, 200.0f); | ||||||
| 				m.position.Set(0.0f, -45.0f, 0.0f); |  | ||||||
| 				m.rotation = b3Diagonal(50.0f, 1.0f, 200.0f); |  | ||||||
| 				 | 				 | ||||||
| 				box.SetTransform(m); | 				b3Vec3 translation(0.0f, -45.0f, 0.0f); | ||||||
|  | 				box.Translate(translation); | ||||||
|  |  | ||||||
| 				b3HullShape hs; | 				b3HullShape hs; | ||||||
| 				hs.m_hull = &box; | 				hs.m_hull = &box; | ||||||
| @@ -58,11 +57,10 @@ public: | |||||||
| 			{ | 			{ | ||||||
| 				static b3BoxHull box; | 				static b3BoxHull box; | ||||||
|  |  | ||||||
| 				b3Transform m; | 				box.SetExtents(50.0f, 1.0f, 200.0f); | ||||||
| 				m.position.Set(0.0f, 50.0f, 0.0f); |  | ||||||
| 				m.rotation = b3Diagonal(50.0f, 1.0f, 200.0f); |  | ||||||
| 				 | 				 | ||||||
| 				box.SetTransform(m); | 				b3Vec3 translation(0.0f, 50.0f, 0.0f); | ||||||
|  | 				box.Translate(translation); | ||||||
|  |  | ||||||
| 				b3HullShape hs; | 				b3HullShape hs; | ||||||
| 				hs.m_hull = &box; | 				hs.m_hull = &box; | ||||||
| @@ -77,11 +75,10 @@ public: | |||||||
| 			{ | 			{ | ||||||
| 				static b3BoxHull box; | 				static b3BoxHull box; | ||||||
|  |  | ||||||
| 				b3Transform m; | 				box.SetExtents(50.0f, 50.0f, 1.0f); | ||||||
| 				m.position.Set(0.0f, 5.0f, -200.0f); |  | ||||||
| 				m.rotation = b3Diagonal(50.0f, 50.0f, 1.0f); |  | ||||||
| 				 | 				 | ||||||
| 				box.SetTransform(m); | 				b3Vec3 translation(0.0f, 5.0f, -200.0f); | ||||||
|  | 				box.Translate(translation); | ||||||
|  |  | ||||||
| 				b3HullShape hs; | 				b3HullShape hs; | ||||||
| 				hs.m_hull = &box; | 				hs.m_hull = &box; | ||||||
| @@ -96,11 +93,10 @@ public: | |||||||
| 			{ | 			{ | ||||||
| 				static b3BoxHull box; | 				static b3BoxHull box; | ||||||
|  |  | ||||||
| 				b3Transform m; | 				box.SetExtents(50.0f, 50.0f, 1.0f); | ||||||
| 				m.position.Set(0.0f, 5.0f, 200.0f); |  | ||||||
| 				m.rotation = b3Diagonal(50.0f, 50.0f, 1.0f); |  | ||||||
| 				 | 				 | ||||||
| 				box.SetTransform(m); | 				b3Vec3 translation(0.0f, 5.0f, 200.0f); | ||||||
|  | 				box.Translate(translation); | ||||||
|  |  | ||||||
| 				b3HullShape hs; | 				b3HullShape hs; | ||||||
| 				hs.m_hull = &box; | 				hs.m_hull = &box; | ||||||
| @@ -115,11 +111,10 @@ public: | |||||||
| 			{ | 			{ | ||||||
| 				static b3BoxHull box; | 				static b3BoxHull box; | ||||||
|  |  | ||||||
| 				b3Transform m; | 				box.SetExtents(1.0f, 50.0f, 200.0f); | ||||||
| 				m.position.Set(-50.0f, 5.0f, 0.0f); |  | ||||||
| 				m.rotation = b3Diagonal(1.0f, 50.0f, 200.0f); |  | ||||||
| 				 | 				 | ||||||
| 				box.SetTransform(m); | 				b3Vec3 translation(-50.0f, 5.0f, 0.0f); | ||||||
|  | 				box.Translate(translation); | ||||||
|  |  | ||||||
| 				b3HullShape hs; | 				b3HullShape hs; | ||||||
| 				hs.m_hull = &box; | 				hs.m_hull = &box; | ||||||
| @@ -134,11 +129,11 @@ public: | |||||||
| 			{ | 			{ | ||||||
| 				static b3BoxHull box; | 				static b3BoxHull box; | ||||||
|  |  | ||||||
| 				b3Transform m; | 				box.SetExtents(1.0f, 50.0f, 200.0f); | ||||||
| 				m.position.Set(50.0f, 5.0f, 0.0f); |  | ||||||
| 				m.rotation = b3Diagonal(1.0f, 50.0f, 200.0f); |  | ||||||
| 				 | 				 | ||||||
| 				box.SetTransform(m); | 				b3Vec3 translation(50.0f, 5.0f, 0.0f); | ||||||
|  |  | ||||||
|  | 				box.Translate(translation); | ||||||
|  |  | ||||||
| 				b3HullShape hs; | 				b3HullShape hs; | ||||||
| 				hs.m_hull = &box; | 				hs.m_hull = &box; | ||||||
| @@ -161,8 +156,8 @@ public: | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		m_coneHull.SetAsCone(); | 		m_coneHull.SetExtents(1.0f, 1.0f); | ||||||
| 		m_cylinderHull.SetAsCylinder(); | 		m_cylinderHull.SetExtents(1.0f, 1.0f); | ||||||
|  |  | ||||||
| 		m_count = 0; | 		m_count = 0; | ||||||
| 	} | 	} | ||||||
| @@ -204,8 +199,8 @@ public: | |||||||
| 				b3Body* body = m_world.CreateBody(bdef); | 				b3Body* body = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
| 				b3CapsuleShape capsule; | 				b3CapsuleShape capsule; | ||||||
| 				capsule.m_centers[0].Set(0.0f, 0.0f, -1.0f); | 				capsule.m_vertex1.Set(0.0f, 0.0f, -1.0f); | ||||||
| 				capsule.m_centers[1].Set(0.0f, 0.0f, 1.0f); | 				capsule.m_vertex2.Set(0.0f, 0.0f, 1.0f); | ||||||
| 				capsule.m_radius = 1.0f; | 				capsule.m_radius = 1.0f; | ||||||
|  |  | ||||||
| 				b3ShapeDef sdef; | 				b3ShapeDef sdef; | ||||||
| @@ -279,8 +274,8 @@ public: | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	u32 m_count; | 	u32 m_count; | ||||||
| 	b3QHull m_coneHull; | 	b3ConeHull m_coneHull; | ||||||
| 	b3QHull m_cylinderHull; | 	b3CylinderHull m_cylinderHull; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
| @@ -36,19 +36,12 @@ public: | |||||||
| 			ground->CreateShape(sd); | 			ground->CreateShape(sd); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		static b3BoxHull rampHull; | 		static b3BoxHull rampHull(25.0f, 0.5f, 25.0f); | ||||||
|  |  | ||||||
| 		{ |  | ||||||
| 			b3Transform xf; |  | ||||||
| 			xf.position.SetZero(); |  | ||||||
| 			xf.rotation = b3Diagonal(25.0f, 0.5f, 25.0f); |  | ||||||
| 			rampHull.SetTransform(xf); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		{ | 		{ | ||||||
| 			b3BodyDef bdef; | 			b3BodyDef bdef; | ||||||
| 			bdef.position.Set(-20.0f, 20.0f, 0.0f); | 			bdef.position.Set(-20.0f, 20.0f, 0.0f); | ||||||
| 			bdef.orientation = b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), -0.1f * B3_PI); | 			bdef.orientation = b3QuatRotationZ(-0.1f * B3_PI); | ||||||
|  |  | ||||||
| 			b3Body* ramp = m_world.CreateBody(bdef); | 			b3Body* ramp = m_world.CreateBody(bdef); | ||||||
| 			 | 			 | ||||||
| @@ -64,7 +57,7 @@ public: | |||||||
| 		{ | 		{ | ||||||
| 			b3BodyDef bdef; | 			b3BodyDef bdef; | ||||||
| 			bdef.position.Set(20.0f, 30.0f, 0.0f); | 			bdef.position.Set(20.0f, 30.0f, 0.0f); | ||||||
| 			bdef.orientation = b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), 0.1f * B3_PI); | 			bdef.orientation = b3QuatRotationZ(0.1f * B3_PI); | ||||||
|  |  | ||||||
| 			b3Body* ramp = m_world.CreateBody(bdef); | 			b3Body* ramp = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
| @@ -80,7 +73,7 @@ public: | |||||||
| 		{ | 		{ | ||||||
| 			b3BodyDef bdef; | 			b3BodyDef bdef; | ||||||
| 			bdef.position.Set(-20.0f, 40.0f, 0.0f); | 			bdef.position.Set(-20.0f, 40.0f, 0.0f); | ||||||
| 			bdef.orientation = b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), -0.1f * B3_PI); | 			bdef.orientation = b3QuatRotationZ(-0.1f * B3_PI); | ||||||
|  |  | ||||||
| 			b3Body* ramp = m_world.CreateBody(bdef); | 			b3Body* ramp = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
| @@ -96,7 +89,7 @@ public: | |||||||
| 		{ | 		{ | ||||||
| 			b3BodyDef bdef; | 			b3BodyDef bdef; | ||||||
| 			bdef.position.Set(20.0f, 50.0f, 0.0f); | 			bdef.position.Set(20.0f, 50.0f, 0.0f); | ||||||
| 			bdef.orientation = b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), 0.1f * B3_PI); | 			bdef.orientation = b3QuatRotationZ(0.1f * B3_PI); | ||||||
|  |  | ||||||
| 			b3Body* ramp = m_world.CreateBody(bdef); | 			b3Body* ramp = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -46,8 +46,8 @@ public: | |||||||
| 			bA = m_world.CreateBody(bd); | 			bA = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
| 			b3CapsuleShape shape; | 			b3CapsuleShape shape; | ||||||
| 			shape.m_centers[0].Set(0.0f, -3.5f, 0.0f); | 			shape.m_vertex1.Set(0.0f, -3.5f, 0.0f); | ||||||
| 			shape.m_centers[1].Set(0.0f, 3.5f, 0.0f); | 			shape.m_vertex2.Set(0.0f, 3.5f, 0.0f); | ||||||
| 			shape.m_radius = 0.5f; | 			shape.m_radius = 0.5f; | ||||||
|  |  | ||||||
| 			b3ShapeDef sd; | 			b3ShapeDef sd; | ||||||
| @@ -64,13 +64,7 @@ public: | |||||||
|  |  | ||||||
| 			bB = m_world.CreateBody(bd); | 			bB = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
| 			static b3BoxHull doorHull; | 			static b3BoxHull doorHull(2.0f, 4.0f, 0.5f); | ||||||
| 			{ |  | ||||||
| 				b3Transform xf; |  | ||||||
| 				xf.position.SetZero(); |  | ||||||
| 				xf.rotation = b3Diagonal(2.0f, 4.0f, 0.5f); |  | ||||||
| 				doorHull.SetTransform(xf); |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			b3HullShape hull; | 			b3HullShape hull; | ||||||
| 			hull.m_hull = &doorHull; | 			hull.m_hull = &doorHull; | ||||||
| @@ -86,14 +80,15 @@ public: | |||||||
|  |  | ||||||
| 				b3WeldJointDef jd; | 				b3WeldJointDef jd; | ||||||
| 				jd.Initialize(bA, bB, anchor); | 				jd.Initialize(bA, bB, anchor); | ||||||
|  | 				jd.frequencyHz = 2.0f; | ||||||
|  | 				jd.dampingRatio = 0.3f; | ||||||
|  |  | ||||||
| 				b3WeldJoint* wj = (b3WeldJoint*)m_world.CreateJoint(jd); | 				b3WeldJoint* wj = (b3WeldJoint*)m_world.CreateJoint(jd); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			// Invalidate the orientation | 			// Invalidate the orientation | ||||||
| 			b3Vec3 axis(1.0f, 0.0f, 0.0f); | 			b3Quat q = b3QuatRotationX(B3_PI); | ||||||
| 			float32 angle = B3_PI; | 			bB->SetTransform(bB->GetPosition(), q); | ||||||
| 			bB->SetTransform(bB->GetPosition(), axis, angle); |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										204
									
								
								examples/testbed/tests/wheel_test.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										204
									
								
								examples/testbed/tests/wheel_test.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,204 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * 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 WHEEL_TEST_H | ||||||
|  | #define WHEEL_TEST_H | ||||||
|  |  | ||||||
|  | class WheelTest : public Test | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	WheelTest() | ||||||
|  | 	{ | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bd; | ||||||
|  | 			b3Body* ground = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
|  | 			b3HullShape hs; | ||||||
|  | 			hs.m_hull = &m_groundHull; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sd; | ||||||
|  | 			sd.shape = &hs; | ||||||
|  |  | ||||||
|  | 			ground->CreateShape(sd); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		m_chassisHull.SetExtents(2.0f, 0.5f, 5.0f); | ||||||
|  |  | ||||||
|  | 		b3HullShape chassisShape; | ||||||
|  | 		chassisShape.m_hull = &m_chassisHull; | ||||||
|  |  | ||||||
|  | 		m_wheelHull.SetExtents(1.0f, 0.5f); | ||||||
|  |  | ||||||
|  | 		b3HullShape wheelShape; | ||||||
|  | 		wheelShape.m_hull = &m_wheelHull; | ||||||
|  |  | ||||||
|  | 		// Chassis | ||||||
|  | 		b3Body* chassis; | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.type = e_dynamicBody; | ||||||
|  | 			bdef.position.Set(0.0f, 10.0f, 0.0f); | ||||||
|  |  | ||||||
|  | 			chassis = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.density = 0.1f; | ||||||
|  | 			sdef.friction = 0.3f; | ||||||
|  | 			sdef.shape = &chassisShape; | ||||||
|  |  | ||||||
|  | 			chassis->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		b3Quat orientation = b3QuatRotationZ(0.5f * B3_PI); | ||||||
|  |  | ||||||
|  | 		b3Body* wheelLF; | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.type = e_dynamicBody; | ||||||
|  | 			bdef.position.Set(-1.0f, 7.0f, 4.5f); | ||||||
|  | 			bdef.orientation = orientation; | ||||||
|  |  | ||||||
|  | 			wheelLF = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.shape = &wheelShape; | ||||||
|  | 			sdef.density = 0.1f; | ||||||
|  | 			sdef.friction = 1.0f; | ||||||
|  |  | ||||||
|  | 			wheelLF->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3WheelJointDef def; | ||||||
|  | 			def.Initialize(chassis, wheelLF, wheelLF->GetPosition(), b3Vec3_y, b3Vec3_x); | ||||||
|  | 			def.motorSpeed = 0.25f * B3_PI; | ||||||
|  | 			def.maxMotorTorque = 1000.0f; | ||||||
|  |  | ||||||
|  | 			m_joint1 = (b3WheelJoint*)m_world.CreateJoint(def); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		b3Body* wheelRF; | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.type = e_dynamicBody; | ||||||
|  | 			bdef.position.Set(1.0f, 7.0, 4.5f); | ||||||
|  | 			bdef.orientation = orientation; | ||||||
|  |  | ||||||
|  | 			wheelRF = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.density = 0.1f; | ||||||
|  | 			sdef.friction = 1.0f; | ||||||
|  | 			sdef.shape = &wheelShape; | ||||||
|  |  | ||||||
|  | 			wheelRF->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3WheelJointDef def; | ||||||
|  | 			def.Initialize(chassis, wheelRF, wheelRF->GetPosition(), b3Vec3_y, b3Vec3_x); | ||||||
|  | 			def.motorSpeed = 0.25f * B3_PI; | ||||||
|  | 			def.maxMotorTorque = 1000.0f; | ||||||
|  |  | ||||||
|  | 			m_joint2 = (b3WheelJoint*)m_world.CreateJoint(def); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		b3Body* wheelLB; | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.type = e_dynamicBody; | ||||||
|  | 			bdef.position.Set(-1.0f, 7.0f, -4.5f); | ||||||
|  | 			bdef.orientation = orientation; | ||||||
|  |  | ||||||
|  | 			wheelLB = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.shape = &wheelShape; | ||||||
|  | 			sdef.density = 0.1f; | ||||||
|  | 			sdef.friction = 1.0f; | ||||||
|  |  | ||||||
|  | 			wheelLB->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3WheelJointDef def; | ||||||
|  | 			def.Initialize(chassis, wheelLB, wheelLB->GetPosition(), b3Vec3_y, b3Vec3_x); | ||||||
|  |  | ||||||
|  | 			m_world.CreateJoint(def); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		b3Body* wheelRB; | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.type = e_dynamicBody; | ||||||
|  | 			bdef.position.Set(1.0f, 7.0f, -4.5f); | ||||||
|  | 			bdef.orientation = orientation; | ||||||
|  |  | ||||||
|  | 			wheelRB = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.density = 0.1f; | ||||||
|  | 			sdef.friction = 1.0f; | ||||||
|  | 			sdef.shape = &wheelShape; | ||||||
|  |  | ||||||
|  | 			wheelRB->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3WheelJointDef def; | ||||||
|  | 			def.Initialize(chassis, wheelRB, wheelRB->GetPosition(), b3Vec3_y, b3Vec3_x); | ||||||
|  |  | ||||||
|  | 			m_world.CreateJoint(def); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void Step() | ||||||
|  | 	{ | ||||||
|  | 		Test::Step(); | ||||||
|  |  | ||||||
|  | 		g_draw->DrawString(b3Color_white, "M - Enable Motor"); | ||||||
|  | 		g_draw->DrawString(b3Color_white, "S - Flip Motor Speed"); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void KeyDown(int button) | ||||||
|  | 	{ | ||||||
|  | 		if (button == GLFW_KEY_M) | ||||||
|  | 		{ | ||||||
|  | 			m_joint1->EnableMotor(!m_joint1->IsMotorEnabled()); | ||||||
|  | 			m_joint2->EnableMotor(!m_joint2->IsMotorEnabled()); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (button == GLFW_KEY_S) | ||||||
|  | 		{ | ||||||
|  | 			m_joint1->SetMotorSpeed(-m_joint1->GetMotorSpeed()); | ||||||
|  | 			m_joint2->SetMotorSpeed(-m_joint2->GetMotorSpeed()); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	static Test* Create() | ||||||
|  | 	{ | ||||||
|  | 		return new WheelTest(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b3BoxHull m_chassisHull; | ||||||
|  | 	b3CylinderHull m_wheelHull; | ||||||
|  | 	b3WheelJoint* m_joint1; | ||||||
|  | 	b3WheelJoint* m_joint2; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user