Compare commits
	
		
			1 Commits
		
	
	
		
			bounce-upg
			...
			upstream_f
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | a61262407c | 
							
								
								
									
										2
									
								
								bat/premake_vs2019.bat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								bat/premake_vs2019.bat
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | |||||||
|  | cd ..\ | ||||||
|  | premake5 solution_vs2019 | ||||||
							
								
								
									
										2487
									
								
								doc/doxyfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2487
									
								
								doc/doxyfile
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											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; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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); | ||||||
|   | |||||||
							
								
								
									
										149
									
								
								examples/testbed/tests/revolute_test.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								examples/testbed/tests/revolute_test.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,149 @@ | |||||||
|  | /* | ||||||
|  | * 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 REVOLUTE_TEST_H | ||||||
|  | #define REVOLUTE_TEST_H | ||||||
|  |  | ||||||
|  | class RevoluteTest : public Test | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	RevoluteTest() | ||||||
|  | 	{ | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bd; | ||||||
|  | 			b3Body* ground = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
|  | 			b3HullShape shape; | ||||||
|  | 			shape.m_hull = &m_groundHull; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sd; | ||||||
|  | 			sd.shape = &shape; | ||||||
|  | 			 | ||||||
|  | 			ground->CreateShape(sd); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		b3Body* hinge, *door; | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bd; | ||||||
|  | 			bd.type = b3BodyType::e_staticBody; | ||||||
|  | 			bd.position.Set(0.0f, 7.0f, 0.0f); | ||||||
|  | 			hinge = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
|  | 			b3CapsuleShape shape; | ||||||
|  | 			shape.m_vertex1.Set(0.0f, 0.0f, -4.0f); | ||||||
|  | 			shape.m_vertex2.Set(0.0f, 0.0f, 4.0f); | ||||||
|  | 			shape.m_radius = 0.5f; | ||||||
|  | 			 | ||||||
|  | 			b3ShapeDef sd; | ||||||
|  | 			sd.shape = &shape; | ||||||
|  | 			sd.density = 1.0f; | ||||||
|  |  | ||||||
|  | 			hinge->CreateShape(sd); | ||||||
|  | 			 | ||||||
|  | 			m_body = hinge; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bd; | ||||||
|  | 			bd.type = b3BodyType::e_dynamicBody; | ||||||
|  | 			bd.position.Set(2.0f, 7.0f, 0.0f); | ||||||
|  |  | ||||||
|  | 			door = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
|  | 			m_doorBox.SetExtents(1.0f, 0.5f, 4.0f); | ||||||
|  |  | ||||||
|  | 			b3HullShape hull; | ||||||
|  | 			hull.m_hull = &m_doorBox; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.shape = &hull; | ||||||
|  | 			sdef.density = 1.0f; | ||||||
|  | 			 | ||||||
|  | 			door->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3Vec3 axis(0.0f, 0.0f, 1.0f); | ||||||
|  | 			b3Vec3 anchor(0.0f, 7.0f, 0.0f); | ||||||
|  | 			 | ||||||
|  | 			b3RevoluteJointDef jd; | ||||||
|  | 			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; | ||||||
|  |  | ||||||
|  | 			m_rj = (b3RevoluteJoint*)m_world.CreateJoint(jd); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Invalidate the orientation | ||||||
|  | 		b3Quat q = b3QuatRotationX(B3_PI); | ||||||
|  | 		door->SetTransform(door->GetPosition(), q);		 | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	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) | ||||||
|  | 	{ | ||||||
|  | 		if (button == GLFW_KEY_M) | ||||||
|  | 		{ | ||||||
|  | 			m_rj->SetEnableMotor(!m_rj->IsMotorEnabled()); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (button == GLFW_KEY_L) | ||||||
|  | 		{ | ||||||
|  | 			m_rj->SetEnableLimit(!m_rj->IsLimitEnabled()); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		if (button == GLFW_KEY_D) | ||||||
|  | 		{ | ||||||
|  | 			m_body->SetType(e_dynamicBody); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (button == GLFW_KEY_S) | ||||||
|  | 		{ | ||||||
|  | 			m_body->SetType(e_staticBody); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (button == GLFW_KEY_K) | ||||||
|  | 		{ | ||||||
|  | 			m_body->SetType(e_kinematicBody); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	static Test* Create() | ||||||
|  | 	{ | ||||||
|  | 		return new RevoluteTest(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b3BoxHull m_doorBox; | ||||||
|  | 	b3Body* m_body; | ||||||
|  | 	b3RevoluteJoint* m_rj; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
| @@ -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; | ||||||
|   | |||||||
| @@ -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 | ||||||
							
								
								
									
										185
									
								
								examples/testbed/tests/spring_test.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										185
									
								
								examples/testbed/tests/spring_test.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,185 @@ | |||||||
|  | /* | ||||||
|  | * 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 SPRING_TEST_H | ||||||
|  | #define SPRING_TEST_H | ||||||
|  |  | ||||||
|  | class SpringTest : public Test | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	SpringTest() | ||||||
|  | 	{ | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bd; | ||||||
|  | 			b3Body* ground = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
|  | 			b3HullShape hs; | ||||||
|  | 			hs.m_hull = &m_groundHull; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sd; | ||||||
|  | 			sd.shape = &hs; | ||||||
|  |  | ||||||
|  | 			ground->CreateShape(sd); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Car frame shape | ||||||
|  | 		m_frameHull.SetExtents(2.0f, 0.5f, 5.0f); | ||||||
|  |  | ||||||
|  | 		b3HullShape box; | ||||||
|  | 		box.m_hull = &m_frameHull; | ||||||
|  |  | ||||||
|  | 		// Wheel shape | ||||||
|  | 		b3SphereShape sphere; | ||||||
|  | 		sphere.m_center.SetZero(); | ||||||
|  | 		sphere.m_radius = 1.0f; | ||||||
|  |  | ||||||
|  | 		// Car frame | ||||||
|  | 		b3Body* frame; | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.type = e_dynamicBody; | ||||||
|  | 			bdef.position.Set(0.0f, 10.0f, 0.0f); | ||||||
|  |  | ||||||
|  | 			frame = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.density = 0.1f; | ||||||
|  | 			sdef.friction = 0.3f; | ||||||
|  | 			sdef.shape = &box; | ||||||
|  |  | ||||||
|  | 			frame->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		b3Body* wheelLF; | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.type = e_dynamicBody; | ||||||
|  | 			bdef.position.Set(-1.0f, 7.0f, 4.5f); | ||||||
|  | 			bdef.fixedRotationY = true; | ||||||
|  |  | ||||||
|  | 			wheelLF = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.shape = &sphere; | ||||||
|  | 			sdef.density = 0.1f; | ||||||
|  | 			sdef.friction = 1.0f; | ||||||
|  |  | ||||||
|  | 			wheelLF->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3SpringJointDef def; | ||||||
|  | 			def.Initialize(frame, wheelLF, b3Vec3(-1.0f, 9.0f, 4.5), b3Vec3(-1.0f, 9.0f, 4.5f)); | ||||||
|  | 			def.collideLinked = true; | ||||||
|  | 			def.dampingRatio = 0.5f; | ||||||
|  | 			def.frequencyHz = 4.0f; | ||||||
|  |  | ||||||
|  | 			m_world.CreateJoint(def); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		b3Body* wheelRF; | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.type = e_dynamicBody; | ||||||
|  | 			bdef.position.Set(1.0f, 7.0, 4.5f); | ||||||
|  | 			bdef.fixedRotationY = true; | ||||||
|  |  | ||||||
|  | 			wheelRF = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.density = 0.1f; | ||||||
|  | 			sdef.friction = 1.0f; | ||||||
|  | 			sdef.shape = &sphere; | ||||||
|  |  | ||||||
|  | 			wheelRF->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3SpringJointDef def; | ||||||
|  | 			def.Initialize(frame, wheelRF, b3Vec3(1.0f, 9.0, 4.5), b3Vec3(1.0f, 9.0, 4.5f)); | ||||||
|  | 			def.collideLinked = true; | ||||||
|  | 			def.dampingRatio = 0.5f; | ||||||
|  | 			def.frequencyHz = 4.0f; | ||||||
|  |  | ||||||
|  | 			m_world.CreateJoint(def); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		b3Body* wheelLB; | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.type = e_dynamicBody; | ||||||
|  | 			bdef.position.Set(-1.0f, 7.0f, -4.5f); | ||||||
|  | 			bdef.fixedRotationY = true; | ||||||
|  |  | ||||||
|  | 			wheelLB = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.shape = &sphere; | ||||||
|  | 			sdef.density = 0.1f; | ||||||
|  | 			sdef.friction = 1.0f; | ||||||
|  |  | ||||||
|  | 			wheelLB->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3SpringJointDef def; | ||||||
|  | 			def.Initialize(frame, wheelLB, b3Vec3(-1.0f, 9.0f, -4.5f), b3Vec3(-1.0f, 9.0f, -4.5f)); | ||||||
|  | 			def.collideLinked = true; | ||||||
|  | 			def.dampingRatio = 0.8f; | ||||||
|  | 			def.frequencyHz = 4.0f; | ||||||
|  |  | ||||||
|  | 			m_world.CreateJoint(def); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		b3Body* wheelRB; | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.type = e_dynamicBody; | ||||||
|  | 			bdef.position.Set(1.0f, 7.0f, -4.5f); | ||||||
|  | 			bdef.fixedRotationY = true; | ||||||
|  |  | ||||||
|  | 			wheelRB = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.density = 0.1f; | ||||||
|  | 			sdef.friction = 1.0f; | ||||||
|  | 			sdef.shape = &sphere; | ||||||
|  |  | ||||||
|  | 			wheelRB->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3SpringJointDef def; | ||||||
|  | 			def.Initialize(frame, wheelRB, b3Vec3(1.0f, 9.0f, -4.5f), b3Vec3(1.0f, 9.0f, -4.5f)); | ||||||
|  | 			def.collideLinked = true; | ||||||
|  | 			def.frequencyHz = 4.0f; | ||||||
|  | 			def.dampingRatio = 0.8f; | ||||||
|  |  | ||||||
|  | 			m_world.CreateJoint(def); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	static Test* Create() | ||||||
|  | 	{ | ||||||
|  | 		return new SpringTest(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b3BoxHull m_frameHull; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
| @@ -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 | ||||||
							
								
								
									
										70
									
								
								examples/testbed/tests/triangle_contact_test.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								examples/testbed/tests/triangle_contact_test.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | |||||||
|  | /* | ||||||
|  | * 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 TRIANGLE_CONTACT_TEST_H | ||||||
|  | #define TRIANGLE_CONTACT_TEST_H | ||||||
|  |  | ||||||
|  | class TriangleContactTest : public Test | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	TriangleContactTest() | ||||||
|  | 	{ | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.type = b3BodyType::e_staticBody; | ||||||
|  |  | ||||||
|  | 			b3Body* body = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			b3TriangleShape ts; | ||||||
|  | 			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); | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.shape = &ts; | ||||||
|  | 			sdef.friction = 1.0f; | ||||||
|  |  | ||||||
|  | 			body->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.type = b3BodyType::e_dynamicBody; | ||||||
|  | 			bdef.position.Set(0.0f, 5.0f, 0.0f); | ||||||
|  |  | ||||||
|  | 			b3Body* body = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			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() | ||||||
|  | 	{ | ||||||
|  | 		return new TriangleContactTest(); | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #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 | ||||||
							
								
								
									
										2
									
								
								external/glad_2/glad.c
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								external/glad_2/glad.c
									
									
									
									
										vendored
									
									
								
							| @@ -21,7 +21,7 @@ | |||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
| #include <glad_2\glad.h> | #include <glad_2/glad.h> | ||||||
|  |  | ||||||
| static void* get_proc(const char *namez); | static void* get_proc(const char *namez); | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										165
									
								
								external/glfw/CMakeLists.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								external/glfw/CMakeLists.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,165 @@ | |||||||
|  |  | ||||||
|  | set(common_HEADERS internal.h mappings.h | ||||||
|  |                    "${GLFW_BINARY_DIR}/src/glfw_config.h" | ||||||
|  |                    "${GLFW_SOURCE_DIR}/include/GLFW/glfw3.h" | ||||||
|  |                    "${GLFW_SOURCE_DIR}/include/GLFW/glfw3native.h") | ||||||
|  | set(common_SOURCES context.c init.c input.c monitor.c vulkan.c window.c) | ||||||
|  |  | ||||||
|  | if (_GLFW_COCOA) | ||||||
|  |     set(glfw_HEADERS ${common_HEADERS} cocoa_platform.h cocoa_joystick.h | ||||||
|  |                      posix_thread.h nsgl_context.h egl_context.h osmesa_context.h) | ||||||
|  |     set(glfw_SOURCES ${common_SOURCES} cocoa_init.m cocoa_joystick.m | ||||||
|  |                      cocoa_monitor.m cocoa_window.m cocoa_time.c posix_thread.c | ||||||
|  |                      nsgl_context.m egl_context.c osmesa_context.c) | ||||||
|  | elseif (_GLFW_WIN32) | ||||||
|  |     set(glfw_HEADERS ${common_HEADERS} win32_platform.h win32_joystick.h | ||||||
|  |                      wgl_context.h egl_context.h osmesa_context.h) | ||||||
|  |     set(glfw_SOURCES ${common_SOURCES} win32_init.c win32_joystick.c | ||||||
|  |                      win32_monitor.c win32_time.c win32_thread.c win32_window.c | ||||||
|  |                      wgl_context.c egl_context.c osmesa_context.c) | ||||||
|  | elseif (_GLFW_X11) | ||||||
|  |     set(glfw_HEADERS ${common_HEADERS} x11_platform.h xkb_unicode.h posix_time.h | ||||||
|  |                      posix_thread.h glx_context.h egl_context.h osmesa_context.h) | ||||||
|  |     set(glfw_SOURCES ${common_SOURCES} x11_init.c x11_monitor.c x11_window.c | ||||||
|  |                      xkb_unicode.c posix_time.c posix_thread.c glx_context.c | ||||||
|  |                      egl_context.c osmesa_context.c) | ||||||
|  | elseif (_GLFW_WAYLAND) | ||||||
|  |     set(glfw_HEADERS ${common_HEADERS} wl_platform.h | ||||||
|  |                      posix_time.h posix_thread.h xkb_unicode.h egl_context.h | ||||||
|  |                      osmesa_context.h) | ||||||
|  |     set(glfw_SOURCES ${common_SOURCES} wl_init.c wl_monitor.c wl_window.c | ||||||
|  |                      posix_time.c posix_thread.c xkb_unicode.c | ||||||
|  |                      egl_context.c osmesa_context.c) | ||||||
|  |  | ||||||
|  |     ecm_add_wayland_client_protocol(glfw_SOURCES | ||||||
|  |         PROTOCOL | ||||||
|  |         "${WAYLAND_PROTOCOLS_PKGDATADIR}/stable/xdg-shell/xdg-shell.xml" | ||||||
|  |         BASENAME xdg-shell) | ||||||
|  |     ecm_add_wayland_client_protocol(glfw_SOURCES | ||||||
|  |         PROTOCOL | ||||||
|  |         "${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml" | ||||||
|  |         BASENAME xdg-decoration) | ||||||
|  |     ecm_add_wayland_client_protocol(glfw_SOURCES | ||||||
|  |         PROTOCOL | ||||||
|  |         "${WAYLAND_PROTOCOLS_PKGDATADIR}/stable/viewporter/viewporter.xml" | ||||||
|  |         BASENAME viewporter) | ||||||
|  |     ecm_add_wayland_client_protocol(glfw_SOURCES | ||||||
|  |         PROTOCOL | ||||||
|  |         "${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/relative-pointer/relative-pointer-unstable-v1.xml" | ||||||
|  |         BASENAME relative-pointer-unstable-v1) | ||||||
|  |     ecm_add_wayland_client_protocol(glfw_SOURCES | ||||||
|  |         PROTOCOL | ||||||
|  |         "${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml" | ||||||
|  |         BASENAME pointer-constraints-unstable-v1) | ||||||
|  |     ecm_add_wayland_client_protocol(glfw_SOURCES | ||||||
|  |         PROTOCOL | ||||||
|  |         "${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml" | ||||||
|  |         BASENAME idle-inhibit-unstable-v1) | ||||||
|  | elseif (_GLFW_OSMESA) | ||||||
|  |     set(glfw_HEADERS ${common_HEADERS} null_platform.h null_joystick.h | ||||||
|  |                      posix_time.h posix_thread.h osmesa_context.h) | ||||||
|  |     set(glfw_SOURCES ${common_SOURCES} null_init.c null_monitor.c null_window.c | ||||||
|  |                      null_joystick.c posix_time.c posix_thread.c osmesa_context.c) | ||||||
|  | endif() | ||||||
|  |  | ||||||
|  | if (_GLFW_X11 OR _GLFW_WAYLAND) | ||||||
|  |     if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") | ||||||
|  |         set(glfw_HEADERS ${glfw_HEADERS} linux_joystick.h) | ||||||
|  |         set(glfw_SOURCES ${glfw_SOURCES} linux_joystick.c) | ||||||
|  |     else() | ||||||
|  |         set(glfw_HEADERS ${glfw_HEADERS} null_joystick.h) | ||||||
|  |         set(glfw_SOURCES ${glfw_SOURCES} null_joystick.c) | ||||||
|  |     endif() | ||||||
|  | endif() | ||||||
|  |  | ||||||
|  | if (APPLE) | ||||||
|  |     # For some reason, CMake doesn't know about .m | ||||||
|  |     set_source_files_properties(${glfw_SOURCES} PROPERTIES LANGUAGE C) | ||||||
|  | endif() | ||||||
|  |  | ||||||
|  | # Make GCC and Clang warn about declarations that VS 2010 and 2012 won't accept | ||||||
|  | # for all source files that VS will build | ||||||
|  | if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR | ||||||
|  |     "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR | ||||||
|  |     "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang") | ||||||
|  |  | ||||||
|  |     if (WIN32) | ||||||
|  |         set(windows_SOURCES ${glfw_SOURCES}) | ||||||
|  |     else() | ||||||
|  |         set(windows_SOURCES ${common_SOURCES}) | ||||||
|  |     endif() | ||||||
|  |     set_source_files_properties(${windows_SOURCES} PROPERTIES | ||||||
|  |         COMPILE_FLAGS -Wdeclaration-after-statement) | ||||||
|  | endif() | ||||||
|  |  | ||||||
|  | add_library(glfw ${glfw_SOURCES} ${glfw_HEADERS}) | ||||||
|  | set_target_properties(glfw PROPERTIES | ||||||
|  |                       OUTPUT_NAME ${GLFW_LIB_NAME} | ||||||
|  |                       VERSION ${GLFW_VERSION} | ||||||
|  |                       SOVERSION ${GLFW_VERSION_MAJOR} | ||||||
|  |                       POSITION_INDEPENDENT_CODE ON | ||||||
|  |                       FOLDER "GLFW3") | ||||||
|  |  | ||||||
|  | target_compile_definitions(glfw PRIVATE _GLFW_USE_CONFIG_H) | ||||||
|  | target_include_directories(glfw PUBLIC | ||||||
|  |                            "$<BUILD_INTERFACE:${GLFW_SOURCE_DIR}/include>" | ||||||
|  |                            "$<INSTALL_INTERFACE:${CMAKE_INSTALL_FULL_INCLUDEDIR}>") | ||||||
|  | target_include_directories(glfw PRIVATE | ||||||
|  |                            "${GLFW_SOURCE_DIR}/src" | ||||||
|  |                            "${GLFW_BINARY_DIR}/src" | ||||||
|  |                            ${glfw_INCLUDE_DIRS}) | ||||||
|  |  | ||||||
|  | # HACK: When building on MinGW, WINVER and UNICODE need to be defined before | ||||||
|  | # the inclusion of stddef.h (by glfw3.h), which is itself included before | ||||||
|  | # win32_platform.h.  We define them here until a saner solution can be found | ||||||
|  | # NOTE: MinGW-w64 and Visual C++ do /not/ need this hack. | ||||||
|  | target_compile_definitions(glfw PRIVATE | ||||||
|  |                            "$<$<BOOL:${MINGW}>:UNICODE;WINVER=0x0501>") | ||||||
|  |  | ||||||
|  | # Enable a reasonable set of warnings (no, -Wextra is not reasonable) | ||||||
|  | target_compile_options(glfw PRIVATE | ||||||
|  |                        "$<$<C_COMPILER_ID:AppleClang>:-Wall>" | ||||||
|  |                        "$<$<C_COMPILER_ID:Clang>:-Wall>" | ||||||
|  |                        "$<$<C_COMPILER_ID:GNU>:-Wall>") | ||||||
|  |  | ||||||
|  | if (BUILD_SHARED_LIBS) | ||||||
|  |     if (WIN32) | ||||||
|  |         if (MINGW) | ||||||
|  |             # Remove the lib prefix on the DLL (but not the import library) | ||||||
|  |             set_target_properties(glfw PROPERTIES PREFIX "") | ||||||
|  |  | ||||||
|  |             # Add a suffix to the import library to avoid naming conflicts | ||||||
|  |             set_target_properties(glfw PROPERTIES IMPORT_SUFFIX "dll.a") | ||||||
|  |         else() | ||||||
|  |             # Add a suffix to the import library to avoid naming conflicts | ||||||
|  |             set_target_properties(glfw PROPERTIES IMPORT_SUFFIX "dll.lib") | ||||||
|  |         endif() | ||||||
|  |     elseif (APPLE) | ||||||
|  |         # Add -fno-common to work around a bug in Apple's GCC | ||||||
|  |         target_compile_options(glfw PRIVATE "-fno-common") | ||||||
|  |  | ||||||
|  |         set_target_properties(glfw PROPERTIES | ||||||
|  |                               INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}") | ||||||
|  |     elseif (UNIX) | ||||||
|  |         # Hide symbols not explicitly tagged for export from the shared library | ||||||
|  |         target_compile_options(glfw PRIVATE "-fvisibility=hidden") | ||||||
|  |     endif() | ||||||
|  |  | ||||||
|  |     target_compile_definitions(glfw INTERFACE GLFW_DLL) | ||||||
|  |     target_link_libraries(glfw PRIVATE ${glfw_LIBRARIES}) | ||||||
|  | else() | ||||||
|  |     target_link_libraries(glfw INTERFACE ${glfw_LIBRARIES}) | ||||||
|  | endif() | ||||||
|  |  | ||||||
|  | if (MSVC) | ||||||
|  |     target_compile_definitions(glfw PRIVATE _CRT_SECURE_NO_WARNINGS) | ||||||
|  | endif() | ||||||
|  |  | ||||||
|  | if (GLFW_INSTALL) | ||||||
|  |     install(TARGETS glfw | ||||||
|  |             EXPORT glfwTargets | ||||||
|  |             RUNTIME DESTINATION "bin" | ||||||
|  |             ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" | ||||||
|  |             LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}") | ||||||
|  | endif() | ||||||
|  |  | ||||||
							
								
								
									
										22
									
								
								external/glfw/LICENSE.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								external/glfw/LICENSE.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | Copyright (c) 2002-2006 Marcus Geelnard | ||||||
|  | Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org> | ||||||
|  |  | ||||||
|  | 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. | ||||||
|  |  | ||||||
							
								
								
									
										526
									
								
								external/glfw/cocoa_init.m
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										526
									
								
								external/glfw/cocoa_init.m
									
									
									
									
										vendored
									
									
								
							| @@ -1,7 +1,7 @@ | |||||||
| //======================================================================== | //======================================================================== | ||||||
| // GLFW 3.3 OS X - www.glfw.org | // GLFW 3.3 macOS - www.glfw.org | ||||||
| //------------------------------------------------------------------------ | //------------------------------------------------------------------------ | ||||||
| // Copyright (c) 2009-2016 Camilla Berglund <elmindreda@glfw.org> | // Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org> | ||||||
| // | // | ||||||
| // This software is provided 'as-is', without any express or implied | // This software is provided 'as-is', without any express or implied | ||||||
| // warranty. In no event will the authors be held liable for any damages | // warranty. In no event will the authors be held liable for any damages | ||||||
| @@ -27,8 +27,8 @@ | |||||||
| #include "internal.h" | #include "internal.h" | ||||||
| #include <sys/param.h> // For MAXPATHLEN | #include <sys/param.h> // For MAXPATHLEN | ||||||
|  |  | ||||||
|  | // Needed for _NSGetProgname | ||||||
| #if defined(_GLFW_USE_CHDIR) | #include <crt_externs.h> | ||||||
|  |  | ||||||
| // Change to our application bundle's resources directory, if present | // Change to our application bundle's resources directory, if present | ||||||
| // | // | ||||||
| @@ -66,7 +66,110 @@ static void changeToResourcesDirectory(void) | |||||||
|     chdir(resourcesPath); |     chdir(resourcesPath); | ||||||
| } | } | ||||||
|  |  | ||||||
| #endif /* _GLFW_USE_CHDIR */ | // Set up the menu bar (manually) | ||||||
|  | // This is nasty, nasty stuff -- calls to undocumented semi-private APIs that | ||||||
|  | // could go away at any moment, lots of stuff that really should be | ||||||
|  | // localize(d|able), etc.  Add a nib to save us this horror. | ||||||
|  | // | ||||||
|  | static void createMenuBar(void) | ||||||
|  | { | ||||||
|  |     size_t i; | ||||||
|  |     NSString* appName = nil; | ||||||
|  |     NSDictionary* bundleInfo = [[NSBundle mainBundle] infoDictionary]; | ||||||
|  |     NSString* nameKeys[] = | ||||||
|  |     { | ||||||
|  |         @"CFBundleDisplayName", | ||||||
|  |         @"CFBundleName", | ||||||
|  |         @"CFBundleExecutable", | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     // Try to figure out what the calling application is called | ||||||
|  |  | ||||||
|  |     for (i = 0;  i < sizeof(nameKeys) / sizeof(nameKeys[0]);  i++) | ||||||
|  |     { | ||||||
|  |         id name = bundleInfo[nameKeys[i]]; | ||||||
|  |         if (name && | ||||||
|  |             [name isKindOfClass:[NSString class]] && | ||||||
|  |             ![name isEqualToString:@""]) | ||||||
|  |         { | ||||||
|  |             appName = name; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (!appName) | ||||||
|  |     { | ||||||
|  |         char** progname = _NSGetProgname(); | ||||||
|  |         if (progname && *progname) | ||||||
|  |             appName = @(*progname); | ||||||
|  |         else | ||||||
|  |             appName = @"GLFW Application"; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     NSMenu* bar = [[NSMenu alloc] init]; | ||||||
|  |     [NSApp setMainMenu:bar]; | ||||||
|  |  | ||||||
|  |     NSMenuItem* appMenuItem = | ||||||
|  |         [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""]; | ||||||
|  |     NSMenu* appMenu = [[NSMenu alloc] init]; | ||||||
|  |     [appMenuItem setSubmenu:appMenu]; | ||||||
|  |  | ||||||
|  |     [appMenu addItemWithTitle:[NSString stringWithFormat:@"About %@", appName] | ||||||
|  |                        action:@selector(orderFrontStandardAboutPanel:) | ||||||
|  |                 keyEquivalent:@""]; | ||||||
|  |     [appMenu addItem:[NSMenuItem separatorItem]]; | ||||||
|  |     NSMenu* servicesMenu = [[NSMenu alloc] init]; | ||||||
|  |     [NSApp setServicesMenu:servicesMenu]; | ||||||
|  |     [[appMenu addItemWithTitle:@"Services" | ||||||
|  |                        action:NULL | ||||||
|  |                 keyEquivalent:@""] setSubmenu:servicesMenu]; | ||||||
|  |     [servicesMenu release]; | ||||||
|  |     [appMenu addItem:[NSMenuItem separatorItem]]; | ||||||
|  |     [appMenu addItemWithTitle:[NSString stringWithFormat:@"Hide %@", appName] | ||||||
|  |                        action:@selector(hide:) | ||||||
|  |                 keyEquivalent:@"h"]; | ||||||
|  |     [[appMenu addItemWithTitle:@"Hide Others" | ||||||
|  |                        action:@selector(hideOtherApplications:) | ||||||
|  |                 keyEquivalent:@"h"] | ||||||
|  |         setKeyEquivalentModifierMask:NSEventModifierFlagOption | NSEventModifierFlagCommand]; | ||||||
|  |     [appMenu addItemWithTitle:@"Show All" | ||||||
|  |                        action:@selector(unhideAllApplications:) | ||||||
|  |                 keyEquivalent:@""]; | ||||||
|  |     [appMenu addItem:[NSMenuItem separatorItem]]; | ||||||
|  |     [appMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %@", appName] | ||||||
|  |                        action:@selector(terminate:) | ||||||
|  |                 keyEquivalent:@"q"]; | ||||||
|  |  | ||||||
|  |     NSMenuItem* windowMenuItem = | ||||||
|  |         [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""]; | ||||||
|  |     [bar release]; | ||||||
|  |     NSMenu* windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; | ||||||
|  |     [NSApp setWindowsMenu:windowMenu]; | ||||||
|  |     [windowMenuItem setSubmenu:windowMenu]; | ||||||
|  |  | ||||||
|  |     [windowMenu addItemWithTitle:@"Minimize" | ||||||
|  |                           action:@selector(performMiniaturize:) | ||||||
|  |                    keyEquivalent:@"m"]; | ||||||
|  |     [windowMenu addItemWithTitle:@"Zoom" | ||||||
|  |                           action:@selector(performZoom:) | ||||||
|  |                    keyEquivalent:@""]; | ||||||
|  |     [windowMenu addItem:[NSMenuItem separatorItem]]; | ||||||
|  |     [windowMenu addItemWithTitle:@"Bring All to Front" | ||||||
|  |                           action:@selector(arrangeInFront:) | ||||||
|  |                    keyEquivalent:@""]; | ||||||
|  |  | ||||||
|  |     // TODO: Make this appear at the bottom of the menu (for consistency) | ||||||
|  |     [windowMenu addItem:[NSMenuItem separatorItem]]; | ||||||
|  |     [[windowMenu addItemWithTitle:@"Enter Full Screen" | ||||||
|  |                            action:@selector(toggleFullScreen:) | ||||||
|  |                     keyEquivalent:@"f"] | ||||||
|  |      setKeyEquivalentModifierMask:NSEventModifierFlagControl | NSEventModifierFlagCommand]; | ||||||
|  |  | ||||||
|  |     // Prior to Snow Leopard, we need to use this oddly-named semi-private API | ||||||
|  |     // to get the application menu working properly. | ||||||
|  |     SEL setAppleMenuSelector = NSSelectorFromString(@"setAppleMenu:"); | ||||||
|  |     [NSApp performSelector:setAppleMenuSelector withObject:appMenu]; | ||||||
|  | } | ||||||
|  |  | ||||||
| // Create key code translation tables | // Create key code translation tables | ||||||
| // | // | ||||||
| @@ -74,129 +177,129 @@ static void createKeyTables(void) | |||||||
| { | { | ||||||
|     int scancode; |     int scancode; | ||||||
|  |  | ||||||
|     memset(_glfw.ns.publicKeys, -1, sizeof(_glfw.ns.publicKeys)); |     memset(_glfw.ns.keycodes, -1, sizeof(_glfw.ns.keycodes)); | ||||||
|     memset(_glfw.ns.nativeKeys, -1, sizeof(_glfw.ns.nativeKeys)); |     memset(_glfw.ns.scancodes, -1, sizeof(_glfw.ns.scancodes)); | ||||||
|  |  | ||||||
|     _glfw.ns.publicKeys[0x1D] = GLFW_KEY_0; |     _glfw.ns.keycodes[0x1D] = GLFW_KEY_0; | ||||||
|     _glfw.ns.publicKeys[0x12] = GLFW_KEY_1; |     _glfw.ns.keycodes[0x12] = GLFW_KEY_1; | ||||||
|     _glfw.ns.publicKeys[0x13] = GLFW_KEY_2; |     _glfw.ns.keycodes[0x13] = GLFW_KEY_2; | ||||||
|     _glfw.ns.publicKeys[0x14] = GLFW_KEY_3; |     _glfw.ns.keycodes[0x14] = GLFW_KEY_3; | ||||||
|     _glfw.ns.publicKeys[0x15] = GLFW_KEY_4; |     _glfw.ns.keycodes[0x15] = GLFW_KEY_4; | ||||||
|     _glfw.ns.publicKeys[0x17] = GLFW_KEY_5; |     _glfw.ns.keycodes[0x17] = GLFW_KEY_5; | ||||||
|     _glfw.ns.publicKeys[0x16] = GLFW_KEY_6; |     _glfw.ns.keycodes[0x16] = GLFW_KEY_6; | ||||||
|     _glfw.ns.publicKeys[0x1A] = GLFW_KEY_7; |     _glfw.ns.keycodes[0x1A] = GLFW_KEY_7; | ||||||
|     _glfw.ns.publicKeys[0x1C] = GLFW_KEY_8; |     _glfw.ns.keycodes[0x1C] = GLFW_KEY_8; | ||||||
|     _glfw.ns.publicKeys[0x19] = GLFW_KEY_9; |     _glfw.ns.keycodes[0x19] = GLFW_KEY_9; | ||||||
|     _glfw.ns.publicKeys[0x00] = GLFW_KEY_A; |     _glfw.ns.keycodes[0x00] = GLFW_KEY_A; | ||||||
|     _glfw.ns.publicKeys[0x0B] = GLFW_KEY_B; |     _glfw.ns.keycodes[0x0B] = GLFW_KEY_B; | ||||||
|     _glfw.ns.publicKeys[0x08] = GLFW_KEY_C; |     _glfw.ns.keycodes[0x08] = GLFW_KEY_C; | ||||||
|     _glfw.ns.publicKeys[0x02] = GLFW_KEY_D; |     _glfw.ns.keycodes[0x02] = GLFW_KEY_D; | ||||||
|     _glfw.ns.publicKeys[0x0E] = GLFW_KEY_E; |     _glfw.ns.keycodes[0x0E] = GLFW_KEY_E; | ||||||
|     _glfw.ns.publicKeys[0x03] = GLFW_KEY_F; |     _glfw.ns.keycodes[0x03] = GLFW_KEY_F; | ||||||
|     _glfw.ns.publicKeys[0x05] = GLFW_KEY_G; |     _glfw.ns.keycodes[0x05] = GLFW_KEY_G; | ||||||
|     _glfw.ns.publicKeys[0x04] = GLFW_KEY_H; |     _glfw.ns.keycodes[0x04] = GLFW_KEY_H; | ||||||
|     _glfw.ns.publicKeys[0x22] = GLFW_KEY_I; |     _glfw.ns.keycodes[0x22] = GLFW_KEY_I; | ||||||
|     _glfw.ns.publicKeys[0x26] = GLFW_KEY_J; |     _glfw.ns.keycodes[0x26] = GLFW_KEY_J; | ||||||
|     _glfw.ns.publicKeys[0x28] = GLFW_KEY_K; |     _glfw.ns.keycodes[0x28] = GLFW_KEY_K; | ||||||
|     _glfw.ns.publicKeys[0x25] = GLFW_KEY_L; |     _glfw.ns.keycodes[0x25] = GLFW_KEY_L; | ||||||
|     _glfw.ns.publicKeys[0x2E] = GLFW_KEY_M; |     _glfw.ns.keycodes[0x2E] = GLFW_KEY_M; | ||||||
|     _glfw.ns.publicKeys[0x2D] = GLFW_KEY_N; |     _glfw.ns.keycodes[0x2D] = GLFW_KEY_N; | ||||||
|     _glfw.ns.publicKeys[0x1F] = GLFW_KEY_O; |     _glfw.ns.keycodes[0x1F] = GLFW_KEY_O; | ||||||
|     _glfw.ns.publicKeys[0x23] = GLFW_KEY_P; |     _glfw.ns.keycodes[0x23] = GLFW_KEY_P; | ||||||
|     _glfw.ns.publicKeys[0x0C] = GLFW_KEY_Q; |     _glfw.ns.keycodes[0x0C] = GLFW_KEY_Q; | ||||||
|     _glfw.ns.publicKeys[0x0F] = GLFW_KEY_R; |     _glfw.ns.keycodes[0x0F] = GLFW_KEY_R; | ||||||
|     _glfw.ns.publicKeys[0x01] = GLFW_KEY_S; |     _glfw.ns.keycodes[0x01] = GLFW_KEY_S; | ||||||
|     _glfw.ns.publicKeys[0x11] = GLFW_KEY_T; |     _glfw.ns.keycodes[0x11] = GLFW_KEY_T; | ||||||
|     _glfw.ns.publicKeys[0x20] = GLFW_KEY_U; |     _glfw.ns.keycodes[0x20] = GLFW_KEY_U; | ||||||
|     _glfw.ns.publicKeys[0x09] = GLFW_KEY_V; |     _glfw.ns.keycodes[0x09] = GLFW_KEY_V; | ||||||
|     _glfw.ns.publicKeys[0x0D] = GLFW_KEY_W; |     _glfw.ns.keycodes[0x0D] = GLFW_KEY_W; | ||||||
|     _glfw.ns.publicKeys[0x07] = GLFW_KEY_X; |     _glfw.ns.keycodes[0x07] = GLFW_KEY_X; | ||||||
|     _glfw.ns.publicKeys[0x10] = GLFW_KEY_Y; |     _glfw.ns.keycodes[0x10] = GLFW_KEY_Y; | ||||||
|     _glfw.ns.publicKeys[0x06] = GLFW_KEY_Z; |     _glfw.ns.keycodes[0x06] = GLFW_KEY_Z; | ||||||
|  |  | ||||||
|     _glfw.ns.publicKeys[0x27] = GLFW_KEY_APOSTROPHE; |     _glfw.ns.keycodes[0x27] = GLFW_KEY_APOSTROPHE; | ||||||
|     _glfw.ns.publicKeys[0x2A] = GLFW_KEY_BACKSLASH; |     _glfw.ns.keycodes[0x2A] = GLFW_KEY_BACKSLASH; | ||||||
|     _glfw.ns.publicKeys[0x2B] = GLFW_KEY_COMMA; |     _glfw.ns.keycodes[0x2B] = GLFW_KEY_COMMA; | ||||||
|     _glfw.ns.publicKeys[0x18] = GLFW_KEY_EQUAL; |     _glfw.ns.keycodes[0x18] = GLFW_KEY_EQUAL; | ||||||
|     _glfw.ns.publicKeys[0x32] = GLFW_KEY_GRAVE_ACCENT; |     _glfw.ns.keycodes[0x32] = GLFW_KEY_GRAVE_ACCENT; | ||||||
|     _glfw.ns.publicKeys[0x21] = GLFW_KEY_LEFT_BRACKET; |     _glfw.ns.keycodes[0x21] = GLFW_KEY_LEFT_BRACKET; | ||||||
|     _glfw.ns.publicKeys[0x1B] = GLFW_KEY_MINUS; |     _glfw.ns.keycodes[0x1B] = GLFW_KEY_MINUS; | ||||||
|     _glfw.ns.publicKeys[0x2F] = GLFW_KEY_PERIOD; |     _glfw.ns.keycodes[0x2F] = GLFW_KEY_PERIOD; | ||||||
|     _glfw.ns.publicKeys[0x1E] = GLFW_KEY_RIGHT_BRACKET; |     _glfw.ns.keycodes[0x1E] = GLFW_KEY_RIGHT_BRACKET; | ||||||
|     _glfw.ns.publicKeys[0x29] = GLFW_KEY_SEMICOLON; |     _glfw.ns.keycodes[0x29] = GLFW_KEY_SEMICOLON; | ||||||
|     _glfw.ns.publicKeys[0x2C] = GLFW_KEY_SLASH; |     _glfw.ns.keycodes[0x2C] = GLFW_KEY_SLASH; | ||||||
|     _glfw.ns.publicKeys[0x0A] = GLFW_KEY_WORLD_1; |     _glfw.ns.keycodes[0x0A] = GLFW_KEY_WORLD_1; | ||||||
|  |  | ||||||
|     _glfw.ns.publicKeys[0x33] = GLFW_KEY_BACKSPACE; |     _glfw.ns.keycodes[0x33] = GLFW_KEY_BACKSPACE; | ||||||
|     _glfw.ns.publicKeys[0x39] = GLFW_KEY_CAPS_LOCK; |     _glfw.ns.keycodes[0x39] = GLFW_KEY_CAPS_LOCK; | ||||||
|     _glfw.ns.publicKeys[0x75] = GLFW_KEY_DELETE; |     _glfw.ns.keycodes[0x75] = GLFW_KEY_DELETE; | ||||||
|     _glfw.ns.publicKeys[0x7D] = GLFW_KEY_DOWN; |     _glfw.ns.keycodes[0x7D] = GLFW_KEY_DOWN; | ||||||
|     _glfw.ns.publicKeys[0x77] = GLFW_KEY_END; |     _glfw.ns.keycodes[0x77] = GLFW_KEY_END; | ||||||
|     _glfw.ns.publicKeys[0x24] = GLFW_KEY_ENTER; |     _glfw.ns.keycodes[0x24] = GLFW_KEY_ENTER; | ||||||
|     _glfw.ns.publicKeys[0x35] = GLFW_KEY_ESCAPE; |     _glfw.ns.keycodes[0x35] = GLFW_KEY_ESCAPE; | ||||||
|     _glfw.ns.publicKeys[0x7A] = GLFW_KEY_F1; |     _glfw.ns.keycodes[0x7A] = GLFW_KEY_F1; | ||||||
|     _glfw.ns.publicKeys[0x78] = GLFW_KEY_F2; |     _glfw.ns.keycodes[0x78] = GLFW_KEY_F2; | ||||||
|     _glfw.ns.publicKeys[0x63] = GLFW_KEY_F3; |     _glfw.ns.keycodes[0x63] = GLFW_KEY_F3; | ||||||
|     _glfw.ns.publicKeys[0x76] = GLFW_KEY_F4; |     _glfw.ns.keycodes[0x76] = GLFW_KEY_F4; | ||||||
|     _glfw.ns.publicKeys[0x60] = GLFW_KEY_F5; |     _glfw.ns.keycodes[0x60] = GLFW_KEY_F5; | ||||||
|     _glfw.ns.publicKeys[0x61] = GLFW_KEY_F6; |     _glfw.ns.keycodes[0x61] = GLFW_KEY_F6; | ||||||
|     _glfw.ns.publicKeys[0x62] = GLFW_KEY_F7; |     _glfw.ns.keycodes[0x62] = GLFW_KEY_F7; | ||||||
|     _glfw.ns.publicKeys[0x64] = GLFW_KEY_F8; |     _glfw.ns.keycodes[0x64] = GLFW_KEY_F8; | ||||||
|     _glfw.ns.publicKeys[0x65] = GLFW_KEY_F9; |     _glfw.ns.keycodes[0x65] = GLFW_KEY_F9; | ||||||
|     _glfw.ns.publicKeys[0x6D] = GLFW_KEY_F10; |     _glfw.ns.keycodes[0x6D] = GLFW_KEY_F10; | ||||||
|     _glfw.ns.publicKeys[0x67] = GLFW_KEY_F11; |     _glfw.ns.keycodes[0x67] = GLFW_KEY_F11; | ||||||
|     _glfw.ns.publicKeys[0x6F] = GLFW_KEY_F12; |     _glfw.ns.keycodes[0x6F] = GLFW_KEY_F12; | ||||||
|     _glfw.ns.publicKeys[0x69] = GLFW_KEY_F13; |     _glfw.ns.keycodes[0x69] = GLFW_KEY_F13; | ||||||
|     _glfw.ns.publicKeys[0x6B] = GLFW_KEY_F14; |     _glfw.ns.keycodes[0x6B] = GLFW_KEY_F14; | ||||||
|     _glfw.ns.publicKeys[0x71] = GLFW_KEY_F15; |     _glfw.ns.keycodes[0x71] = GLFW_KEY_F15; | ||||||
|     _glfw.ns.publicKeys[0x6A] = GLFW_KEY_F16; |     _glfw.ns.keycodes[0x6A] = GLFW_KEY_F16; | ||||||
|     _glfw.ns.publicKeys[0x40] = GLFW_KEY_F17; |     _glfw.ns.keycodes[0x40] = GLFW_KEY_F17; | ||||||
|     _glfw.ns.publicKeys[0x4F] = GLFW_KEY_F18; |     _glfw.ns.keycodes[0x4F] = GLFW_KEY_F18; | ||||||
|     _glfw.ns.publicKeys[0x50] = GLFW_KEY_F19; |     _glfw.ns.keycodes[0x50] = GLFW_KEY_F19; | ||||||
|     _glfw.ns.publicKeys[0x5A] = GLFW_KEY_F20; |     _glfw.ns.keycodes[0x5A] = GLFW_KEY_F20; | ||||||
|     _glfw.ns.publicKeys[0x73] = GLFW_KEY_HOME; |     _glfw.ns.keycodes[0x73] = GLFW_KEY_HOME; | ||||||
|     _glfw.ns.publicKeys[0x72] = GLFW_KEY_INSERT; |     _glfw.ns.keycodes[0x72] = GLFW_KEY_INSERT; | ||||||
|     _glfw.ns.publicKeys[0x7B] = GLFW_KEY_LEFT; |     _glfw.ns.keycodes[0x7B] = GLFW_KEY_LEFT; | ||||||
|     _glfw.ns.publicKeys[0x3A] = GLFW_KEY_LEFT_ALT; |     _glfw.ns.keycodes[0x3A] = GLFW_KEY_LEFT_ALT; | ||||||
|     _glfw.ns.publicKeys[0x3B] = GLFW_KEY_LEFT_CONTROL; |     _glfw.ns.keycodes[0x3B] = GLFW_KEY_LEFT_CONTROL; | ||||||
|     _glfw.ns.publicKeys[0x38] = GLFW_KEY_LEFT_SHIFT; |     _glfw.ns.keycodes[0x38] = GLFW_KEY_LEFT_SHIFT; | ||||||
|     _glfw.ns.publicKeys[0x37] = GLFW_KEY_LEFT_SUPER; |     _glfw.ns.keycodes[0x37] = GLFW_KEY_LEFT_SUPER; | ||||||
|     _glfw.ns.publicKeys[0x6E] = GLFW_KEY_MENU; |     _glfw.ns.keycodes[0x6E] = GLFW_KEY_MENU; | ||||||
|     _glfw.ns.publicKeys[0x47] = GLFW_KEY_NUM_LOCK; |     _glfw.ns.keycodes[0x47] = GLFW_KEY_NUM_LOCK; | ||||||
|     _glfw.ns.publicKeys[0x79] = GLFW_KEY_PAGE_DOWN; |     _glfw.ns.keycodes[0x79] = GLFW_KEY_PAGE_DOWN; | ||||||
|     _glfw.ns.publicKeys[0x74] = GLFW_KEY_PAGE_UP; |     _glfw.ns.keycodes[0x74] = GLFW_KEY_PAGE_UP; | ||||||
|     _glfw.ns.publicKeys[0x7C] = GLFW_KEY_RIGHT; |     _glfw.ns.keycodes[0x7C] = GLFW_KEY_RIGHT; | ||||||
|     _glfw.ns.publicKeys[0x3D] = GLFW_KEY_RIGHT_ALT; |     _glfw.ns.keycodes[0x3D] = GLFW_KEY_RIGHT_ALT; | ||||||
|     _glfw.ns.publicKeys[0x3E] = GLFW_KEY_RIGHT_CONTROL; |     _glfw.ns.keycodes[0x3E] = GLFW_KEY_RIGHT_CONTROL; | ||||||
|     _glfw.ns.publicKeys[0x3C] = GLFW_KEY_RIGHT_SHIFT; |     _glfw.ns.keycodes[0x3C] = GLFW_KEY_RIGHT_SHIFT; | ||||||
|     _glfw.ns.publicKeys[0x36] = GLFW_KEY_RIGHT_SUPER; |     _glfw.ns.keycodes[0x36] = GLFW_KEY_RIGHT_SUPER; | ||||||
|     _glfw.ns.publicKeys[0x31] = GLFW_KEY_SPACE; |     _glfw.ns.keycodes[0x31] = GLFW_KEY_SPACE; | ||||||
|     _glfw.ns.publicKeys[0x30] = GLFW_KEY_TAB; |     _glfw.ns.keycodes[0x30] = GLFW_KEY_TAB; | ||||||
|     _glfw.ns.publicKeys[0x7E] = GLFW_KEY_UP; |     _glfw.ns.keycodes[0x7E] = GLFW_KEY_UP; | ||||||
|  |  | ||||||
|     _glfw.ns.publicKeys[0x52] = GLFW_KEY_KP_0; |     _glfw.ns.keycodes[0x52] = GLFW_KEY_KP_0; | ||||||
|     _glfw.ns.publicKeys[0x53] = GLFW_KEY_KP_1; |     _glfw.ns.keycodes[0x53] = GLFW_KEY_KP_1; | ||||||
|     _glfw.ns.publicKeys[0x54] = GLFW_KEY_KP_2; |     _glfw.ns.keycodes[0x54] = GLFW_KEY_KP_2; | ||||||
|     _glfw.ns.publicKeys[0x55] = GLFW_KEY_KP_3; |     _glfw.ns.keycodes[0x55] = GLFW_KEY_KP_3; | ||||||
|     _glfw.ns.publicKeys[0x56] = GLFW_KEY_KP_4; |     _glfw.ns.keycodes[0x56] = GLFW_KEY_KP_4; | ||||||
|     _glfw.ns.publicKeys[0x57] = GLFW_KEY_KP_5; |     _glfw.ns.keycodes[0x57] = GLFW_KEY_KP_5; | ||||||
|     _glfw.ns.publicKeys[0x58] = GLFW_KEY_KP_6; |     _glfw.ns.keycodes[0x58] = GLFW_KEY_KP_6; | ||||||
|     _glfw.ns.publicKeys[0x59] = GLFW_KEY_KP_7; |     _glfw.ns.keycodes[0x59] = GLFW_KEY_KP_7; | ||||||
|     _glfw.ns.publicKeys[0x5B] = GLFW_KEY_KP_8; |     _glfw.ns.keycodes[0x5B] = GLFW_KEY_KP_8; | ||||||
|     _glfw.ns.publicKeys[0x5C] = GLFW_KEY_KP_9; |     _glfw.ns.keycodes[0x5C] = GLFW_KEY_KP_9; | ||||||
|     _glfw.ns.publicKeys[0x45] = GLFW_KEY_KP_ADD; |     _glfw.ns.keycodes[0x45] = GLFW_KEY_KP_ADD; | ||||||
|     _glfw.ns.publicKeys[0x41] = GLFW_KEY_KP_DECIMAL; |     _glfw.ns.keycodes[0x41] = GLFW_KEY_KP_DECIMAL; | ||||||
|     _glfw.ns.publicKeys[0x4B] = GLFW_KEY_KP_DIVIDE; |     _glfw.ns.keycodes[0x4B] = GLFW_KEY_KP_DIVIDE; | ||||||
|     _glfw.ns.publicKeys[0x4C] = GLFW_KEY_KP_ENTER; |     _glfw.ns.keycodes[0x4C] = GLFW_KEY_KP_ENTER; | ||||||
|     _glfw.ns.publicKeys[0x51] = GLFW_KEY_KP_EQUAL; |     _glfw.ns.keycodes[0x51] = GLFW_KEY_KP_EQUAL; | ||||||
|     _glfw.ns.publicKeys[0x43] = GLFW_KEY_KP_MULTIPLY; |     _glfw.ns.keycodes[0x43] = GLFW_KEY_KP_MULTIPLY; | ||||||
|     _glfw.ns.publicKeys[0x4E] = GLFW_KEY_KP_SUBTRACT; |     _glfw.ns.keycodes[0x4E] = GLFW_KEY_KP_SUBTRACT; | ||||||
|  |  | ||||||
|     for (scancode = 0;  scancode < 256;  scancode++) |     for (scancode = 0;  scancode < 256;  scancode++) | ||||||
|     { |     { | ||||||
|         // Store the reverse translation for faster key name lookup |         // Store the reverse translation for faster key name lookup | ||||||
|         if (_glfw.ns.publicKeys[scancode] >= 0) |         if (_glfw.ns.keycodes[scancode] >= 0) | ||||||
|             _glfw.ns.nativeKeys[_glfw.ns.publicKeys[scancode]] = scancode; |             _glfw.ns.scancodes[_glfw.ns.keycodes[scancode]] = scancode; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -219,7 +322,8 @@ static GLFWbool updateUnicodeDataNS(void) | |||||||
|         return GLFW_FALSE; |         return GLFW_FALSE; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     _glfw.ns.unicodeData = TISGetInputSourceProperty(_glfw.ns.inputSource, |     _glfw.ns.unicodeData = | ||||||
|  |         TISGetInputSourceProperty(_glfw.ns.inputSource, | ||||||
|                                   kTISPropertyUnicodeKeyLayoutData); |                                   kTISPropertyUnicodeKeyLayoutData); | ||||||
|     if (!_glfw.ns.unicodeData) |     if (!_glfw.ns.unicodeData) | ||||||
|     { |     { | ||||||
| @@ -236,7 +340,8 @@ static GLFWbool updateUnicodeDataNS(void) | |||||||
| static GLFWbool initializeTIS(void) | static GLFWbool initializeTIS(void) | ||||||
| { | { | ||||||
|     // This works only because Cocoa has already loaded it properly |     // This works only because Cocoa has already loaded it properly | ||||||
|     _glfw.ns.tis.bundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.HIToolbox")); |     _glfw.ns.tis.bundle = | ||||||
|  |         CFBundleGetBundleWithIdentifier(CFSTR("com.apple.HIToolbox")); | ||||||
|     if (!_glfw.ns.tis.bundle) |     if (!_glfw.ns.tis.bundle) | ||||||
|     { |     { | ||||||
|         _glfwInputError(GLFW_PLATFORM_ERROR, |         _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
| @@ -247,9 +352,6 @@ static GLFWbool initializeTIS(void) | |||||||
|     CFStringRef* kPropertyUnicodeKeyLayoutData = |     CFStringRef* kPropertyUnicodeKeyLayoutData = | ||||||
|         CFBundleGetDataPointerForName(_glfw.ns.tis.bundle, |         CFBundleGetDataPointerForName(_glfw.ns.tis.bundle, | ||||||
|                                       CFSTR("kTISPropertyUnicodeKeyLayoutData")); |                                       CFSTR("kTISPropertyUnicodeKeyLayoutData")); | ||||||
|     CFStringRef* kNotifySelectedKeyboardInputSourceChanged = |  | ||||||
|         CFBundleGetDataPointerForName(_glfw.ns.tis.bundle, |  | ||||||
|                                       CFSTR("kTISNotifySelectedKeyboardInputSourceChanged")); |  | ||||||
|     _glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource = |     _glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource = | ||||||
|         CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle, |         CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle, | ||||||
|                                           CFSTR("TISCopyCurrentKeyboardLayoutInputSource")); |                                           CFSTR("TISCopyCurrentKeyboardLayoutInputSource")); | ||||||
| @@ -261,7 +363,6 @@ static GLFWbool initializeTIS(void) | |||||||
|                                           CFSTR("LMGetKbdType")); |                                           CFSTR("LMGetKbdType")); | ||||||
|  |  | ||||||
|     if (!kPropertyUnicodeKeyLayoutData || |     if (!kPropertyUnicodeKeyLayoutData || | ||||||
|         !kNotifySelectedKeyboardInputSourceChanged || |  | ||||||
|         !TISCopyCurrentKeyboardLayoutInputSource || |         !TISCopyCurrentKeyboardLayoutInputSource || | ||||||
|         !TISGetInputSourceProperty || |         !TISGetInputSourceProperty || | ||||||
|         !LMGetKbdType) |         !LMGetKbdType) | ||||||
| @@ -273,24 +374,93 @@ static GLFWbool initializeTIS(void) | |||||||
|  |  | ||||||
|     _glfw.ns.tis.kPropertyUnicodeKeyLayoutData = |     _glfw.ns.tis.kPropertyUnicodeKeyLayoutData = | ||||||
|         *kPropertyUnicodeKeyLayoutData; |         *kPropertyUnicodeKeyLayoutData; | ||||||
|     _glfw.ns.tis.kNotifySelectedKeyboardInputSourceChanged = |  | ||||||
|         *kNotifySelectedKeyboardInputSourceChanged; |  | ||||||
|  |  | ||||||
|     return updateUnicodeDataNS(); |     return updateUnicodeDataNS(); | ||||||
| } | } | ||||||
|  |  | ||||||
| @interface GLFWLayoutListener : NSObject | @interface GLFWHelper : NSObject | ||||||
| @end | @end | ||||||
|  |  | ||||||
| @implementation GLFWLayoutListener | @implementation GLFWHelper | ||||||
|  |  | ||||||
| - (void)selectedKeyboardInputSourceChanged:(NSObject* )object | - (void)selectedKeyboardInputSourceChanged:(NSObject* )object | ||||||
| { | { | ||||||
|     updateUnicodeDataNS(); |     updateUnicodeDataNS(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | - (void)doNothing:(id)object | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @end // GLFWHelper | ||||||
|  |  | ||||||
|  | @interface GLFWApplicationDelegate : NSObject <NSApplicationDelegate> | ||||||
| @end | @end | ||||||
|  |  | ||||||
|  | @implementation GLFWApplicationDelegate | ||||||
|  |  | ||||||
|  | - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender | ||||||
|  | { | ||||||
|  |     _GLFWwindow* window; | ||||||
|  |  | ||||||
|  |     for (window = _glfw.windowListHead;  window;  window = window->next) | ||||||
|  |         _glfwInputWindowCloseRequest(window); | ||||||
|  |  | ||||||
|  |     return NSTerminateCancel; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | - (void)applicationDidChangeScreenParameters:(NSNotification *) notification | ||||||
|  | { | ||||||
|  |     _GLFWwindow* window; | ||||||
|  |  | ||||||
|  |     for (window = _glfw.windowListHead;  window;  window = window->next) | ||||||
|  |     { | ||||||
|  |         if (window->context.client != GLFW_NO_API) | ||||||
|  |             [window->context.nsgl.object update]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _glfwPollMonitorsNS(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | - (void)applicationWillFinishLaunching:(NSNotification *)notification | ||||||
|  | { | ||||||
|  |     if (_glfw.hints.init.ns.menubar) | ||||||
|  |     { | ||||||
|  |         // In case we are unbundled, make us a proper UI application | ||||||
|  |         [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; | ||||||
|  |  | ||||||
|  |         // Menu bar setup must go between sharedApplication above and | ||||||
|  |         // finishLaunching below, in order to properly emulate the behavior | ||||||
|  |         // of NSApplicationMain | ||||||
|  |  | ||||||
|  |         if ([[NSBundle mainBundle] pathForResource:@"MainMenu" ofType:@"nib"]) | ||||||
|  |         { | ||||||
|  |             [[NSBundle mainBundle] loadNibNamed:@"MainMenu" | ||||||
|  |                                           owner:NSApp | ||||||
|  |                                 topLevelObjects:&_glfw.ns.nibObjects]; | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |             createMenuBar(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | - (void)applicationDidFinishLaunching:(NSNotification *)notification | ||||||
|  | { | ||||||
|  |     [NSApp stop:nil]; | ||||||
|  |  | ||||||
|  |     _glfwPlatformPostEmptyEvent(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | - (void)applicationDidHide:(NSNotification *)notification | ||||||
|  | { | ||||||
|  |     int i; | ||||||
|  |  | ||||||
|  |     for (i = 0;  i < _glfw.monitorCount;  i++) | ||||||
|  |         _glfwRestoreVideoModeNS(_glfw.monitors[i]); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @end // GLFWApplicationDelegate | ||||||
|  |  | ||||||
|  |  | ||||||
| ////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////// | ||||||
| //////                       GLFW platform API                      ////// | //////                       GLFW platform API                      ////// | ||||||
| @@ -298,18 +468,53 @@ static GLFWbool initializeTIS(void) | |||||||
|  |  | ||||||
| int _glfwPlatformInit(void) | int _glfwPlatformInit(void) | ||||||
| { | { | ||||||
|     _glfw.ns.autoreleasePool = [[NSAutoreleasePool alloc] init]; |     @autoreleasepool { | ||||||
|  |  | ||||||
|     _glfw.ns.listener = [[GLFWLayoutListener alloc] init]; |     _glfw.ns.helper = [[GLFWHelper alloc] init]; | ||||||
|     [[NSDistributedNotificationCenter defaultCenter] |  | ||||||
|         addObserver:_glfw.ns.listener |  | ||||||
|            selector:@selector(selectedKeyboardInputSourceChanged:) |  | ||||||
|                name:(__bridge NSString*)kTISNotifySelectedKeyboardInputSourceChanged |  | ||||||
|              object:nil]; |  | ||||||
|  |  | ||||||
| #if defined(_GLFW_USE_CHDIR) |     [NSThread detachNewThreadSelector:@selector(doNothing:) | ||||||
|  |                              toTarget:_glfw.ns.helper | ||||||
|  |                            withObject:nil]; | ||||||
|  |  | ||||||
|  |     if (NSApp) | ||||||
|  |         _glfw.ns.finishedLaunching = GLFW_TRUE; | ||||||
|  |  | ||||||
|  |     [NSApplication sharedApplication]; | ||||||
|  |  | ||||||
|  |     _glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init]; | ||||||
|  |     if (_glfw.ns.delegate == nil) | ||||||
|  |     { | ||||||
|  |         _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                         "Cocoa: Failed to create application delegate"); | ||||||
|  |         return GLFW_FALSE; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [NSApp setDelegate:_glfw.ns.delegate]; | ||||||
|  |  | ||||||
|  |     NSEvent* (^block)(NSEvent*) = ^ NSEvent* (NSEvent* event) | ||||||
|  |     { | ||||||
|  |         if ([event modifierFlags] & NSEventModifierFlagCommand) | ||||||
|  |             [[NSApp keyWindow] sendEvent:event]; | ||||||
|  |  | ||||||
|  |         return event; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     _glfw.ns.keyUpMonitor = | ||||||
|  |         [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyUp | ||||||
|  |                                               handler:block]; | ||||||
|  |  | ||||||
|  |     if (_glfw.hints.init.ns.chdir) | ||||||
|         changeToResourcesDirectory(); |         changeToResourcesDirectory(); | ||||||
| #endif |  | ||||||
|  |     // Press and Hold prevents some keys from emitting repeated characters | ||||||
|  |     NSDictionary* defaults = @{@"ApplePressAndHoldEnabled":@NO}; | ||||||
|  |     [[NSUserDefaults standardUserDefaults] registerDefaults:defaults]; | ||||||
|  |  | ||||||
|  |     [[NSNotificationCenter defaultCenter] | ||||||
|  |         addObserver:_glfw.ns.helper | ||||||
|  |            selector:@selector(selectedKeyboardInputSourceChanged:) | ||||||
|  |                name:NSTextInputContextKeyboardSelectionDidChangeNotification | ||||||
|  |              object:nil]; | ||||||
|  |  | ||||||
|     createKeyTables(); |     createKeyTables(); | ||||||
|  |  | ||||||
| @@ -322,17 +527,19 @@ int _glfwPlatformInit(void) | |||||||
|     if (!initializeTIS()) |     if (!initializeTIS()) | ||||||
|         return GLFW_FALSE; |         return GLFW_FALSE; | ||||||
|  |  | ||||||
|     if (!_glfwInitThreadLocalStoragePOSIX()) |  | ||||||
|         return GLFW_FALSE; |  | ||||||
|  |  | ||||||
|     _glfwInitTimerNS(); |     _glfwInitTimerNS(); | ||||||
|     _glfwInitJoysticksNS(); |     _glfwInitJoysticksNS(); | ||||||
|  |  | ||||||
|  |     _glfwPollMonitorsNS(); | ||||||
|     return GLFW_TRUE; |     return GLFW_TRUE; | ||||||
|  |  | ||||||
|  |     } // autoreleasepool | ||||||
| } | } | ||||||
|  |  | ||||||
| void _glfwPlatformTerminate(void) | void _glfwPlatformTerminate(void) | ||||||
| { | { | ||||||
|  |     @autoreleasepool { | ||||||
|  |  | ||||||
|     if (_glfw.ns.inputSource) |     if (_glfw.ns.inputSource) | ||||||
|     { |     { | ||||||
|         CFRelease(_glfw.ns.inputSource); |         CFRelease(_glfw.ns.inputSource); | ||||||
| @@ -353,43 +560,32 @@ void _glfwPlatformTerminate(void) | |||||||
|         _glfw.ns.delegate = nil; |         _glfw.ns.delegate = nil; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (_glfw.ns.listener) |     if (_glfw.ns.helper) | ||||||
|     { |     { | ||||||
|         [[NSDistributedNotificationCenter defaultCenter] |         [[NSNotificationCenter defaultCenter] | ||||||
|             removeObserver:_glfw.ns.listener |             removeObserver:_glfw.ns.helper | ||||||
|                       name:(__bridge NSString*)kTISNotifySelectedKeyboardInputSourceChanged |                       name:NSTextInputContextKeyboardSelectionDidChangeNotification | ||||||
|                     object:nil]; |                     object:nil]; | ||||||
|         [[NSDistributedNotificationCenter defaultCenter] |         [[NSNotificationCenter defaultCenter] | ||||||
|             removeObserver:_glfw.ns.listener]; |             removeObserver:_glfw.ns.helper]; | ||||||
|         [_glfw.ns.listener release]; |         [_glfw.ns.helper release]; | ||||||
|         _glfw.ns.listener = nil; |         _glfw.ns.helper = nil; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     [_glfw.ns.cursor release]; |     if (_glfw.ns.keyUpMonitor) | ||||||
|     _glfw.ns.cursor = nil; |         [NSEvent removeMonitor:_glfw.ns.keyUpMonitor]; | ||||||
|  |  | ||||||
|     free(_glfw.ns.clipboardString); |     free(_glfw.ns.clipboardString); | ||||||
|  |  | ||||||
|     _glfwTerminateNSGL(); |     _glfwTerminateNSGL(); | ||||||
|     _glfwTerminateJoysticksNS(); |     _glfwTerminateJoysticksNS(); | ||||||
|     _glfwTerminateThreadLocalStoragePOSIX(); |  | ||||||
|  |  | ||||||
|     [_glfw.ns.autoreleasePool release]; |     } // autoreleasepool | ||||||
|     _glfw.ns.autoreleasePool = nil; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| const char* _glfwPlatformGetVersionString(void) | const char* _glfwPlatformGetVersionString(void) | ||||||
| { | { | ||||||
|     return _GLFW_VERSION_NUMBER " Cocoa NSGL" |     return _GLFW_VERSION_NUMBER " Cocoa NSGL EGL OSMesa" | ||||||
| #if defined(_GLFW_USE_CHDIR) |  | ||||||
|         " chdir" |  | ||||||
| #endif |  | ||||||
| #if defined(_GLFW_USE_MENUBAR) |  | ||||||
|         " menubar" |  | ||||||
| #endif |  | ||||||
| #if defined(_GLFW_USE_RETINA) |  | ||||||
|         " retina" |  | ||||||
| #endif |  | ||||||
| #if defined(_GLFW_BUILD_DLL) | #if defined(_GLFW_BUILD_DLL) | ||||||
|         " dynamic" |         " dynamic" | ||||||
| #endif | #endif | ||||||
|   | |||||||
							
								
								
									
										26
									
								
								external/glfw/cocoa_joystick.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								external/glfw/cocoa_joystick.h
									
									
									
									
										vendored
									
									
								
							| @@ -1,7 +1,7 @@ | |||||||
| //======================================================================== | //======================================================================== | ||||||
| // GLFW 3.3 Cocoa - www.glfw.org | // GLFW 3.3 Cocoa - www.glfw.org | ||||||
| //------------------------------------------------------------------------ | //------------------------------------------------------------------------ | ||||||
| // Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org> | // Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org> | ||||||
| // | // | ||||||
| // This software is provided 'as-is', without any express or implied | // This software is provided 'as-is', without any express or implied | ||||||
| // warranty. In no event will the authors be held liable for any damages | // warranty. In no event will the authors be held liable for any damages | ||||||
| @@ -24,37 +24,27 @@ | |||||||
| // | // | ||||||
| //======================================================================== | //======================================================================== | ||||||
|  |  | ||||||
| #ifndef _glfw3_cocoa_joystick_h_ |  | ||||||
| #define _glfw3_cocoa_joystick_h_ |  | ||||||
|  |  | ||||||
| #include <IOKit/IOKitLib.h> | #include <IOKit/IOKitLib.h> | ||||||
| #include <IOKit/IOCFPlugIn.h> | #include <IOKit/IOCFPlugIn.h> | ||||||
| #include <IOKit/hid/IOHIDLib.h> | #include <IOKit/hid/IOHIDLib.h> | ||||||
| #include <IOKit/hid/IOHIDKeys.h> | #include <IOKit/hid/IOHIDKeys.h> | ||||||
|  |  | ||||||
| #define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE \ | #define _GLFW_PLATFORM_JOYSTICK_STATE         _GLFWjoystickNS ns | ||||||
|     _GLFWjoystickNS ns_js[GLFW_JOYSTICK_LAST + 1] | #define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE | ||||||
|  |  | ||||||
|  | #define _GLFW_PLATFORM_MAPPING_NAME "Mac OS X" | ||||||
|  |  | ||||||
| // Cocoa-specific per-joystick data | // Cocoa-specific per-joystick data | ||||||
| // | // | ||||||
| typedef struct _GLFWjoystickNS | typedef struct _GLFWjoystickNS | ||||||
| { | { | ||||||
|     GLFWbool        present; |     IOHIDDeviceRef      device; | ||||||
|     char            name[256]; |     CFMutableArrayRef   axes; | ||||||
|  |     CFMutableArrayRef   buttons; | ||||||
|     IOHIDDeviceRef deviceRef; |     CFMutableArrayRef   hats; | ||||||
|  |  | ||||||
|     CFMutableArrayRef axisElements; |  | ||||||
|     CFMutableArrayRef buttonElements; |  | ||||||
|     CFMutableArrayRef hatElements; |  | ||||||
|  |  | ||||||
|     float*          axes; |  | ||||||
|     unsigned char*  buttons; |  | ||||||
| } _GLFWjoystickNS; | } _GLFWjoystickNS; | ||||||
|  |  | ||||||
|  |  | ||||||
| void _glfwInitJoysticksNS(void); | void _glfwInitJoysticksNS(void); | ||||||
| void _glfwTerminateJoysticksNS(void); | void _glfwTerminateJoysticksNS(void); | ||||||
|  |  | ||||||
| #endif // _glfw3_cocoa_joystick_h_ |  | ||||||
|   | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user