v/examples/js_dom_cube/cube.js.v

453 lines
8.6 KiB
V

import jsdom
import math
const (
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;}
'
frag_code = 'precision mediump float;varying vec3 vColor;void main(void) {gl_FragColor = vec4(vColor, 1.);}
'
vertices = [
f32(-1),
-1,
-1,
1,
-1,
-1,
1,
1,
-1,
-1,
1,
-1,
-1,
-1,
1,
1,
-1,
1,
1,
1,
1,
-1,
1,
1,
-1,
-1,
-1,
-1,
1,
-1,
-1,
1,
1,
-1,
-1,
1,
1,
-1,
-1,
1,
1,
-1,
1,
1,
1,
1,
-1,
1,
-1,
-1,
-1,
-1,
-1,
1,
1,
-1,
1,
1,
-1,
-1,
-1,
1,
-1,
-1,
1,
1,
1,
1,
1,
1,
1,
-1,
]
colors = [
f32(5),
3,
7,
5,
3,
7,
5,
3,
7,
5,
3,
7,
1,
1,
3,
1,
1,
3,
1,
1,
3,
1,
1,
3,
0,
0,
1,
0,
0,
1,
0,
0,
1,
0,
0,
1,
1,
0,
0,
1,
0,
0,
1,
0,
0,
1,
0,
0,
1,
1,
0,
1,
1,
0,
1,
1,
0,
1,
1,
0,
0,
1,
0,
0,
1,
0,
0,
1,
0,
0,
1,
0,
]
indices = [
u16(0),
1,
2,
0,
2,
3,
4,
5,
6,
4,
6,
7,
8,
9,
10,
8,
10,
11,
12,
13,
14,
12,
14,
15,
16,
17,
18,
16,
18,
19,
20,
21,
22,
20,
22,
23,
]
amortization = 0.95
)
fn get_webgl() (&JS.HTMLCanvasElement, JS.WebGLRenderingContext) {
elem := jsdom.document.getElementById('myCanvas'.str) or { panic('cannot get canvas') }
match elem {
JS.HTMLCanvasElement {
webgl := elem.getContext('experimental-webgl'.str, js_undefined()) or {
panic('context not found')
}
match webgl {
JS.WebGLRenderingContext {
return elem, webgl
}
else {
panic('cannot get webgl')
}
}
}
else {
panic('not an canvas')
}
}
}
fn get_projection(angle f64, a f64, z_min f64, z_max f64) []f64 {
ang := math.tan((angle * 0.5) * math.pi / 180)
return [
0.5 / ang,
0,
0,
0,
0,
0.5 * a / ang,
0,
0,
0,
0,
-(z_max + z_min) / (z_max - z_min),
-1,
0,
0,
(-2 * z_max * z_min) / (z_max - z_min),
0,
]
}
fn JS.Math.cos(JS.Number) JS.Number
fn JS.Math.sin(JS.Number) JS.Number
fn rotate_x(mut m []f64, angle f64) {
c := math.cos(angle)
s := math.sin(angle)
mv1 := m[1]
mv5 := m[5]
mv9 := m[9]
m[1] = m[1] * c - m[2] * s
m[5] = m[5] * c - m[6] * s
m[9] = m[9] * c - m[10] * s
m[2] = m[2] * c + mv1 * s
m[6] = m[6] * c + mv5 * s
m[10] = m[10] * c + mv9 * s
}
fn rotate_y(mut m []f64, angle f64) {
c := math.cos(angle)
s := math.sin(angle)
mv0 := m[0]
mv4 := m[4]
mv8 := m[8]
m[0] = c * m[0] + s * m[2]
m[4] = c * m[4] + s * m[6]
m[8] = c * m[8] + s * m[10]
m[2] = c * m[2] - s * mv0
m[6] = c * m[6] - s * mv4
m[10] = c * m[10] - s * mv8
}
struct State {
mut:
drag bool
gl JS.WebGLRenderingContext
canvas JS.HTMLCanvasElement
old_x f64
old_y f64
dx f64
dy f64
theta f64
phi f64
time_old f64
mo_matrix []f64
view_matrix []f64
proj_matrix []f64
pmatrix JS.WebGLUniformLocation
vmatrix JS.WebGLUniformLocation
mmatrix JS.WebGLUniformLocation
index_buffer JS.WebGLBuffer
}
fn animate(mut state State, time f64) {
if !state.drag {
state.dx = state.dx * amortization
state.dy = state.dy * amortization
state.theta += state.dx
state.phi += state.dy
}
state.mo_matrix[0] = 1
state.mo_matrix[1] = 0
state.mo_matrix[2] = 0
state.mo_matrix[3] = 0
state.mo_matrix[4] = 0
state.mo_matrix[5] = 1
state.mo_matrix[6] = 0
state.mo_matrix[7] = 0
state.mo_matrix[8] = 0
state.mo_matrix[9] = 0
state.mo_matrix[10] = 1
state.mo_matrix[11] = 0
state.mo_matrix[12] = 0
state.mo_matrix[13] = 0
state.mo_matrix[14] = 0
state.mo_matrix[15] = 1
// println('${state.theta} ${state.phi}')
rotate_x(mut state.mo_matrix, state.phi)
rotate_y(mut state.mo_matrix, state.theta)
state.time_old = time
state.gl.enable(jsdom.gl_depth_test())
state.gl.clearColor(0.5, 0.5, 0.5, 0.9)
state.gl.clearDepth(1.0)
state.gl.viewport(0.0, 0.0, state.canvas.width, state.canvas.height)
state.gl.clear(JS.Number(int(jsdom.gl_color_buffer_bit()) | int(jsdom.gl_depth_buffer_bit())))
state.gl.uniformMatrix4fv(state.pmatrix, JS.Boolean(false), state.proj_matrix.to_number_array())
state.gl.uniformMatrix4fv(state.vmatrix, JS.Boolean(false), state.view_matrix.to_number_array())
state.gl.uniformMatrix4fv(state.mmatrix, JS.Boolean(false), state.mo_matrix.to_number_array())
state.gl.bindBuffer(jsdom.gl_element_array_buffer(), state.index_buffer)
state.gl.drawElements(jsdom.gl_triangles(), indices.len, jsdom.gl_unsigned_short(),
0)
jsdom.window().requestAnimationFrame(fn [mut state] (time JS.Number) {
animate(mut state, f64(time))
})
}
fn main() {
canvas, gl := get_webgl()
vertex_buffer := gl.createBuffer() ?
gl.bindBuffer(jsdom.gl_array_buffer(), vertex_buffer)
gl.bufferData(jsdom.gl_array_buffer(), float32_array(vertices), jsdom.gl_static_draw())
color_buffer := gl.createBuffer() ?
gl.bindBuffer(jsdom.gl_array_buffer(), color_buffer)
gl.bufferData(jsdom.gl_array_buffer(), float32_array(colors), jsdom.gl_static_draw())
index_buffer := gl.createBuffer() ?
gl.bindBuffer(jsdom.gl_element_array_buffer(), index_buffer)
gl.bufferData(jsdom.gl_element_array_buffer(), uint16_array(indices), jsdom.gl_static_draw())
vert_shader := gl.createShader(jsdom.gl_vertex_shader()) ?
gl.shaderSource(vert_shader, vert_code.str)
gl.compileShader(vert_shader)
if !bool(JS.Boolean(gl.getShaderParameter(vert_shader, jsdom.gl_compile_status()))) {
panic('An error occurred when compiling vertex shader: ${string(gl.getShaderInfoLog(vert_shader))}')
}
frag_shader := gl.createShader(jsdom.gl_fragment_shader()) ?
gl.shaderSource(frag_shader, frag_code.str)
gl.compileShader(frag_shader)
if !bool(JS.Boolean(gl.getShaderParameter(frag_shader, jsdom.gl_compile_status()))) {
panic('An error occurred when compiling fragment shader: ${string(gl.getShaderInfoLog(frag_shader))}')
}
shader_program := gl.createProgram() ?
gl.attachShader(shader_program, vert_shader)
gl.attachShader(shader_program, frag_shader)
gl.linkProgram(shader_program)
if !bool(JS.Boolean(gl.getProgramParameter(shader_program, jsdom.gl_link_status()))) {
panic('unable to initialize the shader program: ${string(gl.getProgramInfoLog(shader_program))}')
}
pmatrix := gl.getUniformLocation(shader_program, 'Pmatrix'.str) ?
vmatrix := gl.getUniformLocation(shader_program, 'Vmatrix'.str) ?
mmatrix := gl.getUniformLocation(shader_program, 'Mmatrix'.str) ?
gl.bindBuffer(jsdom.gl_array_buffer(), vertex_buffer)
position := gl.getAttribLocation(shader_program, 'position'.str)
gl.vertexAttribPointer(position, JS.Number(3), jsdom.gl_float(), JS.Boolean(false),
JS.Number(0), JS.Number(0))
gl.enableVertexAttribArray(position)
gl.bindBuffer(jsdom.gl_array_buffer(), color_buffer)
color := gl.getAttribLocation(shader_program, 'color'.str)
gl.vertexAttribPointer(color, JS.Number(3), jsdom.gl_float(), JS.Boolean(false), JS.Number(0),
JS.Number(0))
gl.enableVertexAttribArray(color)
gl.useProgram(shader_program)
mut proj_matrix := get_projection(40.0, f64(canvas.width) / f64(canvas.height), 1.0,
100.0)
mut mo_matrix := [f64(1), 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
mut view_matrix := [f64(1), 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
view_matrix[14] = view_matrix[14] - 6
mut state := State{false, gl, canvas, 0, 0, 0, 0, 0, 0, 0, mo_matrix, view_matrix, proj_matrix, pmatrix, vmatrix, mmatrix, index_buffer}
canvas.addEventListener('mousedown'.str, fn [mut state] (e JS.Event) {
state.drag = true
match e {
JS.MouseEvent {
state.old_x = f64(e.pageX)
state.old_y = f64(e.pageY)
e.preventDefault()
}
else {}
}
}, JS.EventListenerOptions{})
canvas.addEventListener('mouseup'.str, fn [mut state] (e JS.Event) {
state.drag = false
}, JS.EventListenerOptions{})
canvas.addEventListener('mouseout'.str, fn [mut state] (e JS.Event) {
state.drag = false
}, JS.EventListenerOptions{})
canvas.addEventListener('mousemove'.str, fn [mut state] (e JS.Event) {
if !state.drag {
return
}
match e {
JS.MouseEvent {
state.dx = (f64(e.pageX) - state.old_x) * 2.0 * math.pi / f64(state.canvas.width)
state.dy = (f64(e.pageY) - state.old_y) * 2.0 * math.pi / f64(state.canvas.height)
state.theta += state.dx
state.phi += state.dy
state.old_x = f64(e.pageX)
state.old_y = f64(e.pageY)
e.preventDefault()
}
else {
panic('not a mouse event??')
}
}
}, JS.EventListenerOptions{})
animate(mut state, 0)
}