mittsu 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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,87 @@
1
+ module Mittsu
2
+ class OpenGLRenderTarget < HashObject
3
+ include EventDispatcher
4
+
5
+ attr_accessor :width,
6
+ :height,
7
+ :wrap_s,
8
+ :wrap_t,
9
+ :mag_filter,
10
+ :min_filter,
11
+ :anisotropy,
12
+ :offset,
13
+ :repeat,
14
+ :format,
15
+ :type,
16
+ :depth_buffer,
17
+ :stencil_buffer,
18
+ :generate_mipmaps,
19
+ :share_depth_from
20
+
21
+ def initialize(width, height, options = {})
22
+ super()
23
+
24
+ @width = width
25
+ @height = height
26
+
27
+ @wrap_s = options.fetch(:wrap_s, ClampToEdgeWrapping)
28
+ @wrap_t = options.fetch(:wrap_t, ClampToEdgeWrapping)
29
+
30
+ @mag_filter = options.fetch(:mag_filter, LinearFilter)
31
+ @min_filter = options.fetch(:min_filter, LinearMipMapLinearFilter)
32
+
33
+ @anisotropy = options.fetch(:anisotropy, 1.0);
34
+
35
+ @offset = Vector2.new(0.0, 0.0)
36
+ @repeat = Vector2.new(1.0, 1.0)
37
+
38
+ @format = options.fetch(:format, RGBAFormat)
39
+ @type = options.fetch(:type, UnsignedByteType)
40
+
41
+ @depth_buffer = options.fetch(:depth_buffer, true)
42
+ @stencil_buffer = options.fetch(:stencil_buffer, true)
43
+
44
+ @generate_mipmaps = true
45
+
46
+ @share_depth_from = options.fetch(:share_depth_from, nil)
47
+ end
48
+
49
+ def set_size(width, height)
50
+ @width = width
51
+ @height = height
52
+ end
53
+
54
+ def needs_update?
55
+ false
56
+ end
57
+
58
+ def clone
59
+ OpenGLRenderTarget.new(@width, @height).tap do |tmp|
60
+ tmp.wrap_s = @wrap_s
61
+ tmp.wrap_t = @wrap_t
62
+
63
+ tmp.mag_filter = @mag_filter
64
+ tmp.min_filter = @min_filter
65
+
66
+ tmp.anisotropy = @anisotropy
67
+
68
+ tmp.offset.copy(@offset)
69
+ tmp.repeat.copy(@repeat)
70
+
71
+ tmp.format = @format
72
+ tmp.type = @type
73
+
74
+ tmp.depth_buffer = @depth_buffer
75
+ tmp.stencil_buffer = @stencil_buffer
76
+
77
+ tmp.generate_mipmaps = @generate_mipmaps
78
+
79
+ tmp.share_depth_from = @share_depth_from
80
+ end
81
+ end
82
+
83
+ def dispose
84
+ dispatch_event(type: :dispose)
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,3376 @@
1
+
2
+ require 'opengl'
3
+ require 'glfw'
4
+ require 'fiddle'
5
+
6
+ OpenGL.load_lib
7
+
8
+ require 'mittsu'
9
+ require 'mittsu/renderers/glfw_window'
10
+ require 'mittsu/renderers/opengl/opengl_debug'
11
+ require 'mittsu/renderers/opengl/opengl_program'
12
+ require 'mittsu/renderers/opengl/opengl_state'
13
+ require 'mittsu/renderers/opengl/plugins/shadow_map_plugin'
14
+ require 'mittsu/renderers/shaders/shader_lib'
15
+ require 'mittsu/renderers/shaders/uniforms_utils'
16
+
17
+ include OpenGL
18
+
19
+ module Mittsu
20
+ class OpenGLRenderer
21
+ attr_accessor :auto_clear, :auto_clear_color, :auto_clear_depth, :auto_clear_stencil, :sort_objects, :gamma_factor, :gamma_input, :gamma_output, :shadow_map_enabled, :shadow_map_type, :shadow_map_cull_face, :shadow_map_debug, :shadow_map_cascade, :max_morph_targets, :max_morph_normals, :info, :pixel_ratio, :window, :width, :height, :state
22
+
23
+ def initialize(parameters = {})
24
+ puts "OpenGLRenderer #{REVISION}"
25
+
26
+ @pixel_ratio = 1.0
27
+
28
+ @precision = parameters.fetch(:precision, 'highp') # not sure if OpenGL works with the whole 'highp' thing...
29
+ @_alpha = parameters.fetch(:alpha, false)
30
+ @_depth = parameters.fetch(:depth, true)
31
+ @_stencil = parameters.fetch(:stencil, true)
32
+ @_antialias = parameters.fetch(:antialias, false)
33
+ @_premultiplied_alpha = parameters.fetch(:premultiplied_alpha, true)
34
+ @_preserve_drawing_buffer = parameters.fetch(:preserve_drawing_buffer, false)
35
+ @_logarithmic_depth_buffer = parameters.fetch(:logarithmic_depth_buffer, false)
36
+
37
+ @_clear_color = Color.new(0x000000)
38
+ @_clear_alpha = 0.0
39
+
40
+ @width = parameters.fetch(:width, 800)
41
+ @height = parameters.fetch(:height, 600)
42
+ @title = parameters.fetch(:title, "Mittsu #{REVISION}")
43
+
44
+ @lights = []
45
+
46
+ @_opengl_objects = {}
47
+ @_opengl_objects_immediate = []
48
+
49
+ @opaque_objects = []
50
+ @transparent_objects = []
51
+
52
+ @sprites = []
53
+ @lens_flares = []
54
+
55
+ # public properties
56
+
57
+ # @dom_element = _canvas
58
+ # @context = nil
59
+
60
+ # clearing
61
+
62
+ @auto_clear = true
63
+ @auto_clear_color = true
64
+ @auto_clear_depth = true
65
+ @auto_clear_stencil = true
66
+
67
+ # scene graph
68
+
69
+ @sort_objects = true
70
+
71
+ # physically based shading
72
+
73
+ @gamma_factor = 2.0 # backwards compat???
74
+ @gamma_input = false
75
+ @gamma_output = false
76
+
77
+ # shadow map
78
+
79
+ @shadow_map_enabled = false
80
+ @shadow_map_type = PCFShadowMap
81
+ @shadow_map_cull_face = CullFaceFront
82
+ @shadow_map_debug = false
83
+ @shadow_map_cascade = false
84
+
85
+ # morphs
86
+
87
+ @max_morph_targets = 8
88
+ @max_morph_normals = 4
89
+
90
+ # info
91
+
92
+ @info = {
93
+ memory: {
94
+ programs: 0,
95
+ geometries: 0,
96
+ textures: 0
97
+ },
98
+ render: {
99
+ calls: 0,
100
+ vertices: 0,
101
+ faces: 0,
102
+ points: 0
103
+ }
104
+ }
105
+
106
+ # internal properties
107
+
108
+ @_programs = []
109
+
110
+ # internal state cache
111
+
112
+ @_current_program = nil
113
+ @_current_framebuffer = nil
114
+ @_current_material_id = -1
115
+ @_current_geometry_program = ''
116
+ @_current_camera = nil
117
+
118
+ @_used_texture_units = 0
119
+ @_viewport_x = 0
120
+ @_viewport_y = 0
121
+ @_current_width = 0
122
+ @_current_height = 0
123
+
124
+ # frustum
125
+
126
+ @_frustum = Frustum.new
127
+
128
+ # camera matrices cache
129
+
130
+ @_proj_screen_matrix = Matrix4.new
131
+ @_vector3 = Vector3.new
132
+
133
+ # light arrays cache
134
+
135
+ @_direction = Vector3.new
136
+ @_lights_need_update = true
137
+ # TODO: re-imagine this thing as a bunch of classes...
138
+ @_lights = {
139
+ ambient: [0, 0, 0],
140
+ directional: { length: 0, colors: [], positions: [] },
141
+ point: { length: 0, colors: [], positions: [], distances: [], decays: [] },
142
+ spot: { length: 0, colors: [], positions: [], distances: [], directions: [], angles_cos: [], exponents: [], decays: [] },
143
+ hemi: { length: 0, sky_colors: [], ground_colors: [], positions: []}
144
+ }
145
+
146
+ @geometry_groups = {}
147
+ @geometry_group_counter = 0
148
+
149
+ @shader_ids = {
150
+ # MeshDepthMaterial => :depth, # TODO...
151
+ # MeshNormalMaterial => :normal, # TODO...
152
+ MeshBasicMaterial => :basic,
153
+ MeshLambertMaterial => :lambert,
154
+ MeshPhongMaterial => :phong,
155
+ LineBasicMaterial => :basic,
156
+ # LineDashedMaterial => :dashed, # TODO...
157
+ # PointCloudMaterial => :particle_basic # TODO...
158
+ }
159
+
160
+ # initialize
161
+
162
+ begin
163
+ # attributes = {
164
+ # alpha: _alpha,
165
+ # depth: _depth,
166
+ # stencil: _stencil,
167
+ # antialias: _antialias,
168
+ # premultiplied_alpha: _premultiplied_alpha,
169
+ # preserve_drawing_buffer: _preserve_drawing_buffer
170
+ # }
171
+
172
+ @window = GLFW::Window.new(@width, @height, @title)
173
+
174
+ @_viewport_width, @_viewport_height = *(@window.framebuffer_size)
175
+
176
+ # TODO: handle losing opengl context??
177
+ rescue => error
178
+ puts "ERROR: Mittsu::OpenGLRenderer: #{error.inspect}"
179
+ end
180
+
181
+ @state = OpenGLState.new(self.method(:param_mittsu_to_gl))
182
+
183
+ # TODO: get shader precision format???
184
+ # TODO: load extensions??
185
+
186
+ reset_gl_state
187
+ set_default_gl_state
188
+
189
+ # GPU capabilities
190
+
191
+ @_max_textures = get_gl_parameter(GL_MAX_TEXTURE_IMAGE_UNITS)
192
+ @_max_vertex_textures = get_gl_parameter(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
193
+ @_max_texture_size = get_gl_parameter(GL_MAX_TEXTURE_SIZE)
194
+ @_max_cubemap_size = get_gl_parameter(GL_MAX_CUBE_MAP_TEXTURE_SIZE)
195
+
196
+ @_supports_vertex_textures = @_max_vertex_textures > 0
197
+ @_supports_bone_textures = @_supports_vertex_textures && false # TODO: extensions.get('OES_texture_float') ????
198
+
199
+ #
200
+
201
+ # TODO: get more shader precision formats ???
202
+
203
+ # TODO: clear precision to maximum available ???
204
+
205
+ # Plugins
206
+
207
+ # TODO: when plugins are ready
208
+ @shadow_map_plugin = ShadowMapPlugin.new(self, @lights, @_opengl_objects, @_opengl_objects_immediate)
209
+ #
210
+ # @sprite_plugin = SpritePlugin(self, @sprites)
211
+ # @lens_flare_plugin = LensFlarePlugin(self, @lens_flares)
212
+
213
+ # Events
214
+
215
+ @on_object_removed = -> (event) {
216
+ object = event.target
217
+ object.traverse do |child|
218
+ child.remove_event_listener(:remove, @on_object_removed)
219
+ remove_child(child)
220
+ end
221
+ }
222
+
223
+ @on_geometry_dispose = -> (event) {
224
+ geometry = event.target
225
+ geometry.remove_event_listener(:dispose, @on_geometry_dispose)
226
+ deallocate_geometry(geometry)
227
+ }
228
+
229
+ @on_texture_dispose = -> (event) {
230
+ texture = event.target
231
+ texture.remove_event_listener(:dispose, @on_texture_dispose)
232
+ deallocate_texture(texture)
233
+ @info[:memory][:textures] -= 1
234
+ }
235
+
236
+ @on_render_target_dispose = -> (event) {
237
+ render_target = event.target
238
+ render_target.remove_event_listener(:dispose, @on_render_target_dispose)
239
+ deallocate_render_target(render_target)
240
+ @info[:memory][:textures] -= 1
241
+ }
242
+
243
+ @on_material_dispose = -> (event) {
244
+ material = event.target
245
+ material.remove_event_listener(:dispose, @on_material_dispose)
246
+ deallocate_material(material)
247
+ }
248
+ end
249
+
250
+ # TODO: get_context ???
251
+ # TODO: force_context_loss ???
252
+
253
+ def supports_vertex_textures?
254
+ @_supports_vertex_textures
255
+ end
256
+
257
+ # TODO: supports_float_textures? ???
258
+ # TODO: supports[half|standard|compressed|blend min max] ... ???
259
+
260
+ def max_anisotropy
261
+ @_max_anisotropy ||= nil
262
+ # TODO: get max anisotropy ????
263
+ end
264
+
265
+ def set_size(width, height)
266
+ @width, @height = width, height
267
+ self.set_viewport(0, 0, width, height)
268
+ end
269
+
270
+ def set_viewport(x, y, width, height)
271
+ @_viewport_x = x * pixel_ratio
272
+ @_viewport_x = y * pixel_ratio
273
+
274
+ @_viewport_width = width * pixel_ratio
275
+ @_viewport_height = height * pixel_ratio
276
+
277
+ glViewport(@_viewport_x, @_viewport_y, @_viewport_width, @_viewport_height)
278
+ end
279
+
280
+ def set_scissor(x, y, width, height)
281
+ glScissor(
282
+ x * pixel_ratio,
283
+ y * pixel_ratio,
284
+ width * pixel_ratio,
285
+ height * pixel_ratio
286
+ )
287
+ end
288
+
289
+ def enable_scissor_test(enable)
290
+ enable ? glEnable(GL_SCISSOR_TEST) : glDisable(GL_SCISSOR_TEST)
291
+ end
292
+
293
+ # clearing
294
+
295
+ def get_clear_color
296
+ @_clear_color
297
+ end
298
+
299
+ def set_clear_color(color, alpha = 1.0)
300
+ @_clear_color.set(color)
301
+ @_clear_alpha = alpha
302
+ clear_color(@_clear_color.r, @_clear_color.g, @_clear_color.b, @_clear_alpha)
303
+ end
304
+
305
+ def get_clear_alpha
306
+ @_clear_alpha
307
+ end
308
+
309
+ def set_clear_alpha(alpha)
310
+ @_clear_alpha = alpha
311
+ clear_color(@_clear_color.r, @_clear_color.g, @_clear_color.b, @_clear_alpha)
312
+ end
313
+
314
+ def clear(color = true, depth = true, stencil = true)
315
+ bits = 0
316
+
317
+ bits |= GL_COLOR_BUFFER_BIT if color
318
+ bits |= GL_DEPTH_BUFFER_BIT if depth
319
+ bits |= GL_STENCIL_BUFFER_BIT if stencil
320
+
321
+ glClear(bits)
322
+ end
323
+
324
+ def clear_depth
325
+ glClear(GL_DEPTH_BUFFER_BIT)
326
+ end
327
+
328
+ def clear_stencil
329
+ glClear(GL_STENCIL_BUFFER_BIT)
330
+ end
331
+
332
+ def clear_target(render_target, color, depth, stencil)
333
+ set_render_target(render_target)
334
+ clear(color, depth, stencil)
335
+ end
336
+
337
+ def reset_gl_state
338
+ @_current_program = nil
339
+ @_current_camera = nil
340
+
341
+ @_current_geometry_program = ''
342
+ @_current_material_id = -1
343
+
344
+ @_lights_need_update = true
345
+
346
+ @state.reset
347
+ end
348
+
349
+ def set_render_target(render_target = nil)
350
+ # TODO: when OpenGLRenderTargetCube exists
351
+ is_cube = false # render_target.is_a? OpenGLRenderTargetCube
352
+
353
+ if render_target && render_target[:_opengl_framebuffer].nil?
354
+ render_target.depth_buffer = true if render_target.depth_buffer.nil?
355
+ render_target.stencil_buffer = true if render_target.stencil_buffer.nil?
356
+
357
+ render_target.add_event_listener(:dispose, @on_render_target_dispose)
358
+
359
+ render_target[:_opengl_texture] = glCreateTexture
360
+
361
+ @info[:memory][:textures] += 1
362
+
363
+ # Setup texture, create render and frame buffers
364
+
365
+ is_target_power_of_two = Math.power_of_two?(render_target.width) && Math.power_of_two?(render_target.height)
366
+ gl_format = param_mittsu_to_gl(render_target.format)
367
+ gl_type = param_mittsu_to_gl(render_target.type)
368
+
369
+ if is_cube
370
+ # TODO
371
+ else
372
+ render_target[:_opengl_framebuffer] = glCreateFramebuffer
373
+
374
+ if render_target.share_depth_from
375
+ render_target[:_opengl_renderbuffer] = render_target.share_depth_from[:_opengl_renderbuffer]
376
+ else
377
+ render_target[:_opengl_renderbuffer] = glCreateRenderbuffer
378
+ end
379
+
380
+ glBindTexture(GL_TEXTURE_2D, render_target[:_opengl_texture])
381
+ set_texture_parameters(GL_TEXTURE_2D, render_target, is_target_power_of_two)
382
+
383
+ glTexImage2D(GL_TEXTURE_2D, 0, gl_format, render_target.width, render_target.height, 0, gl_format, gl_type, nil)
384
+
385
+ setup_framebuffer(render_target[:_opengl_framebuffer], render_target, GL_TEXTURE_2D)
386
+
387
+ if render_target.share_depth_from
388
+ if render_target.depth_buffer && !render_target.stencil_buffer
389
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, render_target[:_opengl_renderbuffer])
390
+ elsif render_target.depth_buffer && render_target.stencil_buffer
391
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, render_target[:_opengl_renderbuffer])
392
+ end
393
+ else
394
+ setup_renderbuffer(render_target[:_opengl_renderbuffer], render_target)
395
+ end
396
+
397
+ glGenerateMipmap(GL_TEXTURE_2D) if is_target_power_of_two
398
+ end
399
+
400
+ # Release everything
401
+
402
+ if is_cube
403
+ # TODO
404
+ else
405
+ glBindTexture(GL_TEXTURE_2D, 0)
406
+ end
407
+
408
+ glBindRenderbuffer(GL_RENDERBUFFER, 0)
409
+ glBindFramebuffer(GL_FRAMEBUFFER, 0)
410
+ end
411
+
412
+ if render_target
413
+ if is_cube
414
+ # TODO
415
+ else
416
+ framebuffer = render_target[:_opengl_framebuffer]
417
+ end
418
+
419
+ width = render_target.width
420
+ height = render_target.height
421
+
422
+ vx = 0
423
+ vy = 0
424
+ else
425
+ framebuffer = nil
426
+
427
+ width = @_viewport_width
428
+ height = @_viewport_height
429
+
430
+ vx = @_viewport_x
431
+ vy = @_viewport_y
432
+ end
433
+
434
+ if framebuffer != @_current_framebuffer
435
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer || 0)
436
+ glViewport(vx, vy, width, height)
437
+
438
+ @_current_framebuffer = framebuffer
439
+ end
440
+
441
+ @_current_width = width
442
+ @_current_height = height
443
+ end
444
+
445
+ def render(scene, camera, render_target = nil, force_clear = false)
446
+ if !camera.is_a?(Camera)
447
+ puts "ERROR: Mittsu::OpenGLRenderer#render: camera is not an instance of Mittsu::Camera"
448
+ return
449
+ end
450
+
451
+ fog = scene.fog
452
+
453
+ # reset caching for this frame
454
+
455
+ @_current_geometry_program = ''
456
+ @_current_material_id = -1
457
+ @_current_camera = nil
458
+ @_lights_need_update = true
459
+
460
+ # update scene graph
461
+ scene.update_matrix_world if scene.auto_update
462
+
463
+ # update camera matrices and frustum
464
+ camera.update_matrix_world if camera.parent.nil?
465
+
466
+ # update skeleton objects
467
+ # TODO: when SkinnedMesh is defined
468
+ # scene.traverse do |object|
469
+ # if object.is_a? SkinnedMesh
470
+ # object.skeleton.update
471
+ # end
472
+ # end
473
+
474
+ camera.matrix_world_inverse.inverse(camera.matrix_world)
475
+
476
+ @_proj_screen_matrix.multiply_matrices(camera.projection_matrix, camera.matrix_world_inverse)
477
+ @_frustum.set_from_matrix(@_proj_screen_matrix)
478
+
479
+ @lights.clear
480
+ @opaque_objects.clear
481
+ @transparent_objects.clear
482
+
483
+ @sprites.clear
484
+ @lens_flares.clear
485
+
486
+ project_object(scene)
487
+
488
+ if @sort_objects
489
+ @opaque_objects.sort { |a,b| painter_sort_stable(a,b) }
490
+ @transparent_objects.sort { |a,b| reverse_painter_sort_stable(a,b) }
491
+ end
492
+
493
+ # custom render plugins
494
+ # TODO: when plugins are ready
495
+ @shadow_map_plugin.render(scene, camera)
496
+
497
+ #
498
+
499
+ @info[:render][:calls] = 0
500
+ @info[:render][:vertices] = 0
501
+ @info[:render][:faces] = 0
502
+ @info[:render][:points] = 0
503
+
504
+ set_render_target(render_target)
505
+
506
+ if @auto_clear || force_clear
507
+ clear(@auto_clear_color, @auto_clear_depth, @auto_clear_stencil)
508
+ end
509
+
510
+ # set matrices for immediate objects
511
+
512
+ @_opengl_objects_immediate.each do |opengl_object|
513
+ object = opengl_object[:object]
514
+
515
+ if object.visible
516
+ setup_matrices(object, camera)
517
+ unroll_immediate_buffer_material(opengl_object)
518
+ end
519
+ end
520
+
521
+ if scene.override_material
522
+ override_material = scene.override_material
523
+
524
+ set_material(override_material)
525
+
526
+ render_objects(opaque_object, camera, @lights, fog, override_material)
527
+ render_objects(transparent_objects, camera, @lights, fog, override_material)
528
+ render_objects_immediate(@_opengl_objects_immediate, nil, camera, @lights, fog, override_material)
529
+ else
530
+ # opaque pass (front-to-back order)
531
+
532
+ @state.set_blending(NoBlending)
533
+
534
+ render_objects(@opaque_objects, camera, @lights, fog, nil)
535
+ render_objects_immediate(@_opengl_objects_immediate, :opaque, camera, @lights, fog, nil)
536
+
537
+ # transparent pass (back-to-front-order)
538
+
539
+ render_objects(@transparent_objects, camera, @lights, fog, nil)
540
+ render_objects_immediate(@_opengl_objects_immediate, :transparent, camera, @lights, fog, nil)
541
+ end
542
+
543
+ # custom render plugins (post pass)
544
+
545
+ # TODO: when plugins are ready
546
+ # @sprite_plugin.render(scene, camera)
547
+ # lens_flare_plugin.render(scene, camera, @_current_width, @_current_height)
548
+
549
+ # generate mipmap if we're using any kind of mipmap filtering
550
+ if render_target && render_target.generate_mipmaps && render_target.min_filter != NearestFilter && render_target.min_filter != LinearFilter
551
+ update_render_target_mipmap(render_target)
552
+ end
553
+
554
+ # endure depth buffer writing is enabled so it can be cleared on next render
555
+ @state.set_depth_test(true)
556
+ @state.set_depth_write(true)
557
+ @state.set_color_write(true)
558
+
559
+ #glFinish ??????
560
+ end
561
+
562
+ def set_material_faces(material)
563
+ @state.set_double_sided(material.side == DoubleSide)
564
+ @state.set_flip_sided(material.side == BackSide)
565
+ end
566
+
567
+ def render_buffer(camera, lights, fog, material, geometry_group, object)
568
+ return unless material.visible
569
+
570
+ # TODO: place to put this ???
571
+ vertex_array = geometry_group[:_opengl_vertex_array]
572
+ if vertex_array
573
+ glBindVertexArray(vertex_array)
574
+ end
575
+
576
+ update_object(object)
577
+
578
+ program = set_program(camera, lights, fog, material, object)
579
+
580
+ attributes = program.attributes
581
+
582
+ update_buffers = false
583
+ wireframe_bit = material.wireframe ? 1 : 0
584
+ geometry_program = "#{geometry_group[:id]}_#{program.id}_#{wireframe_bit}"
585
+
586
+ if geometry_program != @_current_geometry_program
587
+ @_current_geometry_program = geometry_program
588
+ update_buffers = true
589
+ end
590
+
591
+ @state.init_attributes if update_buffers
592
+
593
+ # vertices
594
+ if !material.morph_targets && attributes['position'] && attributes['position'] >= 0
595
+ if update_buffers
596
+ glBindBuffer(GL_ARRAY_BUFFER, geometry_group[:_opengl_vertex_buffer])
597
+
598
+ @state.enable_attribute(attributes['position'])
599
+
600
+ glVertexAttribPointer(attributes['position'], 3, GL_FLOAT, GL_FALSE, 0, 0)
601
+ end
602
+ elsif object.morph_target_base
603
+ setup_morph_targets(material, geometry_group, object)
604
+ end
605
+
606
+ if update_buffers
607
+ # custom attributes
608
+
609
+ # use the per-geometry_group custom attribute arrays which are setup in init_mesh_buffers
610
+
611
+ if geometry_group[:_opengl_custom_attributes_list]
612
+ geometry_group[:_opengl_custom_attributes_list].each do |attribute|
613
+ if attributes[attribute.buffer.belongs_to_attribute] >= 0
614
+ glBindBuffer(GL_ARRAY_BUFFER, attribute.buffer)
615
+
616
+ @state.enable_attribute(attributes[attribute.buffer.belongs_to_attribute])
617
+
618
+ glVertexAttribPointer(attributes[attribute.buffer.belongs_to_attribute], attribute.size, GL_FLOAT, GL_FALSE, 0, 0)
619
+ end
620
+ end
621
+ end
622
+
623
+ # colors
624
+
625
+ if attributes['color'] && attributes['color'] >= 0
626
+ glBindBuffer(GL_ARRAY_BUFFER, geometry_group[:_opengl_color_buffer])
627
+
628
+ @state.enable_attribute(attributes['color'])
629
+
630
+ glVertexAttribPointer(attributes['color'], 3, GL_FLOAT, GL_FALSE, 0, 0)
631
+ elsif !material.default_attribute_values.nil?
632
+ glVertexAttrib3fv(attributes['color'], material.default_attribute_values.color)
633
+ end
634
+
635
+ # normals
636
+
637
+ if attributes['normal'] && attributes['normal'] >= 0
638
+ glBindBuffer(GL_ARRAY_BUFFER, geometry_group[:_opengl_normal_buffer])
639
+
640
+ @state.enable_attribute(attributes['normal'])
641
+
642
+ glVertexAttribPointer(attributes['normal'], 3, GL_FLOAT, GL_FALSE, 0, 0)
643
+ end
644
+
645
+ # tangents
646
+
647
+ if attributes['tangent'] && attributes['tangent'] >= 0
648
+ glBindBuffer(GL_ARRAY_BUFFER, geometry_group[:_opengl_tangent_buffer])
649
+
650
+ @state.enable_attribute(attributes['tangent'])
651
+
652
+ glVertexAttribPointer(attributes['tangent'], 4, GL_FLOAT, GL_FALSE, 0, 0)
653
+ end
654
+
655
+ # uvs
656
+
657
+ if attributes['uv'] && attributes['uv'] >= 0
658
+ if object.geometry.face_vertex_uvs[0]
659
+ glBindBuffer(GL_ARRAY_BUFFER, geometry_group[:_opengl_uv_buffer])
660
+
661
+ @state.enable_attribute(attributes['uv'])
662
+
663
+ glVertexAttribPointer(attributes['uv'], 2, GL_FLOAT, GL_FALSE, 0, 0)
664
+ elsif !material.default_attribute_values.nil?
665
+ glVertexAttrib2fv(attributes['uv'], material.default_attribute_values.uv)
666
+ end
667
+ end
668
+
669
+ if attributes['uv2'] && attributes['uv2'] >= 0
670
+ if object.geometry.face_vertex_uvs[1]
671
+ glBindBuffer(GL_ARRAY_BUFFER, geometry_group[:_opengl_uv2_buffer])
672
+
673
+ @state.enable_attribute(attributes['uv2'])
674
+
675
+ glVertexAttribPointer(attributes['uv2'], 2, GL_FLOAT, GL_FALSE, 0, 0)
676
+ elsif !material.default_attribute_values.nil?
677
+ glVertexAttrib2fv(attributes['uv2'], material.default_attribute_values.uv2)
678
+ end
679
+ end
680
+
681
+ if material.skinning && attributes['skin_index'] && attributes['skin_weight'] && attributes['skin_index'] >= 0 && attributes['skin_weight'] >= 0
682
+ glBindBuffer(GL_ARRAY_BUFFER, geometry_group[:_opengl_skin_indices_buffer])
683
+
684
+ @state.enable_attribute(attributes['skin_index'])
685
+
686
+ glVertexAttribPointer(attributes['skin_index'], 4, GL_FLOAT, GL_FALSE, 0, 0)
687
+
688
+ glBindBuffer(GL_ARRAY_BUFFER, geometry_group[:_opengl_skin_weight_buffer])
689
+
690
+ @state.enable_attribute(attributes['skin_weight'])
691
+
692
+ glVertexAttribPointer(attributes['skin_weight'], 4, GL_FLOAT, GL_FALSE, 0, 0)
693
+ end
694
+
695
+ # line distances
696
+
697
+ if attributes['line_distances'] && attributes['line_distances'] >= 0
698
+ glBindBuffer(GL_ARRAY_BUFFER, geometry_group[:_opengl_line_distance_buffer])
699
+
700
+ @state.enable_attribute(attributes['line_distance'])
701
+
702
+ glVertexAttribPointer(attributes['line_distance'], 1, GL_FLOAT, GL_FALSE, 0, 0)
703
+ end
704
+ end
705
+
706
+ @state.disable_unused_attributes
707
+
708
+ case object
709
+
710
+ # render mesh
711
+ when Mesh
712
+ type = GL_UNSIGNED_INT # geometry_group[:_type_array] == Uint32Array ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT
713
+
714
+ # wireframe
715
+ if material.wireframe
716
+ @state.set_line_width(material.wireframe_linewidth * @pixel_ratio)
717
+
718
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geometry_group[:_opengl_line_buffer]) if update_buffers
719
+ glDrawElements(GL_LINES, geometry_group[:_opengl_line_count], type, 0)
720
+
721
+ # triangles
722
+ else
723
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geometry_group[:_opengl_face_buffer]) if update_buffers
724
+ glDrawElements(GL_TRIANGLES, geometry_group[:_opengl_face_count], type, 0)
725
+ end
726
+
727
+ @info[:render][:calls] += 1
728
+ @info[:render][:vertices] += geometry_group[:_opengl_face_count]
729
+ @info[:render][:faces] += geometry_group[:_opengl_face_count] / 3
730
+ when Line
731
+ mode = object.mode == LineStrip ? GL_LINE_STRIP : GL_LINES
732
+
733
+ @state.set_line_width(material.line_width * @pixel_ratio)
734
+
735
+ glDrawArrays(mode, 0, geometry_group[:_opengl_line_count])
736
+
737
+ @info[:render][:calls] += 1
738
+
739
+ # TODO: render particles
740
+ # when PointCloud
741
+ # glDrawArrays(GL_POINTS, 0, geometry_group[:_opengl_particle_count])
742
+ #
743
+ # @info[:render][:calls] += 1
744
+ # @info[:render][:points] += geometry_group[:_opengl_particle_count]
745
+ end
746
+ end
747
+
748
+ def set_texture(texture, slot)
749
+ glActiveTexture(GL_TEXTURE0 + slot)
750
+
751
+ if texture.needs_update?
752
+ upload_texture(texture)
753
+ else
754
+ glBindTexture(GL_TEXTURE_2D, texture[:_opengl_texture])
755
+ end
756
+ end
757
+
758
+ def upload_texture(texture)
759
+ if texture[:_opengl_init].nil?
760
+ texture[:_opengl_init] = true
761
+ texture.add_event_listener :dispose, @on_texture_dispose
762
+ texture[:_opengl_texture] = glCreateTexture
763
+ @info[:memory][:textures] += 1
764
+ end
765
+
766
+ glBindTexture(GL_TEXTURE_2D, texture[:_opengl_texture])
767
+
768
+ # glPixelStorei(GL_UNPACK_FLIP_Y_WEBGL, texture.flip_y) ???
769
+ # glPixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiply_alpha) ???
770
+ glPixelStorei(GL_UNPACK_ALIGNMENT, texture.unpack_alignment)
771
+
772
+ texture.image = clamp_to_max_size(texture.image, @_max_texture_size)
773
+
774
+ image = texture.image
775
+ is_image_power_of_two = Math.power_of_two?(image.width) && Math.power_of_two?(image.height)
776
+ gl_format = param_mittsu_to_gl(texture.format)
777
+ gl_type = param_mittsu_to_gl(texture.type)
778
+
779
+ set_texture_parameters(GL_TEXTURE_2D, texture, is_image_power_of_two)
780
+
781
+ mipmaps = texture.mipmaps
782
+
783
+ if texture.is_a?(DataTexture)
784
+ # use manually created mipmaps if available
785
+ # if there are no manual mipmaps
786
+ # set 0 level mipmap and then use GL to generate other mipmap levels
787
+
788
+ if !mipmaps.empty? && is_image_power_of_two
789
+ mipmaps.each_with_index do |mipmap, i|
790
+ glTexImage2D(GL_TEXTURE_2D, i, gl_format, mipmap.width, mipmap.height, 0, gl_format, gl_type, mipmap.data)
791
+ end
792
+ else
793
+ glTexImage2D(GL_TEXTURE_2D, 0, gl_format, image.width, image.height, 0, gl_format, gl_type, image.data)
794
+ end
795
+ elsif texture.is_a?(CompressedTexture)
796
+ mipmaps.each_with_index do |mipmap, i|
797
+ if texture.format != RGBAFormat && texture.format != RGBFormat
798
+ if get_compressed_texture_formats.index(gl_format)
799
+ glCompressedTexImage2D(GL_TEXTURE_2D, i, gl_format, mipmap.width, mipmap.height, 0, mipmap.data)
800
+ else
801
+ puts 'WARNING: Mittsu::OpenGLRenderer: Attempt to load unsupported compressed texture format in #upload_texture'
802
+ end
803
+ else
804
+ glTexImage2D(GL_TEXTURE_2D, i, gl_format, mipmap.width, mipmap.height, 0, gl_format, gl_type, mipmap.data)
805
+ end
806
+ end
807
+ else # regular texture (image, video, canvas)
808
+ # use manually created mipmaps if available
809
+ # if there are no manual mipmaps
810
+ # set 0 level mipmap and then use GL to generate other mipmap levels
811
+
812
+ if !mipmaps.empty? && is_image_power_of_two
813
+ mipmaps.each_with_index do |mipmap, i|
814
+ glTexImage2D(GL_TEXTURE_2D, i, gl_format, mipmap.width, mipmap.height, 0, gl_format, gl_type, mipmap.data)
815
+ end
816
+
817
+ texture.generate_mipmaps = false
818
+ else
819
+ glTexImage2D(GL_TEXTURE_2D, 0, gl_format, texture.image.width, texture.image.height, 0, gl_format, gl_type, texture.image.data)
820
+ end
821
+ end
822
+
823
+ if texture.generate_mipmaps && is_image_power_of_two
824
+ glGenerateMipmap(GL_TEXTURE_2D)
825
+ end
826
+
827
+ texture.needs_update = false
828
+
829
+ if texture.on_update
830
+ texture.on_update.()
831
+ end
832
+ end
833
+
834
+ private
835
+
836
+ def clear_color(r, g, b, a)
837
+ if (@_premultiplied_alpha)
838
+ r *= a; g *= a; b *= a
839
+ end
840
+
841
+ glClearColor(r, g, b, a)
842
+ end
843
+
844
+ def set_default_gl_state
845
+ glClearColor(0.0, 0.0, 0.0, 1.0)
846
+ glClearDepth(1)
847
+ glClearStencil(0)
848
+
849
+ glEnable(GL_DEPTH_TEST)
850
+ glDepthFunc(GL_LEQUAL)
851
+
852
+ glFrontFace(GL_CCW)
853
+ glCullFace(GL_BACK)
854
+ glEnable(GL_CULL_FACE)
855
+
856
+ glEnable(GL_BLEND)
857
+ glBlendEquation(GL_FUNC_ADD)
858
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
859
+
860
+ glViewport(@_viewport_x, @_viewport_y, @_viewport_width, @_viewport_height)
861
+
862
+ clear_color(@_clear_color.r, @_clear_color.g, @_clear_color.b, @_clear_alpha)
863
+ end
864
+
865
+ def get_compressed_texture_formats
866
+ return @_compressed_texture_formats ||= []
867
+ # TODO: needs extensions.get ...
868
+ end
869
+
870
+ def painter_sort_stable(a, b)
871
+ if a[:object].render_order != b[:object].render_order
872
+ a[:object].render_order - b[:object].render_order
873
+ elsif a[:material].id != b[:material].id
874
+ a[:material].id - b[:material].id
875
+ elsif a[:z] != b[:z]
876
+ a[:z] - b[:z]
877
+ else
878
+ a[:id] - b[:id]
879
+ end
880
+ end
881
+
882
+ def reverse_painter_sort_stable(a, b)
883
+ if a.object.render_order != b.object.render_order
884
+ a.object.render_order - b.object.render_order
885
+ elsif a.z != b.z
886
+ b.z - a.z
887
+ else
888
+ a.id - b.id
889
+ end
890
+ end
891
+
892
+ def get_gl_parameter(pname)
893
+ data = ' '
894
+ glGetIntegerv(pname, data)
895
+ data.unpack('L')[0]
896
+ end
897
+
898
+ def project_object(object)
899
+ return unless object.visible
900
+ if object.is_a? Scene # || object.is_a? Group # TODO: when Group is defined
901
+ # skip
902
+ else
903
+ init_object(object)
904
+ if object.is_a? Light
905
+ @lights << object
906
+ # if object.is_a? Sprite # TODO
907
+ # @sprites << object
908
+ # if object.is_a? LensFlare # TODO
909
+ # @lens_flares << object
910
+ else
911
+ opengl_objects = @_opengl_objects[object.id]
912
+ if opengl_objects && (!object.frustum_culled || @_frustum.intersects_object?(object))
913
+ opengl_objects.each do |opengl_object|
914
+ unroll_buffer_material(opengl_object)
915
+ opengl_object[:render] = true
916
+ if @sort_objects
917
+ @_vector3.set_from_matrix_position(object.matrix_world)
918
+ @_vector3.apply_projection(@_proj_screen_matrix)
919
+
920
+ opengl_object[:z] = @_vector3.z
921
+ end
922
+ end
923
+ end
924
+ end
925
+ end
926
+
927
+ object.children.each do |child|
928
+ project_object(child)
929
+ end
930
+ end
931
+
932
+ def render_objects(render_list, camera, lights, fog, override_material)
933
+ material = nil
934
+ render_list.each do |opengl_object|
935
+ object = opengl_object[:object]
936
+ buffer = opengl_object[:buffer]
937
+
938
+ setup_matrices(object, camera)
939
+
940
+ if override_material
941
+ material = override_material
942
+ else
943
+ material = opengl_object[:material]
944
+ next unless material
945
+ set_material(material)
946
+ end
947
+
948
+ set_material_faces(material)
949
+ if buffer.is_a? BufferGeometry
950
+ render_buffer_direct(camera, lights, fog, material, buffer, object)
951
+ else
952
+ render_buffer(camera, lights, fog, material, buffer, object)
953
+ end
954
+ end
955
+ end
956
+
957
+ def render_objects_immediate(render_list, material_type, camera, lights, fog, override_material)
958
+ material = nil
959
+ render_list.each do |opengl_object|
960
+ object = opengl_object[:object]
961
+ if object.visible
962
+ if override_material
963
+ material = override_material
964
+ else
965
+ material = opengl_object[material_type]
966
+ next unless material
967
+ set_material(material)
968
+ end
969
+ render_immediate_object(camera, lights, fog, material, object)
970
+ end
971
+ end
972
+ end
973
+
974
+ def init_object(object)
975
+ if object[:_opengl_init].nil?
976
+ object[:_opengl_init] = true
977
+ object[:_model_view_matrix] = Matrix4.new
978
+ object[:_normal_matrix] = Matrix3.new
979
+
980
+ object.add_event_listener(:removed, @on_object_removed)
981
+ end
982
+
983
+ geometry = object.geometry
984
+
985
+ if geometry.nil?
986
+ # ImmediateRenderObject
987
+ elsif geometry[:_opengl_init].nil?
988
+ geometry[:_opengl_init] = true
989
+ geometry.add_event_listener(:dispose, @on_geometry_dispose)
990
+ case object
991
+ when BufferGeometry
992
+ @info[:memory][:geometries] += 1
993
+ when Mesh
994
+ init_geometry_groups(object, geometry)
995
+ when Line
996
+ if geometry[:_opengl_vertex_buffer].nil?
997
+ create_line_buffers(geometry)
998
+ init_line_buffers(geometry, object)
999
+
1000
+ geometry.vertices_need_update = true
1001
+ geometry.colors_need_update = true
1002
+ geometry.line_distances_need_update
1003
+ end
1004
+ # TODO: when PointCloud exists
1005
+ # when PointCloud
1006
+ # if geometry[:_opengl_vertex_buffer].nil?
1007
+ # create_particle_buffers(geometry)
1008
+ # init_particle_buffers(geometry, object)
1009
+ #
1010
+ # geometry.vertices_need_update = true
1011
+ # geometry.colors_need_update = true
1012
+ # end
1013
+ end
1014
+ end
1015
+
1016
+ if object[:_opengl_active].nil?
1017
+ object[:_opengl_active] = true
1018
+ case object
1019
+ when Mesh
1020
+ case geometry
1021
+ when BufferGeometry
1022
+ add_buffer(@_opengl_objects, geometry, object)
1023
+ when Geometry
1024
+ geometry_groups_list = @geometry_groups[geometry.id]
1025
+ geometry_groups_list.each do |group|
1026
+ add_buffer(@_opengl_objects, group, object)
1027
+ end
1028
+ end
1029
+ when Line #, PointCloud TODO
1030
+ add_buffer(@_opengl_objects, geometry, object)
1031
+ else
1032
+ # TODO: when ImmediateRenderObject exists
1033
+ # if object.is_a? ImmediateRenderObject || object.immediate_render_callback
1034
+ # add_buffer_immediate(@_opengl_objects_immediate, object)
1035
+ # end
1036
+ end
1037
+ end
1038
+ end
1039
+
1040
+ def make_groups(geometry, uses_face_material = false)
1041
+ max_vertices_in_group = 65535 # TODO: OES_element_index_uint ???
1042
+
1043
+ hash_map = {}
1044
+
1045
+ num_morph_targets = geometry.morph_targets.length
1046
+ num_morph_normals = geometry.morph_normals.length
1047
+
1048
+ groups = {}
1049
+ groups_list = []
1050
+
1051
+ geometry.faces.each_with_index do |face, f|
1052
+ material_index = uses_face_material ? face.material_index : 0
1053
+
1054
+ if !hash_map.include? material_index
1055
+ hash_map[material_index] = { hash: material_index, counter: 0 }
1056
+ end
1057
+
1058
+ group_hash = "#{hash_map[material_index][:hash]}_#{hash_map[material_index][:counter]}"
1059
+
1060
+ if !groups.include? group_hash
1061
+ group = {
1062
+ id: @geometry_group_counter += 1,
1063
+ faces3: [],
1064
+ material_index: material_index,
1065
+ vertices: 0,
1066
+ num_morph_targets: num_morph_targets,
1067
+ num_morph_normals: num_morph_normals
1068
+ }
1069
+
1070
+ groups[group_hash] = group
1071
+ groups_list << group
1072
+ end
1073
+
1074
+ if groups[group_hash][:vertices] + 3 > max_vertices_in_group
1075
+ hash_map[material_index][:counter] += 1
1076
+ group_hash = "#{hash_map[material_index][:hash]}_#{hash_map[material_index][:counter]}"
1077
+
1078
+ if !groups.include? group_hash
1079
+ group = {
1080
+ id: @geometry_group_counter += 1,
1081
+ faces3: [],
1082
+ material_index: material_index,
1083
+ vertices: 0,
1084
+ num_morph_targets: num_morph_targets,
1085
+ num_morph_normals: num_morph_normals
1086
+ }
1087
+
1088
+ groups[group_hash] = group
1089
+ groups_list << group
1090
+ end
1091
+ end
1092
+ groups[group_hash][:faces3] << f
1093
+ groups[group_hash][:vertices] += 3
1094
+ end
1095
+ groups_list
1096
+ end
1097
+
1098
+ def init_geometry_groups(object, geometry)
1099
+ # material = object.material
1100
+ add_buffers = false
1101
+
1102
+ if @geometry_groups[geometry.id].nil? || geometry.groups_need_update
1103
+ @_opengl_objects.delete object.id
1104
+
1105
+ @geometry_groups[geometry.id] = make_groups(geometry, false) # TODO: material.is_a?(MeshFaceMaterial))
1106
+
1107
+ geometry.groups_need_update = false
1108
+ end
1109
+
1110
+ geometry_groups_list = @geometry_groups[geometry.id]
1111
+
1112
+ # create separate VBOs per geometry chunk
1113
+
1114
+ geometry_groups_list.each do |geometry_group|
1115
+ # initialize VBO on the first access
1116
+ if geometry_group[:_opengl_vertex_buffer].nil?
1117
+ create_mesh_buffers(geometry_group)
1118
+ init_mesh_buffers(geometry_group, object)
1119
+
1120
+ geometry.vertices_need_update = true
1121
+ geometry.morph_targets_need_update = true
1122
+ geometry.elements_need_update = true
1123
+ geometry.uvs_need_update = true
1124
+ geometry.normals_need_update = true
1125
+ geometry.tangents_need_update = true
1126
+ geometry.colors_need_update = true
1127
+ else
1128
+ add_buffers = false
1129
+ end
1130
+
1131
+ if add_buffers || object[:_opengl_active].nil?
1132
+ add_buffer(@_opengl_objects, geometry_group, object)
1133
+ end
1134
+ end
1135
+
1136
+ object[:_opengl_active] = true
1137
+ end
1138
+
1139
+ def add_buffer(objlist, buffer, object)
1140
+ id = object.id
1141
+ objlist[id] ||= []
1142
+ objlist[id] << {
1143
+ id: id,
1144
+ buffer: buffer,
1145
+ object: object,
1146
+ material: nil,
1147
+ z: 0
1148
+ }
1149
+ end
1150
+
1151
+ def unroll_buffer_material(globject)
1152
+ object = globject[:object]
1153
+ # buffer = globject[:buffer]
1154
+
1155
+ # geometry = object.geometry
1156
+ material = object.material
1157
+
1158
+ if material
1159
+ # TODO: when MeshFaceMaterial exists
1160
+ # if material.is_a? MeshFaceMaterial
1161
+ # material_index = geometry.is_a? BufferGeometry ? 0 : buffer.material_index
1162
+ #
1163
+ # material = material.materials[material_index]
1164
+ # end
1165
+ globject[:material] = material
1166
+
1167
+ if material.transparent
1168
+ @transparent_objects << globject
1169
+ else
1170
+ @opaque_objects << globject
1171
+ end
1172
+ end
1173
+ end
1174
+
1175
+ def setup_matrices(object, camera)
1176
+ object[:_model_view_matrix].tap do |model_view_matrix|
1177
+ model_view_matrix.multiply_matrices(camera.matrix_world_inverse, object.matrix_world)
1178
+ object[:_normal_matrix].normal_matrix(model_view_matrix)
1179
+ end
1180
+ end
1181
+
1182
+ def set_material(material)
1183
+ if material.transparent
1184
+ @state.set_blending(material.blending, material.blend_equation, material.blend_src, material.blend_dst, material.blend_equation_alpha, material.blend_src_alpha, material.blend_dst_alpha)
1185
+ else
1186
+ @state.set_blending(NoBlending)
1187
+ end
1188
+
1189
+ @state.set_depth_test(material.depth_test)
1190
+ @state.set_depth_write(material.depth_write)
1191
+ @state.set_color_write(material.color_write)
1192
+ @state.set_polygon_offset(material.polygon_offset, material.polygon_offset_factor, material.polygon_offset_units)
1193
+ end
1194
+
1195
+ def create_line_buffers(geometry)
1196
+ geometry[:_opengl_vertex_array] = glCreateVertexArray
1197
+
1198
+ geometry[:_opengl_vertex_buffer] = glCreateBuffer
1199
+ geometry[:_opengl_color_buffer] = glCreateBuffer
1200
+ geometry[:_opengl_line_distance_buffer] = glCreateBuffer
1201
+
1202
+ @info[:memory][:geometries] += 1
1203
+ end
1204
+
1205
+ def create_mesh_buffers(geometry_group)
1206
+ geometry_group[:_opengl_vertex_array] = glCreateVertexArray
1207
+
1208
+ geometry_group[:_opengl_vertex_buffer] = glCreateBuffer
1209
+ geometry_group[:_opengl_normal_buffer] = glCreateBuffer
1210
+ geometry_group[:_opengl_tangent_buffer] = glCreateBuffer
1211
+ geometry_group[:_opengl_color_buffer] = glCreateBuffer
1212
+ geometry_group[:_opengl_uv_buffer] = glCreateBuffer
1213
+ geometry_group[:_opengl_uv2_buffer] = glCreateBuffer
1214
+
1215
+ geometry_group[:_opengl_skin_indices_buffer] = glCreateBuffer
1216
+ geometry_group[:_opengl_skin_weights_buffer] = glCreateBuffer
1217
+
1218
+ geometry_group[:_opengl_face_buffer] = glCreateBuffer
1219
+ geometry_group[:_opengl_line_buffer] = glCreateBuffer
1220
+
1221
+ num_morph_targets = geometry_group[:num_morph_targets]
1222
+
1223
+ if num_morph_targets
1224
+ geometry_group[:_opengl_morph_targets_buffers] = []
1225
+
1226
+ num_morph_targets.times do |m|
1227
+ geometry_group[:_opengl_morph_targets_buffers] << glCreateBuffer
1228
+ end
1229
+ end
1230
+
1231
+ num_morph_normals = geometry_group[:num_morph_normals]
1232
+
1233
+ if num_morph_normals
1234
+ geometry_group[:_opengl_morph_normals_buffers] = []
1235
+
1236
+ num_morph_normals.times do |m|
1237
+ geometry_group[:_opengl_morph_normals_buffers] << glCreateBuffer
1238
+ end
1239
+ end
1240
+
1241
+ @info[:memory][:geometries] += 1
1242
+ end
1243
+
1244
+ def glCreateBuffer
1245
+ @_b ||= ' '*8
1246
+ glGenBuffers(1, @_b)
1247
+ @_b.unpack('L')[0]
1248
+ end
1249
+
1250
+ def glCreateTexture
1251
+ @_b ||= ' '*8
1252
+ glGenTextures(1, @_b)
1253
+ @_b.unpack('L')[0]
1254
+ end
1255
+
1256
+ def glCreateVertexArray
1257
+ @_b ||= ' '*8
1258
+ glGenVertexArrays(1, @_b)
1259
+ @_b.unpack('L')[0]
1260
+ end
1261
+
1262
+ def glCreateFramebuffer
1263
+ @_b ||= ' '*8
1264
+ glGenFramebuffers(1, @_b)
1265
+ @_b.unpack('L')[0]
1266
+ end
1267
+
1268
+ def glCreateRenderbuffer
1269
+ @_b ||= ' '*8
1270
+ glGenRenderbuffers(1, @_b)
1271
+ @_b.unpack('L')[0]
1272
+ end
1273
+
1274
+ def array_to_ptr_easy(data)
1275
+ size_of_element = data.first.is_a?(Float) ? Fiddle::SIZEOF_FLOAT : Fiddle::SIZEOF_INT
1276
+ if data.first.is_a?(Float)
1277
+ size_of_element = Fiddle::SIZEOF_FLOAT
1278
+ format_of_element = 'F'
1279
+ # data.map!{ |d| d.nil? ? 0.0 : d }
1280
+ else
1281
+ size_of_element = Fiddle::SIZEOF_INT
1282
+ format_of_element = 'L'
1283
+ # data.map!{ |d| d.nil? ? 0 : d }
1284
+ end
1285
+ size = data.length * size_of_element
1286
+ array_to_ptr(data, size, format_of_element)
1287
+ end
1288
+
1289
+ def array_to_ptr(data, size, format)
1290
+ ptr = Fiddle::Pointer.malloc(size)
1291
+ ptr[0,size] = data.pack(format * data.length)
1292
+ ptr
1293
+ end
1294
+
1295
+ def glBufferData_easy(target, data, usage)
1296
+ ptr = array_to_ptr_easy(data)
1297
+ glBufferData(target, ptr.size, ptr, usage)
1298
+ end
1299
+
1300
+ def init_custom_attributes(object)
1301
+ geometry = object.geometry
1302
+ material = object.material
1303
+
1304
+ nvertices = geometry.vertices.length
1305
+
1306
+ if material.attributes
1307
+ geometry[:_opengl_custom_attributes_list] ||= []
1308
+
1309
+ material.attributes.each do |(name, attribute)|
1310
+ if !attribute[:_opengl_initialized] || attribute.create_unique_buffers
1311
+ attribute[:_opengl_initialized] = true
1312
+
1313
+ size = case attribute.type
1314
+ when :v2 then 2
1315
+ when :v3 then 3
1316
+ when :v4 then 4
1317
+ when :c then 3
1318
+ else 1
1319
+ end
1320
+
1321
+ attribute.size = size
1322
+
1323
+ attribute.array = Array.new(nvertices * size) # Float32Array
1324
+
1325
+ attribute.buffer = glCreateBuffer
1326
+ attribute.buffer.belongs_to_attribute = name
1327
+
1328
+ attribute.needs_update = true
1329
+ end
1330
+
1331
+ geometry[:_opengl_custom_attributes_list] << attribute
1332
+ end
1333
+ end
1334
+ end
1335
+
1336
+ def init_line_buffers(geometry, object)
1337
+ nvertices = geometry.vertices.length
1338
+
1339
+ geometry[:_vertex_array] = Array.new(nvertices * 3, 0.0) # Float32Array
1340
+ geometry[:_color_array] = Array.new(nvertices * 3, 0.0) # Float32Array
1341
+ geometry[:_line_distance_array] = Array.new(nvertices, 0.0) # Float32Array
1342
+
1343
+ geometry[:_opengl_line_count] = nvertices
1344
+
1345
+ init_custom_attributes(object)
1346
+ end
1347
+
1348
+ def init_mesh_buffers(geometry_group, object)
1349
+ geometry = object.geometry
1350
+ faces3 = geometry_group[:faces3]
1351
+
1352
+ nvertices = faces3.length * 3
1353
+ ntris = faces3.length * 1
1354
+ nlines = faces3.length * 3
1355
+
1356
+ material = get_buffer_material(object, geometry_group)
1357
+
1358
+ geometry_group[:_vertex_array] = Array.new(nvertices * 3) # Float32Array
1359
+ geometry_group[:_normal_array] = Array.new(nvertices * 3) # Float32Array
1360
+ geometry_group[:_color_array] = Array.new(nvertices * 3) # Float32Array
1361
+ geometry_group[:_uv_array] = Array.new(nvertices * 2) # Float32Array
1362
+
1363
+ if geometry.face_vertex_uvs.length > 1
1364
+ geometry_group[:_uv2_array] = Array.new(nvertices * 2) # Float32Array
1365
+ end
1366
+
1367
+ if geometry.has_tangents
1368
+ geometry_group[:_tangent_array] = Array.new(nvertices * 4) # Float32Array
1369
+ end
1370
+
1371
+ if !object.geometry.skin_weights.empty? && !object.geometry.skin_indices.empty?
1372
+ geometry_group[:_skin_index_array] = Array.new(nvertices * 4) # Float32Array
1373
+ geometry_group[:_skin_weight_array] = Array.new(nvertices * 4)
1374
+ end
1375
+
1376
+ # UintArray from OES_element_index_uint ???
1377
+
1378
+ geometry_group[:_type_array] = Array # UintArray ???
1379
+ geometry_group[:_face_array] = Array.new(ntris * 3)
1380
+ geometry_group[:_line_array] = Array.new(nlines * 2)
1381
+
1382
+ num_morph_targets = geometry_group[:num_morph_targets]
1383
+
1384
+ if !num_morph_targets.zero?
1385
+ geometry_group[:_morph_targets_arrays] = []
1386
+
1387
+ num_morph_targets.times do |m|
1388
+ geometry_group[:_morph_targets_arrays] << Array.new(nvertices * 3) # Float32Array ???
1389
+ end
1390
+ end
1391
+
1392
+ num_morph_normals = geometry_group[:num_morph_normals]
1393
+
1394
+ if !num_morph_targets.zero?
1395
+ geometry_group[:_morph_normals_arrays] = []
1396
+
1397
+ num_morph_normals.times do |m|
1398
+ geometry_group[:_morph_normals_arrays] << Array.new(nvertices * 3) # Float32Array ???
1399
+ end
1400
+ end
1401
+
1402
+ geometry_group[:_opengl_face_count] = ntris * 3
1403
+ geometry_group[:_opengl_line_count] = nlines * 2
1404
+
1405
+ # custom attributes
1406
+
1407
+ if material.attributes
1408
+ if geometry_group[:_opengl_custom_attributes_list].nil?
1409
+ geometry_group[:_opengl_custom_attributes_list] = []
1410
+ end
1411
+
1412
+ material.attributes.each do |(name, original_attribute)|
1413
+ attribute = {}
1414
+ original_attribute.each do |(key, value)|
1415
+ attribute[key] = value
1416
+ end
1417
+
1418
+ if !attribute[:_opengl_initialized] || attribute[:create_unique_buffers]
1419
+ attribute[:_opengl_initialized] = true
1420
+
1421
+ size = case attribute[:type]
1422
+ when :v2 then 2
1423
+ when :v3, :c then 3
1424
+ when :v4 then 4
1425
+ else 1 # :f and :i
1426
+ end
1427
+
1428
+ attribute[:size] = size
1429
+ attribute[:array] = Array.new(nvertices * size) # Float32Array
1430
+
1431
+ attribute[:buffer] = glCreateBuffer
1432
+ attribute[:buffer_belongs_to_attribute] = name
1433
+
1434
+ original_attribute[:needs_update] = true
1435
+ attribute[:_original] = original_attribute
1436
+ end
1437
+
1438
+ geometry_group[:_opengl_custom_attributes_list] << attribute
1439
+ end
1440
+ end
1441
+
1442
+ geometry_group[:_initted_arrays] = true
1443
+ end
1444
+
1445
+ def update_object(object)
1446
+ geometry = object.geometry
1447
+
1448
+ if geometry.is_a? BufferGeometry
1449
+ # TODO: geomertry vertex array ?????
1450
+ # glBindVertexArray geometry.vertex_array
1451
+
1452
+ geometry.attributes.each do |(key, attribute)|
1453
+ buffer_type = (key == 'index') ? GL_ELEMENT_ARRAY_BUFFER : GL_ARRAY_BUFFER
1454
+
1455
+ if attribute.buffer.nil?
1456
+ attribute.buffer = glCreateBuffer
1457
+ glBindBuffer(buffer_type, attribute.buffer)
1458
+ glBufferData_easy(buffer_type, attribute.array, (attribute.is_a? DynamicBufferAttribute) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW)
1459
+
1460
+ attribute.needs_update = false
1461
+ elsif attribute.needs_update
1462
+ glBindBuffer(buffer_type, attribute.buffer)
1463
+ if attribute.update_range.nil? || attribute.update_range.count == -1 # Not using update ranged
1464
+ glBufferSubData(buffer_type, 0, attribute.array)
1465
+ elsif attribute.udpate_range.count.zero?
1466
+ puts 'ERROR: Mittsu::OpenGLRenderer#update_object: using update_range for Mittsu::DynamicBufferAttribute and marked as needs_update but count is 0, ensure you are using set methods or updating manually.'
1467
+ else
1468
+ # TODO: make a glBufferSubData_easy method
1469
+ glBufferSubData(buffer_type, attribute.update_range.offset * attribute.array.BYTES_PER_ELEMENT, attribute.array.subarray(attribute.update_range.offset, attribute.update_range.offset + attribute.update_range.count))
1470
+ attribute.update_range.count = 0 # reset range
1471
+ end
1472
+
1473
+ attribute.needs_update = false
1474
+ end
1475
+ end
1476
+ elsif object.is_a? Mesh
1477
+ # check all geometry groups
1478
+ if geometry.groups_need_update
1479
+ init_geometry_groups(object, geometry)
1480
+ end
1481
+
1482
+ geometry_groups_list = @geometry_groups[geometry.id]
1483
+
1484
+ material = nil
1485
+ geometry_groups_list.each do |geometry_group|
1486
+ # TODO: place to put this???
1487
+ # glBindVertexArray(geometry_group[:_opengl_vertex_array])
1488
+ material = get_buffer_material(object, geometry_group)
1489
+
1490
+ custom_attributes_dirty = material.attributes && are_custom_attributes_dirty(material)
1491
+
1492
+ if geometry.vertices_need_update || geometry.morph_targets_need_update || geometry.elements_need_update || geometry.uvs_need_update || geometry.normals_need_update || geometry.colors_need_update || geometry.tangents_need_update || custom_attributes_dirty
1493
+ set_mesh_buffers(geometry_group, object, GL_DYNAMIC_DRAW, !geometry.dynamic, material)
1494
+ end
1495
+ end
1496
+
1497
+ geometry.vertices_need_update = false
1498
+ geometry.morph_targets_need_update = false
1499
+ geometry.elements_need_update = false
1500
+ geometry.uvs_need_update = false
1501
+ geometry.normals_need_update = false
1502
+ geometry.colors_need_update = false
1503
+ geometry.tangents_need_update = false
1504
+
1505
+ material.attributes && clear_custom_attributes(material)
1506
+ elsif (object.is_a? Line)
1507
+ # TODO: glBindVertexArray ???
1508
+ material = get_buffer_material(object, geometry)
1509
+ custom_attributes_dirty = material.attributes && are_custom_attributes_dirty(material)
1510
+
1511
+ if geometry.vertices_need_update || geometry.colors_need_update || geometry.line_distances_need_update || custom_attributes_dirty
1512
+ set_line_buffers(geometry, GL_DYNAMIC_DRAW)
1513
+ end
1514
+
1515
+ geometry.vertices_need_update = false
1516
+ geometry.colors_need_update = false
1517
+ geometry.line_distances_need_update = false
1518
+
1519
+ material.attributes && clear_custom_attributes(material)
1520
+ elsif object.is_A? PointCloud
1521
+ # TODO: glBindVertexArray ???
1522
+ material = get_buffer_material(object, geometry)
1523
+ custom_attributes_dirty = material.attributes && are_custom_attributes_dirty(material)
1524
+
1525
+ if geometry.vertices_need_update || geometry.colors_need_update || custom_attributes_dirty
1526
+ set_particle_buffers(geometry, GL_DYNAMIC_DRAW, object)
1527
+ end
1528
+
1529
+ geometry.vertices_need_update = false
1530
+ geometry.colors_need_update = false
1531
+
1532
+ material.attributes && clear_custom_attributes(material)
1533
+ end
1534
+ end
1535
+
1536
+ def get_buffer_material(object, geometry_group)
1537
+ # TODO: when MeshFaceMaterial exists
1538
+ # object.material.is_a?(MeshFaceMaterial) ? object.material.materials[geometry_group[:material_index]] : object.material
1539
+
1540
+ object.material # for now...
1541
+ end
1542
+
1543
+ def set_line_buffers(geometry, hint)
1544
+ vertices = geometry.vertices
1545
+ colors = geometry.colors
1546
+ line_distances = geometry.line_distances_need_update
1547
+
1548
+ vertex_array = geometry[:_vertex_array]
1549
+ color_array = geometry[:_color_array]
1550
+ line_distance_array = geometry[:_line_distance_array]
1551
+
1552
+ custom_attributes = geometry[:_opengl_custom_attributes_list]
1553
+
1554
+ if geometry.vertices_need_update
1555
+ vertices.each_with_index do |vertex, v|
1556
+ offset = v * 3
1557
+
1558
+ vertex_array[offset] = vertex.x
1559
+ vertex_array[offset + 1] = vertex.y
1560
+ vertex_array[offset + 2] = vertex.z
1561
+ end
1562
+
1563
+ glBindBuffer(GL_ARRAY_BUFFER, geometry[:_opengl_vertex_buffer])
1564
+ glBufferData_easy(GL_ARRAY_BUFFER, vertex_array, hint)
1565
+ end
1566
+
1567
+ if geometry.colors_need_update
1568
+ colors.each_with_index do |color, c|
1569
+ offset = c * 3
1570
+
1571
+ color_array[offset] = color.r
1572
+ color_array[offset + 1] = color.g
1573
+ color_array[offset + 2] = color.b
1574
+ end
1575
+
1576
+ glBindBuffer(GL_ARRAY_BUFFER, geometry[:_opengl_color_buffer])
1577
+ glBufferData_easy(GL_ARRAY_BUFFER, color_array, hint)
1578
+ end
1579
+
1580
+ if geometry.line_distances_need_update
1581
+ line_distances.each_with_index do |l, d|
1582
+ line_distance_array[d] = l
1583
+ end
1584
+
1585
+ glBindBuffer(GL_ARRAY_BUFFER, geometry[:_opengl_line_distance_buffer])
1586
+ glBufferData_easy(GL_ARRAY_BUFFER, line_distance_array, hint)
1587
+ end
1588
+
1589
+ if custom_attributes
1590
+ custom_attribute.each do |custom_attribute|
1591
+ offset = 0
1592
+
1593
+ values = custom_attribute.value
1594
+
1595
+ case custom_attribute.size
1596
+ when 1
1597
+ value.each_with_index do |value, ca|
1598
+ custom_attribute.array[ca] = value
1599
+ end
1600
+ when 2
1601
+ values.each_with_index do |value, ca|
1602
+ custom_attribute[offset ] = value.x
1603
+ custom_attribute[offset + 1] = value.y
1604
+
1605
+ offset += 2
1606
+ end
1607
+ when 3
1608
+ if custom_attribute.type === :c
1609
+ values.each_with_index do |value, ca|
1610
+ custom_attribute[offset ] = value.r
1611
+ custom_attribute[offset + 1] = value.g
1612
+ custom_attribute[offset + 2] = value.b
1613
+
1614
+ offset += 3
1615
+ end
1616
+ else
1617
+ values.each_with_index do |value, ca|
1618
+ custom_attribute[offset ] = value.x
1619
+ custom_attribute[offset + 1] = value.y
1620
+ custom_attribute[offset + 2] = value.z
1621
+
1622
+ offset += 3
1623
+ end
1624
+ end
1625
+ when 4
1626
+ values.each_with_index do |value, ca|
1627
+ custom_attribute[offset ] = value.x
1628
+ custom_attribute[offset + 1] = value.y
1629
+ custom_attribute[offset + 2] = value.z
1630
+ custom_attribute[offset + 3] = value.w
1631
+
1632
+ offset += 4
1633
+ end
1634
+ end
1635
+
1636
+ glBindBuffer(GL_ARRAY_BUFFER, custom_attribute.buffer)
1637
+ glBufferData_easy(GL_ARRAY_BUFFER, custom_attribute.array, hint)
1638
+
1639
+ custom_attribute.needs_update = false
1640
+ end
1641
+ end
1642
+ end
1643
+
1644
+ def set_mesh_buffers(geometry_group, object, hint, dispose, material)
1645
+ return unless geometry_group[:_initted_arrays]
1646
+
1647
+ needs_face_normals = material_needs_face_normals(material)
1648
+
1649
+ vertex_index = 0
1650
+
1651
+ offset = 0
1652
+ offset_uv = 0
1653
+ offset_uv2 = 0
1654
+ offset_face = 0
1655
+ offset_normal = 0
1656
+ offset_tangent = 0
1657
+ offset_line = 0
1658
+ offset_color = 0
1659
+ offset_skin = 0
1660
+ offset_morph_target = 0
1661
+ offset_custom = 0
1662
+
1663
+ vertex_array = geometry_group[:_vertex_array]
1664
+ uv_array = geometry_group[:_uv_array]
1665
+ uv2_array = geometry_group[:_uv2_array]
1666
+ normal_array = geometry_group[:_normal_array]
1667
+ tangent_array = geometry_group[:_tangent_array]
1668
+ color_array = geometry_group[:_color_array]
1669
+
1670
+ skin_index_array = geometry_group[:_skin_index_array]
1671
+ skin_weight_array = geometry_group[:_skin_weight_array]
1672
+
1673
+ morph_targets_arrays = geometry_group[:_morph_targets_arrays]
1674
+ morph_normals_arrays = geometry_group[:_morph_normals_arrays]
1675
+
1676
+ custom_attributes = geometry_group[:_opengl_custom_attributes_list]
1677
+
1678
+ face_array = geometry_group[:_face_array]
1679
+ line_array = geometry_group[:_line_array]
1680
+
1681
+ geometry = object.geometry # this is shared for all chunks
1682
+
1683
+ dirty_vertices = geometry.vertices_need_update
1684
+ dirty_elements = geometry.elements_need_update
1685
+ dirty_uvs = geometry.uvs_need_update
1686
+ dirty_normals = geometry.normals_need_update
1687
+ dirty_tangents = geometry.tangents_need_update
1688
+ dirty_colors = geometry.colors_need_update
1689
+ dirty_morph_targets = geometry.morph_targets_need_update
1690
+
1691
+ vertices = geometry.vertices
1692
+ chunk_faces3 = geometry_group[:faces3]
1693
+ obj_faces = geometry.faces
1694
+
1695
+ obj_uvs = geometry.face_vertex_uvs[0]
1696
+ obj_uvs2 = geometry.face_vertex_uvs[1]
1697
+
1698
+ obj_skin_indices = geometry.skin_indices
1699
+ obj_skin_weights = geometry.skin_weights
1700
+
1701
+ morph_targets = geometry.morph_targets
1702
+ morph_normals = geometry.morph_normals
1703
+
1704
+ if dirty_vertices
1705
+ chunk_faces3.each do |chf|
1706
+ face = obj_faces[chf]
1707
+
1708
+ v1 = vertices[face.a]
1709
+ v2 = vertices[face.b]
1710
+ v3 = vertices[face.c]
1711
+
1712
+ vertex_array[offset] = v1.x
1713
+ vertex_array[offset + 1] = v1.y
1714
+ vertex_array[offset + 2] = v1.z
1715
+
1716
+ vertex_array[offset + 3] = v2.x
1717
+ vertex_array[offset + 4] = v2.y
1718
+ vertex_array[offset + 5] = v2.z
1719
+
1720
+ vertex_array[offset + 6] = v3.x
1721
+ vertex_array[offset + 7] = v3.y
1722
+ vertex_array[offset + 8] = v3.z
1723
+
1724
+ offset += 9
1725
+ end
1726
+
1727
+ glBindBuffer(GL_ARRAY_BUFFER, geometry_group[:_opengl_vertex_buffer])
1728
+ glBufferData_easy(GL_ARRAY_BUFFER, vertex_array, hint)
1729
+ end
1730
+
1731
+ if dirty_morph_targets
1732
+ morph_targets.each_index do |vk|
1733
+ chunk_faces.each do |chf|
1734
+ face = obj_faces[chf]
1735
+
1736
+ # morph positions
1737
+
1738
+ v1 = morph_targets[vk].vertices[face.a]
1739
+ v2 = morph_targets[vk].vertices[face.b]
1740
+ v3 = morph_targets[vk].vertices[face.c]
1741
+
1742
+ vka = morph_targets_arrays[vk]
1743
+
1744
+ vka[offset_morph_target] = v1.x
1745
+ vka[offset_morph_target + 1] = v1.y
1746
+ vka[offset_morph_target + 2] = v1.z
1747
+
1748
+ vka[offset_morph_target + 3] = v2.x
1749
+ vka[offset_morph_target + 4] = v2.y
1750
+ vka[offset_morph_target + 5] = v2.z
1751
+
1752
+ vka[offset_morph_target + 6] = v3.x
1753
+ vka[offset_morph_target + 7] = v3.y
1754
+ vka[offset_morph_target + 8] = v3.z
1755
+
1756
+ # morph normals
1757
+
1758
+ if material.morph_normals
1759
+ if needs_face_normals
1760
+ n1 = morph_normals[vk].face_normals[chf]
1761
+ n2 = n1
1762
+ n3 = n1
1763
+ else
1764
+ face_vertex_normals = morph_normals[vk].vertex_normals[chf]
1765
+
1766
+ n1 = face_vertex_normals.a
1767
+ n2 = face_vertex_normals.b
1768
+ n3 = face_vertex_normals.c
1769
+ end
1770
+
1771
+ nka = morph_normals_arrays[vk]
1772
+
1773
+ nka[offset_morph_target] = n1.x
1774
+ nka[offset_morph_target + 1] = n1.y
1775
+ nka[offset_morph_target + 2] = n1.z
1776
+
1777
+ nka[offset_morph_target + 3] = n2.x
1778
+ nka[offset_morph_target + 4] = n2.y
1779
+ nka[offset_morph_target + 5] = n2.z
1780
+
1781
+ nka[offset_morph_target + 6] = n3.x
1782
+ nka[offset_morph_target + 7] = n3.y
1783
+ nka[offset_morph_target + 8] = n3.z
1784
+ end
1785
+
1786
+ #
1787
+
1788
+ offset_morph_target += 9
1789
+ end
1790
+
1791
+ glBindBuffer(GL_ARRAY_BUFFER, geometry_group[:_opengl_morph_targets_buffers][vk])
1792
+ glBufferData_easy(GL_ARRAY_BUFFER, morph_targets_arrays[vk], hint)
1793
+
1794
+ if material.morph_normals
1795
+ glBindBuffer(GL_ARRAY_BUFFER, geometry_group[:_opengl_morph_normals_buffers][vk])
1796
+ glBufferData_easy(GL_ARRAY_BUFFER, morph_normals_arrays[vk], hint)
1797
+ end
1798
+ end
1799
+ end
1800
+
1801
+ if !obj_skin_weights.empty?
1802
+ chunk_faces3.each do |chf|
1803
+ face = obj_faces[chf]
1804
+
1805
+ # weights
1806
+
1807
+ sw1 = obj_skin_weights[face.a]
1808
+ sw2 = obj_skin_weights[face.b]
1809
+ sw3 = obj_skin_weights[face.c]
1810
+
1811
+ skin_weight_array[offset_skin] = sw1.x
1812
+ skin_weight_array[offset_skin + 1] = sw1.y
1813
+ skin_weight_array[offset_skin + 2] = sw1.z
1814
+ skin_weight_array[offset_skin + 3] = sw1.w
1815
+
1816
+ skin_weight_array[offset_skin + 4] = sw2.x
1817
+ skin_weight_array[offset_skin + 5] = sw2.y
1818
+ skin_weight_array[offset_skin + 6] = sw2.z
1819
+ skin_weight_array[offset_skin + 7] = sw2.w
1820
+
1821
+ skin_weight_array[offset_skin + 8] = sw3.x
1822
+ skin_weight_array[offset_skin + 9] = sw3.y
1823
+ skin_weight_array[offset_skin + 10] = sw3.z
1824
+ skin_weight_array[offset_skin + 11] = sw3.w
1825
+
1826
+ # indices
1827
+
1828
+ si1 = obj_skin_indices[face.a]
1829
+ si2 = obj_skin_indices[face.b]
1830
+ si3 = obj_skin_indices[face.c]
1831
+
1832
+ skin_indices_array[offset_skin] = si1.x
1833
+ skin_indices_array[offset_skin + 1] = si1.y
1834
+ skin_indices_array[offset_skin + 2] = si1.z
1835
+ skin_indices_array[offset_skin + 3] = si1.w
1836
+
1837
+ skin_indices_array[offset_skin + 4] = si2.x
1838
+ skin_indices_array[offset_skin + 5] = si2.y
1839
+ skin_indices_array[offset_skin + 6] = si2.z
1840
+ skin_indices_array[offset_skin + 7] = si2.w
1841
+
1842
+ skin_indices_array[offset_skin + 8] = si3.x
1843
+ skin_indices_array[offset_skin + 9] = si3.y
1844
+ skin_indices_array[offset_skin + 10] = si3.z
1845
+ skin_indices_array[offset_skin + 11] = si3.w
1846
+
1847
+ offset_skin += 12
1848
+ end
1849
+
1850
+ if offset_skin > 0
1851
+ glBindBuffer(GL_ARRAY_BUFFER, geometry_group[:_opengl_skin_indices_buffer])
1852
+ glBufferData_easy(GL_ARRAY_BUFFER, skin_index_array, hint)
1853
+
1854
+ glBindBuffer(GL_ARRAY_BUFFER, geometry_group[:_opengl_skin_weights_buffer])
1855
+ glBufferData_easy(GL_ARRAY_BUFFER, skin_weight_array, hint)
1856
+ end
1857
+ end
1858
+
1859
+ if dirty_colors
1860
+ chunk_faces3.each do |chf|
1861
+ face = obj_faces[chf]
1862
+
1863
+ vertex_colors = face.vertex_colors
1864
+ face_color = face.color
1865
+
1866
+ if vertex_colors.length == 3 && material.vertex_colors == VertexColors
1867
+ c1 = vertex_colors[0]
1868
+ c2 = vertex_colors[1]
1869
+ c3 = vertex_colors[2]
1870
+ else
1871
+ c1 = face_color
1872
+ c2 = face_color
1873
+ c3 = face_color
1874
+ end
1875
+
1876
+ color_array[offset_color] = c1.r
1877
+ color_array[offset_color + 1] = c1.g
1878
+ color_array[offset_color + 2] = c1.b
1879
+
1880
+ color_array[offset_color + 3] = c2.r
1881
+ color_array[offset_color + 4] = c2.g
1882
+ color_array[offset_color + 5] = c2.b
1883
+
1884
+ color_array[offset_color + 6] = c3.r
1885
+ color_array[offset_color + 7] = c3.g
1886
+ color_array[offset_color + 8] = c3.b
1887
+
1888
+ offset_color += 9
1889
+ end
1890
+
1891
+ if offset_color > 0
1892
+ glBindBuffer(GL_ARRAY_BUFFER, geometry_group[:_opengl_color_buffer])
1893
+ glBufferData_easy(GL_ARRAY_BUFFER, color_array, hint)
1894
+ end
1895
+ end
1896
+
1897
+ if dirty_tangents && geometry.has_tangents
1898
+ chunk_faces3.each do |chf|
1899
+ face = obj_faces[chf]
1900
+
1901
+ vertex_tangents = face.vertex_tangents
1902
+
1903
+ t1 = vertex_tangents[0]
1904
+ t2 = vertex_tangents[1]
1905
+ t3 = vertex_tangents[2]
1906
+
1907
+ tangent_array[offset_tangent] = t1.x
1908
+ tangent_array[offset_tangent + 1] = t1.y
1909
+ tangent_array[offset_tangent + 2] = t1.z
1910
+ tangent_array[offset_tangent + 3] = t1.w
1911
+
1912
+ tangent_array[offset_tangent + 4] = t2.x
1913
+ tangent_array[offset_tangent + 5] = t2.y
1914
+ tangent_array[offset_tangent + 6] = t2.z
1915
+ tangent_array[offset_tangent + 7] = t2.w
1916
+
1917
+ tangent_array[offset_tangent + 8] = t3.x
1918
+ tangent_array[offset_tangent + 9] = t3.y
1919
+ tangent_array[offset_tangent + 10] = t3.z
1920
+ tangent_array[offset_tangent + 11] = t3.w
1921
+
1922
+ offset_tangent += 12
1923
+ end
1924
+
1925
+ glBindBuffer(GL_ARRAY_BUFFER, geometry_group[:_opengl_tangent_buffer])
1926
+ glBufferData_easy(GL_ARRAY_BUFFER, tangent_array, hint)
1927
+ end
1928
+
1929
+ if dirty_normals
1930
+ chunk_faces3.each do |chf|
1931
+ face = obj_faces[chf]
1932
+
1933
+ vertex_normals = face.vertex_normals
1934
+ face_normal = face.normal
1935
+
1936
+ if vertex_normals.length == 3 && !needs_face_normals
1937
+ 3.times do |i|
1938
+ vn = vertex_normals[i]
1939
+
1940
+ normal_array[offset_normal] = vn.x
1941
+ normal_array[offset_normal + 1] = vn.y
1942
+ normal_array[offset_normal + 2] = vn.z
1943
+
1944
+ offset_normal += 3
1945
+ end
1946
+ else
1947
+ 3.times do |i|
1948
+ normal_array[offset_normal] = face_normal.x
1949
+ normal_array[offset_normal + 1] = face_normal.y
1950
+ normal_array[offset_normal + 2] = face_normal.z
1951
+
1952
+ offset_normal += 3
1953
+ end
1954
+ end
1955
+ end
1956
+
1957
+ glBindBuffer(GL_ARRAY_BUFFER, geometry_group[:_opengl_normal_buffer])
1958
+ glBufferData_easy(GL_ARRAY_BUFFER, normal_array, hint)
1959
+ end
1960
+
1961
+ if dirty_uvs && obj_uvs
1962
+ chunk_faces3.each do |fi|
1963
+ uv = obj_uvs[fi]
1964
+
1965
+ next if uv.nil?
1966
+
1967
+ 3.times do |i|
1968
+ uvi = uv[i]
1969
+
1970
+ uv_array[offset_uv] = uvi.x
1971
+ uv_array[offset_uv + 1] = uvi.y
1972
+
1973
+ offset_uv += 2
1974
+ end
1975
+ end
1976
+
1977
+ if offset_uv > 0
1978
+ glBindBuffer(GL_ARRAY_BUFFER, geometry_group[:_opengl_uv_buffer])
1979
+ glBufferData_easy(GL_ARRAY_BUFFER, uv_array, hint)
1980
+ end
1981
+ end
1982
+
1983
+ if dirty_uvs && obj_uvs2
1984
+ chunk_faces3.each do |fi|
1985
+ uv2 = obj_uvs2[fi]
1986
+
1987
+ next if uv2.nil?
1988
+
1989
+ 3.times do |i|
1990
+ uv2i = uv2[i]
1991
+
1992
+ uv2_array[offset_uv2] = uv2i.x
1993
+ uv2_array[offset_uv2 + 1] = uv2i.y
1994
+
1995
+ offset_uv2 += 2
1996
+ end
1997
+ end
1998
+
1999
+ if offset_uv2 > 0
2000
+ glBindBuffer(GL_ARRAY_BUFFER, geometry_group[:_opengl_uv2_buffer])
2001
+ glBufferData_easy(GL_ARRAY_BUFFER, uv2_array, hint)
2002
+ end
2003
+ end
2004
+
2005
+ if dirty_elements
2006
+ chunk_faces3.each do |chf|
2007
+ face_array[offset_face] = vertex_index
2008
+ face_array[offset_face + 1] = vertex_index + 1
2009
+ face_array[offset_face + 2] = vertex_index + 2
2010
+
2011
+ offset_face += 3
2012
+
2013
+ line_array[offset_line] = vertex_index
2014
+ line_array[offset_line + 1] = vertex_index + 1
2015
+
2016
+ line_array[offset_line + 2] = vertex_index
2017
+ line_array[offset_line + 3] = vertex_index + 2
2018
+
2019
+ line_array[offset_line + 4] = vertex_index + 1
2020
+ line_array[offset_line + 5] = vertex_index + 2
2021
+
2022
+ offset_line += 6
2023
+
2024
+ vertex_index += 3
2025
+ end
2026
+
2027
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geometry_group[:_opengl_face_buffer])
2028
+ glBufferData_easy(GL_ELEMENT_ARRAY_BUFFER, face_array, hint)
2029
+
2030
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geometry_group[:_opengl_line_buffer])
2031
+ glBufferData_easy(GL_ELEMENT_ARRAY_BUFFER, line_array, hint)
2032
+ end
2033
+
2034
+ if custom_attributes
2035
+ custom_attributes.each do |custom_attribute|
2036
+ next if !custom_attribute[:_original][:needs_update]
2037
+
2038
+ offset_custom = 0
2039
+
2040
+ if custom_attribute[:size] == 1
2041
+ if custom_attribute[:bound_to].nil? || custom_attribute[:bound_to] == :vertices
2042
+ chunk_faces3.each do |chf|
2043
+ face = obj_faces[chf]
2044
+
2045
+ custom_attribute[:array][offset_custom] = custom_attribute[:value][face.a]
2046
+ custom_attribute[:array][offset_custom + 1] = custom_attribute[:value][face.b]
2047
+ custom_attribute[:array][offset_custom + 2] = custom_attribute[:value][face.c]
2048
+
2049
+ offset_custom += 3
2050
+ end
2051
+ elsif custom_attribute[:bound_to] == :faces
2052
+ value = custom_attribute[:value][chf]
2053
+
2054
+ custom_attribute[:array][offset_custom] = value
2055
+ custom_attribute[:array][offset_custom + 1] = value
2056
+ custom_attribute[:array][offset_custom + 2] = value
2057
+
2058
+ offset_custom += 3
2059
+ end
2060
+ elsif custom_attribute[:size] == 2
2061
+ if custom_attribute[:bound_to].nil? || custom_attribute[:bound_to] == :vertices
2062
+ chunk_faces3.each do |chf|
2063
+ face = obj_faces[chf]
2064
+
2065
+ v1 = custom_attribute[:value][face.a]
2066
+ v2 = custom_attribute[:value][face.b]
2067
+ v3 = custom_attribute[:value][face.c]
2068
+
2069
+ custom_attribute[:array][offset_custom] = v1.x
2070
+ custom_attribute[:array][offset_custom + 1] = v1.y
2071
+
2072
+ custom_attribute[:array][offset_custom + 2] = v2.x
2073
+ custom_attribute[:array][offset_custom + 3] = v2.y
2074
+
2075
+ custom_attribute[:array][offset_custom + 4] = v3.x
2076
+ custom_attribute[:array][offset_custom + 5] = v3.y
2077
+
2078
+ offset_custom += 6
2079
+ end
2080
+ elsif custom_attribute[:bound_to] == :faces
2081
+ chunk_faces3.each do |chf|
2082
+ value = custom_attribute[:value][chf]
2083
+
2084
+ v1 = value
2085
+ v2 = value
2086
+ v3 = value
2087
+
2088
+ custom_attribute[:array][offset_custom] = v1.x
2089
+ custom_attribute[:array][offset_custom + 1] = v1.y
2090
+
2091
+ custom_attribute[:array][offset_custom + 2] = v2.x
2092
+ custom_attribute[:array][offset_custom + 3] = v2.y
2093
+
2094
+ custom_attribute[:array][offset_custom + 4] = v3.x
2095
+ custom_attribute[:array][offset_custom + 5] = v3.y
2096
+
2097
+ offset_custom += 6
2098
+ end
2099
+ end
2100
+ elsif custom_attribute[:size] == 3
2101
+ if custom_attribute[:bound_to].nil? || custom_attribute[:bound_to] == :vertices
2102
+ chunk_faces3.each do |chf|
2103
+ face = obj_faces[chf];
2104
+
2105
+ v1 = custom_attribute[:value][face.a]
2106
+ v2 = custom_attribute[:value][face.b]
2107
+ v3 = custom_attribute[:value][face.c]
2108
+
2109
+ custom_attribute[:array][offset_custom] = v1[0]
2110
+ custom_attribute[:array][offset_custom + 1] = v1[1]
2111
+ custom_attribute[:array][offset_custom + 2] = v1[2]
2112
+
2113
+ custom_attribute[:array][offset_custom + 3] = v2[0]
2114
+ custom_attribute[:array][offset_custom + 4] = v2[1]
2115
+ custom_attribute[:array][offset_custom + 5] = v2[2]
2116
+
2117
+ custom_attribute[:array][offset_custom + 6] = v3[0]
2118
+ custom_attribute[:array][offset_custom + 7] = v3[1]
2119
+ custom_attribute[:array][offset_custom + 8] = v3[2]
2120
+
2121
+ offset_custom += 9
2122
+ end
2123
+ elsif custom_attribute[:bound_to] == :faces
2124
+ chunk_faces3.each do |chf|
2125
+ value = custom_attribute[:value][chf]
2126
+
2127
+ v1 = value
2128
+ v2 = value
2129
+ v3 = value
2130
+
2131
+ custom_attribute[:array][offset_custom] = v1[0]
2132
+ custom_attribute[:array][offset_custom + 1] = v1[1]
2133
+ custom_attribute[:array][offset_custom + 2] = v1[2]
2134
+
2135
+ custom_attribute[:array][offset_custom + 3] = v2[0]
2136
+ custom_attribute[:array][offset_custom + 4] = v2[1]
2137
+ custom_attribute[:array][offset_custom + 5] = v2[2]
2138
+
2139
+ custom_attribute[:array][offset_custom + 6] = v3[0]
2140
+ custom_attribute[:array][offset_custom + 7] = v3[1]
2141
+ custom_attribute[:array][offset_custom + 8] = v3[2]
2142
+
2143
+ offset_custom += 9
2144
+ end
2145
+ elsif custom_attribute[:bound_to] == :face_vertices
2146
+ chunk_faces3.each do |chf|
2147
+ value = custom_attribute[:value][chf]
2148
+
2149
+ v1 = value[0]
2150
+ v2 = value[1]
2151
+ v3 = value[2]
2152
+
2153
+ custom_attribute[:array][offset_custom] = v1[0]
2154
+ custom_attribute[:array][offset_custom + 1] = v1[1]
2155
+ custom_attribute[:array][offset_custom + 2] = v1[2]
2156
+
2157
+ custom_attribute[:array][offset_custom + 3] = v2[0]
2158
+ custom_attribute[:array][offset_custom + 4] = v2[1]
2159
+ custom_attribute[:array][offset_custom + 5] = v2[2]
2160
+
2161
+ custom_attribute[:array][offset_custom + 6] = v3[0]
2162
+ custom_attribute[:array][offset_custom + 7] = v3[1]
2163
+ custom_attribute[:array][offset_custom + 8] = v3[2]
2164
+
2165
+ offset_custom += 9
2166
+ end
2167
+ end
2168
+ elsif custom_attribute[:size] == 4
2169
+ if custom_attribute[:bound_to].nil? || custom_attribute[:bound_to] == :vertices
2170
+ chunk_faces3.each do |chf|
2171
+ face = obj_faces[chf]
2172
+
2173
+ v1 = custom_attribute[:value][face.a]
2174
+ v2 = custom_attribute[:value][face.b]
2175
+ v3 = custom_attribute[:value][face.c]
2176
+
2177
+ customAttribute.array[offset_custom] = v1.x
2178
+ customAttribute.array[offset_custom + 1 ] = v1.y
2179
+ customAttribute.array[offset_custom + 2 ] = v1.z
2180
+ customAttribute.array[offset_custom + 3 ] = v1.w
2181
+
2182
+ customAttribute.array[offset_custom + 4 ] = v2.x
2183
+ customAttribute.array[offset_custom + 5 ] = v2.y
2184
+ customAttribute.array[offset_custom + 6 ] = v2.z
2185
+ customAttribute.array[offset_custom + 7 ] = v2.w
2186
+
2187
+ customAttribute.array[offset_custom + 8 ] = v3.x
2188
+ customAttribute.array[offset_custom + 9 ] = v3.y
2189
+ customAttribute.array[offset_custom + 10] = v3.z
2190
+ customAttribute.array[offset_custom + 11] = v3.w
2191
+
2192
+ offset_custom += 12
2193
+ end
2194
+ elsif custom_attribute[:bound_to] == :faces
2195
+ chunk_faces3.each do |chf|
2196
+ value = custom_attribute[:value][chf]
2197
+
2198
+ v1 = value
2199
+ v2 = value
2200
+ v3 = value
2201
+
2202
+ customAttribute.array[offset_custom] = v1.x
2203
+ customAttribute.array[offset_custom + 1 ] = v1.y
2204
+ customAttribute.array[offset_custom + 2 ] = v1.z
2205
+ customAttribute.array[offset_custom + 3 ] = v1.w
2206
+
2207
+ customAttribute.array[offset_custom + 4 ] = v2.x
2208
+ customAttribute.array[offset_custom + 5 ] = v2.y
2209
+ customAttribute.array[offset_custom + 6 ] = v2.z
2210
+ customAttribute.array[offset_custom + 7 ] = v2.w
2211
+
2212
+ customAttribute.array[offset_custom + 8 ] = v3.x
2213
+ customAttribute.array[offset_custom + 9 ] = v3.y
2214
+ customAttribute.array[offset_custom + 10] = v3.z
2215
+ customAttribute.array[offset_custom + 11] = v3.w
2216
+
2217
+ offset_custom += 12
2218
+ end
2219
+ elsif custom_attribute[:bound_to] == :face_vertices
2220
+ chunk_faces3.each do |chf|
2221
+ value = custom_attribute[:value][chf]
2222
+
2223
+ v1 = value[0]
2224
+ v2 = value[1]
2225
+ v3 = value[2]
2226
+
2227
+ customAttribute.array[offset_custom] = v1.x
2228
+ customAttribute.array[offset_custom + 1 ] = v1.y
2229
+ customAttribute.array[offset_custom + 2 ] = v1.z
2230
+ customAttribute.array[offset_custom + 3 ] = v1.w
2231
+
2232
+ customAttribute.array[offset_custom + 4 ] = v2.x
2233
+ customAttribute.array[offset_custom + 5 ] = v2.y
2234
+ customAttribute.array[offset_custom + 6 ] = v2.z
2235
+ customAttribute.array[offset_custom + 7 ] = v2.w
2236
+
2237
+ customAttribute.array[offset_custom + 8 ] = v3.x
2238
+ customAttribute.array[offset_custom + 9 ] = v3.y
2239
+ customAttribute.array[offset_custom + 10] = v3.z
2240
+ customAttribute.array[offset_custom + 11] = v3.w
2241
+
2242
+ offset_custom += 12
2243
+ end
2244
+ end
2245
+ end
2246
+
2247
+ glBindBuffer(GL_ARRAY_BUFFER, custom_attribute[:buffer])
2248
+ glBufferData_easy(GL_ARRAY_BUFFER, custom_attribute[:array], hint)
2249
+ end
2250
+ end
2251
+
2252
+ if dispose
2253
+ geometry_group.delete(:_initted_arrays)
2254
+ geometry_group.delete(:_color_array)
2255
+ geometry_group.delete(:_normal_array)
2256
+ geometry_group.delete(:_tangent_array)
2257
+ geometry_group.delete(:_uv_array)
2258
+ geometry_group.delete(:_uv2_array)
2259
+ geometry_group.delete(:_face_array)
2260
+ geometry_group.delete(:_vertex_array)
2261
+ geometry_group.delete(:_line_array)
2262
+ geometry_group.delete(:_skin_index_array)
2263
+ geometry_group.delete(:_skin_weight_array)
2264
+ end
2265
+ end
2266
+
2267
+ def material_needs_face_normals(material)
2268
+ !material.is_a?(MeshPhongMaterial) && material.shading == FlatShading
2269
+ end
2270
+
2271
+ def set_program(camera, lights, fog, material, object)
2272
+ @_used_texture_units = 0
2273
+
2274
+ if material.needs_update?
2275
+ deallocate_material(material) if material.program
2276
+
2277
+ init_material(material, lights, fog, object)
2278
+ material.needs_update = false
2279
+ end
2280
+
2281
+ if material.morph_targets
2282
+ if !object[:_opengl_morph_target_influences]
2283
+ object[:_opengl_morph_target_influences] = Array.new(@max_morph_targets) # Float32Array
2284
+ end
2285
+ end
2286
+
2287
+ refresh_program = false
2288
+ refresh_material = false
2289
+ refresh_lights = false
2290
+
2291
+ program = material.program
2292
+ p_uniforms = program.uniforms
2293
+ m_uniforms = material[:_opengl_shader][:uniforms]
2294
+
2295
+ if program.id != @_current_program
2296
+ glUseProgram(program.program)
2297
+ @_current_program = program.id
2298
+
2299
+ refresh_program = true
2300
+ refresh_material = true
2301
+ refresh_lights = true
2302
+ end
2303
+
2304
+ if material.id != @_current_material_id
2305
+ refresh_lights = true if @_current_material_id == -1
2306
+ @_current_material_id = material.id
2307
+
2308
+ refresh_material = true
2309
+ end
2310
+
2311
+ if refresh_program || camera != @_current_camera
2312
+ glUniformMatrix4fv(p_uniforms['projectionMatrix'], 1, GL_FALSE, array_to_ptr_easy(camera.projection_matrix.elements))
2313
+
2314
+ if @_logarithmic_depth_buffer
2315
+ glUniform1f(p_uniforms['logDepthBuffFC'], 2.0 / Math.log(camera.far + 1.0) / Math::LN2)
2316
+ end
2317
+
2318
+ @_current_camera = camera if camera != @_current_camera
2319
+
2320
+ # load material specific uniforms
2321
+ # (shader material also gets them for the sake of genericity)
2322
+
2323
+ if material.is_a?(ShaderMaterial) || material.is_a?(MeshPhongMaterial) || material.env_map
2324
+ if !p_uniforms['cameraPosition'].nil?
2325
+ @_vector3.set_from_matrix_position(camera.matrix_world)
2326
+ glUniform3f(p_uniforms['cameraPosition'], @_vector3.x, @_vector3.y, @_vector3.z)
2327
+ end
2328
+ end
2329
+
2330
+ if material.is_a?(MeshPhongMaterial) || material.is_a?(MeshLambertMaterial) || material.is_a?(MeshBasicMaterial) || material.is_a?(ShaderMaterial) || material.skinning
2331
+ if !p_uniforms['viewMatrix'].nil?
2332
+ glUniformMatrix4fv(p_uniforms['viewMatrix'], 1, GL_FALSE, array_to_ptr_easy(camera.matrix_world_inverse.elements))
2333
+ end
2334
+ end
2335
+ end
2336
+
2337
+ if material.skinning
2338
+ if object.bind_matrix && !p_uniforms.bind_matrix.nil?
2339
+ glUniformMatrix4fv(p_uniforms.bind_matrix, GL_FALSE, object.bind_matrix.elements)
2340
+ end
2341
+
2342
+ if object.bind_matrix_inverse && !p_uniforms.bind_matrix_inverse.nil?
2343
+ glUniformMatrix4fv(p_uniforms.bind_matrix_inverse, GL_FALSE, object.bind_matrix_inverse.elements)
2344
+ end
2345
+
2346
+ if _supports_bone_textures && object.skeleton && object.skeleton.use_vertex_texture
2347
+ if !p_uniforms.bone_texture.nil?
2348
+ texture_unit = get_texture_unit
2349
+
2350
+ glUniform1i(p_uniforms.bone_texture, texture_unit)
2351
+ self.set_texture(object.skeleton.bone_texture, texture_unit)
2352
+ end
2353
+
2354
+ if !p_uniforms.bone_texture_width.nil?
2355
+ glUniform1i(p_uniforms.bone_texture_width, object.skeleton.bone_texture_width)
2356
+ end
2357
+
2358
+ if !p_uniforms.bone_texture_height.nil?
2359
+ glUniform1i(p_uniforms.bone_texture_height, object.skeleton.bone_texture_height)
2360
+ end
2361
+ elsif object.skeleton && object.skeleton.bone_matrices
2362
+ if !p_uniforms.bone_global_matrices.nil?
2363
+ glUniformMatrix4fv(p_uniforms.bone_global_matrices, GL_FALSE, object.skeleton.bone_matrices)
2364
+ end
2365
+ end
2366
+ end
2367
+
2368
+ if refresh_material
2369
+ if fog && material.fog
2370
+ end
2371
+
2372
+ if material.is_a?(MeshPhongMaterial) || material.is_a?(MeshLambertMaterial) || material.lights
2373
+ if @_lights_need_update
2374
+ refresh_lights = true
2375
+ setup_lights(lights)
2376
+ @_lights_need_update = false
2377
+ end
2378
+
2379
+ if refresh_lights
2380
+ refresh_uniforms_lights(m_uniforms, @_lights)
2381
+ mark_uniforms_lights_needs_update(m_uniforms, true)
2382
+ else
2383
+ mark_uniforms_lights_needs_update(m_uniforms, false)
2384
+ end
2385
+ end
2386
+
2387
+ if material.is_a?(MeshBasicMaterial) || material.is_a?(MeshLambertMaterial) || material.is_a?(MeshPhongMaterial)
2388
+ refresh_uniforms_common(m_uniforms, material)
2389
+ end
2390
+
2391
+ # refresh single material specific uniforms
2392
+
2393
+ # TODO: when all of these things exist
2394
+ case material
2395
+ when LineBasicMaterial
2396
+ refresh_uniforms_line(m_uniforms, material)
2397
+ # when LineDashedMaterial
2398
+ # refresh_uniforms_line(m_uniforms, material)
2399
+ # refresh_uniforms_dash(m_uniforms, material)
2400
+ # when PointCloudMaterial
2401
+ # refresh_uniforms_particle(m_uniforms, material)
2402
+ when MeshPhongMaterial
2403
+ refresh_uniforms_phong(m_uniforms, material)
2404
+ when MeshLambertMaterial
2405
+ refresh_uniforms_lambert(m_uniforms, material)
2406
+ # when MeshDepthMaterial
2407
+ # m_uniforms.m_near.value = camera.near
2408
+ # m_uniforms.m_far.value = camera.far
2409
+ # m_uniforms.opacity.value = material.opacity
2410
+ # when MeshNormalMaterial
2411
+ # m_uniforms.opactity.value = material.opacity
2412
+ end
2413
+
2414
+ if object.receive_shadow && !material[:_shadow_pass]
2415
+ refresh_uniforms_shadow(m_uniforms, lights)
2416
+ end
2417
+
2418
+ # load common uniforms
2419
+
2420
+ load_uniforms_generic(material[:uniforms_list])
2421
+ end
2422
+
2423
+ load_uniforms_matrices(p_uniforms, object)
2424
+
2425
+ if !p_uniforms['modelMatrix'].nil?
2426
+ glUniformMatrix4fv(p_uniforms['modelMatrix'], 1, GL_FALSE, array_to_ptr_easy(object.matrix_world.elements))
2427
+ end
2428
+
2429
+ program
2430
+ end
2431
+
2432
+ def init_material(material, lights, fog, object)
2433
+ material.add_event_listener(:dispose, @on_material_dispose)
2434
+
2435
+ shader_id = @shader_ids[material.class]
2436
+
2437
+ if shader_id
2438
+ shader = ShaderLib[shader_id]
2439
+ material[:_opengl_shader] = {
2440
+ uniforms: UniformsUtils.clone(shader.uniforms),
2441
+ vertex_shader: shader.vertex_shader,
2442
+ fragment_shader: shader.fragment_shader
2443
+ }
2444
+ else
2445
+ material[:_opengl_shader] = {
2446
+ uniforms: material.uniforms,
2447
+ vertex_shader: material.vertex_shader,
2448
+ fragment_shader: material.fragment_shader
2449
+ }
2450
+ end
2451
+
2452
+ # heuristics to create shader paramaters ccording to lights in the scene
2453
+ # (not to blow over max_lights budget)
2454
+
2455
+ max_light_count = allocate_lights(lights)
2456
+ max_shadows = allocate_shadows(lights)
2457
+ max_bones = allocate_bones(object)
2458
+
2459
+ parameters = {
2460
+ precision: @_precision,
2461
+ supports_vertex_textures: @_supports_vertex_textures,
2462
+
2463
+ map: !!material.map,
2464
+ env_map: !!material.env_map,
2465
+ env_map_mode: material.env_map && material.env_map.mapping,
2466
+ light_map: !!material.light_map,
2467
+ bump_map: !!material.light_map,
2468
+ normal_map: !!material.normal_map,
2469
+ specular_map: !!material.specular_map,
2470
+ alpha_map: !!material.alpha_map,
2471
+
2472
+ combine: material.combine,
2473
+
2474
+ vertex_colors: material.vertex_colors,
2475
+
2476
+ fog: fog,
2477
+ use_fog: material.fog,
2478
+ # fog_exp: fog.is_a?(FogExp2), # TODO: when FogExp2 exists
2479
+
2480
+ flat_shading: material.shading == FlatShading,
2481
+
2482
+ size_attenuation: material.size_attenuation,
2483
+ logarithmic_depth_buffer: @_logarithmic_depth_buffer,
2484
+
2485
+ skinning: material.skinning,
2486
+ max_bones: max_bones,
2487
+ use_vertex_texture: @_supports_bone_textures,
2488
+
2489
+ morph_targets: material.morph_targets,
2490
+ morph_normals: material.morph_normals,
2491
+ max_morph_targets: @max_morph_targets,
2492
+ max_morph_normals: @max_morph_normals,
2493
+
2494
+ max_dir_lights: max_light_count[:directional],
2495
+ max_point_lights: max_light_count[:point],
2496
+ max_spot_lights: max_light_count[:spot],
2497
+ max_hemi_lights: max_light_count[:hemi],
2498
+
2499
+ max_shadows: max_shadows,
2500
+ shadow_map_enabled: @shadow_map_enabled && object.receive_shadow && max_shadows > 0,
2501
+ shadow_map_type: @shadow_map_type,
2502
+ shadow_map_debug: @shadow_map_debug,
2503
+ shadow_map_cascade: @shadow_map_cascade,
2504
+
2505
+ alpha_test: material.alpha_test,
2506
+ metal: material.metal,
2507
+ wrap_around: material.wrap_around,
2508
+ double_sided: material.side == DoubleSide,
2509
+ flip_sided: material.side == BackSide
2510
+ }
2511
+
2512
+ # generate code
2513
+
2514
+ chunks = []
2515
+
2516
+ if shader_id
2517
+ chunks << shader_id
2518
+ else
2519
+ chunks << material.fragment_shader
2520
+ chunks << material.vertex_shader
2521
+ end
2522
+
2523
+ if !material.defines.nil?
2524
+ material.defines.each do |(name, define)|
2525
+ chunks << name
2526
+ chunks << define
2527
+ end
2528
+ end
2529
+
2530
+ parameters.each do |(name, parameter)|
2531
+ chunks << name
2532
+ chunks << parameter
2533
+ end
2534
+
2535
+ code = chunks.join
2536
+
2537
+ program = nil
2538
+
2539
+ # check if code has been already compiled
2540
+
2541
+ @_programs.each do |program_info|
2542
+ if program_info.code == code
2543
+ program = program_info
2544
+ program.used_times += 1
2545
+ break
2546
+ end
2547
+ end
2548
+
2549
+ if program.nil?
2550
+ program = OpenGLProgram.new(self, code, material, parameters)
2551
+ @_programs.push(program)
2552
+
2553
+ @info[:memory][:programs] = @_programs.length
2554
+ end
2555
+
2556
+ material.program = program
2557
+
2558
+ attributes = program.attributes
2559
+
2560
+ if material.morph_targets
2561
+ material.num_supported_morph_targets = 0
2562
+ base = 'morphTarget'
2563
+
2564
+ @max_morph_targets.times do |i|
2565
+ id = base + i
2566
+ if attributes[id] >= 0
2567
+ material.num_supported_morph_targets += 1
2568
+ end
2569
+ end
2570
+ end
2571
+
2572
+ if material.morph_normals
2573
+ material.num_supported_morph_normals = 0
2574
+ base = 'morphNormal'
2575
+
2576
+ @max_morph_normals.times do |i|
2577
+ id = base + i
2578
+ if attributes[id] >= 0
2579
+ material.num_supported_morph_normals += 1
2580
+ end
2581
+ end
2582
+ end
2583
+
2584
+ material[:uniforms_list] = []
2585
+
2586
+ material[:_opengl_shader][:uniforms].each_key do |u|
2587
+ location = material.program.uniforms[u]
2588
+
2589
+ if location
2590
+ material[:uniforms_list] << [material[:_opengl_shader][:uniforms][u], location]
2591
+ end
2592
+ end
2593
+ end
2594
+
2595
+ def allocate_lights(lights)
2596
+ dir_lights = 0
2597
+ point_lights = 0
2598
+ spot_lights = 0
2599
+ hemi_lights = 0
2600
+
2601
+ lights.each do |light|
2602
+ next if light.only_shadow || !light.visible
2603
+
2604
+ dir_lights += 1 if light.is_a? DirectionalLight
2605
+ point_lights += 1 if light.is_a? PointLight
2606
+ spot_lights += 1 if light.is_a? SpotLight
2607
+ hemi_lights += 1 if light.is_a? HemisphereLight
2608
+ end
2609
+
2610
+ {
2611
+ directional: dir_lights,
2612
+ point: point_lights,
2613
+ spot: spot_lights,
2614
+ hemi: hemi_lights
2615
+ }
2616
+ end
2617
+
2618
+ def allocate_shadows(lights)
2619
+ max_shadows = 0
2620
+
2621
+ lights.each do |light|
2622
+ next unless light.cast_shadow
2623
+
2624
+ max_shadows += 1 if light.is_a?(SpotLight)
2625
+ max_shadows += 1 if light.is_a?(DirectionalLight) && !light.shadow_cascade
2626
+ end
2627
+
2628
+ max_shadows
2629
+ end
2630
+
2631
+ def allocate_bones(object = nil)
2632
+ if @_supports_bone_textures && object && object.skeleton && object.skeleton.use_vertex_texture
2633
+ return 1024
2634
+ end
2635
+
2636
+ # default for when object is not specified
2637
+ # ( for example when prebuilding shader
2638
+ # to be used with multiple objects )
2639
+ #
2640
+ # - leave some extra space for other uniforms
2641
+ # - limit here is ANGLE's 254 max uniform vectors
2642
+ # (up to 54 should be safe)
2643
+
2644
+ n_vertex_uniforms = (get_gl_parameter(GL_MAX_VERTEX_UNIFORM_COMPONENTS) / 4.0).floor
2645
+ n_vertex_matrices = ((n_vertex_uniforms - 20) / 4.0).floor
2646
+
2647
+ max_bones = n_vertex_matrices
2648
+
2649
+ # TODO: when SkinnedMesh exists
2650
+ # if !object.nil? && object.is_a?(SkinnedMesh)
2651
+ # max_bones = [object.skeleton.bones.length, max_bones].min
2652
+ #
2653
+ # if max_bones < object.skeleton.bones.length
2654
+ # puts "WARNING: OpenGLRenderer: too many bones - #{object.skeleton.bones.length}, this GPU supports just #{max_bones}"
2655
+ # end
2656
+ # end
2657
+
2658
+ max_bones
2659
+ end
2660
+
2661
+ def refresh_uniforms_common(uniforms, material)
2662
+
2663
+ uniforms['opacity'].value = material.opacity
2664
+
2665
+ uniforms['diffuse'].value = material.color
2666
+
2667
+ uniforms['map'].value = material.map
2668
+ uniforms['lightMap'].value = material.light_map
2669
+ uniforms['specularMap'].value = material.specular_map
2670
+ uniforms['alphaMap'].value = material.alpha_map
2671
+
2672
+ if material.bump_map
2673
+ uniforms['bumpMap'].value = material.bump_map
2674
+ uniforms['bumpScale'].value = material.bump_scale
2675
+ end
2676
+
2677
+ if material.normal_map
2678
+ uniforms['normalMap'].value = material.normal_map
2679
+ uniforms['normalScale'].value.copy( material.normal_scale )
2680
+ end
2681
+
2682
+ # uv repeat and offset setting priorities
2683
+ # 1. color map
2684
+ # 2. specular map
2685
+ # 3. normal map
2686
+ # 4. bump map
2687
+ # 5. alpha map
2688
+
2689
+ uv_scale_map = nil
2690
+
2691
+ if material.map
2692
+ uv_scale_map = material.map
2693
+ elsif material.specular_map
2694
+ uv_scale_map = material.specular_map
2695
+ elsif material.normal_map
2696
+ uv_scale_map = material.normal_map
2697
+ elsif material.bump_map
2698
+ uv_scale_map = material.bump_map
2699
+ elsif material.alpha_map
2700
+ uv_scale_map = material.alpha_map
2701
+ end
2702
+
2703
+ if !uv_scale_map.nil?
2704
+ offset = uv_scale_map.offset
2705
+ repeat = uv_scale_map.repeat
2706
+
2707
+ uniforms['offsetRepeat'].value.set(offset.x, offset.y, repeat.x, repeat.y)
2708
+ end
2709
+
2710
+ uniforms['envMap'].value = material.env_map
2711
+ # TODO: when OpenGLRenderTargetCube exists
2712
+ # uniforms['flipEnvMap'].value = material.envMap.is_a?(OpenGLRenderTargetCube) ? 1 : - 1
2713
+
2714
+ uniforms['reflectivity'].value = material.reflectivity
2715
+ uniforms['refractionRatio'].value = material.refraction_ratio
2716
+ end
2717
+
2718
+ def refresh_uniforms_phong(uniforms, material)
2719
+ uniforms['shininess'].value = material.shininess
2720
+
2721
+ uniforms['emissive'].value = material.emissive
2722
+ uniforms['specular'].value = material.specular
2723
+
2724
+ if material.wrap_around
2725
+ uniforms['wrapRGB'].value.copy(material.wrap_rgb)
2726
+ end
2727
+ end
2728
+
2729
+ def refresh_uniforms_shadow(uniforms, lights)
2730
+ if uniforms['shadowMatrix']
2731
+ lights.select(&:cast_shadow).select { |light|
2732
+ light.is_a?(SpotLight) || (light.is_a?(DirectionalLight) && !light.shadow_cascade)
2733
+ }.each_with_index { |light, i|
2734
+ uniforms['shadowMap'].value[i] = light.shadow_map
2735
+ uniforms['shadowMapSize'].value[i] = light.shadow_map_size
2736
+
2737
+ uniforms['shadowMatrix'].value[i] = light.shadow_matrix
2738
+
2739
+ uniforms['shadowDarkness'].value[i] = light.shadow_darkness
2740
+ uniforms['shadowBias'].value[i] = light.shadow_bias
2741
+ }
2742
+ end
2743
+ end
2744
+
2745
+ def refresh_uniforms_line(uniforms, material)
2746
+ uniforms['diffuse'].value = material.color
2747
+ uniforms['opacity'].value = material.opacity
2748
+ end
2749
+
2750
+ def load_uniforms_generic(uniforms)
2751
+ uniforms.each do |(uniform, location)|
2752
+ # needs_update property is not added to all uniforms.
2753
+ next if uniform.needs_update == false || location == -1
2754
+
2755
+ type = uniform.type
2756
+ value = uniform.value
2757
+
2758
+ case type
2759
+ when :'1i'
2760
+ glUniform1i(location, value)
2761
+ when :'1f'
2762
+ glUniform1f(location, value)
2763
+ when :'2f'
2764
+ glUniform2f(location, value[0], value[1])
2765
+ when :'3f'
2766
+ glUniform2f(location, value[0], value[1], value[2])
2767
+ when :'4f'
2768
+ glUniform4f(location, value[0], value[1], value[2], value[3])
2769
+ when :'1iv'
2770
+ glUniform1iv(location, value.length, array_to_ptr_easy(value))
2771
+ when :'2iv'
2772
+ glUniform2iv(location, value.length / 2, array_to_ptr_easy(value))
2773
+ when :'3iv'
2774
+ glUniform3iv(location, value.length / 3, array_to_ptr_easy(value))
2775
+ when :'4iv'
2776
+ glUniform3iv(location, value.length / 4, array_to_ptr_easy(value))
2777
+ when :'1fv'
2778
+ glUniform1fv(location, value.length, array_to_ptr_easy(value))
2779
+ when :'2fv'
2780
+ glUniform2fv(location, value.length / 2, array_to_ptr_easy(value))
2781
+ when :'3fv'
2782
+ glUniform3fv(location, value.length / 3, array_to_ptr_easy(value))
2783
+ when :'4fv'
2784
+ glUniform3fv(location, value.length / 4, array_to_ptr_easy(value))
2785
+ when :Matrix3fv
2786
+ glUniformMatrix3fv(location, value / 9, GL_FALSE, array_to_ptr_easy(value))
2787
+ when :Matrix4fv
2788
+ glUniformMatrix4fv(location, value / 16, GL_FALSE, array_to_ptr_easy(value))
2789
+
2790
+ #
2791
+
2792
+ when :i
2793
+ # single integer
2794
+ glUniform1i(location, value)
2795
+ when :f
2796
+ # single float
2797
+ glUniform1f(location, value)
2798
+ when :v2
2799
+ # single Mittsu::Vector2
2800
+ glUniform2f(location, value.x, value.y)
2801
+ when :v3
2802
+ # single Mittsu::Vector3
2803
+ glUniform3f(location, value.x, value.y, value.z)
2804
+ when :v4
2805
+ # single Mittsu::Vector4
2806
+ glUniform4f(location, value.x, value.y, value.z, value.w)
2807
+ when :c
2808
+ # single Mittsu::Color
2809
+ glUniform3f(location, value.r, value.g, value.b)
2810
+ when :iv1
2811
+ # flat array of integers
2812
+ glUniform1iv(location, value.length, array_to_ptr_easy(value))
2813
+ when :iv
2814
+ # flat array of integers with 3 x N size
2815
+ glUniform3iv(location, value.length / 3, array_to_ptr_easy(value))
2816
+ when :fv1
2817
+ # flat array of floats
2818
+ glUniform1fv(location, value.length, array_to_ptr_easy(value))
2819
+ when :fv
2820
+ # flat array of float with 3 x N size
2821
+ glUniform3fv(location, value.length / 3, array_to_ptr_easy(value))
2822
+ when :v2v
2823
+ # array of Mittsu::Vector2
2824
+ uniform[:_array] ||= Array.new(2 * value.length) # Float32Array
2825
+
2826
+ value.each_with_index do |v, i|
2827
+ offset = i * 2
2828
+ uniform[:_array][offset] = v.x
2829
+ uniform[:_array][offset + 1] = v.y
2830
+ end
2831
+
2832
+ glUniform2fv(location, value.length * 2, array_to_ptr_easy(uniform[:_array]))
2833
+ when :v3v
2834
+ # array of Mittsu::Vector3
2835
+ uniform[:_array] ||= Array.new(3 * value.length) # Float32Array
2836
+
2837
+ value.each_with_index do |v, i|
2838
+ offset = i * 3
2839
+ uniform[:_array][offset] = v.x
2840
+ uniform[:_array][offset + 1] = v.y
2841
+ uniform[:_array][offset + 2] = v.z
2842
+ end
2843
+
2844
+ glUniform3fv(location, value.length * 3, array_to_ptr_easy(uniform[:_array]))
2845
+ when :v4v
2846
+ # array of Mittsu::Vector4
2847
+ uniform[:_array] ||= Array.new(4 * value.length) # Float32Array
2848
+
2849
+ value.each_with_index do |v, i|
2850
+ offset = i * 4
2851
+ uniform[:_array][offset] = v.x
2852
+ uniform[:_array][offset + 1] = v.y
2853
+ uniform[:_array][offset + 2] = v.z
2854
+ uniform[:_array][offset + 3] = v.w
2855
+ end
2856
+
2857
+ glUniform4fv(location, value.length * 4, array_to_ptr_easy(uniform[:_array]))
2858
+ when :m3
2859
+ # single Mittsu::Matrix3
2860
+ glUniformMatrix3fv(location, 1, GL_FALSE, array_to_ptr_easy(value.elements))
2861
+ when :m3v
2862
+ # array of Mittsu::Matrix3
2863
+ uniform[:_array] ||= Array.new(9 * value.length) # Float32Array
2864
+
2865
+ value.each_with_index do |v, i|
2866
+ value[i].flatten_to_array_offset(uniform[:_array], i * 9)
2867
+ end
2868
+
2869
+ glUniformMatrix3fv(location, value.length, GL_FALSE, array_to_ptr_easy(uniform[:_array]))
2870
+ when :m4
2871
+ # single Mittsu::Matrix4
2872
+ glUniformMatrix4vf(location, 1, GL_FALSE, array_to_ptr_easy(value.elements))
2873
+ when :m4v
2874
+ # array of Mittsu::Matrix4
2875
+ uniform[:_array] ||= Array.new(16 * value.length) # Float32Array
2876
+
2877
+ value.each_with_index do |v, i|
2878
+ value[i].flatten_to_array_offset(uniform[:_array], i * 16)
2879
+ end
2880
+
2881
+ glUniformMatrix4fv(location, value.length, GL_FALSE, array_to_ptr_easy(uniform[:_array]))
2882
+ when :t
2883
+ # single Mittsu::Texture (2d or cube)
2884
+ texture = value
2885
+ texture_unit = get_texture_unit
2886
+
2887
+ glUniform1i(location, texture_unit)
2888
+
2889
+ next unless texture
2890
+
2891
+ if texture.is_a?(CubeTexture) || (texture.is_a?(Array) && texture.image.length == 6)
2892
+ set_cube_texture(texture, texture_unit)
2893
+ # TODO: when OpenGLRenderTargetCube is defined
2894
+ # elsif texture.is_a?(OpenGLRenderTargetCube)
2895
+ # set_cube_texture_dynamic(texture, texture_unit)
2896
+ else
2897
+ set_texture(texture, texture_unit)
2898
+ end
2899
+ when :tv
2900
+ # array of Mittsu::Texture (2d)
2901
+ uniform[:_array] ||= []
2902
+
2903
+ uniform.value.each_index do |i|
2904
+ uniform[:_array][i] = get_texture_unit
2905
+ end
2906
+
2907
+ glUniform1iv(location, uniform[:_array].length, array_to_ptr_easy(uniform[:_array]))
2908
+
2909
+ uniform.value.each_with_index do |tex, i|
2910
+ tex_unit = uniform[:_array][i]
2911
+
2912
+ next unless tex
2913
+
2914
+ set_texture(tex, tex_unit)
2915
+ end
2916
+ else
2917
+ puts "WARNING: Mittsu::OpenGLRenderer: Unknown uniform type: #{type}"
2918
+ end
2919
+ end
2920
+ end
2921
+
2922
+ def load_uniforms_matrices(uniforms, object)
2923
+ glUniformMatrix4fv(uniforms['modelViewMatrix'], 1, GL_FALSE, array_to_ptr_easy(object[:_model_view_matrix].elements))
2924
+
2925
+ if uniforms['normalMatrix']
2926
+ glUniformMatrix3fv(uniforms['normalMatrix'], 1, GL_FALSE, array_to_ptr_easy(object[:_normal_matrix].elements))
2927
+ end
2928
+ end
2929
+
2930
+ def setup_lights(lights)
2931
+ r, g, b = 0.0, 0.0, 0.0
2932
+
2933
+ zlights = @_lights
2934
+
2935
+ dir_colors = zlights[:directional][:colors]
2936
+ dir_positions = zlights[:directional][:positions]
2937
+
2938
+ point_colors = zlights[:point][:colors]
2939
+ point_positions = zlights[:point][:positions]
2940
+ point_distances = zlights[:point][:distances]
2941
+ point_decays = zlights[:point][:decays]
2942
+
2943
+ spot_colors = zlights[:spot][:colors]
2944
+ spot_positions = zlights[:spot][:positions]
2945
+ spot_distances = zlights[:spot][:distances]
2946
+ spot_directions = zlights[:spot][:directions]
2947
+ spot_angles_cos = zlights[:spot][:angles_cos]
2948
+ spot_exponents = zlights[:spot][:exponents]
2949
+ spot_decays = zlights[:spot][:decays]
2950
+
2951
+ hemi_sky_colors = zlights[:hemi][:sky_colors]
2952
+ hemi_ground_colors = zlights[:hemi][:ground_colors]
2953
+ hemi_positions = zlights[:hemi][:positions]
2954
+
2955
+ dir_length = 0
2956
+ point_length = 0
2957
+ spot_length = 0
2958
+ hemi_length = 0
2959
+
2960
+ dir_count = 0
2961
+ point_count = 0
2962
+ spot_count = 0
2963
+ hemi_count = 0
2964
+
2965
+ dir_offset = 0
2966
+ point_offset = 0
2967
+ spot_offset = 0
2968
+ hemi_offset = 0
2969
+
2970
+ lights.each do |light|
2971
+
2972
+ next if light.only_shadow
2973
+
2974
+ color = light.color
2975
+ intensity = light.intensity
2976
+ distance = light.distance
2977
+
2978
+ if light.is_a? AmbientLight
2979
+
2980
+ next unless light.visible
2981
+
2982
+ r += color.r
2983
+ g += color.g
2984
+ b += color.b
2985
+
2986
+ elsif light.is_a? DirectionalLight
2987
+
2988
+ dir_count += 1
2989
+
2990
+ next unless light.visible
2991
+
2992
+ @_direction.set_from_matrix_position(light.matrix_world)
2993
+ @_vector3.set_from_matrix_position(light.target.matrix_world)
2994
+ @_direction.sub(@_vector3)
2995
+ @_direction.normalize
2996
+
2997
+ dir_offset = dir_length * 3
2998
+
2999
+ dir_positions[dir_offset] = @_direction.x
3000
+ dir_positions[dir_offset + 1] = @_direction.y
3001
+ dir_positions[dir_offset + 2] = @_direction.z
3002
+
3003
+ set_color_linear(dir_colors, dir_offset, color, intensity)
3004
+
3005
+ dir_length += 1
3006
+
3007
+ elsif light.is_a? PointLight
3008
+
3009
+ point_count += 1
3010
+
3011
+ next unless light.visible
3012
+
3013
+ point_offset = point_length * 3;
3014
+
3015
+ set_color_linear(point_colors, point_offset, color, intensity)
3016
+
3017
+ @_vector3.set_from_matrix_position(light.matrix_world)
3018
+
3019
+ point_positions[point_offset] = @_vector3.x
3020
+ point_positions[point_offset + 1] = @_vector3.y
3021
+ point_positions[point_offset + 2] = @_vector3.z
3022
+
3023
+ # distance is 0 if decay is 0, because there is no attenuation at all.
3024
+ point_distances[point_length] = distance
3025
+ point_decays[point_length] = light.distance.zero? ? 0.0 : light.decay
3026
+
3027
+ point_length += 1
3028
+
3029
+ elsif light.is_a? SpotLight
3030
+
3031
+ spot_count += 1
3032
+
3033
+ next unless light.visible
3034
+
3035
+ spot_offset = spot_length * 3
3036
+
3037
+ set_color_linear(spot_colors, spot_offset, color, intensity)
3038
+
3039
+ @_direction.set_from_matrix_position(light.matrix_world)
3040
+
3041
+ spot_positions[spot_offset] = @_direction.x
3042
+ spot_positions[spot_offset + 1] = @_direction.y
3043
+ spot_positions[spot_offset + 2] = @_direction.z
3044
+
3045
+ spot_distances[spot_length] = distance
3046
+
3047
+ @_vector3.set_from_matrix_position(light.target.matrix_world)
3048
+ @_direction.sub(@_vector3)
3049
+ @_direction.normalize
3050
+
3051
+ spot_directions[spot_offset] = @_direction.x
3052
+ spot_directions[spot_offset + 1] = @_direction.y
3053
+ spot_directions[spot_offset + 2] = @_direction.z
3054
+
3055
+ spot_angles_cos[spot_length] = Math.cos(light.angle)
3056
+ spot_exponents[spot_length] = light.exponent;
3057
+ spot_decays[spot_length] = light.distance.zero? ? 0.0 : light.decay
3058
+
3059
+ spot_length += 1;
3060
+
3061
+ elsif light.is_a? HemisphereLight
3062
+
3063
+ hemi_count += 1
3064
+
3065
+ next unless light.visible
3066
+
3067
+ @_direction.set_from_matrix_position(light.matrix_world)
3068
+ @_direction.normalize
3069
+
3070
+ hemi_offset = hemi_length * 3
3071
+
3072
+ hemi_positions[hemi_offset] = @_direction.x
3073
+ hemi_positions[hemi_offset + 1] = @_direction.y
3074
+ hemi_positions[hemi_offset + 2] = @_direction.z
3075
+
3076
+ sky_color = light.color
3077
+ ground_color = light.ground_color
3078
+
3079
+ set_color_linear(hemi_sky_colors, hemi_offset, sky_color, intensity )
3080
+ set_color_linear(hemi_ground_colors, hemi_offset, ground_color, intensity)
3081
+
3082
+ hemi_length += 1
3083
+
3084
+ end
3085
+
3086
+ end
3087
+
3088
+ # null eventual remains from removed lights
3089
+ # (this is to avoid if in shader)
3090
+
3091
+ (dir_length * 3).upto([dir_colors.length, dir_count * 3].max - 1).each { |i|
3092
+ dir_colors[i] = 0.0
3093
+ }
3094
+ (point_length * 3).upto([point_colors.length, point_count * 3].max - 1).each { |i|
3095
+ point_colors[i] = 0.0
3096
+ }
3097
+ (spot_length * 3).upto([spot_colors.length, spot_count * 3].max - 1).each { |i|
3098
+ spot_colors[i] = 0.0
3099
+ }
3100
+ (hemi_length * 3).upto([hemi_ground_colors.length, hemi_count * 3].max - 1).each { |i|
3101
+ hemi_ground_colors[i] = 0.0
3102
+ }
3103
+ (hemi_length * 3).upto([hemi_sky_colors.length, hemi_count * 3].max - 1).each { |i|
3104
+ hemi_sky_colors[i] = 0.0
3105
+ }
3106
+
3107
+ zlights[:directional][:length] = dir_length
3108
+ zlights[:point][:length] = point_length
3109
+ zlights[:spot][:length] = spot_length
3110
+ zlights[:hemi][:length] = hemi_length
3111
+
3112
+ zlights[:ambient][0] = r
3113
+ zlights[:ambient][1] = g
3114
+ zlights[:ambient][2] = b
3115
+ end
3116
+
3117
+ def refresh_uniforms_lights(uniforms, lights)
3118
+ uniforms['ambientLightColor'].value = lights[:ambient]
3119
+
3120
+ uniforms['directionalLightColor'].value = lights[:directional][:colors]
3121
+ uniforms['directionalLightDirection'].value = lights[:directional][:positions]
3122
+
3123
+ uniforms['pointLightColor'].value = lights[:point][:colors]
3124
+ uniforms['pointLightPosition'].value = lights[:point][:positions]
3125
+ uniforms['pointLightDistance'].value = lights[:point][:distances]
3126
+ uniforms['pointLightDecay'].value = lights[:point][:decays]
3127
+
3128
+ uniforms['spotLightColor'].value = lights[:spot][:colors]
3129
+ uniforms['spotLightPosition'].value = lights[:spot][:positions]
3130
+ uniforms['spotLightDistance'].value = lights[:spot][:distances]
3131
+ uniforms['spotLightDirection'].value = lights[:spot][:directions]
3132
+ uniforms['spotLightAngleCos'].value = lights[:spot][:angles_cos]
3133
+ uniforms['spotLightExponent'].value = lights[:spot][:exponents]
3134
+ uniforms['spotLightDecay'].value = lights[:spot][:decays]
3135
+
3136
+ uniforms['hemisphereLightSkyColor'].value = lights[:hemi][:sky_colors]
3137
+ uniforms['hemisphereLightGroundColor'].value = lights[:hemi][:ground_colors]
3138
+ uniforms['hemisphereLightDirection'].value = lights[:hemi][:positions]
3139
+ end
3140
+
3141
+ def mark_uniforms_lights_needs_update(uniforms, value)
3142
+ uniforms['ambientLightColor'].needs_update = value
3143
+
3144
+ uniforms['directionalLightColor'].needs_update = value
3145
+ uniforms['directionalLightDirection'].needs_update = value
3146
+
3147
+ uniforms['pointLightColor'].needs_update = value
3148
+ uniforms['pointLightPosition'].needs_update = value
3149
+ uniforms['pointLightDistance'].needs_update = value
3150
+ uniforms['pointLightDecay'].needs_update = value
3151
+
3152
+ uniforms['spotLightColor'].needs_update = value
3153
+ uniforms['spotLightPosition'].needs_update = value
3154
+ uniforms['spotLightDistance'].needs_update = value
3155
+ uniforms['spotLightDirection'].needs_update = value
3156
+ uniforms['spotLightAngleCos'].needs_update = value
3157
+ uniforms['spotLightExponent'].needs_update = value
3158
+ uniforms['spotLightDecay'].needs_update = value
3159
+
3160
+ uniforms['hemisphereLightSkyColor'].needs_update = value
3161
+ uniforms['hemisphereLightGroundColor'].needs_update = value
3162
+ uniforms['hemisphereLightDirection'].needs_update = value
3163
+ end
3164
+
3165
+ def refresh_uniforms_lambert(uniforms, material)
3166
+ uniforms['emissive'].value = material.emissive
3167
+
3168
+ if material.wrap_around
3169
+ uniforms['wrapRGB'].value.copy(material.wrap_rgb)
3170
+ end
3171
+ end
3172
+
3173
+ def set_color_linear(array, offset, color, intensity)
3174
+ array[offset] = color.r * intensity
3175
+ array[offset + 1] = color.g * intensity
3176
+ array[offset + 2] = color.b * intensity
3177
+ end
3178
+
3179
+ def get_texture_unit
3180
+ texture_unit = @_used_texture_units
3181
+
3182
+ if texture_unit >= @_max_textures
3183
+ puts "WARNING: OpenGLRenderer: trying to use #{texture_unit} texture units while this GPU supports only #{@_max_textures}"
3184
+ end
3185
+
3186
+ @_used_texture_units += 1
3187
+ texture_unit
3188
+ end
3189
+
3190
+ def clamp_to_max_size(image, max_size)
3191
+ if image.width > max_size || image.height > max_size
3192
+ # TODO: scale the image ...
3193
+
3194
+ puts "WARNING: Mittsu::OpenGLRenderer: image is too big (#{image.width} x #{image.height}). Resized to ??? x ???"
3195
+ end
3196
+ image
3197
+ end
3198
+
3199
+ def param_mittsu_to_gl(p)
3200
+ case p
3201
+ when RepeatWrapping then GL_REPEAT
3202
+ when ClampToEdgeWrapping then GL_CLAMP_TO_EDGE
3203
+ when MirroredRepeatWrapping then GL_MIRRORED_REPEAT
3204
+
3205
+ when NearestFilter then GL_NEAREST
3206
+ when NearestMipMapNearestFilter then GL_NEAREST_MIPMAP_NEAREST
3207
+ when NearestMipMapLinearFilter then GL_NEAREST_MIPMAP_LINEAR
3208
+
3209
+ when LinearFilter then GL_LINEAR
3210
+ when LinearMipMapNearestFilter then GL_LINEAR_MIPMAP_NEAREST
3211
+ when LinearMipMapLinearFilter then GL_LINEAR_MIPMAP_LINEAR
3212
+
3213
+ when UnsignedByteType then GL_UNSIGNED_BYTE
3214
+ when UnsignedShort4444Type then GL_UNSIGNED_SHORT_4_4_4_4
3215
+ when UnsignedShort5551Type then GL_UNSIGNED_SHORT_5_5_5_1
3216
+ when UnsignedShort565Type then GL_UNSIGNED_SHORT_5_6_5
3217
+
3218
+ when ByteType then GL_BYTE
3219
+ when ShortType then GL_SHORT
3220
+ when UnsignedShortType then GL_UNSIGNED_SHORT
3221
+ when IntType then GL_INT
3222
+ when UnsignedIntType then GL_UNSIGNED_INT
3223
+ when FloatType then GL_FLOAT
3224
+
3225
+ when AlphaFormat then GL_ALPHA
3226
+ when RGBFormat then GL_RGB
3227
+ when RGBAFormat then GL_RGBA
3228
+ when LuminanceFormat then GL_LUMINANCE
3229
+ when LuminanceAlphaFormat then GL_LUMINANCE_ALPHA
3230
+
3231
+ when AddEquation then GL_FUNC_ADD
3232
+ when SubtractEquation then GL_FUNC_SUBTRACT
3233
+ when ReverseSubtractEquation then GL_FUNC_REVERSE_SUBTRACT
3234
+
3235
+ when ZeroFactor then GL_ZERO
3236
+ when OneFactor then GL_ONE
3237
+ when SrcColorFactor then GL_SRC_COLOR
3238
+ when OneMinusSrcColorFactor then GL_ONE_MINUS_SRC_COLOR
3239
+ when SrcAlphaFactor then GL_SRC_ALPHA
3240
+ when OneMinusSrcAlphaFactor then GL_ONE_MINUS_SRC_ALPHA
3241
+ when DstAlphaFactor then GL_DST_ALPHA
3242
+ when OneMinusDstAlphaFactor then GL_ONE_MINUS_DST_ALPHA
3243
+
3244
+ when DstColorFactor then GL_DST_COLOR
3245
+ when OneMinusDstColorFactor then GL_ONE_MINUS_DST_COLOR
3246
+ when SrcAlphaSaturateFactor then GL_SRC_ALPHA_SATURATE
3247
+ else 0
3248
+ end
3249
+ end
3250
+
3251
+ def set_texture_parameters(texture_type, texture, is_image_power_of_two)
3252
+ if is_image_power_of_two
3253
+ glTexParameteri(texture_type, GL_TEXTURE_WRAP_S, param_mittsu_to_gl(texture.wrap_s))
3254
+ glTexParameteri(texture_type, GL_TEXTURE_WRAP_T, param_mittsu_to_gl(texture.wrap_t))
3255
+
3256
+ glTexParameteri(texture_type, GL_TEXTURE_MAG_FILTER, param_mittsu_to_gl(texture.mag_filter))
3257
+ glTexParameteri(texture_type, GL_TEXTURE_MIN_FILTER, param_mittsu_to_gl(texture.min_filter))
3258
+ else
3259
+ glTexParameteri(texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
3260
+ glTexParameteri(texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
3261
+
3262
+ if texture.wrap_s != ClampToEdgeWrapping || texture.wrap_t != ClampToEdgeWrapping
3263
+ puts "WARNING: Mittsu::OpenGLRenderer: Texture is not power of two. Texture.wrap_s and Texture.wrap_t should be set to Mittsu::ClampToEdgeWrapping. (#{texture.source_file})"
3264
+ end
3265
+
3266
+ glTexParameteri(texture_type, GL_TEXTURE_MAG_FILTER, filter_fallback(texture.mag_filter))
3267
+ glTexParameteri(texture_type, GL_TEXTURE_MIN_FILTER, filter_fallback(texture.min_filter))
3268
+
3269
+ if texture.min_filter != NearestFilter && texture.min_filter != LinearFilter
3270
+ puts "WARNING: Mittsu::OpenGLRenderer: Texture is not a power of two. Texture.min_filter should be set to Mittsu::NearestFilter or Mittsu::LinearFilter. (#{texture.source_file})"
3271
+ end
3272
+
3273
+ # TODO: anisotropic extension ???
3274
+ end
3275
+ end
3276
+
3277
+ def set_cube_texture(texture, slot)
3278
+ if texture.image.length == 6
3279
+ if texture.needs_update?
3280
+ if !texture.image[:_opengl_texture_cube]
3281
+ texture.add_event_listener(:dispose, @on_texture_dispose)
3282
+ texture.image[:_opengl_texture_cube] = glCreateTexture
3283
+ @info[:memory][:textures] += 1
3284
+ end
3285
+
3286
+ glActiveTexture(GL_TEXTURE0 + slot)
3287
+ glBindTexture(GL_TEXTURE_CUBE_MAP, texture.image[:_opengl_texture_cube])
3288
+
3289
+ # glPixelStorei(GL_UNPACK_FLIP_Y_WEBGL, texture.flip_y)
3290
+
3291
+ is_compressed = texture.is_a?(CompressedTexture)
3292
+ is_data_texture = texture.image[0].is_a?(DataTexture)
3293
+
3294
+ cube_image = [];
3295
+
3296
+ 6.times do |i|
3297
+ if @auto_scale_cubemaps && !is_compressed && !is_data_texture
3298
+ cube_image[i] = clamp_to_max_size(texture.image[i], @_max_cubemap_size)
3299
+ else
3300
+ cube_image[i] = is_data_texture ? texture.image[i].image : texture.image[i];
3301
+ end
3302
+ end
3303
+
3304
+ image = cube_image[0]
3305
+ is_image_power_of_two = Math.power_of_two?(image.width) && Math.power_of_two?(image.height)
3306
+ gl_format = param_mittsu_to_gl(texture.format)
3307
+ gl_type = param_mittsu_to_gl(texture.type)
3308
+
3309
+ set_texture_parameters(GL_TEXTURE_CUBE_MAP, texture, is_image_power_of_two)
3310
+
3311
+ 6.times do |i|
3312
+ if !is_compressed
3313
+ if is_data_texture
3314
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, gl_format, cube_image[i].width, cube_image[i].height, 0, gl_format, gl_type, cube_image[i].data)
3315
+ else
3316
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, gl_format, cube_image[i].width, cube_image[i].height, 0, gl_format, gl_type, cube_image[i].data)
3317
+ end
3318
+ else
3319
+ mipmaps = cube_image[i].mipmaps
3320
+
3321
+ mipmaps.each_with_index do |mipmap, j|
3322
+ if texture.format != RGBAFormat && texture.format != RGBFormat
3323
+ if get_compressed_texture_formats.include?(gl_format)
3324
+ glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, j, gl_format, mipmap.width, mipmap.height, 0, mipmap.data)
3325
+ else
3326
+ puts "WARNING: Mittsu::OpenGLRenderer: Attempt to load unsupported compressed texture format in #set_cube_texture"
3327
+ end
3328
+ else
3329
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, j, gl_format, mipmap.width, mipmap.height, 0, gl_format, gl_type, mipmap.data)
3330
+ end
3331
+ end
3332
+ end
3333
+ end
3334
+
3335
+ if texture.generate_mipmaps && is_image_power_of_two
3336
+ glGenerateMipmap(GL_TEXTURE_CUBE_MAP)
3337
+ end
3338
+
3339
+ texture.needs_update = false
3340
+
3341
+ # TODO wat?
3342
+ # texture.on_update if texture.on_update
3343
+ else
3344
+ glActiveTexture(GL_TEXTURE0 + slot)
3345
+ glBindTexture(GL_TEXTURE_CUBE_MAP, texture.image[:_opengl_texture_cube])
3346
+ end
3347
+ end
3348
+ end
3349
+
3350
+ def setup_framebuffer(framebuffer, render_target, texture_target)
3351
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer)
3352
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture_target, render_target[:_opengl_texture], 0)
3353
+ end
3354
+
3355
+ def setup_renderbuffer(renderbuffer, render_target)
3356
+ glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer)
3357
+
3358
+ if render_target.depth_buffer && !render_target.stencil_buffer
3359
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, render_target.width, render_target.height)
3360
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffer)
3361
+
3362
+ # TODO: investigate this (?):
3363
+ # THREE.js - For some reason this is not working. Defaulting to RGBA4.
3364
+ # } else if ( ! renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
3365
+ #
3366
+ # _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.STENCIL_INDEX8, renderTarget.width, renderTarget.height );
3367
+ # _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
3368
+ elsif render_target.depth_buffer && render_target.stencil_buffer
3369
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, render_target.width, render_target.height)
3370
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderbuffer)
3371
+ else
3372
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, render_target.width, render_target.height)
3373
+ end
3374
+ end
3375
+ end
3376
+ end