bulldog_physics 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. data/.document +5 -0
  2. data/Gemfile +13 -0
  3. data/Gemfile.lock +22 -0
  4. data/LICENSE.txt +20 -0
  5. data/README.rdoc +25 -0
  6. data/Rakefile +55 -0
  7. data/VERSION +1 -0
  8. data/bulldog_physics.gemspec +92 -0
  9. data/lib/Particles/particle.rb +75 -0
  10. data/lib/Particles/particle_anchored_spring.rb +42 -0
  11. data/lib/Particles/particle_cable.rb +52 -0
  12. data/lib/Particles/particle_contact.rb +121 -0
  13. data/lib/Particles/particle_contact_generator.rb +28 -0
  14. data/lib/Particles/particle_contact_resolver.rb +49 -0
  15. data/lib/Particles/particle_drag.rb +30 -0
  16. data/lib/Particles/particle_force_generator.rb +23 -0
  17. data/lib/Particles/particle_force_registration.rb +15 -0
  18. data/lib/Particles/particle_force_registry.rb +50 -0
  19. data/lib/Particles/particle_gravity.rb +31 -0
  20. data/lib/Particles/particle_ground_contacts.rb +43 -0
  21. data/lib/Particles/particle_link.rb +41 -0
  22. data/lib/Particles/particle_particle_contacts.rb +48 -0
  23. data/lib/Particles/particle_rod.rb +58 -0
  24. data/lib/Particles/particle_spring.rb +44 -0
  25. data/lib/Particles/particle_world.rb +116 -0
  26. data/lib/Particles/projectile.rb +15 -0
  27. data/lib/bulldog_physics.rb +43 -0
  28. data/lib/examples/GlStuff/gl_utility.rb +21 -0
  29. data/lib/examples/GlStuff/lighting.rb +35 -0
  30. data/lib/examples/GlStuff/material.rb +24 -0
  31. data/lib/examples/GlStuff/terrain.rb +216 -0
  32. data/lib/examples/simple_game.rb +289 -0
  33. data/lib/matrix3.rb +242 -0
  34. data/lib/matrix4.rb +230 -0
  35. data/lib/quaternion.rb +86 -0
  36. data/lib/vector3.rb +155 -0
  37. data/test/helper.rb +18 -0
  38. data/test/test_bulldog_physics.rb +7 -0
  39. metadata +190 -0
