gl-plane
Version:
Draw a plane with texture
173 lines (162 loc) • 3.82 kB
text/typescript
import createShader, { GLShader } from "gl-shader"
import tragVertexSrc from "./shaders/trangle-vertex"
import trangFragSrc from "./shaders/trangle-fragment"
import createVAO, { GLVAO } from "gl-vao"
import createBuffer from "gl-buffer"
import createTexture from "gl-texture2d"
type GLBuffer = ReturnType<typeof createBuffer>
type Mat4 = [
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
number
]
type Position = [number, number, number]
const IDENTITY: Mat4 = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
export type DrawParam = {
model?: Mat4
view?: Mat4
projection: Mat4
}
export type GLPlaneOption = {
gl: WebGLRenderingContext
model?: Mat4
view?: Mat4
projection?: Mat4
opacity?: number
points: [Position, Position, Position, Position]
texture?: HTMLImageElement
}
export class GLPlane {
bounds = [
[0.3,0.3,0.4],
[1,1,1.2]
]
option: Required<Omit<GLPlaneOption, "texture">> & {
texture?: HTMLImageElement
}
vao: GLVAO
vertextBuffer: GLBuffer
trangleShader: GLShader<
{
model: Mat4
view: Mat4
projection: Mat4
},
"position"
>
texture: ReturnType<typeof createTexture>
constructor(opt: GLPlaneOption) {
this.option = {
model: IDENTITY,
view: IDENTITY,
projection: IDENTITY,
opacity: 1,
...opt
}
this.texture = createTexture(opt.gl, opt.texture || [1, 1])
const vertex =
this.getVertexCoords(...opt.points)
this.vertextBuffer = createBuffer(
opt.gl,
vertex
)
this.updateBounds(opt.points)
this.trangleShader = createShader(opt.gl, tragVertexSrc, trangFragSrc)
this.vao = createVAO(opt.gl, [
{
buffer: this.vertextBuffer,
type: opt.gl.FLOAT,
size: 3
},
{
buffer: createBuffer(opt.gl, [0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0]),
type: opt.gl.FLOAT,
size: 2
}
])
}
private getVertexCoords(
p1: Position,
p2: Position,
p3: Position,
p4: Position
) {
return [...p1, ...p2, ...p3, ...p1, ...p3, ...p4]
}
private updateBounds(points: Position[]) {
const max = [-Infinity,-Infinity,-Infinity]
const min = [Infinity,Infinity,Infinity]
for (let i = 1; i < points.length ; i++) {
const a = points[i-1]
const b = points[i]
for(let j = 0;j<3;j++) {
max[j] = Math.max(max[j],a[j],b[j])
min[j] = Math.min(min[j],a[j],b[j])
}
}
this.bounds=[
min,max
]
}
public pick() {
// No pick implementation yet
// but plotly need a pick method
return null
}
public isOpaque() {
return this.option.opacity === 1
}
public isTransparent() {
return !this.isOpaque()
}
public update(opt: Partial<GLPlaneOption>) {
const gl = opt.gl ?? this.option.gl
if (opt.texture && opt.texture !== this.option.texture) {
this.texture.dispose()
this.texture = createTexture(gl, opt.texture)
}
this.option = {
...this.option,
...opt
}
if(opt.points) {
this.updateBounds(opt.points)
this.vertextBuffer.update(
this.getVertexCoords(...opt.points)
)
}
}
public draw(param: DrawParam) {
const opt = this.option
const { gl } = opt
const uniforms = {
model: param.model ?? opt.model,
view: param.view ?? opt.view,
projection: param.projection ?? opt.projection,
opacity: opt.opacity,
texture: 0
}
this.texture.bind(0)
this.trangleShader.bind()
this.trangleShader.uniforms = uniforms
this.vao.bind()
gl.drawArrays(gl.TRIANGLES, 0, 6)
this.vao.unbind()
}
public drawTransparent(param: DrawParam) {
this.draw(param)
}
}