mittsu 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 (203) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.travis.yml +3 -0
  4. data/CODE_OF_CONDUCT.md +13 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +39 -0
  8. data/Rakefile +7 -0
  9. data/bin/console +14 -0
  10. data/bin/setup +7 -0
  11. data/examples/01_-_Default1noCulling.png +0 -0
  12. data/examples/01_scene_example.rb +14 -0
  13. data/examples/02_box_mesh_example.rb +30 -0
  14. data/examples/02_sphere_mesh_example.rb +30 -0
  15. data/examples/03_complex_object_example.rb +52 -0
  16. data/examples/04_ambient_light_example.rb +33 -0
  17. data/examples/04_dir_light_example.rb +36 -0
  18. data/examples/04_hemi_light_example.rb +30 -0
  19. data/examples/04_point_light_example.rb +50 -0
  20. data/examples/04_spot_light_example.rb +44 -0
  21. data/examples/05_earth_example.rb +42 -0
  22. data/examples/05_earth_moon_example.rb +46 -0
  23. data/examples/05_texture_example.rb +32 -0
  24. data/examples/06_cube_texture_example.rb +36 -0
  25. data/examples/06_skybox_example.rb +60 -0
  26. data/examples/07_earth_normal_example.rb +36 -0
  27. data/examples/08_shadow_example.rb +87 -0
  28. data/examples/09_line_example.rb +52 -0
  29. data/examples/10_obj_loader_example.rb +68 -0
  30. data/examples/11_character_input_example.rb +18 -0
  31. data/examples/11_continuous_keyboard_input_example.rb +35 -0
  32. data/examples/11_keyboard_input_example.rb +43 -0
  33. data/examples/12_mouse_click_example.rb +38 -0
  34. data/examples/12_mouse_motion_example.rb +35 -0
  35. data/examples/12_mouse_scroll_example.rb +36 -0
  36. data/examples/12_orbit_zoom_example.rb +68 -0
  37. data/examples/13_joystick_example.rb +80 -0
  38. data/examples/cubemap/tron_bk.png +0 -0
  39. data/examples/cubemap/tron_dn.png +0 -0
  40. data/examples/cubemap/tron_ft.png +0 -0
  41. data/examples/cubemap/tron_lf.png +0 -0
  42. data/examples/cubemap/tron_rt.png +0 -0
  43. data/examples/cubemap/tron_up.png +0 -0
  44. data/examples/earth.png +0 -0
  45. data/examples/earth_normal.png +0 -0
  46. data/examples/example_helper.rb +2 -0
  47. data/examples/male-02-1noCulling.png +0 -0
  48. data/examples/male02.mtl +54 -0
  49. data/examples/male02.obj +13888 -0
  50. data/examples/moon.png +0 -0
  51. data/examples/orig_02_-_Defaul1noCulling.png +0 -0
  52. data/examples/texture.png +0 -0
  53. data/lib/mittsu.rb +15 -0
  54. data/lib/mittsu/cameras.rb +4 -0
  55. data/lib/mittsu/cameras/camera.rb +34 -0
  56. data/lib/mittsu/cameras/cube_camera.rb +74 -0
  57. data/lib/mittsu/cameras/orthographic_camera.rb +53 -0
  58. data/lib/mittsu/cameras/perspective_camera.rb +115 -0
  59. data/lib/mittsu/constants.rb +160 -0
  60. data/lib/mittsu/core.rb +10 -0
  61. data/lib/mittsu/core/buffer_attribute.rb +87 -0
  62. data/lib/mittsu/core/buffer_geometry.rb +694 -0
  63. data/lib/mittsu/core/clock.rb +44 -0
  64. data/lib/mittsu/core/dynamic_buffer_attribute.rb +16 -0
  65. data/lib/mittsu/core/event_dispatcher.rb +39 -0
  66. data/lib/mittsu/core/face3.rb +30 -0
  67. data/lib/mittsu/core/geometry.rb +596 -0
  68. data/lib/mittsu/core/hash_array.rb +36 -0
  69. data/lib/mittsu/core/hash_object.rb +19 -0
  70. data/lib/mittsu/core/object_3d.rb +421 -0
  71. data/lib/mittsu/core/raycaster.rb +78 -0
  72. data/lib/mittsu/extras.rb +3 -0
  73. data/lib/mittsu/extras/geometries.rb +2 -0
  74. data/lib/mittsu/extras/geometries/box_geometry.rb +108 -0
  75. data/lib/mittsu/extras/geometries/sphere_geometry.rb +88 -0
  76. data/lib/mittsu/extras/helpers.rb +1 -0
  77. data/lib/mittsu/extras/helpers/camera_helper.rb +155 -0
  78. data/lib/mittsu/extras/image.rb +3 -0
  79. data/lib/mittsu/extras/image_utils.rb +80 -0
  80. data/lib/mittsu/lights.rb +7 -0
  81. data/lib/mittsu/lights/ambient_light.rb +16 -0
  82. data/lib/mittsu/lights/area_light.rb +24 -0
  83. data/lib/mittsu/lights/directional_light.rb +131 -0
  84. data/lib/mittsu/lights/hemisphere_light.rb +29 -0
  85. data/lib/mittsu/lights/light.rb +21 -0
  86. data/lib/mittsu/lights/point_light.rb +27 -0
  87. data/lib/mittsu/lights/spot_light.rb +104 -0
  88. data/lib/mittsu/loaders.rb +7 -0
  89. data/lib/mittsu/loaders/cache.rb +53 -0
  90. data/lib/mittsu/loaders/file_loader.rb +22 -0
  91. data/lib/mittsu/loaders/image_loader.rb +32 -0
  92. data/lib/mittsu/loaders/loader.rb +212 -0
  93. data/lib/mittsu/loaders/loading_manager.rb +17 -0
  94. data/lib/mittsu/loaders/mtl_loader.rb +242 -0
  95. data/lib/mittsu/loaders/obj_mtl_loader.rb +225 -0
  96. data/lib/mittsu/materials.rb +7 -0
  97. data/lib/mittsu/materials/line_basic_material.rb +39 -0
  98. data/lib/mittsu/materials/material.rb +156 -0
  99. data/lib/mittsu/materials/mesh_basic_material.rb +122 -0
  100. data/lib/mittsu/materials/mesh_face_material.rb +30 -0
  101. data/lib/mittsu/materials/mesh_lambert_material.rb +126 -0
  102. data/lib/mittsu/materials/mesh_phong_material.rb +152 -0
  103. data/lib/mittsu/materials/shader_material.rb +108 -0
  104. data/lib/mittsu/math.rb +105 -0
  105. data/lib/mittsu/math/box2.rb +135 -0
  106. data/lib/mittsu/math/box3.rb +194 -0
  107. data/lib/mittsu/math/color.rb +252 -0
  108. data/lib/mittsu/math/color_keywords.rb +151 -0
  109. data/lib/mittsu/math/euler.rb +182 -0
  110. data/lib/mittsu/math/frustum.rb +106 -0
  111. data/lib/mittsu/math/line3.rb +76 -0
  112. data/lib/mittsu/math/matrix3.rb +163 -0
  113. data/lib/mittsu/math/matrix4.rb +581 -0
  114. data/lib/mittsu/math/plane.rb +128 -0
  115. data/lib/mittsu/math/quaternion.rb +309 -0
  116. data/lib/mittsu/math/ray.rb +292 -0
  117. data/lib/mittsu/math/sphere.rb +91 -0
  118. data/lib/mittsu/math/spline.rb +128 -0
  119. data/lib/mittsu/math/triangle.rb +121 -0
  120. data/lib/mittsu/math/vector2.rb +238 -0
  121. data/lib/mittsu/math/vector3.rb +491 -0
  122. data/lib/mittsu/math/vector4.rb +414 -0
  123. data/lib/mittsu/objects.rb +3 -0
  124. data/lib/mittsu/objects/group.rb +8 -0
  125. data/lib/mittsu/objects/line.rb +143 -0
  126. data/lib/mittsu/objects/mesh.rb +243 -0
  127. data/lib/mittsu/renderers.rb +1 -0
  128. data/lib/mittsu/renderers/glfw_window.rb +216 -0
  129. data/lib/mittsu/renderers/opengl/opengl_debug.rb +38 -0
  130. data/lib/mittsu/renderers/opengl/opengl_program.rb +402 -0
  131. data/lib/mittsu/renderers/opengl/opengl_shader.rb +58 -0
  132. data/lib/mittsu/renderers/opengl/opengl_state.rb +207 -0
  133. data/lib/mittsu/renderers/opengl/plugins/shadow_map_plugin.rb +416 -0
  134. data/lib/mittsu/renderers/opengl_render_target.rb +87 -0
  135. data/lib/mittsu/renderers/opengl_renderer.rb +3376 -0
  136. data/lib/mittsu/renderers/shaders/shader_chunk.rb +12 -0
  137. data/lib/mittsu/renderers/shaders/shader_chunk/alphamap_fragment.glsl +5 -0
  138. data/lib/mittsu/renderers/shaders/shader_chunk/alphamap_pars_fragment.glsl +5 -0
  139. data/lib/mittsu/renderers/shaders/shader_chunk/alphatest_fragment.glsl +5 -0
  140. data/lib/mittsu/renderers/shaders/shader_chunk/bumpmap_pars_fragment.glsl +40 -0
  141. data/lib/mittsu/renderers/shaders/shader_chunk/color_fragment.glsl +5 -0
  142. data/lib/mittsu/renderers/shaders/shader_chunk/color_pars_fragment.glsl +5 -0
  143. data/lib/mittsu/renderers/shaders/shader_chunk/color_pars_vertex.glsl +5 -0
  144. data/lib/mittsu/renderers/shaders/shader_chunk/color_vertex.glsl +5 -0
  145. data/lib/mittsu/renderers/shaders/shader_chunk/common.glsl +60 -0
  146. data/lib/mittsu/renderers/shaders/shader_chunk/default_vertex.glsl +15 -0
  147. data/lib/mittsu/renderers/shaders/shader_chunk/defaultnormal_vertex.glsl +21 -0
  148. data/lib/mittsu/renderers/shaders/shader_chunk/envmap_fragment.glsl +62 -0
  149. data/lib/mittsu/renderers/shaders/shader_chunk/envmap_pars_fragment.glsl +21 -0
  150. data/lib/mittsu/renderers/shaders/shader_chunk/envmap_pars_vertex.glsl +7 -0
  151. data/lib/mittsu/renderers/shaders/shader_chunk/envmap_vertex.glsl +17 -0
  152. data/lib/mittsu/renderers/shaders/shader_chunk/fog_fragment.glsl +26 -0
  153. data/lib/mittsu/renderers/shaders/shader_chunk/fog_pars_fragment.glsl +15 -0
  154. data/lib/mittsu/renderers/shaders/shader_chunk/lightmap_fragment.glsl +5 -0
  155. data/lib/mittsu/renderers/shaders/shader_chunk/lightmap_pars_fragment.glsl +6 -0
  156. data/lib/mittsu/renderers/shaders/shader_chunk/lightmap_pars_vertex.glsl +5 -0
  157. data/lib/mittsu/renderers/shaders/shader_chunk/lightmap_vertex.glsl +5 -0
  158. data/lib/mittsu/renderers/shaders/shader_chunk/lights_lambert_pars_vertex.glsl +43 -0
  159. data/lib/mittsu/renderers/shaders/shader_chunk/lights_lambert_vertex.glsl +196 -0
  160. data/lib/mittsu/renderers/shaders/shader_chunk/lights_phong_fragment.glsl +243 -0
  161. data/lib/mittsu/renderers/shaders/shader_chunk/lights_phong_pars_fragment.glsl +58 -0
  162. data/lib/mittsu/renderers/shaders/shader_chunk/lights_phong_pars_vertex.glsl +5 -0
  163. data/lib/mittsu/renderers/shaders/shader_chunk/lights_phong_vertex.glsl +5 -0
  164. data/lib/mittsu/renderers/shaders/shader_chunk/linear_to_gamma_fragment.glsl +2 -0
  165. data/lib/mittsu/renderers/shaders/shader_chunk/logdepthbuf_fragment.glsl +5 -0
  166. data/lib/mittsu/renderers/shaders/shader_chunk/logdepthbuf_pars_fragment.glsl +12 -0
  167. data/lib/mittsu/renderers/shaders/shader_chunk/logdepthbuf_pars_vertex.glsl +11 -0
  168. data/lib/mittsu/renderers/shaders/shader_chunk/logdepthbuf_vertex.glsl +15 -0
  169. data/lib/mittsu/renderers/shaders/shader_chunk/map_fragment.glsl +9 -0
  170. data/lib/mittsu/renderers/shaders/shader_chunk/map_pars_fragment.glsl +11 -0
  171. data/lib/mittsu/renderers/shaders/shader_chunk/map_pars_vertex.glsl +6 -0
  172. data/lib/mittsu/renderers/shaders/shader_chunk/map_particle_fragment.glsl +5 -0
  173. data/lib/mittsu/renderers/shaders/shader_chunk/map_particle_pars_fragment.glsl +6 -0
  174. data/lib/mittsu/renderers/shaders/shader_chunk/map_vertex.glsl +5 -0
  175. data/lib/mittsu/renderers/shaders/shader_chunk/morphnormal_vertex.glsl +12 -0
  176. data/lib/mittsu/renderers/shaders/shader_chunk/morphtarget_pars_vertex.glsl +13 -0
  177. data/lib/mittsu/renderers/shaders/shader_chunk/morphtarget_vertex.glsl +20 -0
  178. data/lib/mittsu/renderers/shaders/shader_chunk/normalmap_pars_fragment.glsl +27 -0
  179. data/lib/mittsu/renderers/shaders/shader_chunk/shadowmap_fragment.glsl +217 -0
  180. data/lib/mittsu/renderers/shaders/shader_chunk/shadowmap_pars_fragment.glsl +19 -0
  181. data/lib/mittsu/renderers/shaders/shader_chunk/shadowmap_pars_vertex.glsl +6 -0
  182. data/lib/mittsu/renderers/shaders/shader_chunk/shadowmap_vertex.glsl +9 -0
  183. data/lib/mittsu/renderers/shaders/shader_chunk/skinbase_vertex.glsl +8 -0
  184. data/lib/mittsu/renderers/shaders/shader_chunk/skinning_pars_vertex.glsl +47 -0
  185. data/lib/mittsu/renderers/shaders/shader_chunk/skinning_vertex.glsl +20 -0
  186. data/lib/mittsu/renderers/shaders/shader_chunk/skinnormal_vertex.glsl +20 -0
  187. data/lib/mittsu/renderers/shaders/shader_chunk/specularmap_fragment.glsl +12 -0
  188. data/lib/mittsu/renderers/shaders/shader_chunk/specularmap_pars_fragment.glsl +5 -0
  189. data/lib/mittsu/renderers/shaders/shader_chunk/worldpos_vertex.glsl +17 -0
  190. data/lib/mittsu/renderers/shaders/shader_lib.rb +420 -0
  191. data/lib/mittsu/renderers/shaders/uniforms_lib.rb +107 -0
  192. data/lib/mittsu/renderers/shaders/uniforms_utils.rb +31 -0
  193. data/lib/mittsu/scenes.rb +1 -0
  194. data/lib/mittsu/scenes/scene.rb +27 -0
  195. data/lib/mittsu/textures.rb +5 -0
  196. data/lib/mittsu/textures/compressed_texture.rb +30 -0
  197. data/lib/mittsu/textures/cube_texture.rb +19 -0
  198. data/lib/mittsu/textures/data_texture.rb +17 -0
  199. data/lib/mittsu/textures/texture.rb +92 -0
  200. data/lib/mittsu/textures/video_texture.rb +17 -0
  201. data/lib/mittsu/version.rb +4 -0
  202. data/mittsu.gemspec +31 -0
  203. metadata +357 -0
