--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Intro a custom model, material and graphics program to draw a globe
+module globe
+
+intrude import gamnit::depth # To access `Mesh::indices_c`
+
+# Number of vertices to create parallels, meridians are double of this
+#
+# The minimum should be 3 for an octahedron planet.
+fun n_parallels: Int do return 25
+
+redef class App
+
+ # Program for the graphic card
+ private var globe_program = new GlobeProgram
+
+ # Texture of the reflexive surface of the earth (with the seas in white)
+ private var texture_seas = new Texture("globe/seas.jpg")
+
+ # Texture of the surface of the earth
+ private var texture_earth = new Texture("globe/earth.jpg")
+
+ # Texture of the lights at night on earth
+ private var texture_night = new Texture("globe/lights.jpg")
+
+ # Elevation map of earth
+ private var texture_elevation = new Texture("globe/elevation.jpg")
+
+ # Texture of the clouds above the earth
+ private var texture_clouds = new Texture("globe/clouds.png")
+
+ redef fun on_create
+ do
+ super
+
+ # Compile globe_program
+ var program = app.globe_program
+ program.compile_and_link
+
+ # Catch any errors
+ var gamnit_error = program.error
+ assert gamnit_error == null else print_error gamnit_error
+ end
+end
+
+# Full model of a globe, with a surface, clouds layer and atmosphere
+class GlobeModel
+ super CompositeModel
+
+ redef fun load
+ do
+ leaves.add new LeafModel(
+ new Mesh.uv_sphere(1.0, 2*n_parallels, n_parallels),
+ new GlobeMaterial.surface)
+ leaves.add new LeafModel(
+ new Mesh.uv_sphere(1.1, 2*n_parallels, n_parallels),
+ new GlobeMaterial.clouds)
+ leaves.add new LeafModel(
+ new Mesh.uv_sphere(1.2, 2*n_parallels, n_parallels),
+ new GlobeMaterial.atmo)
+ end
+end
+
+# Parameterizable material to draw the 3 layers of the globe
+class GlobeMaterial
+ super Material
+
+ # Id of the texture for diffuse colors, if any
+ var texture_id: nullable Int
+
+ # Draw as a surface, using the elevation map and the night lights
+ var is_surface: Bool
+
+ # Ambient color
+ var color: Array[Float]
+
+ # Create and configure a material for the earth surface
+ init surface do init(0, true, [1.0, 1.0, 1.0, 1.0])
+
+ # Create and configure a material for the cloud layer
+ init clouds do init(4, false, [1.0, 1.0, 1.0, 0.25])
+
+ # Create and configure a material for the visible atmosphere
+ init atmo do init(null, false, [0.0, 0.8, 1.0, 0.05])
+
+ redef fun draw(actor, model)
+ do
+ var gl_error = glGetError
+ assert gl_error == gl_NO_ERROR else print gl_error
+
+ var mesh = model.mesh
+
+ var program = app.globe_program
+ program.use
+
+ # Set constant program values
+ program.use
+
+ # Bind textures
+ glActiveTexture gl_TEXTURE0
+ glBindTexture(gl_TEXTURE_2D, app.texture_earth.gl_texture)
+
+ glActiveTexture gl_TEXTURE1
+ glBindTexture(gl_TEXTURE_2D, app.texture_seas.gl_texture)
+
+ glActiveTexture gl_TEXTURE2
+ glBindTexture(gl_TEXTURE_2D, app.texture_night.gl_texture)
+
+ glActiveTexture gl_TEXTURE3
+ glBindTexture(gl_TEXTURE_2D, app.texture_elevation.gl_texture)
+
+ glActiveTexture gl_TEXTURE4
+ glBindTexture(gl_TEXTURE_2D, app.texture_clouds.gl_texture)
+
+ # Set samplers
+ program.tex_specular.uniform 1
+ program.tex_night.uniform 2
+ program.tex_displace.uniform 3
+
+ # Update camera view and light
+ var p = app.world_camera.position
+ program.camera.uniform(p.x, p.y, p.z)
+ program.mvp.uniform app.world_camera.mvp_matrix
+ program.light_center.uniform(app.light.position.x, app.light.position.y, app.light.position.z)
+
+ # Set attributes
+ program.coord.array_enabled = true
+ program.coord.array(mesh.vertices, 3)
+
+ program.tex_coord.array_enabled = true
+ program.tex_coord.array(mesh.texture_coords, 2)
+
+ program.normal.array_enabled = true
+ program.normal.array(mesh.normals, 3)
+
+ # Set uniforms
+ program.scale.uniform 1.0
+ program.rotation.uniform new Matrix.rotation(actor.rotation, 0.0, 1.0, 0.0)
+ program.translation.uniform(actor.center.x, -actor.center.y, actor.center.z, 0.0)
+ program.color.uniform(color[0], color[1], color[2], color[3])
+ program.is_surface.uniform is_surface
+
+ # Set the color texture?
+ var tex = texture_id
+ if tex == null then
+ program.use_texture.uniform false
+ else
+ program.use_texture.uniform true
+ program.tex.uniform tex
+ end
+
+ # Execute draw, support only meshes with `indices`
+ glDrawElements(gl_TRIANGLES, mesh.indices.length, gl_UNSIGNED_SHORT, mesh.indices_c.native_array)
+
+ # Catch any errors
+ gl_error = glGetError
+ assert gl_error == gl_NO_ERROR else print gl_error
+ end
+end
+
+# Graphical program to draw a planet with Phong lighting
+class GlobeProgram
+ super GamnitProgramFromSource
+
+ redef var vertex_shader_source = """
+ // Vertex coordinates
+ attribute vec4 coord;
+
+ // Vertex color tint
+ uniform vec4 color;
+
+ // Vertex translation
+ uniform vec4 translation;
+
+ // Vertex scaling
+ uniform float scale;
+
+ // Vertex coordinates on textures
+ attribute vec2 tex_coord;
+
+ // Vertex normal
+ attribute vec3 normal;
+
+ // Model view projection matrix
+ uniform mat4 mvp;
+
+ // Model rotation
+ uniform mat4 rotation;
+
+ // Lights config
+ uniform vec3 light_center;
+
+ // Texture of surface elevation to displace vertices
+ uniform sampler2D tex_displace;
+
+ // Draw this as a planet surface?
+ uniform bool is_surface;
+
+ // Output for the fragment shader
+ varying vec4 v_color;
+ varying vec2 v_tex_coord;
+ varying vec3 v_normal;
+ varying vec4 v_light_center;
+
+ void main()
+ {
+ v_color = color;
+ v_tex_coord = tex_coord;
+ v_normal = normalize(vec4(normal, 0.0) * rotation * mvp).xyz;
+ v_light_center = vec4(light_center, 0.0) * mvp;
+
+ // Apply displacement map
+ float s = scale;
+ if (is_surface)
+ s += 0.05 * texture2D(tex_displace, tex_coord).r;
+
+ gl_Position = (vec4(coord.xyz * s, 1.0) * rotation + translation) * mvp;
+
+ }
+ """ @ glsl_vertex_shader
+
+ redef var fragment_shader_source = """
+ precision mediump float;
+
+ // Input from the vertex shader
+ varying vec4 v_color;
+ varying vec2 v_tex_coord;
+ varying vec3 v_normal;
+ varying vec4 v_light_center;
+
+ // Coordinates of the camera
+ uniform vec3 camera;
+
+ // Does this object use a texture?
+ uniform bool use_texture;
+
+ // Texture to apply on this object
+ uniform sampler2D tex;
+
+ // Reflection map to apply to the Phong logic
+ uniform sampler2D tex_specular;
+
+ // Texture for the dark side of the earth
+ uniform sampler2D tex_night;
+
+ // Draw this as a planet surface?
+ uniform bool is_surface;
+
+ // Colors config
+ vec4 ambient_color = vec4(0.2, 0.2, 0.2, 1.0);
+ vec4 diffuse_color = vec4(1.0, 1.0, 1.0, 1.0);
+ vec4 specular_color = vec4(1.0, 1.0, 1.0, 1.0);
+
+ void main()
+ {
+ // Lambert diffusion
+ vec3 to_light = normalize(v_light_center.xyz);
+ float lambert = max(dot(to_light, v_normal), 0.0);
+
+ // Phong specular
+ float specular = 0.0;
+ if (lambert > 0.0) {
+ vec3 to_camera = normalize(camera);
+ vec3 normal = normalize(v_normal);
+ vec3 light_reflect = reflect(to_light, normal);
+ float spec_angle = max(dot(light_reflect, to_camera), 0.0);
+ specular = pow(spec_angle, 16.0);
+
+ if (is_surface)
+ specular *= texture2D(tex_specular, v_tex_coord).x;
+ else specular *= 0.2;
+ }
+
+ if(use_texture) {
+ gl_FragColor = v_color * texture2D(tex, v_tex_coord);
+ } else {
+ gl_FragColor = v_color;
+ }
+
+ gl_FragColor *= ambient_color + lambert * diffuse_color;
+ gl_FragColor += specular * specular_color;
+
+ if (is_surface && lambert < 0.2) {
+ // Show city lights at night
+ float p_night = (0.2 - lambert) * 5.0;
+ gl_FragColor += p_night*texture2D(tex_night, v_tex_coord);
+ }
+ }
+ """ @ glsl_fragment_shader
+
+ # Vertices coordinates
+ var coord = attributes["coord"].as(AttributeVec4) is lazy
+
+ # Color tint per vertex
+ var color = uniforms["color"].as(UniformVec4) is lazy
+
+ # Scaling per vertex
+ var scale = uniforms["scale"].as(UniformFloat) is lazy
+
+ # Coordinates on the textures, per vertex
+ var tex_coord = attributes["tex_coord"].as(AttributeVec2) is lazy
+
+ # Normal per vertex
+ var normal = attributes["normal"].as(AttributeVec3) is lazy
+
+ # Model view projection matrix
+ var mvp = uniforms["mvp"].as(UniformMat4) is lazy
+
+ # Should this program use the texture `tex`?
+ var use_texture = uniforms["use_texture"].as(UniformBool) is lazy
+
+ # Main visible texture unit
+ var tex = uniforms["tex"].as(UniformSampler2D) is lazy
+
+ # Texture unit for reflection effect
+ var tex_specular = uniforms["tex_specular"].as(UniformSampler2D) is lazy
+
+ # Texture of the earth at night
+ var tex_night = uniforms["tex_night"].as(UniformSampler2D) is lazy
+
+ # Texture with elevation data
+ var tex_displace = uniforms["tex_displace"].as(UniformSampler2D) is lazy
+
+ # Position of the camera
+ var camera = uniforms["camera"].as(UniformVec3) is lazy
+
+ # Execute this program to draw a planet surface?
+ var is_surface = uniforms["is_surface"].as(UniformBool) is lazy
+
+ # Translation applied to each vertex
+ var translation = uniforms["translation"].as(UniformVec4) is lazy
+
+ # Rotation matrix
+ var rotation = uniforms["rotation"].as(UniformMat4) is lazy
+
+ # Center position of the light
+ var light_center = uniforms["light_center"].as(UniformVec3) is lazy
+end
import gamnit::depth
+import globe
+
redef class App
# All available models
new LeafModel(new Mesh.uv_sphere(4.0, 32, 16), new NormalsMaterial),
new Model("models/Tree_01.obj"),
new Model("models/Oak_Fall_01.obj"),
- new Model("models/Quandtum_BA-2_v1_1.obj")]
+ new Model("models/Quandtum_BA-2_v1_1.obj"),
+ new GlobeModel]
# Index of the current model in `models`
var model_index = 0
actor.center.z -= model.mesh.center.z
var height = model.mesh.dimensions.y
- world_camera.reset_height(height * 4.0)
+ world_camera.reset_height(height * 3.0)
actors.clear
actors.add actor
+++ /dev/null
-NITC=../../../../bin/nitc
-NITLS=../../../../bin/nitls
-
-all: bin/globe
-
-bin/globe: $(shell ${NITLS} -M src/globe.nit linux) ${NITC}
- ${NITC} src/globe.nit -m linux -o $@ -D n_parallels=100
-
-check: bin/globe
- bin/globe
-
-# ---
-# Android
-
-android: bin/globe.apk
-bin/globe.apk: $(shell ${NITLS} -M src/globe.nit android) ${NITC} res/drawable-hdpi/icon.png assets/ld/earth.jpg
- ${NITC} src/globe.nit -m android -o $@
-
-android-release: $(shell ${NITLS} -M src/globe.nit android) ${NITC} res/drawable-hdpi/icon.png assets/ld/earth.jpg
- ${NITC} src/globe.nit -m android -o bin/globe.apk --release
-
-android-wear: $(shell ${NITLS} -M src/globe.nit android) ${NITC} res/drawable-hdpi/icon.png assets/ld/earth.jpg
- ${NITC} src/globe.nit -m android -o bin/planet_wear.apk -D n_parallels=10
-
-res/drawable-hdpi/icon.png: art/icon.png
- mkdir -p res/drawable-ldpi/ res/drawable-mdpi/ res/drawable-hdpi/ \
- res/drawable-xhdpi/ res/drawable-xxhdpi/ res/drawable-xxxhdpi/
- convert -resize 36x36 art/icon.png res/drawable-ldpi/icon.png
- convert -resize 48x48 art/icon.png res/drawable-mdpi/icon.png
- convert -resize 72x72 art/icon.png res/drawable-hdpi/icon.png
- convert -resize 96x96 art/icon.png res/drawable-xhdpi/icon.png
- convert -resize 144x144 art/icon.png res/drawable-xxhdpi/icon.png
- convert -resize 192x192 art/icon.png res/drawable-xxxhdpi/icon.png
-
-assets/ld/earth.jpg:
- mkdir -p assets/ld
- convert -resize 2048x1024 assets/hd/earth.jpg assets/ld/earth.jpg
- convert -resize 2048x1024 assets/hd/seas.jpg assets/ld/seas.jpg
- convert -resize 2048x1024 assets/hd/clouds.png assets/ld/clouds.png
- convert -resize 2048x1024 assets/hd/elevation.jpg assets/ld/elevation.jpg
- convert -resize 2048x1024 assets/hd/lights.jpg assets/ld/lights.jpg
+++ /dev/null
-Sample gamnit app rendering the earth with elevated surface, cloud layer, city lights and Phong lighting.
-
-# Possible variations
-
-It would have been possible to achieve the same result with different approaches.
-They should be explored as they could provide better performances or be easier to understand.
-
-* Use a single set of vertices, normals and indices because we only need spheres.
-* Alternatively, use one program per sphere.
-
-# Art
-
-Images credit: NASA, Visible Earth
+++ /dev/null
-Categories:Nit,Multimedia
-License:Apache2
-Web Site:http://nitlanguage.org
-Source Code:http://nitlanguage.org/nit.git/tree/HEAD:/lib/gamnit/examples/globe
-Issue Tracker:https://github.com/nitlang/nit/issues
-
-Summary:Simple rotating globe of the earth
-Description:
-Non-interactive sample gamnit app rendering the earth with elevated surface, cloud layer, city lights and Phong lighting.
-.
+++ /dev/null
-[package]
-name=globe
-tags=example
-maintainer=Alexis Laferrière <alexis.laf@xymus.net>
-license=Apache-2.0
-[upstream]
-browse=https://github.com/nitlang/nit/tree/master/lib/gamnit/examples/globe/
-git=https://github.com/nitlang/nit.git
-git.directory=lib/gamnit/examples/globe/
-homepage=http://nitlanguage.org
-issues=https://github.com/nitlang/nit/issues
-apk=http://nitlanguage.org/fdroid/apk/globe.apk
+++ /dev/null
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Portable app using gamnit textures and programs with custom calls to OpenGL ES 2.0
-module globe is
- app_name "gamnit Globe"
- app_namespace "org.nitlanguage.globe"
- app_version(1, 0, git_revision)
-
- android_manifest_activity """android:screenOrientation="portrait""""
- android_api_target 15
-end
-
-import realtime
-import matrix::projection
-
-import gamnit
-import gamnit::cameras
-import gamnit::limit_fps
-
-private import more_collections
-
-# Graphical program to draw a planet with Phong lighting
-class GlobeProgram
- super GamnitProgramFromSource
-
- redef var vertex_shader_source = """
- // Vertex coordinates
- attribute vec4 coord;
-
- // Vertex color tint
- attribute vec4 color;
-
- // Vertex translation
- attribute vec4 translation;
-
- // Vertex scaling
- attribute float scale;
-
- // Vertex coordinates on textures
- attribute vec2 tex_coord;
-
- // Vertex normal
- attribute vec3 normal;
-
- // Model view projection matrix
- uniform mat4 mvp;
-
- // Texture of surface elevation to displace vertices
- uniform sampler2D tex_displace;
-
- // Draw this as a planet surface?
- uniform bool is_surface;
-
- // Output for the fragment shader
- varying vec4 v_color;
- varying vec2 v_tex_coord;
- varying vec3 v_normal;
-
- void main()
- {
- // Pass varyings to the fragment shader
- v_color = color;
- v_tex_coord = tex_coord;
- v_normal = normal;
-
- // Apply bump map
- float s = scale;
- if (is_surface)
- s += 0.05 * texture2D(tex_displace, tex_coord).r;
-
- gl_Position = (vec4(coord.xyz * s, 1.0) + translation) * mvp;
- }
- """ @ glsl_vertex_shader
-
- redef var fragment_shader_source = """
- precision mediump float;
-
- // Input from the vertex shader
- varying vec4 v_color;
- varying vec2 v_tex_coord;
- varying vec3 v_normal;
-
- // Coordinates of the camera
- uniform vec3 camera;
-
- // Does this object use a texture?
- uniform bool use_texture;
-
- // Texture to apply on this object
- uniform sampler2D tex;
-
- // Reflection map to apply the the phong logic
- uniform sampler2D tex_shiny;
-
- // Texture for the dark side of the earth
- uniform sampler2D tex_night;
-
- // Draw this as a planet surface?
- uniform bool is_surface;
-
- // Lights config
- // TODO configure from outside the shader
- vec3 light_dir = normalize(vec3(-1.0, 0.0, -1.0));
- vec4 ambient_color = vec4(0.2, 0.2, 0.2, 1.0);
- vec4 diffuse_color = vec4(1.0, 1.0, 1.0, 1.0);
- vec4 specular_color = vec4(1.0, 1.0, 1.0, 1.0);
-
- void main()
- {
- if(use_texture) {
- gl_FragColor = v_color * texture2D(tex, v_tex_coord);
- } else {
- gl_FragColor = v_color;
- }
-
- // Lambert diffusion
- float lambert = max(dot(light_dir, v_normal), 0.0);
-
- // Phong specular
- float specular = 0.0;
- if (lambert > 0.0) {
- vec3 to_camera = normalize(camera);
- vec3 light_reflect = reflect(light_dir, v_normal);
- float specularAngle = max(dot(light_reflect, to_camera), 0.0);
- specular = pow(specularAngle, 16.0);
-
- if (is_surface)
- specular *= texture2D(tex_shiny, v_tex_coord).x;
- else specular *= 0.2;
- }
-
- gl_FragColor *= ambient_color + lambert * diffuse_color;
- gl_FragColor += specular * specular_color;
-
- if (is_surface && lambert < 0.2) {
- // Show city lights at night
- float p_night = (0.2 - lambert) * 5.0;
- gl_FragColor += p_night*texture2D(tex_night, v_tex_coord);
- }
- }
- """ @ glsl_fragment_shader
-
- # Vertices coordinates
- var coord = attributes["coord"].as(AttributeVec4) is lazy
-
- # Color tint per vertex
- var color = attributes["color"].as(AttributeVec4) is lazy
-
- # Scaling per vertex
- var scale = attributes["scale"].as(AttributeFloat) is lazy
-
- # Coordinates on the textures, per vertex
- var tex_coord = attributes["tex_coord"].as(AttributeVec2) is lazy
-
- # Normal per vertex
- var normal = attributes["normal"].as(AttributeVec3) is lazy
-
- # Model view projection matrix
- var mvp = uniforms["mvp"].as(UniformMat4) is lazy
-
- # Should this program use the texture `tex`?
- var use_texture = uniforms["use_texture"].as(UniformBool) is lazy
-
- # Main visible texture unit
- var tex = uniforms["tex"].as(UniformSampler2D) is lazy
-
- # Texture unit for reflection effect
- var tex_shiny = uniforms["tex_shiny"].as(UniformSampler2D) is lazy
-
- # Texture of the earth at night
- var tex_night = uniforms["tex_night"].as(UniformSampler2D) is lazy
-
- # Texture with elevation data
- var tex_displace = uniforms["tex_displace"].as(UniformSampler2D) is lazy
-
- # Position of the camera
- var camera = uniforms["camera"].as(UniformVec3) is lazy
-
- # Execute this program to draw a planet surface?
- var is_surface = uniforms["is_surface"].as(UniformBool) is lazy
-end
-
-# Mesh with all information for drawing
-class Mesh
-
- # Vertices coordinates
- var vertices: Array[Float]
-
- # Indices to draw triangles
- var indices: Array[Int]
-
- private var indices_c = new CUInt16Array.from(indices) is lazy
-
- # Normals on each vertex
- var normals: Array[Float]
-
- # Coordinates on the texture per vertex
- var texture_coords: Array[Float]
-
- # Create an UV sphere of `radius` with `n_meridians` and `n_parallels`
- init uv_sphere(radius: Float, n_meridians, n_parallels: Int)
- do
- var w = n_meridians
- var h = n_parallels
-
- var vertices = new Array[Float].with_capacity(w*h*3)
- var texture_coords = new Array[Float].with_capacity(w*h*2)
- var normals = new Array[Float].with_capacity(w*h*3)
-
- # Build vertices
- for m in [0..w[ do
- for p in [0..h[ do
- var u = m.to_f * 2.0 * pi / (w-1).to_f
- var v = p.to_f * pi / (h-1).to_f
-
- vertices.add radius * u.cos * v.sin
- vertices.add radius * v.cos
- vertices.add radius * u.sin * v.sin
-
- texture_coords.add (1.0 - m.to_f/(w-1).to_f)
- texture_coords.add(p.to_f/(h-1).to_f)
-
- normals.add u.cos * v.sin
- normals.add v.cos
- normals.add u.sin * v.sin
- end
- end
-
- # Build faces
- var indices = new Array[Int].with_capacity((w-1)*(h-1)*6)
- for m in [0..w-1[ do
- for p in [0..h-1[ do
- var a = m*h + p
-
- indices.add a
- indices.add(a+h)
- indices.add(a+1)
-
- indices.add(a+h)
- indices.add(a+h+1)
- indices.add(a+1)
- end
- end
-
- init(vertices, indices, normals, texture_coords)
- end
-end
-
-# Number of vertices to create parallels, meridians are double of this
-#
-# The minimum should be 3 for an octahedron planet.
-fun n_parallels: Int do return 25
-
-redef class GamnitAssetTexture
- # All images are either within the hd or ld folder
- redef fun path do return app.definition / super
-end
-
-redef class App
-
- # Earth
- var planet = new Mesh.uv_sphere(2.0, 2*n_parallels, n_parallels)
-
- # Cloud layer
- var clouds = new Mesh.uv_sphere(2.08, 2*n_parallels, n_parallels)
-
- # Visible atmosphere
- var atmo = new Mesh.uv_sphere(2.16, 2*n_parallels, n_parallels)
-
- # Program for the graphic card
- var program = new GlobeProgram
-
- private var definition: String is lazy do
- var max_texture_size = glGetIntegerv(gl_MAX_TEXTURE_SIZE)
-
- # HD textures max sizes reange from 2048 px to 5400 px
- if max_texture_size < 5400 then
- return "ld"
- else return "hd"
- end
-
- # Texture of the reflexive surface of the earth (with the seas in white)
- var texture_seas = new Texture("seas.jpg")
-
- # Texture of the surface of the earth
- var texture_earth = new Texture("earth.jpg")
-
- # Texture of the lights at night on earth
- var texture_night = new Texture("lights.jpg")
-
- # Elevation map of earth
- var texture_elevation = new Texture("elevation.jpg")
-
- # Texture of the clouds above the earth
- var texture_clouds = new Texture("clouds.png")
-
- # Camera for the only view
- var camera: EulerCamera is lazy do
- var camera = new EulerCamera(app.display.as(not null))
- camera.move(0.0, 0.1, -5.0)
- return camera
- end
-
- redef fun on_create
- do
- super
-
- var display = display
- assert display != null
-
- var gl_error = glGetError
- assert gl_error == gl_NO_ERROR else print gl_error
-
- # Prepare program
- var program = program
- program.compile_and_link
-
- var gamnit_error = program.error
- assert gamnit_error == null else print_error gamnit_error
-
- # Blend
- gl.capabilities.blend.enable
- glBlendFunc(gl_SRC_ALPHA, gl_ONE_MINUS_SRC_ALPHA)
-
- gl.capabilities.depth_test.enable
- glDepthFunc gl_LEQUAL
- glDepthMask true
-
- gl_error = glGetError
- assert gl_error == gl_NO_ERROR else print gl_error
-
- # Prepare to draw
- for tex in all_root_textures do
- tex.load
- glTexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MIN_FILTER, gl_LINEAR)
- glTexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MAG_FILTER, gl_LINEAR)
-
- gamnit_error = tex.error
- assert gamnit_error == null else print_error gamnit_error
- end
-
- gl_error = glGetError
- assert gl_error == gl_NO_ERROR else print gl_error
-
- program.use
-
- glViewport(0, 0, display.width, display.height)
- glClearColor(0.0, 0.02, 0.0, 1.0)
-
- gl_error = glGetError
- assert gl_error == gl_NO_ERROR else print gl_error
-
- # Assign all textures to a unit
- glActiveTexture gl_TEXTURE0
- glBindTexture(gl_TEXTURE_2D, texture_earth.gl_texture)
-
- glActiveTexture gl_TEXTURE1
- glBindTexture(gl_TEXTURE_2D, texture_seas.gl_texture)
-
- glActiveTexture gl_TEXTURE2
- glBindTexture(gl_TEXTURE_2D, texture_night.gl_texture)
-
- glActiveTexture gl_TEXTURE3
- glBindTexture(gl_TEXTURE_2D, texture_elevation.gl_texture)
-
- glActiveTexture gl_TEXTURE4
- glBindTexture(gl_TEXTURE_2D, texture_clouds.gl_texture)
-
- gl_error = glGetError
- assert gl_error == gl_NO_ERROR else print gl_error
-
- # Constant program values
- program.coord.array_enabled = true
- program.tex_coord.array_enabled = true
- program.normal.array_enabled = true
-
- program.scale.uniform 1.0
-
- program.use_texture.uniform true
-
- program.tex_shiny.uniform 1
- program.tex_night.uniform 2
- program.tex_displace.uniform 3
-
- gl_error = glGetError
- assert gl_error == gl_NO_ERROR else print gl_error
- end
-
- private var clock = new Clock
-
- redef fun frame_core(display)
- do
- var t = clock.total.to_f/3.0 + 0.75*pi
-
- var gl_error = glGetError
- assert gl_error == gl_NO_ERROR else print gl_error
-
- glClear(gl_COLOR_BUFFER_BIT | gl_DEPTH_BUFFER_BIT)
- program.use
-
- # Rotate world
- # FIXME do this cleanly by moving the camera
- var mvp = new Matrix.rotation(t, 0.0, 1.0, 0.0) * camera.mvp_matrix
- program.mvp.uniform mvp
- program.camera.uniform(-t.sin, -0.8, -t.cos)
-
- # Planet
- program.coord.array(planet.vertices, 3)
- program.tex_coord.array(planet.texture_coords, 2)
- program.normal.array(planet.normals, 3)
- program.tex.uniform 0
- program.use_texture.uniform true
- program.color.uniform(1.0, 1.0, 1.0, 1.0)
- program.is_surface.uniform true
- glDrawElements(gl_TRIANGLES, planet.indices.length, gl_UNSIGNED_SHORT, planet.indices_c.native_array)
-
- # Clouds
- program.coord.array(clouds.vertices, 3)
- program.tex_coord.array(clouds.texture_coords, 2)
- program.normal.array(clouds.normals, 3)
- program.tex.uniform 4
- program.color.uniform(1.0, 1.0, 1.0, 0.5) # Half transparency
- program.is_surface.uniform false
- glDrawElements(gl_TRIANGLES, clouds.indices.length, gl_UNSIGNED_SHORT, clouds.indices_c.native_array)
-
- # Atmo
- program.coord.array(atmo.vertices, 3)
- program.tex_coord.array(atmo.texture_coords, 2)
- program.normal.array(atmo.normals, 3)
- program.color.uniform(0.0, 0.8, 1.0, 0.02) # Blueish
- program.is_surface.uniform false
- program.use_texture.uniform false
- glDrawElements(gl_TRIANGLES, atmo.indices.length, gl_UNSIGNED_SHORT, atmo.indices_c.native_array)
- assert program.use_texture.is_active
-
- display.flip
-
- gl_error = glGetError
- assert gl_error == gl_NO_ERROR else print gl_error
- end
-
- redef fun on_stop
- do
- # Clean up
- program.delete
-
- # Close gamnit
- var display = display
- if display != null then display.close
- end
-end