diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 5cea5ae..0000000 --- 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 254a952..0000000 --- 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 deleted file mode 100644 index b1f3913..0000000 --- a/.github/workflows/master.yml +++ /dev/null @@ -1,67 +0,0 @@ -name: Node.js CI - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - -jobs: - test: - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [18.x] - - steps: - - uses: actions/checkout@v2 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v2 - with: - node-version: ${{ matrix.node-version }} - - - 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 "::set-output name=publish::true" - else - echo "::set-output name=publish::false" - 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/pages.yml b/.github/workflows/pages.yml new file mode 100644 index 0000000..9f5d7e6 --- /dev/null +++ b/.github/workflows/pages.yml @@ -0,0 +1,93 @@ +# 将文档发布到 GitHub Pages +# 仅在主分支版本号发生变化时触发部署 +name: Deploy to GitHub Pages + +on: + push: + branches: + - master + - main + paths: + - 'package.json' # 仅在 package.json 变化时触发 + workflow_dispatch: # 支持手动触发 + +# 设置 GITHUB_TOKEN 的权限 +permissions: + contents: read + pages: write + id-token: write + +# 只允许一个并发部署 +concurrency: + group: "pages" + cancel-in-progress: true + +jobs: + # 检查版本号是否变化 + check-version: + runs-on: ubuntu-latest + outputs: + version_changed: ${{ steps.check.outputs.changed }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 2 # 获取最近两次提交以比较版本 + + - name: Check if version changed + id: check + run: | + # 获取当前版本 + CURRENT_VERSION=$(node -p "require('./package.json').version") + # 获取上一次提交的版本 + git checkout HEAD~1 -- package.json 2>/dev/null || echo "First commit" + PREVIOUS_VERSION=$(node -p "require('./package.json').version" 2>/dev/null || echo "0.0.0") + git checkout HEAD -- package.json + + if [ "$CURRENT_VERSION" != "$PREVIOUS_VERSION" ]; then + echo "Version changed from $PREVIOUS_VERSION to $CURRENT_VERSION" + echo "changed=true" >> $GITHUB_OUTPUT + else + echo "Version unchanged: $CURRENT_VERSION" + echo "changed=false" >> $GITHUB_OUTPUT + fi + + build: + runs-on: ubuntu-latest + needs: check-version + # 仅在版本号变化或手动触发时构建 + if: needs.check-version.outputs.version_changed == 'true' || github.event_name == 'workflow_dispatch' + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install dependencies + run: npm install + + - name: Build docs + run: npm run docs + + - name: Setup Pages + uses: actions/configure-pages@v4 + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: './public' + + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 + diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..6235e79 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,128 @@ +# 当 package.json 中的版本在 npm 不存在时自动发布 +name: Publish to NPM + +on: + push: + branches: + - master + - main + workflow_dispatch: # 支持手动触发 + +jobs: + check-version: + runs-on: ubuntu-latest + outputs: + should_publish: ${{ steps.check.outputs.should_publish }} + version: ${{ steps.check.outputs.version }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Check if version exists on npm + id: check + run: | + # 获取包名和当前版本 + PACKAGE_NAME=$(node -p "require('./package.json').name") + CURRENT_VERSION=$(node -p "require('./package.json').version") + echo "Package: $PACKAGE_NAME" + echo "Current version: $CURRENT_VERSION" + + # 检查该版本是否已在 npm 上存在 + HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://registry.npmjs.org/$PACKAGE_NAME/$CURRENT_VERSION") + + if [ "$HTTP_STATUS" = "404" ]; then + echo "Version $CURRENT_VERSION not found on npm, will publish" + echo "should_publish=true" >> $GITHUB_OUTPUT + echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT + else + echo "Version $CURRENT_VERSION already exists on npm (HTTP $HTTP_STATUS)" + echo "should_publish=false" >> $GITHUB_OUTPUT + fi + + publish: + needs: check-version + if: needs.check-version.outputs.should_publish == 'true' + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 # 获取完整历史以生成更新日志 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + registry-url: 'https://registry.npmjs.org' + + - name: Install dependencies + run: npm install + + - name: Build + run: npm run build + + - name: Run lint + run: npm run lint + + - name: Run tests + run: npm test + + - name: Publish to NPM + run: npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Create Git Tag + run: | + VERSION=${{ needs.check-version.outputs.version }} + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git tag -a "v$VERSION" -m "Release v$VERSION" + git push origin "v$VERSION" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Generate Release Notes + id: release_notes + run: | + VERSION=${{ needs.check-version.outputs.version }} + + # 获取上一个版本的 tag + PREVIOUS_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") + + echo "Previous tag: $PREVIOUS_TAG" + + # 生成更新日志 + if [ -n "$PREVIOUS_TAG" ]; then + echo "## 更新内容" > release_notes.md + echo "" >> release_notes.md + echo "与 $PREVIOUS_TAG 相比的变更:" >> release_notes.md + echo "" >> release_notes.md + + # 获取提交日志 + git log --pretty=format:"- %s (%h)" $PREVIOUS_TAG..HEAD >> release_notes.md + else + echo "## 更新内容" > release_notes.md + echo "" >> release_notes.md + echo "首次发布" >> release_notes.md + echo "" >> release_notes.md + + # 获取所有提交日志 + git log --pretty=format:"- %s (%h)" >> release_notes.md + fi + + echo "" >> release_notes.md + + # 输出生成的内容 + echo "Generated release notes:" + cat release_notes.md + + - name: Create GitHub Release + uses: softprops/action-gh-release@v1 + with: + tag_name: v${{ needs.check-version.outputs.version }} + name: Release v${{ needs.check-version.outputs.version }} + body_path: release_notes.md + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml new file mode 100644 index 0000000..c039144 --- /dev/null +++ b/.github/workflows/pull-request.yml @@ -0,0 +1,36 @@ +# CI - 运行单元测试 +# 在合并到主分支或在主分支提交代码时执行 +name: CI + +on: + push: + branches: + - master + - main + pull_request: + branches: + - master + - main + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install dependencies + run: npm install + + - name: Run lint + run: npm run lint + + - name: Run unit tests + run: npm test + diff --git a/.gitignore b/.gitignore index a48ec03..2429b1b 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,15 @@ public out package-lock.json pnpm-lock.yaml + +# 以下文件可由 feng3d-cli 自动生成,无需提交 +# 运行 `feng3d-cli update` 可重新生成 +feng3d.json +.cursorrules +eslint.config.js +typedoc.json +test/index.test.ts +test/_.test.ts +.husky/pre-commit +.vscode/settings.json +tsconfig.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 4745c7f..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,9 +0,0 @@ -// 将设置放入此文件中以覆盖默认值和用户设置。 -{ - // 定义函数的左大括号是否放置在新的一行。 - "typescript.format.placeOpenBraceOnNewLineForFunctions": true, - // 定义控制块的左括号是否放置在新的一行。 - "typescript.format.placeOpenBraceOnNewLineForControlBlocks": true, - "javascript.format.placeOpenBraceOnNewLineForFunctions": true, - "javascript.format.placeOpenBraceOnNewLineForControlBlocks": true, -} \ No newline at end of file diff --git a/LICENSE b/LICENSE index 3ece308..af18e8f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,15 @@ -MIT License +MIT 许可证 -Copyright (c) 2019 feng +版权所有 (c) 2025 feng -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +特此授予任何获得本软件及相关文档文件("软件")副本的人免费许可, +可以不受限制地处理本软件,包括但不限于使用、复制、修改、合并、 +发布、分发、再许可和/或销售本软件的副本,并允许向其提供本软件的 +人这样做,但须符合以下条件: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +上述版权声明和本许可声明应包含在本软件的所有副本或主要部分中。 -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +本软件按"原样"提供,不提供任何明示或暗示的保证,包括但不限于对 +适销性、特定用途适用性和非侵权性的保证。在任何情况下,作者或版权 +持有人均不对因本软件或本软件的使用或其他交易而产生的任何索赔、 +损害或其他责任负责,无论是在合同诉讼、侵权诉讼还是其他诉讼中。 diff --git a/package.json b/package.json index 48b79b8..ce36146 100644 --- a/package.json +++ b/package.json @@ -1,61 +1,76 @@ { - "name": "@feng3d/render-api", - "version": "0.0.4", - "description": "提供WebGL/WebGPU统一的渲染数据结构,描述渲染所需的所有数据以及流程,用于@feng3d/webgl与@feng3d/webgpu。", - "author": "feng", - "license": "MIT", - "type": "module", - "main": "./src/index.ts", - "types": "./src/index.ts", - "module": "./src/index.ts", - "exports": { - ".": { - "import": "./src/index.ts", - "require": "./src/index.ts" + "name": "@feng3d/render-api", + "version": "0.0.8", + "description": "提供WebGL/WebGPU统一的渲染数据结构,描述渲染所需的所有数据以及流程,用于@feng3d/webgl与@feng3d/webgpu。", + "homepage": "https://feng3d.com/render-api/", + "author": "feng", + "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" + } + }, + "scripts": { + "clean": "rimraf \"{lib,dist,public}\"", + "build": "vite build", + "test": "vitest", + "types": "tsc", + "watch": "tsc -w", + "lint": "eslint . --ext .js,.ts --max-warnings 0", + "lintfix": "npm run lint -- --fix", + "docs": "typedoc", + "upload_oss": "npm run docs && feng3d-cli oss_upload_dir", + "update": "npx feng3d-cli update && npm install", + "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", + "prepare": "husky", + "postinstall": "npx feng3d-cli update || exit 0" + }, + "repository": { + "type": "git", + "url": "https://github.com/feng3d-labs/render-api.git" + }, + "publishConfig": { + "access": "public" + }, + "files": [ + "dist/", + "lib", + "src", + "readme", + "tsconfig.json" + ], + "devDependencies": { + "@eslint/js": "^9.0.0", + "feng3d-cli": "^0.0.3", + "@typescript-eslint/eslint-plugin": "8.32.1", + "@typescript-eslint/parser": "8.32.1", + "typescript-eslint": "^8.32.1", + "cross-env": "7.0.3", + "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", + "husky": "^9.1.7", + "lint-staged": "^15.2.10" + }, + "dependencies": { + "@webgpu/types": "0.1.60", + "@feng3d/reactivity": "^1.0.6" + }, + "lint-staged": { + "*.{js,ts}": [ + "eslint --fix --max-warnings 0" + ] } - }, - "scripts": { - "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", - "lintfix": "npm run lint -- --fix", - "docs": "typedoc", - "release": "npm run clean && npm run lint && npm run build && npm run types && npm publish", - "prepublishOnly": "node scripts/prepublish.js", - "postpublish": "node scripts/postpublish.js" - }, - "repository": { - "type": "git", - "url": "https://github.com/feng3d-labs/render-api.git" - }, - "publishConfig": { - "access": "public" - }, - "files": [ - "dist/", - "lib", - "src", - "readme", - "tsconfig.json" - ], - "devDependencies": { - "@typescript-eslint/eslint-plugin": "5.17.0", - "@typescript-eslint/parser": "5.17.0", - "@vitest/ui": "^0.32.2", - "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" - }, - "dependencies": { - "@feng3d/reactivity": "^1.0.4" - } } diff --git a/scripts/postpublish.js b/scripts/postpublish.js index 01321a4..7296278 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 db681a8..043f4c8 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 4ccfd06..6666eca 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: Int16Array }, + float16x4: { numComponents: 4, type: 'HALF_FLOAT', normalized: false, dataType: 'float', byteSize: 8, wgslType: 'vec4', typedArrayConstructor: Int16Array }, + 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 350b964..0d07a87 100644 --- a/src/data/BindingResources.ts +++ b/src/data/BindingResources.ts @@ -1,4 +1,4 @@ -import { BufferBinding, BufferBindingItem } from "./BufferBinding"; +import { BufferBinding } from './BufferBinding'; /** * 绑定资源。 @@ -21,5 +21,4 @@ export interface BindingResourceTypeMap * 缓冲区绑定。 */ BufferBinding: BufferBinding; - BufferBindingItem: BufferBindingItem; } diff --git a/src/data/BlendComponent.ts b/src/data/BlendComponent.ts index b9e906b..ca22de9 100644 --- a/src/data/BlendComponent.ts +++ b/src/data/BlendComponent.ts @@ -19,49 +19,66 @@ export interface BlendComponent * * 当 `operation` 值为 "min" 或 "max" 时, `srcFactor` 与 `dstFactor` 将会被引擎自动使用 "one"。 * + * 对于 alpha 通道,未设置时会继承 color 通道的设置。 + * * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/blendEquation */ - readonly operation?: IBlendOperation; + readonly operation?: BlendOperation; /** * 源混合因子。 * - * 默认为 "one"。 + * 默认为 "src-alpha"。 + * + * 对于 alpha 通道,未设置时会继承 color 通道的设置。 * * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/blendFunc */ - readonly srcFactor?: IBlendFactor; + readonly srcFactor?: BlendFactor; /** * 目标混合因子。 * - * 默认为 "zero"。 + * 默认为 "one-minus-src-alpha"。 + * + * 对于 alpha 通道,未设置时会继承 color 通道的设置。 * * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/blendFunc */ - readonly dstFactor?: IBlendFactor; + readonly dstFactor?: BlendFactor; } -export type IBlendOperation = "add" | "subtract" | "reverse-subtract" | "min" | "max"; +export type BlendOperation = 'add' | 'subtract' | 'reverse-subtract' | 'min' | 'max'; /** * @see https://gpuweb.github.io/gpuweb/#enumdef-gpublendfactor */ -export type IBlendFactor = IBlendFactorMap[keyof IBlendFactorMap]; +export type BlendFactor = IBlendFactorMap[keyof IBlendFactorMap]; export interface IBlendFactorMap { - "zero": "zero"; - "one": "one"; - "src": "src"; - "one-minus-src": "one-minus-src"; - "src-alpha": "src-alpha"; - "one-minus-src-alpha": "one-minus-src-alpha"; - "dst": "dst"; - "one-minus-dst": "one-minus-dst"; - "dst-alpha": "dst-alpha"; - "one-minus-dst-alpha": "one-minus-dst-alpha"; - "src-alpha-saturated": "src-alpha-saturated"; - "constant": "constant"; - "one-minus-constant": "one-minus-constant"; + 'zero': 'zero'; + 'one': 'one'; + 'src': 'src'; + 'one-minus-src': 'one-minus-src'; + 'src-alpha': 'src-alpha'; + 'one-minus-src-alpha': 'one-minus-src-alpha'; + 'dst': 'dst'; + 'one-minus-dst': 'one-minus-dst'; + 'dst-alpha': 'dst-alpha'; + 'one-minus-dst-alpha': 'one-minus-dst-alpha'; + 'src-alpha-saturated': 'src-alpha-saturated'; + 'constant': 'constant'; + 'one-minus-constant': 'one-minus-constant'; } + +/** + * 默认混合组件配置。 + * + * 用于 WebGL 和 WebGPU 在未指定混合组件时使用相同的默认值,确保渲染效果一致。 + */ +export const defaultBlendComponent: BlendComponent = { + operation: 'add', + srcFactor: 'src-alpha', + dstFactor: 'one-minus-src-alpha', +}; \ No newline at end of file diff --git a/src/data/BlendState.ts b/src/data/BlendState.ts index 5b68384..ea95aa1 100644 --- a/src/data/BlendState.ts +++ b/src/data/BlendState.ts @@ -1,5 +1,5 @@ -import { BlendComponent } from "./BlendComponent"; -import { Color } from "./RenderPassColorAttachment"; +import { BlendComponent } from './BlendComponent'; +import { Color } from './RenderPassColorAttachment'; /** * 混合状态。 @@ -43,24 +43,31 @@ export class BlendState * @param blend * @returns */ - static getBlendConstantColor(blendState: BlendState): Color + static getBlendConstantColor(blendState: BlendState): Color | undefined { if (!blendState) return undefined; - const { color, alpha, constantColor } = blendState; + const { color, alpha } = blendState; // 当混合系数用到了混合常量值时设置混合常量值。 if (0 - || color?.srcFactor === "constant" - || color?.srcFactor === "one-minus-constant" - || color?.dstFactor === "constant" - || color?.dstFactor === "one-minus-constant" - || alpha?.srcFactor === "constant" - || alpha?.srcFactor === "one-minus-constant" - || alpha?.dstFactor === "constant" - || alpha?.dstFactor === "one-minus-constant" + || color?.srcFactor === 'constant' + || color?.srcFactor === 'one-minus-constant' + || color?.dstFactor === 'constant' + || color?.dstFactor === 'one-minus-constant' + || alpha?.srcFactor === 'constant' + || alpha?.srcFactor === 'one-minus-constant' + || alpha?.dstFactor === 'constant' + || alpha?.dstFactor === 'one-minus-constant' ) { + const constantColor = blendState.constantColor; + + if (constantColor) + { + return constantColor; + } + return constantColor ?? [0, 0, 0, 0]; } diff --git a/src/data/Buffer.ts b/src/data/Buffer.ts index 620ab87..0bb441b 100644 --- a/src/data/Buffer.ts +++ b/src/data/Buffer.ts @@ -1,5 +1,4 @@ -import { TypedArray } from "../types/TypedArray"; -import { WriteBuffer } from "./WriteBuffer"; +import { WriteBuffer } from './WriteBuffer'; /** * 缓冲区 @@ -24,14 +23,14 @@ export interface Buffer * * 尺寸必须为4的倍数。 * - * 注:修改尺寸时,会重新创建缓冲区。 + * 注:修改后将重新创建GPUBuffer。 */ readonly size: number; /** * 缓冲区数据。 */ - readonly data?: TypedArray; + readonly data?: ArrayBufferLike; /** * 写缓冲区。 @@ -40,3 +39,46 @@ export interface Buffer */ readonly writeBuffers?: WriteBuffer[]; } + +export class Buffer +{ + /** + * 从TypedArray创建或获取缓冲区配置 + * 自动处理缓冲区大小对齐(4字节对齐) + * @param arrayBuffer 源数据数组 + * @returns 缓冲区配置对象 + */ + static getBuffer(arrayBuffer: ArrayBufferLike) + { + // 检查是否已存在对应的缓冲区配置 + 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(); +} + +declare global +{ + interface ArrayBuffer + { + // 并不会实际赋值, 只是用于 ArrayBuffer 与 TypedArray 在类型上做区分。 + __type__: 'ArrayBuffer'; + } + interface SharedArrayBuffer + { + // 并不会实际赋值, 只是用于 SharedArrayBuffer 与 TypedArray 在类型上做区分。 + __type__: 'SharedArrayBuffer'; + } +} \ No newline at end of file diff --git a/src/data/BufferBinding.ts b/src/data/BufferBinding.ts index 5c37ab7..49f60bc 100644 --- a/src/data/BufferBinding.ts +++ b/src/data/BufferBinding.ts @@ -1,4 +1,4 @@ -import { TypedArray } from "../types/TypedArray"; +import { TypedArray } from '../types/TypedArray'; /** * 缓冲区绑定。 @@ -10,7 +10,7 @@ import { TypedArray } from "../types/TypedArray"; */ export interface BufferBinding { - readonly [name: string]: BufferBindingItem; + readonly value?: BufferBindingItem; /** * 如果未设置引擎将自动生成。 diff --git a/src/data/CanvasTexture.ts b/src/data/CanvasTexture.ts index de3b617..b2b5753 100644 --- a/src/data/CanvasTexture.ts +++ b/src/data/CanvasTexture.ts @@ -1,4 +1,4 @@ -import { CanvasContext } from "./CanvasContext"; +import { CanvasContext } from './CanvasContext'; /** * 画布纹理,从画布的上下文获取纹理 @@ -9,13 +9,4 @@ export interface CanvasTexture * 画布上下文。 */ context: CanvasContext; - - /** - * 画布尺寸发生变化后引擎自动递增。 - * - * 引擎内部监听这个值,在画布尺寸发生变化后重新获取纹理。 - * - * @private - */ - _canvasSizeVersion?: number; } diff --git a/src/data/ColorTargetState.ts b/src/data/ColorTargetState.ts index e421f6e..db977ea 100644 --- a/src/data/ColorTargetState.ts +++ b/src/data/ColorTargetState.ts @@ -1,4 +1,4 @@ -import { BlendState } from "./BlendState"; +import { BlendState } from './BlendState'; /** * 属性 `format` 将由渲染通道中附件给出。 diff --git a/src/data/CommandEncoder.ts b/src/data/CommandEncoder.ts index b311f3e..2b8a616 100644 --- a/src/data/CommandEncoder.ts +++ b/src/data/CommandEncoder.ts @@ -1,6 +1,7 @@ -import { CopyBufferToBuffer } from "./CopyBufferToBuffer"; -import { CopyTextureToTexture } from "./CopyTextureToTexture"; -import { RenderPass } from "./RenderPass"; +import { CopyBufferToBuffer } from './CopyBufferToBuffer'; +import { CopyTextureToTexture } from './CopyTextureToTexture'; +import { RenderPass } from './RenderPass'; +import { TransformFeedbackPass } from './TransformFeedbackPass'; /** * 命令编码器。 @@ -40,5 +41,10 @@ export interface PassEncoderMap CopyTextureToTexture: CopyTextureToTexture; CopyBufferToBuffer: CopyBufferToBuffer; + + /** + * Transform Feedback 通道(WebGL2 特有,WebGPU 使用计算着色器模拟)。 + */ + TransformFeedbackPass: TransformFeedbackPass; } diff --git a/src/data/CopyBufferToBuffer.ts b/src/data/CopyBufferToBuffer.ts index 264cfde..d894f72 100644 --- a/src/data/CopyBufferToBuffer.ts +++ b/src/data/CopyBufferToBuffer.ts @@ -1,4 +1,4 @@ -import { Buffer } from "./Buffer"; +import { TypedArray } from '../types/TypedArray'; /** * GPU缓冲区之间拷贝。 @@ -11,30 +11,26 @@ export interface CopyBufferToBuffer /** * 数据类型。 */ - readonly __type__: "CopyBufferToBuffer"; + readonly __type__: 'CopyBufferToBuffer'; /** - * 源缓冲区。 + * 源数据。 + * + * source.buffer 对应 GPUBuffer,source.byteOffset 对应 sourceOffset,source.byteLength 对应 size。 */ - source: Buffer; - - /** - * 默认为0。 - */ - sourceOffset?: number; + source: TypedArray; /** * 目标缓冲区。 + * + * {@link destination.buffer} 对应 GPUBuffer,{@link destination.byteOffset} 对应 destinationOffset,{@link destination.byteLength} 对应 size。 */ - destination: Buffer; - - /** - * 默认为0。 - */ - destinationOffset?: number; + destination: TypedArray; /** - * 默认为源缓冲区尺寸。 + * 拷贝的尺寸。 + * + * 默认为源数据与目标数据字节长度的最小值({@link Math.min} ({@link source.byteLength}, {@link destination.byteLength}))。 */ size?: number; } diff --git a/src/data/CopyTextureToTexture.ts b/src/data/CopyTextureToTexture.ts index c55126a..6b18aad 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 a79a051..756721d 100644 --- a/src/data/DepthStencilState.ts +++ b/src/data/DepthStencilState.ts @@ -1,4 +1,4 @@ -import { CompareFunction, StencilFaceState } from "./StencilFaceState"; +import { CompareFunction, StencilFaceState } from './StencilFaceState'; /** * 深度模板阶段描述。 @@ -87,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 8d5614c..8491e65 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 aa2cfdb..146e8a9 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 e21ada0..e727828 100644 --- a/src/data/FragmentState.ts +++ b/src/data/FragmentState.ts @@ -1,4 +1,4 @@ -import { ColorTargetState } from "./ColorTargetState"; +import { ColorTargetState } from './ColorTargetState'; /** * 片段着色器阶段描述。 @@ -10,7 +10,17 @@ export interface FragmentState /** * 着色器代码。 */ - readonly code: string; + readonly code?: string; + + /** + * GLSL着色器代码。适用于WebGL。 + */ + readonly glsl?: string; + + /** + * WGSL着色器代码。适用于WebGPU。 + */ + readonly wgsl?: string; /** * A list of {@link GPUColorTargetState} defining the formats and behaviors of the color targets diff --git a/src/data/ImageCopyTexture.ts b/src/data/ImageCopyTexture.ts index 4f62594..fdeb554 100644 --- a/src/data/ImageCopyTexture.ts +++ b/src/data/ImageCopyTexture.ts @@ -1,4 +1,4 @@ -import { TextureLike, TextureOrigin } from "./Texture"; +import { TextureLike, TextureOrigin } from './Texture'; /** * 被操作的纹理相关信息。 @@ -27,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 6129ec6..4c11805 100644 --- a/src/data/OcclusionQuery.ts +++ b/src/data/OcclusionQuery.ts @@ -1,4 +1,4 @@ -import { RenderObject } from "./RenderObject"; +import { RenderObject } from './RenderObject'; /** * 遮挡查询 @@ -8,7 +8,7 @@ export interface OcclusionQuery /** * 数据类型。 */ - readonly __type__: "OcclusionQuery"; + readonly __type__: 'OcclusionQuery'; /** * GPU渲染对象列表。 diff --git a/src/data/PrimitiveState.ts b/src/data/PrimitiveState.ts index c5048cd..e1350bd 100644 --- a/src/data/PrimitiveState.ts +++ b/src/data/PrimitiveState.ts @@ -54,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', } /** @@ -70,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 516980a..8bce9da 100644 --- a/src/data/ReadPixels.ts +++ b/src/data/ReadPixels.ts @@ -1,4 +1,5 @@ -import { TextureView } from "./TextureView"; +import { TextureFormat } from './Texture'; +import { TextureView } from './TextureView'; /** * 读取渲染缓冲区或者纹理视图中的像素值。 @@ -8,9 +9,15 @@ import { TextureView } from "./TextureView"; export interface ReadPixels { /** - * 读取的纹理视图。 + * 纹理视图 + * + * 当 textureView 为 undefined 时,表示从当前画布纹理读取。 + * + * 支持从纹理数组的特定层读取,通过设置 textureView.baseArrayLayer 指定层索引。 + * + * @default undefined */ - textureView: TextureView; + textureView?: TextureView, /** * 读取位置。 @@ -26,4 +33,12 @@ export interface ReadPixels * 用于保存最后结果。 */ result?: ArrayBufferView; + + /** + * 纹理数据格式。 + * + * 由 readPixels 方法设置,表示返回数据的格式(例如 'rgba8unorm' 或 'bgra8unorm')。 + * 调用者可以根据此格式正确处理颜色通道顺序。 + */ + format?: TextureFormat; } \ No newline at end of file diff --git a/src/data/RenderObject.ts b/src/data/RenderObject.ts index cd4a0eb..2193787 100644 --- a/src/data/RenderObject.ts +++ b/src/data/RenderObject.ts @@ -1,10 +1,10 @@ -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"; +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'; /** * 渲染对象,包含一次渲染时包含的所有数据。 @@ -14,7 +14,7 @@ export interface RenderObject /** * 数据类型。 */ - __type__?: "RenderObject"; + __type__?: 'RenderObject'; /** * 视窗。 @@ -66,7 +66,7 @@ export class RenderObject 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 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; @@ -87,7 +87,7 @@ export class RenderObject 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 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; @@ -102,14 +102,14 @@ export class RenderObject static getDraw(geometry: RenderObject): DrawIndexed | DrawVertex { - if (geometry["_draw"]) return geometry["_draw"]; + if (geometry['_draw']) return geometry['_draw']; const instanceCount = RenderObject.getInstanceCount(geometry); if (geometry.indices) { return { - __type__: "DrawIndexed", + __type__: 'DrawIndexed', indexCount: geometry.indices.length, firstIndex: 0, instanceCount, @@ -117,7 +117,7 @@ export class RenderObject } return { - __type__: "DrawVertex", + __type__: 'DrawVertex', vertexCount: RenderObject.getNumVertex(geometry), instanceCount, }; diff --git a/src/data/RenderPass.ts b/src/data/RenderPass.ts index e7632e8..865ae26 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,12 +12,14 @@ export interface RenderPass /** * 数据类型。 */ - readonly __type__?: "RenderPass"; + readonly __type__?: 'RenderPass'; /** * 渲染通道描述 + * + * 必须提供。第一个颜色附件中的纹理视图可以缺省,当缺省时使用 WebGL/WebGPU 构造函数中传递的 canvasContext。 */ - readonly descriptor?: RenderPassDescriptor; + readonly descriptor: RenderPassDescriptor; /** * 渲染对象列表 diff --git a/src/data/RenderPassColorAttachment.ts b/src/data/RenderPassColorAttachment.ts index c708709..9e8e79e 100644 --- a/src/data/RenderPassColorAttachment.ts +++ b/src/data/RenderPassColorAttachment.ts @@ -1,4 +1,4 @@ -import { TextureView } from "./TextureView"; +import { TextureView } from './TextureView'; /** * 渲染通道颜色附件。 @@ -57,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 3341033..4df34ff 100644 --- a/src/data/RenderPassDepthStencilAttachment.ts +++ b/src/data/RenderPassDepthStencilAttachment.ts @@ -1,4 +1,4 @@ -import { TextureView } from "./TextureView"; +import { TextureView } from './TextureView'; /** * 深度模板附件。 @@ -31,7 +31,7 @@ export interface RenderPassDepthStencilAttachment * * @see https://developer.mozilla.org/docs/Web/API/WebGLRenderingContext/clear */ - readonly depthLoadOp?: "load" | "clear"; + readonly depthLoadOp?: 'load' | 'clear'; /** * 清除后填充模板值。 @@ -49,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 3f44a05..731c7f1 100644 --- a/src/data/RenderPassDescriptor.ts +++ b/src/data/RenderPassDescriptor.ts @@ -1,5 +1,5 @@ -import { RenderPassColorAttachment } from "./RenderPassColorAttachment"; -import { RenderPassDepthStencilAttachment } from "./RenderPassDepthStencilAttachment"; +import { RenderPassColorAttachment } from './RenderPassColorAttachment'; +import { RenderPassDepthStencilAttachment } from './RenderPassDepthStencilAttachment'; /** * 渲染通道描述 @@ -38,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 9fa17b4..aaca08b 100644 --- a/src/data/RenderPipeline.ts +++ b/src/data/RenderPipeline.ts @@ -1,7 +1,7 @@ -import { DepthStencilState } from "./DepthStencilState"; -import { FragmentState } from "./FragmentState"; -import { PrimitiveState } from "./PrimitiveState"; -import { VertexState } from "./VertexState"; +import { DepthStencilState } from './DepthStencilState'; +import { FragmentState } from './FragmentState'; +import { PrimitiveState } from './PrimitiveState'; +import { VertexState } from './VertexState'; /** * 渲染管线。 diff --git a/src/data/Sampler.ts b/src/data/Sampler.ts index a29f06d..d9512cf 100644 --- a/src/data/Sampler.ts +++ b/src/data/Sampler.ts @@ -1,4 +1,4 @@ -import { CompareFunction } from "./StencilFaceState"; +import { CompareFunction } from './StencilFaceState'; /** * 纹理采样器。 @@ -106,7 +106,7 @@ export interface Sampler /** * 采样时使用的最大Lod等级。 * - * 默认 16 。 + * 默认 16。当未设置 {@link mipmapFilter} 时默认为 0(不使用 mipmap),以保持与 WebGL 行为一致。 */ readonly lodMaxClamp?: number; @@ -123,14 +123,30 @@ export interface Sampler /** * 纹理坐标寻址模式。 */ -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'; + +/** + * 采样器默认值。 + */ +export const defaultSampler: Sampler = { + addressModeU: 'repeat', + addressModeV: 'repeat', + addressModeW: 'repeat', + magFilter: 'nearest', + minFilter: 'nearest', + mipmapFilter: 'nearest', + lodMinClamp: 0, + lodMaxClamp: 16, + compare: undefined, + maxAnisotropy: 1, +}; diff --git a/src/data/StencilFaceState.ts b/src/data/StencilFaceState.ts index fa45bfd..e12d0f4 100644 --- a/src/data/StencilFaceState.ts +++ b/src/data/StencilFaceState.ts @@ -34,6 +34,6 @@ export interface StencilFaceState readonly passOp?: StencilOperation; } -export type CompareFunction = "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 StencilOperation = "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 20628a1..936dc75 100644 --- a/src/data/Submit.ts +++ b/src/data/Submit.ts @@ -1,4 +1,4 @@ -import { CommandEncoder } from "./CommandEncoder"; +import { CommandEncoder } from './CommandEncoder'; /** * 一次 GPU 提交。 diff --git a/src/data/Texture.ts b/src/data/Texture.ts index 78f6bf4..da1af69 100644 --- a/src/data/Texture.ts +++ b/src/data/Texture.ts @@ -1,5 +1,6 @@ -import { TextureDataSource } from "./TextureDataSource"; -import { TextureImageSource } from "./TextureImageSource"; +import { CanvasTexture } from './CanvasTexture'; +import { TextureDataSource } from './TextureDataSource'; +import { TextureImageSource } from './TextureImageSource'; /** * 类似纹理,包含画布纹理以及正常纹理。 @@ -17,17 +18,24 @@ export interface TextureLikeMap * 正常纹理。 */ Texture: Texture; + + /** + * 画布纹理。 + */ + CanvasTexture: CanvasTexture; } /** - * 纹理 + * 纹理描述。 */ -export interface Texture +export interface TextureDescriptor { /** * 标签。 * * 用于调试。 + * + * 注:修改后将重新创建纹理。 */ readonly label?: string; @@ -40,6 +48,61 @@ export interface Texture */ readonly size: TextureSize; + /** + * 纹理维度,默认为 "2d" 。 + * + * WebGL中不支持 "1d" "cube-array"。 + * + * 注:修改后将重新创建纹理。 + */ + readonly dimension?: TextureDimension; + + /** + * 纹理格式。 默认为 "rgba8unorm", + * + * 注:修改后将重新创建纹理。 + */ + readonly format?: TextureFormat; + + /** + * The number of mip levels the texture will contain. + * + * 注:修改后将重新创建纹理。 + */ + readonly mipLevelCount?: number; + + /** + * 是否生成mipmap + * + * 仅在纹理创建时执行。 + * + * 注:修改后将重新创建纹理。 + */ + readonly generateMipmap?: boolean; + + /** + * The sample count of the texture. A {@link GPUTextureDescriptor#sampleCount} > `1` indicates + * a multisampled texture. + * + * WebGPU只支持4重采样。 + * + * 注:修改后将重新创建纹理。 + */ + readonly sampleCount?: 4; +} + +/** + * 纹理 + */ +export interface Texture +{ + /** + * 纹理描述。 + * + * 注:修改后将重新创建纹理。 + */ + readonly descriptor: TextureDescriptor; + /** * 初始化纹理资源。 * @@ -50,14 +113,11 @@ export interface Texture * * @see GPUQueue.copyExternalImageToTexture * @see GPUQueue.writeTexture + * + * 注:修改后将重新创建纹理。 */ readonly sources?: readonly TextureSource[]; - /** - * 初始化纹理后是否生成mipmap - */ - readonly generateMipmap?: boolean; - /** * 写入纹理资源。 * @@ -70,23 +130,6 @@ export interface Texture * @see GPUQueue.writeTexture */ readonly writeTextures?: readonly TextureSource[]; - - /** - * 纹理维度,默认为 "2d" 。 - * - * WebGL中不支持 "1d" "cube-array"。 - */ - readonly dimension?: TextureDimension; - - /** - * 纹理格式。 默认为 "rgba8unorm", - */ - readonly format?: TextureFormat; - - /** - * The number of mip levels the texture will contain. - */ - readonly mipLevelCount?: number; } export class Texture @@ -96,7 +139,7 @@ export class Texture * * @param format 纹理格式。 */ - static getTextureBytesPerPixel(format: TextureFormat = "rgba8unorm") + static getTextureBytesPerPixel(format: TextureFormat = 'rgba8unorm') { const bytesPerPixel = formatMap[format]?.bytesPerPixel; @@ -111,7 +154,7 @@ export class Texture * @param format 纹理格式。 * @returns */ - static getTextureDataConstructor(format: TextureFormat = "rgba8unorm") + static getTextureDataConstructor(format: TextureFormat = 'rgba8unorm') { const bytesPerPixel = formatMap[format]?.dataConstructor; @@ -189,108 +232,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]: { @@ -326,12 +369,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 }, @@ -348,59 +391,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 1cf65de..7e1c939 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 f6e3d1f..70fdedc 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 da6fd2c..25eb303 100644 --- a/src/data/TextureView.ts +++ b/src/data/TextureView.ts @@ -1,4 +1,4 @@ -import { TextureLike } from "./Texture"; +import { TextureLike } from './Texture'; /** * 纹理视图。 @@ -9,11 +9,15 @@ export interface TextureView * 标签。 * * 用于调试。 + * + * 注:修改后将重新创建视图。 */ readonly label?: string; /** * 产生视图的纹理。 + * + * 注:修改后将重新创建视图。 */ readonly texture: TextureLike; @@ -21,6 +25,8 @@ export interface TextureView * mipmap级别。 * * 默认为 0。 + * + * 注:修改后将重新创建视图。 */ readonly baseMipLevel?: number; @@ -28,6 +34,26 @@ export interface TextureView * 3d纹理的深度索引、纹理数组中的层次、立方体纹理的面索引。 * * 默认为 0。 + * + * 注:修改后将重新创建视图。 */ readonly baseArrayLayer?: number; + + /** + * 数组层数。 + * + * 默认为 1。 + * + * 被用作颜色附件时,必须为 1。而其他情况默认为 undefined(使用所有剩余层)。 + * + * 注:修改后将重新创建视图。 + */ + readonly arrayLayerCount?: number; + + /** + * 是否被用作颜色附件。 + * + * 注:由 WebGPU 渲染通道颜色附件自动设置。 + */ + readonly isUsedAsColorAttachment?: boolean; } diff --git a/src/data/TransformFeedbackPass.ts b/src/data/TransformFeedbackPass.ts new file mode 100644 index 0000000..6f13ec2 --- /dev/null +++ b/src/data/TransformFeedbackPass.ts @@ -0,0 +1,96 @@ +import { BindingResources } from './BindingResources'; +import { DrawVertex } from './DrawVertex'; +import { VertexAttributes, VertexData } from './VertexAttributes'; +import { VertexState } from './VertexState'; + +export interface TransformFeedbackPass +{ + /** + * 数据类型。 + */ + readonly __type__: 'TransformFeedbackPass'; + + /** + * 变换反馈对象列表。 + */ + transformFeedbackObjects: TransformFeedbackObject[]; +} + +export interface TransformFeedbackObject +{ + /** + * 渲染管线描述。 + */ + readonly pipeline: TransformFeedbackPipeline; + + /** + * 顶点属性数据映射。 + */ + vertices: VertexAttributes; + + /** + * 根据顶点数据绘制图元。 + * + * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/drawVertex + */ + readonly draw: DrawVertex; + + /** + * Uniform渲染数据 + */ + uniforms?: BindingResources; + + /** + * 回写顶点着色器中输出到缓冲区。 + * + * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/bindTransformFeedback + */ + transformFeedback: TransformFeedback; +} + +export interface TransformFeedbackPipeline +{ + /** + * 顶点着色器阶段描述(用于 WebGL Transform Feedback)。 + */ + readonly vertex: VertexState; + + /** + * 回写变量。 + * + * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/transformFeedbackVaryings + */ + transformFeedbackVaryings: TransformFeedbackVaryings; +} + +export interface TransformFeedbackVaryings +{ + /** + * 回写变量列表。 + */ + varyings: string[]; + + /** + * 交叉或者分离。 + */ + bufferMode: 'INTERLEAVED_ATTRIBS' | 'SEPARATE_ATTRIBS'; +} + +/** + * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/createTransformFeedback + */ +export interface TransformFeedback +{ + /** + * 绑定缓冲区列表。 + */ + bindBuffers: TransformFeedbacBindBuffer[]; +} + +export interface TransformFeedbacBindBuffer +{ + index: number; + + data: VertexData; +} + diff --git a/src/data/VertexAttributes.ts b/src/data/VertexAttributes.ts index e5c99f4..1cec2e7 100644 --- a/src/data/VertexAttributes.ts +++ b/src/data/VertexAttributes.ts @@ -1,4 +1,4 @@ -import { vertexFormatMap } from "../consts/vertexFormatMap"; +import { vertexFormatMap } from '../consts/vertexFormatMap'; /** * 顶点属性数据映射。 @@ -16,7 +16,7 @@ export interface VertexAttribute /** * 顶点数据。 */ - data: VertexDataTypes; + data: VertexData; /** * 顶点数据格式。 @@ -81,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 @@ -96,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 ec5a64c..2a7b430 100644 --- a/src/data/VertexState.ts +++ b/src/data/VertexState.ts @@ -6,5 +6,15 @@ export interface VertexState /** * 着色器代码。 */ - readonly code: string; + readonly code?: string; + + /** + * GLSL着色器代码。适用于WebGL。 + */ + readonly glsl?: string; + + /** + * WGSL着色器代码。适用于WebGPU。 + */ + readonly wgsl?: string; } \ No newline at end of file diff --git a/src/data/WriteBuffer.ts b/src/data/WriteBuffer.ts index 98bdb5d..b2d6bfc 100644 --- a/src/data/WriteBuffer.ts +++ b/src/data/WriteBuffer.ts @@ -1,4 +1,4 @@ -import { TypedArray } from "../types/TypedArray"; +import { TypedArray } from '../types/TypedArray'; export interface WriteBuffer { @@ -10,21 +10,12 @@ export interface WriteBuffer /** * 写入缓冲区数据。 */ - data: ArrayBufferLike | TypedArray; + data: TypedArray; /** - * 读取数据的起始位置。 + * 写入数据数量。 * - * 默认为 0 。 - * - * 当写入的数据类型为 {@link ArrayBufferLike} 时单位为字节,当数据类型为 {@link TypedArray} 时单位为元素。 - */ - dataOffset?: number; - - /** - * 写入数据尺寸。 - * - * 当写入的数据类型为 {@link ArrayBufferLike} 时单位为字节,当数据类型为 {@link TypedArray} 时单位为元素。 + * 默认为 {@link data.length} 。 */ size?: number; } diff --git a/src/global.ts b/src/debug.d.ts similarity index 91% rename from src/global.ts rename to src/debug.d.ts index 2e59812..6a38a69 100644 --- a/src/global.ts +++ b/src/debug.d.ts @@ -1,4 +1,3 @@ -export { }; declare global { /** diff --git a/src/index.ts b/src/index.ts index 74cc531..d9311e9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,48 +1,57 @@ -export * from "./consts/vertexFormatMap"; +/// -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 './consts/vertexFormatMap'; -export * from "./types/TypedArray"; -export * from "./types/UnReadonly"; +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/TransformFeedbackPass'; +export * from './data/VertexAttributes'; +export * from './data/VertexState'; +export * from './data/Viewport'; +export * from './data/WriteBuffer'; -export * from "./utils/ChainMap"; +export * from './internal/BufferBindingInfo'; -import "./global"; \ No newline at end of file +export * from './types/TypedArray'; + +export * from './utils/ChainMap'; +export * from './utils/unreadonly'; + +export const renderState = { + isRunWebGPU: false, + isRunWebGL: false, +} \ No newline at end of file diff --git a/src/internal/BufferBindingInfo.ts b/src/internal/BufferBindingInfo.ts index 764a0d5..f13a8a1 100644 --- a/src/internal/BufferBindingInfo.ts +++ b/src/internal/BufferBindingInfo.ts @@ -9,5 +9,9 @@ export interface BufferBindingInfo offset: number; size: number; Cls: Float32ArrayConstructor | Int32ArrayConstructor | Uint32ArrayConstructor | Int16ArrayConstructor; + /** + * 类型名称(用于判断是否需要对齐转换,WebGPU 专用) + */ + typeName?: string; }[] } diff --git a/src/shader.d.ts b/src/shader.d.ts new file mode 100644 index 0000000..193d734 --- /dev/null +++ b/src/shader.d.ts @@ -0,0 +1,65 @@ +/** + * @const + * @readonly + * @kind module + * @description Generic shaders + */ +declare module '*.glsl' { + const shader: string; + export default shader; +} + +/** + * @const + * @readonly + * @kind module + * @description WebGPU shaders + */ +declare module '*.wgsl' { + const shader: string; + export default shader; +} + +/** + * @const + * @readonly + * @kind module + * @description Vertex shaders + */ +declare module '*.vert' { + const shader: string; + export default shader; +} + +/** + * @const + * @readonly + * @kind module + * @description Fragment shaders + */ +declare module '*.frag' { + const shader: string; + export default shader; +} + +/** + * @const + * @readonly + * @kind module + * @description Vertex shaders + */ +declare module '*.vs' { + const shader: string; + export default shader; +} + +/** + * @const + * @readonly + * @kind module + * @description Fragment shaders + */ +declare module '*.fs' { + const shader: string; + export default shader; +} \ No newline at end of file diff --git a/src/types/UnReadonly.ts b/src/types/UnReadonly.ts deleted file mode 100644 index ad8f1b1..0000000 --- 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 index 8aa1d65..346ecdf 100644 --- a/src/utils/ChainMap.ts +++ b/src/utils/ChainMap.ts @@ -8,8 +8,13 @@ export class ChainMap, V> /** * 根字典。 */ - private _根字典 = new WeakMap(); - private _数量 = 0; + private _map = new WeakMap(); + get size() + { + return this._size; + } + + private _size = 0; /** * 获取键对应的值。 @@ -20,7 +25,7 @@ export class ChainMap, V> get(keys: K): V { const keysLength = keys.length; - let map = this._根字典; + let map = this._map; let key: any; for (let i = 0, n = keysLength - 1; i < n; i++) @@ -33,7 +38,7 @@ export class ChainMap, V> key = wrapKey(keys[keysLength - 1]); -return map.get(key); + return map.get(key); } /** @@ -47,7 +52,7 @@ return map.get(key); set(keys: K, value: V) { const keysLength = keys.length; - let map = this._根字典; + let map = this._map; let key: any; for (let i = 0; i < keysLength - 1; i++) @@ -66,7 +71,7 @@ return map.get(key); if (!map.has(key)) { map.set(key, value); - this._数量++; + this._size++; } return value; @@ -81,7 +86,7 @@ return map.get(key); delete(keys: K): boolean { const keysLength = keys.length; - let map = this._根字典; + let map = this._map; let key: any; for (let i = 0; i < keysLength - 1; i++) @@ -94,7 +99,8 @@ return map.get(key); key = wrapKey(keys[keysLength - 1]); const result = map.delete(key); - if (result) this._数量--; + + if (result) this._size--; return result; } @@ -108,7 +114,7 @@ let idCounter = 0; // 包装函数,将非对象值包装成对象 function wrapKey(key: any) { - if (typeof key === "object" && key !== null) + if (typeof key === 'object' && key !== null) { // 如果 key 已经是对象,则直接返回 return key; @@ -123,10 +129,11 @@ function wrapKey(key: any) // 创建一个包装对象 const wrapper = { __id: id, - __value: key + __value: key, }; + // 存储原始值和包装对象的映射 keyMap.set(key, wrapper); -return wrapper; + return wrapper; } \ No newline at end of file diff --git a/src/utils/unreadonly.ts b/src/utils/unreadonly.ts new file mode 100644 index 0000000..05082f7 --- /dev/null +++ b/src/utils/unreadonly.ts @@ -0,0 +1,12 @@ +import { UnReadonly } from '@feng3d/reactivity'; + +/** + * 取消只读 + * @param value + * @returns + */ +export function unreadonly(value: T): UnReadonly +{ + return value; +} + diff --git a/test/index.spec.ts b/test/index.spec.ts deleted file mode 100644 index 9dcf08b..0000000 --- a/test/index.spec.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { TextureImageSource } from "@feng3d/render-api"; -import { assert, describe, it } from "vitest"; - -describe("test", () => -{ - it("test", () => - { - assert.equal(true, true); - }); -}); diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index a737ab8..0000000 --- a/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "compilerOptions": { - "target": "ES5", - "module": "CommonJS", - "noImplicitAny": false, - "sourceMap": true, - "declarationMap": true, - "declaration": true, - "experimentalDecorators": true, - "emitDeclarationOnly": true, - "lib": [ - "ESNext", - "DOM", - ], - "outDir": "lib" - }, - "include": [ - "src/**/*.ts" - ] -} \ No newline at end of file diff --git a/typedoc.json b/typedoc.json deleted file mode 100644 index e88a1a8..0000000 --- a/typedoc.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "@feng3d/render-api", - "$schema": "https://typedoc.org/schema.json", - "entryPoints": [ - "src/index.ts" - ], - "sourceLinkTemplate": "https://github.com/feng3d-labs/render-api/tree/master/{path}#L{line}", - "out": "public" -} \ No newline at end of file diff --git a/vite.config.js b/vite.config.js index f056904..d06a7e0 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: '' } }; }, }; }