lib/gamnit: intro draw_mode
[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 intrude import gamnit::flat
19
20 # Visible entity in the game world, represented by its `model` modified by the other attributes
21 class Actor
22
23 # Model used to dray this actor
24 var model: Model
25
26 # Position of this sprite in world coordinates
27 var center: Point3d[Float] is writable
28
29 # Rotation on the Z axis
30 var rotation = 0.0 is writable
31
32 # Scale applied to this sprite
33 var scale = 1.0 is writable
34
35 # Transparency applied to the texture on draw
36 var alpha = 1.0 is writable
37 end
38
39 # Entire 3D model defined by its `leaves`, an association of `Mesh` to `Material`
40 abstract class Model
41
42 # Load this model in memory
43 fun load do end
44
45 # All `LeafModel` composing this model
46 #
47 # Usually, there is one `LeafModel` per material.
48 # At each frame, each material is asked to draw all the live `LeafModel` instaces.
49 fun leaves: Array[LeafModel] is abstract
50 end
51
52 # Model composed of one or many other `LeafModel`
53 class CompositeModel
54 super Model
55
56 redef var leaves = new Array[LeafModel]
57 end
58
59 # Single model with a `mesh` and `material`
60 #
61 # Only leaves are actually drawn by the `material`.
62 class LeafModel
63 super Model
64
65 # Mesh forming this model
66 var mesh: Mesh
67
68 # Material applied on this model
69 var material: Material
70
71 redef var leaves = [self]
72 end
73
74 # Material for a model or how to draw the model
75 abstract class Material
76
77 # Draw `actor`
78 #
79 # This method should be refined by subclasses as the default implementation is a no-op.
80 #
81 # This method is called on many materials for many `actor` and `model` at each frame.
82 # It is expected to use a `GLProgram` and call an equivalent to `glDrawArrays`.
83 # However, it should not call `glClear` nor `GamnitDisplay::flip`.
84 fun draw(actor: Actor, model: LeafModel) do end
85 end
86
87 # Mesh with all geometry data
88 class Mesh
89
90 # Vertices coordinates
91 var vertices = new Array[Float] is lazy, writable
92
93 # Indices to draw triangles with `glDrawElements`
94 #
95 # If `not_empty`, use `glDrawElements`, otherwise use `glDrawArrays`.
96 var indices = new Array[Int] is lazy, writable
97
98 private var indices_c = new CUInt16Array.from(indices) is lazy, writable
99
100 # Normals on each vertex
101 var normals = new Array[Float] is lazy, writable
102
103 # Coordinates on the texture per vertex
104 var texture_coords = new Array[Float] is lazy, writable
105
106 # `GLDrawMode` used to display this mesh, defaults to `gl_TRIANGLES`
107 fun draw_mode: GLDrawMode do return gl_TRIANGLES
108
109 # Create an UV sphere of `radius` with `n_meridians` and `n_parallels`
110 init uv_sphere(radius: Float, n_meridians, n_parallels: Int)
111 do
112 var w = n_meridians
113 var h = n_parallels
114
115 var vertices = new Array[Float].with_capacity(w*h*3)
116 self.vertices = vertices
117
118 var texture_coords = new Array[Float].with_capacity(w*h*2)
119 self.texture_coords = texture_coords
120
121 var normals = new Array[Float].with_capacity(w*h*3)
122 self.normals = normals
123
124 # Build vertices
125 for m in [0..w[ do
126 for p in [0..h[ do
127 var u = m.to_f * 2.0 * pi / (w-1).to_f
128 var v = p.to_f * pi / (h-1).to_f
129
130 vertices.add radius * u.cos * v.sin
131 vertices.add radius * v.cos
132 vertices.add radius * u.sin * v.sin
133
134 texture_coords.add (1.0 - m.to_f/(w-1).to_f)
135 texture_coords.add(p.to_f/(h-1).to_f)
136
137 normals.add u.cos * v.sin
138 normals.add v.cos
139 normals.add u.sin * v.sin
140 end
141 end
142
143 # Build faces
144 var indices = new Array[Int].with_capacity((w-1)*(h-1)*6)
145 self.indices = indices
146 for m in [0..w-1[ do
147 for p in [0..h-1[ do
148 var a = m*h + p
149
150 indices.add a
151 indices.add a+h
152 indices.add a+1
153
154 indices.add a+h
155 indices.add a+h+1
156 indices.add a+1
157 end
158 end
159 end
160
161 # Dimensions of this geometry using the min and max of all points on each axis
162 var dimensions: Point3d[Float] is lazy, writable do
163 assert vertices.length % 3 == 0
164
165 var minx = inf
166 var miny = inf
167 var minz = inf
168 var maxx = -inf
169 var maxy = -inf
170 var maxz = -inf
171
172 var i = 0
173 while i < vertices.length do
174 var x = vertices[i]
175 i += 1
176 var y = vertices[i]
177 i += 1
178 var z = vertices[i]
179 i += 1
180
181 minx = minx.min(x)
182 miny = miny.min(y)
183 minz = minz.min(z)
184
185 maxx = maxx.max(x)
186 maxy = maxy.max(y)
187 maxz = maxz.max(z)
188 end
189
190 return new Point3d[Float](maxx-minx, maxy-miny, maxz-minz)
191 end
192
193 # Center of the geometry
194 var center: Point3d[Float] is lazy, writable do
195 assert vertices.length % 3 == 0
196
197 var minx = inf
198 var miny = inf
199 var minz = inf
200 var maxx = -inf
201 var maxy = -inf
202 var maxz = -inf
203
204 var i = 0
205 while i < vertices.length do
206 var x = vertices[i]
207 i += 1
208 var y = vertices[i]
209 i += 1
210 var z = vertices[i]
211 i += 1
212
213 minx = minx.min(x)
214 miny = miny.min(y)
215 minz = minz.min(z)
216
217 maxx = maxx.max(x)
218 maxy = maxy.max(y)
219 maxz = maxz.max(z)
220 end
221
222 var center = new Point3d[Float](
223 (minx+maxx)/2.0,
224 (miny+maxy)/2.0,
225 (minz+maxz)/2.0)
226 return center
227 end
228 end
229
230 # Source of light
231 #
232 # Instances of this class define a light source position and type.
233 class Light
234
235 # TODO point light, spotlight, directional light, etc.
236
237 # Center of this light source in world coordinates
238 var position = new Point3d[Float](0.0, 1000.0, 0.0)
239 end
240
241 redef class App
242
243 # Live actors to be drawn on screen
244 var actors = new Array[Actor]
245
246 # Single light of the scene
247 var light = new Light
248
249 # TODO move `actors & light` to a scene object
250 # TODO support more than 1 light
251 end