🏡 index : cold-air-networks/mirror-jetstream.git

/*
 * Copyright (C) 2025 Mozilla. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

const NUM_PARTICLES = 8000;

const scene = new THREE.Scene();
scene.background = new THREE.Color(0x111111);

const camera = new THREE.PerspectiveCamera(75, 1, 0.1, 1000);
const innerHeight = 1080;
const innerWidth = 1920;
camera.position.z = 500;

const canvas = {
  addEventListener() {},
  style: {},
  getContext(kind) {
    return {
      getExtension(extension) {
	if (extension == 'EXT_blend_minmax') {
          return {MIN_EXT: 32775, MAX_EXT: 32776}
	}
	if (extension == 'OES_vertex_array_object') {
          return {
            createVertexArrayOES() { return 1 },
            bindVertexArrayOES() {},
            deleteVertexArrayOES() {},
          }
	}
      },
      createTexture() {},
      bindTexture() {},
      texImage2D() {},
      texImage3D() {},
      texParameteri() {},
      uniform1i() {},
      uniform1f() {},
      uniform2f() {},
      uniform3f() {},
      uniform4f() {},
      clearColor() {},
      clear() {},
      clearDepth() {},
      clearStencil() {},
      enable() {},
      disable() {},
      depthFunc() {},
      depthMask() {},
      frontFace() {},
      cullFace() {},
      getContextAttributes() {},
      createBuffer() {},
      createFramebuffer() {},
      bindBuffer() {},
      bufferData() {},
      createProgram() {},
      attachShader() {},
      linkProgram() {},
      useProgram() {},
      getAttribLocation() {},
      getUniformLocation() {},
      createShader() {},
      shaderSource() {},
      compileShader() {},
      getShaderParameter() {},
      getProgramInfoLog() { return "" },
      getShaderInfoLog() { return "" },
      getProgramParameter() {},
      deleteShader() {},
      colorMask() {},
      stencilMask() {},
      createVertexArray() {},
      bindVertexArray() {},
      drawElements() {},
      lineWidth() {},
      drawArrays() {},
      viewport() {},
      getParameter(param) {
	if (param == 34930) { return 16 }
	if (param == 35660) { return 16 }
	if (param == 3379) { return 8192 }
	if (param == 36347) { return 1024 }
	if (param == 36348) { return 32 }
	if (param == 36349) { return 1024 }
	if (param == 35661) { return 80 }
	if (param == 7938) { return "WebGL 2.0" }
	if (param == 3088) { return [0,0,1024,480] }
	if (param == 2978) { return [0,0,1024,480] }
      },
      MAX_TEXTURE_IMAGE_UNITS: 34930,
      MAX_VERTEX_TEXTURE_IMAGE_UNITS: 35660,
      MAX_TEXTURE_SIZE: 3379,
      MAX_VERTEX_UNIFORM_VECTORS: 36347,
      MAX_VARYING_VECTORS: 36348,
      MAX_FRAGMENT_UNIFORM_VECTORS: 36349,
      MAX_COMBINED_TEXTURE_IMAGE_UNITS: 35661,
      VERSION: 7938,
      SCISSOR_BOX: 3088,
      VIEWPORT: 2978
    }
  }
}

const renderer = new THREE.WebGLRenderer({
  antialias: false,
  canvas,
  powerPreference: 'low-power',
  precision: 'lowp'
});
renderer.setSize(innerWidth, innerHeight);

const createGeometryParticle = (size) => {
  const visibleHeight = 2 * Math.tan(75 * Math.PI/360) * 500;
  const radius = (size / innerHeight) * visibleHeight / 2;

  // Main circle
  const geometry = new THREE.CircleGeometry(radius, 32);
  const material = new THREE.MeshBasicMaterial({
    color: 0xffffff,
    depthTest: false
  });
  const circle = new THREE.Mesh(geometry, material);

  const posArray = geometry.attributes.position.array;
  const outlineVertices = [];
  for (let i = 3; i < posArray.length; i += 3) {
    outlineVertices.push(
      new THREE.Vector3(
        posArray[i],
        posArray[i + 1],
        posArray[i + 2]
      )
    );
  }
  const outlineGeometry = new THREE.BufferGeometry().setFromPoints(outlineVertices);
  const outline = new THREE.LineLoop(
    outlineGeometry,
    new THREE.LineBasicMaterial({ color: 0x000000, depthTest: false })
  );

  const group = new THREE.Group();
  group.add(circle);
  group.add(outline);
  return group;
};

// Initialize particles
var initialized = false;
const particles = [];

function initialize() {
  for(let i = 0; i < NUM_PARTICLES; i++) {
    const size = 10 + Math.random() * 80;
    const particle = createGeometryParticle(size);

    // Random initial position
    const visibleWidth = 2 * Math.tan(75 * Math.PI/360) * 500 * camera.aspect;
    particle.position.set(
      THREE.MathUtils.randFloatSpread(visibleWidth),
      THREE.MathUtils.randFloatSpread(visibleWidth/camera.aspect),
      0
    );

    // Velocity storage
    particle.velocity = new THREE.Vector2(
      (Math.random() - 0.5) * 8,
      (Math.random() - 0.5) * 8
    );

    scene.add(particle);
    particles.push(particle);
  }
  initialized = true;
}

// Metrics and animation
const visibleWidth = 2 * Math.tan(75 * Math.PI/360) * 500 * camera.aspect;
const visibleHeight = visibleWidth / camera.aspect;

function animate() {
  particles.forEach(particle => {
    particle.position.x += particle.velocity.x;
    particle.position.y += particle.velocity.y;

    // Boundary checks
    if(Math.abs(particle.position.x) > visibleWidth/2)
      particle.velocity.x *= -1;
    if(Math.abs(particle.position.y) > visibleHeight/2)
      particle.velocity.y *= -1;
  });

  renderer.render(scene, camera);
}

class Benchmark {
  runIteration() {
    if (!initialized) {
      initialize();
    }
    animate();
  }
}