lodash#isTypedArray TypeScript Examples

The following examples show how to use lodash#isTypedArray. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: GeometryComponent.ts    From GWebGPUEngine with MIT License 5 votes vote down vote up
/**
   * when merge all the geometries into one, we need to transform every vertex's position
   * and every face's normal
   */
  public applyMatrix(matrix: mat4) {
    const positionAttribute = this.attributes.find(
      ({ name }) => name === 'position',
    );
    const normalAttribute = this.attributes.find(
      ({ name }) => name === 'normal',
    );

    if (positionAttribute) {
      positionAttribute.dirty = true;

      if (positionAttribute.data && positionAttribute.data.length) {
        for (let i = 0; i < positionAttribute.data.length; i += 3) {
          const position = vec4.fromValues(
            positionAttribute.data[i] as number,
            positionAttribute.data[i + 1] as number,
            positionAttribute.data[i + 2] as number,
            1,
          );
          vec4.transformMat4(position, position, matrix);
          if (isTypedArray(positionAttribute.data)) {
            positionAttribute.data.set(
              [position[0], position[1], position[2]],
              i,
            );
          } else {
            positionAttribute.data[i] = position[0];
            positionAttribute.data[i + 1] = position[1];
            positionAttribute.data[i + 2] = position[2];
          }
        }
      }
    }

    if (normalAttribute) {
      const normalMatrix = mat3.normalFromMat4(mat3.create(), matrix);
      if (normalAttribute.data && normalAttribute.data.length) {
        for (let i = 0; i < normalAttribute.data.length; i += 3) {
          const normal = vec3.fromValues(
            normalAttribute.data[i] as number,
            normalAttribute.data[i + 1] as number,
            normalAttribute.data[i + 2] as number,
          );
          vec3.transformMat3(normal, normal, normalMatrix);
          vec3.normalize(normal, normal);
          if (isTypedArray(normalAttribute.data)) {
            normalAttribute.data.set(
              [normal[0], normal[1], normal[2]],
              i,
            );
          } else {
            normalAttribute.data[i] = normal[0];
            normalAttribute.data[i + 1] = normal[1];
            normalAttribute.data[i + 2] = normal[2];
          }
        }
      }
    }
  }
Example #2
Source File: uniform.ts    From GWebGPUEngine with MIT License 5 votes vote down vote up
function extractUniformsRecursively(
  uniformName: string,
  uniformValue: IUniform,
  uniforms: {
    [key: string]: IUniform;
  },
  prefix: string,
) {
  if (
    uniformValue === null ||
    typeof uniformValue === 'number' || // u_A: 1
    typeof uniformValue === 'boolean' || // u_A: false
    (Array.isArray(uniformValue) && typeof uniformValue[0] === 'number') || // u_A: [1, 2, 3]
    isTypedArray(uniformValue) || // u_A: Float32Array
    // @ts-ignore
    uniformValue === '' ||
    // @ts-ignore
    uniformValue.resize !== undefined
  ) {
    uniforms[`${prefix && prefix + '.'}${uniformName}`] = uniformValue;
    return;
  }

  // u_Struct.a.b.c
  if (isPlainObject(uniformValue)) {
    Object.keys(uniformValue).forEach((childName) => {
      extractUniformsRecursively(
        childName,
        // @ts-ignore
        uniformValue[childName],
        uniforms,
        `${prefix && prefix + '.'}${uniformName}`,
      );
    });
  }

  // u_Struct[0].a
  if (Array.isArray(uniformValue)) {
    // @ts-ignore
    uniformValue.forEach((child, idx) => {
      Object.keys(child).forEach((childName) => {
        extractUniformsRecursively(
          childName,
          // @ts-ignore
          child[childName],
          uniforms,
          `${prefix && prefix + '.'}${uniformName}[${idx}]`,
        );
      });
    });
  }
}
Example #3
Source File: ReglComputeModel.ts    From GWebGPUEngine with MIT License 5 votes vote down vote up
private calcDataTexture(
    name: string,
    type: DataType,
    data:
      | number
      | number[]
      | Float32Array
      | Uint8Array
      | Uint16Array
      | Uint32Array
      | Int8Array
      | Int16Array
      | Int32Array,
  ) {
    let elementsPerTexel = 1;
    if (type === AST_TOKEN_TYPES.Vector4FloatArray) {
      elementsPerTexel = 4;
    }

    // 用 0 补全不足 vec4 的部分
    const paddingData: number[] = [];
    for (let i = 0; i < (data as number[]).length; i += elementsPerTexel) {
      if (elementsPerTexel === 1) {
        paddingData.push((data as number[])[i], 0, 0, 0);
      } else if (elementsPerTexel === 2) {
        paddingData.push(
          (data as number[])[i],
          (data as number[])[i + 1],
          0,
          0,
        );
      } else if (elementsPerTexel === 3) {
        paddingData.push(
          (data as number[])[i],
          (data as number[])[i + 1],
          (data as number[])[i + 2],
          0,
        );
      } else if (elementsPerTexel === 4) {
        paddingData.push(
          (data as number[])[i],
          (data as number[])[i + 1],
          (data as number[])[i + 2],
          (data as number[])[i + 3],
        );
      }
    }

    // 使用纹理存储,例如 Array(8) 使用 3 * 3 纹理,末尾空白使用 0 填充
    const originalDataLength = (data as ArrayLike<number>).length;
    const texelCount = Math.ceil(originalDataLength / elementsPerTexel);
    const width = Math.ceil(Math.sqrt(texelCount));
    const paddingTexelCount = width * width;
    if (texelCount < paddingTexelCount) {
      paddingData.push(
        ...new Array((paddingTexelCount - texelCount) * 4).fill(0),
      );
    }

    const texture = this.reGl.texture({
      width,
      height: width,
      data: paddingData,
      type: 'float',
    });

    return {
      id: textureId++,
      data: paddingData,
      originalDataLength,
      typedArrayConstructor: isTypedArray(data) ? data!.constructor : undefined,
      textureWidth: width,
      texture,
      texelCount,
      elementsPerTexel,
      isOutput: name === this.context.output.name,
    };
  }
