v2 / examples / js_dom_cube / cube.js.v
451 lines · 414 sloc · 8.48 KB · e2e5cf8db56f3562c7baa735061690be936bdf3e
Raw
1import js.dom
2import math
3
4const vert_code = 'attribute vec3 position;uniform mat4 Pmatrix;uniform mat4 Vmatrix;uniform mat4 Mmatrix;attribute vec3 color;varying vec3 vColor;void main(void) {gl_Position = Pmatrix * Vmatrix * Mmatrix * vec4(position,1.);vColor = color;}
5 '
6
7const frag_code = 'precision mediump float;varying vec3 vColor;void main(void) {gl_FragColor = vec4(vColor, 1.);}
8 '
9
10const vertices = [
11 f32(-1),
12 -1,
13 -1,
14 1,
15 -1,
16 -1,
17 1,
18 1,
19 -1,
20 -1,
21 1,
22 -1,
23 -1,
24 -1,
25 1,
26 1,
27 -1,
28 1,
29 1,
30 1,
31 1,
32 -1,
33 1,
34 1,
35 -1,
36 -1,
37 -1,
38 -1,
39 1,
40 -1,
41 -1,
42 1,
43 1,
44 -1,
45 -1,
46 1,
47 1,
48 -1,
49 -1,
50 1,
51 1,
52 -1,
53 1,
54 1,
55 1,
56 1,
57 -1,
58 1,
59 -1,
60 -1,
61 -1,
62 -1,
63 -1,
64 1,
65 1,
66 -1,
67 1,
68 1,
69 -1,
70 -1,
71 -1,
72 1,
73 -1,
74 -1,
75 1,
76 1,
77 1,
78 1,
79 1,
80 1,
81 1,
82 -1,
83]
84const colors = [
85 f32(5),
86 3,
87 7,
88 5,
89 3,
90 7,
91 5,
92 3,
93 7,
94 5,
95 3,
96 7,
97 1,
98 1,
99 3,
100 1,
101 1,
102 3,
103 1,
104 1,
105 3,
106 1,
107 1,
108 3,
109 0,
110 0,
111 1,
112 0,
113 0,
114 1,
115 0,
116 0,
117 1,
118 0,
119 0,
120 1,
121 1,
122 0,
123 0,
124 1,
125 0,
126 0,
127 1,
128 0,
129 0,
130 1,
131 0,
132 0,
133 1,
134 1,
135 0,
136 1,
137 1,
138 0,
139 1,
140 1,
141 0,
142 1,
143 1,
144 0,
145 0,
146 1,
147 0,
148 0,
149 1,
150 0,
151 0,
152 1,
153 0,
154 0,
155 1,
156 0,
157]
158const indices = [
159 u16(0),
160 1,
161 2,
162 0,
163 2,
164 3,
165 4,
166 5,
167 6,
168 4,
169 6,
170 7,
171 8,
172 9,
173 10,
174 8,
175 10,
176 11,
177 12,
178 13,
179 14,
180 12,
181 14,
182 15,
183 16,
184 17,
185 18,
186 16,
187 18,
188 19,
189 20,
190 21,
191 22,
192 20,
193 22,
194 23,
195]
196const amortization = 0.95
197
198fn get_webgl() (JS.HTMLCanvasElement, JS.WebGLRenderingContext) {
199 JS.console.log(dom.document)
200 elem := dom.document.getElementById('myCanvas'.str) or { panic('cannot get canvas') }
201 match elem {
202 JS.HTMLCanvasElement {
203 webgl := elem.getContext('experimental-webgl'.str, js_undefined()) or {
204 panic('context not found')
205 }
206 match webgl {
207 JS.WebGLRenderingContext {
208 return elem, webgl
209 }
210 else {
211 panic('cannot get webgl')
212 }
213 }
214 }
215 else {
216 panic('not an canvas')
217 }
218 }
219}
220
221fn get_projection(angle f64, a f64, z_min f64, z_max f64) []f64 {
222 ang := math.tan((angle * 0.5) * math.pi / 180)
223 return [
224 0.5 / ang,
225 0,
226 0,
227 0,
228 0,
229 0.5 * a / ang,
230 0,
231 0,
232 0,
233 0,
234 -(z_max + z_min) / (z_max - z_min),
235 -1,
236 0,
237 0,
238 (-2 * z_max * z_min) / (z_max - z_min),
239 0,
240 ]
241}
242
243fn JS.Math.cos(JS.Number) JS.Number
244fn JS.Math.sin(JS.Number) JS.Number
245fn rotate_x(mut m []f64, angle f64) {
246 c := math.cos(angle)
247 s := math.sin(angle)
248 mv1 := m[1]
249 mv5 := m[5]
250 mv9 := m[9]
251 m[1] = m[1] * c - m[2] * s
252 m[5] = m[5] * c - m[6] * s
253 m[9] = m[9] * c - m[10] * s
254
255 m[2] = m[2] * c + mv1 * s
256 m[6] = m[6] * c + mv5 * s
257 m[10] = m[10] * c + mv9 * s
258}
259
260fn rotate_y(mut m []f64, angle f64) {
261 c := math.cos(angle)
262 s := math.sin(angle)
263
264 mv0 := m[0]
265 mv4 := m[4]
266 mv8 := m[8]
267 m[0] = c * m[0] + s * m[2]
268 m[4] = c * m[4] + s * m[6]
269 m[8] = c * m[8] + s * m[10]
270
271 m[2] = c * m[2] - s * mv0
272 m[6] = c * m[6] - s * mv4
273 m[10] = c * m[10] - s * mv8
274}
275
276struct State {
277mut:
278 drag bool
279 gl JS.WebGLRenderingContext
280 canvas JS.HTMLCanvasElement
281 old_x f64
282 old_y f64
283 dx f64
284 dy f64
285 theta f64
286 phi f64
287 time_old f64
288 mo_matrix []f64
289 view_matrix []f64
290 proj_matrix []f64
291 pmatrix JS.WebGLUniformLocation
292 vmatrix JS.WebGLUniformLocation
293 mmatrix JS.WebGLUniformLocation
294 index_buffer JS.WebGLBuffer
295}
296
297fn animate(mut state State, time f64) {
298 if !state.drag {
299 state.dx = state.dx * amortization
300 state.dy = state.dy * amortization
301 state.theta += state.dx
302 state.phi += state.dy
303 }
304
305 state.mo_matrix[0] = 1
306 state.mo_matrix[1] = 0
307 state.mo_matrix[2] = 0
308 state.mo_matrix[3] = 0
309
310 state.mo_matrix[4] = 0
311 state.mo_matrix[5] = 1
312 state.mo_matrix[6] = 0
313 state.mo_matrix[7] = 0
314
315 state.mo_matrix[8] = 0
316 state.mo_matrix[9] = 0
317 state.mo_matrix[10] = 1
318 state.mo_matrix[11] = 0
319
320 state.mo_matrix[12] = 0
321 state.mo_matrix[13] = 0
322 state.mo_matrix[14] = 0
323 state.mo_matrix[15] = 1
324 // println('${state.theta} ${state.phi}')
325 rotate_x(mut state.mo_matrix, state.phi)
326 rotate_y(mut state.mo_matrix, state.theta)
327 state.time_old = time
328 state.gl.enable(dom.gl_depth_test())
329 state.gl.clearColor(JS.Number(0.5), JS.Number(0.5), JS.Number(0.5), JS.Number(0.9))
330 state.gl.clearDepth(JS.Number(1.0))
331 state.gl.viewport(JS.Number(0.0), JS.Number(0.0), state.canvas.width, state.canvas.height)
332 state.gl.clear(JS.Number(int(dom.gl_color_buffer_bit()) | int(dom.gl_depth_buffer_bit())))
333
334 state.gl.uniformMatrix4fv(state.pmatrix, JS.Boolean(false), state.proj_matrix.to_number_array())
335 state.gl.uniformMatrix4fv(state.vmatrix, JS.Boolean(false), state.view_matrix.to_number_array())
336 state.gl.uniformMatrix4fv(state.mmatrix, JS.Boolean(false), state.mo_matrix.to_number_array())
337
338 state.gl.bindBuffer(dom.gl_element_array_buffer(), state.index_buffer)
339 state.gl.drawElements(dom.gl_triangles(), JS.Number(indices.len), dom.gl_unsigned_short(),
340 JS.Number(0))
341
342 dom.window().requestAnimationFrame(fn [mut state] (time JS.Number) {
343 animate(mut state, f64(time))
344 })
345}
346
347fn main() {
348 canvas, gl := get_webgl()
349
350 vertex_buffer := gl.createBuffer()?
351 gl.bindBuffer(dom.gl_array_buffer(), vertex_buffer)
352 gl.bufferData(dom.gl_array_buffer(), float32_array(vertices), dom.gl_static_draw())
353
354 color_buffer := gl.createBuffer()?
355 gl.bindBuffer(dom.gl_array_buffer(), color_buffer)
356 gl.bufferData(dom.gl_array_buffer(), float32_array(colors), dom.gl_static_draw())
357
358 index_buffer := gl.createBuffer()?
359 gl.bindBuffer(dom.gl_element_array_buffer(), index_buffer)
360 gl.bufferData(dom.gl_element_array_buffer(), uint16_array(indices), dom.gl_static_draw())
361
362 vert_shader := gl.createShader(dom.gl_vertex_shader())?
363 gl.shaderSource(vert_shader, vert_code.str)
364 gl.compileShader(vert_shader)
365
366 if !bool(JS.Boolean(gl.getShaderParameter(vert_shader, dom.gl_compile_status()))) {
367 panic('An error occurred when compiling vertex shader: ${string(gl.getShaderInfoLog(vert_shader))}')
368 }
369
370 frag_shader := gl.createShader(dom.gl_fragment_shader())?
371 gl.shaderSource(frag_shader, frag_code.str)
372 gl.compileShader(frag_shader)
373 if !bool(JS.Boolean(gl.getShaderParameter(frag_shader, dom.gl_compile_status()))) {
374 panic('An error occurred when compiling fragment shader: ${string(gl.getShaderInfoLog(frag_shader))}')
375 }
376
377 shader_program := gl.createProgram()?
378 gl.attachShader(shader_program, vert_shader)
379 gl.attachShader(shader_program, frag_shader)
380 gl.linkProgram(shader_program)
381
382 if !bool(JS.Boolean(gl.getProgramParameter(shader_program, dom.gl_link_status()))) {
383 panic('unable to initialize the shader program: ${string(gl.getProgramInfoLog(shader_program))}')
384 }
385
386 pmatrix := gl.getUniformLocation(shader_program, 'Pmatrix'.str)?
387 vmatrix := gl.getUniformLocation(shader_program, 'Vmatrix'.str)?
388 mmatrix := gl.getUniformLocation(shader_program, 'Mmatrix'.str)?
389
390 gl.bindBuffer(dom.gl_array_buffer(), vertex_buffer)
391 position := gl.getAttribLocation(shader_program, 'position'.str)
392 gl.vertexAttribPointer(position, JS.Number(3), dom.gl_float(), JS.Boolean(false), JS.Number(0),
393 JS.Number(0))
394 gl.enableVertexAttribArray(position)
395
396 gl.bindBuffer(dom.gl_array_buffer(), color_buffer)
397 color := gl.getAttribLocation(shader_program, 'color'.str)
398 gl.vertexAttribPointer(color, JS.Number(3), dom.gl_float(), JS.Boolean(false), JS.Number(0),
399 JS.Number(0))
400 gl.enableVertexAttribArray(color)
401 gl.useProgram(shader_program)
402
403 mut proj_matrix := get_projection(40.0, f64(canvas.width) / f64(canvas.height), 1.0, 100.0)
404 mut mo_matrix := [f64(1), 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
405 mut view_matrix := [f64(1), 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
406
407 view_matrix[14] = view_matrix[14] - 6
408
409 mut state :=
410 State{false, gl, canvas, 0, 0, 0, 0, 0, 0, 0, mo_matrix, view_matrix, proj_matrix, pmatrix, vmatrix, mmatrix, index_buffer}
411
412 canvas.addEventListener('mousedown'.str, fn [mut state] (e JS.Event) {
413 state.drag = true
414 match e {
415 JS.MouseEvent {
416 state.old_x = f64(e.pageX)
417 state.old_y = f64(e.pageY)
418 e.preventDefault()
419 }
420 else {}
421 }
422 }, JS.EventListenerOptions{})
423
424 canvas.addEventListener('mouseup'.str, fn [mut state] (e JS.Event) {
425 state.drag = false
426 }, JS.EventListenerOptions{})
427 canvas.addEventListener('mouseout'.str, fn [mut state] (e JS.Event) {
428 state.drag = false
429 }, JS.EventListenerOptions{})
430 canvas.addEventListener('mousemove'.str, fn [mut state] (e JS.Event) {
431 if !state.drag {
432 return
433 }
434 match e {
435 JS.MouseEvent {
436 state.dx = (f64(e.pageX) - state.old_x) * 2.0 * math.pi / f64(state.canvas.width)
437 state.dy = (f64(e.pageY) - state.old_y) * 2.0 * math.pi / f64(state.canvas.height)
438 state.theta += state.dx
439 state.phi += state.dy
440 state.old_x = f64(e.pageX)
441 state.old_y = f64(e.pageY)
442 e.preventDefault()
443 }
444 else {
445 panic('not a mouse event??')
446 }
447 }
448 }, JS.EventListenerOptions{})
449
450 animate(mut state, 0)
451}
452