aboutsummaryrefslogtreecommitdiff
path: root/web/pw-visualizer/src/webgl/vertexBufferLayout.ts
blob: f44ed47afc81b111969d541110be17a2a0b0c6b4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import type { VertexBuffer } from './buffer';
import type { Shader } from './shader';

export class VertexBufferElement {
    type: number;
    amount: number;
    type_size: number;
    normalized: boolean;
    index: string;

    constructor(
        type: number,
        amount: number,
        type_size: number,
        index: string,
        normalized: boolean,
    ) {
        this.type = type;
        this.amount = amount;
        this.type_size = type_size;
        this.normalized = normalized;
        this.index = index;
    }
}

export class VertexBufferLayout {
    elements: VertexBufferElement[];
    stride: number;
    offset: number;

    constructor(offset = 0) {
        this.elements = [];
        this.stride = 0;
        this.offset = offset;
    }

    // Maybe wrong normalized type
    push(
        type: number,
        amount: number,
        type_size: number,
        index: string,
        normalized = false,
    ) {
        this.elements.push(new VertexBufferElement(type, amount, type_size, index, normalized));
        this.stride += amount * type_size;
    }

    getElements(): VertexBufferElement[] {
        return this.elements;
    }

    getStride(): number {
        return this.stride;
    }
}

// glEnableVertexAttribArray is to specify what location of the current program the follow data is needed
// glVertexAttribPointer tells gl that that data is at which location in the supplied data
export class VertexArray {
    // There is no renderer ID, always at bind buffers and use glVertexAttribPointer
    buffers: VertexBuffer[];
    layouts: VertexBufferLayout[];

    constructor() {
        this.buffers = [];
        this.layouts = [];
    }

    addBuffer(vb: VertexBuffer, layout: VertexBufferLayout) {
        this.buffers.push(vb);
        this.layouts.push(layout);
    }

    updateBuffer(gl: WebGLRenderingContext, index: number, data: number[]) {
        this.buffers[index].updateData(gl, data);
    }

    /// Bind buffers providing program data
    bind(gl: WebGLRenderingContext, shader: Shader) {
        shader.bind(gl);
        for(let i = 0; i < this.buffers.length; i ++) {
            const buffer = this.buffers[i];
            const layout = this.layouts[i];

            buffer.bind(gl);
            const elements = layout.getElements();
            let offset = layout.offset;

            for (let j = 0; j < elements.length; j ++) {
                const element = elements[j];
                const location = shader.getAttribLocation(gl, element.index);

                if (location >= 0) {
                    gl.enableVertexAttribArray(location);
                    gl.vertexAttribPointer(
                        location, element.amount, element.type,
                        element.normalized, layout.stride, offset
                    );
                }

                offset += element.amount * element.type_size;
            }
        }
    }

    /// Undo bind operation
    unbind(gl: WebGLRenderingContext) {
        this.layouts.forEach((layout) => {
            layout.getElements().forEach((_, index) => {
                gl.disableVertexAttribArray(index);
            });
        })
    }
}