Example #4
Source File: Kernel.ts    From GWebGPUEngine with MIT License 5 votes vote down vote up
public setBinding(
    name:
      | string
      | Record<
          string,
          | number
          | number[]
          | Float32Array
          | Uint8Array
          | Uint16Array
          | Uint32Array
          | Int8Array
          | Int16Array
          | Int32Array
        >,
    data?:
      | number
      | number[]
      | Float32Array
      | Uint8Array
      | Uint16Array
      | Uint32Array
      | Int8Array
      | Int16Array
      | Int32Array
      | Kernel,
  ) {
    if (typeof name === 'string') {
      const isNumberLikeData =
        isNumber(data) || isTypedArray(data) || isArray(data);
      if (this.compiledBundle && this.compiledBundle.context) {
        // set define, eg. setBinding('MAX_LENGTH', 10)
        const existedDefine = this.compiledBundle.context.defines.find(
          (b) => b.name === name,
        );
        if (existedDefine) {
          existedDefine.value = data as number;
          return this;
        }

        // set uniform
        const existedBinding = this.compiledBundle.context.uniforms.find(
          (b) => b.name === name,
        );
        if (existedBinding) {
          // update uniform or buffer
          if (isNumberLikeData) {
            // @ts-ignore
            existedBinding.data = data;
            existedBinding.isReferer = false;

            if (existedBinding.storageClass === STORAGE_CLASS.Uniform) {
              if (this.model) {
                // @ts-ignore
                this.model.updateUniform(name, data);
              }
            } else {
              if (this.model) {
                // @ts-ignore
                this.model.updateBuffer(name, data);
              }
            }
          } else {
            // update with another kernel
            existedBinding.isReferer = true;
            // @ts-ignore
            existedBinding.data = data as Kernel;
          }
        }
      }
    } else {
      Object.keys(name).forEach((key) => {
        this.setBinding(key, name[key]);
      });
    }
    return this;
  }
