mittsu 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (203) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.travis.yml +3 -0
  4. data/CODE_OF_CONDUCT.md +13 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +39 -0
  8. data/Rakefile +7 -0
  9. data/bin/console +14 -0
  10. data/bin/setup +7 -0
  11. data/examples/01_-_Default1noCulling.png +0 -0
  12. data/examples/01_scene_example.rb +14 -0
  13. data/examples/02_box_mesh_example.rb +30 -0
  14. data/examples/02_sphere_mesh_example.rb +30 -0
  15. data/examples/03_complex_object_example.rb +52 -0
  16. data/examples/04_ambient_light_example.rb +33 -0
  17. data/examples/04_dir_light_example.rb +36 -0
  18. data/examples/04_hemi_light_example.rb +30 -0
  19. data/examples/04_point_light_example.rb +50 -0
  20. data/examples/04_spot_light_example.rb +44 -0
  21. data/examples/05_earth_example.rb +42 -0
  22. data/examples/05_earth_moon_example.rb +46 -0
  23. data/examples/05_texture_example.rb +32 -0
  24. data/examples/06_cube_texture_example.rb +36 -0
  25. data/examples/06_skybox_example.rb +60 -0
  26. data/examples/07_earth_normal_example.rb +36 -0
  27. data/examples/08_shadow_example.rb +87 -0
  28. data/examples/09_line_example.rb +52 -0
  29. data/examples/10_obj_loader_example.rb +68 -0
  30. data/examples/11_character_input_example.rb +18 -0
  31. data/examples/11_continuous_keyboard_input_example.rb +35 -0
  32. data/examples/11_keyboard_input_example.rb +43 -0
  33. data/examples/12_mouse_click_example.rb +38 -0
  34. data/examples/12_mouse_motion_example.rb +35 -0
  35. data/examples/12_mouse_scroll_example.rb +36 -0
  36. data/examples/12_orbit_zoom_example.rb +68 -0
  37. data/examples/13_joystick_example.rb +80 -0
  38. data/examples/cubemap/tron_bk.png +0 -0
  39. data/examples/cubemap/tron_dn.png +0 -0
  40. data/examples/cubemap/tron_ft.png +0 -0
  41. data/examples/cubemap/tron_lf.png +0 -0
  42. data/examples/cubemap/tron_rt.png +0 -0
  43. data/examples/cubemap/tron_up.png +0 -0
  44. data/examples/earth.png +0 -0
  45. data/examples/earth_normal.png +0 -0
  46. data/examples/example_helper.rb +2 -0
  47. data/examples/male-02-1noCulling.png +0 -0
  48. data/examples/male02.mtl +54 -0
  49. data/examples/male02.obj +13888 -0
  50. data/examples/moon.png +0 -0
  51. data/examples/orig_02_-_Defaul1noCulling.png +0 -0
  52. data/examples/texture.png +0 -0
  53. data/lib/mittsu.rb +15 -0
  54. data/lib/mittsu/cameras.rb +4 -0
  55. data/lib/mittsu/cameras/camera.rb +34 -0
  56. data/lib/mittsu/cameras/cube_camera.rb +74 -0
  57. data/lib/mittsu/cameras/orthographic_camera.rb +53 -0
  58. data/lib/mittsu/cameras/perspective_camera.rb +115 -0
  59. data/lib/mittsu/constants.rb +160 -0
  60. data/lib/mittsu/core.rb +10 -0
  61. data/lib/mittsu/core/buffer_attribute.rb +87 -0
  62. data/lib/mittsu/core/buffer_geometry.rb +694 -0
  63. data/lib/mittsu/core/clock.rb +44 -0
  64. data/lib/mittsu/core/dynamic_buffer_attribute.rb +16 -0
  65. data/lib/mittsu/core/event_dispatcher.rb +39 -0
  66. data/lib/mittsu/core/face3.rb +30 -0
  67. data/lib/mittsu/core/geometry.rb +596 -0
  68. data/lib/mittsu/core/hash_array.rb +36 -0
  69. data/lib/mittsu/core/hash_object.rb +19 -0
  70. data/lib/mittsu/core/object_3d.rb +421 -0
  71. data/lib/mittsu/core/raycaster.rb +78 -0
  72. data/lib/mittsu/extras.rb +3 -0
  73. data/lib/mittsu/extras/geometries.rb +2 -0
  74. data/lib/mittsu/extras/geometries/box_geometry.rb +108 -0
  75. data/lib/mittsu/extras/geometries/sphere_geometry.rb +88 -0
  76. data/lib/mittsu/extras/helpers.rb +1 -0
  77. data/lib/mittsu/extras/helpers/camera_helper.rb +155 -0
  78. data/lib/mittsu/extras/image.rb +3 -0
  79. data/lib/mittsu/extras/image_utils.rb +80 -0
  80. data/lib/mittsu/lights.rb +7 -0
  81. data/lib/mittsu/lights/ambient_light.rb +16 -0
  82. data/lib/mittsu/lights/area_light.rb +24 -0
  83. data/lib/mittsu/lights/directional_light.rb +131 -0
  84. data/lib/mittsu/lights/hemisphere_light.rb +29 -0
  85. data/lib/mittsu/lights/light.rb +21 -0
  86. data/lib/mittsu/lights/point_light.rb +27 -0
  87. data/lib/mittsu/lights/spot_light.rb +104 -0
  88. data/lib/mittsu/loaders.rb +7 -0
  89. data/lib/mittsu/loaders/cache.rb +53 -0
  90. data/lib/mittsu/loaders/file_loader.rb +22 -0
  91. data/lib/mittsu/loaders/image_loader.rb +32 -0
  92. data/lib/mittsu/loaders/loader.rb +212 -0
  93. data/lib/mittsu/loaders/loading_manager.rb +17 -0
  94. data/lib/mittsu/loaders/mtl_loader.rb +242 -0
  95. data/lib/mittsu/loaders/obj_mtl_loader.rb +225 -0
  96. data/lib/mittsu/materials.rb +7 -0
  97. data/lib/mittsu/materials/line_basic_material.rb +39 -0
  98. data/lib/mittsu/materials/material.rb +156 -0
  99. data/lib/mittsu/materials/mesh_basic_material.rb +122 -0
  100. data/lib/mittsu/materials/mesh_face_material.rb +30 -0
  101. data/lib/mittsu/materials/mesh_lambert_material.rb +126 -0
  102. data/lib/mittsu/materials/mesh_phong_material.rb +152 -0
  103. data/lib/mittsu/materials/shader_material.rb +108 -0
  104. data/lib/mittsu/math.rb +105 -0
  105. data/lib/mittsu/math/box2.rb +135 -0
  106. data/lib/mittsu/math/box3.rb +194 -0
  107. data/lib/mittsu/math/color.rb +252 -0
  108. data/lib/mittsu/math/color_keywords.rb +151 -0
  109. data/lib/mittsu/math/euler.rb +182 -0
  110. data/lib/mittsu/math/frustum.rb +106 -0
  111. data/lib/mittsu/math/line3.rb +76 -0
  112. data/lib/mittsu/math/matrix3.rb +163 -0
  113. data/lib/mittsu/math/matrix4.rb +581 -0
  114. data/lib/mittsu/math/plane.rb +128 -0
  115. data/lib/mittsu/math/quaternion.rb +309 -0
  116. data/lib/mittsu/math/ray.rb +292 -0
  117. data/lib/mittsu/math/sphere.rb +91 -0
  118. data/lib/mittsu/math/spline.rb +128 -0
  119. data/lib/mittsu/math/triangle.rb +121 -0
  120. data/lib/mittsu/math/vector2.rb +238 -0
  121. data/lib/mittsu/math/vector3.rb +491 -0
  122. data/lib/mittsu/math/vector4.rb +414 -0
  123. data/lib/mittsu/objects.rb +3 -0
  124. data/lib/mittsu/objects/group.rb +8 -0
  125. data/lib/mittsu/objects/line.rb +143 -0
  126. data/lib/mittsu/objects/mesh.rb +243 -0
  127. data/lib/mittsu/renderers.rb +1 -0
  128. data/lib/mittsu/renderers/glfw_window.rb +216 -0
  129. data/lib/mittsu/renderers/opengl/opengl_debug.rb +38 -0
  130. data/lib/mittsu/renderers/opengl/opengl_program.rb +402 -0
  131. data/lib/mittsu/renderers/opengl/opengl_shader.rb +58 -0
  132. data/lib/mittsu/renderers/opengl/opengl_state.rb +207 -0
  133. data/lib/mittsu/renderers/opengl/plugins/shadow_map_plugin.rb +416 -0
  134. data/lib/mittsu/renderers/opengl_render_target.rb +87 -0
  135. data/lib/mittsu/renderers/opengl_renderer.rb +3376 -0
  136. data/lib/mittsu/renderers/shaders/shader_chunk.rb +12 -0
  137. data/lib/mittsu/renderers/shaders/shader_chunk/alphamap_fragment.glsl +5 -0
  138. data/lib/mittsu/renderers/shaders/shader_chunk/alphamap_pars_fragment.glsl +5 -0
  139. data/lib/mittsu/renderers/shaders/shader_chunk/alphatest_fragment.glsl +5 -0
  140. data/lib/mittsu/renderers/shaders/shader_chunk/bumpmap_pars_fragment.glsl +40 -0
  141. data/lib/mittsu/renderers/shaders/shader_chunk/color_fragment.glsl +5 -0
  142. data/lib/mittsu/renderers/shaders/shader_chunk/color_pars_fragment.glsl +5 -0
  143. data/lib/mittsu/renderers/shaders/shader_chunk/color_pars_vertex.glsl +5 -0
  144. data/lib/mittsu/renderers/shaders/shader_chunk/color_vertex.glsl +5 -0
  145. data/lib/mittsu/renderers/shaders/shader_chunk/common.glsl +60 -0
  146. data/lib/mittsu/renderers/shaders/shader_chunk/default_vertex.glsl +15 -0
  147. data/lib/mittsu/renderers/shaders/shader_chunk/defaultnormal_vertex.glsl +21 -0
  148. data/lib/mittsu/renderers/shaders/shader_chunk/envmap_fragment.glsl +62 -0
  149. data/lib/mittsu/renderers/shaders/shader_chunk/envmap_pars_fragment.glsl +21 -0
  150. data/lib/mittsu/renderers/shaders/shader_chunk/envmap_pars_vertex.glsl +7 -0
  151. data/lib/mittsu/renderers/shaders/shader_chunk/envmap_vertex.glsl +17 -0
  152. data/lib/mittsu/renderers/shaders/shader_chunk/fog_fragment.glsl +26 -0
  153. data/lib/mittsu/renderers/shaders/shader_chunk/fog_pars_fragment.glsl +15 -0
  154. data/lib/mittsu/renderers/shaders/shader_chunk/lightmap_fragment.glsl +5 -0
  155. data/lib/mittsu/renderers/shaders/shader_chunk/lightmap_pars_fragment.glsl +6 -0
  156. data/lib/mittsu/renderers/shaders/shader_chunk/lightmap_pars_vertex.glsl +5 -0
  157. data/lib/mittsu/renderers/shaders/shader_chunk/lightmap_vertex.glsl +5 -0
  158. data/lib/mittsu/renderers/shaders/shader_chunk/lights_lambert_pars_vertex.glsl +43 -0
  159. data/lib/mittsu/renderers/shaders/shader_chunk/lights_lambert_vertex.glsl +196 -0
  160. data/lib/mittsu/renderers/shaders/shader_chunk/lights_phong_fragment.glsl +243 -0
  161. data/lib/mittsu/renderers/shaders/shader_chunk/lights_phong_pars_fragment.glsl +58 -0
  162. data/lib/mittsu/renderers/shaders/shader_chunk/lights_phong_pars_vertex.glsl +5 -0
  163. data/lib/mittsu/renderers/shaders/shader_chunk/lights_phong_vertex.glsl +5 -0
  164. data/lib/mittsu/renderers/shaders/shader_chunk/linear_to_gamma_fragment.glsl +2 -0
  165. data/lib/mittsu/renderers/shaders/shader_chunk/logdepthbuf_fragment.glsl +5 -0
  166. data/lib/mittsu/renderers/shaders/shader_chunk/logdepthbuf_pars_fragment.glsl +12 -0
  167. data/lib/mittsu/renderers/shaders/shader_chunk/logdepthbuf_pars_vertex.glsl +11 -0
  168. data/lib/mittsu/renderers/shaders/shader_chunk/logdepthbuf_vertex.glsl +15 -0
  169. data/lib/mittsu/renderers/shaders/shader_chunk/map_fragment.glsl +9 -0
  170. data/lib/mittsu/renderers/shaders/shader_chunk/map_pars_fragment.glsl +11 -0
  171. data/lib/mittsu/renderers/shaders/shader_chunk/map_pars_vertex.glsl +6 -0
  172. data/lib/mittsu/renderers/shaders/shader_chunk/map_particle_fragment.glsl +5 -0
  173. data/lib/mittsu/renderers/shaders/shader_chunk/map_particle_pars_fragment.glsl +6 -0
  174. data/lib/mittsu/renderers/shaders/shader_chunk/map_vertex.glsl +5 -0
  175. data/lib/mittsu/renderers/shaders/shader_chunk/morphnormal_vertex.glsl +12 -0
  176. data/lib/mittsu/renderers/shaders/shader_chunk/morphtarget_pars_vertex.glsl +13 -0
  177. data/lib/mittsu/renderers/shaders/shader_chunk/morphtarget_vertex.glsl +20 -0
  178. data/lib/mittsu/renderers/shaders/shader_chunk/normalmap_pars_fragment.glsl +27 -0
  179. data/lib/mittsu/renderers/shaders/shader_chunk/shadowmap_fragment.glsl +217 -0
  180. data/lib/mittsu/renderers/shaders/shader_chunk/shadowmap_pars_fragment.glsl +19 -0
  181. data/lib/mittsu/renderers/shaders/shader_chunk/shadowmap_pars_vertex.glsl +6 -0
  182. data/lib/mittsu/renderers/shaders/shader_chunk/shadowmap_vertex.glsl +9 -0
  183. data/lib/mittsu/renderers/shaders/shader_chunk/skinbase_vertex.glsl +8 -0
  184. data/lib/mittsu/renderers/shaders/shader_chunk/skinning_pars_vertex.glsl +47 -0
  185. data/lib/mittsu/renderers/shaders/shader_chunk/skinning_vertex.glsl +20 -0
  186. data/lib/mittsu/renderers/shaders/shader_chunk/skinnormal_vertex.glsl +20 -0
  187. data/lib/mittsu/renderers/shaders/shader_chunk/specularmap_fragment.glsl +12 -0
  188. data/lib/mittsu/renderers/shaders/shader_chunk/specularmap_pars_fragment.glsl +5 -0
  189. data/lib/mittsu/renderers/shaders/shader_chunk/worldpos_vertex.glsl +17 -0
  190. data/lib/mittsu/renderers/shaders/shader_lib.rb +420 -0
  191. data/lib/mittsu/renderers/shaders/uniforms_lib.rb +107 -0
  192. data/lib/mittsu/renderers/shaders/uniforms_utils.rb +31 -0
  193. data/lib/mittsu/scenes.rb +1 -0
  194. data/lib/mittsu/scenes/scene.rb +27 -0
  195. data/lib/mittsu/textures.rb +5 -0
  196. data/lib/mittsu/textures/compressed_texture.rb +30 -0
  197. data/lib/mittsu/textures/cube_texture.rb +19 -0
  198. data/lib/mittsu/textures/data_texture.rb +17 -0
  199. data/lib/mittsu/textures/texture.rb +92 -0
  200. data/lib/mittsu/textures/video_texture.rb +17 -0
  201. data/lib/mittsu/version.rb +4 -0
  202. data/mittsu.gemspec +31 -0
  203. metadata +357 -0
@@ -0,0 +1,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