@@ -0,0 +1,243 @@
1
+ require 'mittsu/core'
2
+ require 'mittsu/materials'
3
+
4
+ module Mittsu
5
+ class Mesh < Object3D
6
+ attr_accessor :material, :morph_target_base
7
+
8
+ def initialize(geometry = Geometry.new, material = MeshBasicMaterial.new(color: rand * 0xffffff))
9
+ super()
10
+
11
+ @type = 'Mesh'
12
+
13
+ @geometry, @material = geometry, material
14
+
15
+ update_morph_targets
16
+ end
17
+
18
+ def update_morph_targets
19
+ if !@morph_targets.nil? && !@morph_targets.empty?
20
+ @morph_targets_base = -1
21
+ @morph_target_forced_order = []
22
+ @morph_targets_influences = []
23
+ @morph_targets_dictionary = {}
24
+
25
+ @geometry.morph_targets.each_with_index do |target, m|
26
+ @morph_targets_influences << 0
27
+ @morph_targets_dictionary[target.name] = m
28
+ end
29
+
30
+ def morph_target_index_by_name(name)
31
+ morph_target_index = @morph_targets_dictionary[name]
32
+ return morph_target_index unless morph_target_index.nil?
33
+
34
+ puts "WARNING: Mittsu::Mest#morph_target_index_by_name: morph target #{name} does not exist. Returning 0."
35
+ 0
36
+ end
37
+ end
38
+ end
39
+
40
+ def raycast(raycaster, intersects)
41
+ @_inverse_matrix = Matrix4.new
42
+ @_ray = Ray.new
43
+ @_sphere = Sphere.new
44
+
45
+ @_v_a = Vector3.new
46
+ @_v_b = Vector3.new
47
+ @_v_c = Vector3.new
48
+
49
+ # Checking bounding_sphere distance to ray
50
+
51
+ @geometry.compute_bounding_sphere if @geometry.bounding_sphere.nil?
52
+
53
+ sphere.copy(geometry.bounding_sphere)
54
+ sphere.apply_matrix4(@matrix_world)
55
+
56
+ return unless raycaster.intersection_sphere?(sphere)
57
+
58
+ # check bounding box before continuing
59
+
60
+ inverse_matrix.inverse(@matrix_world)
61
+ ray.copy(raycaster.ray).apply_matrix4(inverse_matrix)
62
+
63
+ if !geometry.bounding_bounding_box
64
+ return unless ray.intersection_box?(geometry.bounding_box)
65
+ end
66
+
67
+ if geometry.is_a?(BufferGeometry)
68
+ return if @material.nil?
69
+
70
+ attributes = geometry.attributes
71
+ precision = raycaster.precision
72
+
73
+ if !attributes[:index].nil?
74
+ indices = attributes[:index].array
75
+ positions = attributes[:position].array
76
+ offsets = geometry.offsets
77
+
78
+ offsets = [BufferGeometry::DrawCall.new(0, indices.length, 0)]
79
+
80
+ @offsets.each_with_index do |index, oi|
81
+ start = offsets[oi].start
82
+ count = offsets[oi].count
83
+ index = offsets[oi].index
84
+
85
+ i = start
86
+ il = start + count
87
+ while i < il
88
+ a = index + indices[i]
89
+ b = index + indices[i + 1]
90
+ c = index + indices[i + 2]
91
+
92
+ v_a.from_array(positions, a * 3)
93
+ v_b.from_array(positions, b * 3)
94
+ v_c.from_array(positions, c * 3)
95
+
96
+ if material.side = BackSide
97
+ intersection_point = ray.intersect_triangle(v_c, v_b, v_a, true)
98
+ else
99
+ intersection_point = ray.intersect_triangle(v_a, v_b, v_c, material.side != DoubleSide)
100
+ end
101
+
102
+ next if intersect_point.nil?
103
+
104
+ intersection_point.apply_matrix4(@matrix_world)
105
+
106
+ distance = racaster.ray.origin.distance_to(intersection_point)
107
+
108
+ next if distance < precision || distance < raycaster.near || distance > raycaster.far
109
+
110
+ intersects << {
111
+ distance: distance,
112
+ point: intersection_point,
113
+ face: Face.new(a, b, c, Triangle.normal(v_a, v_b, v_c)),
114
+ face_index: nil,
115
+ object: self
116
+ }
117
+ i += 3
118
+ end
119
+ end
120
+ else
121
+ positions = attributes[:position].array
122
+
123
+ i = 0
124
+ j = 0
125
+ il = positions.length
126
+ while i < il
127
+ a = i
128
+ b = i + 1
129
+ c = i + 2
130
+
131
+ v_a.from_array(positions, j)
132
+ v_b.from_array(positions, j + 3)
133
+ v_c.from_array(positions, j + 6)
134
+
135
+ if material.side = BackSide
136
+ intersection_point = ray.intersect_triangle(v_c, v_b, v_a, true)
137
+ else
138
+ intersection_point = ray.intersect_triangle(v_a, v_b, v_c, material.side != DoubleSide)
139
+ end
140
+
141
+ next if intersect_point.nil?
142
+
143
+ intersection_point.apply_matrix4(@matrix_world)
144
+
145
+ distance = racaster.ray.origin.distance_to(intersection_point)
146
+
147
+ next if distance < precision || distance < raycaster.near || distance > raycaster.far
148
+
149
+ intersects << {
150
+ distance: distance,
151
+ point: intersection_point,
152
+ face: Face.new(a, b, c, Triangle.normal(v_a, v_b, v_c)),
153
+ face_index: nil,
154
+ object: self
155
+ }
156
+
157
+ i += 3
158
+ j += 9
159
+ end
160
+ end
161
+ elsif geometry.is_a? Geometry
162
+ is_face_material = @material.is_a? MeshFaceMaterial
163
+ object_materials = is_face_material ? @material.materials : nil
164
+
165
+ precision = raycaster.precision
166
+
167
+ vertices = geometry.vertices
168
+
169
+ geometry.faces.each do |face|
170
+ material = is_face_material ? object_materials[face.material_index] : @material
171
+ next if material.nil?
172
+
173
+ a = vertices[face.a]
174
+ b = vertices[face.b]
175
+ c = vertices[face.c]
176
+
177
+ if material.morph_targets
178
+ morph_targets = geometry.morph_targets
179
+ morph_influences
180
+
181
+ v_a.set(0.0, 0.0, 0.0)
182
+ v_b.set(0.0, 0.0, 0.0)
183
+ v_c.set(0.0, 0.0, 0.0)
184
+
185
+ morph_targets.each_with_index do |morph_target, t|
186
+ influence = morph_influences[t]
187
+ next if influence.zero?
188
+
189
+ targets = morph_target.vertices
190
+
191
+ v_a.x += (targets[face.a].x - a.x) * influence
192
+ v_a.y += (targets[face.a].y - a.y) * influence
193
+ v_a.z += (targets[face.a].z - a.z) * influence
194
+
195
+ v_b.x += (targets[face.b].x - b.x) * influence
196
+ v_b.y += (targets[face.b].y - b.y) * influence
197
+ v_b.z += (targets[face.b].z - b.z) * influence
198
+
199
+ v_c.x += (targets[face.c].x - c.x) * influence
200
+ v_c.y += (targets[face.c].y - c.y) * influence
201
+ v_c.z += (targets[face.c].z - c.z) * influence
202
+ end
203
+
204
+ v_a.add(a)
205
+ v_b.add(b)
206
+ v_c.add(c)
207
+
208
+ a = v_a
209
+ b = v_b
210
+ c = v_c
211
+ end
212
+
213
+ if material.side = BackSide
214
+ intersection_point = ray.intersect_triangle(v_c, v_b, v_a, true)
215
+ else
216
+ intersection_point = ray.intersect_triangle(v_a, v_b, v_c, material.side != DoubleSide)
217
+ end
218
+
219
+ next if intersect_point.nil?
220
+
221
+ intersection_point.apply_matrix4(@matrix_world)
222
+
223
+ distance = racaster.ray.origin.distance_to(intersection_point)
224
+
225
+ next if distance < precision || distance < raycaster.near || distance > raycaster.far
226
+
227
+ intersects << {
228
+ distance: distance,
229
+ point: intersection_point,
230
+ face: face,
231
+ face_index: f,
232
+ object: self
233
+ }
234
+ end
235
+ end
236
+ end
237
+
238
+ def clone(object = Mesh.new(@geometry, @material), recursive = true)
239
+ super(object, recursive)
240
+ return object
241
+ end
242
+ end
243
+ end
@@ -0,0 +1 @@
1
+ require 'mittsu/renderers/opengl_renderer'
@@ -0,0 +1,216 @@
1
+ require 'opengl'
2
+ require 'glfw'
3
+
4
+ path = `pkg-config glfw3 --libs-only-L`.chomp.strip[2..-1]
5
+ GLFW.load_lib('libglfw3.dylib', path)
6
+
7
+ include GLFW
8
+
9
+ module Mittsu
10
+ module GLFW
11
+ class Window
12
+ attr_accessor :key_press_handler, :key_release_handler, :key_repeat_handler, :char_input_handler, :cursor_pos_handler, :mouse_button_press_handler, :mouse_button_release_handler, :scroll_handler, :framebuffer_size_handler
13
+
14
+ def initialize(width, height, title)
15
+ glfwInit
16
+
17
+ glfwWindowHint GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE
18
+ glfwWindowHint GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE
19
+ glfwWindowHint GLFW_CONTEXT_VERSION_MAJOR, 3
20
+ glfwWindowHint GLFW_CONTEXT_VERSION_MINOR, 3
21
+ glfwWindowHint GLFW_CONTEXT_REVISION, 0
22
+
23
+ @width, @height, @title = width, height, title
24
+ @handle = glfwCreateWindow(@width, @height, @title, nil, nil)
25
+ glfwMakeContextCurrent @handle
26
+ glfwSwapInterval 1
27
+
28
+ this = self
29
+ @key_callback = ::GLFW::create_callback(:GLFWkeyfun) do |window_handle, key, scancode, action, mods|
30
+ if action == GLFW_PRESS
31
+ this.key_press_handler.call(key) unless this.key_press_handler.nil?
32
+ this.key_repeat_handler.call(key) unless this.key_repeat_handler.nil?
33
+ elsif action == GLFW_RELEASE
34
+ this.key_release_handler.call(key) unless this.key_release_handler.nil?
35
+ elsif action == GLFW_REPEAT
36
+ this.key_repeat_handler.call(key) unless this.key_repeat_handler.nil?
37
+ end
38
+ end
39
+ glfwSetKeyCallback(@handle, @key_callback)
40
+
41
+ @char_callback = ::GLFW::create_callback(:GLFWcharfun) do |window_handle, codepoint|
42
+ char = [codepoint].pack('U')
43
+ this.char_input_handler.call(char) unless this.char_input_handler.nil?
44
+ end
45
+ glfwSetCharCallback(@handle, @char_callback)
46
+
47
+ @cursor_pos_callback = ::GLFW::create_callback(:GLFWcursorposfun) do |window_handle, xpos, ypos|
48
+ this.cursor_pos_handler.call(Vector2.new(xpos, ypos)) unless this.cursor_pos_handler.nil?
49
+ end
50
+ glfwSetCursorPosCallback(@handle, @cursor_pos_callback)
51
+
52
+ @mouse_button_callback = ::GLFW::create_callback(:GLFWmousebuttonfun) do |window_handle, button, action, mods|
53
+ mpos = this.mouse_position
54
+ if action == GLFW_PRESS
55
+ this.mouse_button_press_handler.call(button, mpos) unless this.mouse_button_press_handler.nil?
56
+ elsif action == GLFW_RELEASE
57
+ this.mouse_button_release_handler.call(button, mpos) unless this.mouse_button_release_handler.nil?
58
+ end
59
+ end
60
+ glfwSetMouseButtonCallback(@handle, @mouse_button_callback)
61
+
62
+ @scroll_callback = ::GLFW::create_callback(:GLFWscrollfun) do |window_handle, xoffset, yoffset|
63
+ this.scroll_handler.call(Vector2.new(xoffset, yoffset)) unless this.scroll_handler.nil?
64
+ end
65
+ glfwSetScrollCallback(@handle, @scroll_callback)
66
+
67
+ @frabuffer_size_callback = ::GLFW::create_callback(:GLFWframebuffersizefun) do |window_handle, new_width, new_height|
68
+ this.framebuffer_size_handler.call(new_width, new_height) unless this.framebuffer_size_handler.nil?
69
+ end
70
+ glfwSetFramebufferSizeCallback(@handle, @frabuffer_size_callback)
71
+
72
+ @joystick_buttons = poll_all_joysticks_buttons
73
+ end
74
+
75
+ def run
76
+ while glfwWindowShouldClose(@handle) == 0
77
+ yield
78
+
79
+ glfwSwapBuffers @handle
80
+ glfwPollEvents
81
+ poll_joystick_events
82
+ end
83
+ glfwDestroyWindow @handle
84
+ glfwTerminate
85
+ end
86
+
87
+ def framebuffer_size
88
+ width, height = ' '*8, ' '*8
89
+ glfwGetFramebufferSize(@handle, width, height)
90
+ [width.unpack('L')[0], height.unpack('L')[0]]
91
+ end
92
+
93
+ def on_key_pressed &block
94
+ @key_press_handler = block
95
+ end
96
+
97
+ def on_key_released &block
98
+ @key_release_handler = block
99
+ end
100
+
101
+ def on_key_typed &block
102
+ @key_repeat_handler = block
103
+ end
104
+
105
+ def key_down?(key)
106
+ glfwGetKey(@handle, key) == GLFW_PRESS
107
+ end
108
+
109
+ def on_character_input &block
110
+ @char_input_handler = block
111
+ end
112
+
113
+ def on_mouse_move &block
114
+ @cursor_pos_handler = block
115
+ end
116
+
117
+ def on_mouse_button_pressed &block
118
+ @mouse_button_press_handler = block
119
+ end
120
+
121
+ def on_mouse_button_released &block
122
+ @mouse_button_release_handler = block
123
+ end
124
+
125
+ def mouse_position
126
+ xpos, ypos = ' '*8, ' '*8
127
+ glfwGetCursorPos(@handle, xpos, ypos);
128
+ Vector2.new(xpos.unpack('D')[0], ypos.unpack('D')[0])
129
+ end
130
+
131
+ def mouse_button_down?(button)
132
+ glfwGetMouseButton(@handle, button) == GLFW_PRESS
133
+ end
134
+
135
+ def on_scroll &block
136
+ @scroll_handler = block
137
+ end
138
+
139
+ def on_resize &block
140
+ @framebuffer_size_handler = block
141
+ end
142
+
143
+ def joystick_buttons(joystick = GLFW_JOYSTICK_1)
144
+ @joystick_buttons = poll_all_joysticks_buttons
145
+ @joystick_buttons[joystick]
146
+ end
147
+
148
+ def joystick_axes(joystick = GLFW_JOYSTICK_1)
149
+ return [] unless joystick_present?(joystick)
150
+ count = ' ' * 4
151
+ array = glfwGetJoystickAxes(joystick, count)
152
+ count = count.unpack('l')[0]
153
+ array[0, count * 4].unpack('f' * count)
154
+ end
155
+
156
+ def on_joystick_button_pressed &block
157
+ @joystick_button_press_handler = block
158
+ end
159
+
160
+ def on_joystick_button_released &block
161
+ @joystick_button_release_handler = block
162
+ end
163
+
164
+ def joystick_present?(joystick = GLFW_JOYSTICK_1)
165
+ glfwJoystickPresent(joystick).nonzero?
166
+ end
167
+
168
+ def joystick_button_down?(button, joystick = GLFW_JOYSTICK_1)
169
+ @joystick_buttons[joystick][button]
170
+ end
171
+
172
+ def joystick_name(joystick = GLFW_JOYSTICK_1)
173
+ glfwGetJoystickName(joystick)
174
+ end
175
+
176
+ private
177
+
178
+ def poll_all_joysticks_buttons
179
+ (GLFW_JOYSTICK_1..GLFW_JOYSTICK_LAST).map do |joystick|
180
+ poll_joystick_buttons(joystick)
181
+ end
182
+ end
183
+
184
+ def poll_joystick_buttons(joystick)
185
+ return nil unless joystick_present?(joystick)
186
+ count = ' ' * 4
187
+ array = glfwGetJoystickButtons(joystick, count)
188
+ count = count.unpack('l')[0]
189
+ array[0, count].unpack('c' * count).map(&:nonzero?)
190
+ end
191
+
192
+ def poll_joystick_events
193
+ new_joystick_buttons = poll_all_joysticks_buttons
194
+ new_joystick_buttons.each_with_index do |buttons, joystick|
195
+ poll_single_joystick_events(joystick, buttons)
196
+ end
197
+ @joystick_buttons = new_joystick_buttons
198
+ end
199
+
200
+ def poll_single_joystick_events(joystick, buttons)
201
+ return if buttons.nil?
202
+ buttons.each_with_index do |pressed, button|
203
+ fire_joystick_button_event(joystick, button, pressed)
204
+ end
205
+ end
206
+
207
+ def fire_joystick_button_event(joystick, button, pressed)
208
+ if !@joystick_buttons[joystick][button] && pressed
209
+ @joystick_button_press_handler.call(joystick, button) unless @joystick_button_press_handler.nil?
210
+ elsif @joystick_buttons[joystick][button] && !pressed
211
+ @joystick_button_release_handler.call(joystick, button) unless @joystick_button_release_handler.nil?
212
+ end
213
+ end
214
+ end
215
+ end
216
+ end