Ускорение записи новых значений в массив?
Я пополняю массив большим количеством новых значений, для отрисовки объектов на canvas'е, это занимает не мало времени. Собственно вопрос: можно ли ускорить этот процесс/другой способ сохранения данных? Код:
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>-</title>
</head>
<body style="margin: 0px;">
<canvas id="canvas" width="5000" height="5000">HTML5 Canvas is not supported by your browser</canvas>
<script src="./engine.js"></script>
<script id="main"></script>
<script>
window.onload = function() {
document.querySelector('#main').src = "./main.js";
}
</script>
</body>
</html>
main.js:
'use strict';
function draw() {
console.time('execution time');
console.time('write time');
for(let y = 0; y < mapY; y++) {
for(let x = 0; x < mapX; x++) {
addCell(x, y, 1, 0, 0, 1, 0, 0); // add cell to draw list (positionX, positionY, color0, color1, color2, color3, rotateAngle)
}
}
console.timeEnd('write time');
console.time('render time');
render(); // draw all from draw list
console.timeEnd('render time');
console.timeEnd('execution time');
}
const atlas = new Image();
const scale = 5;
const lineWidth = 0;
const mapX = Math.floor(canvas.width / scale);
const mapY = Math.floor(canvas.height / scale);
setupGL(scale, lineWidth, [0, 0, 0, 1]);
console.log('Map size: ' + mapX + 'x' + mapY);
atlas.src = './atlas.png';
atlas.onload = function() {
addTexture(gl, atlas);
draw();
}
window.onmousedown = function(e) {
if (e.button == 2) {
clearList(); // clear draw list
draw(); // draw
}
}
engine.js:
'use strict';
// ========== shaders ==========
const vsSource =
`#version 300 es
layout(location=0) in vec2 aPosition;
layout(location=1) in vec2 aTexCoord;
layout(location=2) in vec2 aOffset;
layout(location=3) in float aTexID;
layout(location=4) in vec4 aColor;
layout(location=5) in float aAngle;
layout(location=6) in float aTexTransperent;
layout(location=7) in float aSize;
layout(location=8) in float aLineWidth;
layout(location=9) in vec2 aResolution;
out vec4 vColor;
out vec2 vTexCoord;
out float vTexID;
out float vTexTransperent;
vec2 rotate(float angle) {
float c = cos(angle);
float s = sin(angle);
return vec2(aPosition.x * c - aPosition.y * s + 0.5, aPosition.x * s + aPosition.y * c + 0.5);
}
void main() {
gl_Position = vec4((((rotate(radians(aAngle)) + aOffset) * aSize + aOffset * aLineWidth) / aResolution * 2.0 - 1.0) * vec2(1.0, -1.0), 0.0, 1.0);
vColor = aColor;
vTexCoord = aTexCoord;
vTexID = aTexID;
vTexTransperent = aTexTransperent;
}`;
const fsSource =
`#version 300 es
precision lowp float;
in vec4 vColor;
in vec2 vTexCoord;
in float vTexID;
in float vTexTransperent;
uniform sampler2D uTexture;
out vec4 fragColor;
void main() {
if (vTexTransperent > 0.0) {
fragColor = texture(uTexture, (vTexCoord + vec2(mod(vTexID, 6.0), floor(vTexID / 6.0))) * 32.0 / 128.0) * vec4(1.0, 1.0, 1.0, vTexTransperent);
}
else {
fragColor = vColor;
}
}`;
// =========================
// ========== functions ==========
function createShader(gl, type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (gl.getShaderParameter(shader, gl.COMPILE_STATUS)) return shader;
console.log(type == gl.VERTEX_SHADER? 'VERTEX SHADER' : 'FRAGMENT SHADER', gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
}
function createProgram(gl, vsSource, fsSource) {
const program = gl.createProgram();
gl.attachShader(program, createShader(gl, gl.VERTEX_SHADER, vsSource));
gl.attachShader(program, createShader(gl, gl.FRAGMENT_SHADER, fsSource));
gl.linkProgram(program);
if (gl.getProgramParameter(program, gl.LINK_STATUS)) {
gl.useProgram(program);
return program
};
console.log(gl.getProgramInfoLog(program));
gl.deleteProgram(program);
}
function addTexture(gl, image) {
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
return texture;
}
function setupGL(size, lineWidth, color) {
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(color[0], color[1], color[2], color[3]);
gl.clear(gl.COLOR_BUFFER_BIT);
clearList();
gl.vertexAttrib1f(7, size); // set size
gl.vertexAttrib1f(8, lineWidth); // set line width
gl.vertexAttrib2f(9, canvas.width, canvas.height); // set canvas resolution in WebGL
}
function clearList() { // clear draw list
transformData.length = 0;
}
function addCell(offsetX, offsetY, color0, color1, color2, color3, angle, id) { // add cell to draw list
transformData.push(offsetX, offsetY, id, color0, color1, color2, color3, angle, 0, offsetX, offsetY, id, color0, color1, color2, color3, angle, 1);
}
function render() { // draw all form draw list
gl.bindBuffer(gl.ARRAY_BUFFER, transformBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(transformData), gl.STATIC_DRAW); // upload data to buffer
// set data to attributes
gl.vertexAttribPointer(2, 2, gl.FLOAT, false, 36, 0);
gl.vertexAttribPointer(3, 1, gl.FLOAT, false, 36, 8);
gl.vertexAttribPointer(4, 4, gl.FLOAT, false, 36, 12);
gl.vertexAttribPointer(5, 1, gl.FLOAT, false, 36, 28);
gl.vertexAttribPointer(6, 1, gl.FLOAT, false, 36, 32);
gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, transformData.length / 9);
}
// =========================
// ========== init ==========
const canvas = document.querySelector('#canvas');
const gl = canvas.getContext('webgl2', { preserveDrawingBuffer: true }) || canvas.getContext('experimental-webgl2', { preserveDrawingBuffer: true }); // get GL context
if (!gl) alert('WebGL Context init failed');
const program = createProgram(gl, vsSource, fsSource); // create shader program
const modelData = new Float32Array([
// position texCoord
-0.5, -0.5, 0, 0,
0.5, -0.5, 1, 0,
-0.5, 0.5, 0, 1,
-0.5, 0.5, 0, 1,
0.5, -0.5, 1, 0,
0.5, 0.5, 1, 1,
]);
const transformData = []; // offset; color; angle; texTransperent; texOffset
const modelBuffer = gl.createBuffer();
const transformBuffer = gl.createBuffer();
gl.enable(gl.BLEND); // enable transperency
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
//gl.enable(gl.DEPTH_TEST);
//gl.depthFunc(gl.LESS);
gl.bindBuffer(gl.ARRAY_BUFFER, modelBuffer);
gl.bufferData(gl.ARRAY_BUFFER, modelData, gl.STATIC_DRAW);
// set primitives vertecies
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 16, 0);
gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 16, 8);
// say webgl, that this attributes must change 1 per instance
gl.vertexAttribDivisor(2, 1);
gl.vertexAttribDivisor(3, 1);
gl.vertexAttribDivisor(4, 1);
gl.vertexAttribDivisor(5, 1);
gl.vertexAttribDivisor(6, 1);
gl.enableVertexAttribArray(0);
gl.enableVertexAttribArray(1);
gl.enableVertexAttribArray(2);
gl.enableVertexAttribArray(3);
gl.enableVertexAttribArray(4);
gl.enableVertexAttribArray(5);
gl.enableVertexAttribArray(6);
// =========================
Запись в массив в main.js => draw() & engine.js => addCell()
Источник: Stack Overflow на русском