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
, camera
)
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
112 glActiveTexture gl_TEXTURE0
113 glBindTexture
(gl_TEXTURE_2D
, app
.texture_earth
.gl_texture
)
115 glActiveTexture gl_TEXTURE1
116 glBindTexture
(gl_TEXTURE_2D
, app
.texture_seas
.gl_texture
)
118 glActiveTexture gl_TEXTURE2
119 glBindTexture
(gl_TEXTURE_2D
, app
.texture_night
.gl_texture
)
121 glActiveTexture gl_TEXTURE3
122 glBindTexture
(gl_TEXTURE_2D
, app
.texture_elevation
.gl_texture
)
124 glActiveTexture gl_TEXTURE4
125 glBindTexture
(gl_TEXTURE_2D
, app
.texture_clouds
.gl_texture
)
128 program
.tex_specular
.uniform
1
129 program
.tex_night
.uniform
2
130 program
.tex_displace
.uniform
3
132 # Update camera view and light
133 var p
= app
.world_camera
.position
134 program
.camera
.uniform
(p
.x
, p
.y
, p
.z
)
135 program
.mvp
.uniform camera
.mvp_matrix
136 program
.light_center
.uniform
(app
.light
.position
.x
, app
.light
.position
.y
, app
.light
.position
.z
)
139 program
.coord
.array_enabled
= true
140 program
.coord
.array
(mesh
.vertices
, 3)
142 program
.tex_coord
.array_enabled
= true
143 program
.tex_coord
.array
(mesh
.texture_coords
, 2)
145 program
.normal
.array_enabled
= true
146 program
.normal
.array
(mesh
.normals
, 3)
149 program
.scale
.uniform
1.0
150 program
.rotation
.uniform
new Matrix.gamnit_euler_rotation
(actor
.pitch
, actor
.yaw
, actor
.roll
)
151 program
.translation
.uniform
(actor
.center
.x
, -actor
.center
.y
, actor
.center
.z
, 0.0)
152 program
.color
.uniform
(color
[0], color
[1], color
[2], color
[3])
153 program
.is_surface
.uniform is_surface
155 # Set the color texture?
158 program
.use_texture
.uniform
false
160 program
.use_texture
.uniform
true
161 program
.tex
.uniform tex
164 # Execute draw, support only meshes with `indices`
165 glDrawElements
(gl_TRIANGLES
, mesh
.indices
.length
, gl_UNSIGNED_SHORT
, mesh
.indices_c
.native_array
)
168 gl_error
= glGetError
169 assert gl_error
== gl_NO_ERROR
else print gl_error
173 # Graphical program to draw a planet with Phong lighting
175 super GamnitProgramFromSource
177 redef var vertex_shader_source
= """
178 // Vertex coordinates
179 attribute vec4 coord;
184 // Vertex translation
185 uniform vec4 translation;
190 // Vertex coordinates on textures
191 attribute vec2 tex_coord;
194 attribute vec3 normal;
196 // Model view projection matrix
200 uniform mat4 rotation;
203 uniform vec3 light_center;
205 // Texture of surface elevation to displace vertices
206 uniform sampler2D tex_displace;
208 // Draw this as a planet surface?
209 uniform bool is_surface;
211 // Output for the fragment shader
212 varying vec4 v_color;
213 varying vec2 v_tex_coord;
214 varying vec3 v_normal;
215 varying vec4 v_light_center;
220 v_tex_coord = tex_coord;
221 v_normal = normalize(vec4(normal, 0.0) * rotation * mvp).xyz;
222 v_light_center = vec4(light_center, 0.0) * mvp;
224 // Apply displacement map
227 s += 0.05 * texture2D(tex_displace, tex_coord).r;
229 gl_Position = (vec4(coord.xyz * s, 1.0) * rotation + translation) * mvp;
231 """ @ glsl_vertex_shader
233 redef var fragment_shader_source
= """
234 precision mediump float;
236 // Input from the vertex shader
237 varying vec4 v_color;
238 varying vec2 v_tex_coord;
239 varying vec3 v_normal;
240 varying vec4 v_light_center;
242 // Coordinates of the camera
245 // Does this object use a texture?
246 uniform bool use_texture;
248 // Texture to apply on this object
249 uniform sampler2D tex;
251 // Reflection map to apply to the Phong logic
252 uniform sampler2D tex_specular;
254 // Texture for the dark side of the earth
255 uniform sampler2D tex_night;
257 // Draw this as a planet surface?
258 uniform bool is_surface;
261 vec4 ambient_color = vec4(0.2, 0.2, 0.2, 1.0);
262 vec4 diffuse_color = vec4(1.0, 1.0, 1.0, 1.0);
263 vec4 specular_color = vec4(1.0, 1.0, 1.0, 1.0);
268 vec3 to_light = normalize(v_light_center.xyz);
269 float lambert = max(dot(to_light, v_normal), 0.0);
272 float specular = 0.0;
274 vec3 to_camera = normalize(camera);
275 vec3 normal = normalize(v_normal);
276 vec3 light_reflect = reflect(to_light, normal);
277 float spec_angle = max(dot(light_reflect, to_camera), 0.0);
278 specular = pow(spec_angle, 16.0);
281 specular *= texture2D(tex_specular, v_tex_coord).x;
282 else specular *= 0.2;
286 gl_FragColor = v_color * texture2D(tex, v_tex_coord);
288 gl_FragColor = v_color;
291 gl_FragColor *= ambient_color + lambert * diffuse_color;
292 gl_FragColor += specular * specular_color;
294 if (is_surface && lambert < 0.2) {
295 // Show city lights at night
296 float p_night = (0.2 - lambert) * 5.0;
297 gl_FragColor += p_night*texture2D(tex_night, v_tex_coord);
300 """ @ glsl_fragment_shader
302 # Vertices coordinates
303 var coord
= attributes
["coord"].as(AttributeVec4) is lazy
305 # Color tint per vertex
306 var color
= uniforms
["color"].as(UniformVec4) is lazy
309 var scale
= uniforms
["scale"].as(UniformFloat) is lazy
311 # Coordinates on the textures, per vertex
312 var tex_coord
= attributes
["tex_coord"].as(AttributeVec2) is lazy
315 var normal
= attributes
["normal"].as(AttributeVec3) is lazy
317 # Model view projection matrix
318 var mvp
= uniforms
["mvp"].as(UniformMat4) is lazy
320 # Should this program use the texture `tex`?
321 var use_texture
= uniforms
["use_texture"].as(UniformBool) is lazy
323 # Main visible texture unit
324 var tex
= uniforms
["tex"].as(UniformSampler2D) is lazy
326 # Texture unit for reflection effect
327 var tex_specular
= uniforms
["tex_specular"].as(UniformSampler2D) is lazy
329 # Texture of the earth at night
330 var tex_night
= uniforms
["tex_night"].as(UniformSampler2D) is lazy
332 # Texture with elevation data
333 var tex_displace
= uniforms
["tex_displace"].as(UniformSampler2D) is lazy
335 # Position of the camera
336 var camera
= uniforms
["camera"].as(UniformVec3) is lazy
338 # Execute this program to draw a planet surface?
339 var is_surface
= uniforms
["is_surface"].as(UniformBool) is lazy
341 # Translation applied to each vertex
342 var translation
= uniforms
["translation"].as(UniformVec4) is lazy
345 var rotation
= uniforms
["rotation"].as(UniformMat4) is lazy
347 # Center position of the light
348 var light_center
= uniforms
["light_center"].as(UniformVec3) is lazy