1class GizmoRenderer { 2 async init() { 3 const vertexShaderSource = await fetchFile('shaders/gizmo_vertex.glsl') 4 const fragmentShaderSource = await fetchFile('shaders/gizmo_fragment.glsl') 5 6 this.program = createProgram(gl, vertexShaderSource, fragmentShaderSource) 7 this.buffer = gl.createBuffer() 8 9 this.planeVertices = [] 10 } 11 12 // Construct a plane from 3 vertices 13 setPlaneVertices(v1 = [], v2 = [], v3 = []) { 14 // Return if there are not enough vertices 15 if (v1.length * v2.length * v3.length === 0) { 16 this.planeVertices = new Float32Array([...v1, ...v2, ...v3]) 17 return 18 } 19 20 // Update GUI 21 if (camController.p.textContent !== camController.texts['calibrated']) { 22 camController.p.textContent = camController.texts['calibrated'] 23 camController.finish.enable() 24 } 25 26 // Calculate center of selection 27 const center = vec3.add(vec3.create(), v1, vec3.add(vec3.create(), v2, v3)) 28 vec3.scale(center, center, 1 / 3) 29 30 // Calculate normal vector and 2 orthogonal vectors 31 const normal = vec3.normalize(vec3.create(), vec3.cross(vec3.create(), vec3.subtract(vec3.create(), v2, v1), vec3.subtract(vec3.create(), v3, v1))) 32 const u = vec3.normalize(vec3.create(), vec3.subtract(vec3.create(), v2, v1)) 33 const v = vec3.normalize(vec3.create(), vec3.cross(vec3.create(), normal, u)) 34 35 // Rotate orthogonal vectors by 45 degree along the normal 36 const rotM = mat4.fromRotation(mat4.create(), Math.PI/4, normal) 37 vec3.transformMat4(u, u, rotM) 38 vec3.transformMat4(v, v, rotM) 39 40 // Calculate 4 vertices to form a square 41 const scale = 15 42 vec3.add(v1, center, vec3.scale(vec3.create(), u, -scale)) 43 vec3.add(v2, center, vec3.scale(vec3.create(), v, scale)) 44 vec3.add(v3, center, vec3.scale(vec3.create(), v, -scale)) 45 const v4 = vec3.add(vec3.create(), center, vec3.scale(vec3.create(), u, scale)) 46 47 this.planeVertices = new Float32Array([...v1, ...v2, ...v3, ...v4]) 48 this.planeNormal = normal 49 if (this.planeNormal[2] < 0) vec3.scale(this.planeNormal, this.planeNormal, -1) 50 } 51 52 render() { 53 if (!settings.showGizmo || this.planeVertices.length === 0) return 54 55 gl.useProgram(this.program) 56 57 gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer) 58 gl.bufferData(gl.ARRAY_BUFFER, this.planeVertices, gl.DYNAMIC_DRAW) 59 60 const positionAttributeLocation = gl.getAttribLocation(this.program, "a_pos") 61 gl.vertexAttribPointer(positionAttributeLocation, 3, gl.FLOAT, false, 0, 0) 62 63 gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) 64 gl.uniformMatrix4fv(gl.getUniformLocation(this.program, 'projmatrix'), false, cam.vpm) 65 66 const cornerCount = this.planeVertices.length / 3 67 const drawCorners = cornerCount < 4 68 gl.uniform1f(gl.getUniformLocation(this.program, 'draw_plane'), drawCorners ? 0 : 1) 69 gl.uniform1f(gl.getUniformLocation(this.program, 'aspect'), gl.canvas.width / gl.canvas.height) 70 71 if (drawCorners) { 72 gl.drawArraysInstanced(gl.TRIANGLE_STRIP, 0, 4, this.planeVertices.length / 3) 73 } 74 else { 75 gl.vertexAttribDivisor(positionAttributeLocation, 0) 76 gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4) 77 } 78 79 // Undo WebGL state changes 80 gl.blendFunc(gl.ONE_MINUS_DST_ALPHA, gl.ONE) 81 gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); 82 gl.bufferData(gl.ARRAY_BUFFER, positionData, gl.DYNAMIC_DRAW); 83 gl.vertexAttribPointer(positionAttributeLocation, 3, gl.FLOAT, false, 0, 0) 84 gl.vertexAttribDivisor(positionAttributeLocation, 1) 85 } 86}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.