@@ -0,0 +1,28 @@
1
+ module BulldogPhysics
2
+ module Particles
3
+ module Collisions
4
+
5
+
6
+
7
+ # Links connect two particles together, generating a contact if * they violate the constraints of their link. It is used as a
8
+ # base class for cables and rods, and could be used as a base
9
+ # class for springs with a limit to their extension.
10
+
11
+ class ParticleContactGenerator
12
+
13
+ # Fills the given contact structure with the generated
14
+ # contact. The contact pointer should point to the first
15
+ # available contact in a contact array, where limit is the
16
+ # maximum number of contacts in the array that can be written * to. The method returns the number of contacts that have
17
+ # been written.
18
+ #def add_contact(contact, limit)
19
+ #end
20
+
21
+
22
+
23
+ end
24
+
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,49 @@
1
+ module BulldogPhysics
2
+ module Particles
3
+ module Collisions
4
+
5
+ REAL_MAX = 10000000
6
+ # The contact resolution routine for particle contacts.
7
+ # One resolver instance can be shared for the entire simulation.
8
+ class ParticleContactResolver
9
+
10
+ attr_accessor :iterations
11
+ attr_accessor :iterations_used
12
+
13
+ def initialize(iters = 2)
14
+ @iterations = iters
15
+ @iterations_used = 0
16
+ end
17
+
18
+ def resolve_contacts(contact_array, num_contacts, duration)
19
+
20
+ max_index = num_contacts
21
+ max = REAL_MAX
22
+ @iterations_used = 0
23
+ while( @iterations_used < @iterations )
24
+
25
+ contact_array.each_with_index do |contact, i|
26
+ sep_vel = contact.calculate_separating_velocity
27
+ if( sep_vel < max and ( sep_vel < 0 or contact.penetration > 0) )
28
+ max = sep_vel
29
+ max_index = i
30
+ end
31
+ end
32
+
33
+ if( max_index.eql? num_contacts)
34
+ break
35
+ end
36
+
37
+ contact_array[max_index].resolve(duration)
38
+
39
+ @iterations_used += 1
40
+ end # end while
41
+ contact_array
42
+ end # end resolve_contacts
43
+
44
+ end
45
+
46
+
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,30 @@
1
+ module BulldogPhysics
2
+ module Particles
3
+ module Generators
4
+
5
+ class ParticleDrag < ParticleForceGenerator
6
+ attr :kl # holds the velocity drag coefficient
7
+ attr :k2 # holds the velocity squared drag coefficient
8
+
9
+ def initialize(k1,k2)
10
+ super
11
+ @k1 = k1
12
+ @k2 = k2
13
+ end
14
+
15
+ def update_force(particle, duration)
16
+ force = particle.velocity
17
+
18
+ dragCoeff = force.magnitude
19
+
20
+ dragCoeff = k1 * dragCoeff + k2 * dragCoeff * dragCoeff
21
+
22
+ force.normalize
23
+ force *= -dragCoeff
24
+ particle.addForce(force)
25
+ end
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,23 @@
1
+ module BulldogPhysics
2
+ module Particles
3
+ module Generators
4
+
5
+ # A force generator can be asked to add a force to one or more particles.
6
+ class ParticleForceGenerator
7
+
8
+ attr_accessor :registrations
9
+
10
+ def initialize
11
+ @registrations = Array.new # array of ParticleForceRegistration(s)
12
+ end
13
+
14
+ # Overload this in implementations of the interface to calculate
15
+ # and update the force applied to the given particle.
16
+ def update_force(particle, duration)
17
+ end
18
+
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,15 @@
1
+ module BulldogPhysics
2
+ module Particles
3
+
4
+ # Keeps track of one force generator and the particle it applies to.
5
+ class ParticleForceRegistration
6
+ attr_accessor :particle, :particle_force_generator
7
+
8
+ def initialize()
9
+ @particle = Particle.new
10
+ @particle_force_generator = ParticleForceGenerator.new
11
+ end
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,50 @@
1
+ module BulldogPhysics
2
+ module Particles
3
+
4
+ class ParticleForceRegistry
5
+ attr_accessor :registrations
6
+
7
+ def initialize()
8
+ @registrations = Array.new # array of ParticleForceRegistration(s)
9
+ end
10
+
11
+ # Registers the given force generator to apply to the
12
+ # given particle.
13
+ def add(particle, force_generator)
14
+ particle_registration = ParticleForceRegistration.new
15
+ particle_registration.particle = particle
16
+ particle_registration.particle_force_generator = force_generator
17
+ @registrations << particle_registration
18
+ puts "Registration count #{@registrations.count}"
19
+ end
20
+
21
+
22
+ # Removes the given registered pair from the registry.
23
+ # If the pair is not registered, this method will have
24
+ # no effect.
25
+ def remove(particle,force_generator)
26
+ @registrations.remove_if do |registry|
27
+ registry.particle.eql? particle and registry.force_generator.eql? force_generator
28
+ end
29
+ end
30
+
31
+ ### Clears all registrations from the registry. This will
32
+ ### not delete the particles or the force generators
33
+ ### themselves, just the records of their connection.
34
+ def clear
35
+ @registrations = Array.new
36
+ end
37
+
38
+
39
+ #Calls all the force generators to update the forces of
40
+ #their corresponding particles.
41
+ def update_forces(duration)
42
+ for registry in @registrations
43
+ registry.particle_force_generator.update_force(registry.particle,duration)
44
+ end
45
+ end
46
+
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,31 @@
1
+ module BulldogPhysics
2
+ module Particles
3
+ module Generators
4
+
5
+ # A force generator that applies a gravitational force. One instance * can be used for multiple particles.
6
+ class ParticleGravity < ParticleForceGenerator
7
+ attr_accessor :gravity
8
+
9
+ def initialize(gravityForce = Vector3.new(0,-9.8,0))
10
+ #super if defined?(super)
11
+ @gravity = gravityForce # vector3
12
+ super()
13
+ end
14
+
15
+ #override
16
+ def update_force(particle, duration)
17
+ unless particle.has_infinite_mass
18
+ #puts "update_force"
19
+ #puts particle.mass
20
+ force_to_add = @gravity * particle.mass
21
+ particle.addForce(@gravity * particle.mass)
22
+ #puts particle.object_id
23
+ end
24
+ particle
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,43 @@
1
+ module BulldogPhysics
2
+ module Particles
3
+ module Collisions
4
+
5
+ class ParticleGroundContacts < ParticleContactGenerator
6
+
7
+ attr :particles
8
+
9
+ def initialize(particles)
10
+ @particles = particles
11
+ end
12
+
13
+ def add_contact(contactArray, limit)
14
+
15
+ count = 0
16
+ @particles.each do |p|
17
+
18
+ y = p.position.y
19
+
20
+ if y < 0.0
21
+ contact = ParticleContact.new(p, nil)
22
+ contact.penetration = (p.position - Vector3.new(p.position.x, 0, p.position.z)).magnitude.abs - p.radius
23
+ contact.restitution = 0.2
24
+ contactArray << contact
25
+ count+=1
26
+ end
27
+
28
+
29
+ if( count >= limit)
30
+ return count
31
+ end
32
+
33
+ end
34
+
35
+ return count
36
+
37
+ end
38
+
39
+
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,41 @@
1
+ module BulldogPhysics
2
+ module Particles
3
+ module Collisions
4
+
5
+
6
+ # Links connect two particles together, generating a contact if * they violate the constraints of their link. It is used as a
7
+ # base class for cables and rods, and could be used as a base
8
+ # class for springs with a limit to their extension.
9
+
10
+ class ParticleLink < ParticleContactGenerator
11
+
12
+ attr_accessor :particle1
13
+ attr_accessor :particle2
14
+
15
+ def initialize(particle1, particle2)
16
+ @particle1 = particle1
17
+ @particle2 = particle2
18
+ end
19
+
20
+ # Generates the contacts to keep this link from being
21
+ # violated. This class can only ever generate a single
22
+ # contact, so the pointer can be a pointer to a single
23
+ # element, the limit parameter is assumed to be at least 1
24
+ # (0 isn’t valid), and the return value is 0 if the
25
+ # cable wasn’t overextended, or 1 if a contact was needed. *
26
+ # NB: This method is declared in the same way (as pure
27
+ # virtual) in the parent class, but is replicated here for
28
+ # documentation purposes.
29
+
30
+ virtual :add_contact
31
+
32
+ protected
33
+
34
+ virtual :current_length
35
+
36
+ end
37
+
38
+
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,48 @@
1
+ module BulldogPhysics
2
+ module Particles
3
+ module Collisions
4
+
5
+
6
+
7
+ class ParticleParticleContacts < ParticleContactGenerator
8
+
9
+ attr :particles
10
+
11
+ def initialize(particles)
12
+ @particles = particles
13
+ end
14
+
15
+ def add_contact(contactArray, limit)
16
+
17
+ count = 0
18
+ @particles.each do |p|
19
+
20
+
21
+ other_particles = @particles.select{|x| x.object_id != p.object_id}
22
+ other_particles.each do |other|
23
+
24
+ if (p.position - other.position).magnitude < (p.radius + other.radius)
25
+ contact = ParticleContact.new(p, other)
26
+ contact.penetration = (p.position - other.position).magnitude - (p.radius + other.radius)
27
+ contact.restitution = 0.5
28
+ contactArray << contact
29
+ count+=1
30
+ end
31
+ end
32
+
33
+
34
+ if( count >= limit)
35
+ return count
36
+ end
37
+
38
+ end
39
+
40
+ return count
41
+
42
+ end
43
+
44
+
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,58 @@
1
+ module BulldogPhysics
2
+ module Particles
3
+ module Collisions
4
+
5
+
6
+ # Cables link a pair of particles, generating a contact if they stray too far apart.
7
+ class ParticleRod < ParticleLink
8
+
9
+
10
+ # Holds the length of the rod
11
+ attr_accessor :length
12
+
13
+
14
+ def initialize(particle1, particle2, length)
15
+ super(particle1, particle2)
16
+ @length = length
17
+ puts "CREATING ROD WITH LENGTH #{@length}"
18
+ end
19
+
20
+ # * Fills the given contact structure with the contact needed to keep the rod from extending or compressing.
21
+ def add_contact(contactArray, limit)
22
+ current_len = (@particle1.position - @particle2.position).magnitude
23
+
24
+ if( current_len == @length)
25
+ return 0
26
+ end
27
+
28
+
29
+ contact = ParticleContact.new(@particle1, @particle2)
30
+
31
+
32
+ # The contact normal depends on whether we’re extending or compressing.
33
+
34
+ if( current_len > @length)
35
+ contact.penetration = (current_len - @length)
36
+ #contact.penetration = -1
37
+ else
38
+ contact.contact_normal *= -1
39
+ contact.penetration = @length - current_len
40
+ #contact.penetration = 1
41
+ end
42
+
43
+ contact.restitution = 0
44
+ contactArray << contact
45
+
46
+ return 1
47
+ end
48
+
49
+ def current_length
50
+ (@particle1.position - @particle2.position).magnitude
51
+ end
52
+
53
+ end
54
+
55
+
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,44 @@
1
+ module BulldogPhysics
2
+ module Particles
3
+ module Generators
4
+
5
+ class ParticleSpring < ParticleForceGenerator
6
+
7
+ attr_accessor :other_particle # particle at other end of the spring
8
+ attr_accessor :spring_constant
9
+ attr_accessor :rest_length # rest length of the string
10
+
11
+
12
+ def initialize(other, spring_const, rest_len)
13
+ @other_particle = other
14
+ @spring_constant = spring_const
15
+ @rest_length = rest_len
16
+ end
17
+
18
+ def update_force(particle, duration)
19
+
20
+ #calculate vector of the spring
21
+ force = particle.position.dup
22
+
23
+ force.subtractVector(@other_particle.position)
24
+ # calculate magnitude of the force
25
+ magnitude = force.magnitude
26
+ magnitude = (magnitude - @rest_length).abs
27
+ magnitude *= @spring_constant
28
+
29
+ #calculate final force and apply it
30
+ force.normalize
31
+
32
+ force.multiplyByScalar(-magnitude)
33
+ particle.addForce(force)
34
+
35
+ end
36
+
37
+
38
+
39
+ end
40
+
41
+
42
+ end
43
+ end
44
+ end