three-rb 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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +19 -0
- data/LICENSE +21 -0
- data/README.md +153 -0
- data/docs/browser-runtime.md +153 -0
- data/docs/implementation-plan.md +874 -0
- data/docs/loaded-assets-design.md +400 -0
- data/docs/next-work.md +107 -0
- data/docs/publishing.md +64 -0
- data/docs/release-readiness.md +83 -0
- data/examples/browser/README.md +54 -0
- data/examples/browser/assets/animated_triangle.gltf +123 -0
- data/examples/browser/assets/checker.svg +11 -0
- data/examples/browser/assets/compressed_triangle.gltf +74 -0
- data/examples/browser/assets/studio.hdr +5 -0
- data/examples/browser/assets/triangle.gltf +67 -0
- data/examples/browser/composition/README.md +35 -0
- data/examples/browser/composition/boot.mjs +6 -0
- data/examples/browser/composition/index.html +136 -0
- data/examples/browser/composition/main.rb +216 -0
- data/examples/browser/composition/smoke_test.mjs +266 -0
- data/examples/browser/cube/README.md +41 -0
- data/examples/browser/cube/boot.mjs +6 -0
- data/examples/browser/cube/index.html +142 -0
- data/examples/browser/cube/main.rb +62 -0
- data/examples/browser/cube/smoke_test.mjs +99 -0
- data/examples/browser/cubemap/README.md +23 -0
- data/examples/browser/cubemap/boot.mjs +6 -0
- data/examples/browser/cubemap/index.html +142 -0
- data/examples/browser/cubemap/main.rb +84 -0
- data/examples/browser/cubemap/smoke_test.mjs +91 -0
- data/examples/browser/gltf/README.md +23 -0
- data/examples/browser/gltf/boot.mjs +6 -0
- data/examples/browser/gltf/index.html +142 -0
- data/examples/browser/gltf/main.rb +105 -0
- data/examples/browser/gltf/smoke_test.mjs +162 -0
- data/examples/browser/picking/README.md +33 -0
- data/examples/browser/picking/boot.mjs +6 -0
- data/examples/browser/picking/index.html +142 -0
- data/examples/browser/picking/main.rb +113 -0
- data/examples/browser/picking/smoke_test.mjs +78 -0
- data/examples/browser/postprocessing/README.md +26 -0
- data/examples/browser/postprocessing/boot.mjs +6 -0
- data/examples/browser/postprocessing/index.html +142 -0
- data/examples/browser/postprocessing/main.rb +117 -0
- data/examples/browser/postprocessing/smoke_test.mjs +121 -0
- data/examples/browser/primitives/README.md +33 -0
- data/examples/browser/primitives/boot.mjs +6 -0
- data/examples/browser/primitives/index.html +142 -0
- data/examples/browser/primitives/main.rb +116 -0
- data/examples/browser/primitives/smoke_test.mjs +113 -0
- data/examples/browser/serialization/README.md +33 -0
- data/examples/browser/serialization/boot.mjs +6 -0
- data/examples/browser/serialization/index.html +142 -0
- data/examples/browser/serialization/main.rb +97 -0
- data/examples/browser/serialization/smoke_test.mjs +67 -0
- data/examples/browser/shared/boot.mjs +79 -0
- data/examples/browser/shared/smoke_test_helpers.mjs +151 -0
- data/examples/browser/textures/README.md +35 -0
- data/examples/browser/textures/boot.mjs +6 -0
- data/examples/browser/textures/index.html +142 -0
- data/examples/browser/textures/main.rb +142 -0
- data/examples/browser/textures/smoke_test.mjs +189 -0
- data/lib/three/animation/animation_action.rb +57 -0
- data/lib/three/animation/animation_clip.rb +22 -0
- data/lib/three/animation/animation_mixer.rb +43 -0
- data/lib/three/backends/base.rb +87 -0
- data/lib/three/backends/threejs/materialization.rb +143 -0
- data/lib/three/backends/threejs/parameters.rb +97 -0
- data/lib/three/backends/threejs/resource_management.rb +69 -0
- data/lib/three/backends/threejs/ruby_wasm_adapter.rb +873 -0
- data/lib/three/backends/threejs/synchronization.rb +224 -0
- data/lib/three/backends/threejs.rb +365 -0
- data/lib/three/cameras/camera.rb +39 -0
- data/lib/three/cameras/orthographic_camera.rb +107 -0
- data/lib/three/cameras/perspective_camera.rb +137 -0
- data/lib/three/constants.rb +40 -0
- data/lib/three/controls/orbit_controls.rb +118 -0
- data/lib/three/core/buffer_attribute.rb +151 -0
- data/lib/three/core/buffer_geometry.rb +181 -0
- data/lib/three/core/clock.rb +58 -0
- data/lib/three/core/event_dispatcher.rb +57 -0
- data/lib/three/core/layers.rb +75 -0
- data/lib/three/core/object3d.rb +331 -0
- data/lib/three/core/raycaster.rb +73 -0
- data/lib/three/dirty.rb +58 -0
- data/lib/three/exporters/three_json_exporter.rb +187 -0
- data/lib/three/geometries/box_geometry.rb +97 -0
- data/lib/three/geometries/plane_geometry.rb +70 -0
- data/lib/three/geometries/sphere_geometry.rb +107 -0
- data/lib/three/lights/ambient_light.rb +12 -0
- data/lib/three/lights/directional_light.rb +38 -0
- data/lib/three/lights/hemisphere_light.rb +34 -0
- data/lib/three/lights/light.rb +85 -0
- data/lib/three/lights/point_light.rb +33 -0
- data/lib/three/loaders/cube_texture_loader.rb +13 -0
- data/lib/three/loaders/gltf_loader.rb +48 -0
- data/lib/three/loaders/rgbe_loader.rb +15 -0
- data/lib/three/loaders/texture_loader.rb +13 -0
- data/lib/three/loaders/three_json_loader.rb +409 -0
- data/lib/three/materials/line_basic_material.rb +65 -0
- data/lib/three/materials/material.rb +158 -0
- data/lib/three/materials/mesh_basic_material.rb +64 -0
- data/lib/three/materials/mesh_lambert_material.rb +71 -0
- data/lib/three/materials/mesh_matcap_material.rb +86 -0
- data/lib/three/materials/mesh_normal_material.rb +42 -0
- data/lib/three/materials/mesh_phong_material.rb +119 -0
- data/lib/three/materials/mesh_physical_material.rb +155 -0
- data/lib/three/materials/mesh_standard_material.rb +149 -0
- data/lib/three/materials/mesh_toon_material.rb +98 -0
- data/lib/three/materials/points_material.rb +74 -0
- data/lib/three/materials/shadow_material.rb +45 -0
- data/lib/three/materials/sprite_material.rb +75 -0
- data/lib/three/math/color.rb +133 -0
- data/lib/three/math/euler.rb +197 -0
- data/lib/three/math/math_utils.rb +36 -0
- data/lib/three/math/matrix3.rb +255 -0
- data/lib/three/math/matrix4.rb +448 -0
- data/lib/three/math/quaternion.rb +277 -0
- data/lib/three/math/vector2.rb +95 -0
- data/lib/three/math/vector3.rb +396 -0
- data/lib/three/objects/external_object3d.rb +28 -0
- data/lib/three/objects/group.rb +12 -0
- data/lib/three/objects/instanced_mesh.rb +110 -0
- data/lib/three/objects/line.rb +41 -0
- data/lib/three/objects/mesh.rb +45 -0
- data/lib/three/objects/points.rb +41 -0
- data/lib/three/objects/sprite.rb +57 -0
- data/lib/three/postprocessing/dot_screen_pass.rb +83 -0
- data/lib/three/postprocessing/effect_composer.rb +56 -0
- data/lib/three/postprocessing/output_pass.rb +40 -0
- data/lib/three/postprocessing/render_pass.rb +42 -0
- data/lib/three/postprocessing/unreal_bloom_pass.rb +56 -0
- data/lib/three/renderers/renderer.rb +11 -0
- data/lib/three/renderers/threejs_renderer.rb +85 -0
- data/lib/three/scenes/scene.rb +29 -0
- data/lib/three/textures/cube_texture.rb +72 -0
- data/lib/three/textures/rgbe_texture.rb +45 -0
- data/lib/three/textures/texture.rb +200 -0
- data/lib/three/version.rb +5 -0
- data/lib/three-rb.rb +3 -0
- data/lib/three.rb +77 -0
- data/package.json +30 -0
- data/pnpm-lock.yaml +86 -0
- metadata +216 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "camera"
|
|
4
|
+
|
|
5
|
+
module Three
|
|
6
|
+
class OrthographicCamera < Camera
|
|
7
|
+
attr_reader :left, :right, :top, :bottom, :near, :far, :zoom
|
|
8
|
+
attr_reader :view
|
|
9
|
+
|
|
10
|
+
def initialize(left = -1, right = 1, top = 1, bottom = -1, near: 0.1, far: 2000)
|
|
11
|
+
super()
|
|
12
|
+
@type = "OrthographicCamera"
|
|
13
|
+
@left = left
|
|
14
|
+
@right = right
|
|
15
|
+
@top = top
|
|
16
|
+
@bottom = bottom
|
|
17
|
+
@near = near
|
|
18
|
+
@far = far
|
|
19
|
+
@zoom = 1
|
|
20
|
+
@view = nil
|
|
21
|
+
update_projection_matrix
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def left=(value)
|
|
25
|
+
@left = value
|
|
26
|
+
mark_dirty!(:camera)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def right=(value)
|
|
30
|
+
@right = value
|
|
31
|
+
mark_dirty!(:camera)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def top=(value)
|
|
35
|
+
@top = value
|
|
36
|
+
mark_dirty!(:camera)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def bottom=(value)
|
|
40
|
+
@bottom = value
|
|
41
|
+
mark_dirty!(:camera)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def near=(value)
|
|
45
|
+
@near = value
|
|
46
|
+
mark_dirty!(:camera)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def far=(value)
|
|
50
|
+
@far = value
|
|
51
|
+
mark_dirty!(:camera)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def zoom=(value)
|
|
55
|
+
@zoom = value
|
|
56
|
+
mark_dirty!(:camera)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def set_view_offset(full_width, full_height, x, y, width, height)
|
|
60
|
+
@view = {
|
|
61
|
+
enabled: true,
|
|
62
|
+
full_width: full_width,
|
|
63
|
+
full_height: full_height,
|
|
64
|
+
offset_x: x,
|
|
65
|
+
offset_y: y,
|
|
66
|
+
width: width,
|
|
67
|
+
height: height
|
|
68
|
+
}
|
|
69
|
+
mark_dirty!(:camera)
|
|
70
|
+
update_projection_matrix
|
|
71
|
+
self
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def clear_view_offset
|
|
75
|
+
@view[:enabled] = false if @view
|
|
76
|
+
mark_dirty!(:camera)
|
|
77
|
+
update_projection_matrix
|
|
78
|
+
self
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def update_projection_matrix
|
|
82
|
+
dx = (@right - @left).to_f / (2 * @zoom)
|
|
83
|
+
dy = (@top - @bottom).to_f / (2 * @zoom)
|
|
84
|
+
cx = (@right + @left).to_f / 2
|
|
85
|
+
cy = (@top + @bottom).to_f / 2
|
|
86
|
+
|
|
87
|
+
left = cx - dx
|
|
88
|
+
right = cx + dx
|
|
89
|
+
top = cy + dy
|
|
90
|
+
bottom = cy - dy
|
|
91
|
+
|
|
92
|
+
if @view && @view[:enabled]
|
|
93
|
+
scale_w = (@right - @left).to_f / @view[:full_width] / @zoom
|
|
94
|
+
scale_h = (@top - @bottom).to_f / @view[:full_height] / @zoom
|
|
95
|
+
left += scale_w * @view[:offset_x]
|
|
96
|
+
right = left + scale_w * @view[:width]
|
|
97
|
+
top -= scale_h * @view[:offset_y]
|
|
98
|
+
bottom = top - scale_h * @view[:height]
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
@projection_matrix.make_orthographic(left, right, top, bottom, @near, @far)
|
|
102
|
+
@projection_matrix_inverse.copy(@projection_matrix).invert
|
|
103
|
+
mark_dirty!(:camera)
|
|
104
|
+
self
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../math/math_utils"
|
|
4
|
+
require_relative "camera"
|
|
5
|
+
|
|
6
|
+
module Three
|
|
7
|
+
class PerspectiveCamera < Camera
|
|
8
|
+
attr_reader :fov, :zoom, :near, :far, :focus, :aspect, :film_gauge, :film_offset
|
|
9
|
+
attr_reader :view
|
|
10
|
+
|
|
11
|
+
def initialize(fov = 50, aspect: 1, near: 0.1, far: 2000)
|
|
12
|
+
super()
|
|
13
|
+
@type = "PerspectiveCamera"
|
|
14
|
+
@fov = fov
|
|
15
|
+
@zoom = 1
|
|
16
|
+
@near = near
|
|
17
|
+
@far = far
|
|
18
|
+
@focus = 10
|
|
19
|
+
@aspect = aspect
|
|
20
|
+
@view = nil
|
|
21
|
+
@film_gauge = 35
|
|
22
|
+
@film_offset = 0
|
|
23
|
+
update_projection_matrix
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def fov=(value)
|
|
27
|
+
@fov = value
|
|
28
|
+
mark_dirty!(:camera)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def zoom=(value)
|
|
32
|
+
@zoom = value
|
|
33
|
+
mark_dirty!(:camera)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def near=(value)
|
|
37
|
+
@near = value
|
|
38
|
+
mark_dirty!(:camera)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def far=(value)
|
|
42
|
+
@far = value
|
|
43
|
+
mark_dirty!(:camera)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def focus=(value)
|
|
47
|
+
@focus = value
|
|
48
|
+
mark_dirty!(:camera)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def aspect=(value)
|
|
52
|
+
@aspect = value
|
|
53
|
+
mark_dirty!(:camera)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def film_gauge=(value)
|
|
57
|
+
@film_gauge = value
|
|
58
|
+
mark_dirty!(:camera)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def film_offset=(value)
|
|
62
|
+
@film_offset = value
|
|
63
|
+
mark_dirty!(:camera)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def set_focal_length(focal_length)
|
|
67
|
+
vertical_extent_slope = 0.5 * film_height / focal_length
|
|
68
|
+
@fov = MathUtils.rad_to_deg(2 * Math.atan(vertical_extent_slope))
|
|
69
|
+
mark_dirty!(:camera)
|
|
70
|
+
update_projection_matrix
|
|
71
|
+
self
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def focal_length
|
|
75
|
+
vertical_extent_slope = Math.tan(MathUtils.deg_to_rad(0.5 * @fov))
|
|
76
|
+
0.5 * film_height / vertical_extent_slope
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def effective_fov
|
|
80
|
+
MathUtils.rad_to_deg(2 * Math.atan(Math.tan(MathUtils.deg_to_rad(0.5 * @fov)) / @zoom))
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def film_width
|
|
84
|
+
@film_gauge * [@aspect, 1].min
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def film_height
|
|
88
|
+
@film_gauge / [@aspect, 1].max
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def set_view_offset(full_width, full_height, x, y, width, height)
|
|
92
|
+
@aspect = full_width.to_f / full_height
|
|
93
|
+
@view = {
|
|
94
|
+
enabled: true,
|
|
95
|
+
full_width: full_width,
|
|
96
|
+
full_height: full_height,
|
|
97
|
+
offset_x: x,
|
|
98
|
+
offset_y: y,
|
|
99
|
+
width: width,
|
|
100
|
+
height: height
|
|
101
|
+
}
|
|
102
|
+
mark_dirty!(:camera)
|
|
103
|
+
update_projection_matrix
|
|
104
|
+
self
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def clear_view_offset
|
|
108
|
+
@view[:enabled] = false if @view
|
|
109
|
+
mark_dirty!(:camera)
|
|
110
|
+
update_projection_matrix
|
|
111
|
+
self
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def update_projection_matrix
|
|
115
|
+
top = @near * Math.tan(MathUtils.deg_to_rad(0.5 * @fov)) / @zoom
|
|
116
|
+
height = 2 * top
|
|
117
|
+
width = @aspect * height
|
|
118
|
+
left = -0.5 * width
|
|
119
|
+
|
|
120
|
+
if @view && @view[:enabled]
|
|
121
|
+
full_width = @view[:full_width]
|
|
122
|
+
full_height = @view[:full_height]
|
|
123
|
+
left += @view[:offset_x] * width / full_width
|
|
124
|
+
top -= @view[:offset_y] * height / full_height
|
|
125
|
+
width *= @view[:width].to_f / full_width
|
|
126
|
+
height *= @view[:height].to_f / full_height
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
left += @near * @film_offset / film_width unless @film_offset.zero?
|
|
130
|
+
|
|
131
|
+
@projection_matrix.make_perspective(left, left + width, top, top - height, @near, @far)
|
|
132
|
+
@projection_matrix_inverse.copy(@projection_matrix).invert
|
|
133
|
+
mark_dirty!(:camera)
|
|
134
|
+
self
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Three
|
|
4
|
+
FrontSide = 0
|
|
5
|
+
BackSide = 1
|
|
6
|
+
DoubleSide = 2
|
|
7
|
+
|
|
8
|
+
NoBlending = 0
|
|
9
|
+
NormalBlending = 1
|
|
10
|
+
|
|
11
|
+
RepeatWrapping = 1000
|
|
12
|
+
ClampToEdgeWrapping = 1001
|
|
13
|
+
MirroredRepeatWrapping = 1002
|
|
14
|
+
|
|
15
|
+
NearestFilter = 1003
|
|
16
|
+
NearestMipmapNearestFilter = 1004
|
|
17
|
+
NearestMipMapNearestFilter = 1004
|
|
18
|
+
NearestMipmapLinearFilter = 1005
|
|
19
|
+
NearestMipMapLinearFilter = 1005
|
|
20
|
+
LinearFilter = 1006
|
|
21
|
+
LinearMipmapNearestFilter = 1007
|
|
22
|
+
LinearMipMapNearestFilter = 1007
|
|
23
|
+
LinearMipmapLinearFilter = 1008
|
|
24
|
+
LinearMipMapLinearFilter = 1008
|
|
25
|
+
|
|
26
|
+
UVMapping = 300
|
|
27
|
+
CubeReflectionMapping = 301
|
|
28
|
+
CubeRefractionMapping = 302
|
|
29
|
+
EquirectangularReflectionMapping = 303
|
|
30
|
+
EquirectangularRefractionMapping = 304
|
|
31
|
+
|
|
32
|
+
NoColorSpace = ""
|
|
33
|
+
SRGBColorSpace = "srgb"
|
|
34
|
+
LinearSRGBColorSpace = "srgb-linear"
|
|
35
|
+
|
|
36
|
+
BasicShadowMap = 0
|
|
37
|
+
PCFShadowMap = 1
|
|
38
|
+
PCFSoftShadowMap = 2
|
|
39
|
+
VSMShadowMap = 3
|
|
40
|
+
end
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../backends/threejs"
|
|
4
|
+
require_relative "../math/vector3"
|
|
5
|
+
|
|
6
|
+
module Three
|
|
7
|
+
module Controls
|
|
8
|
+
class OrbitControls
|
|
9
|
+
PROPERTY_NAMES = {
|
|
10
|
+
enabled: "enabled",
|
|
11
|
+
enable_damping: "enableDamping",
|
|
12
|
+
damping_factor: "dampingFactor",
|
|
13
|
+
enable_zoom: "enableZoom",
|
|
14
|
+
zoom_speed: "zoomSpeed",
|
|
15
|
+
enable_rotate: "enableRotate",
|
|
16
|
+
rotate_speed: "rotateSpeed",
|
|
17
|
+
enable_pan: "enablePan",
|
|
18
|
+
pan_speed: "panSpeed",
|
|
19
|
+
auto_rotate: "autoRotate",
|
|
20
|
+
auto_rotate_speed: "autoRotateSpeed",
|
|
21
|
+
min_distance: "minDistance",
|
|
22
|
+
max_distance: "maxDistance",
|
|
23
|
+
min_zoom: "minZoom",
|
|
24
|
+
max_zoom: "maxZoom"
|
|
25
|
+
}.freeze
|
|
26
|
+
|
|
27
|
+
attr_reader :object, :renderer, :backend, :handle, :dom_element, :target
|
|
28
|
+
attr_reader(*PROPERTY_NAMES.keys)
|
|
29
|
+
|
|
30
|
+
def initialize(object, renderer: nil, dom_element: nil, backend: nil, **parameters)
|
|
31
|
+
@object = object
|
|
32
|
+
@renderer = renderer
|
|
33
|
+
@backend = backend || renderer&.backend || Backends::ThreeJS.new
|
|
34
|
+
@dom_element = dom_element || default_dom_element(renderer)
|
|
35
|
+
@target = Vector3.new
|
|
36
|
+
bind_target_changes
|
|
37
|
+
set_defaults
|
|
38
|
+
|
|
39
|
+
object_handle = @backend.sync(object)
|
|
40
|
+
@handle = @backend.create_orbit_controls(object_handle, @dom_element)
|
|
41
|
+
set_values(parameters)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def update
|
|
45
|
+
@backend.update_controls(@handle)
|
|
46
|
+
@backend.sync_object_transform_from_handle(@object)
|
|
47
|
+
self
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def dispose
|
|
51
|
+
@backend.dispose_controls(@handle)
|
|
52
|
+
self
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def target=(value)
|
|
56
|
+
@target = coerce_vector3(value)
|
|
57
|
+
bind_target_changes
|
|
58
|
+
sync_target if @handle
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
PROPERTY_NAMES.each do |ruby_name, js_name|
|
|
62
|
+
define_method("#{ruby_name}=") do |value|
|
|
63
|
+
instance_variable_set("@#{ruby_name}", value)
|
|
64
|
+
@backend.set_control_property(@handle, js_name, value) if @handle
|
|
65
|
+
value
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
def set_defaults
|
|
72
|
+
@enabled = true
|
|
73
|
+
@enable_damping = false
|
|
74
|
+
@damping_factor = 0.05
|
|
75
|
+
@enable_zoom = true
|
|
76
|
+
@zoom_speed = 1.0
|
|
77
|
+
@enable_rotate = true
|
|
78
|
+
@rotate_speed = 1.0
|
|
79
|
+
@enable_pan = true
|
|
80
|
+
@pan_speed = 1.0
|
|
81
|
+
@auto_rotate = false
|
|
82
|
+
@auto_rotate_speed = 2.0
|
|
83
|
+
@min_distance = 0
|
|
84
|
+
@max_distance = Float::INFINITY
|
|
85
|
+
@min_zoom = 0
|
|
86
|
+
@max_zoom = Float::INFINITY
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def set_values(parameters)
|
|
90
|
+
parameters.each do |key, value|
|
|
91
|
+
setter = "#{key}="
|
|
92
|
+
public_send(setter, value) if respond_to?(setter)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def default_dom_element(renderer)
|
|
97
|
+
return nil unless renderer
|
|
98
|
+
|
|
99
|
+
renderer.dom_element
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def coerce_vector3(value)
|
|
103
|
+
return value if value.is_a?(Vector3)
|
|
104
|
+
return Vector3.new(*value) if value.respond_to?(:to_ary)
|
|
105
|
+
|
|
106
|
+
raise TypeError, "target must be a Three::Vector3 or an array-like [x, y, z]"
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def bind_target_changes
|
|
110
|
+
@target.on_change { sync_target if @handle }
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def sync_target
|
|
114
|
+
@backend.set_orbit_controls_target(@handle, @target.to_a)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../dirty"
|
|
4
|
+
require_relative "event_dispatcher"
|
|
5
|
+
|
|
6
|
+
module Three
|
|
7
|
+
class BufferAttribute < EventDispatcher
|
|
8
|
+
include Dirty
|
|
9
|
+
|
|
10
|
+
@next_id = 0
|
|
11
|
+
|
|
12
|
+
class << self
|
|
13
|
+
attr_accessor :next_id
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
attr_reader :id
|
|
17
|
+
attr_accessor :name, :array, :item_size, :normalized, :usage, :update_ranges, :version
|
|
18
|
+
attr_accessor :component_type
|
|
19
|
+
|
|
20
|
+
def initialize(array, item_size, normalized = false, component_type: :generic)
|
|
21
|
+
super()
|
|
22
|
+
@id = self.class.allocate_id
|
|
23
|
+
@name = ""
|
|
24
|
+
@array = array.dup
|
|
25
|
+
@item_size = item_size
|
|
26
|
+
@normalized = normalized
|
|
27
|
+
@usage = :static_draw
|
|
28
|
+
@update_ranges = []
|
|
29
|
+
@version = 0
|
|
30
|
+
@component_type = component_type
|
|
31
|
+
mark_dirty!
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.allocate_id
|
|
35
|
+
id = BufferAttribute.next_id
|
|
36
|
+
BufferAttribute.next_id += 1
|
|
37
|
+
id
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def count
|
|
41
|
+
@array.length / @item_size
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def needs_update=(value)
|
|
45
|
+
return unless value
|
|
46
|
+
|
|
47
|
+
needs_update!
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def needs_update!
|
|
51
|
+
@version += 1
|
|
52
|
+
mark_dirty!(:array)
|
|
53
|
+
dispatch_event(:change)
|
|
54
|
+
self
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def set_usage(value)
|
|
58
|
+
@usage = value
|
|
59
|
+
mark_dirty!(:usage)
|
|
60
|
+
self
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def add_update_range(start, count)
|
|
64
|
+
@update_ranges << { start: start, count: count }
|
|
65
|
+
mark_dirty!(:update_ranges)
|
|
66
|
+
self
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def clear_update_ranges
|
|
70
|
+
@update_ranges.clear
|
|
71
|
+
mark_dirty!(:update_ranges)
|
|
72
|
+
self
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def copy(source)
|
|
76
|
+
@name = source.name
|
|
77
|
+
@array = source.array.dup
|
|
78
|
+
@item_size = source.item_size
|
|
79
|
+
@normalized = source.normalized
|
|
80
|
+
@usage = source.usage
|
|
81
|
+
@component_type = source.component_type
|
|
82
|
+
needs_update!
|
|
83
|
+
self
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def clone
|
|
87
|
+
self.class.new(@array, @item_size, @normalized)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def get_component(index, component)
|
|
91
|
+
@array[index * @item_size + component]
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def set_component(index, component, value)
|
|
95
|
+
@array[index * @item_size + component] = value
|
|
96
|
+
needs_update!
|
|
97
|
+
self
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def get_x(index)
|
|
101
|
+
get_component(index, 0)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def get_y(index)
|
|
105
|
+
get_component(index, 1)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def get_z(index)
|
|
109
|
+
get_component(index, 2)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def set_x(index, value)
|
|
113
|
+
set_component(index, 0, value)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def set_y(index, value)
|
|
117
|
+
set_component(index, 1, value)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def set_z(index, value)
|
|
121
|
+
set_component(index, 2, value)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def to_h
|
|
125
|
+
{
|
|
126
|
+
item_size: @item_size,
|
|
127
|
+
component_type: @component_type,
|
|
128
|
+
normalized: @normalized,
|
|
129
|
+
array: @array.dup
|
|
130
|
+
}
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
class Float32BufferAttribute < BufferAttribute
|
|
135
|
+
def initialize(array, item_size, normalized = false)
|
|
136
|
+
super(array, item_size, normalized, component_type: :float32)
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
class Uint16BufferAttribute < BufferAttribute
|
|
141
|
+
def initialize(array, item_size, normalized = false)
|
|
142
|
+
super(array, item_size, normalized, component_type: :uint16)
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
class Uint32BufferAttribute < BufferAttribute
|
|
147
|
+
def initialize(array, item_size, normalized = false)
|
|
148
|
+
super(array, item_size, normalized, component_type: :uint32)
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|