contrib: intro model viewer
[nit.git] / contrib / model_viewer / src / model_viewer.nit
diff --git a/contrib/model_viewer/src/model_viewer.nit b/contrib/model_viewer/src/model_viewer.nit
new file mode 100644 (file)
index 0000000..dd1fa98
--- /dev/null
@@ -0,0 +1,148 @@
+# 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 game to destroy asteroids
+module model_viewer is
+       app_name "Model Viewer"
+       app_namespace "org.nitlanguage.model_viewer"
+       app_version(1, 0, git_revision)
+
+       android_manifest_activity """android:screenOrientation="landscape""""
+       android_api_target 15
+end
+
+import gamnit::depth
+
+redef class App
+
+       # All available models
+       var models: Array[Model] = [
+               new LeafModel(new Cube, new SmoothMaterial.default),
+               new LeafModel(new Mesh.uv_sphere(4.0, 32, 16), new SmoothMaterial.default),
+               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")]
+
+       # Index of the current model in `models`
+       var model_index = 0
+
+       # Texture "Previous model"
+       var ui_prev = new Texture("ui/prev.png")
+
+       # Texture "Next model"
+       var ui_next = new Texture("ui/next.png")
+
+       redef fun on_create
+       do
+               super
+
+               if args.length > 0 then
+                       # Load a model passed as the first command line argument
+                       var model_path = args.first
+                       if model_path.has_prefix("assets/") then model_path = model_path.substring_from(7)
+
+                       var model = new Model(model_path)
+                       models.unshift model
+               end
+
+               world_camera.near = 1.0
+               world_camera.far = 1000.0
+
+               for model in models do model.load
+               for texture in asset_textures_by_name.values do texture.load
+
+               # Display the first model
+               model = models[model_index]
+
+               # Setup UI
+               # Use 800 px in height as screen reference
+               ui_camera.reset_height 800.0
+
+               var prev_sprite = new Sprite(ui_prev,
+                       ui_camera.bottom_left.offset(200, -40, 0))
+               prev_sprite.scale = 0.5
+               ui_sprites.add prev_sprite
+
+               var next_sprite = new Sprite(ui_next,
+                       ui_camera.bottom_right.offset(-165, -40, 0))
+               next_sprite.scale = 0.5
+               ui_sprites.add next_sprite
+       end
+
+       # Set the currently displayed model
+       fun model=(model: Model)
+       do
+               var actor = new Actor(model, new Point3d[Float](0.0, 0.0, 0.0))
+
+               model = model.leaves.first
+               actor.center.x -= model.mesh.center.x
+               actor.center.y += model.mesh.center.y
+               actor.center.z -= model.mesh.center.z
+
+               var height = model.mesh.dimensions.y
+               world_camera.reset_height(height * 4.0)
+
+               actors.clear
+               actors.add actor
+       end
+
+       # Cycle to the next or previous model, changing the index by `d`
+       fun cycle_model(d: Int)
+       do
+               model_index = (model_index + d + models.length) % models.length
+               model = models[model_index]
+       end
+
+       redef fun accept_event(event)
+       do
+               var display = display
+               if display == null then return super
+
+               if event isa QuitEvent then
+                       exit 0
+               else if event isa KeyEvent and event.is_down then
+                       if event.is_arrow_right then
+                               cycle_model 1
+                       else if event.is_arrow_left then
+                               cycle_model -1
+                       end
+               else if event isa PointerEvent and event.pressed then
+                       if event.x.to_i > display.width / 2 then
+                               cycle_model 1
+                       else cycle_model -1
+               end
+
+               return super
+       end
+
+       private var clock = new Clock
+
+       redef fun update(dt)
+       do
+               super
+
+               var t = clock.total.to_f
+
+               # Rotate the model
+               actors.first.rotation = t
+
+               # Move the light source
+               var dist_to_light = 20.0
+               t *= 1.33
+               light.position.x = dist_to_light * t.cos
+               light.position.y = 4.0
+               light.position.z = dist_to_light * t.sin
+       end
+end