From: Alexis Laferrière Date: Sat, 16 Jan 2016 17:16:50 +0000 (-0500) Subject: contrib/model_viewer: move the globe example as a custom model X-Git-Tag: v0.8~11^2~2 X-Git-Url: http://nitlanguage.org?hp=055d2aaa1260e05582e2d57d72cc7390a38c652e contrib/model_viewer: move the globe example as a custom model Signed-off-by: Alexis Laferrière --- diff --git a/contrib/model_viewer/assets/globe/clouds.png b/contrib/model_viewer/assets/globe/clouds.png new file mode 100644 index 0000000..6a34285 Binary files /dev/null and b/contrib/model_viewer/assets/globe/clouds.png differ diff --git a/contrib/model_viewer/assets/globe/earth.jpg b/contrib/model_viewer/assets/globe/earth.jpg new file mode 100644 index 0000000..53388c8 Binary files /dev/null and b/contrib/model_viewer/assets/globe/earth.jpg differ diff --git a/contrib/model_viewer/assets/globe/elevation.jpg b/contrib/model_viewer/assets/globe/elevation.jpg new file mode 100644 index 0000000..48737a0 Binary files /dev/null and b/contrib/model_viewer/assets/globe/elevation.jpg differ diff --git a/contrib/model_viewer/assets/globe/lights.jpg b/contrib/model_viewer/assets/globe/lights.jpg new file mode 100644 index 0000000..48dff8d Binary files /dev/null and b/contrib/model_viewer/assets/globe/lights.jpg differ diff --git a/contrib/model_viewer/assets/globe/seas.jpg b/contrib/model_viewer/assets/globe/seas.jpg new file mode 100644 index 0000000..a078e66 Binary files /dev/null and b/contrib/model_viewer/assets/globe/seas.jpg differ diff --git a/contrib/model_viewer/src/globe.nit b/contrib/model_viewer/src/globe.nit new file mode 100644 index 0000000..9da1c59 --- /dev/null +++ b/contrib/model_viewer/src/globe.nit @@ -0,0 +1,351 @@ +# 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 diff --git a/contrib/model_viewer/src/model_viewer.nit b/contrib/model_viewer/src/model_viewer.nit index dd1fa98..f147823 100644 --- a/contrib/model_viewer/src/model_viewer.nit +++ b/contrib/model_viewer/src/model_viewer.nit @@ -24,6 +24,8 @@ end import gamnit::depth +import globe + redef class App # All available models @@ -33,7 +35,8 @@ redef class App 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 @@ -92,7 +95,7 @@ redef class App 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 diff --git a/lib/gamnit/examples/globe/Makefile b/lib/gamnit/examples/globe/Makefile deleted file mode 100644 index d18b689..0000000 --- a/lib/gamnit/examples/globe/Makefile +++ /dev/null @@ -1,41 +0,0 @@ -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 diff --git a/lib/gamnit/examples/globe/README b/lib/gamnit/examples/globe/README deleted file mode 100644 index 0234f7f..0000000 --- a/lib/gamnit/examples/globe/README +++ /dev/null @@ -1,13 +0,0 @@ -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 diff --git a/lib/gamnit/examples/globe/art/icon.png b/lib/gamnit/examples/globe/art/icon.png deleted file mode 100644 index 71612a4..0000000 Binary files a/lib/gamnit/examples/globe/art/icon.png and /dev/null differ diff --git a/lib/gamnit/examples/globe/art/icon.xcf b/lib/gamnit/examples/globe/art/icon.xcf deleted file mode 100644 index efcf652..0000000 Binary files a/lib/gamnit/examples/globe/art/icon.xcf and /dev/null differ diff --git a/lib/gamnit/examples/globe/assets/hd/clouds.png b/lib/gamnit/examples/globe/assets/hd/clouds.png deleted file mode 100644 index c4319d7..0000000 Binary files a/lib/gamnit/examples/globe/assets/hd/clouds.png and /dev/null differ diff --git a/lib/gamnit/examples/globe/assets/hd/earth.jpg b/lib/gamnit/examples/globe/assets/hd/earth.jpg deleted file mode 100644 index 79f6f2c..0000000 Binary files a/lib/gamnit/examples/globe/assets/hd/earth.jpg and /dev/null differ diff --git a/lib/gamnit/examples/globe/assets/hd/elevation.jpg b/lib/gamnit/examples/globe/assets/hd/elevation.jpg deleted file mode 100644 index 3ec70c0..0000000 Binary files a/lib/gamnit/examples/globe/assets/hd/elevation.jpg and /dev/null differ diff --git a/lib/gamnit/examples/globe/assets/hd/lights.jpg b/lib/gamnit/examples/globe/assets/hd/lights.jpg deleted file mode 100644 index 240df35..0000000 Binary files a/lib/gamnit/examples/globe/assets/hd/lights.jpg and /dev/null differ diff --git a/lib/gamnit/examples/globe/assets/hd/seas.jpg b/lib/gamnit/examples/globe/assets/hd/seas.jpg deleted file mode 100644 index 52ad2ac..0000000 Binary files a/lib/gamnit/examples/globe/assets/hd/seas.jpg and /dev/null differ diff --git a/lib/gamnit/examples/globe/bin/.gitignore b/lib/gamnit/examples/globe/bin/.gitignore deleted file mode 100644 index 72e8ffc..0000000 --- a/lib/gamnit/examples/globe/bin/.gitignore +++ /dev/null @@ -1 +0,0 @@ -* diff --git a/lib/gamnit/examples/globe/org.nitlanguage.globe.txt b/lib/gamnit/examples/globe/org.nitlanguage.globe.txt deleted file mode 100644 index 845e177..0000000 --- a/lib/gamnit/examples/globe/org.nitlanguage.globe.txt +++ /dev/null @@ -1,10 +0,0 @@ -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. -. diff --git a/lib/gamnit/examples/globe/package.ini b/lib/gamnit/examples/globe/package.ini deleted file mode 100644 index b4e8861..0000000 --- a/lib/gamnit/examples/globe/package.ini +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name=globe -tags=example -maintainer=Alexis Laferrière -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 diff --git a/lib/gamnit/examples/globe/src/globe.nit b/lib/gamnit/examples/globe/src/globe.nit deleted file mode 100644 index 570cb5d..0000000 --- a/lib/gamnit/examples/globe/src/globe.nit +++ /dev/null @@ -1,463 +0,0 @@ -# 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