3rb 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 (100) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +2 -0
  3. data/3rb.gemspec +29 -0
  4. data/CHANGELOG.md +12 -0
  5. data/LICENSE +21 -0
  6. data/README.md +321 -0
  7. data/Rakefile +13 -0
  8. data/examples/01_hello_cube.rb +29 -0
  9. data/examples/02_basic_geometries.rb +56 -0
  10. data/examples/03_materials.rb +61 -0
  11. data/examples/04_lighting.rb +63 -0
  12. data/examples/05_animation.rb +79 -0
  13. data/examples/06_custom_shader.rb +92 -0
  14. data/examples/07_scene_graph.rb +74 -0
  15. data/examples/08_orbit_controls.rb +50 -0
  16. data/examples/09_3d_chart.rb +71 -0
  17. data/examples/10_procedural_terrain.rb +140 -0
  18. data/examples/11_particle_system.rb +68 -0
  19. data/examples/12_model_loader.rb +73 -0
  20. data/examples/13_game_prototype.rb +145 -0
  21. data/examples/14_utah_teapot.rb +291 -0
  22. data/examples/15_stanford_bunny.rb +200 -0
  23. data/examples/16_cornell_box.rb +373 -0
  24. data/examples/17_weird_fractal4.rb +130 -0
  25. data/examples/18_platonic_solids.rb +268 -0
  26. data/lib/3rb/animation/animation_clip.rb +287 -0
  27. data/lib/3rb/animation/animation_mixer.rb +366 -0
  28. data/lib/3rb/cameras/camera.rb +50 -0
  29. data/lib/3rb/cameras/orthographic_camera.rb +92 -0
  30. data/lib/3rb/cameras/perspective_camera.rb +103 -0
  31. data/lib/3rb/controls/orbit_controls.rb +341 -0
  32. data/lib/3rb/core/buffer_attribute.rb +172 -0
  33. data/lib/3rb/core/group.rb +9 -0
  34. data/lib/3rb/core/object3d.rb +298 -0
  35. data/lib/3rb/core/scene.rb +78 -0
  36. data/lib/3rb/dsl/helpers.rb +57 -0
  37. data/lib/3rb/dsl/scene_builder.rb +288 -0
  38. data/lib/3rb/ffi/glfw.rb +61 -0
  39. data/lib/3rb/ffi/opengl.rb +137 -0
  40. data/lib/3rb/ffi/platform.rb +65 -0
  41. data/lib/3rb/geometries/box_geometry.rb +101 -0
  42. data/lib/3rb/geometries/buffer_geometry.rb +345 -0
  43. data/lib/3rb/geometries/cone_geometry.rb +29 -0
  44. data/lib/3rb/geometries/cylinder_geometry.rb +149 -0
  45. data/lib/3rb/geometries/plane_geometry.rb +75 -0
  46. data/lib/3rb/geometries/sphere_geometry.rb +93 -0
  47. data/lib/3rb/geometries/torus_geometry.rb +77 -0
  48. data/lib/3rb/lights/ambient_light.rb +9 -0
  49. data/lib/3rb/lights/directional_light.rb +57 -0
  50. data/lib/3rb/lights/hemisphere_light.rb +26 -0
  51. data/lib/3rb/lights/light.rb +27 -0
  52. data/lib/3rb/lights/point_light.rb +68 -0
  53. data/lib/3rb/lights/rect_area_light.rb +35 -0
  54. data/lib/3rb/lights/spot_light.rb +88 -0
  55. data/lib/3rb/loaders/gltf_loader.rb +304 -0
  56. data/lib/3rb/loaders/loader.rb +94 -0
  57. data/lib/3rb/loaders/obj_loader.rb +186 -0
  58. data/lib/3rb/loaders/texture_loader.rb +55 -0
  59. data/lib/3rb/materials/basic_material.rb +70 -0
  60. data/lib/3rb/materials/lambert_material.rb +102 -0
  61. data/lib/3rb/materials/material.rb +114 -0
  62. data/lib/3rb/materials/phong_material.rb +106 -0
  63. data/lib/3rb/materials/shader_material.rb +104 -0
  64. data/lib/3rb/materials/standard_material.rb +106 -0
  65. data/lib/3rb/math/color.rb +246 -0
  66. data/lib/3rb/math/euler.rb +156 -0
  67. data/lib/3rb/math/math_utils.rb +132 -0
  68. data/lib/3rb/math/matrix3.rb +269 -0
  69. data/lib/3rb/math/matrix4.rb +501 -0
  70. data/lib/3rb/math/quaternion.rb +337 -0
  71. data/lib/3rb/math/vector2.rb +216 -0
  72. data/lib/3rb/math/vector3.rb +366 -0
  73. data/lib/3rb/math/vector4.rb +233 -0
  74. data/lib/3rb/native/gl.rb +382 -0
  75. data/lib/3rb/native/native.rb +55 -0
  76. data/lib/3rb/native/window.rb +111 -0
  77. data/lib/3rb/native.rb +9 -0
  78. data/lib/3rb/objects/line.rb +116 -0
  79. data/lib/3rb/objects/mesh.rb +40 -0
  80. data/lib/3rb/objects/points.rb +71 -0
  81. data/lib/3rb/renderers/opengl_renderer.rb +567 -0
  82. data/lib/3rb/renderers/renderer.rb +60 -0
  83. data/lib/3rb/renderers/shader_lib.rb +100 -0
  84. data/lib/3rb/textures/cube_texture.rb +26 -0
  85. data/lib/3rb/textures/data_texture.rb +35 -0
  86. data/lib/3rb/textures/render_target.rb +125 -0
  87. data/lib/3rb/textures/texture.rb +190 -0
  88. data/lib/3rb/version.rb +5 -0
  89. data/lib/3rb.rb +86 -0
  90. data/shaders/basic.frag +19 -0
  91. data/shaders/basic.vert +15 -0
  92. data/shaders/common/lights.glsl +53 -0
  93. data/shaders/common/uniforms.glsl +9 -0
  94. data/shaders/lambert.frag +37 -0
  95. data/shaders/lambert.vert +22 -0
  96. data/shaders/phong.frag +51 -0
  97. data/shaders/phong.vert +28 -0
  98. data/shaders/standard.frag +92 -0
  99. data/shaders/standard.vert +28 -0
  100. metadata +155 -0