Example #5
Source File: Merged.ts    From GWebGPUEngine with MIT License 5 votes vote down vote up
protected onEntityCreated() {
    const { geometries = [] } = this.config;

    const mergedComponent = this.getComponent();
    mergedComponent.aabb = new AABB();

    const mergedAttributes: GeometryComponent['attributes'] = [];
    const mergedIndices: number[] = [];
    let indexOffset = 0;
    geometries.forEach((geometry) => {
      const { aabb, indices, vertexCount, attributes } = geometry;

      // merge aabb
      mergedComponent.aabb.add(aabb);
      mergedComponent.vertexCount += vertexCount;

      // merge indices
      if (indices) {
        mergedIndices.push(...indices.map((index) => index + indexOffset));
      }
      indexOffset += vertexCount;

      // merge attributes
      attributes.forEach((attribute, i) => {
        if (!mergedAttributes[i]) {
          mergedAttributes[i] = attribute;
          mergedAttributes[i].dirty = true;
        } else {
          if (attribute.data) {
            if (isNumber(attribute.data)) {
              // @ts-ignore
              mergedAttributes[i].push(attribute.data);
            } else if (isTypedArray(attribute.data)) {
              // @ts-ignore
              mergedAttributes[i].data = merge(
                // @ts-ignore
                mergedAttributes[i].data,
                attribute.data,
              );
            } else {
              // @ts-ignore
              mergedAttributes[i].data = mergedAttributes[i].data.concat(
                attribute.data,
              );
            }
          }
        }
      });
    });

    mergedComponent.attributes = mergedAttributes;
    mergedComponent.indices = Uint32Array.from(mergedIndices);
    mergedComponent.dirty = true;
  }
Example #6
Source File: ReglComputeModel.ts    From GWebGPUEngine with MIT License 4 votes vote down vote up
constructor(private reGl: regl.Regl, private context: GLSLContext) {
    const uniforms: Record<string, any> = {};
    this.context.uniforms.forEach((uniform) => {
      const { name, type, data, isReferer, storageClass } = uniform;
      // store data with a 2D texture
      if (storageClass === STORAGE_CLASS.StorageBuffer) {
        if (!isReferer) {
          this.textureCache[name] = this.calcDataTexture(name, type, data!);
          const { textureWidth: width, isOutput } = this.textureCache[name];
          uniforms[`${name}Size`] = [width, width];

          if (isOutput) {
            this.outputTextureName = name;
            if (this.context.needPingpong) {
              this.outputTextureName = `${name}Output`;
              this.textureCache[this.outputTextureName] = this.calcDataTexture(
                name,
                type,
                data!,
              );
            }
          }
        } else {
          this.textureCache[name] = {
            data: undefined,
          };
          // refer to another kernel's output,
          // the referred kernel may not have been initialized, so we use dynamic way here
          uniforms[`${name}Size`] = () =>
            // @ts-ignore
            data.compiledBundle.context.output.textureSize;
        }

        uniforms[name] = () => {
          if (debug) {
            console.log(
              `[${this.entity}]: ${name} ${this.textureCache[name].id}`,
            );
          }
          return this.textureCache[name].texture;
        };
      } else if (storageClass === STORAGE_CLASS.Uniform) {
        if (
          data &&
          (Array.isArray(data) || isTypedArray(data)) &&
          (data as ArrayLike<number>).length > 16
        ) {
          // up to mat4 which includes 16 elements
          throw new Error(`invalid data type ${type}`);
        }
        // get uniform dynamically
        uniforms[name] = () => uniform.data;
      }
    });

    const { textureWidth, texelCount } = this.getOuputDataTexture();

    // 传入 output 纹理尺寸和数据长度,便于多余的 texel 提前退出
    uniforms.u_OutputTextureSize = [textureWidth, textureWidth];
    uniforms.u_OutputTexelCount = texelCount;

    // 保存在 Kernel 的上下文中,供其他 Kernel 引用
    this.context.output.textureSize = [textureWidth!, textureWidth!];

    const drawParams: regl.DrawConfig = {
      attributes: {
        a_Position: [
          [-1, 1, 0],
          [-1, -1, 0],
          [1, 1, 0],
          [1, -1, 0],
        ],
        a_TexCoord: [
          [0, 1],
          [0, 0],
          [1, 1],
          [1, 0],
        ],
      },
      frag: `#ifdef GL_FRAGMENT_PRECISION_HIGH
  precision highp float;
#else
  precision mediump float;
#endif
${this.context.shader}`,
      uniforms,
      vert: quadVert,
      // TODO: use a fullscreen triangle instead.
      primitive: 'triangle strip',
      count: 4,
    };

    this.computeCommand = this.reGl(drawParams);
  }