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, 1.0, 1.0, 0.5])
96 # Create and configure a material for the visible atmosphere
97 init atmo
do init(null, false, [0.0, 0.8, 1.0, 0.05])
99 redef fun draw
(actor
, model
)
101 var gl_error
= glGetError
102 assert gl_error
== gl_NO_ERROR
else print gl_error
104 var mesh
= model
.mesh
106 var program
= app
.globe_program
109 # Set constant program values
113 glActiveTexture gl_TEXTURE0
114 glBindTexture
(gl_TEXTURE_2D
, app
.texture_earth
.gl_texture
)
116 glActiveTexture gl_TEXTURE1
117 glBindTexture
(gl_TEXTURE_2D
, app
.texture_seas
.gl_texture
)
119 glActiveTexture gl_TEXTURE2
120 glBindTexture
(gl_TEXTURE_2D
, app
.texture_night
.gl_texture
)
122 glActiveTexture gl_TEXTURE3
123 glBindTexture
(gl_TEXTURE_2D
, app
.texture_elevation
.gl_texture
)
125 glActiveTexture gl_TEXTURE4
126 glBindTexture
(gl_TEXTURE_2D
, app
.texture_clouds
.gl_texture
)
129 program
.tex_specular
.uniform
1
130 program
.tex_night
.uniform
2
131 program
.tex_displace
.uniform
3
133 # Update camera view and light
134 var p
= app
.world_camera
.position
135 program
.camera
.uniform
(p
.x
, p
.y
, p
.z
)
136 program
.mvp
.uniform app
.world_camera
.mvp_matrix
137 program
.light_center
.uniform
(app
.light
.position
.x
, app
.light
.position
.y
, app
.light
.position
.z
)
140 program
.coord
.array_enabled
= true
141 program
.coord
.array
(mesh
.vertices
, 3)
143 program
.tex_coord
.array_enabled
= true
144 program
.tex_coord
.array
(mesh
.texture_coords
, 2)
146 program
.normal
.array_enabled
= true
147 program
.normal
.array
(mesh
.normals
, 3)
150 program
.scale
.uniform
1.0
151 program
.rotation
.uniform
new Matrix.gamnit_euler_rotation
(actor
.pitch
, actor
.yaw
, actor
.roll
)
152 program
.translation
.uniform
(actor
.center
.x
, -actor
.center
.y
, actor
.center
.z
, 0.0)
153 program
.color
.uniform
(color
[0], color
[1], color
[2], color
[3])
154 program
.is_surface
.uniform is_surface
156 # Set the color texture?
159 program
.use_texture
.uniform
false
161 program
.use_texture
.uniform
true
162 program
.tex
.uniform tex
165 # Execute draw, support only meshes with `indices`
166 glDrawElements
(gl_TRIANGLES
, mesh
.indices
.length
, gl_UNSIGNED_SHORT
, mesh
.indices_c
.native_array
)
169 gl_error
= glGetError
170 assert gl_error
== gl_NO_ERROR
else print gl_error
174 # Graphical program to draw a planet with Phong lighting
176 super GamnitProgramFromSource
178 redef var vertex_shader_source
= """
179 // Vertex coordinates
180 attribute vec4 coord;
185 // Vertex translation
186 uniform vec4 translation;
191 // Vertex coordinates on textures
192 attribute vec2 tex_coord;
195 attribute vec3 normal;
197 // Model view projection matrix
201 uniform mat4 rotation;
204 uniform vec3 light_center;
206 // Texture of surface elevation to displace vertices
207 uniform sampler2D tex_displace;
209 // Draw this as a planet surface?
210 uniform bool is_surface;
212 // Output for the fragment shader
213 varying vec4 v_color;
214 varying vec2 v_tex_coord;
215 varying vec3 v_normal;
216 varying vec4 v_light_center;
221 v_tex_coord = tex_coord;
222 v_normal = normalize(vec4(normal, 0.0) * rotation * mvp).xyz;
223 v_light_center = vec4(light_center, 0.0) * mvp;
225 // Apply displacement map
228 s += 0.05 * texture2D(tex_displace, tex_coord).r;
230 gl_Position = (vec4(coord.xyz * s, 1.0) * rotation + translation) * mvp;
233 """ @ glsl_vertex_shader
235 redef var fragment_shader_source
= """
236 precision mediump float;
238 // Input from the vertex shader
239 varying vec4 v_color;
240 varying vec2 v_tex_coord;
241 varying vec3 v_normal;
242 varying vec4 v_light_center;
244 // Coordinates of the camera
247 // Does this object use a texture?
248 uniform bool use_texture;
250 // Texture to apply on this object
251 uniform sampler2D tex;
253 // Reflection map to apply to the Phong logic
254 uniform sampler2D tex_specular;
256 // Texture for the dark side of the earth
257 uniform sampler2D tex_night;
259 // Draw this as a planet surface?
260 uniform bool is_surface;
263 vec4 ambient_color = vec4(0.2, 0.2, 0.2, 1.0);
264 vec4 diffuse_color = vec4(1.0, 1.0, 1.0, 1.0);
265 vec4 specular_color = vec4(1.0, 1.0, 1.0, 1.0);
270 vec3 to_light = normalize(v_light_center.xyz);
271 float lambert = max(dot(to_light, v_normal), 0.0);
274 float specular = 0.0;
276 vec3 to_camera = normalize(camera);
277 vec3 normal = normalize(v_normal);
278 vec3 light_reflect = reflect(to_light, normal);
279 float spec_angle = max(dot(light_reflect, to_camera), 0.0);
280 specular = pow(spec_angle, 16.0);
283 specular *= texture2D(tex_specular, v_tex_coord).x;
284 else specular *= 0.2;
288 gl_FragColor = v_color * texture2D(tex, v_tex_coord);
290 gl_FragColor = v_color;
293 gl_FragColor *= ambient_color + lambert * diffuse_color;
294 gl_FragColor += specular * specular_color;
296 if (is_surface && lambert < 0.2) {
297 // Show city lights at night
298 float p_night = (0.2 - lambert) * 5.0;
299 gl_FragColor += p_night*texture2D(tex_night, v_tex_coord);
302 """ @ glsl_fragment_shader
304 # Vertices coordinates
305 var coord
= attributes
["coord"].as(AttributeVec4) is lazy
307 # Color tint per vertex
308 var color
= uniforms
["color"].as(UniformVec4) is lazy
311 var scale
= uniforms
["scale"].as(UniformFloat) is lazy
313 # Coordinates on the textures, per vertex
314 var tex_coord
= attributes
["tex_coord"].as(AttributeVec2) is lazy
317 var normal
= attributes
["normal"].as(AttributeVec3) is lazy
319 # Model view projection matrix
320 var mvp
= uniforms
["mvp"].as(UniformMat4) is lazy
322 # Should this program use the texture `tex`?
323 var use_texture
= uniforms
["use_texture"].as(UniformBool) is lazy
325 # Main visible texture unit
326 var tex
= uniforms
["tex"].as(UniformSampler2D) is lazy
328 # Texture unit for reflection effect
329 var tex_specular
= uniforms
["tex_specular"].as(UniformSampler2D) is lazy
331 # Texture of the earth at night
332 var tex_night
= uniforms
["tex_night"].as(UniformSampler2D) is lazy
334 # Texture with elevation data
335 var tex_displace
= uniforms
["tex_displace"].as(UniformSampler2D) is lazy
337 # Position of the camera
338 var camera
= uniforms
["camera"].as(UniformVec3) is lazy
340 # Execute this program to draw a planet surface?
341 var is_surface
= uniforms
["is_surface"].as(UniformBool) is lazy
343 # Translation applied to each vertex
344 var translation
= uniforms
["translation"].as(UniformVec4) is lazy
347 var rotation
= uniforms
["rotation"].as(UniformMat4) is lazy
349 # Center position of the light
350 var light_center
= uniforms
["light_center"].as(UniformVec3) is lazy