1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Intro a custom model, material and graphics program to draw a globe
18 intrude import gamnit
::depth
# To access `Mesh::indices_c`
20 # Number of vertices to create parallels, meridians are double of this
22 # The minimum should be 3 for an octahedron planet.
23 fun n_parallels
: Int do return 25
27 # Program for the graphic card
28 private var globe_program
= new GlobeProgram
30 # Texture of the reflexive surface of the earth (with the seas in white)
31 private var texture_seas
= new Texture("globe/seas.jpg")
33 # Texture of the surface of the earth
34 private var texture_earth
= new Texture("globe/earth.jpg")
36 # Texture of the lights at night on earth
37 private var texture_night
= new Texture("globe/lights.jpg")
39 # Elevation map of earth
40 private var texture_elevation
= new Texture("globe/elevation.jpg")
42 # Texture of the clouds above the earth
43 private var texture_clouds
= new Texture("globe/clouds.png")
49 # Compile globe_program
50 var program
= app
.globe_program
51 program
.compile_and_link
54 var gamnit_error
= program
.error
55 assert gamnit_error
== null else print_error gamnit_error
59 # Full model of a globe, with a surface, clouds layer and atmosphere
65 leaves
.add
new LeafModel(
66 new UVSphere(1.0, 2*n_parallels
, n_parallels
),
67 new GlobeMaterial.surface
)
68 leaves
.add
new LeafModel(
69 new UVSphere(1.1, 2*n_parallels
, n_parallels
),
70 new GlobeMaterial.clouds
)
71 leaves
.add
new LeafModel(
72 new UVSphere(1.2, 2*n_parallels
, n_parallels
),
73 new GlobeMaterial.atmo
)
77 # Parameterizable material to draw the 3 layers of the globe
81 # Id of the texture for diffuse colors, if any
82 var texture_id
: nullable Int
84 # Draw as a surface, using the elevation map and the night lights
88 var color
: Array[Float]
90 # Create and configure a material for the earth surface
91 init surface
do init(0, true, [1.0, 1.0, 1.0, 1.0])
93 # Create and configure a material for the cloud layer
94 init clouds
do init(4, false, [1.0*clouds_a
, 1.0*clouds_a
, 1.0*clouds_a
, clouds_a
])
95 private var clouds_a
= 0.5
97 # Create and configure a material for the visible atmosphere
98 init atmo
do init(null, false, [0.0, 0.8*atmo_a
, 1.0*atmo_a
, atmo_a
])
99 private var atmo_a
= 0.05
101 redef fun draw
(actor
, model
)
103 var gl_error
= glGetError
104 assert gl_error
== gl_NO_ERROR
else print gl_error
106 var mesh
= model
.mesh
108 var program
= app
.globe_program
111 # Set constant program values
115 glActiveTexture gl_TEXTURE0
116 glBindTexture
(gl_TEXTURE_2D
, app
.texture_earth
.gl_texture
)
118 glActiveTexture gl_TEXTURE1
119 glBindTexture
(gl_TEXTURE_2D
, app
.texture_seas
.gl_texture
)
121 glActiveTexture gl_TEXTURE2
122 glBindTexture
(gl_TEXTURE_2D
, app
.texture_night
.gl_texture
)
124 glActiveTexture gl_TEXTURE3
125 glBindTexture
(gl_TEXTURE_2D
, app
.texture_elevation
.gl_texture
)
127 glActiveTexture gl_TEXTURE4
128 glBindTexture
(gl_TEXTURE_2D
, app
.texture_clouds
.gl_texture
)
131 program
.tex_specular
.uniform
1
132 program
.tex_night
.uniform
2
133 program
.tex_displace
.uniform
3
135 # Update camera view and light
136 var p
= app
.world_camera
.position
137 program
.camera
.uniform
(p
.x
, p
.y
, p
.z
)
138 program
.mvp
.uniform app
.world_camera
.mvp_matrix
139 program
.light_center
.uniform
(app
.light
.position
.x
, app
.light
.position
.y
, app
.light
.position
.z
)
142 program
.coord
.array_enabled
= true
143 program
.coord
.array
(mesh
.vertices
, 3)
145 program
.tex_coord
.array_enabled
= true
146 program
.tex_coord
.array
(mesh
.texture_coords
, 2)
148 program
.normal
.array_enabled
= true
149 program
.normal
.array
(mesh
.normals
, 3)
152 program
.scale
.uniform
1.0
153 program
.rotation
.uniform
new Matrix.gamnit_euler_rotation
(actor
.pitch
, actor
.yaw
, actor
.roll
)
154 program
.translation
.uniform
(actor
.center
.x
, -actor
.center
.y
, actor
.center
.z
, 0.0)
155 program
.color
.uniform
(color
[0], color
[1], color
[2], color
[3])
156 program
.is_surface
.uniform is_surface
158 # Set the color texture?
161 program
.use_texture
.uniform
false
163 program
.use_texture
.uniform
true
164 program
.tex
.uniform tex
167 # Execute draw, support only meshes with `indices`
168 glDrawElements
(gl_TRIANGLES
, mesh
.indices
.length
, gl_UNSIGNED_SHORT
, mesh
.indices_c
.native_array
)
171 gl_error
= glGetError
172 assert gl_error
== gl_NO_ERROR
else print gl_error
176 # Graphical program to draw a planet with Phong lighting
178 super GamnitProgramFromSource
180 redef var vertex_shader_source
= """
181 // Vertex coordinates
182 attribute vec4 coord;
187 // Vertex translation
188 uniform vec4 translation;
193 // Vertex coordinates on textures
194 attribute vec2 tex_coord;
197 attribute vec3 normal;
199 // Model view projection matrix
203 uniform mat4 rotation;
206 uniform vec3 light_center;
208 // Texture of surface elevation to displace vertices
209 uniform sampler2D tex_displace;
211 // Draw this as a planet surface?
212 uniform bool is_surface;
214 // Output for the fragment shader
215 varying vec4 v_color;
216 varying vec2 v_tex_coord;
217 varying vec3 v_normal;
218 varying vec4 v_light_center;
223 v_tex_coord = tex_coord;
224 v_normal = normalize(vec4(normal, 0.0) * rotation * mvp).xyz;
225 v_light_center = vec4(light_center, 0.0) * mvp;
227 // Apply displacement map
230 s += 0.05 * texture2D(tex_displace, tex_coord).r;
232 gl_Position = (vec4(coord.xyz * s, 1.0) * rotation + translation) * mvp;
234 """ @ glsl_vertex_shader
236 redef var fragment_shader_source
= """
237 precision mediump float;
239 // Input from the vertex shader
240 varying vec4 v_color;
241 varying vec2 v_tex_coord;
242 varying vec3 v_normal;
243 varying vec4 v_light_center;
245 // Coordinates of the camera
248 // Does this object use a texture?
249 uniform bool use_texture;
251 // Texture to apply on this object
252 uniform sampler2D tex;
254 // Reflection map to apply to the Phong logic
255 uniform sampler2D tex_specular;
257 // Texture for the dark side of the earth
258 uniform sampler2D tex_night;
260 // Draw this as a planet surface?
261 uniform bool is_surface;
264 vec4 ambient_color = vec4(0.2, 0.2, 0.2, 1.0);
265 vec4 diffuse_color = vec4(1.0, 1.0, 1.0, 1.0);
266 vec4 specular_color = vec4(1.0, 1.0, 1.0, 1.0);
271 vec3 to_light = normalize(v_light_center.xyz);
272 float lambert = max(dot(to_light, v_normal), 0.0);
275 float specular = 0.0;
277 vec3 to_camera = normalize(camera);
278 vec3 normal = normalize(v_normal);
279 vec3 light_reflect = reflect(to_light, normal);
280 float spec_angle = max(dot(light_reflect, to_camera), 0.0);
281 specular = pow(spec_angle, 16.0);
284 specular *= texture2D(tex_specular, v_tex_coord).x;
285 else specular *= 0.2;
289 gl_FragColor = v_color * texture2D(tex, v_tex_coord);
291 gl_FragColor = v_color;
294 gl_FragColor *= ambient_color + lambert * diffuse_color;
295 gl_FragColor += specular * specular_color;
297 if (is_surface && lambert < 0.2) {
298 // Show city lights at night
299 float p_night = (0.2 - lambert) * 5.0;
300 gl_FragColor += p_night*texture2D(tex_night, v_tex_coord);
303 """ @ glsl_fragment_shader
305 # Vertices coordinates
306 var coord
= attributes
["coord"].as(AttributeVec4) is lazy
308 # Color tint per vertex
309 var color
= uniforms
["color"].as(UniformVec4) is lazy
312 var scale
= uniforms
["scale"].as(UniformFloat) is lazy
314 # Coordinates on the textures, per vertex
315 var tex_coord
= attributes
["tex_coord"].as(AttributeVec2) is lazy
318 var normal
= attributes
["normal"].as(AttributeVec3) is lazy
320 # Model view projection matrix
321 var mvp
= uniforms
["mvp"].as(UniformMat4) is lazy
323 # Should this program use the texture `tex`?
324 var use_texture
= uniforms
["use_texture"].as(UniformBool) is lazy
326 # Main visible texture unit
327 var tex
= uniforms
["tex"].as(UniformSampler2D) is lazy
329 # Texture unit for reflection effect
330 var tex_specular
= uniforms
["tex_specular"].as(UniformSampler2D) is lazy
332 # Texture of the earth at night
333 var tex_night
= uniforms
["tex_night"].as(UniformSampler2D) is lazy
335 # Texture with elevation data
336 var tex_displace
= uniforms
["tex_displace"].as(UniformSampler2D) is lazy
338 # Position of the camera
339 var camera
= uniforms
["camera"].as(UniformVec3) is lazy
341 # Execute this program to draw a planet surface?
342 var is_surface
= uniforms
["is_surface"].as(UniformBool) is lazy
344 # Translation applied to each vertex
345 var translation
= uniforms
["translation"].as(UniformVec4) is lazy
348 var rotation
= uniforms
["rotation"].as(UniformMat4) is lazy
350 # Center position of the light
351 var light_center
= uniforms
["light_center"].as(UniformVec3) is lazy