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,116 @@
1
+ module BulldogPhysics
2
+ module Particles
3
+ module Collisions
4
+
5
+
6
+
7
+ # Keeps track of a set of particles, and provides the means to update them all.
8
+ class ParticleWorld
9
+
10
+
11
+ protected
12
+
13
+
14
+ attr_accessor :resolver
15
+
16
+ attr_accessor :max_contacts
17
+ attr_accessor :calculate_iterations
18
+
19
+
20
+ public
21
+
22
+ attr_accessor :contact_generators
23
+ attr_accessor :contacts
24
+ attr_accessor :particles
25
+ attr_accessor :registry
26
+
27
+ # Creates a new particle simulator that can handle up to the
28
+ # given number of contacts per frame. You can also optionally
29
+ # give a number of contact-resolution iterations to use. If you * don’t give a number of iterations, then twice the number of
30
+ # contacts will be used.
31
+ def initialize(max_contacts = 100, iterations = 1)
32
+ @max_contacts = max_contacts
33
+ @calculate_iterations = iterations
34
+ @particles = Array.new
35
+ @contacts = Array.new
36
+ @contact_generators = Array.new
37
+ @registry = ParticleForceRegistry.new
38
+ @resolver = ParticleContactResolver.new
39
+ end
40
+
41
+ # Initializes the world for a simulation frame. This clears * the force accumulators for particles in the world. After
42
+ # calling this, the particles can have their forces for this * frame added.
43
+ def start_frame()
44
+
45
+
46
+ @particles.each do |particle|
47
+ particle.clearAccumulator()
48
+ end
49
+ end
50
+
51
+ # Calls each of the registered contact generators to report * their contacts.
52
+ # Returns the number of generated contacts.
53
+ def generate_contacts()
54
+ limit = @max_contacts
55
+
56
+ #if @contacts.size == 0
57
+ # return 0
58
+ #end
59
+
60
+
61
+ for g in @contact_generators
62
+ used = g.add_contact(@contacts, limit)
63
+
64
+
65
+ limit -= used
66
+ # We’ve run out of contacts to fill. This means we’re missing // contacts.
67
+ if limit <= 0
68
+ break
69
+ end
70
+ end
71
+
72
+ #return number of contacts used
73
+ return @max_contacts - limit
74
+ end
75
+
76
+ # Integrates all the particles in this world forward in time
77
+ # by the given duration.
78
+ def integrate(duration)
79
+ @particles.each{|p| p.integrate(duration)}
80
+ end
81
+
82
+ def run_physics(duration)
83
+
84
+ # check for colliding and hitting floor
85
+
86
+ @contacts.clear
87
+
88
+ @registry.update_forces(duration)
89
+
90
+
91
+ integrate(duration)
92
+
93
+ used_contacts = generate_contacts()
94
+
95
+ if(used_contacts > 0)
96
+ if(@calculate_iterations > 0)
97
+ @resolver.iterations = used_contacts * 2
98
+ @resolver.resolve_contacts(@contacts, used_contacts, duration)
99
+ end
100
+ end
101
+
102
+ #@resolver.resolve_contacts(@contacts, @contacts.size, duration)
103
+
104
+ end
105
+
106
+ def add_gravity
107
+ gravity = ParticleGravity.new(Vector3.new(0, -0.5, 0))
108
+ @particles.each{|part| @registry.add(part, gravity)}
109
+ end
110
+
111
+ end
112
+
113
+
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,15 @@
1
+ module BulldogPhysics
2
+ module Particles
3
+ class Projectile
4
+
5
+ attr_accessor :particle, :start_time
6
+
7
+ def initialize()
8
+ @particle = Particle.new
9
+ @start_time = 0
10
+ end
11
+
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,43 @@
1
+ # make life easier by including all Physics files here
2
+ require 'rubygems'
3
+ require 'require_all'
4
+
5
+
6
+ class VirtualMethodCalledError < RuntimeError
7
+ attr :name
8
+ def initialize(name)
9
+ super("Virtual function '#{name}' called")
10
+ @name = name
11
+ end
12
+ end
13
+
14
+ class Module
15
+ def virtual(*methods)
16
+ methods.each do |m|
17
+ define_method(m) {
18
+ raise VirtualMethodCalledError, m
19
+ }
20
+ end
21
+ end
22
+ end
23
+
24
+ require './vector3.rb'
25
+ require './matrix3.rb'
26
+ require './matrix4.rb'
27
+ require './quaternion.rb'
28
+
29
+ module BulldogPhysics
30
+
31
+ def localToWorld(local, transform)
32
+ return tarnsform.transform(local)
33
+ end
34
+
35
+ def worldToLocal(world, transform)
36
+ inverseTransform = Matrix4.new
37
+ inverseTransform.setInverse(transform)
38
+ return inverseTransform.transform(world)
39
+ end
40
+
41
+ end
42
+
43
+ require_all 'Particles'
@@ -0,0 +1,21 @@
1
+ module GlStuff
2
+ class GlUtility
3
+
4
+ def self.draw_line(ax, ay, bx, by, width, r, g, b, a)
5
+ glDisable(GL_TEXTURE_2D);
6
+ #glEnable(GL_BLEND);
7
+ #glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
8
+ glColor4ub( r, g, b, a);
9
+
10
+ glLineWidth(width);
11
+ glBegin(GL_LINES);
12
+ glVertex2i( ax, ay);
13
+ glVertex2i( bx, by);
14
+ glEnd();
15
+
16
+ #glDisable(GL_BLEND);
17
+ glEnable(GL_TEXTURE_2D);
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,35 @@
1
+ module GlStuff
2
+
3
+ class Lighting
4
+
5
+ attr_accessor :ambient, :diffuse, :position, :lmodel_ambient, :no_mat, :mat_ambient, :mat_ambient_color, :mat_diffuse,
6
+ :mat_specular, :no_shininess, :low_shininess, :high_shininess, :mat_emission, :local_view
7
+
8
+
9
+ def initialize
10
+ @ambient = [ 0.0, 1.0, 0.0, 1.0 ]
11
+ @diffuse = [ 1.0, 1.0, 1.0, 1.0 ]
12
+ @position = [ 1.0, 5.0, 1.0, 0.0 ]
13
+ @lmodel_ambient = [ 0.4, 0.4, 0.4, 1.0 ]
14
+ @no_mat = [ 0.0, 0.0, 0.0, 1.0 ]
15
+ @mat_ambient = [ 0.7, 0.7, 0.7, 1.0 ]
16
+ @mat_ambient_color = [ 0.8, 0.8, 0.2, 1.0 ]
17
+ @mat_diffuse = [ 0.1, 0.5, 0.0, 1.0 ]
18
+ @mat_specular = [ 1.0, 1.0, 1.0, 1.0 ]
19
+ @no_shininess = [ 0.0 ]
20
+ @low_shininess = [ 5.0 ]
21
+ @high_shininess = [ 100.0 ]
22
+ @mat_emission = [0.3, 0.2, 0.2, 0.0]
23
+ @local_view = [ 0.0 ]
24
+ end
25
+
26
+ def setup
27
+ glEnable(GL_LIGHTING)
28
+ glEnable(GL_LIGHT0)
29
+ glShadeModel(GL_SMOOTH);
30
+ glLightfv(GL_LIGHT0, GL_POSITION, @position)
31
+ end
32
+
33
+ end
34
+
35
+ end
@@ -0,0 +1,24 @@
1
+ module GlStuff
2
+ class Material
3
+
4
+ attr_accessor :ambient, :diffuse, :specular, :shininess, :emission
5
+
6
+ def initialize()
7
+ @ambient = [ 0.7, 0.7, 0.7, 1.0 ]
8
+ @ambient_color = [ 0.8, 0.8, 0.2, 1.0 ]
9
+ @diffuse = [ 0.5, 0.5, 0.5, 1.0 ]
10
+ @specular = [ 1.0, 1.0, 1.0, 1.0 ]
11
+ @shininess = [ 0.0 ] # 0 is noe, 100 would be hide
12
+ @emission = [0.3, 0.2, 0.2, 0.0]
13
+ end
14
+
15
+ def setup_material
16
+ glMaterial(GL_FRONT, GL_AMBIENT, @ambient)
17
+ glMaterial(GL_FRONT, GL_DIFFUSE, @diffuse)
18
+ glMaterial(GL_FRONT, GL_SPECULAR, @specular)
19
+ glMaterial(GL_FRONT, GL_SHININESS, @shininess)
20
+ glMaterial(GL_FRONT, GL_EMISSION, @emission)
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,216 @@
1
+ class Terrain
2
+
3
+ attr_accessor :height_map_image, :terrain_grid_width, :terrain_grid_length, :terrain_normals
4
+
5
+ def initialize(surface)
6
+ @height_map_image = surface
7
+ @terrain_normals = Array.new
8
+ load_from_surface()
9
+ #compute_normals()
10
+ end
11
+
12
+ def load_from_surface
13
+ mode = @height_map_image.depth
14
+ puts mode
15
+ @terrain_grid_width = @height_map_image.width
16
+ @terrain_grid_length = @height_map_image.height
17
+ @terrain_heights = Array.new( @terrain_grid_width * @terrain_grid_length)
18
+ pixels = @height_map_image.pixels()
19
+ #puts pixels
20
+ puts pixels.size
21
+ for i in 0..@terrain_grid_length-1
22
+ for j in 0..@terrain_grid_width-1
23
+ #aux = mode * (i * @terrain_grid_width + j)
24
+ #index = aux + (mode - 1)
25
+ #puts@height_map_image.get_at(i,j)[1]
26
+ #if index < pixels.size
27
+ point_height = @height_map_image.get_at(i,j)[0] / 255.0
28
+ #puts point_height
29
+ #end
30
+ @terrain_heights[i * @terrain_grid_width + j] = point_height
31
+ end
32
+ end
33
+
34
+ for i in 0..10
35
+ #puts @terrain_heights[i * 1000]
36
+ end
37
+ end
38
+
39
+ def terrain_cross_product(x1, z1, x2, z2, x3, z3)
40
+ v1 = v2 = aux = Vector3.new
41
+
42
+ v1.x = (x2 - x1 )
43
+ v1.y = -@terrain_heights[z1 * @terrain_grid_width + x1] +
44
+ @terrain_heights[z2 * @terrain_grid_width + x2]
45
+ v1.z = (z2 - z1)
46
+
47
+ v2.x = (x3 - x1)
48
+ v2.y = -@terrain_heights[z1 * @terrain_grid_width + x1] +
49
+ @terrain_heights[z3 * @terrain_grid_width + x3]
50
+ v2.z = (z3 - z1)
51
+
52
+ v1 -= v1.crossProduct(v2)
53
+ end
54
+
55
+ def create_display_list(x_offset, y_offset, z_offset)
56
+
57
+ start_w = (@terrain_grid_width / 2.0) - @terrain_grid_width
58
+ start_l = (-@terrain_grid_length / 2.0) + @terrain_grid_length
59
+
60
+ terrain_dl = glGenLists(1)
61
+
62
+ glNewList(terrain_dl, GL_COMPILE)
63
+
64
+ for i in 0..(@terrain_grid_length - 2)
65
+ glBegin(GL_TRIANGLE_STRIP)
66
+ for j in 0..(@terrain_grid_width - 2)
67
+
68
+ unless @terrain_normals.empty?
69
+ glNormal3f(@terrain_normals[3*((i+1)*@terrain_grid_width)],
70
+ @terrain_normals[3*((i+1)*@terrain_grid_width)+1],
71
+ @terrain_normals[3*((i+1)*@terrain_grid_width)+2] )
72
+ end
73
+ glVertex3f(
74
+ start_w + j,
75
+ @terrain_heights[(i+1)*@terrain_grid_width + (j)],
76
+ start_l - (i+1)
77
+ )
78
+
79
+ unless @terrain_normals.empty?
80
+ glNormal3f(@terrain_normals[3*(i+@terrain_grid_width + j)],
81
+ @terrain_normals[3*(i+@terrain_grid_width + j)+1],
82
+ @terrain_normals[3*(i+@terrain_grid_width + j)+2] )
83
+ end
84
+
85
+ aux = 3 * ((i+1) * @terrain_grid_length + j)
86
+ glVertex3f( (start_w + j),
87
+ @terrain_heights[(i * @terrain_grid_width) + j],
88
+ (start_l - i)
89
+ )
90
+ end
91
+ glEnd()
92
+ end
93
+
94
+ glEndList()
95
+
96
+ terrain_dl
97
+ end
98
+
99
+
100
+ def terrain_scale(minnum, maxnum)
101
+ if minnum > maxnum
102
+ aux = minnum
103
+ minnum = maxnum
104
+ maxnum = aux
105
+ end
106
+
107
+ amp = maxnum - minnum
108
+
109
+ total = @terrain_grid_width * @terrain_grid_length
110
+
111
+ min_val = @terrain_heights.min
112
+ max_val = @terrain_heights.max
113
+ for i in 0..total-2
114
+ height = (@terrain_heights[i] - min_val) / (max_val - min_val)
115
+ if height == nil
116
+ next
117
+ end
118
+ @terrain_heights[i] = (height * amp) - minnum
119
+ #puts @terrain_heights[i]
120
+ end
121
+
122
+ compute_normals()
123
+ end
124
+
125
+ def compute_normals
126
+ norm1,norm2 = Vector3.new, Vector3.new
127
+ @terrain_normals = Array.new(@terrain_grid_width * @terrain_grid_length * 3)
128
+
129
+ return if @terrain_normals.nil?
130
+
131
+
132
+
133
+ for i in 0..@terrain_grid_length - 1
134
+ for j in 0..@terrain_grid_width - 1
135
+ norm1.clear
136
+ norm2.clear
137
+ if i == 0 && j == 0
138
+ norm1 = terrain_cross_product(0,0, 0,1, 1,0)
139
+ norm1.normalize()
140
+ elsif j == @terrain_grid_width-1 && i == @terrain_grid_length-1
141
+ norm1 = terrain_cross_product(j,i, j,i-1, j-1,i)
142
+ norm1.normalize()
143
+ elsif j == 0 && i == @terrain_grid_length-1
144
+ norm1 = terrain_cross_product(j,i, j,i-1, j+1, i)
145
+ norm1.normalize()
146
+ elsif j == @terrain_grid_width - 1 && i == 0
147
+ norm1 = terrain_cross_product(j,i, j,i+1, j-1,i)
148
+ elsif i == 0
149
+ norm1 = terrain_cross_product(j,0, j-1,0, j,1)
150
+ norm1.normalize
151
+ norm2 = terrain_cross_product(j,0, j,1, j+1,0)
152
+ norm2.normalize
153
+ norm1 += norm2
154
+ elsif j == 0
155
+ norm1 = terrain_cross_product(0,i, 1,i, 0,i-1)
156
+ norm1.normalize
157
+ norm2 = terrain_cross_product(j,0, j,1, j+1,0)
158
+ norm2.normalize
159
+ norm1 += norm2
160
+ elsif i == @terrain_grid_length-1
161
+ norm1 = terrain_cross_product(j,i, j,i-1, j+1,i);
162
+ norm1.normalize
163
+ norm2 = terrain_cross_product(j,i, j+1,i, j,i-1);
164
+ norm2.normalize
165
+ norm1 += norm2
166
+ elsif (j == @terrain_grid_width-1)
167
+ norm1 = terrain_cross_product(j,i, j,i-1, j-1,i);
168
+ norm1.normalize
169
+ norm2 = terrain_cross_product(j,i, j-1,i, j,i+1);
170
+ norm2.normalize
171
+ norm1 += norm2;
172
+ else
173
+ norm1 = terrain_cross_product(j,i, j-1,i, j-1,i+1).unit
174
+ norm2 = terrain_cross_product(j,i, j-1,i+1, j,i+1).unit
175
+ norm1 += norm2;
176
+
177
+ norm2 = terrain_cross_product(j,i, j,i+1, j+1,i+1).unit
178
+ norm1 += norm2;
179
+
180
+ norm2 = terrain_cross_product(j,i, j+1,i+1, j+1,i).unit
181
+ norm1 += norm2
182
+
183
+ norm2 = terrain_cross_product(j,i, j+1,i, j+1,i-1).unit
184
+ norm1 += norm2
185
+
186
+ norm2 = terrain_cross_product(j,i, j+1,i-1, j,i-1).unit
187
+ norm1 += norm2
188
+
189
+ norm2 = terrain_cross_product(j,i, j,i-1, j-1,i-1).unit
190
+ norm1 += norm2
191
+
192
+ norm2 = terrain_cross_product(j,i, j-1,i-1, j-1,i).unit
193
+ norm1 += norm2
194
+ end
195
+
196
+ norm1.normalize
197
+ norm1.z = - norm1.z
198
+
199
+ component = 0
200
+ for k in 0..3
201
+ case k
202
+ when 0
203
+ component = norm1.x
204
+ when 1
205
+ component = norm1.y
206
+ when 2
207
+ component = norm1.z
208
+ end
209
+ @terrain_normals[3*(i*@terrain_grid_width + j) + k] = component;
210
+ end
211
+ end
212
+ end
213
+ end
214
+
215
+
216
+ end