Merge: gamnit: new services and a lot of bug fixes and performance improvements
[nit.git] / lib / gamnit / depth / depth_core.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
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
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
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.
14
15 # Base entities of the depth 3D game framework
16 module depth_core
17
18 import gamnit::flat_core
19
20 # Visible 3D entity in the game world
21 #
22 # Similar to `gamnit::Sprite` which is in 2D.
23 #
24 # Each actor associates a `model` to the position `center`.
25 # The appearance is modified by `rotation`, `scale` and `alpha`,
26 # as well as the attributes of `model` itself.
27 #
28 # ~~~
29 # import gamnit::depth
30 #
31 # # Load model from the assets folder
32 # var model = new Model("path/in/assets.obj")
33 #
34 # # Create and configure an actor
35 # var actor = new Actor(model, new Point3d[Float](0.0, 0.0, 0.0))
36 # actor.scale = 2.0
37 #
38 # # Add to the visible game world
39 # app.actors.add actor
40 # ~~~
41 class Actor
42
43 # Model used to draw this actor
44 var model: Model
45
46 # Position of this sprite in world coordinates
47 var center: Point3d[Float] is writable
48
49 # Rotation around the X axis (+ looks up, - looks down)
50 #
51 # Positive values look up, and negative look down.
52 #
53 # All actor rotations follow the right hand rule.
54 # The default orientation of the model should look towards -Z.
55 var pitch = 0.0 is writable
56
57 # Rotation around the Y axis (+ turns left, - turns right)
58 #
59 # Positive values turn `self` to the left, and negative values to the right.
60 #
61 # All actor rotations follow the right hand rule.
62 # The default orientation of the model should look towards -Z.
63 var yaw = 0.0 is writable
64
65 # Rotation around the Z axis (looking to -Z: + turns counterclockwise, - clockwise)
66 #
67 # From the default camera point of view, looking down on the Z axis,
68 # positive values turn `self` counterclockwise, and negative values clockwise.
69 #
70 # All actor rotations follow the right hand rule.
71 # The default orientation of the model should look towards -Z.
72 var roll = 0.0 is writable
73
74 # Scale applied to the model
75 var scale = 1.0 is writable
76
77 # Transparency applied to the model on draw
78 #
79 # This value may be ignored by some materials.
80 # Non-opaque values may result in artifacts as there is no specialized
81 # support for transparent models and the depth buffer.
82 var alpha = 1.0 is writable
83 end
84
85 # 3D model composed of `Mesh` and `Material`, loaded from the assets folder by default
86 #
87 # Instances can be created at any time and must be loaded after or at the end of `create_scene`.
88 # If loading fails, the model is replaced by `placeholder_model`.
89 #
90 # ~~~
91 # import gamnit::depth
92 #
93 # var model = new Model("path/in/assets.obj")
94 # model.load
95 # ~~~
96 #
97 # The most simple model is `LeafModel`, composed of a single `Mesh` and `Material`.
98 # It can be easily created programmatically to display simple geometries.
99 # Whereas `CompositeModel` is composed of one or many `LeafModel` and is usually
100 # loaded from the assets folder as a `ModelAsset`.
101 # Instances of `ModelAsset` must be in the format OBJ and MAT,
102 # and their texture in PNG or JPG.
103 abstract class Model
104
105 # Load this model in memory
106 fun load do end
107
108 # Errors raised at loading
109 var errors = new Array[Error]
110
111 # All `LeafModel` composing this model
112 #
113 # Usually, there is one `LeafModel` per material.
114 # At each frame, each material is asked to draw all the live `LeafModel` instaces.
115 fun leaves: Array[LeafModel] is abstract
116
117 # Sub-models with names, usually declared in the asset file
118 var named_parts = new Map[Text, Model]
119 end
120
121 # Model composed of one or many other `LeafModel`
122 class CompositeModel
123 super Model
124
125 redef var leaves = new Array[LeafModel]
126 end
127
128 # Basic model with a single `mesh` and `material`
129 #
130 # Only leaves are actually drawn by the `material`.
131 class LeafModel
132 super Model
133
134 # Mesh forming this model
135 var mesh: Mesh
136
137 # Material applied on this model
138 var material: Material
139
140 redef var leaves = [self]
141 end
142
143 # Material for models, or how to draw the model
144 #
145 # To create a simple basic blueish material, use `new Material`.
146 #
147 # Each class of material is associated to a `GLProgram` and its GPU shaders.
148 # The simple material `SmoothMaterial` allows to set an ambient, diffuse and specular color.
149 # To which `TextureMaterial` adds three textures, for each kind of light.
150 # The `NormalsMaterial` may be useful for debugging, it show the orientation of
151 # the normal vectors as colors.
152 #
153 # ~~~
154 # import gamnit::depth
155 #
156 # var blueish_material = new Material
157 # var redish_material = new SmoothMaterial([0.3, 0.0, 0.0],
158 # [0.6, 0.0, 0.0],
159 # [1.0, 1.0, 1.0])
160 # var normals_material = new NormalsMaterial
161 # ~~~
162 abstract class Material
163
164 # Draw a `model` from `actor`
165 #
166 # This method should be refined by subclasses as the default implementation is a no-op.
167 #
168 # This method is called on many materials for many `actor` and `model` at each frame.
169 # It is expected to use a `GLProgram` and call an equivalent to `glDrawArrays`.
170 # However, it should not call `glClear` nor `GamnitDisplay::flip`.
171 fun draw(actor: Actor, model: LeafModel, camera: Camera) do end
172 end
173
174 # Mesh with all geometry data
175 #
176 # May be created via `Plane`, `Cube` or `UVSphere`,
177 # or loaded from the assets folder indirectly with a `Model`.
178 #
179 # ~~~
180 # import gamnit::depth
181 #
182 # var plane = new Plane
183 # var cube = new Cube
184 # var sphere = new UVSphere(1.0, 32, 16)
185 # ~~~
186 class Mesh
187
188 # Number for vertices
189 fun n_vertices: Int do return vertices.length / 3
190
191 # Vertices relative coordinates, 3 floats per vertex
192 var vertices = new Array[Float] is lazy, writable
193
194 # Indices to draw triangles with `glDrawElements`
195 #
196 # If `not_empty`, use `glDrawElements`, otherwise use `glDrawArrays`.
197 var indices = new Array[Int] is lazy, writable
198
199 private var indices_c = new CUInt16Array.from(indices) is lazy, writable
200
201 # Normals, 3 floats per vertex
202 var normals = new Array[Float] is lazy, writable
203
204 # Coordinates on the texture, 2 floats per vertex
205 var texture_coords = new Array[Float] is lazy, writable
206
207 # `GLDrawMode` used to display this mesh, defaults to `gl_TRIANGLES`
208 fun draw_mode: GLDrawMode do return gl_TRIANGLES
209 end
210
211 # Source of light
212 abstract class Light
213
214 # Center of this light source in world coordinates
215 var position = new Point3d[Float](0.0, 1000.0, 0.0)
216 end
217
218 # Basic light projected from a single point
219 class PointLight
220 super Light
221 end
222
223 # Source of light casting shadows
224 abstract class LightCastingShadows
225 super Light
226
227 # View from the camera, used for shadow mapping, implemented by sub-classes
228 fun camera: Camera is abstract
229 end
230
231 redef class App
232
233 # Live actors to be drawn on screen
234 var actors = new Array[Actor]
235
236 # Single light of the scene
237 var light: Light = new PointLight is writable
238
239 # TODO move `actors & light` to a scene object
240 # TODO support more than 1 light
241 end