@@ -0,0 +1,382 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sunrb
4
+ module Native
5
+ module GL
6
+ class << self
7
+ def clear_color(r, g, b, a)
8
+ FFI::OpenGL.glClearColor(r, g, b, a)
9
+ nil
10
+ end
11
+
12
+ def clear(mask)
13
+ FFI::OpenGL.glClear(mask)
14
+ nil
15
+ end
16
+
17
+ def viewport(x, y, width, height)
18
+ FFI::OpenGL.glViewport(x, y, width, height)
19
+ nil
20
+ end
21
+
22
+ def enable(cap)
23
+ FFI::OpenGL.glEnable(cap)
24
+ nil
25
+ end
26
+
27
+ def disable(cap)
28
+ FFI::OpenGL.glDisable(cap)
29
+ nil
30
+ end
31
+
32
+ def depth_func(func)
33
+ FFI::OpenGL.glDepthFunc(func)
34
+ nil
35
+ end
36
+
37
+ def blend_func(sfactor, dfactor)
38
+ FFI::OpenGL.glBlendFunc(sfactor, dfactor)
39
+ nil
40
+ end
41
+
42
+ def cull_face(mode)
43
+ FFI::OpenGL.glCullFace(mode)
44
+ nil
45
+ end
46
+
47
+ def front_face(mode)
48
+ FFI::OpenGL.glFrontFace(mode)
49
+ nil
50
+ end
51
+
52
+ def get_error
53
+ FFI::OpenGL.glGetError
54
+ end
55
+
56
+ def get_string(name)
57
+ ptr = FFI::OpenGL.glGetString(name)
58
+ return nil if ptr.nil? || ptr.null?
59
+
60
+ ptr.read_string
61
+ end
62
+
63
+ def polygon_mode(face, mode)
64
+ FFI::OpenGL.glPolygonMode(face, mode)
65
+ nil
66
+ end
67
+
68
+ def line_width(width)
69
+ FFI::OpenGL.glLineWidth(width)
70
+ nil
71
+ end
72
+
73
+ def create_shader(type)
74
+ FFI::OpenGL.glCreateShader(type)
75
+ end
76
+
77
+ def shader_source(shader, source)
78
+ src_ptr = ::FFI::MemoryPointer.from_string(source)
79
+ src_ptr_ptr = ::FFI::MemoryPointer.new(:pointer)
80
+ src_ptr_ptr.write_pointer(src_ptr)
81
+
82
+ len_ptr = ::FFI::MemoryPointer.new(:int)
83
+ len_ptr.write_int(source.bytesize)
84
+
85
+ FFI::OpenGL.glShaderSource(shader, 1, src_ptr_ptr, len_ptr)
86
+ nil
87
+ end
88
+
89
+ def compile_shader(shader)
90
+ FFI::OpenGL.glCompileShader(shader)
91
+ nil
92
+ end
93
+
94
+ def get_shader_iv(shader, pname)
95
+ result_ptr = ::FFI::MemoryPointer.new(:int)
96
+ FFI::OpenGL.glGetShaderiv(shader, pname, result_ptr)
97
+ result_ptr.read_int
98
+ end
99
+
100
+ def get_shader_info_log(shader)
101
+ length = get_shader_iv(shader, FFI::OpenGL::GL_INFO_LOG_LENGTH)
102
+ return "" if length <= 0
103
+
104
+ log_ptr = ::FFI::MemoryPointer.new(:char, length)
105
+ FFI::OpenGL.glGetShaderInfoLog(shader, length, nil, log_ptr)
106
+ log_ptr.read_string
107
+ end
108
+
109
+ def delete_shader(shader)
110
+ FFI::OpenGL.glDeleteShader(shader)
111
+ nil
112
+ end
113
+
114
+ def create_program
115
+ FFI::OpenGL.glCreateProgram
116
+ end
117
+
118
+ def attach_shader(program, shader)
119
+ FFI::OpenGL.glAttachShader(program, shader)
120
+ nil
121
+ end
122
+
123
+ def link_program(program)
124
+ FFI::OpenGL.glLinkProgram(program)
125
+ nil
126
+ end
127
+
128
+ def get_program_iv(program, pname)
129
+ result_ptr = ::FFI::MemoryPointer.new(:int)
130
+ FFI::OpenGL.glGetProgramiv(program, pname, result_ptr)
131
+ result_ptr.read_int
132
+ end
133
+
134
+ def get_program_info_log(program)
135
+ length = get_program_iv(program, FFI::OpenGL::GL_INFO_LOG_LENGTH)
136
+ return "" if length <= 0
137
+
138
+ log_ptr = ::FFI::MemoryPointer.new(:char, length)
139
+ FFI::OpenGL.glGetProgramInfoLog(program, length, nil, log_ptr)
140
+ log_ptr.read_string
141
+ end
142
+
143
+ def use_program(program)
144
+ FFI::OpenGL.glUseProgram(program)
145
+ nil
146
+ end
147
+
148
+ def delete_program(program)
149
+ FFI::OpenGL.glDeleteProgram(program)
150
+ nil
151
+ end
152
+
153
+ def get_uniform_location(program, name)
154
+ FFI::OpenGL.glGetUniformLocation(program, name)
155
+ end
156
+
157
+ def uniform_1f(location, v0)
158
+ FFI::OpenGL.glUniform1f(location, v0)
159
+ nil
160
+ end
161
+
162
+ def uniform_2f(location, v0, v1)
163
+ FFI::OpenGL.glUniform2f(location, v0, v1)
164
+ nil
165
+ end
166
+
167
+ def uniform_3f(location, v0, v1, v2)
168
+ FFI::OpenGL.glUniform3f(location, v0, v1, v2)
169
+ nil
170
+ end
171
+
172
+ def uniform_4f(location, v0, v1, v2, v3)
173
+ FFI::OpenGL.glUniform4f(location, v0, v1, v2, v3)
174
+ nil
175
+ end
176
+
177
+ def uniform_1i(location, v0)
178
+ FFI::OpenGL.glUniform1i(location, v0)
179
+ nil
180
+ end
181
+
182
+ def uniform_matrix4fv(location, transpose, value)
183
+ buffer = ::FFI::MemoryPointer.new(:float, 16)
184
+ buffer.write_array_of_float(value.map(&:to_f))
185
+ FFI::OpenGL.glUniformMatrix4fv(location, 1, transpose ? 1 : 0, buffer)
186
+ nil
187
+ end
188
+
189
+ def uniform_matrix3fv(location, transpose, value)
190
+ buffer = ::FFI::MemoryPointer.new(:float, 9)
191
+ buffer.write_array_of_float(value.map(&:to_f))
192
+ FFI::OpenGL.glUniformMatrix3fv(location, 1, transpose ? 1 : 0, buffer)
193
+ nil
194
+ end
195
+
196
+ def gen_vertex_arrays(n)
197
+ buffer = ::FFI::MemoryPointer.new(:uint, n)
198
+ FFI::OpenGL.glGenVertexArrays(n, buffer)
199
+ buffer.read_array_of_uint(n)
200
+ end
201
+
202
+ def bind_vertex_array(array)
203
+ FFI::OpenGL.glBindVertexArray(array)
204
+ nil
205
+ end
206
+
207
+ def delete_vertex_arrays(arrays)
208
+ arrays = Array(arrays)
209
+ buffer = ::FFI::MemoryPointer.new(:uint, arrays.length)
210
+ buffer.write_array_of_uint(arrays)
211
+ FFI::OpenGL.glDeleteVertexArrays(arrays.length, buffer)
212
+ nil
213
+ end
214
+
215
+ def gen_buffers(n)
216
+ buffer = ::FFI::MemoryPointer.new(:uint, n)
217
+ FFI::OpenGL.glGenBuffers(n, buffer)
218
+ buffer.read_array_of_uint(n)
219
+ end
220
+
221
+ def bind_buffer(target, buffer)
222
+ FFI::OpenGL.glBindBuffer(target, buffer)
223
+ nil
224
+ end
225
+
226
+ def buffer_data(target, data, usage)
227
+ data = data.map(&:to_f)
228
+ buffer = ::FFI::MemoryPointer.new(:float, data.length)
229
+ buffer.write_array_of_float(data)
230
+ FFI::OpenGL.glBufferData(target, data.length * 4, buffer, usage)
231
+ nil
232
+ end
233
+
234
+ def buffer_data_uint(target, data, usage)
235
+ data = data.map(&:to_i)
236
+ buffer = ::FFI::MemoryPointer.new(:uint, data.length)
237
+ buffer.write_array_of_uint(data)
238
+ FFI::OpenGL.glBufferData(target, data.length * 4, buffer, usage)
239
+ nil
240
+ end
241
+
242
+ def delete_buffers(buffers)
243
+ buffers = Array(buffers)
244
+ buffer = ::FFI::MemoryPointer.new(:uint, buffers.length)
245
+ buffer.write_array_of_uint(buffers)
246
+ FFI::OpenGL.glDeleteBuffers(buffers.length, buffer)
247
+ nil
248
+ end
249
+
250
+ def vertex_attrib_pointer(index, size, type, normalized, stride, offset)
251
+ offset_ptr = ::FFI::Pointer.new(:void, offset)
252
+ FFI::OpenGL.glVertexAttribPointer(index, size, type, normalized ? 1 : 0, stride, offset_ptr)
253
+ nil
254
+ end
255
+
256
+ def enable_vertex_attrib_array(index)
257
+ FFI::OpenGL.glEnableVertexAttribArray(index)
258
+ nil
259
+ end
260
+
261
+ def disable_vertex_attrib_array(index)
262
+ FFI::OpenGL.glDisableVertexAttribArray(index)
263
+ nil
264
+ end
265
+
266
+ def draw_arrays(mode, first, count)
267
+ FFI::OpenGL.glDrawArrays(mode, first, count)
268
+ nil
269
+ end
270
+
271
+ def draw_elements(mode, count, type, offset)
272
+ offset_ptr = ::FFI::Pointer.new(:void, offset)
273
+ FFI::OpenGL.glDrawElements(mode, count, type, offset_ptr)
274
+ nil
275
+ end
276
+
277
+ def gen_textures(n)
278
+ buffer = ::FFI::MemoryPointer.new(:uint, n)
279
+ FFI::OpenGL.glGenTextures(n, buffer)
280
+ buffer.read_array_of_uint(n)
281
+ end
282
+
283
+ def bind_texture(target, texture)
284
+ FFI::OpenGL.glBindTexture(target, texture)
285
+ nil
286
+ end
287
+
288
+ def tex_parameter_i(target, pname, param)
289
+ FFI::OpenGL.glTexParameteri(target, pname, param)
290
+ nil
291
+ end
292
+
293
+ def active_texture(texture)
294
+ FFI::OpenGL.glActiveTexture(texture)
295
+ nil
296
+ end
297
+
298
+ def delete_textures(textures)
299
+ textures = Array(textures)
300
+ buffer = ::FFI::MemoryPointer.new(:uint, textures.length)
301
+ buffer.write_array_of_uint(textures)
302
+ FFI::OpenGL.glDeleteTextures(textures.length, buffer)
303
+ nil
304
+ end
305
+
306
+ def tex_image_2d(target, level, internal_format, width, height, border, format, type, data)
307
+ if data.nil?
308
+ FFI::OpenGL.glTexImage2D(target, level, internal_format, width, height, border, format, type, nil)
309
+ else
310
+ data = data.map(&:to_i)
311
+ buffer = ::FFI::MemoryPointer.new(:uchar, data.length)
312
+ buffer.write_array_of_uchar(data)
313
+ FFI::OpenGL.glTexImage2D(target, level, internal_format, width, height, border, format, type, buffer)
314
+ end
315
+ nil
316
+ end
317
+ end
318
+
319
+ COLOR_BUFFER_BIT = FFI::OpenGL::GL_COLOR_BUFFER_BIT
320
+ DEPTH_BUFFER_BIT = FFI::OpenGL::GL_DEPTH_BUFFER_BIT
321
+ STENCIL_BUFFER_BIT = FFI::OpenGL::GL_STENCIL_BUFFER_BIT
322
+
323
+ DEPTH_TEST = FFI::OpenGL::GL_DEPTH_TEST
324
+ BLEND = FFI::OpenGL::GL_BLEND
325
+ CULL_FACE = FFI::OpenGL::GL_CULL_FACE
326
+
327
+ LESS = FFI::OpenGL::GL_LESS
328
+ LEQUAL = FFI::OpenGL::GL_LEQUAL
329
+ GREATER = FFI::OpenGL::GL_GREATER
330
+
331
+ SRC_ALPHA = FFI::OpenGL::GL_SRC_ALPHA
332
+ ONE_MINUS_SRC_ALPHA = FFI::OpenGL::GL_ONE_MINUS_SRC_ALPHA
333
+
334
+ FRONT = FFI::OpenGL::GL_FRONT
335
+ BACK = FFI::OpenGL::GL_BACK
336
+ FRONT_AND_BACK = FFI::OpenGL::GL_FRONT_AND_BACK
337
+ LINE = FFI::OpenGL::GL_LINE
338
+ FILL = FFI::OpenGL::GL_FILL
339
+
340
+ CW = FFI::OpenGL::GL_CW
341
+ CCW = FFI::OpenGL::GL_CCW
342
+
343
+ VERTEX_SHADER = FFI::OpenGL::GL_VERTEX_SHADER
344
+ FRAGMENT_SHADER = FFI::OpenGL::GL_FRAGMENT_SHADER
345
+ COMPILE_STATUS = FFI::OpenGL::GL_COMPILE_STATUS
346
+ LINK_STATUS = FFI::OpenGL::GL_LINK_STATUS
347
+
348
+ ARRAY_BUFFER = FFI::OpenGL::GL_ARRAY_BUFFER
349
+ ELEMENT_ARRAY_BUFFER = FFI::OpenGL::GL_ELEMENT_ARRAY_BUFFER
350
+ STATIC_DRAW = FFI::OpenGL::GL_STATIC_DRAW
351
+ DYNAMIC_DRAW = FFI::OpenGL::GL_DYNAMIC_DRAW
352
+
353
+ FLOAT = FFI::OpenGL::GL_FLOAT
354
+ UNSIGNED_INT = FFI::OpenGL::GL_UNSIGNED_INT
355
+ UNSIGNED_BYTE = FFI::OpenGL::GL_UNSIGNED_BYTE
356
+
357
+ TRIANGLES = FFI::OpenGL::GL_TRIANGLES
358
+ LINES = FFI::OpenGL::GL_LINES
359
+ POINTS = FFI::OpenGL::GL_POINTS
360
+
361
+ TEXTURE_2D = FFI::OpenGL::GL_TEXTURE_2D
362
+ TEXTURE0 = FFI::OpenGL::GL_TEXTURE0
363
+ TEXTURE_MIN_FILTER = FFI::OpenGL::GL_TEXTURE_MIN_FILTER
364
+ TEXTURE_MAG_FILTER = FFI::OpenGL::GL_TEXTURE_MAG_FILTER
365
+ TEXTURE_WRAP_S = FFI::OpenGL::GL_TEXTURE_WRAP_S
366
+ TEXTURE_WRAP_T = FFI::OpenGL::GL_TEXTURE_WRAP_T
367
+ LINEAR = FFI::OpenGL::GL_LINEAR
368
+ NEAREST = FFI::OpenGL::GL_NEAREST
369
+ REPEAT = FFI::OpenGL::GL_REPEAT
370
+ CLAMP_TO_EDGE = FFI::OpenGL::GL_CLAMP_TO_EDGE
371
+ RGBA = FFI::OpenGL::GL_RGBA
372
+ RGB = FFI::OpenGL::GL_RGB
373
+
374
+ VENDOR = FFI::OpenGL::GL_VENDOR
375
+ RENDERER = FFI::OpenGL::GL_RENDERER
376
+ VERSION = FFI::OpenGL::GL_VERSION
377
+
378
+ TRUE = FFI::OpenGL::GL_TRUE
379
+ FALSE = FFI::OpenGL::GL_FALSE
380
+ end
381
+ end
382
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sunrb
4
+ module Native
5
+ @glfw_initialized = false
6
+
7
+ class << self
8
+ def init_glfw
9
+ return true if @glfw_initialized
10
+
11
+ result = FFI::GLFW.glfwInit
12
+ raise RuntimeError, "Failed to initialize GLFW" if result == 0
13
+
14
+ @glfw_initialized = true
15
+ true
16
+ end
17
+
18
+ def terminate_glfw
19
+ return unless @glfw_initialized
20
+
21
+ FFI::GLFW.glfwTerminate
22
+ @glfw_initialized = false
23
+ nil
24
+ end
25
+
26
+ def poll_events
27
+ FFI::GLFW.glfwPollEvents
28
+ nil
29
+ end
30
+
31
+ def get_time
32
+ FFI::GLFW.glfwGetTime
33
+ end
34
+ end
35
+
36
+ KEY_ESCAPE = FFI::GLFW::KEY_ESCAPE
37
+ KEY_SPACE = FFI::GLFW::KEY_SPACE
38
+ KEY_W = FFI::GLFW::KEY_W
39
+ KEY_A = FFI::GLFW::KEY_A
40
+ KEY_S = FFI::GLFW::KEY_S
41
+ KEY_D = FFI::GLFW::KEY_D
42
+ KEY_UP = FFI::GLFW::KEY_UP
43
+ KEY_DOWN = FFI::GLFW::KEY_DOWN
44
+ KEY_LEFT = FFI::GLFW::KEY_LEFT
45
+ KEY_RIGHT = FFI::GLFW::KEY_RIGHT
46
+
47
+ MOUSE_BUTTON_LEFT = FFI::GLFW::MOUSE_BUTTON_LEFT
48
+ MOUSE_BUTTON_RIGHT = FFI::GLFW::MOUSE_BUTTON_RIGHT
49
+ MOUSE_BUTTON_MIDDLE = FFI::GLFW::MOUSE_BUTTON_MIDDLE
50
+
51
+ PRESS = FFI::GLFW::PRESS
52
+ RELEASE = FFI::GLFW::RELEASE
53
+ REPEAT = FFI::GLFW::REPEAT
54
+ end
55
+ end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sunrb
4
+ module Native
5
+ class Window
6
+ def initialize(width, height, title)
7
+ FFI::GLFW.glfwWindowHint(FFI::GLFW::CONTEXT_VERSION_MAJOR, 3)
8
+ FFI::GLFW.glfwWindowHint(FFI::GLFW::CONTEXT_VERSION_MINOR, 3)
9
+ FFI::GLFW.glfwWindowHint(FFI::GLFW::OPENGL_PROFILE, FFI::GLFW::OPENGL_CORE_PROFILE)
10
+
11
+ if FFI::Platform.os == :macos
12
+ FFI::GLFW.glfwWindowHint(FFI::GLFW::OPENGL_FORWARD_COMPAT, 1)
13
+ end
14
+
15
+ @handle = FFI::GLFW.glfwCreateWindow(width, height, title, nil, nil)
16
+ raise RuntimeError, "Failed to create GLFW window" if @handle.nil? || @handle.null?
17
+
18
+ FFI::GLFW.glfwMakeContextCurrent(@handle)
19
+ FFI::GLFW.glfwSwapInterval(1)
20
+
21
+ @width = width
22
+ @height = height
23
+ end
24
+
25
+ def should_close?
26
+ return true if @handle.nil? || @handle.null?
27
+
28
+ FFI::GLFW.glfwWindowShouldClose(@handle) != 0
29
+ end
30
+
31
+ def should_close=(value)
32
+ return if @handle.nil? || @handle.null?
33
+
34
+ FFI::GLFW.glfwSetWindowShouldClose(@handle, value ? 1 : 0)
35
+ end
36
+
37
+ def swap_buffers
38
+ return if @handle.nil? || @handle.null?
39
+
40
+ FFI::GLFW.glfwSwapBuffers(@handle)
41
+ end
42
+
43
+ def make_current
44
+ return if @handle.nil? || @handle.null?
45
+
46
+ FFI::GLFW.glfwMakeContextCurrent(@handle)
47
+ end
48
+
49
+ def width
50
+ update_framebuffer_size
51
+ @fb_width || 0
52
+ end
53
+
54
+ def height
55
+ update_framebuffer_size
56
+ @fb_height || 0
57
+ end
58
+
59
+ def size
60
+ update_framebuffer_size
61
+ [@fb_width || 0, @fb_height || 0]
62
+ end
63
+
64
+ def title=(title)
65
+ return if @handle.nil? || @handle.null?
66
+
67
+ FFI::GLFW.glfwSetWindowTitle(@handle, title)
68
+ end
69
+
70
+ def get_key(key)
71
+ return FFI::GLFW::RELEASE if @handle.nil? || @handle.null?
72
+
73
+ FFI::GLFW.glfwGetKey(@handle, key)
74
+ end
75
+
76
+ def get_mouse_button(button)
77
+ return FFI::GLFW::RELEASE if @handle.nil? || @handle.null?
78
+
79
+ FFI::GLFW.glfwGetMouseButton(@handle, button)
80
+ end
81
+
82
+ def cursor_pos
83
+ return [0.0, 0.0] if @handle.nil? || @handle.null?
84
+
85
+ x_ptr = ::FFI::MemoryPointer.new(:double)
86
+ y_ptr = ::FFI::MemoryPointer.new(:double)
87
+ FFI::GLFW.glfwGetCursorPos(@handle, x_ptr, y_ptr)
88
+ [x_ptr.read_double, y_ptr.read_double]
89
+ end
90
+
91
+ def destroy
92
+ if @handle && !@handle.null?
93
+ FFI::GLFW.glfwDestroyWindow(@handle)
94
+ @handle = nil
95
+ end
96
+ end
97
+
98
+ private
99
+
100
+ def update_framebuffer_size
101
+ return unless @handle && !@handle.null?
102
+
103
+ w_ptr = ::FFI::MemoryPointer.new(:int)
104
+ h_ptr = ::FFI::MemoryPointer.new(:int)
105
+ FFI::GLFW.glfwGetFramebufferSize(@handle, w_ptr, h_ptr)
106
+ @fb_width = w_ptr.read_int
107
+ @fb_height = h_ptr.read_int
108
+ end
109
+ end
110
+ end
111
+ end
data/lib/3rb/native.rb ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ffi"
4
+ require_relative "ffi/platform"
5
+ require_relative "ffi/glfw"
6
+ require_relative "ffi/opengl"
7
+ require_relative "native/native"
8
+ require_relative "native/window"
9
+ require_relative "native/gl"
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sunrb
4
+ class LineBasicMaterial < Material
5
+ attr_accessor :color, :linewidth, :linecap, :linejoin
6
+
7
+ def initialize(color: 0xffffff, linewidth: 1)
8
+ super()
9
+ @color = color.is_a?(Color) ? color : Color.new(color)
10
+ @linewidth = linewidth
11
+ @linecap = "round"
12
+ @linejoin = "round"
13
+ @lights = false
14
+ end
15
+
16
+ def copy(source)
17
+ super
18
+ @color = source.color.clone
19
+ @linewidth = source.linewidth
20
+ @linecap = source.linecap
21
+ @linejoin = source.linejoin
22
+ self
23
+ end
24
+
25
+ def to_h
26
+ super.merge(
27
+ color: @color.get_hex,
28
+ linewidth: @linewidth
29
+ )
30
+ end
31
+ end
32
+
33
+ class Line < Object3D
34
+ attr_accessor :geometry, :material
35
+
36
+ def initialize(geometry = nil, material = nil)
37
+ super()
38
+ @geometry = geometry || BufferGeometry.new
39
+ @material = material || LineBasicMaterial.new
40
+ end
41
+
42
+ def copy(source, recursive = true)
43
+ super
44
+ @material = source.material.clone
45
+ @geometry = source.geometry.clone
46
+ self
47
+ end
48
+
49
+ def clone(recursive = true)
50
+ new_line = super
51
+ new_line.geometry = @geometry.clone
52
+ new_line.material = @material.clone
53
+ new_line
54
+ end
55
+
56
+ def compute_line_distances
57
+ position = @geometry.get_attribute(:position)
58
+ return self unless position
59
+
60
+ line_distances = [0.0]
61
+
62
+ (1...position.count).each do |i|
63
+ p1 = Vector3.new(
64
+ position.get_x(i - 1),
65
+ position.get_y(i - 1),
66
+ position.get_z(i - 1)
67
+ )
68
+ p2 = Vector3.new(
69
+ position.get_x(i),
70
+ position.get_y(i),
71
+ position.get_z(i)
72
+ )
73
+ line_distances.push(line_distances.last + p1.distance_to(p2))
74
+ end
75
+
76
+ @geometry.set_attribute(:line_distance, Float32BufferAttribute.new(line_distances, 1))
77
+ self
78
+ end
79
+
80
+ def to_h
81
+ super.merge(
82
+ geometry: @geometry.uuid,
83
+ material: @material.uuid
84
+ )
85
+ end
86
+ end
87
+
88
+ class LineLoop < Line
89
+ end
90
+
91
+ class LineSegments < Line
92
+ def compute_line_distances
93
+ position = @geometry.get_attribute(:position)
94
+ return self unless position
95
+
96
+ line_distances = []
97
+
98
+ (0...position.count).step(2) do |i|
99
+ p1 = Vector3.new(
100
+ position.get_x(i),
101
+ position.get_y(i),
102
+ position.get_z(i)
103
+ )
104
+ p2 = Vector3.new(
105
+ position.get_x(i + 1),
106
+ position.get_y(i + 1),
107
+ position.get_z(i + 1)
108
+ )
109
+ line_distances.push(0, p1.distance_to(p2))
110
+ end
111
+
112
+ @geometry.set_attribute(:line_distance, Float32BufferAttribute.new(line_distances, 1))
113
+ self
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sunrb
4
+ class Mesh < Object3D
5
+ attr_accessor :geometry, :material
6
+
7
+ def initialize(geometry = nil, material = nil)
8
+ super()
9
+ @geometry = geometry || BufferGeometry.new
10
+ @material = material || MeshBasicMaterial.new
11
+ end
12
+
13
+ def copy(source, recursive = true)
14
+ super
15
+ @material = source.material.is_a?(Array) ? source.material.map(&:clone) : source.material.clone
16
+ @geometry = source.geometry.clone
17
+ self
18
+ end
19
+
20
+ def clone(recursive = true)
21
+ new_mesh = super
22
+ new_mesh.geometry = @geometry.clone
23
+ new_mesh.material = @material.is_a?(Array) ? @material.map(&:clone) : @material.clone
24
+ new_mesh
25
+ end
26
+
27
+ def raycast(_raycaster, _intersects)
28
+ end
29
+
30
+ def update_morph_targets
31
+ end
32
+
33
+ def to_h
34
+ super.merge(
35
+ geometry: @geometry.uuid,
36
+ material: @material.is_a?(Array) ? @material.map(&:uuid) : @material.uuid
37
+ )
38
+ end
39
+ end
40
+ end