diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 5cea5ae2becb87f548c21fa17caa8ea5ea2f6b3e..0000000000000000000000000000000000000000 --- a/.eslintignore +++ /dev/null @@ -1,6 +0,0 @@ -node_modules - -dist -build -lib - diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 254a952a202ea94ab12564caf3fafbdea82bdb1c..0000000000000000000000000000000000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,473 +0,0 @@ -{ - "env": { - "es6": true, - "browser": true, - "node": true, - "mocha": true - }, - "globals": { - "global": false - }, - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaVersion": 8, - "sourceType": "module" - }, - "plugins": [ - "@typescript-eslint" - ], - "rules": { - // Possible Errors - "comma-dangle": [ - 1, - "only-multiline" - ], - "no-cond-assign": [ - 1, - "except-parens" - ], - "no-constant-condition": 1, - "no-control-regex": 1, - "no-debugger": 0, - "no-dupe-args": 1, - "no-dupe-keys": 1, - "no-duplicate-case": 1, - "no-empty": 1, - "no-empty-character-class": 1, - "no-ex-assign": 1, - "no-extra-boolean-cast": 1, - "no-extra-parens": 0, - "no-extra-semi": 1, - "no-func-assign": 1, - "no-inner-declarations": 1, - "no-invalid-regexp": 1, - "no-irregular-whitespace": 1, - "no-negated-in-lhs": 1, - "no-obj-calls": 1, - "no-regex-spaces": 1, - "no-sparse-arrays": 1, - "no-unexpected-multiline": 1, - "no-unreachable": 1, - "no-unsafe-finally": 1, - "use-isnan": 1, - "valid-jsdoc": [ - 0, - { - "requireReturn": false, - "requireReturnType": true, - "requireParamDescription": true, - "requireReturnDescription": true - } - ], - "valid-typeof": 1, - // Best Practices - "accessor-pairs": 1, - "array-callback-return": 1, - "block-scoped-var": 1, - "complexity": 0, - "curly": [ - 1, - "multi-line" - ], - "default-case": 0, - "dot-location": [ - 1, - "property" - ], - "dot-notation": 0, - "eqeqeq": 1, - "guard-for-in": 0, - "no-alert": 0, - "no-caller": 1, - "no-case-declarations": 0, - "no-div-regex": 1, - "no-else-return": 1, - "no-empty-function": 0, - "no-empty-pattern": 1, - "no-eq-null": 1, - "no-eval": 1, - "no-extend-native": 1, - "no-extra-bind": 1, - "no-extra-label": 1, - "no-fallthrough": 1, - "no-floating-decimal": 1, - "no-implicit-coercion": [ - 1, - { - "boolean": false, - "number": true, - "string": true, - "allow": [] - } - ], - "no-implicit-globals": 1, - "no-implied-eval": 1, - "no-invalid-this": 0, - "no-iterator": 1, - "no-labels": 1, - "no-lone-blocks": 1, - "no-loop-func": 1, - "no-magic-numbers": [ - 0 - ], - "no-multi-spaces": [ - 1, - { - "exceptions": { - "VariableDeclarator": true, - "ImportDeclaration": true, - "Property": true - } - } - ], - "no-multi-str": 1, - "no-native-reassign": 1, - "no-new": 0, - "no-new-func": 1, - "no-new-wrappers": 1, - "no-octal": 1, - "no-octal-escape": 1, - "no-param-reassign": 0, - "no-redeclare": 1, - "no-return-assign": 0, - "no-script-url": 1, - "no-self-assign": 1, - "no-self-compare": 1, - "no-sequences": 1, - "no-unmodified-loop-condition": 1, - "no-unused-expressions": "off", - "no-unused-labels": 1, - "no-useless-call": 1, - "no-useless-concat": 1, - "no-useless-escape": 0, - "no-void": 1, - "no-warning-comments": 0, - "no-with": 1, - "radix": 0, - "vars-on-top": 0, - "wrap-iife": [ - 1, - "inside" - ], - "yoda": 0, - // Strict Mode - "strict": [ - 1, - "global" - ], - // Variables - "init-declarations": 0, - "no-catch-shadow": 1, - "no-delete-var": 1, - "no-label-var": 1, - "no-restricted-globals": [ - "error", - "event", - "fdescribe" - ], - "no-shadow": 0, - "no-shadow-restricted-names": 1, - "no-undef": 1, - "no-undef-init": 1, - "no-undefined": 0, - "no-unused-vars": "off", - // Node.js and CommonJS - "callback-return": 0, - "global-require": 1, - "handle-callback-err": 1, - "no-mixed-requires": 1, - "no-new-require": 1, - "no-path-concat": 1, - "no-process-env": 0, - "no-process-exit": 0, - "no-restricted-modules": 0, - "no-sync": 0, - // Stylistic Issues - "array-bracket-spacing": [ - 1, - "never" - ], - "block-spacing": [ - 1, - "always" - ], - "brace-style": [ - 1, - "allman", - { - "allowSingleLine": true - } - ], - "camelcase": [ - 0, - { - "properties": "never" - } - ], - "comma-spacing": [ - 1, - { - "before": false, - "after": true - } - ], - "comma-style": [ - 1, - "last" - ], - "computed-property-spacing": [ - 1, - "never" - ], - "consistent-this": 0, - "func-style": [ - 1, - "declaration", - { - "allowArrowFunctions": true - } - ], - "id-blacklist": 0, - "id-length": 0, - "id-match": 0, - "jsx-quotes": [ - 1, - "prefer-double" - ], - "key-spacing": [ - 1, - { - "beforeColon": false, - "afterColon": true, - "mode": "minimum" - } - ], - "keyword-spacing": [ - 1, - { - "before": true, - "after": true - } - ], - "lines-around-comment": 0, - "max-depth": [ - 1, - 6 - ], - "max-lines": 0, - "max-nested-callbacks": [ - 1, - { - "max": 5 - } - ], - "max-params": [ - 1, - { - "max": 10 - } - ], - "max-statements": 0, - "new-cap": [ - 1, - { - "newIsCap": true, - "capIsNew": false, - "properties": false - } - ], - "new-parens": 1, - "newline-before-return": 1, - "newline-per-chained-call": [ - 1, - { - "ignoreChainWithDepth": 4 - } - ], - "no-array-constructor": 1, - "no-bitwise": 0, - "no-continue": 0, - "no-inline-comments": 0, - "no-lonely-if": 0, - "no-mixed-spaces-and-tabs": 1, - "no-multiple-empty-lines": [ - 1, - { - "max": 1, - "maxEOF": 1, - "maxBOF": 0 - } - ], - "no-negated-condition": 0, - "no-new-object": 1, - "no-plusplus": 0, - "no-restricted-syntax": 0, - "no-spaced-func": 1, - "no-ternary": 0, - "no-trailing-spaces": 1, - "no-underscore-dangle": 0, - "no-unneeded-ternary": 1, - "no-whitespace-before-property": 1, - "object-curly-newline": 0, - "object-curly-spacing": [ - 1, - "always" - ], - "object-property-newline": 0, - "one-var": [ - 1, - "never" - ], - "one-var-declaration-per-line": [ - 1, - "always" - ], - "operator-assignment": 0, - "operator-linebreak": [ - 1, - "before" - ], - "padded-blocks": [ - 1, - "never" - ], - "quote-props": [ - 1, - "as-needed" - ], - "quotes": [ - 1, - "double", - { - "allowTemplateLiterals": true - } - ], - "require-jsdoc": [ - 0, - { - "require": { - "FunctionDeclaration": false, - "ClassDeclaration": true, - "MethodDefinition": true - } - } - ], - "semi": [ - 1, - "always" - ], - "semi-spacing": [ - 1, - { - "before": false, - "after": true - } - ], - "sort-vars": 0, - "space-before-blocks": [ - 1, - "always" - ], - "space-in-parens": [ - 1, - "never" - ], - "space-infix-ops": 1, - "space-unary-ops": [ - 1, - { - "words": true, - "nonwords": false - } - ], - "unicode-bom": [ - 1, - "never" - ], - "wrap-regex": 1, - // ECMAScript 6 - "arrow-body-style": [ - 1, - "as-needed" - ], - "arrow-parens": 1, - "arrow-spacing": [ - 1, - { - "before": true, - "after": true - } - ], - "constructor-super": 1, - "generator-star-spacing": [ - 1, - { - "before": true, - "after": false - } - ], - "no-class-assign": 1, - "no-confusing-arrow": [ - 1, - { - "allowParens": true - } - ], - "no-const-assign": 1, - "no-dupe-class-members": 0, - "no-duplicate-imports": 0, - "no-new-symbol": 1, - "no-restricted-imports": 0, - "no-this-before-super": 1, - "no-useless-computed-key": 1, - "no-useless-constructor": 0, - "@typescript-eslint/no-useless-constructor": 0, - "no-useless-rename": 1, - "no-var": 1, - "object-shorthand": 1, - "prefer-arrow-callback": 0, - "prefer-const": 1, - "prefer-reflect": 0, - "prefer-rest-params": 0, - "prefer-spread": 0, - "prefer-template": 1, - "require-yield": 1, - "rest-spread-spacing": [ - 1, - "never" - ], - "sort-imports": 0, - "template-curly-spacing": [ - 1, - "never" - ], - "yield-star-spacing": [ - 1, - "before" - ] - }, - "overrides": [ - { - "files": [ - "*.ts" - ], - "extends": [ - "plugin:@typescript-eslint/recommended" - ], - "rules": { - "@typescript-eslint/ban-types": 0, - "@typescript-eslint/semi": 1, - "@typescript-eslint/no-explicit-any": 0, - "@typescript-eslint/interface-name-prefix": 0, - "@typescript-eslint/no-unused-vars": 0, - "@typescript-eslint/no-empty-interface": 0, - "@typescript-eslint/explicit-module-boundary-types": 0, - "@typescript-eslint/ban-ts-comment": 0, - "@typescript-eslint/no-this-alias": 0, - "@typescript-eslint/no-empty-function": 0, - "prefer-spread": 0, - "@typescript-eslint/no-non-null-assertion": 0 - } - } - ] -} \ No newline at end of file diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml new file mode 100644 index 0000000000000000000000000000000000000000..746cb82a8918a638a580d4082e16883e4cb3fd88 --- /dev/null +++ b/.github/workflows/master.yml @@ -0,0 +1,61 @@ +name: Master Branch CI + +on: + push: + branches: [ master ] + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Use Node.js 20.x + uses: actions/setup-node@v4 + with: + node-version: '20.x' + + - name: Install dependencies + run: npm install + + - name: Run unit tests + run: npm test + + - name: Build project + run: npm run build + + - name: docs + run: npm run docs + + - name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./public + + - name: Check npm version + id: check-npm-version + run: | + CURRENT_VERSION=$(node -p "require('./package.json').version") + PUBLISHED_VERSION=$(npm view . version 2>/dev/null || echo "0.0.0") + if [ "$CURRENT_VERSION" != "$PUBLISHED_VERSION" ]; then + echo "publish=true" >> $GITHUB_OUTPUT + else + echo "publish=false" >> $GITHUB_OUTPUT + fi + + - name: Publish to npm + if: steps.check-npm-version.outputs.publish == 'true' + run: | + echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > .npmrc + npm run release + + - name: Create git tag + if: steps.check-npm-version.outputs.publish == 'true' + run: | + VERSION=$(node -p "require('./package.json').version") + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git tag -a v$VERSION -m "Release v$VERSION" + git push origin v$VERSION diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml new file mode 100644 index 0000000000000000000000000000000000000000..bbeceb7f2ba0216a724f3f43689156cf69f68a2d --- /dev/null +++ b/.github/workflows/pull-request.yml @@ -0,0 +1,26 @@ +name: Pull Request CI + +on: + pull_request: + branches: [ master ] + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Use Node.js 20.x + uses: actions/setup-node@v4 + with: + node-version: '20.x' + + - name: Install dependencies + run: npm install + + - name: Run unit tests + run: npm test + + - name: Build project + run: npm run build \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 54bd9ee1017606651480d79d9a1767635b744bdd..0000000000000000000000000000000000000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,33 +0,0 @@ -# To contribute improvements to CI/CD templates, please follow the Development guide at: -# https://docs.gitlab.com/ee/development/cicd/templates.html -# This specific template is located at: -# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/npm.gitlab-ci.yml - -image: node:latest - -cache: - paths: - - node_modules/ - - examples/node_modules/ - -test: - stage: test - script: - - npm i -g pnpm - - pnpm i --no-frozen-lockfile - - npm run test - rules: - - if: $CI_MERGE_REQUEST_IID - - if: $CI_COMMIT_TAG - - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH - -pages: - stage: deploy - script: - - npm run docs - - npm run examples - artifacts: - paths: - - public - only: - - master diff --git a/.gitpod.yml b/.gitpod.yml deleted file mode 100644 index c165d7ff5b2781f2a344b6d1380b9cd6a48b7a70..0000000000000000000000000000000000000000 --- a/.gitpod.yml +++ /dev/null @@ -1,3 +0,0 @@ -tasks: - - init: npm i -g pnpm && pnpm i - command: npm run watch diff --git a/README.md b/README.md index 7dcf394a13721c0aac45ef4aa04a33bb2274ae42..69f9f938329bea50817e8d853b9e6661c0259fd6 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,17 @@ -# @feng3d/renderer +# @feng3d/render-api +提供WebGL/WebGPU统一的渲染数据结构,描述渲染所需的所有数据以及流程,用于@feng3d/webgl与@feng3d/webgpu。 -## 示例 +## 功能特性 -### WebGL2Samples -https://github.com/WebGLSamples/WebGL2Samples \ No newline at end of file +- 提供统一的WebGL/WebGPU渲染接口 +- 支持缓冲区(Buffer)、纹理(Texture)、采样器(Sampler)等资源管理 +- 支持渲染管线(RenderPipeline)配置 +- 支持渲染通道(RenderPass)设置 +- 类型安全的TypeScript实现 + +## 安装 + +```bash +npm install @feng3d/render-api +``` diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000000000000000000000000000000000000..26e30c793bdfc1db91f796e7035359be309b1bec --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,160 @@ +// 导入 ESLint 核心模块 +import eslint from '@eslint/js'; +// 导入 TypeScript ESLint 配置 +import tseslint from 'typescript-eslint'; +// 导入全局变量定义 +import globals from 'globals'; + +// 导出 ESLint 配置 +export default [ + // 忽略检查的文件和目录 + { + ignores: [ + '**/node_modules/**', // 忽略所有 node_modules 目录 + '**/dist/**', // 忽略所有 dist 目录 + '**/lib/**', // 忽略所有 lib 目录 + '**/public/**', // 忽略所有 public 目录 + '**/coverage/**', // 忽略所有 coverage 目录 + '**/.git/**', // 忽略所有 .git 目录 + '**/packages/**', // 忽略所有 packages 目录 + ], + }, + // 使用 ESLint 推荐配置 + eslint.configs.recommended, + // 使用 TypeScript ESLint 推荐配置 + ...tseslint.configs.recommended, + { + // 语言选项配置 + languageOptions: { + // 全局变量配置 + globals: { + ...globals.browser, // 浏览器环境全局变量 + ...globals.node, // Node.js 环境全局变量 + ...globals.es2021, // ES2021 全局变量 + global: false, // 禁用 global 全局变量 + }, + // 解析器选项 + parserOptions: { + ecmaVersion: 2021, // 使用 ES2021 语法 + sourceType: 'module', // 使用 ES 模块 + tsconfigRootDir: import.meta.dirname, // 明确指定 tsconfig 根目录 + }, + }, + rules: { + '@typescript-eslint/no-unused-vars': 'off', // 允许未使用的变量 + '@typescript-eslint/no-explicit-any': 'off', // 允许使用 any 类型 + 'no-prototype-builtins': 'off', // 允许直接使用 Object.prototype 方法 + '@typescript-eslint/ban-ts-comment': 'off', // 允许使用 @ts 注释 + '@typescript-eslint/no-unused-expressions': 'off', // 允许未使用的表达式 + '@typescript-eslint/no-empty-object-type': 'off', // 允许空对象类型 + '@typescript-eslint/no-unsafe-declaration-merging': 'off', // 允许不安全的声明合并 + '@typescript-eslint/no-unsafe-function-type': 'off', // 允许不安全的函数类型 + '@typescript-eslint/no-this-alias': 'off', // 允许 this 别名 + 'prefer-const': 'off', // 不强制使用 const + 'no-fallthrough': 'off', // 允许 fallthrough + 'no-constant-binary-expression': 'off', // 允许常量二进制表达式 + + // 注释格式规则 + 'spaced-comment': ['warn', 'always', { + 'line': { + 'markers': ['/'], // 以 / 开头的注释需要空格 + 'exceptions': ['-', '+'], // 允许以 - 和 + 开头的注释不需要空格 + }, + 'block': { + 'markers': ['!'], // 以 ! 开头的块级注释需要空格 + 'exceptions': ['*'], // 允许以 * 开头的块级注释不需要空格 + 'balanced': true, // 要求块级注释的 * 对齐 + }, + }], + + // 空格和换行规则 + 'no-trailing-spaces': ['warn', { // 禁止行尾空格 + 'skipBlankLines': false, // 不跳过空行 + 'ignoreComments': false, // 不忽略注释 + }], + 'no-multiple-empty-lines': ['warn', { // 限制空行数量 + 'max': 1, // 最多允许 1 个空行 + 'maxEOF': 1, // 文件末尾最多 1 个空行 + 'maxBOF': 0, // 文件开头不允许空行 + }], + 'lines-between-class-members': ['warn', 'always', { // 类成员之间需要空行 + 'exceptAfterSingleLine': true, // 单行成员后可以没有空行 + }], + 'padding-line-between-statements': [ // 语句之间的空行规则 + 'warn', + { 'blankLine': 'always', 'prev': '*', 'next': 'return' }, // return 前需要空行 + { 'blankLine': 'always', 'prev': ['const', 'let', 'var'], 'next': '*' }, // 变量声明后需要空行 + { 'blankLine': 'any', 'prev': ['const', 'let', 'var'], 'next': ['const', 'let', 'var'] }, // 变量声明之间可以没有空行 + ], + + // 缩进规则 + 'indent': ['warn', 4, { // 使用 4 空格缩进 + 'SwitchCase': 1, // switch case 缩进 1 级 + 'VariableDeclarator': 'first', // 变量声明对齐到第一个变量 + 'outerIIFEBody': 1, // 外层 IIFE 缩进 1 级 + 'MemberExpression': 1, // 成员表达式缩进 1 级 + 'FunctionDeclaration': { // 函数声明缩进规则 + 'parameters': 1, // 参数缩进 1 级 + 'body': 1, // 函数体缩进 1 级 + }, + 'FunctionExpression': { // 函数表达式缩进规则 + 'parameters': 1, // 参数缩进 1 级 + 'body': 1, // 函数体缩进 1 级 + }, + 'CallExpression': { // 函数调用缩进规则 + 'arguments': 1, // 参数缩进 1 级 + }, + 'ArrayExpression': 1, // 数组表达式缩进 1 级 + 'ObjectExpression': 1, // 对象表达式缩进 1 级 + 'ImportDeclaration': 1, // import 声明缩进 1 级 + 'flatTernaryExpressions': false, // 不扁平化三元表达式 + 'ignoreComments': false, // 不忽略注释 + }], + + // 引号规则 + 'quotes': ['warn', 'single', { // 使用单引号 + 'avoidEscape': true, // 允许使用转义字符 + 'allowTemplateLiterals': true, // 允许使用模板字符串 + }], + + // 其他格式规则 + 'semi': ['off'], // 要求使用分号 + 'comma-dangle': ['warn', 'always-multiline'], // 多行时要求尾随逗号 + 'object-curly-spacing': ['warn', 'always'], // 对象括号内要求空格 + 'array-bracket-spacing': ['warn', 'never'], // 数组括号内不允许空格 + 'arrow-spacing': ['warn', { // 箭头函数空格规则 + 'before': true, // 箭头前需要空格 + 'after': true, // 箭头后需要空格 + }], + 'block-spacing': ['warn', 'always'], // 块级代码需要空格 + 'brace-style': ['warn', 'allman', { // 大括号风格 + 'allowSingleLine': false, // 不允许单行大括号 + }], + 'comma-spacing': ['warn', { // 逗号空格规则 + 'before': false, // 逗号前不允许空格 + 'after': true, // 逗号后需要空格 + }], + 'comma-style': ['warn', 'last'], // 逗号放在行尾 + 'key-spacing': ['warn', { // 对象键值对空格规则 + 'beforeColon': false, // 冒号前不允许空格 + 'afterColon': true, // 冒号后需要空格 + }], + 'keyword-spacing': ['warn', { // 关键字空格规则 + 'before': true, // 关键字前需要空格 + 'after': true, // 关键字后需要空格 + }], + 'space-before-blocks': ['warn', 'always'], // 块级代码前需要空格 + 'space-before-function-paren': ['warn', { // 函数括号前空格规则 + 'anonymous': 'always', // 匿名函数括号前需要空格 + 'named': 'never', // 命名函数括号前不允许空格 + 'asyncArrow': 'always', // 异步箭头函数括号前需要空格 + }], + 'space-in-parens': ['warn', 'never'], // 括号内不允许空格 + 'space-infix-ops': ['warn'], // 操作符前后需要空格 + 'space-unary-ops': ['warn', { // 一元操作符空格规则 + 'words': true, // 单词类操作符需要空格 + 'nonwords': false, // 非单词类操作符不需要空格 + }], + }, + }, +]; \ No newline at end of file diff --git a/package.json b/package.json index df76e41e9b7276e3a3daaba9af09fda44fc07d3e..553b2b0678973f9d227b468a471e19479e425925 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,16 @@ { "name": "@feng3d/render-api", - "version": "0.0.6", - "description": "渲染接口", + "version": "0.0.7", + "description": "提供WebGL/WebGPU统一的渲染数据结构,描述渲染所需的所有数据以及流程,用于@feng3d/webgl与@feng3d/webgpu。", + "homepage": "https://feng3d.com/render-api/", "author": "feng", - "license": "MIT", "type": "module", "main": "./src/index.ts", "types": "./src/index.ts", "module": "./src/index.ts", "exports": { ".": { + "types": "./src/index.ts", "import": "./src/index.ts", "require": "./src/index.ts" } @@ -18,13 +19,13 @@ "clean": "rimraf \"{lib,dist,public}\"", "build": "vite build", "test": "vitest", - "test:ui": "vitest --ui", "types": "tsc", "watch": "tsc -w", - "lint": "eslint --ext .js --ext .ts src --ignore-path .gitignore --max-warnings 0", + "lint": "eslint . --ext .js,.ts --max-warnings 0", "lintfix": "npm run lint -- --fix", "docs": "typedoc", - "release": "npm run clean && npm run lint && npm run build && npm run types && npm publish", + "upload_oss": "npm run docs && feng3d-cli oss_upload_dir", + "release": "npm run clean && npm run lint && npm run build && npm run docs && npm run types && npm publish", "prepublishOnly": "node scripts/prepublish.js", "postpublish": "node scripts/postpublish.js" }, @@ -43,17 +44,22 @@ "tsconfig.json" ], "devDependencies": { - "@typescript-eslint/eslint-plugin": "5.17.0", - "@typescript-eslint/parser": "5.17.0", - "@vitest/ui": "^0.32.2", + "@eslint/js": "^9.0.0", + "@feng3d/cli": "^0.0.19", + "@typescript-eslint/eslint-plugin": "8.32.1", + "@typescript-eslint/parser": "8.32.1", + "typescript-eslint": "^8.32.1", "cross-env": "7.0.3", - "eslint": "8.12.0", - "rimraf": "3.0.2", - "tslib": "^2.4.0", - "typedoc": "^0.24.8", - "typescript": "5.1.3", - "vite": "^4.3.9", - "vitest": "^0.32.2" + "eslint": "9.26.0", + "globals": "^14.0.0", + "rimraf": "6.0.1", + "tslib": "^2.8.1", + "typedoc": "^0.28.4", + "typescript": "5.8.3", + "vite": "^6.3.5", + "vitest": "^3.1.3" }, - "dependencies": {} + "dependencies": { + "@feng3d/reactivity": "^1.0.6" + } } \ No newline at end of file diff --git a/scripts/postpublish.js b/scripts/postpublish.js index 01321a4f8d02a713ca1761b9439a8bb307f4685c..7296278c7ddd2d7a49f79e54c9798e633736be90 100644 --- a/scripts/postpublish.js +++ b/scripts/postpublish.js @@ -1,9 +1,10 @@ -import * as fs from "fs"; -import * as path from "path"; +import * as fs from 'fs'; +import * as path from 'path'; -const pkgpath = path.resolve("package.json"); +const pkgpath = path.resolve('package.json'); + +let pkg = fs.readFileSync(pkgpath, 'utf8'); -let pkg = fs.readFileSync(pkgpath, "utf8"); pkg = pkg .replace(`"types": "./lib/index.d.ts"`, `"types": "./src/index.ts"`) // @@ -12,6 +13,6 @@ pkg = pkg // .replace(`"import": "./dist/index.js"`, `"import": "./src/index.ts"`) .replace(`"require": "./dist/index.umd.cjs"`, `"require": "./src/index.ts"`) - ; +; -fs.writeFileSync(pkgpath, pkg, "utf8"); +fs.writeFileSync(pkgpath, pkg, 'utf8'); diff --git a/scripts/prepublish.js b/scripts/prepublish.js index db681a82362865d816f1de37e2b04357c58165a5..043f4c8f69daac13c4057bfea452b85d5ea3d15b 100644 --- a/scripts/prepublish.js +++ b/scripts/prepublish.js @@ -1,9 +1,10 @@ -import * as fs from "fs"; -import * as path from "path"; +import * as fs from 'fs'; +import * as path from 'path'; -const pkgpath = path.resolve("package.json"); +const pkgpath = path.resolve('package.json'); + +let pkg = fs.readFileSync(pkgpath, 'utf8'); -let pkg = fs.readFileSync(pkgpath, "utf8"); pkg = pkg .replace(`"types": "./src/index.ts"`, `"types": "./lib/index.d.ts"`) // @@ -12,6 +13,6 @@ pkg = pkg // .replace(`"import": "./src/index.ts"`, `"import": "./dist/index.js"`) .replace(`"require": "./src/index.ts"`, `"require": "./dist/index.umd.cjs"`) - ; +; -fs.writeFileSync(pkgpath, pkg, "utf8"); +fs.writeFileSync(pkgpath, pkg, 'utf8'); diff --git a/src/consts/vertexFormatMap.ts b/src/consts/vertexFormatMap.ts index 4ccfd06e0110b488dbcdacda322fb5f6a1e0e9db..7631ea94f0986a4a2216101a2b1f4c540bbf7c90 100644 --- a/src/consts/vertexFormatMap.ts +++ b/src/consts/vertexFormatMap.ts @@ -1,40 +1,40 @@ -import { VertexFormat } from "../data/VertexAttributes"; +import { VertexFormat } from '../data/VertexAttributes'; /** * 顶点属性格式信息映射。 */ export const vertexFormatMap: Record = { - uint8x2: { numComponents: 2, type: "UNSIGNED_BYTE", normalized: false, dataType: "unsigned int", byteSize: 2, wgslType: "vec2", typedArrayConstructor: Uint8Array }, - uint8x4: { numComponents: 4, type: "UNSIGNED_BYTE", normalized: false, dataType: "unsigned int", byteSize: 4, wgslType: "vec4", typedArrayConstructor: Uint8Array }, - sint8x2: { numComponents: 2, type: "BYTE", normalized: false, dataType: "signed int", byteSize: 2, wgslType: "vec2", typedArrayConstructor: Int8Array }, - sint8x4: { numComponents: 4, type: "BYTE", normalized: false, dataType: "signed int", byteSize: 4, wgslType: "vec4", typedArrayConstructor: Int8Array }, - unorm8x2: { numComponents: 2, type: "UNSIGNED_BYTE", normalized: true, dataType: "unsigned normalized", byteSize: 2, wgslType: "vec2", typedArrayConstructor: Uint8Array }, - unorm8x4: { numComponents: 4, type: "UNSIGNED_BYTE", normalized: true, dataType: "unsigned normalized", byteSize: 4, wgslType: "vec4", typedArrayConstructor: Uint8Array }, - snorm8x2: { numComponents: 2, type: "BYTE", normalized: true, dataType: "signed normalized", byteSize: 2, wgslType: "vec2", typedArrayConstructor: Int8Array }, - snorm8x4: { numComponents: 4, type: "BYTE", normalized: true, dataType: "signed normalized", byteSize: 4, wgslType: "vec4", typedArrayConstructor: Int8Array }, - uint16x2: { numComponents: 2, type: "UNSIGNED_SHORT", normalized: false, dataType: "unsigned int", byteSize: 4, wgslType: "vec2", typedArrayConstructor: Uint16Array }, - uint16x4: { numComponents: 4, type: "UNSIGNED_SHORT", normalized: false, dataType: "unsigned int", byteSize: 8, wgslType: "vec4", typedArrayConstructor: Uint16Array }, - sint16x2: { numComponents: 2, type: "SHORT", normalized: false, dataType: "signed int", byteSize: 4, wgslType: "vec2", typedArrayConstructor: Int16Array }, - sint16x4: { numComponents: 4, type: "SHORT", normalized: false, dataType: "signed int", byteSize: 8, wgslType: "vec4", typedArrayConstructor: Int16Array }, - unorm16x2: { numComponents: 2, type: "UNSIGNED_SHORT", normalized: true, dataType: "unsigned normalized", byteSize: 4, wgslType: "vec2", typedArrayConstructor: Uint16Array }, - unorm16x4: { numComponents: 4, type: "UNSIGNED_SHORT", normalized: true, dataType: "unsigned normalized", byteSize: 8, wgslType: "vec4", typedArrayConstructor: Uint16Array }, - snorm16x2: { numComponents: 2, type: "SHORT", normalized: true, dataType: "signed normalized", byteSize: 4, wgslType: "vec2", typedArrayConstructor: Int16Array }, - snorm16x4: { numComponents: 4, type: "SHORT", normalized: true, dataType: "signed normalized", byteSize: 8, wgslType: "vec4", typedArrayConstructor: Int16Array }, - float16x2: { numComponents: 2, type: "HALF_FLOAT", normalized: false, dataType: "float", byteSize: 4, wgslType: "vec2", typedArrayConstructor: undefined }, - float16x4: { numComponents: 4, type: "HALF_FLOAT", normalized: false, dataType: "float", byteSize: 8, wgslType: "vec4", typedArrayConstructor: undefined }, - float32: { numComponents: 1, type: "FLOAT", normalized: false, dataType: "float", byteSize: 4, wgslType: "f32", typedArrayConstructor: Float32Array }, - float32x2: { numComponents: 2, type: "FLOAT", normalized: false, dataType: "float", byteSize: 8, wgslType: "vec2", typedArrayConstructor: Float32Array }, - float32x3: { numComponents: 3, type: "FLOAT", normalized: false, dataType: "float", byteSize: 12, wgslType: "vec3", typedArrayConstructor: Float32Array }, - float32x4: { numComponents: 4, type: "FLOAT", normalized: false, dataType: "float", byteSize: 16, wgslType: "vec4", typedArrayConstructor: Float32Array }, - uint32: { numComponents: 1, type: "UNSIGNED_INT", normalized: false, dataType: "unsigned int", byteSize: 4, wgslType: "u32", typedArrayConstructor: Uint32Array }, - uint32x2: { numComponents: 2, type: "UNSIGNED_INT", normalized: false, dataType: "unsigned int", byteSize: 8, wgslType: "vec2", typedArrayConstructor: Uint32Array }, - uint32x3: { numComponents: 3, type: "UNSIGNED_INT", normalized: false, dataType: "unsigned int", byteSize: 12, wgslType: "vec3", typedArrayConstructor: Uint32Array }, - uint32x4: { numComponents: 4, type: "UNSIGNED_INT", normalized: false, dataType: "unsigned int", byteSize: 16, wgslType: "vec4", typedArrayConstructor: Uint32Array }, - sint32: { numComponents: 1, type: "INT", normalized: false, dataType: "signed int", byteSize: 4, wgslType: "i32", typedArrayConstructor: Int32Array }, - sint32x2: { numComponents: 2, type: "INT", normalized: false, dataType: "signed int", byteSize: 8, wgslType: "vec2", typedArrayConstructor: Int32Array }, - sint32x3: { numComponents: 3, type: "INT", normalized: false, dataType: "signed int", byteSize: 12, wgslType: "vec3", typedArrayConstructor: Int32Array }, - sint32x4: { numComponents: 4, type: "INT", normalized: false, dataType: "signed int", byteSize: 16, wgslType: "vec4", typedArrayConstructor: Int32Array }, - "unorm10-10-10-2": { numComponents: 4, type: "UNSIGNED_INT_2_10_10_10_REV", normalized: true, dataType: "unsigned normalized", byteSize: 4, wgslType: "vec4", typedArrayConstructor: Int32Array } + uint8x2: { numComponents: 2, type: 'UNSIGNED_BYTE', normalized: false, dataType: 'unsigned int', byteSize: 2, wgslType: 'vec2', typedArrayConstructor: Uint8Array }, + uint8x4: { numComponents: 4, type: 'UNSIGNED_BYTE', normalized: false, dataType: 'unsigned int', byteSize: 4, wgslType: 'vec4', typedArrayConstructor: Uint8Array }, + sint8x2: { numComponents: 2, type: 'BYTE', normalized: false, dataType: 'signed int', byteSize: 2, wgslType: 'vec2', typedArrayConstructor: Int8Array }, + sint8x4: { numComponents: 4, type: 'BYTE', normalized: false, dataType: 'signed int', byteSize: 4, wgslType: 'vec4', typedArrayConstructor: Int8Array }, + unorm8x2: { numComponents: 2, type: 'UNSIGNED_BYTE', normalized: true, dataType: 'unsigned normalized', byteSize: 2, wgslType: 'vec2', typedArrayConstructor: Uint8Array }, + unorm8x4: { numComponents: 4, type: 'UNSIGNED_BYTE', normalized: true, dataType: 'unsigned normalized', byteSize: 4, wgslType: 'vec4', typedArrayConstructor: Uint8Array }, + snorm8x2: { numComponents: 2, type: 'BYTE', normalized: true, dataType: 'signed normalized', byteSize: 2, wgslType: 'vec2', typedArrayConstructor: Int8Array }, + snorm8x4: { numComponents: 4, type: 'BYTE', normalized: true, dataType: 'signed normalized', byteSize: 4, wgslType: 'vec4', typedArrayConstructor: Int8Array }, + uint16x2: { numComponents: 2, type: 'UNSIGNED_SHORT', normalized: false, dataType: 'unsigned int', byteSize: 4, wgslType: 'vec2', typedArrayConstructor: Uint16Array }, + uint16x4: { numComponents: 4, type: 'UNSIGNED_SHORT', normalized: false, dataType: 'unsigned int', byteSize: 8, wgslType: 'vec4', typedArrayConstructor: Uint16Array }, + sint16x2: { numComponents: 2, type: 'SHORT', normalized: false, dataType: 'signed int', byteSize: 4, wgslType: 'vec2', typedArrayConstructor: Int16Array }, + sint16x4: { numComponents: 4, type: 'SHORT', normalized: false, dataType: 'signed int', byteSize: 8, wgslType: 'vec4', typedArrayConstructor: Int16Array }, + unorm16x2: { numComponents: 2, type: 'UNSIGNED_SHORT', normalized: true, dataType: 'unsigned normalized', byteSize: 4, wgslType: 'vec2', typedArrayConstructor: Uint16Array }, + unorm16x4: { numComponents: 4, type: 'UNSIGNED_SHORT', normalized: true, dataType: 'unsigned normalized', byteSize: 8, wgslType: 'vec4', typedArrayConstructor: Uint16Array }, + snorm16x2: { numComponents: 2, type: 'SHORT', normalized: true, dataType: 'signed normalized', byteSize: 4, wgslType: 'vec2', typedArrayConstructor: Int16Array }, + snorm16x4: { numComponents: 4, type: 'SHORT', normalized: true, dataType: 'signed normalized', byteSize: 8, wgslType: 'vec4', typedArrayConstructor: Int16Array }, + float16x2: { numComponents: 2, type: 'HALF_FLOAT', normalized: false, dataType: 'float', byteSize: 4, wgslType: 'vec2', typedArrayConstructor: undefined }, + float16x4: { numComponents: 4, type: 'HALF_FLOAT', normalized: false, dataType: 'float', byteSize: 8, wgslType: 'vec4', typedArrayConstructor: undefined }, + float32: { numComponents: 1, type: 'FLOAT', normalized: false, dataType: 'float', byteSize: 4, wgslType: 'f32', typedArrayConstructor: Float32Array }, + float32x2: { numComponents: 2, type: 'FLOAT', normalized: false, dataType: 'float', byteSize: 8, wgslType: 'vec2', typedArrayConstructor: Float32Array }, + float32x3: { numComponents: 3, type: 'FLOAT', normalized: false, dataType: 'float', byteSize: 12, wgslType: 'vec3', typedArrayConstructor: Float32Array }, + float32x4: { numComponents: 4, type: 'FLOAT', normalized: false, dataType: 'float', byteSize: 16, wgslType: 'vec4', typedArrayConstructor: Float32Array }, + uint32: { numComponents: 1, type: 'UNSIGNED_INT', normalized: false, dataType: 'unsigned int', byteSize: 4, wgslType: 'u32', typedArrayConstructor: Uint32Array }, + uint32x2: { numComponents: 2, type: 'UNSIGNED_INT', normalized: false, dataType: 'unsigned int', byteSize: 8, wgslType: 'vec2', typedArrayConstructor: Uint32Array }, + uint32x3: { numComponents: 3, type: 'UNSIGNED_INT', normalized: false, dataType: 'unsigned int', byteSize: 12, wgslType: 'vec3', typedArrayConstructor: Uint32Array }, + uint32x4: { numComponents: 4, type: 'UNSIGNED_INT', normalized: false, dataType: 'unsigned int', byteSize: 16, wgslType: 'vec4', typedArrayConstructor: Uint32Array }, + sint32: { numComponents: 1, type: 'INT', normalized: false, dataType: 'signed int', byteSize: 4, wgslType: 'i32', typedArrayConstructor: Int32Array }, + sint32x2: { numComponents: 2, type: 'INT', normalized: false, dataType: 'signed int', byteSize: 8, wgslType: 'vec2', typedArrayConstructor: Int32Array }, + sint32x3: { numComponents: 3, type: 'INT', normalized: false, dataType: 'signed int', byteSize: 12, wgslType: 'vec3', typedArrayConstructor: Int32Array }, + sint32x4: { numComponents: 4, type: 'INT', normalized: false, dataType: 'signed int', byteSize: 16, wgslType: 'vec4', typedArrayConstructor: Int32Array }, + 'unorm10-10-10-2': { numComponents: 4, type: 'UNSIGNED_INT_2_10_10_10_REV', normalized: true, dataType: 'unsigned normalized', byteSize: 4, wgslType: 'vec4', typedArrayConstructor: Int32Array }, }; /** @@ -46,31 +46,31 @@ export type TypedArrayConstructor = Int8ArrayConstructor | Uint8ArrayConstructor * GPU顶点数据类型 */ export type VertexDataType = - | "unsigned int" - | "signed int" - | "unsigned normalized" - | "signed normalized" - | "float" + | 'unsigned int' + | 'signed int' + | 'unsigned normalized' + | 'signed normalized' + | 'float' ; /** * 顶点数据在WGSL中的类型。 */ export type WGSLVertexType = - | "vec2" - | "vec4" - | "vec2" - | "vec4" - | "vec2" - | "vec4" - | "vec2" - | "vec4" - | "f32" - | "vec3" - | "u32" - | "vec3" - | "i32" - | "vec3" + | 'vec2' + | 'vec4' + | 'vec2' + | 'vec4' + | 'vec2' + | 'vec4' + | 'vec2' + | 'vec4' + | 'f32' + | 'vec3' + | 'u32' + | 'vec3' + | 'i32' + | 'vec3' ; /** @@ -94,8 +94,8 @@ export type WGSLVertexType = * * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/vertexAttribPointer */ -export type GLVertexAttributeTypes = "FLOAT" | "BYTE" | "SHORT" | "UNSIGNED_BYTE" | "UNSIGNED_SHORT" // WebGL1 - | "HALF_FLOAT" | "INT" | "UNSIGNED_INT" | "INT_2_10_10_10_REV" | "UNSIGNED_INT_2_10_10_10_REV"; // WebGL2 +export type GLVertexAttributeTypes = 'FLOAT' | 'BYTE' | 'SHORT' | 'UNSIGNED_BYTE' | 'UNSIGNED_SHORT' // WebGL1 + | 'HALF_FLOAT' | 'INT' | 'UNSIGNED_INT' | 'INT_2_10_10_10_REV' | 'UNSIGNED_INT_2_10_10_10_REV'; // WebGL2 /** * 顶点属性格式信息 diff --git a/src/data/BindingResources.ts b/src/data/BindingResources.ts index bc81821878dcd5bee47dc01be3ac39889d2dc2d8..0d07a876c6a9a989a8d91fa5a84f468e9ac0d067 100644 --- a/src/data/BindingResources.ts +++ b/src/data/BindingResources.ts @@ -1,4 +1,4 @@ -import { BufferBinding, BufferBindingItem } from './BufferBinding'; +import { BufferBinding } from './BufferBinding'; /** * 绑定资源。 @@ -7,7 +7,7 @@ import { BufferBinding, BufferBindingItem } from './BufferBinding'; */ export interface BindingResources { - [key: string]: BindingResource; + readonly [key: string]: BindingResource; } /** @@ -21,5 +21,4 @@ export interface BindingResourceTypeMap * 缓冲区绑定。 */ BufferBinding: BufferBinding; - BufferBindingItem: BufferBindingItem; } diff --git a/src/data/BlendState.ts b/src/data/BlendState.ts index 1d98929875ac49a631c229d55bf43920da4d6b97..ea95aa17c704fabe9cf156700003359df22b670b 100644 --- a/src/data/BlendState.ts +++ b/src/data/BlendState.ts @@ -43,7 +43,7 @@ export class BlendState * @param blend * @returns */ - static getBlendConstantColor(blendState: BlendState): Color + static getBlendConstantColor(blendState: BlendState): Color | undefined { if (!blendState) return undefined; @@ -65,7 +65,7 @@ export class BlendState if (constantColor) { - return [constantColor[0], constantColor[1], constantColor[2], constantColor[3]]; + return constantColor; } return constantColor ?? [0, 0, 0, 0]; diff --git a/src/data/Buffer.ts b/src/data/Buffer.ts index de7689afb52884809df84605790fa72bf88dd63c..0a33275c3de594899e206da797c59c854e410e5c 100644 --- a/src/data/Buffer.ts +++ b/src/data/Buffer.ts @@ -16,6 +16,8 @@ export interface Buffer * 标签。 * * 用于调试。 + * + * 注:修改后将重新创建GPUBuffer。 */ readonly label?: string; @@ -24,19 +26,57 @@ export interface Buffer * * 尺寸必须为4的倍数。 * - * 注:修改尺寸时,会重新创建缓冲区。 + * 注:修改后将重新创建GPUBuffer。 */ readonly size: number; /** * 缓冲区数据。 + * + * 注:修改后将重新创建GPUBuffer。 */ - data?: TypedArray; + readonly data?: ArrayBufferLike; /** * 写缓冲区。 * * {@link GPUQueue.writeBuffer} */ - writeBuffers?: WriteBuffer[]; + readonly writeBuffers?: WriteBuffer[]; } + +export class Buffer +{ + /** + * 从TypedArray创建或获取缓冲区配置 + * 自动处理缓冲区大小对齐(4字节对齐) + * @param arrayBuffer 源数据数组 + * @returns 缓冲区配置对象 + */ + static getBuffer(data: TypedArray | ArrayBufferLike) + { + let arrayBuffer = data as ArrayBuffer; + + if ((data as ArrayBufferView).buffer) + { + arrayBuffer = (data as ArrayBufferView).buffer as ArrayBuffer; + } + + // 检查是否已存在对应的缓冲区配置 + let buffer = this.bufferMap.get(arrayBuffer); + + if (buffer) return buffer; + + // 创建新的缓冲区配置,确保大小为4的倍数 + buffer = { + size: Math.ceil(arrayBuffer.byteLength / 4) * 4, + data: arrayBuffer, + }; + this.bufferMap.set(arrayBuffer, buffer); + + return buffer; + } + + /** 缓冲区配置缓存映射表 */ + private static readonly bufferMap = new WeakMap(); +} \ No newline at end of file diff --git a/src/data/BufferBinding.ts b/src/data/BufferBinding.ts index c5fdea77a3f1b8ec37a149ee9f55a7db15399498..49f60bc7630a4115896ffa4ae40dc908da498bc7 100644 --- a/src/data/BufferBinding.ts +++ b/src/data/BufferBinding.ts @@ -10,7 +10,7 @@ import { TypedArray } from '../types/TypedArray'; */ export interface BufferBinding { - [name: string]: BufferBindingItem; + readonly value?: BufferBindingItem; /** * 如果未设置引擎将自动生成。 diff --git a/src/data/CanvasContext.ts b/src/data/CanvasContext.ts index daf99105f890d89d306721f3a8e56c52dc8bbfbc..b4d47d3f5f2bd2b31e89819a6e0b3a2fa7675846 100644 --- a/src/data/CanvasContext.ts +++ b/src/data/CanvasContext.ts @@ -3,10 +3,10 @@ */ export interface CanvasContext { - __type__?: "CanvasContext"; - /** - * 画布id + * 画布。 + * + * 可能是画布的编号,也可能是画布元素或者离屏画布。 */ - readonly canvasId: string; + readonly canvasId: string | HTMLCanvasElement | OffscreenCanvas; } diff --git a/src/data/CanvasTexture.ts b/src/data/CanvasTexture.ts index 6737ac740a7814beeecd5adbcde6b321b41067da..b2b5753c88a2524fd93573a171ab20b50a9ef221 100644 --- a/src/data/CanvasTexture.ts +++ b/src/data/CanvasTexture.ts @@ -1,12 +1,10 @@ -import { CanvasContext } from "./CanvasContext"; +import { CanvasContext } from './CanvasContext'; /** * 画布纹理,从画布的上下文获取纹理 */ export interface CanvasTexture { - __type__?: "CanvasTexture"; - /** * 画布上下文。 */ diff --git a/src/data/ColorTargetState.ts b/src/data/ColorTargetState.ts index 49ac8075ff2c77e895f1a29441d473ee8b919578..db977ea8416123ff70cbf8163e5d919b1c1d632d 100644 --- a/src/data/ColorTargetState.ts +++ b/src/data/ColorTargetState.ts @@ -1,4 +1,4 @@ -import { BlendState } from "./BlendState"; +import { BlendState } from './BlendState'; /** * 属性 `format` 将由渲染通道中附件给出。 @@ -7,8 +7,6 @@ import { BlendState } from "./BlendState"; */ export interface ColorTargetState { - __type__?: "ColorTargetState"; - /** * The blending behavior for this color target. If left undefined, disables blending for this * color target. @@ -17,7 +15,7 @@ export interface ColorTargetState * * 默认 `undefined`,表示不进行混合。 */ - blend?: BlendState; + readonly blend?: BlendState; /** * 控制那些颜色分量是否可以被写入到颜色中。 @@ -28,7 +26,7 @@ export interface ColorTargetState * * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/colorMask */ - readonly writeMask?: IWriteMask; + readonly writeMask?: WriteMask; } -export type IWriteMask = [red: boolean, green: boolean, blue: boolean, alpha: boolean]; +export type WriteMask = readonly [red: boolean, green: boolean, blue: boolean, alpha: boolean]; diff --git a/src/data/CommandEncoder.ts b/src/data/CommandEncoder.ts index a1465eaceaac63af8b0b6ebadf52455c5aa62542..09639ea2df21b90d82065f9fad7051032fbcc422 100644 --- a/src/data/CommandEncoder.ts +++ b/src/data/CommandEncoder.ts @@ -1,6 +1,6 @@ -import { CopyBufferToBuffer } from "./CopyBufferToBuffer"; -import { CopyTextureToTexture } from "./CopyTextureToTexture"; -import { RenderPass } from "./RenderPass"; +import { CopyBufferToBuffer } from './CopyBufferToBuffer'; +import { CopyTextureToTexture } from './CopyTextureToTexture'; +import { RenderPass } from './RenderPass'; /** * 命令编码器。 @@ -9,14 +9,12 @@ import { RenderPass } from "./RenderPass"; */ export interface CommandEncoder { - __type__?: "CommandEncoder"; - /** * 通道编码器列表。 * * 包括计算通道编码器、渲染通道编码器 以及 GPU中缓存与纹理之间拷贝。 */ - passEncoders: IPassEncoder[] + passEncoders: PassEncoder[] } /** @@ -24,7 +22,7 @@ export interface CommandEncoder * * 如需扩展 IPassEncoder ,请在 PassEncoderMap 中进行添加。 */ -export type IPassEncoder = PassEncoderMap[keyof PassEncoderMap]; +export type PassEncoder = PassEncoderMap[keyof PassEncoderMap]; /** * 如需扩展 IPassEncoder ,请在 PassEncoderMap 中进行添加。 @@ -34,13 +32,13 @@ export interface PassEncoderMap /** * 渲染通道。 */ - IRenderPass: RenderPass; + RenderPass: RenderPass; /** * 纹理之间拷贝。 */ - ICopyTextureToTexture: CopyTextureToTexture; + CopyTextureToTexture: CopyTextureToTexture; - ICopyBufferToBuffer: CopyBufferToBuffer; + CopyBufferToBuffer: CopyBufferToBuffer; } diff --git a/src/data/CopyBufferToBuffer.ts b/src/data/CopyBufferToBuffer.ts index 264cfdedd5daba57a22819ef65b69dbae319dec4..36febdb6a929623182d033170f1f1099a627c446 100644 --- a/src/data/CopyBufferToBuffer.ts +++ b/src/data/CopyBufferToBuffer.ts @@ -1,4 +1,4 @@ -import { Buffer } from "./Buffer"; +import { Buffer } from './Buffer'; /** * GPU缓冲区之间拷贝。 @@ -11,7 +11,7 @@ export interface CopyBufferToBuffer /** * 数据类型。 */ - readonly __type__: "CopyBufferToBuffer"; + readonly __type__: 'CopyBufferToBuffer'; /** * 源缓冲区。 diff --git a/src/data/CopyTextureToTexture.ts b/src/data/CopyTextureToTexture.ts index c55126a012bc86b778790b5430f1cd63154d464b..6b18aadbc7354d3956d44aef8c913d699d063913 100644 --- a/src/data/CopyTextureToTexture.ts +++ b/src/data/CopyTextureToTexture.ts @@ -1,5 +1,5 @@ -import { ImageCopyTexture } from "./ImageCopyTexture"; -import { TextureSize } from "./Texture"; +import { ImageCopyTexture } from './ImageCopyTexture'; +import { TextureSize } from './Texture'; /** * GPU纹理间拷贝。 @@ -11,7 +11,7 @@ export interface CopyTextureToTexture /** * 数据类型。 */ - readonly __type__: "CopyTextureToTexture"; + readonly __type__: 'CopyTextureToTexture'; /** * Combined with `copySize`, defines the region of the source texture subresources. diff --git a/src/data/DepthStencilState.ts b/src/data/DepthStencilState.ts index 968cc071972e459e427161e477e069ced9c4b5c8..756721d79f7aa60424f10f57e432902623374fad 100644 --- a/src/data/DepthStencilState.ts +++ b/src/data/DepthStencilState.ts @@ -1,4 +1,4 @@ -import { ICompareFunction, StencilFaceState } from "./StencilFaceState"; +import { CompareFunction, StencilFaceState } from './StencilFaceState'; /** * 深度模板阶段描述。 @@ -11,8 +11,6 @@ import { ICompareFunction, StencilFaceState } from "./StencilFaceState"; */ export interface DepthStencilState { - __type__?: "DepthStencilState"; - /** * 指示这个 GPURenderPipeline 是否可以修改 depthStencilAttachment 深度值。 * @@ -29,7 +27,7 @@ export interface DepthStencilState * * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/depthFunc */ - readonly depthCompare?: ICompareFunction; + readonly depthCompare?: CompareFunction; /** * 定义了如何为朝前的图元执行模板比较和操作。 @@ -89,3 +87,40 @@ export interface DepthStencilState */ readonly depthBiasSlopeScale?: number; } + +/** + * 如果任意模板测试结果使用了 "replace" 运算,则需要再渲染前设置 `stencilReference` 值。 + * + * @param depthStencil + * @returns + */ +export function getStencilReference(depthStencil?: DepthStencilState): number | undefined +{ + if (!depthStencil) return undefined; + + const { stencilFront, stencilBack } = depthStencil; + + // 如果开启了模板测试,则需要设置模板索引值 + let stencilReference: number; + + if (stencilFront) + { + const { failOp, depthFailOp, passOp } = stencilFront; + + if (failOp === 'replace' || depthFailOp === 'replace' || passOp === 'replace') + { + stencilReference = depthStencil?.stencilReference ?? 0; + } + } + if (stencilBack) + { + const { failOp, depthFailOp, passOp } = stencilBack; + + if (failOp === 'replace' || depthFailOp === 'replace' || passOp === 'replace') + { + stencilReference = depthStencil?.stencilReference ?? 0; + } + } + + return stencilReference; +} \ No newline at end of file diff --git a/src/data/DrawIndexed.ts b/src/data/DrawIndexed.ts index 8d5614cd97dd8bf552f82e5d115633823775ec3f..8491e655a1efc6d84cb8a83c8f172fa7ee00990e 100644 --- a/src/data/DrawIndexed.ts +++ b/src/data/DrawIndexed.ts @@ -9,7 +9,7 @@ export interface DrawIndexed /** * 数据类型。 */ - readonly __type__: "DrawIndexed"; + readonly __type__: 'DrawIndexed'; /** * The number of indices to draw. diff --git a/src/data/DrawVertex.ts b/src/data/DrawVertex.ts index aa2cfdb2d315e7fb872985c94459437db1f0d4b8..146e8a9f2e2991c81cde642588e8b7ed3a4a3308 100644 --- a/src/data/DrawVertex.ts +++ b/src/data/DrawVertex.ts @@ -11,7 +11,7 @@ export interface DrawVertex /** * 数据类型。 */ - readonly __type__: "DrawVertex"; + readonly __type__: 'DrawVertex'; /** * The number of vertices to draw. diff --git a/src/data/FragmentState.ts b/src/data/FragmentState.ts index be66cb0784343a108e053f40758e769e7b27dc67..0c9da1898b941943d934f598fb80bdf871b054e8 100644 --- a/src/data/FragmentState.ts +++ b/src/data/FragmentState.ts @@ -1,4 +1,4 @@ -import { ColorTargetState } from "./ColorTargetState"; +import { ColorTargetState } from './ColorTargetState'; /** * 片段着色器阶段描述。 @@ -7,12 +7,10 @@ import { ColorTargetState } from "./ColorTargetState"; */ export interface FragmentState { - __type__?: "FragmentState"; - /** * 着色器代码。 */ - code: string; + readonly code: string; /** * A list of {@link GPUColorTargetState} defining the formats and behaviors of the color targets diff --git a/src/data/Geometry.ts b/src/data/Geometry.ts deleted file mode 100644 index 6e82cdf1b7be22bd7eedf9d52083d8d301a21aa4..0000000000000000000000000000000000000000 --- a/src/data/Geometry.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { DrawIndexed } from "./DrawIndexed"; -import { DrawVertex } from "./DrawVertex"; -import { PrimitiveState } from "./PrimitiveState"; -import { VertexAttribute, VertexAttributes } from "./VertexAttributes"; - -/** - * 几何数据。 - * - * 包含以下数据: - * - 顶点属性数据 - * - 顶点索引数据 - * - 如何渲染 - * - 拓扑结构 - */ -export interface Geometry -{ - __type__?: "Geometry"; - - /** - * Describes the primitive-related properties of the pipeline. - * - * 图元拓扑结构。 - */ - primitive?: PrimitiveState; - - /** - * 顶点属性数据映射。 - */ - vertices?: VertexAttributes; - - /** - * 顶点索引数据。 - */ - indices?: IIndicesDataTypes; - - /** - * 绘制。 - */ - draw?: IDraw; -} - -export class Geometry -{ - /** - * 获取顶点数量。 - * - * @returns 顶点数量。 - */ - static getNumVertex(geometry: Geometry) - { - const attributes = geometry.vertices; - const vertexList = Object.keys(attributes).map((v) => attributes[v]).filter((v) => (v.data && v.stepMode !== "instance")); - - const count = vertexList.length > 0 ? VertexAttribute.getVertexCount(vertexList[0]) : 0; - - // 验证所有顶点属性数据的顶点数量一致。 - if (vertexList.length > 0) - { - console.assert(vertexList.every((v) => count === VertexAttribute.getVertexCount(v))); - } - - return count; - } - - /** - * 获取实例数量。 - * - * @returns 实例数量。 - */ - static getInstanceCount(geometry: Geometry) - { - const attributes = geometry.vertices; - const vertexList = Object.keys(attributes).map((v) => attributes[v]).filter((v) => (v.data && v.stepMode === "instance")); - - const count = vertexList.length > 0 ? VertexAttribute.getVertexCount(vertexList[0]) : 1; - - // 验证所有顶点属性数据的顶点数量一致。 - if (vertexList.length > 0) - { - console.assert(vertexList.every((v) => count === VertexAttribute.getVertexCount(v))); - } - - return count; - } - - static getDraw(geometry: Geometry): DrawIndexed | DrawVertex - { - if (geometry["_draw"]) return geometry["_draw"]; - - const instanceCount = Geometry.getInstanceCount(geometry); - - if (geometry.indices) - { - return { - __type__: "DrawIndexed", - indexCount: geometry.indices.length, - firstIndex: 0, - instanceCount, - }; - } - - return { - __type__: "DrawVertex", - vertexCount: Geometry.getNumVertex(geometry), - instanceCount, - }; - } -} - -/** - * 顶点索引数据类型。 - */ -export type IIndicesDataTypes = Uint16Array | Uint32Array; - -/** - * 绘制图形。 - */ -export type IDraw = DrawVertex | DrawIndexed; diff --git a/src/data/ImageCopyTexture.ts b/src/data/ImageCopyTexture.ts index ff42f76f492e57fe3230d5f26e061a4bb68c8958..fdeb5544aa0d4120fd2f9e833eeacc4ac7e0c75b 100644 --- a/src/data/ImageCopyTexture.ts +++ b/src/data/ImageCopyTexture.ts @@ -1,5 +1,4 @@ -import { TextureOrigin, Texture } from "./Texture"; -import { TextureLike } from "./TextureView"; +import { TextureLike, TextureOrigin } from './Texture'; /** * 被操作的纹理相关信息。 @@ -9,8 +8,6 @@ import { TextureLike } from "./TextureView"; */ export interface ImageCopyTexture { - __type__?: "ImageCopyTexture"; - /** * Texture to copy to/from. */ @@ -30,7 +27,7 @@ export interface ImageCopyTexture /** * Defines which aspects of the {@link GPUImageCopyTexture#texture} to copy to/from. */ - aspect?: ITextureAspect; + aspect?: TextureAspect; } -export type ITextureAspect = "all" | "stencil-only" | "depth-only"; \ No newline at end of file +export type TextureAspect = 'all' | 'stencil-only' | 'depth-only'; \ No newline at end of file diff --git a/src/data/OcclusionQuery.ts b/src/data/OcclusionQuery.ts index 2d9836e524edc524138432e742e83bcfe3cefc04..4c11805ef92a9e71c0f804d2e1d4099f47dbe47c 100644 --- a/src/data/OcclusionQuery.ts +++ b/src/data/OcclusionQuery.ts @@ -1,11 +1,14 @@ -import { RenderObject } from "./RenderObject"; +import { RenderObject } from './RenderObject'; +/** + * 遮挡查询 + */ export interface OcclusionQuery { /** * 数据类型。 */ - readonly __type__: "OcclusionQuery"; + readonly __type__: 'OcclusionQuery'; /** * GPU渲染对象列表。 @@ -13,12 +16,9 @@ export interface OcclusionQuery renderObjects: RenderObject[]; /** - * 渲染完成后由引擎自动填充。 + * 查询结束回调。 + * + * @param result 是否被渲染。true表示被渲染,false表示未被渲染。 */ - result?: { - /** - * 查询结果。 - */ - result: number; - }; + onQuery?(result: number): void; } \ No newline at end of file diff --git a/src/data/PrimitiveState.ts b/src/data/PrimitiveState.ts index edcd0ce79988afeb930ff4f2aa8d6779c8c8c0f3..e1350bd469b167f56fc5f83e56323f0f4ad74029 100644 --- a/src/data/PrimitiveState.ts +++ b/src/data/PrimitiveState.ts @@ -7,8 +7,6 @@ */ export interface PrimitiveState { - __type__?: "PrimitiveState"; - /** * The type of primitive to be constructed from the vertex inputs. * @@ -26,7 +24,7 @@ export interface PrimitiveState * * LINE_LOOP 绘制循环连线。 * * TRIANGLE_FAN 绘制三角扇形。 */ - topology?: PrimitiveTopology; + readonly topology?: PrimitiveTopology; /** * Defines which polygon orientation will be culled, if any. @@ -39,14 +37,14 @@ export interface PrimitiveState * * `front` 剔除正面 * * `back` 剔除背面 */ - cullFace?: CullFace; + readonly cullFace?: CullFace; /** * Defines which polygons are considered front-facing. * * 正向方向。默认 "ccw",表示三角形逆时针方向为正面。 */ - frontFace?: FrontFace; + readonly frontFace?: FrontFace; } /** @@ -56,11 +54,11 @@ export type PrimitiveTopology = PrimitiveTopologyMap[keyof PrimitiveTopologyMap] export interface PrimitiveTopologyMap { - "point-list": "point-list", - "line-list": "line-list", - "line-strip": "line-strip", - "triangle-list": "triangle-list", - "triangle-strip": "triangle-strip", + 'point-list': 'point-list', + 'line-list': 'line-list', + 'line-strip': 'line-strip', + 'triangle-list': 'triangle-list', + 'triangle-strip': 'triangle-strip', } /** @@ -72,12 +70,12 @@ export type CullFace = CullFaceMap[keyof CullFaceMap]; export interface CullFaceMap { - "none": "none", - "front": "front", - "back": "back", + 'none': 'none', + 'front': 'front', + 'back': 'back', } /** * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/frontFace */ -export type FrontFace = "ccw" | "cw"; \ No newline at end of file +export type FrontFace = 'ccw' | 'cw'; \ No newline at end of file diff --git a/src/data/ReadPixels.ts b/src/data/ReadPixels.ts index 516980a0eda51303667273315a21ca2a94289806..0a743169986c58b44f47bc04a7dc4f8e56409a56 100644 --- a/src/data/ReadPixels.ts +++ b/src/data/ReadPixels.ts @@ -1,4 +1,4 @@ -import { TextureView } from "./TextureView"; +import { TextureView } from './TextureView'; /** * 读取渲染缓冲区或者纹理视图中的像素值。 diff --git a/src/data/RenderObject.ts b/src/data/RenderObject.ts index 46a560633062b1f395022b4ebf46736c00815de5..2193787ef7c42255145b88a130d59ed5f1588d82 100644 --- a/src/data/RenderObject.ts +++ b/src/data/RenderObject.ts @@ -1,8 +1,10 @@ -import { Geometry } from "./Geometry"; -import { RenderPipeline } from "./RenderPipeline"; -import { ScissorRect } from "./ScissorRect"; -import { BindingResources } from "./BindingResources"; -import { Viewport } from "./Viewport"; +import { BindingResources } from './BindingResources'; +import { DrawIndexed } from './DrawIndexed'; +import { DrawVertex } from './DrawVertex'; +import { RenderPipeline } from './RenderPipeline'; +import { ScissorRect } from './ScissorRect'; +import { VertexAttribute, VertexAttributes } from './VertexAttributes'; +import { Viewport } from './Viewport'; /** * 渲染对象,包含一次渲染时包含的所有数据。 @@ -12,34 +14,122 @@ export interface RenderObject /** * 数据类型。 */ - __type__?: "RenderObject"; + __type__?: 'RenderObject'; /** * 视窗。 * * 描述渲染在画布的哪个区域,默认整个画布。 */ - viewport?: Viewport; + readonly viewport?: Viewport; /** * 光栅化阶段中使用的剪刀矩形。 */ - scissorRect?: ScissorRect; + readonly scissorRect?: ScissorRect; /** * 渲染管线描述。 */ - pipeline: RenderPipeline; + readonly pipeline: RenderPipeline; /** - * 渲染几何数据。 + * 顶点属性数据映射。 */ - geometry: Geometry; + readonly vertices?: VertexAttributes; /** - * Uniform变量数据 + * 顶点索引数据。 */ - uniforms?: BindingResources; + readonly indices?: IndicesDataTypes; - _version?: number; + /** + * 绘制。 + */ + readonly draw?: IDraw; + + /** + * 绑定资源。 + * + * 与着色器中名称对应的绑定资源(纹理、采样器、统一数据、存储数据等)。 + */ + readonly bindingResources?: BindingResources; +} + +export class RenderObject +{ + /** + * 获取顶点数量。 + * + * @returns 顶点数量。 + */ + static getNumVertex(geometry: RenderObject) + { + const attributes = geometry.vertices; + const vertexList = Object.keys(attributes).map((v) => attributes[v]).filter((v) => (v.data && v.stepMode !== 'instance')); + + const count = vertexList.length > 0 ? VertexAttribute.getVertexCount(vertexList[0]) : 0; + + // 验证所有顶点属性数据的顶点数量一致。 + if (vertexList.length > 0) + { + console.assert(vertexList.every((v) => count === VertexAttribute.getVertexCount(v))); + } + + return count; + } + + /** + * 获取实例数量。 + * + * @returns 实例数量。 + */ + static getInstanceCount(geometry: RenderObject) + { + const attributes = geometry.vertices; + const vertexList = Object.keys(attributes).map((v) => attributes[v]).filter((v) => (v.data && v.stepMode === 'instance')); + + const count = vertexList.length > 0 ? VertexAttribute.getVertexCount(vertexList[0]) : 1; + + // 验证所有顶点属性数据的顶点数量一致。 + if (vertexList.length > 0) + { + console.assert(vertexList.every((v) => count === VertexAttribute.getVertexCount(v))); + } + + return count; + } + + static getDraw(geometry: RenderObject): DrawIndexed | DrawVertex + { + if (geometry['_draw']) return geometry['_draw']; + + const instanceCount = RenderObject.getInstanceCount(geometry); + + if (geometry.indices) + { + return { + __type__: 'DrawIndexed', + indexCount: geometry.indices.length, + firstIndex: 0, + instanceCount, + }; + } + + return { + __type__: 'DrawVertex', + vertexCount: RenderObject.getNumVertex(geometry), + instanceCount, + }; + } } + +/** + * 顶点索引数据类型。 + */ +export type IndicesDataTypes = Uint16Array | Uint32Array; + +/** + * 绘制图形。 + */ +export type IDraw = DrawVertex | DrawIndexed; diff --git a/src/data/RenderPass.ts b/src/data/RenderPass.ts index 81d4a24f445e11fcecfd772d5b02151b43624026..a9ff9b80024b27861245bd3c0351cd584d0deb38 100644 --- a/src/data/RenderPass.ts +++ b/src/data/RenderPass.ts @@ -1,6 +1,6 @@ -import { OcclusionQuery } from "./OcclusionQuery"; -import { RenderObject } from "./RenderObject"; -import { RenderPassDescriptor } from "./RenderPassDescriptor"; +import { OcclusionQuery } from './OcclusionQuery'; +import { RenderObject } from './RenderObject'; +import { RenderPassDescriptor } from './RenderPassDescriptor'; /** * WebGL渲染通道 @@ -12,7 +12,7 @@ export interface RenderPass /** * 数据类型。 */ - readonly __type__?: "RenderPass"; + readonly __type__?: 'RenderPass'; /** * 渲染通道描述 @@ -22,17 +22,18 @@ export interface RenderPass /** * 渲染对象列表 */ - readonly renderObjects?: readonly IRenderPassObject[]; + readonly renderPassObjects?: readonly RenderPassObject[]; /** - * 渲染不被遮挡查询结果。具体数据保存在各子项的"result"属性中。 + * 当渲染通道中存在遮挡查询时,在查询结束后调用该函数返回查询结果。 * - * 当提交WebGL后自动获取结果后填充该属性。 + * @param occlusionQuerys 遮挡查询列表 + * @param results 是否被渲染。true表示被渲染,false表示未被渲染。 */ - occlusionQueryResults?: OcclusionQuery[]; + onOcclusionQuery?(occlusionQuerys: OcclusionQuery[], results: number[]): void; } -export type IRenderPassObject = RenderPassObjectMap[keyof RenderPassObjectMap]; +export type RenderPassObject = RenderPassObjectMap[keyof RenderPassObjectMap]; export interface RenderPassObjectMap { diff --git a/src/data/RenderPassColorAttachment.ts b/src/data/RenderPassColorAttachment.ts index f7970f22595f0f464b155f51477a4d9aed32364c..9e8e79e1083c88efc4281447123e4b3856b80b00 100644 --- a/src/data/RenderPassColorAttachment.ts +++ b/src/data/RenderPassColorAttachment.ts @@ -1,12 +1,10 @@ -import { TextureView } from "./TextureView"; +import { TextureView } from './TextureView'; /** * 渲染通道颜色附件。 */ export interface RenderPassColorAttachment { - __type__?: "RenderPassColorAttachment"; - /** * 颜色附件视图。 * @@ -59,6 +57,15 @@ export interface RenderPassColorAttachment readonly loadOp?: LoadOp; } -export type Color = [red: number, green: number, blue: number, alpha: number]; +export type Color = readonly [red: number, green: number, blue: number, alpha: number]; + +export type LoadOp = 'load' | 'clear'; -export type LoadOp = "load" | "clear"; +/** + * 默认渲染通道颜色附件。 + */ +export const defaultRenderPassColorAttachment: RenderPassColorAttachment = { + view: undefined, + clearValue: [0, 0, 0, 0], + loadOp: 'clear', +} \ No newline at end of file diff --git a/src/data/RenderPassDepthStencilAttachment.ts b/src/data/RenderPassDepthStencilAttachment.ts index 77573f93de1ca7aa8e6fea51504b68b072cd402e..4df34ff1fa7fb02d8fa2da2b9e07e5a589176907 100644 --- a/src/data/RenderPassDepthStencilAttachment.ts +++ b/src/data/RenderPassDepthStencilAttachment.ts @@ -1,12 +1,10 @@ -import { TextureView } from "./TextureView"; +import { TextureView } from './TextureView'; /** * 深度模板附件。 */ export interface RenderPassDepthStencilAttachment { - __type__?: "RenderPassDepthStencilAttachment"; - /** * 深度附件视图。 * @@ -33,7 +31,7 @@ export interface RenderPassDepthStencilAttachment * * @see https://developer.mozilla.org/docs/Web/API/WebGLRenderingContext/clear */ - readonly depthLoadOp?: "load" | "clear"; + readonly depthLoadOp?: 'load' | 'clear'; /** * 清除后填充模板值。 @@ -51,5 +49,5 @@ export interface RenderPassDepthStencilAttachment * * @see https://developer.mozilla.org/docs/Web/API/WebGLRenderingContext/clear */ - readonly stencilLoadOp?: "load" | "clear"; -} \ No newline at end of file + readonly stencilLoadOp?: 'load' | 'clear'; +} diff --git a/src/data/RenderPassDescriptor.ts b/src/data/RenderPassDescriptor.ts index f571aa24f93edf852a65a3737d4813f3300dc134..731c7f1ac8ac4ce09204b37d3b9aed72d5581ef0 100644 --- a/src/data/RenderPassDescriptor.ts +++ b/src/data/RenderPassDescriptor.ts @@ -1,13 +1,11 @@ -import { RenderPassColorAttachment } from "./RenderPassColorAttachment"; -import { RenderPassDepthStencilAttachment } from "./RenderPassDepthStencilAttachment"; +import { RenderPassColorAttachment } from './RenderPassColorAttachment'; +import { RenderPassDepthStencilAttachment } from './RenderPassDepthStencilAttachment'; /** * 渲染通道描述 */ export interface RenderPassDescriptor { - __type__?: "RenderPassDescriptor"; - /** * 标签。 * @@ -40,4 +38,4 @@ export interface RenderPassDescriptor * 是否开启多重采样。WebGPU貌似只支持4重采样。如果在颜色附件中没有给出支持多重采样的纹理时则引擎将会自动为其添加。 */ readonly sampleCount?: 4; -} \ No newline at end of file +} diff --git a/src/data/RenderPipeline.ts b/src/data/RenderPipeline.ts index 448d83e47aea2e785dc4db24232bc738962ef8a8..aaca08b5a12e87363a0ee2964fc53e7de751242e 100644 --- a/src/data/RenderPipeline.ts +++ b/src/data/RenderPipeline.ts @@ -1,6 +1,7 @@ -import { DepthStencilState } from "./DepthStencilState"; -import { FragmentState } from "./FragmentState"; -import { VertexState } from "./VertexState"; +import { DepthStencilState } from './DepthStencilState'; +import { FragmentState } from './FragmentState'; +import { PrimitiveState } from './PrimitiveState'; +import { VertexState } from './VertexState'; /** * 渲染管线。 @@ -9,8 +10,6 @@ import { VertexState } from "./VertexState"; */ export interface RenderPipeline { - __type__?: "RenderPipeline"; - /** * 标签。 * @@ -21,12 +20,19 @@ export interface RenderPipeline /** * 顶点着色器阶段描述。 */ - vertex: VertexState; + readonly vertex: VertexState; /** * 片段着色器阶段描述。 */ - fragment?: FragmentState; + readonly fragment?: FragmentState; + + /** + * Describes the primitive-related properties of the pipeline. + * + * 图元拓扑结构。 + */ + readonly primitive?: PrimitiveState; /** * 深度模板阶段描述。 diff --git a/src/data/Sampler.ts b/src/data/Sampler.ts index c30d42db7d2159c3f2d6008cef4b2ef5b57c468c..6b50b77a5ed158a038df3f60ce93036fa3264b31 100644 --- a/src/data/Sampler.ts +++ b/src/data/Sampler.ts @@ -1,4 +1,4 @@ -import { ICompareFunction } from "./StencilFaceState"; +import { CompareFunction } from './StencilFaceState'; /** * 纹理采样器。 @@ -12,8 +12,6 @@ import { ICompareFunction } from "./StencilFaceState"; */ export interface Sampler { - __type__?: "Sampler"; - /** * 标签。 * @@ -29,7 +27,7 @@ export interface Sampler * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/samplerParameter#gl.texture_wrap_s * @see https://gpuweb.github.io/gpuweb/#dom-gpusamplerdescriptor-addressmodeu */ - addressModeU?: IAddressMode; + readonly addressModeU?: IAddressMode; /** * 用于指定纹理在垂直方向(即T或V坐标轴)上的寻址模式。 @@ -39,7 +37,7 @@ export interface Sampler * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/samplerParameter#gl.texture_wrap_t * @see https://gpuweb.github.io/gpuweb/#dom-gpusamplerdescriptor-addressmodev */ - addressModeV?: IAddressMode; + readonly addressModeV?: IAddressMode; /** * 用于指定纹理在深度方向(即R或W坐标轴)上的寻址模式。用于3D纹理或者纹理数组。 @@ -49,7 +47,7 @@ export interface Sampler * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/samplerParameter#gl.texture_wrap_r * @see https://gpuweb.github.io/gpuweb/#dom-gpusamplerdescriptor-addressmodew */ - addressModeW?: IAddressMode; + readonly addressModeW?: IAddressMode; /** * 指定样本足迹小于或等于一个纹素时的采样行为 @@ -59,7 +57,7 @@ export interface Sampler * @see https://www.orillusion.com/zh/webgpu.html#dom-gpusamplerdescriptor-magfilter * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/samplerParameter#gl.texture_mag_filter */ - magFilter?: IFilterMode; + readonly magFilter?: IFilterMode; /** * 指定样本足迹大于一个纹素时的采样行为。 @@ -71,7 +69,7 @@ export interface Sampler * @see https://www.orillusion.com/zh/webgpu.html#dom-gpusamplerdescriptor-minfilter * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/samplerParameter#gl.texture_min_filter */ - minFilter?: IFilterMode; + readonly minFilter?: IFilterMode; /** * 指定在 mipmap 级别之间进行采样的行为。 @@ -81,12 +79,14 @@ export interface Sampler * @see https://www.orillusion.com/zh/webgpu.html#dom-gpusamplerdescriptor-mipmapfilter * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/samplerParameter#gl.texture_min_filter */ - mipmapFilter?: IMipmapFilterMode; + readonly mipmapFilter?: IMipmapFilterMode; /** * 指定采样器使用的最大各向异性值夹具。 * 各向异性过滤。使用各向异性过滤能够使纹理的效果更好,但是会消耗更多的内存、CPU、GPU时间。默认为1。 * + * 仅当 minFilter 、magFilter 或 mipmapFilter 为 "linear" 时才有效,否则取 1。 + * * 默认 1。 * * 注:大多数实现支持范围在1到16之间(包括1和16)的maxAnisotropy值。所使用的maxAnisotropy值将被限制在平台支持的最大值内 @@ -94,21 +94,21 @@ export interface Sampler * @see https://www.orillusion.com/zh/webgpu.html#dom-gpusamplerdescriptor-maxanisotropy * @see https://developer.mozilla.org/en-US/docs/Web/API/EXT_texture_filter_anisotropic */ - maxAnisotropy?: number; + readonly maxAnisotropy?: number; /** * 采样时使用的最小Lod等级。 * * 默认 0。 */ - lodMinClamp?: number; + readonly lodMinClamp?: number; /** * 采样时使用的最大Lod等级。 * * 默认 16 。 */ - lodMaxClamp?: number; + readonly lodMaxClamp?: number; /** * 涉及纹理比较操作时需提供,采样器将是具有指定 GPUCompareFunction 的比较采样器。 @@ -117,20 +117,20 @@ export interface Sampler * * 注:比较采样器可能会使用过滤,但采样结果将是 依赖于实现并且可能不同于正常的过滤规则。 */ - compare?: ICompareFunction; + readonly compare?: CompareFunction; } /** * 纹理坐标寻址模式。 */ -export type IAddressMode = "clamp-to-edge" | "repeat" | "mirror-repeat"; +export type IAddressMode = 'clamp-to-edge' | 'repeat' | 'mirror-repeat'; /** * 描述采样器在采样足迹与一个纹素不完全匹配时的行为。 */ -export type IFilterMode = "nearest" | "linear"; +export type IFilterMode = 'nearest' | 'linear'; /** * 描述采样器在采样足迹与mipmap层级不完全匹配时的行为。 */ -export type IMipmapFilterMode = "nearest" | "linear"; +export type IMipmapFilterMode = 'nearest' | 'linear'; diff --git a/src/data/ScissorRect.ts b/src/data/ScissorRect.ts index 7ac515760e5535830ed82e659f0913bace057266..f4d9996edc2cab16d33bc16c65394c1391dd561a 100644 --- a/src/data/ScissorRect.ts +++ b/src/data/ScissorRect.ts @@ -17,8 +17,6 @@ */ export interface ScissorRect { - __type__?: "ScissorRect"; - /** * 是否为Y轴朝上。 * diff --git a/src/data/StencilFaceState.ts b/src/data/StencilFaceState.ts index defeef3485154eff5f5740d4cfd5c3cd2bfa2f3f..e12d0f411b04b934fecbac17947164a2148a5735 100644 --- a/src/data/StencilFaceState.ts +++ b/src/data/StencilFaceState.ts @@ -5,37 +5,35 @@ */ export interface StencilFaceState { - __type__?: "StencilFaceState"; - /** * 在测试片元与 depthStencilAttachment 模板值时使用的 GPUCompareFunction。 * * 默认为 "always"。 */ - readonly compare?: ICompareFunction; + readonly compare?: CompareFunction; /** * 如果片元模板比较测试(由 compare 描述)失败,则执行的 GPUStencilOperation。 * * 默认为 "keep"。 */ - readonly failOp?: IStencilOperation; + readonly failOp?: StencilOperation; /** * 如果由 depthCompare 描述的片元深度比较失败,则执行的 GPUStencilOperation。 * * 默认为 "keep"。 */ - readonly depthFailOp?: IStencilOperation; + readonly depthFailOp?: StencilOperation; /** * 如果片元模板比较测试通过,则执行由compare描述的GPUStencilOperation。 * * 默认为 "keep"。 */ - readonly passOp?: IStencilOperation; + readonly passOp?: StencilOperation; } -export type ICompareFunction = "never" | "less" | "equal" | "less-equal" | "greater" | "not-equal" | "greater-equal" | "always"; +export type CompareFunction = 'never' | 'less' | 'equal' | 'less-equal' | 'greater' | 'not-equal' | 'greater-equal' | 'always'; -export type IStencilOperation = "keep" | "zero" | "replace" | "invert" | "increment-clamp" | "decrement-clamp" | "increment-wrap" | "decrement-wrap"; \ No newline at end of file +export type StencilOperation = 'keep' | 'zero' | 'replace' | 'invert' | 'increment-clamp' | 'decrement-clamp' | 'increment-wrap' | 'decrement-wrap'; \ No newline at end of file diff --git a/src/data/Submit.ts b/src/data/Submit.ts index fba33cbfc0a8c53d41f41342ccda2ddbf497b390..936dc751d198205a850c7b472245d38b98e7b783 100644 --- a/src/data/Submit.ts +++ b/src/data/Submit.ts @@ -1,4 +1,4 @@ -import { CommandEncoder } from "./CommandEncoder"; +import { CommandEncoder } from './CommandEncoder'; /** * 一次 GPU 提交。 @@ -7,8 +7,6 @@ import { CommandEncoder } from "./CommandEncoder"; */ export interface Submit { - __type__?: "Submit"; - /** * 命令编码器列表。 */ diff --git a/src/data/Texture.ts b/src/data/Texture.ts index c08d57112b11c12203688e2f50432112d592415e..6769ce2fa564dacdc014b5a9d266b53e04d0529e 100644 --- a/src/data/Texture.ts +++ b/src/data/Texture.ts @@ -1,17 +1,35 @@ -import { TextureDataSource } from "./TextureDataSource"; -import { TextureImageSource } from "./TextureImageSource"; +import { TextureDataSource } from './TextureDataSource'; +import { TextureImageSource } from './TextureImageSource'; /** - * 纹理 + * 类似纹理,包含画布纹理以及正常纹理。 + * + * 如需扩展 ITextureLike,则需在 ITextureMap 中添加类型。 */ -export interface Texture +export type TextureLike = TextureLikeMap[keyof TextureLikeMap]; + +/** + * 如需扩展 ITextureLike,则需在 ITextureMap 中添加类型。 + */ +export interface TextureLikeMap { - __type__?: "Texture"; + /** + * 正常纹理。 + */ + Texture: Texture; +} +/** + * 纹理描述。 + */ +export interface TextureDescriptor +{ /** * 标签。 * * 用于调试。 + * + * 注:修改后将重新创建纹理。 */ readonly label?: string; @@ -22,55 +40,90 @@ export interface Texture * * 修改尺寸将会引发纹理销毁,使用时重新创建新纹理。 */ - size: TextureSize; + readonly size: TextureSize; /** - * 初始化纹理资源。 + * 纹理维度,默认为 "2d" 。 * - * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/texImage2D - * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/texImage3D + * WebGL中不支持 "1d" "cube-array"。 * - * ### WebGPU + * 注:修改后将重新创建纹理。 + */ + readonly dimension?: TextureDimension; + + /** + * 纹理格式。 默认为 "rgba8unorm", * - * @see GPUQueue.copyExternalImageToTexture - * @see GPUQueue.writeTexture + * 注:修改后将重新创建纹理。 */ - sources?: readonly TextureSource[]; + readonly format?: TextureFormat; /** - * 初始化纹理后是否生成mipmap + * The number of mip levels the texture will contain. + * + * 注:修改后将重新创建纹理。 */ - readonly generateMipmap?: boolean; + readonly mipLevelCount?: number; /** - * 写入纹理资源。 + * 是否生成mipmap * - * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/texSubImage2D - * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/texSubImage3D + * 仅在纹理创建时执行。 * - * ### WebGPU + * 注:修改后将重新创建纹理。 + */ + readonly generateMipmap?: boolean; + + /** + * The sample count of the texture. A {@link GPUTextureDescriptor#sampleCount} > `1` indicates + * a multisampled texture. * - * @see GPUQueue.copyExternalImageToTexture - * @see GPUQueue.writeTexture + * WebGPU只支持4重采样。 + * + * 注:修改后将重新创建纹理。 */ - writeTextures?: readonly TextureSource[]; + readonly sampleCount?: 4; +} +/** + * 纹理 + */ +export interface Texture +{ /** - * 纹理维度,默认为 "2d" 。 + * 纹理描述。 * - * WebGL中不支持 "1d" "cube-array"。 + * 注:修改后将重新创建纹理。 */ - readonly dimension?: TextureDimension; + readonly descriptor: TextureDescriptor; /** - * 纹理格式。 默认为 "rgba8unorm", + * 初始化纹理资源。 + * + * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/texImage2D + * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/texImage3D + * + * ### WebGPU + * + * @see GPUQueue.copyExternalImageToTexture + * @see GPUQueue.writeTexture + * + * 注:修改后将重新创建纹理。 */ - readonly format?: TextureFormat; + readonly sources?: readonly TextureSource[]; /** - * The number of mip levels the texture will contain. + * 写入纹理资源。 + * + * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/texSubImage2D + * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/texSubImage3D + * + * ### WebGPU + * + * @see GPUQueue.copyExternalImageToTexture + * @see GPUQueue.writeTexture */ - readonly mipLevelCount?: number; + readonly writeTextures?: readonly TextureSource[]; } export class Texture @@ -80,7 +133,7 @@ export class Texture * * @param format 纹理格式。 */ - static getTextureBytesPerPixel(format: TextureFormat = "rgba8unorm") + static getTextureBytesPerPixel(format: TextureFormat = 'rgba8unorm') { const bytesPerPixel = formatMap[format]?.bytesPerPixel; @@ -95,7 +148,7 @@ export class Texture * @param format 纹理格式。 * @returns */ - static getTextureDataConstructor(format: TextureFormat = "rgba8unorm") + static getTextureDataConstructor(format: TextureFormat = 'rgba8unorm') { const bytesPerPixel = formatMap[format]?.dataConstructor; @@ -173,108 +226,108 @@ export type TextureOrigin = readonly [x: number, y: number, depthOrArrayLayers?: /** * 纹理规格维度。 */ -export type TextureDimension = "1d" | "2d" | "2d-array" | "cube" | "cube-array" | "3d"; +export type TextureDimension = '1d' | '2d' | '2d-array' | 'cube' | 'cube-array' | '3d'; /** * 参考 GPUTextureFormat */ export type TextureFormat = - | "r8unorm" - | "r8snorm" - | "r8uint" - | "r8sint" - | "r16uint" - | "r16sint" - | "r16float" - | "rg8unorm" - | "rg8snorm" - | "rg8uint" - | "rg8sint" - | "r32uint" - | "r32sint" - | "r32float" - | "rg16uint" - | "rg16sint" - | "rg16float" - | "rgba8unorm" - | "rgba8unorm-srgb" - | "rgba8snorm" - | "rgba8uint" - | "rgba8sint" - | "bgra8unorm" - | "bgra8unorm-srgb" - | "rgb9e5ufloat" - | "rgb10a2uint" - | "rgb10a2unorm" - | "rg11b10ufloat" - | "rg32uint" - | "rg32sint" - | "rg32float" - | "rgba16uint" - | "rgba16sint" - | "rgba16float" - | "rgba32uint" - | "rgba32sint" - | "rgba32float" - | "stencil8" - | "depth16unorm" - | "depth24plus" - | "depth24plus-stencil8" - | "depth32float" - | "depth32float-stencil8" - | "bc1-rgba-unorm" - | "bc1-rgba-unorm-srgb" - | "bc2-rgba-unorm" - | "bc2-rgba-unorm-srgb" - | "bc3-rgba-unorm" - | "bc3-rgba-unorm-srgb" - | "bc4-r-unorm" - | "bc4-r-snorm" - | "bc5-rg-unorm" - | "bc5-rg-snorm" - | "bc6h-rgb-ufloat" - | "bc6h-rgb-float" - | "bc7-rgba-unorm" - | "bc7-rgba-unorm-srgb" - | "etc2-rgb8unorm" - | "etc2-rgb8unorm-srgb" - | "etc2-rgb8a1unorm" - | "etc2-rgb8a1unorm-srgb" - | "etc2-rgba8unorm" - | "etc2-rgba8unorm-srgb" - | "eac-r11unorm" - | "eac-r11snorm" - | "eac-rg11unorm" - | "eac-rg11snorm" - | "astc-4x4-unorm" - | "astc-4x4-unorm-srgb" - | "astc-5x4-unorm" - | "astc-5x4-unorm-srgb" - | "astc-5x5-unorm" - | "astc-5x5-unorm-srgb" - | "astc-6x5-unorm" - | "astc-6x5-unorm-srgb" - | "astc-6x6-unorm" - | "astc-6x6-unorm-srgb" - | "astc-8x5-unorm" - | "astc-8x5-unorm-srgb" - | "astc-8x6-unorm" - | "astc-8x6-unorm-srgb" - | "astc-8x8-unorm" - | "astc-8x8-unorm-srgb" - | "astc-10x5-unorm" - | "astc-10x5-unorm-srgb" - | "astc-10x6-unorm" - | "astc-10x6-unorm-srgb" - | "astc-10x8-unorm" - | "astc-10x8-unorm-srgb" - | "astc-10x10-unorm" - | "astc-10x10-unorm-srgb" - | "astc-12x10-unorm" - | "astc-12x10-unorm-srgb" - | "astc-12x12-unorm" - | "astc-12x12-unorm-srgb"; + | 'r8unorm' + | 'r8snorm' + | 'r8uint' + | 'r8sint' + | 'r16uint' + | 'r16sint' + | 'r16float' + | 'rg8unorm' + | 'rg8snorm' + | 'rg8uint' + | 'rg8sint' + | 'r32uint' + | 'r32sint' + | 'r32float' + | 'rg16uint' + | 'rg16sint' + | 'rg16float' + | 'rgba8unorm' + | 'rgba8unorm-srgb' + | 'rgba8snorm' + | 'rgba8uint' + | 'rgba8sint' + | 'bgra8unorm' + | 'bgra8unorm-srgb' + | 'rgb9e5ufloat' + | 'rgb10a2uint' + | 'rgb10a2unorm' + | 'rg11b10ufloat' + | 'rg32uint' + | 'rg32sint' + | 'rg32float' + | 'rgba16uint' + | 'rgba16sint' + | 'rgba16float' + | 'rgba32uint' + | 'rgba32sint' + | 'rgba32float' + | 'stencil8' + | 'depth16unorm' + | 'depth24plus' + | 'depth24plus-stencil8' + | 'depth32float' + | 'depth32float-stencil8' + | 'bc1-rgba-unorm' + | 'bc1-rgba-unorm-srgb' + | 'bc2-rgba-unorm' + | 'bc2-rgba-unorm-srgb' + | 'bc3-rgba-unorm' + | 'bc3-rgba-unorm-srgb' + | 'bc4-r-unorm' + | 'bc4-r-snorm' + | 'bc5-rg-unorm' + | 'bc5-rg-snorm' + | 'bc6h-rgb-ufloat' + | 'bc6h-rgb-float' + | 'bc7-rgba-unorm' + | 'bc7-rgba-unorm-srgb' + | 'etc2-rgb8unorm' + | 'etc2-rgb8unorm-srgb' + | 'etc2-rgb8a1unorm' + | 'etc2-rgb8a1unorm-srgb' + | 'etc2-rgba8unorm' + | 'etc2-rgba8unorm-srgb' + | 'eac-r11unorm' + | 'eac-r11snorm' + | 'eac-rg11unorm' + | 'eac-rg11snorm' + | 'astc-4x4-unorm' + | 'astc-4x4-unorm-srgb' + | 'astc-5x4-unorm' + | 'astc-5x4-unorm-srgb' + | 'astc-5x5-unorm' + | 'astc-5x5-unorm-srgb' + | 'astc-6x5-unorm' + | 'astc-6x5-unorm-srgb' + | 'astc-6x6-unorm' + | 'astc-6x6-unorm-srgb' + | 'astc-8x5-unorm' + | 'astc-8x5-unorm-srgb' + | 'astc-8x6-unorm' + | 'astc-8x6-unorm-srgb' + | 'astc-8x8-unorm' + | 'astc-8x8-unorm-srgb' + | 'astc-10x5-unorm' + | 'astc-10x5-unorm-srgb' + | 'astc-10x6-unorm' + | 'astc-10x6-unorm-srgb' + | 'astc-10x8-unorm' + | 'astc-10x8-unorm-srgb' + | 'astc-10x10-unorm' + | 'astc-10x10-unorm-srgb' + | 'astc-12x10-unorm' + | 'astc-12x10-unorm-srgb' + | 'astc-12x12-unorm' + | 'astc-12x12-unorm-srgb'; const formatMap: { [key: string]: { @@ -310,12 +363,12 @@ const formatMap: { rg16sint: { bytesPerPixel: 4, dataConstructor: Int16Array }, rg16float: { bytesPerPixel: 4, dataConstructor: Uint16Array }, rgba8unorm: { bytesPerPixel: 4, dataConstructor: Uint8Array }, - "rgba8unorm-srgb": { bytesPerPixel: 4, dataConstructor: Uint8Array }, + 'rgba8unorm-srgb': { bytesPerPixel: 4, dataConstructor: Uint8Array }, rgba8snorm: { bytesPerPixel: 4, dataConstructor: Int8Array }, rgba8uint: { bytesPerPixel: 4, dataConstructor: Uint8Array }, rgba8sint: { bytesPerPixel: 4, dataConstructor: Int8Array }, bgra8unorm: { bytesPerPixel: 4, dataConstructor: Uint8Array }, - "bgra8unorm-srgb": { bytesPerPixel: 4, dataConstructor: Uint8Array }, + 'bgra8unorm-srgb': { bytesPerPixel: 4, dataConstructor: Uint8Array }, rgb9e5ufloat: { bytesPerPixel: 4, dataConstructor: Uint32Array }, rgb10a2uint: { bytesPerPixel: 4, dataConstructor: Uint32Array }, rgb10a2unorm: { bytesPerPixel: 4, dataConstructor: Uint32Array }, @@ -332,59 +385,59 @@ const formatMap: { stencil8: { bytesPerPixel: 1, dataConstructor: Uint8Array }, depth16unorm: { bytesPerPixel: 2, dataConstructor: Uint16Array }, depth24plus: { bytesPerPixel: 3, dataConstructor: Uint8Array }, - "depth24plus-stencil8": { bytesPerPixel: 4 }, + 'depth24plus-stencil8': { bytesPerPixel: 4 }, depth32float: { bytesPerPixel: 4 }, - "depth32float-stencil8": { bytesPerPixel: 5 }, - "bc1-rgba-unorm": undefined, - "bc1-rgba-unorm-srgb": undefined, - "bc2-rgba-unorm": undefined, - "bc2-rgba-unorm-srgb": undefined, - "bc3-rgba-unorm": undefined, - "bc3-rgba-unorm-srgb": undefined, - "bc4-r-unorm": undefined, - "bc4-r-snorm": undefined, - "bc5-rg-unorm": undefined, - "bc5-rg-snorm": undefined, - "bc6h-rgb-ufloat": undefined, - "bc6h-rgb-float": undefined, - "bc7-rgba-unorm": undefined, - "bc7-rgba-unorm-srgb": undefined, - "etc2-rgb8unorm": undefined, - "etc2-rgb8unorm-srgb": undefined, - "etc2-rgb8a1unorm": undefined, - "etc2-rgb8a1unorm-srgb": undefined, - "etc2-rgba8unorm": undefined, - "etc2-rgba8unorm-srgb": undefined, - "eac-r11unorm": undefined, - "eac-r11snorm": undefined, - "eac-rg11unorm": undefined, - "eac-rg11snorm": undefined, - "astc-4x4-unorm": undefined, - "astc-4x4-unorm-srgb": undefined, - "astc-5x4-unorm": undefined, - "astc-5x4-unorm-srgb": undefined, - "astc-5x5-unorm": undefined, - "astc-5x5-unorm-srgb": undefined, - "astc-6x5-unorm": undefined, - "astc-6x5-unorm-srgb": undefined, - "astc-6x6-unorm": undefined, - "astc-6x6-unorm-srgb": undefined, - "astc-8x5-unorm": undefined, - "astc-8x5-unorm-srgb": undefined, - "astc-8x6-unorm": undefined, - "astc-8x6-unorm-srgb": undefined, - "astc-8x8-unorm": undefined, - "astc-8x8-unorm-srgb": undefined, - "astc-10x5-unorm": undefined, - "astc-10x5-unorm-srgb": undefined, - "astc-10x6-unorm": undefined, - "astc-10x6-unorm-srgb": undefined, - "astc-10x8-unorm": undefined, - "astc-10x8-unorm-srgb": undefined, - "astc-10x10-unorm": undefined, - "astc-10x10-unorm-srgb": undefined, - "astc-12x10-unorm": undefined, - "astc-12x10-unorm-srgb": undefined, - "astc-12x12-unorm": undefined, - "astc-12x12-unorm-srgb": undefined, + 'depth32float-stencil8': { bytesPerPixel: 5 }, + 'bc1-rgba-unorm': undefined, + 'bc1-rgba-unorm-srgb': undefined, + 'bc2-rgba-unorm': undefined, + 'bc2-rgba-unorm-srgb': undefined, + 'bc3-rgba-unorm': undefined, + 'bc3-rgba-unorm-srgb': undefined, + 'bc4-r-unorm': undefined, + 'bc4-r-snorm': undefined, + 'bc5-rg-unorm': undefined, + 'bc5-rg-snorm': undefined, + 'bc6h-rgb-ufloat': undefined, + 'bc6h-rgb-float': undefined, + 'bc7-rgba-unorm': undefined, + 'bc7-rgba-unorm-srgb': undefined, + 'etc2-rgb8unorm': undefined, + 'etc2-rgb8unorm-srgb': undefined, + 'etc2-rgb8a1unorm': undefined, + 'etc2-rgb8a1unorm-srgb': undefined, + 'etc2-rgba8unorm': undefined, + 'etc2-rgba8unorm-srgb': undefined, + 'eac-r11unorm': undefined, + 'eac-r11snorm': undefined, + 'eac-rg11unorm': undefined, + 'eac-rg11snorm': undefined, + 'astc-4x4-unorm': undefined, + 'astc-4x4-unorm-srgb': undefined, + 'astc-5x4-unorm': undefined, + 'astc-5x4-unorm-srgb': undefined, + 'astc-5x5-unorm': undefined, + 'astc-5x5-unorm-srgb': undefined, + 'astc-6x5-unorm': undefined, + 'astc-6x5-unorm-srgb': undefined, + 'astc-6x6-unorm': undefined, + 'astc-6x6-unorm-srgb': undefined, + 'astc-8x5-unorm': undefined, + 'astc-8x5-unorm-srgb': undefined, + 'astc-8x6-unorm': undefined, + 'astc-8x6-unorm-srgb': undefined, + 'astc-8x8-unorm': undefined, + 'astc-8x8-unorm-srgb': undefined, + 'astc-10x5-unorm': undefined, + 'astc-10x5-unorm-srgb': undefined, + 'astc-10x6-unorm': undefined, + 'astc-10x6-unorm-srgb': undefined, + 'astc-10x8-unorm': undefined, + 'astc-10x8-unorm-srgb': undefined, + 'astc-10x10-unorm': undefined, + 'astc-10x10-unorm-srgb': undefined, + 'astc-12x10-unorm': undefined, + 'astc-12x10-unorm-srgb': undefined, + 'astc-12x12-unorm': undefined, + 'astc-12x12-unorm-srgb': undefined, }; \ No newline at end of file diff --git a/src/data/TextureDataSource.ts b/src/data/TextureDataSource.ts index 1cf65de5ba30e2b7c85b448a80008a6481651c32..7e1c939a526eef8199350e3f808ca4739e9b71d8 100644 --- a/src/data/TextureDataSource.ts +++ b/src/data/TextureDataSource.ts @@ -1,4 +1,4 @@ -import { TextureDataLayout, DataImageOrigin, TextureOrigin, TextureSize } from "./Texture"; +import { TextureDataLayout, DataImageOrigin, TextureOrigin, TextureSize } from './Texture'; /** * 纹理的数据资源。 @@ -15,7 +15,7 @@ export interface TextureDataSource /** * 数据类型。 */ - readonly __type__: "TextureDataSource"; + readonly __type__: 'TextureDataSource'; /** * 纹理数据。 diff --git a/src/data/TextureImageSource.ts b/src/data/TextureImageSource.ts index f6e3d1fc9a2fa9a59f02bc293fbadf07f1a23977..70fdedcd8a464d7fa06d74a9d9c5c6d01b4b2a4a 100644 --- a/src/data/TextureImageSource.ts +++ b/src/data/TextureImageSource.ts @@ -1,4 +1,4 @@ -import { ImageOrigin, ImageSize, TextureOrigin, TextureSize } from "./Texture"; +import { ImageOrigin, ImageSize, TextureOrigin, TextureSize } from './Texture'; /** * 纹理的图片资源。 @@ -17,7 +17,7 @@ export interface TextureImageSource /** * 数据类型。 */ - readonly __type__?: "TextureImageSource"; + readonly __type__?: 'TextureImageSource'; /** * 图片资源。 @@ -74,6 +74,7 @@ export class TextureImageSource { let width: number; let height: number; + if (image instanceof VideoFrame) { width = image.codedWidth; diff --git a/src/data/TextureView.ts b/src/data/TextureView.ts index 158de4c3cba4315acc8b65defc6d96b362d2c3be..439e37404ca68880ff92acee40a70cdf18f1a22e 100644 --- a/src/data/TextureView.ts +++ b/src/data/TextureView.ts @@ -1,21 +1,23 @@ -import { Texture } from "./Texture"; +import { TextureLike } from './Texture'; /** * 纹理视图。 */ export interface TextureView { - __type__?: "TextureView"; - /** * 标签。 * * 用于调试。 + * + * 注:修改后将重新创建视图。 */ readonly label?: string; /** * 产生视图的纹理。 + * + * 注:修改后将重新创建视图。 */ readonly texture: TextureLike; @@ -23,6 +25,8 @@ export interface TextureView * mipmap级别。 * * 默认为 0。 + * + * 注:修改后将重新创建视图。 */ readonly baseMipLevel?: number; @@ -30,24 +34,8 @@ export interface TextureView * 3d纹理的深度索引、纹理数组中的层次、立方体纹理的面索引。 * * 默认为 0。 + * + * 注:修改后将重新创建视图。 */ readonly baseArrayLayer?: number; } - -/** - * 类似纹理,包含画布纹理以及正常纹理。 - * - * 如需扩展 ITextureLike,则需在 ITextureMap 中添加类型。 - */ -export type TextureLike = TextureLikeMap[keyof TextureLikeMap]; - -/** - * 如需扩展 ITextureLike,则需在 ITextureMap 中添加类型。 - */ -export interface TextureLikeMap -{ - /** - * 正常纹理。 - */ - Texture: Texture; -} \ No newline at end of file diff --git a/src/data/VertexAttributes.ts b/src/data/VertexAttributes.ts index cbf53ec64cff1a8142c9f0bdffb33dcd5f452ef5..1cec2e764c0e2132e63ebc2e2d79ff4e8159de6d 100644 --- a/src/data/VertexAttributes.ts +++ b/src/data/VertexAttributes.ts @@ -1,12 +1,10 @@ -import { vertexFormatMap } from "../consts/vertexFormatMap"; +import { vertexFormatMap } from '../consts/vertexFormatMap'; /** * 顶点属性数据映射。 */ export interface VertexAttributes { - __type__?: any; - [name: string]: VertexAttribute; } @@ -18,7 +16,7 @@ export interface VertexAttribute /** * 顶点数据。 */ - data: VertexDataTypes; + data: VertexData; /** * 顶点数据格式。 @@ -83,9 +81,9 @@ export class VertexAttribute } } -export type VertexStepMode = "vertex" | "instance"; +export type VertexStepMode = 'vertex' | 'instance'; -export type VertexDataTypes = | Float32Array +export type VertexData = | Float32Array | Uint32Array | Int32Array | Uint16Array @@ -98,34 +96,34 @@ export type VertexDataTypes = | Float32Array * 顶点数据格式。 */ export type VertexFormat = - | "uint8x2" - | "uint8x4" - | "sint8x2" - | "sint8x4" - | "unorm8x2" - | "unorm8x4" - | "snorm8x2" - | "snorm8x4" - | "uint16x2" - | "uint16x4" - | "sint16x2" - | "sint16x4" - | "unorm16x2" - | "unorm16x4" - | "snorm16x2" - | "snorm16x4" - | "float16x2" - | "float16x4" - | "float32" - | "float32x2" - | "float32x3" - | "float32x4" - | "uint32" - | "uint32x2" - | "uint32x3" - | "uint32x4" - | "sint32" - | "sint32x2" - | "sint32x3" - | "sint32x4" - | "unorm10-10-10-2"; \ No newline at end of file + | 'uint8x2' + | 'uint8x4' + | 'sint8x2' + | 'sint8x4' + | 'unorm8x2' + | 'unorm8x4' + | 'snorm8x2' + | 'snorm8x4' + | 'uint16x2' + | 'uint16x4' + | 'sint16x2' + | 'sint16x4' + | 'unorm16x2' + | 'unorm16x4' + | 'snorm16x2' + | 'snorm16x4' + | 'float16x2' + | 'float16x4' + | 'float32' + | 'float32x2' + | 'float32x3' + | 'float32x4' + | 'uint32' + | 'uint32x2' + | 'uint32x3' + | 'uint32x4' + | 'sint32' + | 'sint32x2' + | 'sint32x3' + | 'sint32x4' + | 'unorm10-10-10-2'; \ No newline at end of file diff --git a/src/data/VertexState.ts b/src/data/VertexState.ts index 21335b7db79a7cb80b08ffcb8c014900ccb7486c..ec5a64c392accf5398b2913d0863a5b30db0582b 100644 --- a/src/data/VertexState.ts +++ b/src/data/VertexState.ts @@ -3,10 +3,8 @@ */ export interface VertexState { - __type__?: "VertexState"; - /** * 着色器代码。 */ - code: string; + readonly code: string; } \ No newline at end of file diff --git a/src/data/Viewport.ts b/src/data/Viewport.ts index f7e6031d5b722655e3f80198e8d0e1ad20ac3c69..be479cfd71c3088a20d135db7750078979239aaa 100644 --- a/src/data/Viewport.ts +++ b/src/data/Viewport.ts @@ -19,8 +19,6 @@ */ export interface Viewport { - __type__?: "Viewport"; - /** * 是否为Y轴朝上。 * diff --git a/src/data/WriteBuffer.ts b/src/data/WriteBuffer.ts index 2b656667ec823bfd96d998204dcc448ad5d57880..dfc4b70ddc3fb70a1e41cacae83a37a66cd04f80 100644 --- a/src/data/WriteBuffer.ts +++ b/src/data/WriteBuffer.ts @@ -1,9 +1,7 @@ -import { TypedArray } from "../types/TypedArray"; +import { TypedArray } from '../types/TypedArray'; export interface WriteBuffer { - __type__?: "WriteBuffer"; - /** * GPU缓冲区写入起始位置。 */ diff --git a/src/global.ts b/src/global.ts new file mode 100644 index 0000000000000000000000000000000000000000..2e598121b171ccc681cb935a1cbdeb3de8c87885 --- /dev/null +++ b/src/global.ts @@ -0,0 +1,9 @@ +export { }; +declare global +{ + /** + * 是否为开发模式。 + */ + // eslint-disable-next-line no-var + var __DEV__: boolean; +} diff --git a/src/index.ts b/src/index.ts index db3c056ef30066d13c5f8bd68572561342610b91..68a0c2c8a1fc81beb5ad623b653520af810be034 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,46 +1,47 @@ -export * from "./consts/vertexFormatMap"; +export * from './consts/vertexFormatMap'; -export * from "./data/BlendComponent"; -export * from "./data/BlendState"; -export * from "./data/Buffer"; -export * from "./data/BufferBinding"; -export * from "./data/CanvasContext"; -export * from "./data/CanvasTexture"; -export * from "./data/ColorTargetState"; -export * from "./data/CommandEncoder"; -export * from "./data/CopyBufferToBuffer"; -export * from "./data/CopyTextureToTexture"; -export * from "./data/DepthStencilState"; -export * from "./data/DrawIndexed"; -export * from "./data/DrawVertex"; -export * from "./data/FragmentState"; -export * from "./data/Geometry"; -export * from "./data/ImageCopyTexture"; -export * from "./data/OcclusionQuery"; -export * from "./data/PrimitiveState"; -export * from "./data/ReadPixels"; -export * from "./data/RenderObject"; -export * from "./data/RenderPass"; -export * from "./data/RenderPassColorAttachment"; -export * from "./data/RenderPassDepthStencilAttachment"; -export * from "./data/RenderPassDescriptor"; -export * from "./data/RenderPipeline"; -export * from "./data/Sampler"; -export * from "./data/ScissorRect"; -export * from "./data/StencilFaceState"; -export * from "./data/Submit"; -export * from "./data/Texture"; -export * from "./data/TextureDataSource"; -export * from "./data/TextureImageSource"; -export * from "./data/TextureView"; -export * from "./data/BindingResources"; -export * from "./data/VertexAttributes"; -export * from "./data/VertexState"; -export * from "./data/Viewport"; -export * from "./data/WriteBuffer"; +export * from './data/BindingResources'; +export * from './data/BlendComponent'; +export * from './data/BlendState'; +export * from './data/Buffer'; +export * from './data/BufferBinding'; +export * from './data/CanvasContext'; +export * from './data/CanvasTexture'; +export * from './data/ColorTargetState'; +export * from './data/CommandEncoder'; +export * from './data/CopyBufferToBuffer'; +export * from './data/CopyTextureToTexture'; +export * from './data/DepthStencilState'; +export * from './data/DrawIndexed'; +export * from './data/DrawVertex'; +export * from './data/FragmentState'; +export * from './data/ImageCopyTexture'; +export * from './data/OcclusionQuery'; +export * from './data/PrimitiveState'; +export * from './data/ReadPixels'; +export * from './data/RenderObject'; +export * from './data/RenderPass'; +export * from './data/RenderPassColorAttachment'; +export * from './data/RenderPassDepthStencilAttachment'; +export * from './data/RenderPassDescriptor'; +export * from './data/RenderPipeline'; +export * from './data/Sampler'; +export * from './data/ScissorRect'; +export * from './data/StencilFaceState'; +export * from './data/Submit'; +export * from './data/Texture'; +export * from './data/TextureDataSource'; +export * from './data/TextureImageSource'; +export * from './data/TextureView'; +export * from './data/VertexAttributes'; +export * from './data/VertexState'; +export * from './data/Viewport'; +export * from './data/WriteBuffer'; -export * from "./internal/BufferBindingInfo"; +export * from './internal/BufferBindingInfo'; -export * from "./types/TypedArray"; -export * from "./types/UnReadonly"; +export * from './types/TypedArray'; +export * from './utils/ChainMap'; + +import './global'; \ No newline at end of file diff --git a/src/types/UnReadonly.ts b/src/types/UnReadonly.ts deleted file mode 100644 index ad8f1b104e999296d36bc8753dc5a9e72b5186d1..0000000000000000000000000000000000000000 --- a/src/types/UnReadonly.ts +++ /dev/null @@ -1,6 +0,0 @@ -/** - * 移除对象属性中的 readonly 关键字。 - */ -export type UnReadonly = { - -readonly [P in keyof T]: T[P]; -}; diff --git a/src/utils/ChainMap.ts b/src/utils/ChainMap.ts new file mode 100644 index 0000000000000000000000000000000000000000..346ecdf7b78637d56b7df886a9a9820efc3c319b --- /dev/null +++ b/src/utils/ChainMap.ts @@ -0,0 +1,139 @@ +/** + * 链式字典。 + * + * 使用WeakMap构建的,支持多个key数组对应一个值。 + */ +export class ChainMap, V> +{ + /** + * 根字典。 + */ + private _map = new WeakMap(); + get size() + { + return this._size; + } + + private _size = 0; + + /** + * 获取键对应的值。 + * + * @param keys 键。 + * @returns 值。 + */ + get(keys: K): V + { + const keysLength = keys.length; + let map = this._map; + let key: any; + + for (let i = 0, n = keysLength - 1; i < n; i++) + { + key = wrapKey(keys[i]); + map = map.get(key); + + if (map === undefined) return undefined; + } + + key = wrapKey(keys[keysLength - 1]); + + return map.get(key); + } + + /** + * 设置映射。 + * + * @param keys 键。 + * @param value 值。 + * + * @returns 返回设置的值。 + */ + set(keys: K, value: V) + { + const keysLength = keys.length; + let map = this._map; + let key: any; + + for (let i = 0; i < keysLength - 1; i++) + { + key = wrapKey(keys[i]); + + if (!map.has(key)) + { + map.set(key, new WeakMap()); + } + + map = map.get(key); + } + + key = wrapKey(keys[keysLength - 1]); + if (!map.has(key)) + { + map.set(key, value); + this._size++; + } + + return value; + } + + /** + * 删除映射。 + * + * @param keys 键。 + * @returns 如果找到目标值且被删除返回 `true` ,否则返回 `false` 。 + */ + delete(keys: K): boolean + { + const keysLength = keys.length; + let map = this._map; + let key: any; + + for (let i = 0; i < keysLength - 1; i++) + { + key = wrapKey(keys[i]); + map = map.get(key); + + if (map === undefined) return false; + } + + key = wrapKey(keys[keysLength - 1]); + const result = map.delete(key); + + if (result) this._size--; + + return result; + } +} + +// 创建一个普通 Map 用于存储原始值和包装对象的映射 +const keyMap = new Map(); +// 用于生成唯一 ID 的计数器 +let idCounter = 0; + +// 包装函数,将非对象值包装成对象 +function wrapKey(key: any) +{ + if (typeof key === 'object' && key !== null) + { + // 如果 key 已经是对象,则直接返回 + return key; + } + if (keyMap.has(key)) + { + // 如果原始值已经有对应的包装对象,直接返回 + return keyMap.get(key); + } + // 为非对象 key 生成一个唯一 ID + const id = idCounter++; + // 创建一个包装对象 + const wrapper = { + __id: id, + __value: key, + }; + + // 存储原始值和包装对象的映射 + keyMap.set(key, wrapper); + + return wrapper; +} \ No newline at end of file diff --git a/test/index.spec.ts b/test/index.spec.ts index 9dcf08b60dd55fa6b762959e049d7931abbd2375..00252bf960267cf4c012c0ec7487ab1521312aa5 100644 --- a/test/index.spec.ts +++ b/test/index.spec.ts @@ -1,9 +1,9 @@ -import { TextureImageSource } from "@feng3d/render-api"; -import { assert, describe, it } from "vitest"; +import { TextureImageSource } from '@feng3d/render-api'; +import { assert, describe, it } from 'vitest'; -describe("test", () => +describe('test', () => { - it("test", () => + it('test', () => { assert.equal(true, true); }); diff --git a/tsconfig.json b/tsconfig.json index f20f562259330de63f98545ed9b963e55cf5857a..34a176d12c37e013e682ef47b7812e2000515576 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,11 +8,13 @@ "declaration": true, "experimentalDecorators": true, "emitDeclarationOnly": true, - "types": [ - "@webgpu/types" - ], + "skipLibCheck": true, + "esModuleInterop": true, + "downlevelIteration": true, "lib": [ - "ESNext", + "ES2015", + "ES2017", + "ES2020", "DOM", ], "outDir": "lib" diff --git a/vite.config.js b/vite.config.js index f0569049d11b0cce94cdda67b66a8cec63414f36..d06a7e0f749c1c279eda94fb90e09530cb1b9890 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,10 +1,10 @@ // @see https://cn.vitejs.dev/guide/build.html#library-mode -import { resolve } from "path"; -import { defineConfig } from "vite"; -import pkg from "./package.json"; +import { resolve } from 'path'; +import { defineConfig } from 'vite'; +import pkg from './package.json'; -const namespace = "feng3d"; +const namespace = 'feng3d'; const external = pkg.standalone ? [] : Object.keys(pkg.dependencies || []); const globals = () => namespace; @@ -12,10 +12,10 @@ export default defineConfig({ build: { lib: { // Could also be a dictionary or array of multiple entry points - entry: resolve(__dirname, "src/index.ts"), + entry: resolve(__dirname, 'src/index.ts'), name: namespace, // the proper extensions will be added - fileName: "index", + fileName: 'index', }, minify: false, sourcemap: true, @@ -30,20 +30,20 @@ export default defineConfig({ }, plugins: [ shaderToString(), - ] + ], }); function shaderToString() { return { - name: "vite-plugin-string", + name: 'vite-plugin-string', async transform(source, id) { - if (!["glsl", "wgsl", "vert", "frag", "vs", "fs"].includes(id.split(".").pop())) return; + if (!['glsl', 'wgsl', 'vert', 'frag', 'vs', 'fs'].includes(id.split('.').pop())) return; const esm = `export default \`${source}\`;`; - return { code: esm, map: { mappings: "" } }; + return { code: esm, map: { mappings: '' } }; }, }; }