diff --git a/graphic/ArkGraphics3D/.gitignore b/graphic/ArkGraphics3D/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..ea27eaff8c3ecef3e9ebe6399a5f9073cd962a7b --- /dev/null +++ b/graphic/ArkGraphics3D/.gitignore @@ -0,0 +1,13 @@ +/node_modules +/oh_modules +/local.properties +/.idea +**/build +/.hvigor +.cxx +/.clangd +/.clang-format +/.clang-tidy +**/.test +/.appanalyzer +oh-package-lock.json5 \ No newline at end of file diff --git a/graphic/ArkGraphics3D/AppScope/app.json5 b/graphic/ArkGraphics3D/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..2a2fc64855bea3030a8066d67f3bec55e500e921 --- /dev/null +++ b/graphic/ArkGraphics3D/AppScope/app.json5 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "app": { + "bundleName": "com.samples.ArkGraphics3D", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name" + } +} diff --git a/graphic/ArkGraphics3D/AppScope/resources/base/element/string.json b/graphic/ArkGraphics3D/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..64d50a205bd8227bb17db7c6805f2e86f81e658f --- /dev/null +++ b/graphic/ArkGraphics3D/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "com.samples.ArkGraphics3D" + } + ] +} diff --git a/graphic/ArkGraphics3D/AppScope/resources/base/media/app_icon.png b/graphic/ArkGraphics3D/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a39445dc87828b76fed6d2ec470dd455c45319e3 Binary files /dev/null and b/graphic/ArkGraphics3D/AppScope/resources/base/media/app_icon.png differ diff --git a/graphic/ArkGraphics3D/README.md b/graphic/ArkGraphics3D/README.md new file mode 100644 index 0000000000000000000000000000000000000000..5f94084f7e2904c4a66a0f5809359e03c59d8f12 --- /dev/null +++ b/graphic/ArkGraphics3D/README.md @@ -0,0 +1,133 @@ +# ArkGraphics 3D + +## 介绍 + +本示例通过 ArkGraphics 3D 的接口,利用轻量级的 3D 引擎和渲染管线,实现了 3D 场景创建、3D 场景资源创建和 3D 动画创建。 + +本示例主要展现了如何利用 ArkGraphics 3D 来实现 3D 图像的渲染,其中利用 Scene、Camera 和 Light 来创建基础的场景,使用 Material、Shader、Image 和Environment 来实现场景资源,采用 Animation 的各种方法来播放 3D 动画。 + +## 效果预览 + +| Index | Scene | Resource | Animation | +| :-----------------------------------------------: | :-----------------------------------------------: | :--------------------------------------------------: | :---------------------------------------------------: | +| | | | | + +**使用方法:** + +1. 在 Index 页面点击 ` BUilding and Managing ArkGraphics 3D Scenes` 按钮,跳转至 Scene 页面; + - 在 Scene 页面点击 `Model Loading and Display` 按钮,页面跳转至 Model 页面,显现 3D 头盔图像。点击 `Back` 按钮,返回至 Scene 页面; + - 在 Scene 页面点击 `Creating and Managing a Camera` 按钮,页面跳转至 Camera 页面,显现几何体图像。通过调节 `X-axis`、`Y-axis` 和 `Z-axis` 滑动条,即可分别修改相机的 X 轴,Y 轴和 Z 轴。点击 `Back` 按钮,返回至 Scene 页面; + - 在 Scene 页面点击 `Creating and Managing Light` 按钮,页面跳转至 Light 页面,显现几何体图像。通过调节 `Red`、`Green` 和 `Blue` 滑动条,即可分别调节光线的红、绿和蓝的颜色通道。点击 `Back` 按钮,返回至 Scene 页面; + - 在 Scene 页面点击 `Back` 按钮,返回至 `Index` 页面; +2. 在 Index 页面点击 `Creating and using ArkGraphics 3D Resources` 按钮,跳转至 Resource 页面。点击 `Replace with a blank material` 按钮,几何体图像的材质被空白材质替换。点击 `Replace with a Shader material` 按钮,几何体图像的材质被着色器材质替换。点击 `Replace with a Image material`,几何体材质被图像材质替换。点击 `Add to Environment` 按钮,给几何体图像添加背景。点击 `Back` 按钮,返回至 Index 页面; +3. 在 Index 页面点击 `Controlling and Managing ArkGraphics 3D Scene Animations` 按钮,跳转至 Animation 页面。点击 `start` 按钮,播放动画。点击 `pause` 按钮,中止动画。点击 `stop` 按钮,暂停动画。点击 `finish` 按钮,结束动画。点击 `restart` 按钮,重新播放动画。点击 `seek to 30% progress` 按钮,动画从 30% 进度开始播放。点击 `Back` 按钮,返回至 Index 页面; + +## 工程目录 + +``` +|--entry/src/main +│ |--ets // ets代码区 +│ │ |--entryability +│ │ │ |--EntryAbility.ts // 程序入口类 +| | | |--EntryAbility.ets +| | |--arkGraphic +│ │ │ |--animation.ets // 动画 +| | | |--resource.ets // 场景资源 +| | | |--scene.ets // 场景搭建 +| | |--scene +| | | |--camera.ets // 相机 +| | | |--init.ets // 模型加载 +| | | |--light.ets // 光线 +│ │ |--pages // 页面文件 +│ │ | |--Index.ets // 初始页面 +│ │ |--utils // 工具类 +| |--resources // 资源文件目录 +``` + +## 具体实现 + +1. 创建场景:一个 3D 场景通常由模型、相机和光源三个关键部分组成。其中先加载模型,再生成相机和光源。等 3D 图像加载完毕,可以使 Component3D 组件将渲染好的图像传递给用户。 + + - | 接口名 | 描述 | + | ------------------------------------------------------ | -------- | + | `Scene.load(): Promise` | 加载模型 | + | `SceneResourceFactory.createCamera(): Promise` | 创建相机 | + | `SceneResourceFactory.createLight(): Promise` | 创建光源 | + + - | SceneOption 参数 | 描述 | + | -------------------- | ------------------------------------------------------------ | + | scene: Scene | 3D模型资源文件或场景对象,默认值为undefined。
**说明:目前仅支持GLTF格式资源。** | + | modelType: ModelType | 3D场景显示合成方式。
**说明:**
一般开发者可以使用默认值而无需关心此项设置。 | + +2. 创建场景资源:3D 场景中主要有以下常见资源: + + - 材质(Material):材质是对场景中物体的光学物理性质的数学建模。在渲染计算的过程中,利用这些物理性质计算与光的相互作用,得到渲染的颜色。ArkGraphics 3D 提供的材质类型基于 PBR 渲染,支持用户参照 PBR 渲染材质类型创建材质资源,得到预期的渲染结果。 + + - 图片(Image): 图片本质上是上一个储存信息的二维内存块(buffer),用于储存 3D 渲染计算过程需要的相关信息,比如基础色、法线等等。ArkGraphics 3D 提供基于 PNG、JPG、KTX格式创建 Image 资源的能力,支持用户自定义需要的 Image 资源。 + + - 着色器(Shader): 着色器是 GPU 上可以执行的一段程序,可以控制 GPU 执行哪些并行计算操作。AGP 引擎提供的默认着色器实现了 PBR 渲染,开发者只需要指定对应的参数就可以完成不同的 PBR 渲染。ArkGraphics 3D 支持开发者创建自定义的着色器,开发者可以通过自定义着色器自定义渲染计算过程,完全控制渲染计算流程,比如控制某物体不受某光源的影响等。 + + - 环境(Environment): 环境是 3D 场景背景的一种描述,可以基于图片进行创建。通过将一张图片进行正方体或者球体的映射处理,将图片贴在正方体或者球体上,在 3D 场景中模拟真实的环境。ArkGraphics 3D 支持用户创建环境资源,定义 3D 场景的背景。 + + - | 接口名 | 描述 | + | ------------------------------------------------------------ | ---------- | + | `SceneResourceFactory.createMaterial(): Promise` | 创建材质 | + | `SceneResourceFactory.createImage(): Promise` | 创建图片 | + | `SceneResourceFactory.createShader(): Promise` | 创建着色器 | + | `SceneResourceFactory.createEnvironment(): Promise` | 创建环境 | + + - 尤其需要注意:在 ArkGraphics 3D 中需要将材质(Material)给与子网格(SubMesh)才能成功替换材质。 + + - | SubMesh 属性 | 说明 | + | ---------------------- | ------------------------ | + | name: string | 名称,没有特殊格式要求。 | + | **material: Material** | 材质。 | + | aabb: Aabb | 轴对齐边界盒。 | + +3. 创建动画:动画是3D场景中重要的资源类型,用于控制场景中各种元素的运动。 + + - 调用 `start` 方法控制动画开启; + + - 调用 `pause` 方法控制动画暂停; + + - 调用 `stop` 方法控制动画停止,并将动画状态设置为开头; + + - 调用`finish` 方法控制动画结束,并将动画状态设置为结尾; + + - 调用 `restart` 方法控制动画从头开始; + + - 调用 `seek` 方法控制动画设置到指定状态; + + - `onStarted` 方法在动画开始时执行传入的回调; + + - `onFinished` 方法在动画结束时执行传入的回调。 + +## 相关权限 + +不涉及。 + +## 依赖 + +不涉及。 + +## 约束与限制 + +1. 本示例仅支持标准系统上运行,支持设备:华为手机。 + +2. HarmonyOS系统:HarmonyOS 5.0.2 Release及以上。 + +3. DevEco Studio版本:DevEco Studio 5.0.2 Release及以上。 + +4. HarmonyOS SDK版本:HarmonyOS 5.0.2 Release及以上。 + +## 下载 + +如需单独下载本工程,执行如下命令: + +``` +git init +git config core.sparsecheckout true +echo code/DocsSample/graphic/Arkgraphics3D/ > .git/info/sparse-checkout +git remote add origin https://gitcode.com/openharmony/applications_app_samples.git +git pull origin master +``` \ No newline at end of file diff --git a/graphic/ArkGraphics3D/build-profile.json5 b/graphic/ArkGraphics3D/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..9beb54e97334358d1dc01477101aa0a0aa5e103d --- /dev/null +++ b/graphic/ArkGraphics3D/build-profile.json5 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "app": { + "products": [ + { + "name": "default", + "signingConfig": "default", + "compatibleSdkVersion": "5.0.2(14)", + "targetSdkVersion": "5.0.2(14)", + "runtimeOS": "HarmonyOS" + } + ], + "buildModeSet": [ + { + "name": "debug" + }, + { + "name": "release" + } + ], + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ], + } + ] +} \ No newline at end of file diff --git a/graphic/ArkGraphics3D/code-linter.json5 b/graphic/ArkGraphics3D/code-linter.json5 new file mode 100644 index 0000000000000000000000000000000000000000..28586467ee7a761c737d8654a73aed6fddbc3c71 --- /dev/null +++ b/graphic/ArkGraphics3D/code-linter.json5 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "files": [ + "**/*.ets" + ], + "ignore": [ + "**/src/ohosTest/**/*", + "**/src/test/**/*", + "**/src/mock/**/*", + "**/node_modules/**/*", + "**/oh_modules/**/*", + "**/build/**/*", + "**/.preview/**/*" + ], + "ruleSet": [ + "plugin:@performance/recommended", + "plugin:@typescript-eslint/recommended" + ], + "rules": { + } +} \ No newline at end of file diff --git a/graphic/ArkGraphics3D/entry/.gitignore b/graphic/ArkGraphics3D/entry/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5 --- /dev/null +++ b/graphic/ArkGraphics3D/entry/.gitignore @@ -0,0 +1,6 @@ +/node_modules +/oh_modules +/.preview +/build +/.cxx +/.test \ No newline at end of file diff --git a/graphic/ArkGraphics3D/entry/build-profile.json5 b/graphic/ArkGraphics3D/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..ad1d4aa712abae906cc8f085863ca3eea087e13a --- /dev/null +++ b/graphic/ArkGraphics3D/entry/build-profile.json5 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "apiType": "stageMode", + "buildOption": { + }, + "buildOptionSet": [ + { + "name": "release", + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": false, + "files": [ + "./obfuscation-rules.txt" + ] + } + } + } + }, + ], + "targets": [ + { + "name": "default" + }, + { + "name": "ohosTest", + } + ], +} \ No newline at end of file diff --git a/graphic/ArkGraphics3D/entry/hvigorfile.ts b/graphic/ArkGraphics3D/entry/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..e4f43d54667f8327c367c8096bd08bb8c75aff54 --- /dev/null +++ b/graphic/ArkGraphics3D/entry/hvigorfile.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { hapTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/graphic/ArkGraphics3D/entry/obfuscation-rules.txt b/graphic/ArkGraphics3D/entry/obfuscation-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..272efb6ca3f240859091bbbfc7c5802d52793b0b --- /dev/null +++ b/graphic/ArkGraphics3D/entry/obfuscation-rules.txt @@ -0,0 +1,23 @@ +# Define project specific obfuscation rules here. +# You can include the obfuscation configuration files in the current module's build-profile.json5. +# +# For more details, see +# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5 + +# Obfuscation options: +# -disable-obfuscation: disable all obfuscations +# -enable-property-obfuscation: obfuscate the property names +# -enable-toplevel-obfuscation: obfuscate the names in the global scope +# -compact: remove unnecessary blank spaces and all line feeds +# -remove-log: remove all console.* statements +# -print-namecache: print the name cache that contains the mapping from the old names to new names +# -apply-namecache: reuse the given cache file + +# Keep options: +# -keep-property-name: specifies property names that you want to keep +# -keep-global-name: specifies names that you want to keep in the global scope + +-enable-property-obfuscation +-enable-toplevel-obfuscation +-enable-filename-obfuscation +-enable-export-obfuscation \ No newline at end of file diff --git a/graphic/ArkGraphics3D/entry/oh-package.json5 b/graphic/ArkGraphics3D/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..c9cb6c8174858277c9b0d465a51547dcab16d5ff --- /dev/null +++ b/graphic/ArkGraphics3D/entry/oh-package.json5 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "name": "entry", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "", + "author": "", + "license": "", + "dependencies": {} +} + diff --git a/graphic/ArkGraphics3D/entry/src/main/ets/arkgraphic/animation.ets b/graphic/ArkGraphics3D/entry/src/main/ets/arkgraphic/animation.ets new file mode 100644 index 0000000000000000000000000000000000000000..f35cfaf6882202f41f210cda3af91826a10ea926 --- /dev/null +++ b/graphic/ArkGraphics3D/entry/src/main/ets/arkgraphic/animation.ets @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Animation, Camera, Scene, SceneResourceFactory } from '@kit.ArkGraphics3D'; +import { router } from '@kit.ArkUI'; +import logger from '../utils/Logger'; + +@Entry +@Component +struct sceneAnimation { + scene: Scene | null = null; + @State sceneOpt: SceneOptions | null = null; + cam: Camera | null = null; + anim: Animation | null = null; + @State animationCallbackInvoked: string = 'no invoked callback'; + + onPageShow(): void { + this.init(); + } + + onPageHide(): void { + if (this.scene) { + this.scene.destroy(); + } + this.scene = null; + this.sceneOpt = null; + this.cam = null; + this.anim = null; + } + + init(): void { + if (this.scene == null) { + // Loading scene. + // Switched from .gltf to .glb; same content, different format + Scene.load($rawfile('gltf/BrainStem/glTF/BrainStem.glb')) + .then(async (result: Scene) => { + this.scene = result; + let rf: SceneResourceFactory = this.scene.getResourceFactory(); + + // Get animation resources + this.anim = this.scene.animations[0]; + if (this.anim) { + this.anim.enabled = true; + // Register callback function + this.anim.onStarted(() => { + console.info('onStarted'); + this.animationCallbackInvoked = 'animation on start'; + }); + + this.anim.onFinished(() => { + console.info('onFinished'); + this.animationCallbackInvoked = 'animation on finish'; + }); + + logger.info('ready to create a new animation.'); + } else { + logger.error('No animation found in scene.'); + } + + // create a new camera. + this.cam = await rf.createCamera({ 'name': 'Camera' }); + // set the camera. + this.cam.enabled = true; + this.cam.position.z = 5; + + this.sceneOpt = { scene: this.scene, modelType: ModelType.SURFACE } as SceneOptions; + }).catch((err: string) => { + logger.error(err); + }); + } + } + + build() { + Row() { + Column() { + Column() { + if (this.sceneOpt) { + Component3D(this.sceneOpt) + .renderWidth('60%') + .renderHeight('60%'); + } else { + Text('Loading···'); + } + } + .height('30%'); + + Text('animation invoked callback:' + this.animationCallbackInvoked) + .fontSize(16) + .fontWeight(500); + + Button('start') + .id('start') + .margin({ top: 50, left: 6 }) + .width('30%') + .height(40) + .onClick(async () => { + if (!this.scene || !this.scene.animations[0]) { + return; + } + this.anim = this.scene.animations[0]; + this.anim.start(); + }); + + Button('pause') + .id('pause') + .margin({ top: 10, left: 6 }) + .width('30%') + .height(40) + .onClick(async () => { + if (!this.scene || !this.scene.animations[0]) { + return; + } + this.anim = this.scene.animations[0]; + this.anim.pause(); + }); + + Button('stop') + .id('stop') + .margin({ top: 10, left: 6 }) + .width('30%') + .height(40) + .onClick(async () => { + if (!this.scene || !this.scene.animations[0]) { + return; + } + this.anim = this.scene.animations[0]; + this.anim.stop(); + }); + + Button('finish') + .margin({ top: 10, left: 6 }) + .width('30%') + .height(40) + .onClick(async () => { + if (!this.scene || !this.scene.animations[0]) { + return; + } + this.anim = this.scene.animations[0]; + this.anim.finish(); + }) + .id('finish'); + + Button('restart') + .margin({ top: 10, left: 6 }) + .width('30%') + .height(40) + .onClick(async () => { + if (!this.scene || !this.scene.animations[0]) { + return; + } + this.anim = this.scene.animations[0]; + this.anim.restart(); + }) + .id('restart'); + + Button('seek to 30% progress') + .margin({ top: 10, left: 6 }) + .width('30%') + .height(40) + .onClick(async () => { + if (!this.scene || !this.scene.animations[0]) { + return; + } + this.anim = this.scene.animations[0]; + // seek to 30% + this.anim.seek(0.3); + }) + .id('seek'); + + Button('back') + .margin({ top: 10, left: 6 }) + .width('30%') + .height(40) + .onClick(() => { + router.back(); + }) + .id('back'); + } + .width('100%'); + } + .height('100%'); + } +} \ No newline at end of file diff --git a/graphic/ArkGraphics3D/entry/src/main/ets/arkgraphic/resource.ets b/graphic/ArkGraphics3D/entry/src/main/ets/arkgraphic/resource.ets new file mode 100644 index 0000000000000000000000000000000000000000..a7b6cd5e34f4cc4292e3f4e0cc8c50d98774b92a --- /dev/null +++ b/graphic/ArkGraphics3D/entry/src/main/ets/arkgraphic/resource.ets @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + Camera, + Environment, + Geometry, + Image, + Material, + MaterialType, + Scene, + SceneResourceFactory, + SceneResourceParameters, + Shader, + ShaderMaterial, + EnvironmentBackgroundType +} from '@kit.ArkGraphics3D'; +import { router } from '@kit.ArkUI'; +import logger from '../utils/Logger'; + +let globalScene: Scene | null = null; + +function createMaterialPromise(): Promise { + return new Promise((resolve, reject) => { + // Ensure the scene is loaded before accessing sceneFactory + if (globalScene) { + let sceneFactory: SceneResourceFactory = globalScene.getResourceFactory(); + let sceneMaterialParameter: SceneResourceParameters = { name: 'material' }; + // Create Material + let material: Promise = sceneFactory.createMaterial(sceneMaterialParameter, MaterialType.SHADER); + material.then(resolve) + .catch((err: string) => { + logger.error('Blank material create failed: ' + err); + reject(err); + }); + } else { + reject('Scene is not loaded yet.'); + } + }); +} + +function createShaderPromise(): Promise { + return new Promise((resolve, reject) => { + // Ensure the scene is loaded before accessing sceneFactory + if (globalScene) { + let sceneFactory: SceneResourceFactory = globalScene.getResourceFactory(); + + // Create a SceneResourceParameters object and use it to create a shader + let sceneResourceParameter: SceneResourceParameters = { + name: 'shaderResource', + uri: $rawfile('shaders/custom_shader/custom_material_sample.shader') + }; + let shader: Promise = sceneFactory.createShader(sceneResourceParameter); + shader.then(async (shaderEntity: Shader) => { + let sceneMaterialParameter: SceneResourceParameters = { name: 'material' }; + // Create material + let material: Promise = sceneFactory.createMaterial(sceneMaterialParameter, MaterialType.SHADER); + material.then(async (materialEntity: ShaderMaterial) => { + // Bind material with shader + materialEntity.colorShader = shaderEntity; + resolve(shaderEntity); + }).catch((err: string) => { + logger.error('Custom ShaderMaterial create failed: ' + err + '.'); + reject(err); + }); + }).catch((err: string) => { + logger.error('Shader load failed: ' + err + '.'); + reject(err); + }); + } else { + reject('Scene is not loaded yet.'); + } + }); +} + +function createImagePromise(): Promise { + return new Promise((resolve, reject) => { + // Ensure the scene is loaded before accessing sceneFactory + if (globalScene) { + let sceneFactory: SceneResourceFactory = globalScene.getResourceFactory(); + let sceneImageParameter: SceneResourceParameters = { name: 'image', uri: $rawfile('image/Cube_BaseColor.png') }; + // Create image + let image: Promise = sceneFactory.createImage(sceneImageParameter); + image.then(async (imageEntity: Image) => { + let sceneMaterialParameter: SceneResourceParameters = { name: 'material' }; + // Create material + let material: Promise = sceneFactory.createMaterial(sceneMaterialParameter, MaterialType.SHADER); + material.then(async (materialEntity: ShaderMaterial) => { + // Use the created image resource to set texture property + if (materialEntity && materialEntity.colorShader) { + materialEntity.colorShader.inputs['BASE_COLOR_Image'] = imageEntity; + } + resolve(imageEntity); + }).catch((err: string) => { + logger.error('Shader material of image texture create failed: ' + err + '.'); + reject(err); + }); + }).catch((err: string) => { + logger.error('ImageTexture load failed: ' + err + '.'); + reject(err); + }); + } else { + reject('Scene is not loaded yet.'); + } + }); +} + +function createEnvironmentPromise() : Promise { + return new Promise((resolve, reject) => { + // Ensure the scene is loaded before accessing sceneFactory + if (globalScene) { + let sceneFactory: SceneResourceFactory = globalScene.getResourceFactory(); + + // Manually load environment maps (.ktx/.jpg/.png etc.) + let sceneImageParameter: SceneResourceParameters = { name: 'image', uri: $rawfile('image/Cube_BaseColor.png') }; + let image: Promise = sceneFactory.createImage(sceneImageParameter); + image.then(async (imageEntity: Image) => { + // Create Environment + let sceneEnvironmentParameter: SceneResourceParameters = { name: 'env' }; + let env: Promise = sceneFactory.createEnvironment(sceneEnvironmentParameter); + env.then(async (envEntity: Environment) => { + envEntity.backgroundType = EnvironmentBackgroundType.BACKGROUND_EQUIRECTANGULAR; + envEntity.environmentImage = imageEntity; + // Set environment related properties + envEntity.indirectDiffuseFactor.x = 1; + envEntity.indirectDiffuseFactor.y = 1; + envEntity.indirectDiffuseFactor.z = 1; + envEntity.indirectDiffuseFactor.w = 1; + resolve(envEntity); + }).catch((err: string) => { + logger.error('Environment mapping material create failed: ' + err + '.'); + reject(err); + }); + }).catch((err: string) => { + logger.error('Image load failed: ' + err); + reject(err); + }); + } else { + reject('Scene is not loaded yet.'); + } + }); +} + +@Entry +@Component +struct materialPage { + scene: Scene | null = null; + @State sceneOpt: SceneOptions | null = null; + rf: SceneResourceFactory | null = null; + cam: Camera | null = null; + shader: Shader | null = null; + material: ShaderMaterial | null = null; + geom: Geometry | null = null; + image: Image | null = null; + originalMat: ShaderMaterial | null = null; + blankMat: Material | null = null; + shaderMat: ShaderMaterial | null = null; + imageMat: ShaderMaterial | null = null; + env: Environment | null = null; + + onPageShow(): void { + this.init(); + } + + onPageHide(): void { + if (this.scene) { + this.scene.destroy(); + } + this.scene = null; + this.sceneOpt = null; + this.rf = null; + this.cam = null; + this.shader = null; + this.material = null; + this.geom = null; + this.image = null; + this.originalMat = null; + this.blankMat = null; + this.shaderMat = null; + this.imageMat = null; + this.env = null; + globalScene = null; + } + + init(): void { + if (this.scene === null) { + // Switched from .gltf to .glb; same content, different format + Scene.load($rawfile('gltf/CubeWithFloor/glTF/AnimatedCube.glb')) + .then(async (result: Scene) => { + // Assign loaded scene to globalScene for unified resource creation + globalScene = result; + this.scene = result; + this.sceneOpt = { scene: this.scene, modelType: ModelType.SURFACE } as SceneOptions; + this.rf = this.scene.getResourceFactory(); + this.cam = await this.rf.createCamera({ 'name': 'Camera1' }); + this.cam.enabled = true; + this.cam.position.z = 5; + + // create a geometry + this.geom = this.scene.getNodeByPath('rootNode_/Unnamed Node 1/AnimatedCube') as Geometry; + + // record original material + this.originalMat = this.geom.mesh.subMeshes[0].material; + }) + .catch((error: string) => { + logger.error('init error: ' + error + '.'); + }); + } + } + + build() { + Row() { + Column() { + Column() { + if (this.sceneOpt) { + Component3D(this.sceneOpt); + } else { + Text('Loading···'); + } + } + .height('30%'); + + Button('Replace with a blank material') + .id('material') + .margin({ top: 80, left: 6 }) + .width('60%') + .height(40) + .onClick(async (): Promise => { + logger.info('Start to replace with a blank material'); + + if (!this.blankMat) { + this.blankMat = await createMaterialPromise(); + } + + if (!this.scene || !this.rf) { + return; + } + + this.geom = this.scene.getNodeByPath('rootNode_/Unnamed Node 1/AnimatedCube') as Geometry; + + this.geom.mesh.materialOverride = undefined; + if (this.blankMat) { + this.geom.mesh.subMeshes[0].material = this.blankMat; + } + + }); + + Button('Replace with a Shader material') + .id('shader') + .margin({ top: 20, left: 6 }) + .width('60%') + .height(40) + .onClick(async (): Promise => { + logger.info('Start to replace with a shader material'); + + if (!this.shader) { + this.shader = await createShaderPromise(); + } + + if (!this.scene || !this.rf) { + return; + } + + if (!this.shaderMat) { + let rf = this.scene.getResourceFactory(); + this.shaderMat = await rf.createMaterial({ name: 'shaderMat' }, MaterialType.SHADER); + } + + if (this.shader) { + this.shaderMat.colorShader = this.shader; + } + + this.geom = this.scene.getNodeByPath('rootNode_/Unnamed Node 1/AnimatedCube') as Geometry; + + this.geom.mesh.materialOverride = undefined; + + if (this.shaderMat) { + this.geom.mesh.subMeshes[0].material = this.shaderMat; + } + }) + + Button('Replace with a Image material') + .id('image') + .margin({ top: 20, left: 6 }) + .width('60%') + .height(40) + .onClick(async (): Promise => { + logger.info('Start to replace with a material of image'); + + if (!this.scene || !this.cam || !this.rf) { + return; + } + + // create shader + this.shader = await this.rf.createShader({ + name: 'shaderResource', + uri: $rawfile('shaders/custom_shader/custom_material_sample.shader') + }); + + // create imageMat + this.imageMat = await this.rf.createMaterial({ name: 'imageMat' }, MaterialType.SHADER) as ShaderMaterial; + + // bind between shader and imageMat + this.imageMat.colorShader = this.shader; + let createdImage = await createImagePromise(); + if (createdImage) { + this.imageMat.colorShader.inputs['BASE_COLOR_Image'] = createdImage; + } + + this.geom = this.scene.getNodeByPath('rootNode_/Unnamed Node 1/AnimatedCube') as Geometry; + + this.geom.mesh.materialOverride = undefined; + this.geom.mesh.subMeshes[0].material = this.imageMat; + }) + + Button('Add to Environment') + .id('env') + .margin({ top: 20, left: 6 }) + .width('60%') + .height(40) + .onClick(async (): Promise => { + logger.info('Start to replace with a material of image'); + + if (!this.scene || !this.cam) { + return; + } + + this.env = await createEnvironmentPromise(); + if (this.env) { + this.scene.environment = this.env; + } + }); + + Button('back') + .id('back') + .margin({ top: 20, left: 6 }) + .width('60%') + .height(40) + .onClick(() => { + router.back(); + }) + } + .width('100%'); + } + .height('100%'); + } +} \ No newline at end of file diff --git a/graphic/ArkGraphics3D/entry/src/main/ets/arkgraphic/scene.ets b/graphic/ArkGraphics3D/entry/src/main/ets/arkgraphic/scene.ets new file mode 100644 index 0000000000000000000000000000000000000000..005b2cdcbe73c8a6f64346ce56d41397e23493d6 --- /dev/null +++ b/graphic/ArkGraphics3D/entry/src/main/ets/arkgraphic/scene.ets @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { router } from '@kit.ArkUI'; +import logger from '../utils/Logger'; + +@Entry +@Component +struct scenePage { + build() { + Column({ space: 20 }) { + Button('Model Loading and Display') + .id('init') + .fontSize(16) + .fontWeight(500) + .margin({ top: 200, left: 6 }) + .onClick((): void => { + router.pushUrl({ + url: 'scene/init' + }, router.RouterMode.Standard, (err) => { + if (err) { + logger.error('Invoke replaceUrl failed, code is %{public}s, message is %{public}s'); + return; + } + logger.info('Invoke replaceUrl succeeded.'); + }); + }) + .width('80%') + .height(40); + + Button('Creating and Managing a Camera') + .id('camera') + .fontSize(16) + .fontWeight(500) + .margin({ top: 20, left: 6 }) + .onClick((): void => { + router.pushUrl({ + url: 'scene/camera' + }, router.RouterMode.Standard, (err) => { + if (err) { + logger.error('Invoke replaceUrl failed, code is %{public}s, message is %{public}s'); + return; + } + logger.info('Invoke replaceUrl succeeded.'); + }); + }) + .width('80%') + .height(40) + + Button('Creating and Managing Light') + .id('light') + .fontSize(16) + .fontWeight(500) + .margin({ top: 20, left: 6 }) + .onClick((): void => { + router.pushUrl({ + url: 'scene/light' + }, router.RouterMode.Standard, (err) => { + if (err) { + logger.error('Invoke replaceUrl failed, code is %{public}s, message is %{public}s'); + return; + } + logger.info('Invoke replaceUrl succeeded.'); + }); + }) + .width('80%') + .height(40) + + Button('back') + .id('back') + .fontSize(16) + .fontWeight(500) + .margin({ top: 20, left: 6 }) + .onClick(() => { + router.back(); + }) + .width('80%') + .height(40); + } + .width('100%'); + } +} \ No newline at end of file diff --git a/graphic/ArkGraphics3D/entry/src/main/ets/entryability/EntryAbility.ets b/graphic/ArkGraphics3D/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..edc2839f203ba057c186e19b0cbbbf80c8faa8b3 --- /dev/null +++ b/graphic/ArkGraphics3D/entry/src/main/ets/entryability/EntryAbility.ets @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { window } from '@kit.ArkUI'; + +export default class EntryAbility extends UIAbility { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { + this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); + } + + onDestroy(): void { + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); + } + + onWindowStageCreate(windowStage: window.WindowStage): void { + // Main window is created, set main page for this ability + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + + windowStage.loadContent('pages/Index', (err) => { + if (err.code) { + hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); + return; + } + hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.'); + }); + } + + onWindowStageDestroy(): void { + // Main window is destroyed, release UI related resources + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); + } + + onForeground(): void { + // Ability has brought to foreground + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); + } + + onBackground(): void { + // Ability has back to background + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); + } +} \ No newline at end of file diff --git a/graphic/ArkGraphics3D/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/graphic/ArkGraphics3D/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..b1e212947256c5533c7b06285a597c94f840a6e3 --- /dev/null +++ b/graphic/ArkGraphics3D/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit'; + +export default class EntryBackupAbility extends BackupExtensionAbility { + async onBackup() { + hilog.info(0x0000, 'testTag', 'onBackup ok'); + } + + async onRestore(bundleVersion: BundleVersion) { + hilog.info(0x0000, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); + } +} \ No newline at end of file diff --git a/graphic/ArkGraphics3D/entry/src/main/ets/pages/Index.ets b/graphic/ArkGraphics3D/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..c1ce392bc104598fd9058b7ec82a7dc1a9a166fa --- /dev/null +++ b/graphic/ArkGraphics3D/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { router } from '@kit.ArkUI'; +import logger from '../utils/Logger'; + +@Entry +@Component +struct Index { + build() { + Column({ space: 20 }) { + Button('Building and Managing ArkGraphics 3D Scenes') + .id('scene') + .fontWeight(500) + .margin({ top: 200, left: 6 }) + .width('80%') + .height(40) + .onClick((): void => { + router.pushUrl( + { url: 'arkgraphic/scene' }, + router.RouterMode.Standard, + (err) => { + if (err) { + logger.error('Invoke replaceUrl failed, code is ' + err.code + ', message is ' + err.message); + return; + } + logger.info('Invoke replaceUrl succeeded.'); + } + ); + }) + + Button('Creating and Using ArkGraphics 3D Resources') + .id('resource') + .fontWeight(500) + .margin({ top: 20, left: 6 }) + .width('80%') + .height(40) + .onClick((): void => { + router.pushUrl( + { url: 'arkgraphic/resource' }, + router.RouterMode.Standard, + (err) => { + if (err) { + logger.error('Invoke replaceUrl failed, code is ' + err.code + ', message is ' + err.message); + return; + } + logger.info('Invoke replaceUrl succeeded.'); + } + ); + }) + + Button('Controlling and Managing ArkGraphics 3D Scene Animations') + .id('animation') + .fontWeight(500) + .margin({ top: 20, left: 6 }) + .width('80%') + .height(40) + .onClick((): void => { + router.pushUrl({ url: 'arkgraphic/animation' }, + router.RouterMode.Single, + (err) => { + if (err) { + logger.error('Invoke replaceUrl failed, code is ' + err.code + ', message is ' + err.message); + return; + } + logger.info('Invoke replaceUrl succeeded.'); + } + ); + }) + } + .width('100%'); + } +} + diff --git a/graphic/ArkGraphics3D/entry/src/main/ets/scene/camera.ets b/graphic/ArkGraphics3D/entry/src/main/ets/scene/camera.ets new file mode 100644 index 0000000000000000000000000000000000000000..03cd0ffae1c5912b4cdc97576a8df06a7e0ec4a8 --- /dev/null +++ b/graphic/ArkGraphics3D/entry/src/main/ets/scene/camera.ets @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Camera, Scene, SceneNodeParameters, SceneResourceFactory } from '@kit.ArkGraphics3D'; +import { router } from '@kit.ArkUI'; +import logger from '../utils/Logger'; + +let globalScene: Scene | null = null; + +function createCameraPromise(): Promise { + return new Promise((resolve, reject) => { + // Switched from .gltf to .glb; same content, different format + let scene: Promise = Scene.load($rawfile('gltf/CubeWithFloor/glTF/AnimatedCube.glb')); + scene.then(async (result: Scene) => { + // Save loaded scene globally for reuse (e.g., in CameraPage) + globalScene = result; + let sceneFactory: SceneResourceFactory = result.getResourceFactory(); + let sceneCameraParameter: SceneNodeParameters = { name: 'camera' }; + // Create a Camera. + let camera: Promise = sceneFactory.createCamera(sceneCameraParameter); + camera.then(async (cameraEntity: Camera) => { + // Enable the camera node. + cameraEntity.enabled = true; + + // Set the camera position. + cameraEntity.position.z = 5; + + // Set the FoV. + cameraEntity.fov = 60 * Math.PI / 180; + + // Set other camera parameters. + // ... + resolve(cameraEntity); + }).catch((error: string) => { + logger.error('Camera create failed: ' + error + '.'); + reject(error); + }); + }).catch((error: string) => { + logger.error('Scene load failed: ' + error); + reject(error); + }); + }); +} + +@Entry +@Component +struct CameraPage { + scene: Scene | null = null; + @State sceneOpt: SceneOptions | null = null; + camera: Camera | null = null; + @State positionX: number = 0; + @State positionY: number = 0; + @State positionZ: number = 5; + + onPageShow(): void { + this.init(); + } + + onPageHide(): void { + if (this.scene) { + this.scene.destroy(); + } + this.scene = null; + this.sceneOpt = null; + this.camera = null; + globalScene = null; + } + + async init(): Promise { + this.camera = await createCameraPromise(); + if (globalScene && this.camera) { + this.scene = globalScene; + this.positionX = this.camera.position.x; + this.positionY = this.camera.position.y; + this.positionZ = this.camera.position.z; + this.sceneOpt = { scene: globalScene, modelType: ModelType.SURFACE } as SceneOptions; + } + } + + build() { + Row() { + Column() { + Column() { + if (this.sceneOpt) { + // Use Component3D to display the 3D scenario. + Component3D(this.sceneOpt); + } else { + Text('Loading···'); + } + } + + Column() { + Text('X-axis: ' + this.positionX.toFixed(1)).fontSize(12); + Slider({ + value: this.positionX, + min: 0, + max: 5, + step: 0.1, + style: SliderStyle.OutSet + }) + .id('xAxis') + .showTips(false) + .onChange((value: number, mode: SliderChangeMode) => { + this.positionX = value; + if (mode === SliderChangeMode.End) { + if (!this.scene || !this.camera) { + return; + } + this.camera.position.x = value; + } + }) + .width('100%') + } + .width('100%') + + Column() { + Text('Y-axis: ' + this.positionY.toFixed(1)).fontSize(12); + Slider({ + value: this.positionY, + min: 0, + max: 5, + step: 0.1, + style: SliderStyle.OutSet + }) + .showTips(false) + .onChange((value: number, mode: SliderChangeMode) => { + this.positionY = value; + if (mode === SliderChangeMode.End) { + if (!this.scene || !this.camera) { + return; + } + this.camera.position.y = value; + } + }) + .width('100%') + } + .width('100%') + + Column() { + Text('Z-axis: ' + this.positionZ.toFixed(1)).fontSize(12) + Slider({ + value: this.positionZ, + min: 5, + max: 10, + step: 0.1, + style: SliderStyle.OutSet + }) + .showTips(false) + .onChange((value: number, mode: SliderChangeMode) => { + this.positionZ = value; + if (mode === SliderChangeMode.End) { + if (!this.scene || !this.camera) { + return; + } + this.camera.position.z = value; + } + }) + .width('100%') + } + .width('100%') + + Button('back') + .id('back') + .fontSize(16) + .fontWeight(500) + .margin({ top: 20, left: 6 }) + .onClick(() => { + router.back(); + }) + .width('80%') + .height(40) + } + }.height('60%') + } +} diff --git a/graphic/ArkGraphics3D/entry/src/main/ets/scene/init.ets b/graphic/ArkGraphics3D/entry/src/main/ets/scene/init.ets new file mode 100644 index 0000000000000000000000000000000000000000..1f80003f476516547818cbdc94338ec838739cb4 --- /dev/null +++ b/graphic/ArkGraphics3D/entry/src/main/ets/scene/init.ets @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Camera, Scene, SceneResourceFactory } from '@kit.ArkGraphics3D'; +import { router } from '@kit.ArkUI'; +import logger from '../utils/Logger'; + +@Entry +@Component +struct Model { + scene: Scene | null = null; + @State sceneOpt: SceneOptions | null = null; + cam: Camera | null = null; + + onPageShow(): void { + this.init(); + } + + onPageHide(): void { + if (this.scene) { + this.scene.destroy(); + } + this.scene = null; + this.sceneOpt = null; + this.cam = null; + } + + init(): void { + if (this.scene == null) { + // Load the model and place the gltf file in the related path. Use the actual path during loading. + // Switched from .gltf to .glb; same content, different format + Scene.load($rawfile('gltf/DamagedHelmet/glTF/DamagedHelmet.glb')) + .then(async (result: Scene) => { + this.scene = result; + let rf: SceneResourceFactory = this.scene.getResourceFactory(); + // Create a Camera. + this.cam = await rf.createCamera({ 'name': 'Camera' }); + // Set proper camera parameters. + this.cam.enabled = true; + this.cam.position.z = 5; + + this.sceneOpt = { scene: this.scene, modelType: ModelType.SURFACE } as SceneOptions; + logger.info('initialization completely.'); + }) + .catch((reason: string) => { + console.log(reason); + }); + } + } + + build() { + Row() { + Column() { + if (this.sceneOpt) { + // Use Component3D to display the 3D scenario. + Component3D(this.sceneOpt); + } else { + Text('Loading···'); + } + + Button('back') + .id('back') + .fontSize(16) + .fontWeight(500) + .margin({ top: 20, left: 6 }) + .onClick(() => { + router.back(); + }) + .width('80%') + .height(40) + }.width('100%') + }.height('60%') + } +} diff --git a/graphic/ArkGraphics3D/entry/src/main/ets/scene/light.ets b/graphic/ArkGraphics3D/entry/src/main/ets/scene/light.ets new file mode 100644 index 0000000000000000000000000000000000000000..0a7482a83645a352f1b1af955fc7cd680ec93437 --- /dev/null +++ b/graphic/ArkGraphics3D/entry/src/main/ets/scene/light.ets @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Camera, Light, LightType, Scene, SceneNodeParameters, SceneResourceFactory } from '@kit.ArkGraphics3D'; +import { router } from '@kit.ArkUI'; +import logger from '../utils/Logger'; + +let globalScene: Scene | null = null; + +function createLightPromise(): Promise { + return new Promise((resolve, reject) => { + // Switched from .gltf to .glb; same content, different format + let scene: Promise = Scene.load($rawfile('gltf/CubeWithFloor/glTF/AnimatedCube.glb')); + scene.then(async (result: Scene) => { + // Save loaded scene globally for reuse (e.g., in LightPage) + globalScene = result; + let sceneFactory: SceneResourceFactory = result.getResourceFactory(); + let lightParameter: SceneNodeParameters = { name: 'light' }; + // Create directional light. + let light: Promise = sceneFactory.createLight(lightParameter, LightType.DIRECTIONAL); + light.then(async (lightEntity: Light) => { + // Set the color of the directional light. + lightEntity.color = { r: 0.8, g: 0.1, b: 0.2, a: 1.0 }; + + // Set other light parameters. + // ... + resolve(lightEntity); + }).catch((err: string) => { + logger.error('Light create failed: ' + err + '.'); + reject(err); + }); + }).catch((error: string) => { + logger.error('Scene load failed: ' + error); + reject(error); + }); + }); +} + +@Entry +@Component +struct LightPage { + scene: Scene | null = null; + @State sceneOpt: SceneOptions | null = null; + cam: Camera | null = null; + light: Light | null = null; + rf: SceneResourceFactory | null = null; + @State red: number = 0; + @State green: number = 0; + @State blue: number = 0; + + onPageShow(): void { + this.init(); + } + + onPageHide(): void { + if (this.scene) { + this.scene.destroy(); + } + this.scene = null; + this.sceneOpt = null; + this.cam = null; + this.light = null; + this.rf = null; + globalScene = null; + } + + async init(): Promise { + this.light = await createLightPromise(); + if (globalScene && this.light) { + this.scene = globalScene; + this.sceneOpt = { scene: globalScene, modelType: ModelType.SURFACE } as SceneOptions; + this.rf = this.scene.getResourceFactory(); + this.cam = await this.rf.createCamera({ 'name': 'Camera1' }); + this.cam.enabled = true; + this.cam.position.z = 5; + // Initialize color value + this.red = this.light.color.r; + this.green = this.light.color.g; + this.blue = this.light.color.b; + } + } + + build() { + Row() { + Column() { + if (this.sceneOpt) { + Component3D(this.sceneOpt); + } else { + Text('Loading···'); + } + + Column() { + Text('Red: ' + this.red.toFixed(1)).fontSize(12); + Slider({ + value: this.red, + min: 0, + max: 1, + step: 0.01, + style: SliderStyle.OutSet + }) + .showTips(false) + .onChange((value: number, mode: SliderChangeMode) => { + this.red = value; + if (mode === SliderChangeMode.End) { + if (!this.scene || !this.light) { + return; + } + this.light.color = { + r: this.red, + g: this.green, + b: this.blue, + a: 1.0 + } + } + }) + .width('100%') + } + .width('100%') + + Column() { + Text('Green: ' + this.green.toFixed(1)).fontSize(12) + Slider({ + value: this.green, + min: 0, + max: 1, + step: 0.01, + style: SliderStyle.OutSet + }) + .showTips(false) + .onChange((value: number, mode: SliderChangeMode) => { + this.green = value; + if (mode === SliderChangeMode.End) { + if (!this.scene || !this.light) { + return; + } + + this.light.color = { + r: this.red, + g: this.green, + b: this.blue, + a: 1.0 + } + } + }) + .width('100%') + } + .width('100%') + + Column() { + Text('Blue: ' + this.blue.toFixed(1)).fontSize(12) + Slider({ + value: this.blue, + min: 0, + max: 1, + step: 0.01, + style: SliderStyle.OutSet + }) + .showTips(false) + .onChange((value: number, mode: SliderChangeMode) => { + this.blue = value; + if (mode === SliderChangeMode.End) { + if (!this.scene || !this.light) { + return; + } + + this.light.color = { + r: this.red, + g: this.green, + b: this.blue, + a: 1.0 + } + } + }) + .width('100%') + } + .width('100%') + + Button('back') + .id('back') + .fontSize(16) + .fontWeight(500) + .margin({ top: 20, left: 6 }) + .onClick(() => { + router.back(); + }) + .width('80%') + .height(40) + } + .width('100%') + } + .height('60%') + } +} diff --git a/graphic/ArkGraphics3D/entry/src/main/ets/utils/Logger.ets b/graphic/ArkGraphics3D/entry/src/main/ets/utils/Logger.ets new file mode 100644 index 0000000000000000000000000000000000000000..6ae0f3425a43a6501455d3a6020793ed1168b177 --- /dev/null +++ b/graphic/ArkGraphics3D/entry/src/main/ets/utils/Logger.ets @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { hilog } from '@kit.PerformanceAnalysisKit'; + +class Logger { + private domain: number; + private prefix: string; + private format: string = '%{public}s'; + + constructor(prefix: string) { + this.prefix = prefix; + this.domain = 0xFF00; + } + + debug(...args: string[]) { + hilog.debug(this.domain, this.prefix, this.format, args); + } + + info(...args: string[]) { + hilog.info(this.domain, this.prefix, this.format, args); + } + + warn(...args: string[]) { + hilog.warn(this.domain, this.prefix, this.format, args); + } + + error(...args: string[]) { + hilog.error(this.domain, this.prefix, this.format, args); + } +} + +export default new Logger('[Sample_ArkGraphics3D]'); \ No newline at end of file diff --git a/graphic/ArkGraphics3D/entry/src/main/module.json5 b/graphic/ArkGraphics3D/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..4144486d1af4c03b0d767cce1cda86fc0d697f91 --- /dev/null +++ b/graphic/ArkGraphics3D/entry/src/main/module.json5 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "module": { + "name": "entry", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "EntryAbility", + "deviceTypes": [ + "default", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "abilities": [ + { + "name": "EntryAbility", + "srcEntry": "./ets/entryability/EntryAbility.ets", + "description": "$string:EntryAbility_desc", + "icon": "$media:layered_image", + "label": "$string:EntryAbility_label", + "startWindowIcon": "$media:startIcon", + "startWindowBackground": "$color:start_window_background", + "exported": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ], + "extensionAbilities": [ + { + "name": "EntryBackupAbility", + "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets", + "type": "backup", + "exported": false, + "metadata": [ + { + "name": "ohos.extension.backup", + "resource": "$profile:backup_config" + } + ] + } + ] + } +} \ No newline at end of file diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/base/element/color.json b/graphic/ArkGraphics3D/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02 --- /dev/null +++ b/graphic/ArkGraphics3D/entry/src/main/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + } + ] +} \ No newline at end of file diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/base/element/string.json b/graphic/ArkGraphics3D/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..22d70eec8727bed9ab34886858eb3fb30c773fd5 --- /dev/null +++ b/graphic/ArkGraphics3D/entry/src/main/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "ArkGraphics3D" + } + ] +} \ No newline at end of file diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/base/media/background.png b/graphic/ArkGraphics3D/entry/src/main/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..f939c9fa8cc8914832e602198745f592a0dfa34d Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/base/media/background.png differ diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/base/media/foreground.png b/graphic/ArkGraphics3D/entry/src/main/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..4483ddad1f079e1089d685bd204ee1cfe1d01902 Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/base/media/foreground.png differ diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/base/media/layered_image.json b/graphic/ArkGraphics3D/entry/src/main/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/graphic/ArkGraphics3D/entry/src/main/resources/base/media/layered_image.json @@ -0,0 +1,7 @@ +{ + "layered-image": + { + "background" : "$media:background", + "foreground" : "$media:foreground" + } +} \ No newline at end of file diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/base/media/startIcon.png b/graphic/ArkGraphics3D/entry/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/base/media/startIcon.png differ diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/base/profile/backup_config.json b/graphic/ArkGraphics3D/entry/src/main/resources/base/profile/backup_config.json new file mode 100644 index 0000000000000000000000000000000000000000..78f40ae7c494d71e2482278f359ec790ca73471a --- /dev/null +++ b/graphic/ArkGraphics3D/entry/src/main/resources/base/profile/backup_config.json @@ -0,0 +1,3 @@ +{ + "allowToBackupRestore": true +} \ No newline at end of file diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/base/profile/main_pages.json b/graphic/ArkGraphics3D/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..4158b4f8ebadd84491400b286ba8b526df17a5f6 --- /dev/null +++ b/graphic/ArkGraphics3D/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,11 @@ +{ + "src": [ + "pages/Index", + "arkgraphic/scene", + "arkgraphic/resource", + "arkgraphic/animation", + "scene/init", + "scene/camera", + "scene/light" + ] +} diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/dark/element/color.json b/graphic/ArkGraphics3D/entry/src/main/resources/dark/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..79b11c2747aec33e710fd3a7b2b3c94dd9965499 --- /dev/null +++ b/graphic/ArkGraphics3D/entry/src/main/resources/dark/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#000000" + } + ] +} \ No newline at end of file diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/KTX/quarry_02_2k_radiance.ktx b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/KTX/quarry_02_2k_radiance.ktx new file mode 100644 index 0000000000000000000000000000000000000000..250942b8b36600420116f48a6c85def90efaf0a4 Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/KTX/quarry_02_2k_radiance.ktx differ diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Binary/BrainStem.glb b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Binary/BrainStem.glb new file mode 100644 index 0000000000000000000000000000000000000000..88fe89569bedb74926a35b460b8b29ff8b609d01 Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Binary/BrainStem.glb differ diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Draco/BrainStem.glb b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Draco/BrainStem.glb new file mode 100644 index 0000000000000000000000000000000000000000..c72536ca3be25984c17c30ef662c3983b0c9ba05 Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Draco/BrainStem.glb differ diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Draco/BrainStem0.bin b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Draco/BrainStem0.bin new file mode 100644 index 0000000000000000000000000000000000000000..96c3c805156e57c05b37a10db54a5709f9cf47fd Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Draco/BrainStem0.bin differ diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Embedded/BrainStem.glb b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Embedded/BrainStem.glb new file mode 100644 index 0000000000000000000000000000000000000000..fb2fbe95ad93346218092f02a3b725d697db8504 Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Embedded/BrainStem.glb differ diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Meshopt/BrainStem.bin b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Meshopt/BrainStem.bin new file mode 100644 index 0000000000000000000000000000000000000000..5f85d43cc9a5ff51a05650692a22024c9379390c Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Meshopt/BrainStem.bin differ diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Meshopt/BrainStem.glb b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Meshopt/BrainStem.glb new file mode 100644 index 0000000000000000000000000000000000000000..c600aeb2fa4df27b6537fe3960d589d82a290a36 Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Meshopt/BrainStem.glb differ diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF/BrainStem.glb b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF/BrainStem.glb new file mode 100644 index 0000000000000000000000000000000000000000..fb2fbe95ad93346218092f02a3b725d697db8504 Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF/BrainStem.glb differ diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF/BrainStem0.bin b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF/BrainStem0.bin new file mode 100644 index 0000000000000000000000000000000000000000..a684a8f3ea96953630e64babe15c93c75c3035cf Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF/BrainStem0.bin differ diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/CubeWithFloor/glTF/AnimatedCube.bin b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/CubeWithFloor/glTF/AnimatedCube.bin new file mode 100644 index 0000000000000000000000000000000000000000..72f7d2d52ad79f8cb5a71f1640e51bd91ddd4a08 Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/CubeWithFloor/glTF/AnimatedCube.bin differ diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/CubeWithFloor/glTF/AnimatedCube.glb b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/CubeWithFloor/glTF/AnimatedCube.glb new file mode 100644 index 0000000000000000000000000000000000000000..ff0f71c3156997419e45c91bfe9bc75c23318596 Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/CubeWithFloor/glTF/AnimatedCube.glb differ diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/CubeWithFloor/glTF/AnimatedCube_BaseColor.png b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/CubeWithFloor/glTF/AnimatedCube_BaseColor.png new file mode 100644 index 0000000000000000000000000000000000000000..5e5cb2068fa85aec944bd75c981fa6420c1cea87 Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/CubeWithFloor/glTF/AnimatedCube_BaseColor.png differ diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/CubeWithFloor/glTF/AnimatedCube_MetallicRoughness.png b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/CubeWithFloor/glTF/AnimatedCube_MetallicRoughness.png new file mode 100644 index 0000000000000000000000000000000000000000..efd20260218a92d097c4005a8167dcdf08180664 Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/CubeWithFloor/glTF/AnimatedCube_MetallicRoughness.png differ diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/DamagedHelmet.bin b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/DamagedHelmet.bin new file mode 100644 index 0000000000000000000000000000000000000000..662eacc1da580cdcbc08572d5535b3ed484b1579 Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/DamagedHelmet.bin differ diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/DamagedHelmet.glb b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/DamagedHelmet.glb new file mode 100644 index 0000000000000000000000000000000000000000..2cee76d76a752c92458a8a8294ff3658fdc9d6c7 Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/DamagedHelmet.glb differ diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_AO.jpg b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_AO.jpg new file mode 100644 index 0000000000000000000000000000000000000000..419f62840ad0eff2bc2482ada01e55ed02fb87e3 Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_AO.jpg differ diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_albedo.jpg b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_albedo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..15d64855c732130451cfd511d61ffb07b2d97e1f Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_albedo.jpg differ diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_emissive.jpg b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_emissive.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2de59e897bbfb1a664053bc5ba3cab0cd21accf0 Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_emissive.jpg differ diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_metalRoughness.jpg b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_metalRoughness.jpg new file mode 100644 index 0000000000000000000000000000000000000000..04874cb6e9aba270a2c5d3b41f487c0dcc7b481d Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_metalRoughness.jpg differ diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_normal.jpg b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_normal.jpg new file mode 100644 index 0000000000000000000000000000000000000000..94ca20a2d131d5aa70f93f040707a80987cc4904 Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_normal.jpg differ diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/image/Cube_BaseColor.png b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/image/Cube_BaseColor.png new file mode 100644 index 0000000000000000000000000000000000000000..5e5cb2068fa85aec944bd75c981fa6420c1cea87 Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/image/Cube_BaseColor.png differ diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag new file mode 100644 index 0000000000000000000000000000000000000000..97d939730b439961cb3dd709c063c29eaddda15f --- /dev/null +++ b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#version 460 core +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +// includes + +#include "render/shaders/common/render_compatibility_common.h" + +#include "render/shaders/common/render_color_conversion_common.h" +#include "render/shaders/common/render_post_process_common.h" +#include "render/shaders/common/render_tonemap_common.h" + +#include "3d/shaders/common/3d_dm_structures_common.h" + +// sets and specializations + +#include "3d/shaders/common/3d_dm_frag_layout_common.h" +#include "3d/shaders/common/3d_dm_lighting_common.h" + +// custom user set +struct MyMaterialSampleStruct { + vec4 vec_1; + float time; + bool dof; + bool motionBlur; +}; +layout(set = 1, binding = 4, std140) uniform uMyBuffer0 +{ + MyMaterialSampleStruct uMyData; +}; + + +#define CORE3D_DM_FW_FRAG_INPUT 1 +#include "3d/shaders/common/3d_dm_inout_common.h" +#include "3d/shaders/common/3d_dm_inplace_sampling_common.h" +#include "3d/shaders/common/3d_dm_inplace_post_process.h" + +// in / out + +layout(location = 0) out vec4 outColor; + + +// Corrected normal vector. + +#define hash(x) fract(sin(x)*5723.2622) +const float pi = acos(-1.); +const float pi2 = acos(-1.)*2.; + +// If you have a strong PC, make it bigger. +const int nS = 2; // Number of samples. + +const float w = .03; // Width of the fiber. + +// Rotation matrix in two dimensions. +mat2 rot(float a) { + float s = sin(a), c = cos(a); + return mat2(c, s, -s, c); +} + +float hash12(vec2 p) { + float v = dot(p, vec2(1.8672, 1.3723)); + return hash(v); +} + +// 1D perlin noise. +float perlin1d(float x) { + float i = floor(x); + float f = fract(x); + float u = f*f*(3.-2.*f); + + return mix(f*(hash(i)*2.-1.), (f-1.)*(hash(i+1.)*2.-1.), u); // from -0.5 to 0.5 +} + +float fiberShape(float x, float time) { + float s = .03; + float curve = smoothstep(.25-s, .25+s, abs(fract(time*.11) - .5)); + return perlin1d(x) * (1. - w * 2.) * curve; +} + +// Smooth stair-like noise. +float stepNoise(float x, float n) { + float i = floor(x); + float s = .1; + float u = smoothstep(.5-s, .5+s, fract(x)); + + return mix(floor(hash(i)*n), floor(hash(i+1.)*n), u); +} + + + +void main(void) +{ + vec2 uv = (inUv.xy-vec2(0.5,0.5))*2.0f; + vec2 fragCoord = inUv.xy; + + vec3 col = vec3(0); + + vec3 ac = vec3(0); + + + for(float j=0.; j 0. && abs(p.x) < w) { + q = p; + hit = true; + break; + } + } + + if(hit) { // Ray hit a fiber. + vec3 add = vec3(1); + + vec3 lightDir = normalize(vec3(-5, 2, -2)); + vec3 normal = normalize(vec3(q.x, sqrt(w*w - q.x*q.x), 0)); + + float e = 1e-4; + float grad = (fiberShape(q.y + e, time) - fiberShape(q.y - e, time)) / (e*2.); + float a = atan(grad); + normal.xz *= rot(-id.x*2. + a); + + // Shading + float diff = max(dot(normal, lightDir), 0.); + float spec = pow(max(dot(reflect(lightDir, normal), rds), 0.), 20.); + float m = .5; + float lp = 3.; + add *= diff * (1.-m) * lp + spec * m * lp + .2; + + // Streaming light. + q.y = fract(q.y * .03 - time * .2) - .5; + add += smoothstep(.01, 0., abs(q.y)) * 3.; + + // Flickering light. + float T = time + hash12(id); + add += step(hash12(id*1.1 + floor(T)), .05) * step(fract(T*3.), .8) * 3.; + + add *= exp(-t*t*.1 -id.x*id.x*.001); + + ac += add; + } + } + + col += ac / float(nS); + + float a= uMyData.vec_1.w; + + col*=uMyData.vec_1.xyz; + + col = pow(col, vec3(1./2.2)); // Gamma correction. + + CORE_RELAXEDP vec4 baseColor = GetBaseColorSample(inUv); + + col*=baseColor.xyz; + + outColor = vec4(col,a); +} + diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..534bdb3ca4c0ed704d84f6d2d27162e5d2fc4ac6 Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv differ diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv.gl b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv.gl new file mode 100644 index 0000000000000000000000000000000000000000..3a703d3a60b377450fb36391e722d743459d2c28 --- /dev/null +++ b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv.gl @@ -0,0 +1,234 @@ +#version 450 + +struct DefaultMaterialSingleMaterialStruct +{ + vec4 factors[15]; + uvec4 indices; +}; + +struct DefaultMaterialMaterialStruct +{ + DefaultMaterialSingleMaterialStruct material[64]; +}; + +#ifndef SPIRV_CROSS_CONSTANT_ID_1 +#define SPIRV_CROSS_CONSTANT_ID_1 0u +#endif +const uint CORE_MATERIAL_FLAGS = SPIRV_CROSS_CONSTANT_ID_1; +const uint _162 = (CORE_MATERIAL_FLAGS & 8u); +const bool _163 = (_162 == 8u); + +struct DefaultMaterialTransformSingleMaterialStruct +{ + uvec4 _packed[15]; + uvec4 indices; +}; + +struct DefaultMaterialTransformMaterialStruct +{ + DefaultMaterialTransformSingleMaterialStruct material[64]; +}; + +struct MyMaterialSampleStruct +{ + vec4 vec_1; + float time; + uint dof; + uint motionBlur; +}; + +layout(std140) uniform s1_b2 +{ + DefaultMaterialMaterialStruct uMaterialData; +} _s1_b2; + +layout(std140) uniform s1_b3 +{ + DefaultMaterialTransformMaterialStruct uMaterialTransformData; +} _s1_b3; + +layout(std140) uniform s1_b4 +{ + MyMaterialSampleStruct uMyData; +} _s1_b4; + +uniform sampler2D s2_b0; + +layout(location = 4) in vec4 inUv; +layout(location = 0) out vec4 outColor; + +vec2 _1444; +float _1477; +float _1562; + +void main() +{ + vec2 _336 = (inUv.xy - vec2(0.5)) * 2.0; + vec3 _1434; + vec2 _1462; + vec2 _1470; + _1470 = _1444; + _1462 = _1444; + _1434 = vec3(0.0); + vec2 _1466; + float _1472; + vec3 _1490; + vec2 _1516; + float _1476; + for (float _1433 = 0.0; _1433 < 2.0; _1476 = _1472, _1470 = _1466, _1462 = _1516, _1434 = _1490, _1433 += 1.0) + { + vec2 _372 = (inUv.xy + vec2(fract(_s1_b4.uMyData.time) * 500.0)) + vec2(_1433 * 31.3528308868408203125); + float _1448; + if (_s1_b4.uMyData.motionBlur != 0u) + { + _1448 = fma(fract(sin(dot(_372, vec2(1.86720001697540283203125, 1.37230002880096435546875))) * 5723.26220703125), 0.0500000007450580596923828125, _s1_b4.uMyData.time); + } + else + { + _1448 = _s1_b4.uMyData.time; + } + float _389 = -_1448; + float _912 = floor(_389); + vec3 _1368 = vec3(0.0, 1.0, _389); + _1368.x = (mix(floor(fract(sin(_912) * 5723.26220703125) * 5.0), floor(fract(sin(_912 + 1.0) * 5723.26220703125) * 5.0), smoothstep(0.4000000059604644775390625, 0.60000002384185791015625, fract(_389))) - 2.0) * 0.5; + float _411 = (-500.0) - _1448; + float _943 = floor(_411); + vec3 _1372 = _1368; + _1372.y = fma(mix(floor(fract(sin(_943) * 5723.26220703125) * 5.0), floor(fract(sin(_943 + 1.0) * 5723.26220703125) * 5.0), smoothstep(0.4000000059604644775390625, 0.60000002384185791015625, fract(_411))), 0.5, 1.0); + vec3 _423 = vec3(0.0, -0.5, (-0.5) - _1448) - _1372; + vec3 _424 = normalize(_423); + vec3 _429 = normalize(cross(_424, vec3(0.0, 1.0, 0.0))); + float _440 = (-1000.0) - _1448; + float _974 = floor(_440); + float _475 = length(_423); + vec3 _1449; + if (_s1_b4.uMyData.dof != 0u) + { + float _504 = fract(sin(dot(_372 * 1.2000000476837158203125, vec2(1.86720001697540283203125, 1.37230002880096435546875))) * 5723.26220703125) * 6.283185482025146484375; + vec2 _518 = _1372.xy + (((vec2(cos(_504), sin(_504)) * sqrt(fract(sin(dot(_372 * 1.10000002384185791015625, vec2(1.86720001697540283203125, 1.37230002880096435546875))) * 5723.26220703125))) * _475) * 0.02500000037252902984619140625); + vec3 _1377 = _1372; + _1377.x = _518.x; + vec3 _1379 = _1377; + _1379.y = _518.y; + _1449 = _1379; + } + else + { + _1449 = _1372; + } + vec3 _527 = normalize((_1372 + (normalize(((_429 * _336.x) + (normalize(cross(_429, _424)) * _336.y)) + (_424 / vec3(tan(fma(fma(mix(floor(fract(sin(_974) * 5723.26220703125) * 2.0), floor(fract(sin(_974 + 1.0) * 5723.26220703125) * 2.0), smoothstep(0.4000000059604644775390625, 0.60000002384185791015625, fract(_440))), 2.0, -1.0), 20.0, 40.0) * 0.00872664712369441986083984375)))) * _475)) - _1449); + vec2 _1467; + _1467 = _1470; + float _548; + vec2 _577; + bool _1455; + vec2 _1458; + float _1450 = 0.0; + float _1473 = _1476; + for (;;) + { + if (_1450 < 50.0) + { + _548 = (-fma(_1450, 0.0500000007450580596923828125, _1449.y)) / _527.y; + vec2 _556 = _1449.xz + (_527.xz * _548); + vec2 _1384 = _556; + _1384.x = fma(fract(sin(_1450) * 5723.26220703125), 500.0, _556.x); + float _567 = _1450 * 2.0; + float _1023 = sin(_567); + float _1025 = cos(_567); + vec2 _571 = _1384 * mat2(vec2(_1025, _1023), vec2(-_1023, _1025)); + float _575 = _571.x; + _577 = vec2(_1450, floor(_575)); + float _581 = fract(_575) - 0.5; + float _589 = fma(fract(sin(dot(_577, vec2(1.86720001697540283203125, 1.37230002880096435546875))) * 5723.26220703125), 500.0, _571.y); + float _1069 = floor(_589); + float _1071 = fract(_589); + float _599 = fma(mix(_1071 * fma(fract(sin(_1069) * 5723.26220703125), 2.0, -1.0), (_1071 - 1.0) * fma(fract(sin(_1069 + 1.0) * 5723.26220703125), 2.0, -1.0), (_1071 * _1071) * fma(-2.0, _1071, 3.0)) * (-0.939999997615814208984375), smoothstep(0.2199999988079071044921875, 0.2800000011920928955078125, abs(fract(_1448 * 0.10999999940395355224609375) - 0.5)), _581); + vec2 _1395 = vec2(_581, _589); + _1395.x = _599; + bool _602 = _548 > 0.0; + bool _609; + if (_602) + { + _609 = abs(_599) < 0.02999999932944774627685546875; + } + else + { + _609 = _602; + } + if (_609) + { + _1472 = _548; + _1466 = _577; + _1458 = _1395; + _1455 = true; + break; + } + _1450 += 1.0; + _1473 = _548; + _1467 = _577; + continue; + } + else + { + _1472 = _1473; + _1466 = _1467; + _1458 = _1462; + _1455 = false; + break; + } + } + if (_1455) + { + vec3 _640 = normalize(vec3(_1458.x, sqrt(fma(-_1458.x, _1458.x, 0.000899999984540045261383056640625)), 0.0)); + float _647 = _1458.y + 9.9999997473787516355514526367188e-05; + float _1113 = smoothstep(0.2199999988079071044921875, 0.2800000011920928955078125, abs(fract(_1448 * 0.10999999940395355224609375) - 0.5)); + float _1125 = floor(_647); + float _1127 = fract(_647); + float _655 = _1458.y - 9.9999997473787516355514526367188e-05; + float _1181 = floor(_655); + float _1183 = fract(_655); + float _672 = fma(_1466.x, -2.0, atan(fma(mix(_1127 * fma(fract(sin(_1125) * 5723.26220703125), 2.0, -1.0), (_1127 - 1.0) * fma(fract(sin(_1125 + 1.0) * 5723.26220703125), 2.0, -1.0), (_1127 * _1127) * fma(-2.0, _1127, 3.0)) * 0.939999997615814208984375, _1113, -((mix(_1183 * fma(fract(sin(_1181) * 5723.26220703125), 2.0, -1.0), (_1183 - 1.0) * fma(fract(sin(_1181 + 1.0) * 5723.26220703125), 2.0, -1.0), (_1183 * _1183) * fma(-2.0, _1183, 3.0)) * 0.939999997615814208984375) * _1113)) * 5000.0)); + float _1216 = sin(_672); + float _1218 = cos(_672); + vec2 _677 = _640.xz * mat2(vec2(_1218, _1216), vec2(-_1216, _1218)); + vec3 _1404 = _640; + _1404.x = _677.x; + vec3 _1406 = _1404; + _1406.z = _677.y; + float _720 = fract(fma(_1458.y, 0.02999999932944774627685546875, _1448 * (-0.20000000298023223876953125))) - 0.5; + vec2 _1409 = _1458; + _1409.y = _720; + float _736 = _1448 + fract(sin(dot(_1466, vec2(1.86720001697540283203125, 1.37230002880096435546875))) * 5723.26220703125); + _1516 = _1409; + _1490 = _1434 + ((((vec3(1.0) * fma(1.5, max(dot(_1406, vec3(-0.8703882694244384765625, 0.348155319690704345703125, -0.348155319690704345703125)), 0.0) + pow(max(dot(reflect(vec3(-0.8703882694244384765625, 0.348155319690704345703125, -0.348155319690704345703125), _1406), _527), 0.0), 20.0), 0.20000000298023223876953125)) + vec3(smoothstep(0.00999999977648258209228515625, 0.0, abs(_720)) * 3.0)) + vec3((step(fract(sin(dot((_1466 * 1.10000002384185791015625) + vec2(floor(_736)), vec2(1.86720001697540283203125, 1.37230002880096435546875))) * 5723.26220703125), 0.0500000007450580596923828125) * step(fract(_736 * 3.0), 0.800000011920928955078125)) * 3.0)) * exp(fma((-_1472) * _1472, 0.100000001490116119384765625, (_1466.x * _1466.x) * (-0.001000000047497451305389404296875)))); + } + else + { + _1516 = _1458; + _1490 = _1434; + } + } + uint _1301 = floatBitsToUint(_s1_b2.uMaterialData.material[0].factors[11].y); + vec2 _1436; + if (((_1301 >> uint(16)) & 1u) == 1u) + { + _1436 = inUv.zw; + } + else + { + _1436 = inUv.xy; + } + vec2 _1445; + if (_163 && (((_1301 & 65535u) & 1u) == 1u)) + { + vec4 _1531 = vec4(unpackHalf2x16(_s1_b3.uMaterialTransformData.material[0]._packed[0u].x), unpackHalf2x16(_s1_b3.uMaterialTransformData.material[0]._packed[0u].y)); + _1445 = vec2(dot(_1531.xy, _1436), dot(_1531.zw, _1436)) + vec4(unpackHalf2x16(_s1_b3.uMaterialTransformData.material[0]._packed[0u].z), _1562, _1562).xy; + } + else + { + _1445 = _1436; + } + outColor = vec4(pow((_1434 * vec3(0.5)) * _s1_b4.uMyData.vec_1.xyz, vec3(0.4545454680919647216796875)) * texture(s2_b0, _1445).xyz, _s1_b4.uMyData.vec_1.w); +} + diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv.gles b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv.gles new file mode 100644 index 0000000000000000000000000000000000000000..1a0fbb10c1ce24c15566a2eedf398db642c32afc --- /dev/null +++ b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv.gles @@ -0,0 +1,236 @@ +#version 320 es +precision highp float; +precision highp int; + +struct DefaultMaterialSingleMaterialStruct +{ + vec4 factors[15]; + uvec4 indices; +}; + +struct DefaultMaterialMaterialStruct +{ + DefaultMaterialSingleMaterialStruct material[64]; +}; + +#ifndef SPIRV_CROSS_CONSTANT_ID_1 +#define SPIRV_CROSS_CONSTANT_ID_1 0u +#endif +const uint CORE_MATERIAL_FLAGS = SPIRV_CROSS_CONSTANT_ID_1; +const uint _162 = (CORE_MATERIAL_FLAGS & 8u); +const bool _163 = (_162 == 8u); + +struct DefaultMaterialTransformSingleMaterialStruct +{ + uvec4 _packed[15]; + uvec4 indices; +}; + +struct DefaultMaterialTransformMaterialStruct +{ + DefaultMaterialTransformSingleMaterialStruct material[64]; +}; + +struct MyMaterialSampleStruct +{ + vec4 vec_1; + float time; + uint dof; + uint motionBlur; +}; + +layout(std140) uniform s1_b2 +{ + DefaultMaterialMaterialStruct uMaterialData; +} _s1_b2; + +layout(std140) uniform s1_b3 +{ + DefaultMaterialTransformMaterialStruct uMaterialTransformData; +} _s1_b3; + +layout(std140) uniform s1_b4 +{ + MyMaterialSampleStruct uMyData; +} _s1_b4; + +uniform mediump sampler2D s2_b0; + +layout(location = 4) in vec4 inUv; +layout(location = 0) out vec4 outColor; + +vec2 _1444; +float _1477; +float _1562; + +void main() +{ + vec2 _336 = (inUv.xy - vec2(0.5)) * 2.0; + vec3 _1434; + vec2 _1462; + vec2 _1470; + _1470 = _1444; + _1462 = _1444; + _1434 = vec3(0.0); + vec2 _1466; + float _1472; + vec3 _1490; + vec2 _1516; + float _1476; + for (float _1433 = 0.0; _1433 < 2.0; _1476 = _1472, _1470 = _1466, _1462 = _1516, _1434 = _1490, _1433 += 1.0) + { + vec2 _372 = (inUv.xy + vec2(fract(_s1_b4.uMyData.time) * 500.0)) + vec2(_1433 * 31.3528308868408203125); + float _1448; + if (_s1_b4.uMyData.motionBlur != 0u) + { + _1448 = fma(fract(sin(dot(_372, vec2(1.86720001697540283203125, 1.37230002880096435546875))) * 5723.26220703125), 0.0500000007450580596923828125, _s1_b4.uMyData.time); + } + else + { + _1448 = _s1_b4.uMyData.time; + } + float _389 = -_1448; + float _912 = floor(_389); + vec3 _1368 = vec3(0.0, 1.0, _389); + _1368.x = (mix(floor(fract(sin(_912) * 5723.26220703125) * 5.0), floor(fract(sin(_912 + 1.0) * 5723.26220703125) * 5.0), smoothstep(0.4000000059604644775390625, 0.60000002384185791015625, fract(_389))) - 2.0) * 0.5; + float _411 = (-500.0) - _1448; + float _943 = floor(_411); + vec3 _1372 = _1368; + _1372.y = fma(mix(floor(fract(sin(_943) * 5723.26220703125) * 5.0), floor(fract(sin(_943 + 1.0) * 5723.26220703125) * 5.0), smoothstep(0.4000000059604644775390625, 0.60000002384185791015625, fract(_411))), 0.5, 1.0); + vec3 _423 = vec3(0.0, -0.5, (-0.5) - _1448) - _1372; + vec3 _424 = normalize(_423); + vec3 _429 = normalize(cross(_424, vec3(0.0, 1.0, 0.0))); + float _440 = (-1000.0) - _1448; + float _974 = floor(_440); + float _475 = length(_423); + vec3 _1449; + if (_s1_b4.uMyData.dof != 0u) + { + float _504 = fract(sin(dot(_372 * 1.2000000476837158203125, vec2(1.86720001697540283203125, 1.37230002880096435546875))) * 5723.26220703125) * 6.283185482025146484375; + vec2 _518 = _1372.xy + (((vec2(cos(_504), sin(_504)) * sqrt(fract(sin(dot(_372 * 1.10000002384185791015625, vec2(1.86720001697540283203125, 1.37230002880096435546875))) * 5723.26220703125))) * _475) * 0.02500000037252902984619140625); + vec3 _1377 = _1372; + _1377.x = _518.x; + vec3 _1379 = _1377; + _1379.y = _518.y; + _1449 = _1379; + } + else + { + _1449 = _1372; + } + vec3 _527 = normalize((_1372 + (normalize(((_429 * _336.x) + (normalize(cross(_429, _424)) * _336.y)) + (_424 / vec3(tan(fma(fma(mix(floor(fract(sin(_974) * 5723.26220703125) * 2.0), floor(fract(sin(_974 + 1.0) * 5723.26220703125) * 2.0), smoothstep(0.4000000059604644775390625, 0.60000002384185791015625, fract(_440))), 2.0, -1.0), 20.0, 40.0) * 0.00872664712369441986083984375)))) * _475)) - _1449); + vec2 _1467; + _1467 = _1470; + float _548; + vec2 _577; + bool _1455; + vec2 _1458; + float _1450 = 0.0; + float _1473 = _1476; + for (;;) + { + if (_1450 < 50.0) + { + _548 = (-fma(_1450, 0.0500000007450580596923828125, _1449.y)) / _527.y; + vec2 _556 = _1449.xz + (_527.xz * _548); + vec2 _1384 = _556; + _1384.x = fma(fract(sin(_1450) * 5723.26220703125), 500.0, _556.x); + float _567 = _1450 * 2.0; + float _1023 = sin(_567); + float _1025 = cos(_567); + vec2 _571 = _1384 * mat2(vec2(_1025, _1023), vec2(-_1023, _1025)); + float _575 = _571.x; + _577 = vec2(_1450, floor(_575)); + float _581 = fract(_575) - 0.5; + float _589 = fma(fract(sin(dot(_577, vec2(1.86720001697540283203125, 1.37230002880096435546875))) * 5723.26220703125), 500.0, _571.y); + float _1069 = floor(_589); + float _1071 = fract(_589); + float _599 = fma(mix(_1071 * fma(fract(sin(_1069) * 5723.26220703125), 2.0, -1.0), (_1071 - 1.0) * fma(fract(sin(_1069 + 1.0) * 5723.26220703125), 2.0, -1.0), (_1071 * _1071) * fma(-2.0, _1071, 3.0)) * (-0.939999997615814208984375), smoothstep(0.2199999988079071044921875, 0.2800000011920928955078125, abs(fract(_1448 * 0.10999999940395355224609375) - 0.5)), _581); + vec2 _1395 = vec2(_581, _589); + _1395.x = _599; + bool _602 = _548 > 0.0; + bool _609; + if (_602) + { + _609 = abs(_599) < 0.02999999932944774627685546875; + } + else + { + _609 = _602; + } + if (_609) + { + _1472 = _548; + _1466 = _577; + _1458 = _1395; + _1455 = true; + break; + } + _1450 += 1.0; + _1473 = _548; + _1467 = _577; + continue; + } + else + { + _1472 = _1473; + _1466 = _1467; + _1458 = _1462; + _1455 = false; + break; + } + } + if (_1455) + { + vec3 _640 = normalize(vec3(_1458.x, sqrt(fma(-_1458.x, _1458.x, 0.000899999984540045261383056640625)), 0.0)); + float _647 = _1458.y + 9.9999997473787516355514526367188e-05; + float _1113 = smoothstep(0.2199999988079071044921875, 0.2800000011920928955078125, abs(fract(_1448 * 0.10999999940395355224609375) - 0.5)); + float _1125 = floor(_647); + float _1127 = fract(_647); + float _655 = _1458.y - 9.9999997473787516355514526367188e-05; + float _1181 = floor(_655); + float _1183 = fract(_655); + float _672 = fma(_1466.x, -2.0, atan(fma(mix(_1127 * fma(fract(sin(_1125) * 5723.26220703125), 2.0, -1.0), (_1127 - 1.0) * fma(fract(sin(_1125 + 1.0) * 5723.26220703125), 2.0, -1.0), (_1127 * _1127) * fma(-2.0, _1127, 3.0)) * 0.939999997615814208984375, _1113, -((mix(_1183 * fma(fract(sin(_1181) * 5723.26220703125), 2.0, -1.0), (_1183 - 1.0) * fma(fract(sin(_1181 + 1.0) * 5723.26220703125), 2.0, -1.0), (_1183 * _1183) * fma(-2.0, _1183, 3.0)) * 0.939999997615814208984375) * _1113)) * 5000.0)); + float _1216 = sin(_672); + float _1218 = cos(_672); + vec2 _677 = _640.xz * mat2(vec2(_1218, _1216), vec2(-_1216, _1218)); + vec3 _1404 = _640; + _1404.x = _677.x; + vec3 _1406 = _1404; + _1406.z = _677.y; + float _720 = fract(fma(_1458.y, 0.02999999932944774627685546875, _1448 * (-0.20000000298023223876953125))) - 0.5; + vec2 _1409 = _1458; + _1409.y = _720; + float _736 = _1448 + fract(sin(dot(_1466, vec2(1.86720001697540283203125, 1.37230002880096435546875))) * 5723.26220703125); + _1516 = _1409; + _1490 = _1434 + ((((vec3(1.0) * fma(1.5, max(dot(_1406, vec3(-0.8703882694244384765625, 0.348155319690704345703125, -0.348155319690704345703125)), 0.0) + pow(max(dot(reflect(vec3(-0.8703882694244384765625, 0.348155319690704345703125, -0.348155319690704345703125), _1406), _527), 0.0), 20.0), 0.20000000298023223876953125)) + vec3(smoothstep(0.00999999977648258209228515625, 0.0, abs(_720)) * 3.0)) + vec3((step(fract(sin(dot((_1466 * 1.10000002384185791015625) + vec2(floor(_736)), vec2(1.86720001697540283203125, 1.37230002880096435546875))) * 5723.26220703125), 0.0500000007450580596923828125) * step(fract(_736 * 3.0), 0.800000011920928955078125)) * 3.0)) * exp(fma((-_1472) * _1472, 0.100000001490116119384765625, (_1466.x * _1466.x) * (-0.001000000047497451305389404296875)))); + } + else + { + _1516 = _1458; + _1490 = _1434; + } + } + uint _1301 = floatBitsToUint(_s1_b2.uMaterialData.material[0].factors[11].y); + vec2 _1436; + if (((_1301 >> uint(16)) & 1u) == 1u) + { + _1436 = inUv.zw; + } + else + { + _1436 = inUv.xy; + } + vec2 _1445; + if (_163 && (((_1301 & 65535u) & 1u) == 1u)) + { + vec4 _1531 = vec4(unpackHalf2x16(_s1_b3.uMaterialTransformData.material[0]._packed[0u].x), unpackHalf2x16(_s1_b3.uMaterialTransformData.material[0]._packed[0u].y)); + _1445 = vec2(dot(_1531.xy, _1436), dot(_1531.zw, _1436)) + vec4(unpackHalf2x16(_s1_b3.uMaterialTransformData.material[0]._packed[0u].z), _1562, _1562).xy; + } + else + { + _1445 = _1436; + } + outColor = vec4(pow((_1434 * vec3(0.5)) * _s1_b4.uMyData.vec_1.xyz, vec3(0.4545454680919647216796875)) * texture(s2_b0, _1445).xyz, _s1_b4.uMyData.vec_1.w); +} + diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv.lsb b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv.lsb new file mode 100644 index 0000000000000000000000000000000000000000..7a6b95bcf11cef0aea50d0634c2a3471381a2201 Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv.lsb differ diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv.pre b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv.pre new file mode 100644 index 0000000000000000000000000000000000000000..18078b919e3173acdac1ad428476c8c8f3d38d22 --- /dev/null +++ b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv.pre @@ -0,0 +1,5758 @@ +#version 460 core +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + + + +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_compatibility_common.h" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +precision highp float; +precision highp int; + + + + + +layout(constant_id = 256) const uint CORE_BACKEND_TYPE = 0; + + + + +layout(constant_id = 257) const float CORE_FLIP_NDC = 1.0; + + + + + + + + + + +vec2 GetFragCoordUv(vec2 fragCoord, vec2 inverseTexelSize) +{ + vec2 uv = fragCoord * inverseTexelSize; + if (CORE_FLIP_NDC < 0.0) { + uv = vec2(uv.x, 1.0 - uv.y); + } + return uv; +} + + + + + + + +#line 8 "shader/custom_materiaL_sample.frag" + +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_color_conversion_common.h" + + + + + + + + + + + + + + + + + + + + + + +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_compatibility_common.h" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#line 24 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_color_conversion_common.h" + + + + +float CalcLuma(const vec3 color) +{ + + return 0.299 * color.r + 0.587 * color.g + 0.114 * color.b; +} + + + + +float CalcLumaFxaa(const vec3 color) +{ + + return color.g * (0.587 / 0.299) + color.r; +} + + + + +float LumaWeight(const float luma) +{ + return(1.0 / (1.0 + luma)); +} + + + + +vec3 TonemapLuma(const vec3 color, const float luma, const float range) +{ + return color / (1.0 + luma / range); +} + + + + +vec3 TonemapLumaInv(const vec3 color, const float luma, const float range) +{ + return color / (1.0 - luma / range); +} + + + + + +vec3 SrgbToLinear(const vec3 srgb) +{ + const float mlow = 1.0f / 12.92f; + const float mhigh = 1.0f / 1.055f; + + const vec3 high = pow( (srgb + 0.055f) * mhigh, vec3(2.4f)); + const vec3 low = srgb * mlow; + const bvec3 cutoff = lessThan(srgb, vec3(0.04045f)); + return mix(high, low, cutoff); +} + + + + + +vec3 LinearToSrgb(const vec3 linear) +{ + const float mlow = 12.92f; + const float mhigh = 1.055f; + + const vec3 high = pow(linear, vec3(0.416f)) * mhigh - 0.055f; + const vec3 low = linear * mlow; + const bvec3 cutoff = lessThan(linear, vec3(0.0031308f)); + return mix(high, low, cutoff); +} + + + + + +vec3 rgbToYCoCg(const vec3 rgb) +{ + const float y = dot(rgb, vec3(0.25, 0.5, 0.25)); + const float co = dot(rgb, vec3(0.5, 0.0, - 0.5)); + const float cg = dot(rgb, vec3(- 0.25, 0.5, - 0.25)); + return vec3(y, co, cg); +} + + + + + +vec3 yCoCgToRgb(const vec3 ycocg) +{ + const float y = ycocg.r; + const float co = ycocg.g; + const float cg = ycocg.b; + return vec3(y + co - cg, y + cg, y - co - cg); +} + + +#line 10 "shader/custom_materiaL_sample.frag" +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_post_process_common.h" + + + + + + + + + + + + + + + + + + +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_post_process_structs_common.h" + + + + + + + + + + + + + + + + + + +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_compatibility_common.h" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#line 20 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_post_process_structs_common.h" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +struct GlobalPostProcessStruct { + + uvec4 flags; + + vec4 renderTimings; + + + vec4 factors[14]; + + + vec4 userFactors[16]; +}; + + + + +struct LocalPostProcessStruct { + + vec4 factors[16]; +}; + +struct LocalPostProcessPushConstantStruct { + + vec4 viewportSizeInvSize; + + vec4 factor; +}; + +struct PostProcessTonemapStruct { + vec4 texSizeInvTexSize; + + uvec4 flags; + + vec4 tonemap; + vec4 vignette; + vec4 colorFringe; + vec4 dither; + + vec4 bloomParameters; +}; + + +#line 20 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_post_process_common.h" + + + + + + +float getVignetteCoeff(const vec2 uv, mediump const float coeff, mediump const float power) +{ + vec2 uvVal = uv.xy * (vec2(1.0) - uv.yx); + float vignette = uvVal.x * uvVal.y * coeff; + vignette = pow(vignette, power); + return clamp(vignette, 0.0, 1.0); +} + + + + +float getChromaCoeff(const vec2 uv, mediump const float chromaCoefficient) +{ + + vec2 distUv = (uv - 0.5) * 2.0; + return dot(distUv, distUv) * chromaCoefficient; +} + + + + +float RandomDither(vec2 st) +{ + return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453); +} + + + + +#line 11 "shader/custom_materiaL_sample.frag" +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_tonemap_common.h" + + + + + + + + + + + + + + + + + + +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_post_process_common.h" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#line 20 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_tonemap_common.h" + + + + + +vec3 TonemapAces(vec3 x) +{ + const float a = 2.51f; + const float b = 0.03f; + const float c = 2.43f; + const float d = 0.59f; + const float e = 0.14f; + return(x * (a * x + b)) / (x * (c * x + d) + e); +} + + + + + +vec3 TonemapAcesFilmRec2020(vec3 x) +{ + float a = 15.8f; + float b = 2.12f; + float c = 1.2f; + float d = 5.92f; + float e = 1.9f; + return(x * (a * x + b)) / (x * (c * x + d) + e); +} + + + + + +float TonemapFilmic(float x) +{ + const float a = 0.15f; + const float b = 0.50f; + const float c = 0.10f; + const float d = 0.20f; + const float e = 0.02f; + const float f = 0.30f; + return( (x * (a * x + c * b) + d * e) / (x * (a * x + b) + d * f)) - e / f; +} +vec3 TonemapFilmic(vec3 x) +{ + const float a = 0.15f; + const float b = 0.50f; + const float c = 0.10f; + const float d = 0.20f; + const float e = 0.02f; + const float f = 0.30f; + const float w = 11.2f; + const vec3 curr = ( (x * (a * x + c * b) + d * e) / (x * (a * x + b) + d * f)) - e / f; + const float whiteScale = 1.0 / TonemapFilmic(w); + return curr * vec3(whiteScale); +} + + +#line 12 "shader/custom_materiaL_sample.frag" + +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_structures_common.h" + + + + + + + + + + + + + + + + + + +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_compatibility_common.h" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#line 20 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_structures_common.h" +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_packing_common.h" + + + + + + + + + + + + + + + + + + + + + +uvec2 PackVec4Half2x16(const vec4 up) +{ + uvec2 packed; + packed.x = packHalf2x16(up.xy); + packed.y = packHalf2x16(up.zw); + return packed; +} + +vec4 UnpackVec4Half2x16(const uvec2 packed) +{ + vec4 up; + up.xy = unpackHalf2x16(packed.x); + up.zw = unpackHalf2x16(packed.y); + return up; +} + +uvec4 Pack2Vec4Half2x16(const vec4 up0, const vec4 up1) +{ + uvec4 packed; + packed.x = packHalf2x16(up0.xy); + packed.y = packHalf2x16(up0.zw); + packed.z = packHalf2x16(up1.xy); + packed.w = packHalf2x16(up1.zw); + return packed; +} + +void UnpackVec42Half2x16(const uvec4 packed, inout vec4 up0, inout vec4 up1) +{ + up0.xy = unpackHalf2x16(packed.x); + up0.zw = unpackHalf2x16(packed.y); + up1.xy = unpackHalf2x16(packed.z); + up1.zw = unpackHalf2x16(packed.w); +} + + + + +#line 21 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_structures_common.h" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +struct DefaultMaterialSingleMeshStruct { + + + mat4 world; + mat4 normalWorld; + mat4 prevWorld; + + + uvec4 indices; + + uvec4 layers; + + uvec4 customData[2]; +}; + +struct DefaultMaterialMeshStruct { + DefaultMaterialSingleMeshStruct mesh[64]; +}; + +struct DefaultMaterialSingleMaterialStruct { + vec4 factors[15]; + uvec4 indices; +}; + +struct DefaultMaterialMaterialStruct { + DefaultMaterialSingleMaterialStruct material[64]; +}; + +struct DefaultMaterialTransformSingleMaterialStruct { + uvec4 packed[15]; + uvec4 indices; +}; + +struct DefaultMaterialTransformMaterialStruct { + DefaultMaterialTransformSingleMaterialStruct material[64]; +}; + +struct DefaultMaterialSingleUserMaterialStruct { + uvec4 userData[16u]; +}; + +struct DefaultMaterialUserMaterialStruct { + DefaultMaterialSingleUserMaterialStruct material[64]; +}; + +struct DefaultMaterialSingleLightStruct { + vec4 pos; + + vec4 dir; + + vec4 color; + + vec4 spotLightParams; + + vec4 shadowFactors; + + vec4 additionalFactor; + + + uvec4 flags; + + uvec4 indices; +}; + +struct DefaultMaterialLightStruct { + uint directionalLightBeginIndex; + uint directionalLightCount; + + uint pointLightBeginIndex; + uint pointLightCount; + + uint spotLightBeginIndex; + uint spotLightCount; + + uint pad0; + uint pad1; + + uvec4 clusterSizes; + vec4 clusterFactors; + + vec4 atlasSizeInvSize; + vec4 additionalFactors; + + DefaultMaterialSingleLightStruct lights[64]; +}; + +struct DefaultMaterialSkinStruct { + + mat4 jointMatrices[256u]; +}; + + +struct DefaultMaterialGeneralDataStruct { + + uvec4 indices; + + vec4 viewportSizeInvViewportSize; + + vec4 sceneTimingData; +}; + + +struct DefaultMaterialEnvironmentStruct { + + vec4 indirectSpecularColorFactor; + + vec4 indirectDiffuseColorFactor; + + vec4 envMapColorFactor; + + vec4 values; + + vec4 blendFactor; + + + mat4 envRotation; + + + uvec4 indices; + + + vec4 shIndirectCoefficients[9]; + + + vec4 pad0; +}; + +struct DefaultMaterialFogStruct { + + uvec4 indices; + + + vec4 firstLayer; + + vec4 secondLayer; + + + vec4 baseFactors; + + vec4 inscatteringColor; + + vec4 envMapFactor; + + + vec4 additionalFactor; +}; + + +struct DefaultCameraMatrixStruct { + mat4 view; + mat4 proj; + mat4 viewProj; + + mat4 viewInv; + mat4 projInv; + mat4 viewProjInv; + + mat4 viewPrevFrame; + mat4 projPrevFrame; + mat4 viewProjPrevFrame; + + mat4 shadowViewProj; + mat4 shadowViewProjInv; + + + vec4 jitter; + vec4 jitterPrevFrame; + + + uvec4 indices; + + uvec4 multiViewIndices; + + vec4 frustumPlanes[6]; + + + uvec4 counts; + + uvec4 pad0; + mat4 matPad0; + mat4 matPad1; +}; + + + + + +struct DefaultMaterialUnpackedSceneTimingStruct { + + float sceneDeltaTime; + + float tickDeltaTime; + + float tickTotalTime; + + uint frameIndex; +}; + +struct DefaultMaterialUnpackedPostProcessStruct { + float tonemapExposure; + float vignetteCoeff; + float vignettePower; +}; + +uint GetPackFlatIndices(const uint cameraIdx, const uint instanceIdx) +{ + return( (instanceIdx << 16) | (cameraIdx & 0xffff)); +} + +void GetUnpackFlatIndices(in uint indices, out uint cameraIdx, out uint instanceIdx) +{ + cameraIdx = indices & 0xffff; + instanceIdx = indices >> 16; +} + +uint GetUnpackFlatIndicesInstanceIdx(in uint indices) +{ + return(indices >> 16); +} + +uint GetUnpackFlatIndicesCameraIdx(in uint indices) +{ + return(indices & 0xffff); +} + +uint GetUnpackCameraIndex(const DefaultMaterialGeneralDataStruct dmgds) +{ + return dmgds.indices.x; +} + +DefaultMaterialUnpackedSceneTimingStruct GetUnpackSceneTiming(const DefaultMaterialGeneralDataStruct dmgds) +{ + DefaultMaterialUnpackedSceneTimingStruct dm; + dm.sceneDeltaTime = dmgds.sceneTimingData.x; + dm.tickDeltaTime = dmgds.sceneTimingData.y; + dm.tickTotalTime = dmgds.sceneTimingData.z; + dm.frameIndex = floatBitsToUint(dmgds.sceneTimingData.w); + return dm; +} + +vec4 GetUnpackViewport(const DefaultMaterialGeneralDataStruct dmgds) +{ + return dmgds.viewportSizeInvViewportSize; +} + + + +struct DefaultMaterialUnpackedTexTransformStruct { + vec4 rotateScale; + vec2 translate; +}; + +DefaultMaterialUnpackedTexTransformStruct GetUnpackTextureTransform(const uvec4 packedTexTransform) +{ + DefaultMaterialUnpackedTexTransformStruct dm; + dm.rotateScale = UnpackVec4Half2x16(packedTexTransform.xy); + dm.translate = UnpackVec4Half2x16(packedTexTransform.zw).xy; + return dm; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#line 14 "shader/custom_materiaL_sample.frag" + + + +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_frag_layout_common.h" + + + + + + + + + + + + + + + + + + +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_structures_common.h" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#line 20 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_frag_layout_common.h" +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_compatibility_common.h" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#line 21 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_frag_layout_common.h" +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_post_process_structs_common.h" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#line 22 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_frag_layout_common.h" + + + + + + + +layout(set = 0, binding = 0, std140) uniform uCameraMatrices +{ + DefaultCameraMatrixStruct uCameras[16]; +}; +layout(set = 0, binding = 1, std140) uniform uGeneralStructData +{ + DefaultMaterialGeneralDataStruct uGeneralData; +}; +layout(set = 0, binding = 2, std140) uniform uEnvironmentStructData +{ + DefaultMaterialEnvironmentStruct uEnvironmentData; +}; +layout(set = 0, binding = 3, std140) uniform uFogStructData +{ + DefaultMaterialFogStruct uFogData; +}; +layout(set = 0, binding = 4, std140) uniform uLightStructData +{ + DefaultMaterialLightStruct uLightData; +}; +layout(set = 0, binding = 5, std140) uniform uPostProcessStructData +{ + GlobalPostProcessStruct uPostProcessData; +}; +layout(set = 0, binding = 6, std430) buffer uLightClusterIndexData +{ + uint uLightClusterData; +}; +layout(set = 0, binding = 7) uniform mediump sampler2D uSampColorPrePass; +layout(set = 0, binding = 8) uniform sampler2D uSampColorShadow; +layout(set = 0, binding = 9) uniform sampler2DShadow uSampDepthShadow; +layout(set = 0, binding = 10) uniform samplerCube uSampRadiance; + + + +layout(set = 1, binding = 0, std140) uniform uMeshStructData +{ + DefaultMaterialMeshStruct uMeshMatrix; +}; +layout(set = 1, binding = 1, std140) uniform uObjectSkinStructData +{ + DefaultMaterialSkinStruct uSkinData; +}; +layout(set = 1, binding = 2, std140) uniform uMaterialStructData +{ + DefaultMaterialMaterialStruct uMaterialData; +}; + +layout(set = 1, binding = 3, std140) uniform uMaterialTransformStructData +{ + DefaultMaterialTransformMaterialStruct uMaterialTransformData; +}; +layout(set = 1, binding = 4, std140) uniform uMaterialUserStructData +{ + DefaultMaterialUserMaterialStruct uMaterialUserData; +}; + + +layout(set = 2, binding = 0) uniform mediump sampler2D uSampTextureBase; +layout(set = 2, binding = 1) uniform mediump sampler2D uSampTextures[10]; + +layout(constant_id = 0) const uint CORE_MATERIAL_TYPE = 0; +layout(constant_id = 1) const uint CORE_MATERIAL_FLAGS = 0; +layout(constant_id = 2) const uint CORE_LIGHTING_FLAGS = 0; +layout(constant_id = 3) const uint CORE_POST_PROCESS_FLAGS = 0; +layout(constant_id = 4) const uint CORE_CAMERA_FLAGS = 0; + + + + + + +#line 18 "shader/custom_materiaL_sample.frag" +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_lighting_common.h" + + + + + + + + + + + + + + + + + + +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_brdf_common.h" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +float dLambert() +{ + return(1.0 / 3.14159265359); +} + + + +float EnvSpecularAo(float ao, float NoV, float roughness) +{ + return clamp(pow(NoV + ao, exp2(- 16.0 * roughness - 1.0)) - 1.0 + ao, 0.0, 1.0); +} + +float SpecularHorizonOcclusion(vec3 R, vec3 N) +{ + const float horizon = min(1.0 + dot(R, N), 1.0); + return horizon * horizon; +} + +float dAshikhmin(float roughness, float NoH) +{ + const float r2 = roughness * roughness; + const float cos2h = NoH * NoH; + const float sin2h = 1.0 - cos2h; + const float sin4h = sin2h * sin2h; + return(sin4h + 4.0 * exp(- cos2h / (sin2h * r2))) / (3.14159265359 * (1.0 + 4.0 * r2) * sin4h); +} + + +float vAshikhmin(float NoV, float NoL) +{ + return 1.0 / (4.0 * (NoL + NoV - NoL * NoL)); +} + +float dCharlie(float roughness, float NoH) +{ + const float invR = 1.0 / roughness; + const float cos2h = NoH * NoH; + const float sin2h = 1.0 - cos2h; + return(2.0 + invR) * pow(sin2h, invR * 0.5) / (2.0 * 3.14159265359); +} + + +vec3 f0ClearcoatToSurface(const vec3 f0) +{ + + return clamp(f0 * (f0 * 0.526868 + 0.529324) - 0.0482256, 0.0, 1.0); +} + + +float EnvBRDFApproxSheen(float NoV, float alpha) +{ + const float c = 1.0 - NoV; + const float c3 = c * c * c; + return 0.6558446 * c3 + 1.0 / (4.1652655 + exp(- 7.9729136 * alpha + 6.3351689)); +} + +vec3 fSchlick(vec3 f0, float VoH) +{ + + const float p = pow(1.0 - VoH, 5.0); + return p + f0 * (1.0 - p); +} + +float fSchlickSingle(float f0, float VoH) +{ + const float p = pow(1.0 - VoH, 5.0); + return p + f0 * (1.0 - p); +} + + +vec3 fSchlick(vec4 f0, float VoH) +{ + const float p = pow(1.0 - VoH, 5.0); + return(f0.w * p) + f0.xyz * (1.0 - p); +} + + +float dGGX(float alpha2, float NoH) +{ + const float f = (NoH * alpha2 - NoH) * NoH + 1.0; + return alpha2 / (3.14159265359 * (f * f)); +} + + +float dGGXAnisotropic(float at, float ab, float NoH, float ToH, float BoH, float anisotropy) +{ + float a2 = at * ab; + vec3 d = vec3(ab * ToH, at * BoH, a2 * NoH); + float d2 = dot(d, d); + if (d2 == 0) { + return 0.0; + } + float w2 = a2 / d2; + return a2 * w2 * w2 * (1.0 / 3.14159265359); +} + + +float vGGXWithCombinedDenominator(float alpha2, float NoV, float NoL) +{ + const float gv = NoV + sqrt( (NoV - NoV * alpha2) * NoV + alpha2); + const float gl = NoL + sqrt( (NoL - NoL * alpha2) * NoL + alpha2); + return min(1.0 / (gv * gl), 64512.0); +} + + + +float vKelemen(float LoH) +{ + return min(0.25 / (LoH * LoH), 64512.0); +} + +float vGGXAnisotropic( + float at, float ab, float NoL, float NoV, float ToL, float ToV, float BoL, float BoV, float anisotropy) +{ + float gv = NoL * length(vec3(at * ToV, ab * BoV, NoV)); + float gl = NoV * length(vec3(at * ToL, ab * BoL, NoL)); + float v = 0.5 / (gv + gl); + return clamp(v, 0.0, 1.0); +} + +vec3 microfacedSpecularBrdf(vec3 f0, float alpha2, float NoL, float NoV, float NoH, float VoH) +{ + + float D = dGGX(alpha2, NoH); + float G = vGGXWithCombinedDenominator(alpha2, NoV, NoL); + vec3 F = fSchlick(f0, VoH); + return F * (D * G); +} + +float microfacedSpecularBrdfClearcoat( + float f0, float alpha2, float NoL, float NoH, float VoH, float clearcoat, out float fcc) +{ + + float D = dGGX(alpha2, NoH); + float G = vKelemen(NoH); + float F = fSchlickSingle(f0, VoH) * clearcoat; + fcc = F; + return F * D * G; +} + +vec3 microfacedSpecularBrdfAnisotropic(vec3 f0, float alpha, float NoL, float NoV, float NoH, float VoH, float ToL, + float ToV, float ToH, float BoL, float BoV, float BoH, float anisotropy) +{ + const float at = max(alpha * (1.0 + anisotropy), 0.0001); + const float ab = max(alpha * (1.0 - anisotropy), 0.0001); + + float D = dGGXAnisotropic(at, ab, NoH, ToH, BoH, anisotropy); + float V = vGGXAnisotropic(at, ab, NoL, NoV, BoV, ToV, ToL, BoL, anisotropy); + vec3 F = fSchlick(f0, VoH); + return F * (V * D); +} + +float diffuseCoeff() +{ + return dLambert(); +} + + +#line 20 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_lighting_common.h" +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_indirect_lighting_common.h" + + + + + + + + + + + + + + + + + + +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_structures_common.h" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#line 20 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_indirect_lighting_common.h" +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_compatibility_common.h" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#line 21 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_indirect_lighting_common.h" + + + + + + + + + + + + + +vec3 unpackEnvMap(vec4 envColorRgbd) +{ + return envColorRgbd.xyz * (1.0 / envColorRgbd.a); +} + + +vec3 unpackIblRadiance(vec4 envColorRgbd) +{ + return envColorRgbd.xyz * (1.0 / envColorRgbd.a); +} + + +vec3 unpackIblIrradianceSH(vec3 n, vec4 sh[9]) +{ + + return max(vec3(0.0), sh[0].xyz + + + sh[1].xyz * n.y + sh[2].xyz * n.z + sh[3].xyz * n.x + + + sh[4].xyz * (n.x * n.y) + sh[5].xyz * (n.z * n.y) + + sh[6].xyz * ( (3.0 * n.z * n.z) - 1.0) + sh[7].xyz * (n.x * n.z) + + sh[8].xyz * (n.x * n.x - n.y * n.y)); +} + + + +vec3 EnvBRDFApprox(vec3 f0, float roughness, float NoV) +{ + const vec4 c0 = vec4(- 1.0, - 0.0275, - 0.572, 0.022); + const vec4 c1 = vec4(1.0, 0.0425, 1.04, - 0.04); + vec4 r = roughness * c0 + c1; + float a004 = min(r.x * r.x, exp2(- 9.28 * NoV)) * r.x + r.y; + vec2 ab = vec2(- 1.04, 1.04) * a004 + r.zw; + + + const float f90 = clamp(50.0 * max(f0.x, max(f0.y, f0.z)), 0.0, 1.0); + return f0 * ab.x + ab.y * f90; +} + + + +float EnvBRDFApproxNonmetal(float Roughness, float NoV) +{ + + const vec2 c0 = { - 1, - 0.0275 }; + const vec2 c1 = { 1, 0.0425 }; + vec2 r = Roughness * c0 + c1; + return min(r.x * r.x, exp2(- 9.28 * NoV)) * r.x + r.y; +} + + + + +#line 21 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_lighting_common.h" +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_shadowing_common.h" + + + + + + + + + + + + + + + + + + +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_compatibility_common.h" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#line 20 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_shadowing_common.h" + + + + + + + +vec2 ComputeReceiverPlaneDepthBias(const vec3 uvDdx, const vec3 uvDdy) +{ + vec2 uvBias; + uvBias.x = uvDdy.y * uvDdx.z - uvDdx.y * uvDdy.z; + uvBias.y = uvDdx.x * uvDdy.z - uvDdy.x * uvDdx.z; + uvBias *= 1.0f / ( (uvDdx.x * uvDdy.y) - (uvDdx.y * uvDdy.x)); + return uvBias; +} + +float GetPcfSample(sampler2DShadow shadow, const vec2 baseUv, const vec2 offset, const float compareDepth, + const vec2 texelSize, const vec2 receiverPlaneDepthBias) +{ + const vec2 uvOffset = offset * texelSize; + + + + const float compZ = compareDepth; + + return texture(shadow, vec3(baseUv + uvOffset, compZ)).x; +} + +bool ValidShadowRange(const vec3 shadowCoord, float stepSize, float shadowIdx) +{ + const float xMin = stepSize * shadowIdx; + const float xMax = xMin + stepSize; + return( (shadowCoord.z > 0.0) && (shadowCoord.x > xMin) && (shadowCoord.x < xMax)); +} + + + +float CalcPcfShadow( + sampler2DShadow shadow, vec4 inShadowCoord, float NoL, vec4 shadowFactor, vec4 atlasSizeInvSize, uvec2 shadowFlags) +{ + + const vec3 shadowCoord = inShadowCoord.xyz / inShadowCoord.w; + + mediump float light = 1.0; + if (ValidShadowRange(shadowCoord, shadowFactor.w, float(shadowFlags.x))) { + const vec2 textureSize = atlasSizeInvSize.xy; + const vec2 texelSize = atlasSizeInvSize.zw; + const float normalBias = shadowFactor.z; + const float depthBias = shadowFactor.y; + const float bias = max(normalBias * (1.0 - NoL), depthBias); + + const vec2 offset = vec2(0.5); + const vec2 uv = (shadowCoord.xy * textureSize) + offset; + vec2 baseUv = (floor(uv) - offset) * texelSize; + const float fracS = fract(uv.x); + const float fracT = fract(uv.y); + + + + + + + + + + + + + const vec2 receiverPlaneDepthBias = vec2(shadowFactor.y, shadowFactor.y); + const float compareDepth = shadowCoord.z - bias; + + + const float uw0 = 4.0 - 3.0 * fracS; + const float uw1 = 7.0; + const float uw2 = 1.0 + 3.0 * fracS; + + const float u0 = (3.0 - 2.0 * fracS) / uw0 - 2.0; + const float u1 = (3.0 + fracS) / uw1; + const float u2 = fracS / uw2 + 2.0; + + const float vw0 = 4.0 - 3.0 * fracT; + const float vw1 = 7.0; + const float vw2 = 1.0 + 3.0 * fracT; + + const float v0 = (3.0 - 2.0 * fracT) / vw0 - 2.0; + const float v1 = (3.0 + fracT) / vw1; + const float v2 = fracT / vw2 + 2.0; + + mediump float sum = 0; + + sum += uw0 * vw0 * GetPcfSample(shadow, baseUv, vec2(u0, v0), compareDepth, texelSize, receiverPlaneDepthBias); + sum += uw1 * vw0 * GetPcfSample(shadow, baseUv, vec2(u1, v0), compareDepth, texelSize, receiverPlaneDepthBias); + sum += uw2 * vw0 * GetPcfSample(shadow, baseUv, vec2(u2, v0), compareDepth, texelSize, receiverPlaneDepthBias); + + sum += uw0 * vw1 * GetPcfSample(shadow, baseUv, vec2(u0, v1), compareDepth, texelSize, receiverPlaneDepthBias); + sum += uw1 * vw1 * GetPcfSample(shadow, baseUv, vec2(u1, v1), compareDepth, texelSize, receiverPlaneDepthBias); + sum += uw2 * vw1 * GetPcfSample(shadow, baseUv, vec2(u2, v1), compareDepth, texelSize, receiverPlaneDepthBias); + + sum += uw0 * vw2 * GetPcfSample(shadow, baseUv, vec2(u0, v2), compareDepth, texelSize, receiverPlaneDepthBias); + sum += uw1 * vw2 * GetPcfSample(shadow, baseUv, vec2(u1, v2), compareDepth, texelSize, receiverPlaneDepthBias); + sum += uw2 * vw2 * GetPcfSample(shadow, baseUv, vec2(u2, v2), compareDepth, texelSize, receiverPlaneDepthBias); + + sum *= 1.0f / 144.0f; + + light = 1.0 - (sum * shadowFactor.x); + } + + return light; +} +float CalcPcfShadowMed( + sampler2DShadow shadow, vec4 inShadowCoord, float NoL, vec4 shadowFactor, vec4 atlasSizeInvSize, uvec2 shadowFlags) +{ + + const vec3 shadowCoord = inShadowCoord.xyz / inShadowCoord.w; + + mediump float light = 1.0; + if (ValidShadowRange(shadowCoord, shadowFactor.w, float(shadowFlags.x))) { + const vec2 textureSize = vec2(textureSize(shadow, 0).xy); + const vec2 texelSize = 1.0 / textureSize; + const float normalBias = shadowFactor.z; + const float depthBias = shadowFactor.y; + const float bias = max(normalBias * (1.0 - NoL), depthBias); + + const vec2 offset = vec2(0.5); + const vec2 uv = (shadowCoord.xy * textureSize) + offset; + vec2 baseUv = (floor(uv) - offset) * texelSize; + const float fracS = fract(uv.x); + const float fracT = fract(uv.y); + + + + + + + + + + + + + const vec2 receiverPlaneDepthBias = vec2(shadowFactor.y, shadowFactor.y); + const float compareDepth = shadowCoord.z - bias; + + + const float uw0 = (3 - 2 * fracS); + const float uw1 = (1 + 2 * fracS); + + const float u0 = (2 - fracS) / uw0 - 1; + const float u1 = fracS / uw1 + 1; + + const float vw0 = (3 - 2 * fracT); + const float vw1 = (1 + 2 * fracT); + + float v0 = (2 - fracT) / vw0 - 1; + float v1 = fracT / vw1 + 1; + + mediump float sum = 0; + + sum += uw0 * vw0 * GetPcfSample(shadow, baseUv, vec2(u0, v0), compareDepth, texelSize, receiverPlaneDepthBias); + sum += uw1 * vw0 * GetPcfSample(shadow, baseUv, vec2(u1, v0), compareDepth, texelSize, receiverPlaneDepthBias); + + sum += uw0 * vw1 * GetPcfSample(shadow, baseUv, vec2(u0, v1), compareDepth, texelSize, receiverPlaneDepthBias); + sum += uw1 * vw1 * GetPcfSample(shadow, baseUv, vec2(u1, v1), compareDepth, texelSize, receiverPlaneDepthBias); + + sum *= (1.0f / 16.0f); + + light = 1.0 - (sum * shadowFactor.x); + } + + return light; +} + +float CalcPcfShadowSimpleSample( + sampler2DShadow shadow, vec4 inShadowCoord, vec4 shadowFactor, vec4 atlasSizeInvSize, uvec2 shadowFlags) +{ + + const vec3 shadowCoord = inShadowCoord.xyz / inShadowCoord.w; + + mediump float light = 1.0; + if (ValidShadowRange(shadowCoord, shadowFactor.w, float(shadowFlags.x))) { + const float bias = 0.002; + const vec2 baseUv = shadowCoord.xy; + const float compareDepth = shadowCoord.z - bias; + const mediump float sum = texture(shadow, vec3(baseUv, compareDepth)).x; + + light = 1.0 - (sum * shadowFactor.x); + } + + return light; +} + + + +float LinstepVsm(float minVal, float maxVal, float v) +{ + return clamp( (v - minVal) / (maxVal - minVal), 0.0, 1.0); +} +float ReduceLightBleedingVsm(float pMax, float amount) +{ + + return LinstepVsm(amount, 1.0, pMax); +} + +float CalcVsmShadow( + sampler2D shadow, vec4 inShadowCoord, float NoL, vec4 shadowFactors, vec4 atlasSizeInvSize, uvec2 shadowFlags) +{ + + const vec3 shadowCoord = inShadowCoord.xyz / inShadowCoord.w; + + mediump float light = 1.0; + if (ValidShadowRange(shadowCoord, shadowFactors.w, float(shadowFlags.x))) { + const vec2 moments = texture(shadow, shadowCoord.xy).xy; + if (shadowCoord.z > moments.x) { + float variance = moments.y - (moments.x * moments.x); + const float evaluatedMinValue = 0.00001; + variance = max(variance, evaluatedMinValue); + + const float d = shadowCoord.z - moments.x; + light = variance / (variance + d * d); + const float evaluatedLightBleedingVal = 0.2; + light = ReduceLightBleedingVsm(light, evaluatedLightBleedingVal); + light = 1.0 - (1.0 - light) * shadowFactors.x; + } + } + + return light; +} + +float CalcVsmShadowSimpleSample( + sampler2D shadow, vec4 inShadowCoord, vec4 shadowFactors, vec4 atlasSizeInvSize, uvec2 shadowFlags) +{ + + const vec3 shadowCoord = inShadowCoord.xyz / inShadowCoord.w; + + mediump float light = 1.0; + if (ValidShadowRange(shadowCoord, shadowFactors.w, float(shadowFlags.x))) { + const vec2 moments = texture(shadow, shadowCoord.xy).xy; + if (shadowCoord.z > moments.x) { + float variance = moments.y - (moments.x * moments.x); + const float evaluatedMinValue = 0.00001; + variance = max(variance, evaluatedMinValue); + + const float d = shadowCoord.z - moments.x; + light = variance / (variance + d * d); + const float evaluatedLightBleedingVal = 0.2; + light = ReduceLightBleedingVsm(light, evaluatedLightBleedingVal); + light = 1.0 - (1.0 - light) * shadowFactors.x; + } + } + + return light; +} + + +#line 22 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_lighting_common.h" +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_compatibility_common.h" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#line 23 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_lighting_common.h" + + + + + + + + + +struct InputBrdfData { + vec4 f0; + vec3 diffuseColor; + float roughness; + float alpha2; +}; + +struct ShadingData { + vec3 pos; + vec3 N; + float NoV; + vec3 V; + float alpha2; + vec4 f0; + vec3 diffuseColor; +}; + +struct ShadingDataInplace { + vec3 pos; + vec3 N; + float NoV; + vec3 V; + float alpha2; + vec4 f0; + vec3 diffuseColor; + uint materialFlags; + uvec2 layers; +}; + +struct ClearcoatShadingVariables { + vec3 ccNormal; + float cc; + mediump float ccRoughness; + float ccAlpha2; +}; + +struct SheenShadingVariables { + mediump vec3 sheenColor; + mediump float sheenRoughness; + mediump float sheenColorMax; + mediump float sheenBRDFApprox; +}; + +struct AnisotropicShadingVariables { + float roughness; + float alpha; + float anisotropy; + float ToV; + float BoV; + vec3 anisotropicT; + vec3 anisotropicB; +}; + +struct SubsurfaceScatterShadingVariables { + vec3 scatterColor; + float scatterDistance; + float thickness; +}; + + + +void GetFinalCorrectedRoughness(mediump in vec3 polygonNormal, mediump inout float roughness) +{ + + + const mediump vec3 normalDFdx = dFdx(polygonNormal); + const mediump vec3 normalDdFdy = dFdy(polygonNormal); + const mediump float geometricRoughness = + pow(clamp(max(dot(normalDFdx, normalDFdx), dot(normalDdFdy, normalDdFdy)), 0.0, 1.0), 0.333); + roughness = max(roughness, geometricRoughness); + + roughness = clamp(roughness, 0.089, 1.0); +} + +void AppendIndirectSheen(in SheenShadingVariables ssv, in mediump vec3 radianceSample, + in mediump float alpha, inout mediump vec3 irradiance, inout mediump vec3 radiance) +{ + const vec3 sheenF = ssv.sheenColor * ssv.sheenBRDFApprox; + const float sheenAttenuation = 1.0 - (ssv.sheenColorMax * ssv.sheenBRDFApprox); + + irradiance *= sheenAttenuation; + radiance *= sheenAttenuation; + + radiance += sheenF * radianceSample; +} + +void AppendIndirectClearcoat(in ClearcoatShadingVariables ccsv, in mediump vec3 radianceSample, + in mediump float alpha, in vec3 V, inout mediump vec3 irradiance, inout mediump vec3 radiance) +{ + const float ccNoV = clamp(dot(ccsv.ccNormal, V), 0.0001, 1.0); + + GetFinalCorrectedRoughness(ccsv.ccNormal, ccsv.ccAlpha2); + + float ccRadianceFactor = EnvBRDFApproxNonmetal(ccsv.ccAlpha2, ccNoV); + float ccAttenuation = 1.0 - ccRadianceFactor; + + + irradiance *= ccAttenuation; + radiance *= ccAttenuation; + + + radiance += radianceSample * ccRadianceFactor; +} + +void AppendIndirectTransmission(in mediump vec3 radianceSample, in mediump vec3 baseColor, + in mediump float transmission, inout mediump vec3 irradiance) +{ + + const mediump vec3 Ft = radianceSample * baseColor.rgb; + irradiance *= (1.0 - transmission); + irradiance = mix(irradiance, Ft, transmission); +} + +void GetFinalSampledBrdfGeometricCorrection(in vec3 polygonNormal, inout InputBrdfData ibd) +{ + + mediump float roughness = ibd.roughness; + GetFinalCorrectedRoughness(polygonNormal, roughness); + + const mediump float alpha = roughness * roughness; + ibd.alpha2 = alpha * alpha; + ibd.roughness = roughness; +} + +void GetFinalSampledBrdfGeometricCorrection(inout InputBrdfData ibd) +{ + const mediump float roughness = ibd.roughness; + const mediump float alpha = roughness * roughness; + ibd.alpha2 = alpha * alpha; +} + +InputBrdfData CalcBRDFMetallicRoughness(mediump vec4 baseColor, vec3 polygonNormal, mediump vec4 material) +{ + InputBrdfData bd; + { + const mediump float metallic = clamp(material.b, 0.0, 1.0); + bd.f0.xyz = mix(vec3(material.a), baseColor.rgb, metallic); + bd.f0.w = 1.0; + + bd.diffuseColor = mix(baseColor.rgb * (1.0 - bd.f0.xyz), vec3(0.0), vec3(metallic)); + bd.roughness = material.g; + } + + GetFinalSampledBrdfGeometricCorrection(polygonNormal, bd); + + return bd; +} + +InputBrdfData CalcBRDFMetallicRoughness(mediump vec4 baseColor, mediump vec4 material) +{ + InputBrdfData bd; + { + const mediump float metallic = clamp(material.b, 0.0, 1.0); + bd.f0.xyz = mix(vec3(material.a), baseColor.rgb, metallic); + bd.f0.w = 1.0; + + bd.diffuseColor = mix(baseColor.rgb * (1.0 - bd.f0.xyz), vec3(0.0), vec3(metallic)); + bd.roughness = material.g; + } + + GetFinalSampledBrdfGeometricCorrection(bd); + + return bd; +} + +InputBrdfData CalcBRDFSpecularGlossiness(mediump vec4 baseColor, vec3 polygonNormal, mediump vec4 material) +{ + InputBrdfData bd; + { + bd.f0.xyz = material.xyz; + bd.f0.w = 1.0; + bd.diffuseColor = baseColor.rgb * (1.0 - max(bd.f0.x, max(bd.f0.y, bd.f0.z))); + bd.roughness = 1.0 - clamp(material.a, 0.0, 1.0); + } + + GetFinalSampledBrdfGeometricCorrection(polygonNormal, bd); + + return bd; +} + +InputBrdfData CalcBRDFSpecular( + mediump vec4 baseColor, vec3 polygonNormal, mediump vec4 material, mediump vec4 specular) +{ + InputBrdfData bd; + { + const mediump float metallic = clamp(material.b, 0.0, 1.0); + + bd.f0.xyz = mix(vec3(material.a), baseColor.rgb, metallic); + + + bd.f0.xyz = min(bd.f0.xyz * specular.rgb, vec3(1.0)) * specular.a; + + + bd.diffuseColor = mix(baseColor.rgb * (1.0 - max(bd.f0.x, max(bd.f0.y, bd.f0.z))), vec3(0.0), vec3(metallic)); + + + bd.f0.xyz = mix(bd.f0.xyz, baseColor.rgb, metallic); + bd.f0.w = mix(specular.a, 1.0, metallic); + bd.roughness = material.g; + } + + GetFinalSampledBrdfGeometricCorrection(polygonNormal, bd); + + return bd; +} + +mat3 CalcTbnMatrix(in vec3 polygonNormal, in vec4 tangentW) +{ + const vec3 tangent = normalize(tangentW.xyz); + const vec3 bitangent = cross(polygonNormal, tangent.xyz) * tangentW.w; + return mat3(tangent.xyz, bitangent.xyz, polygonNormal); +} + +vec3 CalcFinalNormal(in mat3 tbn, in vec3 normal, in float normalScale) +{ + vec3 n = normalize( (2.0 * normal - 1.0) * vec3(normalScale, normalScale, 1.0f)); + return normalize(tbn * n); +} + +vec3 GetAnistropicReflectionVector(const vec3 V, const vec3 N, AnisotropicShadingVariables asv) +{ + + const vec3 anisoDir = asv.anisotropy >= 0.0 ? asv.anisotropicB : asv.anisotropicT; + const vec3 anisoTangent = cross(anisoDir, V); + const vec3 anisoNormal = cross(anisoTangent, anisoDir); + + const float bendFactor = abs(asv.anisotropy) * clamp(asv.roughness * 5.0, 0.0, 1.0); + const vec3 bentNormal = normalize(mix(N, anisoNormal, bendFactor)); + + return reflect(- V, bentNormal); +} + +mat4 GetShadowMatrix(const uint shadowCamIdx) +{ + + return uCameras[shadowCamIdx].shadowViewProj; +} + +vec3 CalculateLight( + uint currLightIdx, vec3 materialDiffuseBRDF, vec3 L, float NoL, ShadingData sd, const uint materialFlags) +{ + const vec3 H = normalize(L + sd.V); + const float VoH = clamp(dot(sd.V, H), 0.0, 1.0); + const float NoH = clamp(dot(sd.N, H), 0.0, 1.0); + + float extAttenuation = 1.0; + vec3 calculatedColor = vec3(0.0); + const float D = dGGX(sd.alpha2, NoH); + const float G = vGGXWithCombinedDenominator(sd.alpha2, sd.NoV, NoL); + const vec3 F = fSchlick(sd.f0, VoH); + const vec3 specContrib = F * (D * G); + + + + const vec3 diffuseContrib = (1.0 - F.xyz) * materialDiffuseBRDF; + calculatedColor += (diffuseContrib + specContrib * extAttenuation) * extAttenuation * NoL; + calculatedColor *= uLightData.lights[currLightIdx].color.xyz; + return calculatedColor; +} + +vec3 CalculateLight(uint currLightIdx, vec3 materialDiffuseBRDF, vec3 L, float NoL, ShadingData sd, + ClearcoatShadingVariables ccsv, SheenShadingVariables ssv, const uint materialFlags) +{ + const vec3 H = normalize(L + sd.V); + const float VoH = clamp(dot(sd.V, H), 0.0, 1.0); + const float NoH = clamp(dot(sd.N, H), 0.0, 1.0); + + float extAttenuation = 1.0; + vec3 calculatedColor = vec3(0.0); + if ( (materialFlags & (1 << 6)) == (1 << 6)) { + const float sheenD = dCharlie(ssv.sheenRoughness, NoH); + const float sheenV = vAshikhmin(sd.NoV, NoL); + const vec3 sheenSpec = ssv.sheenColor * (sheenD * sheenV); + + extAttenuation *= (1.0 - (ssv.sheenColorMax * ssv.sheenBRDFApprox)); + calculatedColor += (sheenSpec * NoL); + } + if ( (materialFlags & (1 << 4)) == (1 << 4)) { + const float ccNoL = clamp(dot(ccsv.ccNormal, L), 0.0001, 1.0); + const float ccNoH = clamp(dot(ccsv.ccNormal, H), 0.0001, 1.0); + const float ccLoH = clamp(dot(L, H), 0.0001, 1.0); + const float ccNoV = clamp(dot(ccsv.ccNormal, sd.V), 0.0001, 1.0); + const float ccf0 = 0.04; + + const float ccD = dGGX(ccsv.ccAlpha2, ccNoH); + const float ccG = vKelemen(ccLoH); + const float ccF = fSchlickSingle(ccf0, ccNoV) * ccsv.cc; + const float ccSpec = ccF * ccD * ccG; + + extAttenuation *= (1.0 - ccF); + calculatedColor += vec3(ccSpec * ccNoL); + } + const float D = dGGX(sd.alpha2, NoH); + const float G = vGGXWithCombinedDenominator(sd.alpha2, sd.NoV, NoL); + const vec3 F = fSchlick(sd.f0, VoH); + const vec3 specContrib = F * (D * G); + + + + const vec3 diffuseContrib = (1.0 - F.xyz) * materialDiffuseBRDF; + calculatedColor += (diffuseContrib + specContrib * extAttenuation) * extAttenuation * NoL; + calculatedColor *= uLightData.lights[currLightIdx].color.xyz; + return calculatedColor; +} + +vec3 CalculateLighting(ShadingData sd, const uint materialFlags) +{ + const vec3 materialDiffuseBRDF = sd.diffuseColor * diffuseCoeff(); + vec3 color = vec3(0.0); + const uint directionalLightCount = uLightData.directionalLightCount; + const uint directionalLightBeginIndex = uLightData.directionalLightBeginIndex; + const vec4 atlasSizeInvSize = uLightData.atlasSizeInvSize; + for (uint lightIdx = 0; lightIdx < directionalLightCount; ++ lightIdx) { + const uint currLightIdx = directionalLightBeginIndex + lightIdx; + const vec3 L = - uLightData.lights[currLightIdx].dir.xyz; + const float NoL = clamp(dot(sd.N, L), 0.0, 1.0); + + mediump float shadowCoeff = 1.0; + if ( (materialFlags & (1 << 0)) == (1 << 0)) { + const uvec4 lightFlags = uLightData.lights[currLightIdx].flags; + if ( (lightFlags.x & (1 << 3)) == (1 << 3)) { + const vec4 shadowCoord = GetShadowMatrix(lightFlags.y) * vec4(sd.pos.xyz, 1.0); + const vec4 shadowFactors = uLightData.lights[currLightIdx].shadowFactors; + if ( (CORE_LIGHTING_FLAGS & (1 << 0)) == (1 << 0)) { + shadowCoeff = CalcVsmShadow( + uSampColorShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw); + } else { + shadowCoeff = CalcPcfShadow( + uSampDepthShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw); + } + } + } + color += CalculateLight(currLightIdx, materialDiffuseBRDF, L, NoL, sd, materialFlags) * shadowCoeff; + } + + if ( (CORE_LIGHTING_FLAGS & (1 << 2)) == (1 << 2)) { + const uint spotLightCount = uLightData.spotLightCount; + const uint spotLightLightBeginIndex = uLightData.spotLightBeginIndex; + for (uint spotIdx = 0; spotIdx < spotLightCount; ++ spotIdx) { + const uint currLightIdx = spotLightLightBeginIndex + spotIdx; + + const vec3 pointToLight = uLightData.lights[currLightIdx].pos.xyz - sd.pos.xyz; + const float dist = length(pointToLight); + const vec3 L = pointToLight / dist; + const float NoL = clamp(dot(sd.N, L), 0.0, 1.0); + + mediump float shadowCoeff = 1.0; + if ( (materialFlags & (1 << 0)) == (1 << 0)) { + const uvec4 lightFlags = uLightData.lights[currLightIdx].flags; + if ( (lightFlags.x & (1 << 3)) == (1 << 3)) { + const vec4 shadowCoord = GetShadowMatrix(lightFlags.y) * vec4(sd.pos.xyz, 1.0); + const vec4 shadowFactors = uLightData.lights[currLightIdx].shadowFactors; + if ( (CORE_LIGHTING_FLAGS & (1 << 0)) == + (1 << 0)) { + shadowCoeff = CalcVsmShadow( + uSampColorShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw); + } else { + shadowCoeff = CalcPcfShadow( + uSampDepthShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw); + } + } + } + + const float lightAngleScale = uLightData.lights[currLightIdx].spotLightParams.x; + const float lightAngleOffset = uLightData.lights[currLightIdx].spotLightParams.y; + + const float cd = dot(uLightData.lights[currLightIdx].dir.xyz, - L); + const float angularAttenuation = clamp(cd * lightAngleScale + lightAngleOffset, 0.0, 1.0); + + const float range = uLightData.lights[currLightIdx].dir.w; + const float attenuation = max(min(1.0 - pow(dist / range, 4.0), 1.0), 0.0) / (dist * dist); + color += CalculateLight(currLightIdx, materialDiffuseBRDF, L, NoL, sd, materialFlags) * + (angularAttenuation * angularAttenuation * attenuation) * shadowCoeff; + } + } + + if ( (CORE_LIGHTING_FLAGS & (1 << 1)) == (1 << 1)) { + const uint pointLightCount = uLightData.pointLightCount; + const uint pointLightBeginIndex = uLightData.pointLightBeginIndex; + for (uint pointIdx = 0; pointIdx < pointLightCount; ++ pointIdx) { + const uint currLightIdx = pointLightBeginIndex + pointIdx; + + const vec3 pointToLight = uLightData.lights[currLightIdx].pos.xyz - sd.pos.xyz; + const float dist = length(pointToLight); + const vec3 L = pointToLight / dist; + const float NoL = clamp(dot(sd.N, L), 0.0, 1.0); + const float range = uLightData.lights[currLightIdx].dir.w; + const float attenuation = max(min(1.0 - pow(dist / range, 4.0), 1.0), 0.0) / (dist * dist); + + color += CalculateLight(currLightIdx, materialDiffuseBRDF, L, NoL, sd, materialFlags) * attenuation; + } + } + + return color; +} + +vec3 CalculateLighting( + ShadingData sd, ClearcoatShadingVariables ccsv, SheenShadingVariables ssv, const uint materialFlags) +{ + const vec3 materialDiffuseBRDF = sd.diffuseColor * diffuseCoeff(); + vec3 color = vec3(0.0); + const uint directionalLightCount = uLightData.directionalLightCount; + const uint directionalLightBeginIndex = uLightData.directionalLightBeginIndex; + const vec4 atlasSizeInvSize = uLightData.atlasSizeInvSize; + for (uint lightIdx = 0; lightIdx < directionalLightCount; ++ lightIdx) { + const uint currLightIdx = directionalLightBeginIndex + lightIdx; + const vec3 L = - uLightData.lights[currLightIdx].dir.xyz; + const float NoL = clamp(dot(sd.N, L), 0.0, 1.0); + + mediump float shadowCoeff = 1.0; + if ( (materialFlags & (1 << 0)) == (1 << 0)) { + const uvec4 lightFlags = uLightData.lights[currLightIdx].flags; + if ( (lightFlags.x & (1 << 3)) == (1 << 3)) { + const vec4 shadowCoord = GetShadowMatrix(lightFlags.y) * vec4(sd.pos.xyz, 1.0); + const vec4 shadowFactors = uLightData.lights[currLightIdx].shadowFactors; + if ( (CORE_LIGHTING_FLAGS & (1 << 0)) == (1 << 0)) { + shadowCoeff = CalcVsmShadow( + uSampColorShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw); + } else { + shadowCoeff = CalcPcfShadow( + uSampDepthShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw); + } + } + } + color += CalculateLight(currLightIdx, materialDiffuseBRDF, L, NoL, sd, ccsv, ssv, materialFlags) * shadowCoeff; + } + + if ( (CORE_LIGHTING_FLAGS & (1 << 2)) == (1 << 2)) { + const uint spotLightCount = uLightData.spotLightCount; + const uint spotLightLightBeginIndex = uLightData.spotLightBeginIndex; + for (uint spotIdx = 0; spotIdx < spotLightCount; ++ spotIdx) { + const uint currLightIdx = spotLightLightBeginIndex + spotIdx; + + const vec3 pointToLight = uLightData.lights[currLightIdx].pos.xyz - sd.pos.xyz; + const float dist = length(pointToLight); + const vec3 L = pointToLight / dist; + const float NoL = clamp(dot(sd.N, L), 0.0, 1.0); + + mediump float shadowCoeff = 1.0; + if ( (materialFlags & (1 << 0)) == (1 << 0)) { + const uvec4 lightFlags = uLightData.lights[currLightIdx].flags; + if ( (lightFlags.x & (1 << 3)) == (1 << 3)) { + const vec4 shadowCoord = GetShadowMatrix(lightFlags.y) * vec4(sd.pos.xyz, 1.0); + const vec4 shadowFactors = uLightData.lights[currLightIdx].shadowFactors; + if ( (CORE_LIGHTING_FLAGS & (1 << 0)) == + (1 << 0)) { + shadowCoeff = CalcVsmShadow( + uSampColorShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw); + } else { + shadowCoeff = CalcPcfShadow( + uSampDepthShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw); + } + } + } + + const float lightAngleScale = uLightData.lights[currLightIdx].spotLightParams.x; + const float lightAngleOffset = uLightData.lights[currLightIdx].spotLightParams.y; + + const float cd = dot(uLightData.lights[currLightIdx].dir.xyz, - L); + const float angularAttenuation = clamp(cd * lightAngleScale + lightAngleOffset, 0.0, 1.0); + + const float range = uLightData.lights[currLightIdx].dir.w; + const float attenuation = max(min(1.0 - pow(dist / range, 4.0), 1.0), 0.0) / (dist * dist); + color += CalculateLight(currLightIdx, materialDiffuseBRDF, L, NoL, sd, ccsv, ssv, materialFlags) * + (angularAttenuation * angularAttenuation * attenuation) * shadowCoeff; + } + } + if ( (CORE_LIGHTING_FLAGS & (1 << 1)) == (1 << 1)) { + const uint pointLightCount = uLightData.pointLightCount; + const uint pointLightBeginIndex = uLightData.pointLightBeginIndex; + for (uint pointIdx = 0; pointIdx < pointLightCount; ++ pointIdx) { + const uint currLightIdx = pointLightBeginIndex + pointIdx; + + const vec3 pointToLight = uLightData.lights[currLightIdx].pos.xyz - sd.pos.xyz; + const float dist = length(pointToLight); + const vec3 L = pointToLight / dist; + const float NoL = clamp(dot(sd.N, L), 0.0, 1.0); + const float range = uLightData.lights[currLightIdx].dir.w; + const float attenuation = max(min(1.0 - pow(dist / range, 4.0), 1.0), 0.0) / (dist * dist); + + color += + CalculateLight(currLightIdx, materialDiffuseBRDF, L, NoL, sd, ccsv, ssv, materialFlags) * attenuation; + } + } + + return color; +} + +vec3 CalculateLight(uint currLightIdx, vec3 materialDiffuseBRDF, vec3 L, float NoL, ShadingData sd, + AnisotropicShadingVariables asv, ClearcoatShadingVariables ccsv, SheenShadingVariables ssv, + const uint materialFlags) +{ + const vec3 H = normalize(L + sd.V); + const float VoH = dot(sd.V, H); + const float NoH = dot(sd.N, H); + + vec3 calculatedColor = vec3(0.0); + float extAttenuation = 1.0; + if ( (materialFlags & (1 << 6)) == (1 << 6)) { + const float sheenD = dCharlie(ssv.sheenRoughness, NoH); + const float sheenV = vAshikhmin(sd.NoV, NoL); + const vec3 sheenSpec = ssv.sheenColor * (sheenD * sheenV); + + extAttenuation *= (1.0 - (ssv.sheenColorMax * ssv.sheenBRDFApprox)); + calculatedColor += (sheenSpec * NoL); + } + if ( (materialFlags & (1 << 4)) == (1 << 4)) { + const float ccNoL = clamp(dot(ccsv.ccNormal, L), 0.0001, 1.0); + const float ccNoH = clamp(dot(ccsv.ccNormal, H), 0.0, 1.0); + const float ccf0 = 0.04; + + const float ccD = dGGX(ccsv.ccAlpha2, ccNoH); + const float ccG = vKelemen(ccNoH); + const float ccF = fSchlickSingle(ccf0, VoH) * ccsv.cc; + const float ccSpec = ccF * ccD * ccG; + + extAttenuation *= (1.0 - ccF); + calculatedColor += vec3(ccSpec * ccNoL); + } + + const float ToL = dot(asv.anisotropicT, L); + const float ToH = dot(asv.anisotropicT, H); + const float BoL = dot(asv.anisotropicB, L); + const float BoH = dot(asv.anisotropicB, H); + const float at = max(asv.alpha * (1.0 + asv.anisotropy), 0.0001); + const float ab = max(asv.alpha * (1.0 - asv.anisotropy), 0.0001); + + const float D = dGGXAnisotropic(at, ab, NoH, ToH, BoH, asv.anisotropy); + const float G = vGGXAnisotropic(at, ab, NoL, sd.NoV, ToL, asv.ToV, BoL, asv.BoV, asv.anisotropy); + const vec3 F = fSchlick(sd.f0, VoH); + const vec3 specContrib = F * (D * G); + + + + const vec3 diffuseContrib = (1.0 - F.xyz) * materialDiffuseBRDF; + calculatedColor += (diffuseContrib + specContrib * extAttenuation) * extAttenuation * NoL; + calculatedColor *= uLightData.lights[currLightIdx].color.xyz; + return calculatedColor; +} + +vec3 CalculateLighting(ShadingData sd, AnisotropicShadingVariables asv, ClearcoatShadingVariables ccsv, + SheenShadingVariables ssv, const uint materialFlags) +{ + const vec3 materialDiffuseBRDF = sd.diffuseColor * diffuseCoeff(); + vec3 color = vec3(0.0); + const uint directionalLightCount = uLightData.directionalLightCount; + const uint directionalLightBeginIndex = uLightData.directionalLightBeginIndex; + const vec4 atlasSizeInvSize = uLightData.atlasSizeInvSize; + for (uint lightIdx = 0; lightIdx < directionalLightCount; ++ lightIdx) { + const uint currLightIdx = directionalLightBeginIndex + lightIdx; + const vec3 L = - uLightData.lights[currLightIdx].dir.xyz; + const float NoL = clamp(dot(sd.N, L), 0.0, 1.0); + + mediump float shadowCoeff = 1.0; + if ( (materialFlags & (1 << 0)) == (1 << 0)) { + const uvec4 lightFlags = uLightData.lights[currLightIdx].flags; + if ( (lightFlags.x & (1 << 3)) == (1 << 3)) { + const vec4 shadowCoord = GetShadowMatrix(lightFlags.y) * vec4(sd.pos.xyz, 1.0); + const vec4 shadowFactors = uLightData.lights[currLightIdx].shadowFactors; + if ( (CORE_LIGHTING_FLAGS & (1 << 0)) == (1 << 0)) { + shadowCoeff = CalcVsmShadow( + uSampColorShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw); + } else { + shadowCoeff = CalcPcfShadow( + uSampDepthShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw); + } + } + } + color += + CalculateLight(currLightIdx, materialDiffuseBRDF, L, NoL, sd, asv, ccsv, ssv, materialFlags) * shadowCoeff; + } + + if ( (CORE_LIGHTING_FLAGS & (1 << 2)) == (1 << 2)) { + const uint spotLightCount = uLightData.spotLightCount; + const uint spotLightLightBeginIndex = uLightData.spotLightBeginIndex; + for (uint spotIdx = 0; spotIdx < spotLightCount; ++ spotIdx) { + const uint currLightIdx = spotLightLightBeginIndex + spotIdx; + + const vec3 pointToLight = uLightData.lights[currLightIdx].pos.xyz - sd.pos.xyz; + const float dist = length(pointToLight); + const vec3 L = pointToLight / dist; + const float NoL = clamp(dot(sd.N, L), 0.0, 1.0); + + mediump float shadowCoeff = 1.0; + if ( (materialFlags & (1 << 0)) == (1 << 0)) { + const uvec4 lightFlags = uLightData.lights[currLightIdx].flags; + if ( (lightFlags.x & (1 << 3)) == (1 << 3)) { + const vec4 shadowCoord = GetShadowMatrix(lightFlags.y) * vec4(sd.pos.xyz, 1.0); + const vec4 shadowFactors = uLightData.lights[currLightIdx].shadowFactors; + if ( (CORE_LIGHTING_FLAGS & (1 << 0)) == + (1 << 0)) { + shadowCoeff = CalcVsmShadow( + uSampColorShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw); + } else { + shadowCoeff = CalcPcfShadow( + uSampDepthShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw); + } + } + } + + const float lightAngleScale = uLightData.lights[currLightIdx].spotLightParams.x; + const float lightAngleOffset = uLightData.lights[currLightIdx].spotLightParams.y; + + const float cd = dot(uLightData.lights[currLightIdx].dir.xyz, - L); + const float angularAttenuation = clamp(cd * lightAngleScale + lightAngleOffset, 0.0, 1.0); + + const float range = uLightData.lights[currLightIdx].dir.w; + const float attenuation = max(min(1.0 - pow(dist / range, 4.0), 1.0), 0.0) / (dist * dist); + color += CalculateLight(currLightIdx, materialDiffuseBRDF, L, NoL, sd, asv, ccsv, ssv, materialFlags) * + (angularAttenuation * angularAttenuation * attenuation) * shadowCoeff; + } + } + if ( (CORE_LIGHTING_FLAGS & (1 << 1)) == (1 << 1)) { + const uint pointLightCount = uLightData.pointLightCount; + const uint pointLightBeginIndex = uLightData.pointLightBeginIndex; + for (uint pointIdx = 0; pointIdx < pointLightCount; ++ pointIdx) { + const uint currLightIdx = pointLightBeginIndex + pointIdx; + + const vec3 pointToLight = uLightData.lights[currLightIdx].pos.xyz - sd.pos.xyz; + const float dist = length(pointToLight); + const vec3 L = pointToLight / dist; + const float NoL = clamp(dot(sd.N, L), 0.0, 1.0); + const float range = uLightData.lights[currLightIdx].dir.w; + const float attenuation = max(min(1.0 - pow(dist / range, 4.0), 1.0), 0.0) / (dist * dist); + + color += CalculateLight(currLightIdx, materialDiffuseBRDF, L, NoL, sd, asv, ccsv, ssv, materialFlags) * + attenuation; + } + } + + return color; +} + +vec3 CalculateLight(uint currLightIdx, vec3 materialDiffuseBRDF, vec3 L, float NoL, ShadingData sd, + SubsurfaceScatterShadingVariables ssssv, const uint materialFlags) +{ + const vec3 H = normalize(L + sd.V); + const float VoH = clamp(dot(sd.V, H), 0.0, 1.0); + const float NoH = clamp(dot(sd.N, H), 0.0, 1.0); + + float extAttenuation = 1.0; + vec3 calculatedColor = vec3(0.0); + const float D = dGGX(sd.alpha2, NoH); + const float G = vGGXWithCombinedDenominator(sd.alpha2, sd.NoV, NoL); + const vec3 F = fSchlick(sd.f0, VoH); + const vec3 specContrib = F * (D * G); + + const vec3 diffuseContrib = (1.0 - F.xyz) * materialDiffuseBRDF; + calculatedColor += (diffuseContrib + specContrib * extAttenuation) * extAttenuation * NoL; + + + + + float scatterVoH = clamp(dot(sd.V, - L), 0.0, 1.0); + + float sharpness = 10000.0 - 10000.0 * ssssv.scatterDistance; + float forwardScatter = exp2(scatterVoH * sharpness - sharpness); + float backScatter = clamp(NoL * ssssv.thickness + (1.0 - ssssv.thickness), 0.0, 1.0) * 0.5; + float subsurface = mix(backScatter, 1.0, forwardScatter) * (1.0 - ssssv.thickness); + calculatedColor += ssssv.scatterColor * (subsurface * dLambert()); + + + return(calculatedColor * uLightData.lights[currLightIdx].color.rgb); +} + +vec3 CalculateLighting(ShadingData sd, SubsurfaceScatterShadingVariables sssv, const uint materialFlags) +{ + const vec3 materialDiffuseBRDF = sd.diffuseColor * diffuseCoeff(); + vec3 color = vec3(0.0); + const uint directionalLightCount = uLightData.directionalLightCount; + const uint directionalLightBeginIndex = uLightData.directionalLightBeginIndex; + const vec4 atlasSizeInvSize = uLightData.atlasSizeInvSize; + for (uint lightIdx = 0; lightIdx < directionalLightCount; ++ lightIdx) { + const uint currLightIdx = directionalLightBeginIndex + lightIdx; + const vec3 L = - uLightData.lights[currLightIdx].dir.xyz; + const float NoL = clamp(dot(sd.N, L), 0.0, 1.0); + + mediump float shadowCoeff = 1.0; + if ( (materialFlags & (1 << 0)) == (1 << 0)) { + const uvec4 lightFlags = uLightData.lights[currLightIdx].flags; + if ( (lightFlags.x & (1 << 3)) == (1 << 3)) { + const vec4 shadowCoord = GetShadowMatrix(lightFlags.y) * vec4(sd.pos.xyz, 1.0); + const vec4 shadowFactors = uLightData.lights[currLightIdx].shadowFactors; + if ( (CORE_LIGHTING_FLAGS & (1 << 0)) == (1 << 0)) { + shadowCoeff = CalcVsmShadow( + uSampColorShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw); + } else { + shadowCoeff = CalcPcfShadow( + uSampDepthShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw); + } + } + } + color += CalculateLight(currLightIdx, materialDiffuseBRDF, L, NoL, sd, sssv, materialFlags) * shadowCoeff; + } + + if ( (CORE_LIGHTING_FLAGS & (1 << 2)) == (1 << 2)) { + const uint spotLightCount = uLightData.spotLightCount; + const uint spotLightLightBeginIndex = uLightData.spotLightBeginIndex; + for (uint spotIdx = 0; spotIdx < spotLightCount; ++ spotIdx) { + const uint currLightIdx = spotLightLightBeginIndex + spotIdx; + + const vec3 pointToLight = uLightData.lights[currLightIdx].pos.xyz - sd.pos.xyz; + const float dist = length(pointToLight); + const vec3 L = pointToLight / dist; + const float NoL = clamp(dot(sd.N, L), 0.0, 1.0); + + mediump float shadowCoeff = 1.0; + if ( (materialFlags & (1 << 0)) == (1 << 0)) { + const uvec4 lightFlags = uLightData.lights[currLightIdx].flags; + if ( (lightFlags.x & (1 << 3)) == (1 << 3)) { + const vec4 shadowCoord = GetShadowMatrix(lightFlags.y) * vec4(sd.pos.xyz, 1.0); + const vec4 shadowFactors = uLightData.lights[currLightIdx].shadowFactors; + if ( (CORE_LIGHTING_FLAGS & (1 << 0)) == + (1 << 0)) { + shadowCoeff = CalcVsmShadow( + uSampColorShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw); + } else { + shadowCoeff = CalcPcfShadow( + uSampDepthShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw); + } + } + } + + const float lightAngleScale = uLightData.lights[currLightIdx].spotLightParams.x; + const float lightAngleOffset = uLightData.lights[currLightIdx].spotLightParams.y; + + const float cd = dot(uLightData.lights[currLightIdx].dir.xyz, - L); + const float angularAttenuation = clamp(cd * lightAngleScale + lightAngleOffset, 0.0, 1.0); + + const float range = uLightData.lights[currLightIdx].dir.w; + const float attenuation = max(min(1.0 - pow(dist / range, 4.0), 1.0), 0.0) / (dist * dist); + color += CalculateLight(currLightIdx, materialDiffuseBRDF, L, NoL, sd, sssv, materialFlags) * + (angularAttenuation * angularAttenuation * attenuation) * shadowCoeff; + } + } + if ( (CORE_LIGHTING_FLAGS & (1 << 1)) == (1 << 1)) { + const uint pointLightCount = uLightData.pointLightCount; + const uint pointLightBeginIndex = uLightData.pointLightBeginIndex; + for (uint pointIdx = 0; pointIdx < pointLightCount; ++ pointIdx) { + const uint currLightIdx = pointLightBeginIndex + pointIdx; + + const vec3 pointToLight = uLightData.lights[currLightIdx].pos.xyz - sd.pos.xyz; + const float dist = length(pointToLight); + const vec3 L = pointToLight / dist; + const float NoL = clamp(dot(sd.N, L), 0.0, 1.0); + const float range = uLightData.lights[currLightIdx].dir.w; + const float attenuation = max(min(1.0 - pow(dist / range, 4.0), 1.0), 0.0) / (dist * dist); + + color += CalculateLight(currLightIdx, materialDiffuseBRDF, L, NoL, sd, sssv, materialFlags) * attenuation; + } + } + + return color; +} + + +#line 19 "shader/custom_materiaL_sample.frag" + + +struct MyMaterialSampleStruct { + vec4 vec_1; + float time; + bool dof; + bool motionBlur; +}; +layout(set = 1, binding = 4, std140) uniform uMyBuffer0 +{ + MyMaterialSampleStruct uMyData; +}; + + + +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_inout_common.h" + + + + + + + + + + + + + + + + + + +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_compatibility_common.h" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#line 20 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_inout_common.h" + + + + + + + + + + + + + + + + + + + + + + + + + +layout(location = 0) in vec3 inPos; +layout(location = 1) in vec3 inNormal; +layout(location = 2) in vec4 inTangentW; +layout(location = 3) in vec4 inPrevPosI; +layout(location = 4) in vec4 inUv; +layout(location = 5) in mediump vec4 inColor; +layout(location = 6) in flat uint inIndices; + + + + + + + + + + + + + +#line 35 "shader/custom_materiaL_sample.frag" +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_inplace_sampling_common.h" + + + + + + + + + + + + + + + + + + + + + + +vec2 GetTransformedUV(const DefaultMaterialUnpackedTexTransformStruct texTransform, const vec2 uvInput) +{ + vec2 uv; + uv.x = dot(texTransform.rotateScale.xy, uvInput); + uv.y = dot(texTransform.rotateScale.zw, uvInput); + uv += texTransform.translate.xy; + return uv; +} + + + +uint GetUnpackTexCoordInfo() +{ + return floatBitsToUint(uMaterialData.material[0].factors[11].y); +} +uint GetUnpackTexCoordInfo(uint instanceIdx) +{ + return floatBitsToUint(uMaterialData.material[instanceIdx].factors[11].y); +} + +vec2 GetFinalSamplingUV(vec4 inputUv, uint texCoordInfoBit, uint texCoordIdx) +{ + const uint texCoordInfo = GetUnpackTexCoordInfo(); + vec2 uv = ( ( (texCoordInfo >> 16) & texCoordInfoBit) == texCoordInfoBit) ? inputUv.zw + : inputUv.xy; + const bool doTrans = ( ( (texCoordInfo & 0xffff) & texCoordInfoBit) == texCoordInfoBit); + if ( ( (CORE_MATERIAL_FLAGS & (1 << 3)) == (1 << 3)) && + doTrans) { + DefaultMaterialUnpackedTexTransformStruct texTransform = + GetUnpackTextureTransform(uMaterialTransformData.material[0].packed[texCoordIdx]); + uv = GetTransformedUV(texTransform, uv); + } + return uv; +} +vec2 GetFinalSamplingUV(vec4 inputUv, uint texCoordInfoBit, uint texCoordIdx, uint instanceIdx) +{ + const uint texCoordInfo = GetUnpackTexCoordInfo(instanceIdx); + vec2 uv = ( ( (texCoordInfo >> 16) & texCoordInfoBit) == texCoordInfoBit) ? inputUv.zw + : inputUv.xy; + const bool doTrans = ( ( (texCoordInfo & 0xffff) & texCoordInfoBit) == texCoordInfoBit); + if ( ( (CORE_MATERIAL_FLAGS & (1 << 3)) == (1 << 3)) && + doTrans) { + DefaultMaterialUnpackedTexTransformStruct texTransform = + GetUnpackTextureTransform(uMaterialTransformData.material[instanceIdx].packed[texCoordIdx]); + uv = GetTransformedUV(texTransform, uv); + } + return uv; +} + +vec4 GetBaseColorSample(const vec4 uvInput) +{ + const vec2 uv = + GetFinalSamplingUV(uvInput, (1 << 0), 0); + return texture(uSampTextureBase, uv); +} +vec4 GetBaseColorSample(const vec4 uvInput, const uint instanceIdx) +{ + const vec2 uv = GetFinalSamplingUV( + uvInput, (1 << 0), 0, instanceIdx); + return texture(uSampTextureBase, uv); +} + +vec3 GetNormalSample(const vec4 uvInput) +{ + const vec2 uv = + GetFinalSamplingUV(uvInput, (1 << 1), 1); + return texture(uSampTextures[0], uv).xyz; +} +vec3 GetNormalSample(const vec4 uvInput, const uint instanceIdx) +{ + const vec2 uv = GetFinalSamplingUV( + uvInput, (1 << 1), 1, instanceIdx); + return texture(uSampTextures[0], uv).xyz; +} + +vec4 GetMaterialSample(const vec4 uvInput) +{ + const vec2 uv = + GetFinalSamplingUV(uvInput, (1 << 2), 2); + return texture(uSampTextures[1], uv); +} +vec4 GetMaterialSample(const vec4 uvInput, const uint instanceIdx) +{ + const vec2 uv = GetFinalSamplingUV( + uvInput, (1 << 2), 2, instanceIdx); + return texture(uSampTextures[1], uv); +} + +vec3 GetEmissiveSample(const vec4 uvInput) +{ + const vec2 uv = + GetFinalSamplingUV(uvInput, (1 << 3), 3); + return texture(uSampTextures[2], uv).xyz; +} +vec3 GetEmissiveSample(const vec4 uvInput, const uint instanceIdx) +{ + const vec2 uv = GetFinalSamplingUV( + uvInput, (1 << 3), 3, instanceIdx); + return texture(uSampTextures[2], uv).xyz; +} + +float GetAOSample(const vec4 uvInput) +{ + const vec2 uv = GetFinalSamplingUV(uvInput, (1 << 4), 4); + return texture(uSampTextures[3], uv).x; +} +float GetAOSample(const vec4 uvInput, const uint instanceIdx) +{ + const vec2 uv = + GetFinalSamplingUV(uvInput, (1 << 4), 4, instanceIdx); + return texture(uSampTextures[3], uv).x; +} + +float GetClearcoatSample(const vec4 uvInput) +{ + const vec2 uv = + GetFinalSamplingUV(uvInput, (1 << 5), 5); + return texture(uSampTextures[4], uv).x; +} +float GetClearcoatSample(const vec4 uvInput, const uint instanceIdx) +{ + const vec2 uv = GetFinalSamplingUV( + uvInput, (1 << 5), 5, instanceIdx); + return texture(uSampTextures[4], uv).x; +} + +float GetClearcoatRoughnessSample(const vec4 uvInput) +{ + const vec2 uv = GetFinalSamplingUV(uvInput, (1 << 6), + 6); + return texture(uSampTextures[5], uv).y; +} +float GetClearcoatRoughnessSample(const vec4 uvInput, const uint instanceIdx) +{ + const vec2 uv = GetFinalSamplingUV(uvInput, (1 << 6), + 6, instanceIdx); + return texture(uSampTextures[5], uv).y; +} + +vec3 GetClearcoatNormalSample(const vec4 uvInput) +{ + const vec2 uv = GetFinalSamplingUV( + uvInput, (1 << 7), 7); + return texture(uSampTextures[6], uv).xyz; +} +vec3 GetClearcoatNormalSample(const vec4 uvInput, const uint instanceIdx) +{ + const vec2 uv = GetFinalSamplingUV(uvInput, (1 << 7), + 7, instanceIdx); + return texture(uSampTextures[6], uv).xyz; +} + +vec3 GetSheenSample(const vec4 uvInput) +{ + const vec2 uv = + GetFinalSamplingUV(uvInput, (1 << 8), 8); + return texture(uSampTextures[7], uv).xyz; +} +vec3 GetSheenSample(const vec4 uvInput, const uint instanceIdx) +{ + const vec2 uv = GetFinalSamplingUV( + uvInput, (1 << 8), 8, instanceIdx); + return texture(uSampTextures[7], uv).xyz; +} + + +float GetSheenRoughnessSample(const vec4 uvInput) +{ + const vec2 uv = + GetFinalSamplingUV(uvInput, (1 << 8), 8); + return texture(uSampTextures[7], uv).a; +} +float GetSheenRoughnessSample(const vec4 uvInput, const uint instanceIdx) +{ + const vec2 uv = GetFinalSamplingUV( + uvInput, (1 << 8), 8, instanceIdx); + return texture(uSampTextures[7], uv).a; +} + +float GetTransmissionSample(const vec4 uvInput) +{ + const vec2 uv = GetFinalSamplingUV( + uvInput, (1 << 9), 9); + return texture(uSampTextures[8], uv).r; +} +float GetTransmissionSample(const vec4 uvInput, const uint instanceIdx) +{ + const vec2 uv = GetFinalSamplingUV( + uvInput, (1 << 9), 9, instanceIdx); + return texture(uSampTextures[8], uv).r; +} + +vec4 GetSpecularSample(const vec4 uvInput) +{ + const vec2 uv = + GetFinalSamplingUV(uvInput, (1 << 10), 10); + return texture(uSampTextures[9], uv); +} +vec4 GetSpecularSample(const vec4 uvInput, const uint instanceIdx) +{ + const vec2 uv = GetFinalSamplingUV( + uvInput, (1 << 10), 10, instanceIdx); + return texture(uSampTextures[9], uv); +} + + + + + +uint GetUnpackCameraIndex() +{ + return uGeneralData.indices.x; +} + +vec4 GetUnpackViewport() +{ + return uGeneralData.viewportSizeInvViewportSize; +} + +vec4 GetUnpackBaseColor(const uint instanceIdx) +{ + return uMaterialData.material[instanceIdx].factors[0]; +} + +vec4 GetUnpackMaterial(const uint instanceIdx) +{ + return uMaterialData.material[instanceIdx].factors[2]; +} + +float GetUnpackAO(const uint instanceIdx) +{ + return uMaterialData.material[instanceIdx].factors[4].x; +} + +float GetUnpackClearcoat(const uint instanceIdx) +{ + return uMaterialData.material[instanceIdx].factors[5].x; +} + + +float GetUnpackClearcoatRoughness(const uint instanceIdx) +{ + return uMaterialData.material[instanceIdx].factors[6].y; +} + +float GetUnpackClearcoatNormalScale(const uint instanceIdx) +{ + return uMaterialData.material[instanceIdx].factors[7].x; +} + + +vec4 GetUnpackSheen(const uint instanceIdx) +{ + return uMaterialData.material[instanceIdx].factors[8]; +} + +float GetUnpackTransmission(const uint instanceIdx) +{ + return uMaterialData.material[instanceIdx].factors[9].x; +} + + +vec4 GetUnpackSpecular(const uint instanceIdx) +{ + return uMaterialData.material[instanceIdx].factors[10]; +} + +vec3 GetUnpackEmissiveColor(const uint instanceIdx) +{ + const vec4 emissive = uMaterialData.material[instanceIdx].factors[3]; + return emissive.rgb * emissive.a; +} + +float GetUnpackNormalScale(const uint instanceIdx) +{ + return uMaterialData.material[instanceIdx].factors[1].x; +} + +float GetUnpackAlphaCutoff(const uint instanceIdx) +{ + return uMaterialData.material[instanceIdx].factors[11].x; +} + +vec4 GetUnpackMaterialTextureInfoSlotFactor(const uint materialIndexSlot, const uint instanceIdx) +{ + const uint maxIndex = min(materialIndexSlot, 15 - 1); + return uMaterialData.material[instanceIdx].factors[maxIndex].xyzw; +} + +vec4 Unpremultiply(in vec4 color) +{ + if (color.a == 0.0) { + return vec4(0); + } + return vec4(color.rgb / color.a, color.a); +} + + mediump vec4 GetUnpackBaseColorFinalValue(in mediump vec4 color, in vec4 uv, in uint instanceIdx) +{ + + mediump vec4 baseColor = GetBaseColorSample(uv, instanceIdx) * GetUnpackBaseColor(instanceIdx) * color; + baseColor.a = clamp(baseColor.a, 0.0, 1.0); + if ( (CORE_MATERIAL_FLAGS & (1 << 7)) == + (1 << 7)) { + if (baseColor.a < GetUnpackAlphaCutoff(instanceIdx)) { + discard; + } + } + if ( (CORE_MATERIAL_FLAGS & (1 << 8)) == (1 << 8)) { + baseColor.a = 1.0; + } else { + baseColor = Unpremultiply(baseColor); + } + return baseColor; +} + + +vec2 GetFinalCalculatedVelocity(in vec3 pos, in vec3 prevPos) +{ + + + + const uint cameraIdx = GetUnpackCameraIndex(); + const vec4 projPos = uCameras[cameraIdx].viewProj * vec4(pos.xyz, 1.0); + const vec4 projPosPrev = uCameras[cameraIdx].viewProjPrevFrame * vec4(prevPos.xyz, 1.0); + + const vec2 uvPos = (projPos.xy / projPos.w) * 0.5 + 0.5; + const vec2 oldUvPos = (projPosPrev.xy / projPosPrev.w) * 0.5 + 0.5; + + return(uvPos - oldUvPos) * uGeneralData.viewportSizeInvViewportSize.xy; +} + +vec2 GetFinalCalculatedVelocity(in vec3 pos, in vec3 prevPos, in uint cameraIdx) +{ + + + + const vec4 projPos = uCameras[cameraIdx].viewProj * vec4(pos.xyz, 1.0); + const vec4 projPosPrev = uCameras[cameraIdx].viewProjPrevFrame * vec4(prevPos.xyz, 1.0); + + const vec2 uvPos = (projPos.xy / projPos.w) * 0.5 + 0.5; + const vec2 oldUvPos = (projPosPrev.xy / projPosPrev.w) * 0.5 + 0.5; + + return(uvPos - oldUvPos) * uGeneralData.viewportSizeInvViewportSize.xy; +} + +#line 36 "shader/custom_materiaL_sample.frag" +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_inplace_post_process.h" + + + + + + + + + + + + + + + + + + + +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_post_process_blocks.h" + + + + + + + + + + + + + + + + + + +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_color_conversion_common.h" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#line 20 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_post_process_blocks.h" +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_post_process_structs_common.h" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#line 21 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_post_process_blocks.h" +#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_tonemap_common.h" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#line 22 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_post_process_blocks.h" + + + + + + +void PostProcessTonemapBlock(in uint postProcessFlags, in vec4 tonemapFactor, in vec3 inCol, out vec3 outCol) +{ + outCol = inCol; + if ( (postProcessFlags & (1 << 0)) == (1 << 0)) { + const float exposure = tonemapFactor.x; + const vec3 x = outCol * exposure; + const uint tonemapType = uint(tonemapFactor.w); + if (tonemapType == 0) { + outCol = TonemapAces(x); + } else if (tonemapType == 1) { + outCol = TonemapAcesFilmRec2020(x); + } else if (tonemapType == 2) { + const float exposureEstimate = 6.0f; + outCol = TonemapFilmic(x * exposureEstimate); + } + } +} + + + + +void PostProcessVignetteBlock( + in uint postProcessFlags, in vec4 vignetteFactor, in vec2 uv, in vec3 inCol, out vec3 outCol) +{ + outCol = inCol; + if ( (postProcessFlags & (1 << 1)) == (1 << 1)) { + const vec2 uvVal = uv.xy * (vec2(1.0) - uv.yx); + mediump float vignette = uvVal.x * uvVal.y * vignetteFactor.x * 40.0; + vignette = clamp(pow(vignette, vignetteFactor.y), 0.0, 1.0); + outCol.rgb *= vignette; + } +} + + + + +void PostProcessColorFringeBlock(in uint postProcessFlags, in vec4 chromaFactor, in vec2 uv, in vec2 uvSize, + in sampler2D imgSampler, in vec3 inCol, out vec3 outCol) +{ + outCol = inCol; + if ( (postProcessFlags & (1 << 4)) == + (1 << 4)) { + + const vec2 distUv = (uv - 0.5) * 2.0; + const mediump float chroma = dot(distUv, distUv) * chromaFactor.y * chromaFactor.x; + + const vec2 uvDistToImageCenter = chroma * uvSize; + const mediump float chromaRed = + textureLod(imgSampler, uv - vec2(uvDistToImageCenter.x, uvDistToImageCenter.y), 0).x; + const mediump float chromaBlue = + textureLod(imgSampler, uv + vec2(uvDistToImageCenter.x, uvDistToImageCenter.y), 0).z; + + outCol.r = chromaRed; + outCol.b = chromaBlue; + } +} + + + + +void PostProcessDitherBlock(in uint postProcessFlags, in vec4 ditherFactor, in vec2 uv, in vec3 inCol, out vec3 outCol) +{ + outCol = inCol; + if ( (postProcessFlags & (1 << 2)) == (1 << 2)) { + const vec2 random01Range = vec2(uv.x * ditherFactor.y, uv.y * ditherFactor.z); + outCol += fract(sin(dot(random01Range.xy, vec2(12.9898, 78.233))) * 43758.5453) * ditherFactor.x; + } +} + + + + +void PostProcessColorConversionBlock( + in uint postProcessFlags, in vec4 colorConversionFactor, in vec3 inCol, out vec3 outCol) +{ + outCol = inCol; + if ( (postProcessFlags & (1 << 3)) == + (1 << 3)) { + const uint conversionType = uint(colorConversionFactor.w); + if (conversionType == 1) { + outCol.rgb = LinearToSrgb(outCol.rgb); + } + } +} + + + + +void PostProcessBloomCombineBlock(in uint postProcessFlags, in vec4 bloomFactor, in vec2 uv, in sampler2D imgSampler, + in sampler2D dirtImgSampler, in vec3 inCol, out vec3 outCol) +{ + outCol = inCol; + if ( (postProcessFlags & (1 << 9)) == (1 << 9)) { + + const vec3 bloomColor = textureLod(imgSampler, uv, 0).rgb * bloomFactor.z; + const vec3 dirtColor = textureLod(dirtImgSampler, uv, 0).rgb * bloomFactor.w; + const vec3 bloomCombine = outCol + bloomColor + dirtColor * max(bloomColor.x, max(bloomColor.y, bloomColor.z)); + outCol.rgb = min(bloomCombine, 64512.0); + } +} + + +#line 21 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_inplace_post_process.h" + + + + + +void InplacePostProcess(in vec2 fragUv, inout vec4 color) +{ + + PostProcessTonemapBlock( + uPostProcessData.flags.x, uPostProcessData.factors[0], color.rgb, color.rgb); + + const float tickDelta = uPostProcessData.renderTimings.y; + const vec2 vecCoeffs = fragUv.xy * tickDelta; + PostProcessDitherBlock( + uPostProcessData.flags.x, uPostProcessData.factors[2], vecCoeffs, color.rgb, color.rgb); + PostProcessVignetteBlock( + uPostProcessData.flags.x, uPostProcessData.factors[1], fragUv, color.rgb, color.rgb); + PostProcessColorConversionBlock( + uPostProcessData.flags.x, uPostProcessData.factors[3], color.rgb, color.rgb); +} + + + + +#line 37 "shader/custom_materiaL_sample.frag" + + + +layout(location = 0) out vec4 outColor; + + + + + +const float pi = acos(- 1.); +const float pi2 = acos(- 1.) * 2.; + + +const int nS = 2; + +const float w = .03; + + +mat2 rot(float a) { + float s = sin(a), c = cos(a); + return mat2(c, s, - s, c); +} + +float hash12(vec2 p) { + float v = dot(p, vec2(1.8672, 1.3723)); + return fract(sin(v) * 5723.2622); +} + + +float perlin1d(float x) { + float i = floor(x); + float f = fract(x); + float u = f * f * (3. - 2. * f); + + return mix(f * (fract(sin(i) * 5723.2622) * 2. - 1.), (f - 1.) * (fract(sin(i + 1.) * 5723.2622) * 2. - 1.), u); +} + +float fiberShape(float x, float time) { + float s = .03; + float curve = smoothstep(.25 - s, .25 + s, abs(fract(time * .11) - .5)); + return perlin1d(x) * (1. - w * 2.) * curve; +} + + +float stepNoise(float x, float n) { + float i = floor(x); + float s = .1; + float u = smoothstep(.5 - s, .5 + s, fract(x)); + + return mix(floor(fract(sin(i) * 5723.2622) * n), floor(fract(sin(i + 1.) * 5723.2622) * n), u); +} + + + +void main(void) +{ + vec2 uv = (inUv.xy - vec2(0.5, 0.5)) * 2.0f; + vec2 fragCoord = inUv.xy; + + vec3 col = vec3(0); + + vec3 ac = vec3(0); + + + for (float j = 0.; j < float(nS); j ++) { + float time = uMyData.time; + vec2 seed = fragCoord.xy + fract(time) * 500. + j * sqrt(983.); + + + if (uMyData.motionBlur) { + time += hash12(seed) * .05; + } + + vec3 ro = vec3(0, 1, - time); + vec3 ta = vec3(0, - .5, - time - .5); + + + ro.x += (stepNoise(ro.z, 5.) - 2.) * .5; + ro.y += stepNoise(ro.z - 500., 5.) * .5; + + vec3 dir = normalize(ta - ro); + vec3 side = normalize(cross(dir, vec3(0, 1, 0))); + vec3 up = normalize(cross(side, dir)); + + float fov = 40.; + fov += (stepNoise(ro.z - 1000., 2.) * 2. - 1.) * 20.; + vec3 rd = normalize(uv.x * side + uv.y * up + dir / tan(fov / 360. * pi)); + float L = length(ta - ro); + vec3 fp = ro + rd * L; + + + vec3 ros = ro; + if (uMyData.dof) { + float r = sqrt(hash12(seed * 1.1)); + float theta = hash12(seed * 1.2) * pi2; + ros.xy += r * vec2(cos(theta), sin(theta)) * L * .025; + } + vec3 rds = normalize(fp - ros); + + bool hit = false; + float t; + vec2 id, q; + + for (float i = 0.; i < 50.; i ++) { + t = - (ros.y + i * .05) / rds.y; + vec2 p = ros.xz + t * rds.xz; + p.x += fract(sin(i) * 5723.2622) * 500.; + p *= rot(i * 2.); + + id = vec2(i, floor(p.x)); + + p.x = fract(p.x) - .5; + p.y += hash12(id) * 500.; + p.x -= fiberShape(p.y, time); + + if (t > 0. && abs(p.x) < w) { + q = p; + hit = true; + break; + } + } + + if (hit) { + vec3 add = vec3(1); + + vec3 lightDir = normalize(vec3(- 5, 2, - 2)); + vec3 normal = normalize(vec3(q.x, sqrt(w * w - q.x * q.x), 0)); + + float e = 1e-4; + float grad = (fiberShape(q.y + e, time) - fiberShape(q.y - e, time)) / (e * 2.); + float a = atan(grad); + normal.xz *= rot(- id.x * 2. + a); + + + float diff = max(dot(normal, lightDir), 0.); + float spec = pow(max(dot(reflect(lightDir, normal), rds), 0.), 20.); + float m = .5; + float lp = 3.; + add *= diff * (1. - m) * lp + spec * m * lp + .2; + + + q.y = fract(q.y * .03 - time * .2) - .5; + add += smoothstep(.01, 0., abs(q.y)) * 3.; + + + float T = time + hash12(id); + add += step(hash12(id * 1.1 + floor(T)), .05) * step(fract(T * 3.), .8) * 3.; + + add *= exp(- t * t * .1 - id.x * id.x * .001); + + ac += add; + } + } + + col += ac / float(nS); + + float a = uMyData.vec_1.w; + + col *= uMyData.vec_1.xyz; + + col = pow(col, vec3(1. / 2.2)); + + mediump vec4 baseColor = GetBaseColorSample(inUv); + + col *= baseColor.xyz; + + outColor = vec4(col, a); +} diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.shader b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.shader new file mode 100644 index 0000000000000000000000000000000000000000..a5cfb9a650d0216c02e9979c6a97783dd7da324d --- /dev/null +++ b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.shader @@ -0,0 +1,72 @@ +{ + "compatibility_info" : { "version" : "22.00", "type" : "shader" }, + "vert": "3dshaders://shader/core3d_dm_fw.vert.spv", + "frag": "appshaders://custom_shader/custom_material_sample.frag.spv", + "vertexInputDeclaration": "3dvertexinputdeclarations://core3d_dm_fw.shadervid", + "state": { + "rasterizationState": { + "enableDepthClamp": true, + "enableDepthBias": true, + "enableRasterizerDiscard": true, + "polygonMode": "line", + "cullModeFlags": "back", + "frontFace": "counter_clockwise" + }, + "depthStencilState": { + "enableDepthTest": true, + "enableDepthWrite": true, + "enableDepthBoundsTest": false, + "enableStencilTest": false, + "depthCompareOp": "less_or_equal" + }, + "colorBlendState": { + "colorAttachments": [ + { + "enableBlend": true, + "colorWriteMask": "g_bit|b_bit", + "srcColorBlendFactor": "one", + "dstColorBlendFactor": "one_minus_src_alpha", + "colorBlendOp": "add", + "srcAlphaBlendFactor": "one", + "dstAlphaBlendFactor": "one_minus_src_alpha", + "alphaBlendOp": "add" + } + ] + } + }, + "materialMetadata": [ + { + "name": "MaterialComponent", + "customProperties": [ + { + "data": [ + { + "name": "vec_1", + "displayName": "Color", + "type": "vec4", + "value" : [1.0,1.0,1.0,1.0] + }, + { + "name": "time", + "displayName": "Time", + "type": "float", + "value": 0.0 + }, + { + "name": "dof", + "displayName": "Dof", + "type": "int", + "value": 1 + }, + { + "name": "motionblur", + "displayName": "MotionBlur", + "type": "int", + "value": 1 + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/graphic/ArkGraphics3D/entry/src/ohosTest/ets/test/Ability.test.ets b/graphic/ArkGraphics3D/entry/src/ohosTest/ets/test/Ability.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..9d824a856741e821689a087273851e7ea2b8a90a --- /dev/null +++ b/graphic/ArkGraphics3D/entry/src/ohosTest/ets/test/Ability.test.ets @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, expect, it } from '@ohos/hypium'; +import { abilityDelegatorRegistry, Driver, ON } from '@kit.TestKit'; +import Logger from '../utils/Logger'; + +const TAG = '[Sample_Graphics3D]'; +const BUNDLE = 'MyApp_'; +const DELAYMS_1S = 1000; +const DELAYMS_2S = 2000; + +const bundleName = abilityDelegatorRegistry.getArguments().bundleName; + + +export default function abilityTest() { + describe('abilityTest', () => { + // Test to verify starting the EntryAbility within a specific bundle. + // Logs test start/end and any startup errors. Signals completion. + it(BUNDLE + 'StartAbility_001, begin', 0, async (done: Function) => { + Logger.info(TAG, BUNDLE + 'StartAbility_001'); + let abilityDelegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator(); + try { + await abilityDelegator.startAbility({ + bundleName: bundleName, + abilityName: 'EntryAbility' + }); + } catch (err) { + Logger.info(TAG, `beforeAll exception = ${JSON.stringify(err)}`); + } + + Logger.info(TAG, BUNDLE + 'StartAbility_001, end'); + done(); + }); + + // Test to verify navigation through a series of UI components within a scene. + // Interacts with various buttons and checks for their existence. Logs test entry. + // In case of failure, marks the test as failed. Signals completion on success. + it(BUNDLE + 'Scene_001', 0, async (done: Function) => { + try { + Logger.info(TAG, BUNDLE + 'Scene_001' + 'in'); + let driver = Driver.create(); + await driver.delayMs(DELAYMS_2S); + + await driver.assertComponentExist(ON.id('scene')); + let sceneButton = await driver.findComponent(ON.id('scene')); + await sceneButton.click(); + await driver.delayMs(DELAYMS_1S); + + await driver.assertComponentExist(ON.id('init')); + let initButton = await driver.findComponent(ON.id('init')); + await initButton.click(); + await driver.delayMs(DELAYMS_1S); + + await driver.assertComponentExist(ON.id('back')); + let backButton = await driver.findComponent(ON.id('back')); + await backButton.click(); + await driver.delayMs(DELAYMS_1S); + + await driver.assertComponentExist(ON.id('camera')); + let cameraButton = await driver.findComponent(ON.id('camera')); + await cameraButton.click(); + await driver.delayMs(DELAYMS_1S); + + await driver.assertComponentExist(ON.id('back')); + backButton = await driver.findComponent(ON.id('back')); + await backButton.click(); + await driver.delayMs(DELAYMS_1S); + + await driver.assertComponentExist(ON.id('light')); + let lightButton = await driver.findComponent(ON.id('light')); + await lightButton.click(); + await driver.delayMs(DELAYMS_1S); + + await driver.assertComponentExist(ON.id('back')); + backButton = await driver.findComponent(ON.id('back')); + await backButton.click(); + await driver.delayMs(DELAYMS_1S); + + await driver.assertComponentExist(ON.id('back')); + backButton = await driver.findComponent(ON.id('back')); + await backButton.click(); + await driver.delayMs(DELAYMS_1S); + + done(); + } catch { + expect().assertFail(); + } + }) + + // Test to verify the navigation and interaction with resource-related UI components. + // Logs test entry, checks for the existence of resource buttons, and interacts with them. + // Interacts with resource, material, shader, image, env, and back buttons in sequence. + // In case of failure, marks the test as failed. Signals completion on success. + it(BUNDLE + 'Resource_001', 0, async (done: Function) => { + try { + Logger.info(TAG, BUNDLE + 'Resource_001' + 'in'); + let driver = Driver.create(); + await driver.delayMs(DELAYMS_2S); + + await driver.assertComponentExist(ON.id('resource')); + let resourceButton = await driver.findComponent(ON.id('resource')); + await resourceButton.click(); + await driver.delayMs(DELAYMS_1S); + + await driver.assertComponentExist(ON.id('material')); + let materialButton = await driver.findComponent(ON.id('material')); + await materialButton.click(); + await driver.delayMs(DELAYMS_1S); + + await driver.assertComponentExist(ON.id('shader')); + let shaderButton = await driver.findComponent(ON.id('shader')); + await shaderButton.click(); + await driver.delayMs(DELAYMS_1S); + + await driver.assertComponentExist(ON.id('image')); + let imageButton = await driver.findComponent(ON.id('image')); + await imageButton.click(); + await driver.delayMs(DELAYMS_1S); + + await driver.assertComponentExist(ON.id('env')); + let envButton = await driver.findComponent(ON.id('env')); + await envButton.click(); + await driver.delayMs(DELAYMS_1S); + + await driver.assertComponentExist(ON.id('back')); + let backButton = await driver.findComponent(ON.id('back')); + await backButton.click(); + await driver.delayMs(DELAYMS_1S); + + done(); + } catch { + expect().assertFail(); + } + }) + + // Test to verify the functionality of animation controls within an application. + // Logs test entry and checks for the existence of various animation control buttons. + // Interacts with the animation, start, pause, stop, finish, restart, seek, and back buttons in sequence. + // In case of failure, marks the test as failed. Signals completion on success. + it(BUNDLE + 'Animation_001', 0, async (done: Function) => { + try { + Logger.info(TAG, BUNDLE + 'Animation_001' + 'in'); + let driver = Driver.create(); + await driver.delayMs(DELAYMS_1S); + + await driver.assertComponentExist(ON.id('animation')); + let animationButton = await driver.findComponent(ON.id('animation')); + await animationButton.click(); + await driver.delayMs(DELAYMS_1S); + + await driver.assertComponentExist(ON.id('start')); + let startButton = await driver.findComponent(ON.id('start')); + await startButton.click(); + await driver.delayMs(DELAYMS_1S); + + await driver.assertComponentExist(ON.id('pause')); + let pauseButton = await driver.findComponent(ON.id('pause')); + await pauseButton.click(); + await driver.delayMs(DELAYMS_1S); + + await driver.assertComponentExist(ON.id('stop')); + let stopButton = await driver.findComponent(ON.id('stop')); + await stopButton.click(); + await driver.delayMs(DELAYMS_1S); + + await driver.assertComponentExist(ON.id('finish')); + let finishButton = await driver.findComponent(ON.id('finish')); + await finishButton.click(); + await driver.delayMs(DELAYMS_1S); + + await driver.assertComponentExist(ON.id('restart')); + let restartButton = await driver.findComponent(ON.id('restart')); + await restartButton.click(); + await driver.delayMs(DELAYMS_1S); + + await driver.assertComponentExist(ON.id('seek')); + let seekButton = await driver.findComponent(ON.id('seek')); + await seekButton.click(); + await driver.delayMs(DELAYMS_1S); + + await driver.assertComponentExist(ON.id('back')); + let backButton = await driver.findComponent(ON.id('back')); + await backButton.click(); + await driver.delayMs(DELAYMS_1S); + + done(); + } catch { + expect().assertFail(); + } + }) + }); +} \ No newline at end of file diff --git a/graphic/ArkGraphics3D/entry/src/ohosTest/ets/test/List.test.ets b/graphic/ArkGraphics3D/entry/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..f645b15b2d03979e7ec326b478de4d06b2ee506b --- /dev/null +++ b/graphic/ArkGraphics3D/entry/src/ohosTest/ets/test/List.test.ets @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import abilityTest from './Ability.test'; + +export default function testsuite() { + abilityTest(); +} \ No newline at end of file diff --git a/graphic/ArkGraphics3D/entry/src/ohosTest/ets/utils/Logger.ets b/graphic/ArkGraphics3D/entry/src/ohosTest/ets/utils/Logger.ets new file mode 100644 index 0000000000000000000000000000000000000000..41b9aead45571dd477832871577e6e8ba6315558 --- /dev/null +++ b/graphic/ArkGraphics3D/entry/src/ohosTest/ets/utils/Logger.ets @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { hilog } from '@kit.PerformanceAnalysisKit'; + +class Logger { + private domain: number; + private prefix: string; + private format: string = '%{public}s'; + + constructor(prefix: string) { + this.prefix = prefix; + this.domain = 0xF811; + } + + debug(...args: string[]) { + hilog.debug(this.domain, this.prefix, this.format, args); + } + + info(...args: string[]) { + hilog.info(this.domain, this.prefix, this.format, args); + } + + warn(...args: string[]) { + hilog.warn(this.domain, this.prefix, this.format, args); + } + + error(...args: string[]) { + hilog.error(this.domain, this.prefix, this.format, args); + } +} + +export default new Logger('[Sample_ArkGraphics3D]'); \ No newline at end of file diff --git a/graphic/ArkGraphics3D/entry/src/ohosTest/module.json5 b/graphic/ArkGraphics3D/entry/src/ohosTest/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..c3fd9dda3040d888d9d8b0b62bcb5d3b6fbeb614 --- /dev/null +++ b/graphic/ArkGraphics3D/entry/src/ohosTest/module.json5 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "module": { + "name": "entry_test", + "type": "feature", + "deviceTypes": [ + "default", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false + } +} diff --git a/graphic/ArkGraphics3D/hvigor/hvigor-config.json5 b/graphic/ArkGraphics3D/hvigor/hvigor-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..d584c19c247db9a7caee4b606bb931aa9279c637 --- /dev/null +++ b/graphic/ArkGraphics3D/hvigor/hvigor-config.json5 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "modelVersion": "5.0.1", + "dependencies": { + }, + "execution": { + // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | false ]. Default: "normal" */ + // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */ + // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */ + // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */ + // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */ + }, + "logging": { + // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */ + }, + "debugging": { + // "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */ + }, + "nodeOptions": { + // "maxOldSpaceSize": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/ + // "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/ + } +} diff --git a/graphic/ArkGraphics3D/hvigorfile.ts b/graphic/ArkGraphics3D/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..2a5e543f190732c159beb574dfc9fa37bc94e156 --- /dev/null +++ b/graphic/ArkGraphics3D/hvigorfile.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { appTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/graphic/ArkGraphics3D/oh-package.json5 b/graphic/ArkGraphics3D/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..e41bae026aab3b50d0abb42fece08ba43b4a772b --- /dev/null +++ b/graphic/ArkGraphics3D/oh-package.json5 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "modelVersion": "5.0.1", + "description": "Please describe the basic information.", + "dependencies": { + }, + "devDependencies": { + "@ohos/hypium": "1.0.19", + "@ohos/hamock": "1.0.0" + } +} diff --git a/graphic/ArkGraphics3D/ohosTest.md b/graphic/ArkGraphics3D/ohosTest.md new file mode 100644 index 0000000000000000000000000000000000000000..280dbe74c4e1e68fdc32d7d2aab71374a791f532 --- /dev/null +++ b/graphic/ArkGraphics3D/ohosTest.md @@ -0,0 +1,26 @@ +| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 | +|:-------:|:------------:|:--------------:|:---------------------:|:----:|:----:| +| 拉起应用 | 设备正常运行 | | 成功拉起应用 | 是 | Pass | +| 主页展示 | 设备正常运行 | | 展示 Building and Managing ArkGraphics 3D Scenes、Creating and Using ArkGraphics 3D Resources 和 Controlling and Managing ArkGraphics 3D Scene Animations 三种按钮 | 是 | Pass | +| 主页按钮点击 | 位于主页 | 点击 Building and Managing ArkGraphics 3D Scenes 按钮 | 跳转 Scene 页面 | 是 | Pass | +| Scene 页面按钮点击 | 位于 Scene 页面 | 点击 Model Loading and Display 按钮 | 跳转至 Model 页面,显现头盔 | 是 | Pass | +| Model 页面按钮点击 | 位于 Model 页面 | 点击 Back 按钮 | 返回 Scene 页面 | 是 | Pass | +| Scene 页面按钮点击 | 位于 Scene 页面 | 点击 Creating and Managing a Camera 按钮 | 跳转至 Camera 页面,显现几何体 | 是 | Pass | +| Camera 页面按钮点击 | 位于 Camera 页面 | 点击 Back 按钮 | 返回 Scene 页面 | 是 | Pass | +| Scene 页面 按钮点击 | 位于 Scene 页面 | 点击 Creating and Managing Light 按钮 | 跳转至 Light 页面 | 是 | Pass | +| Light 页面按钮点击 | 位于 Light 页面 | 点击 Back 按钮 | 返回 Scene 页面 | 是 | Pass | +| Scene 页面 按钮点击 | 位于 Scene 页面 | 点击 Back 按钮 | 返回主页 | 是 | Pass | +| 主页按钮点击 | 位于主页 | 点击 Creating and Using ArkGraphics 3D Resources 按钮 | 跳转至 Resource 页面,显现几何体 | 是 | Pass | +| Resource 页面按钮点击 | 位于 Resource 页面 | 点击 Replace with a blank material 按钮 | 用空白材质替换原有的材质 | 是 | Pass | +| Resource 页面按钮点击 | 位于 Resource 页面 | 点击 Replace with a image material 按钮 | 用图像材质替换原有的材质 | 是 | Pass | +| Resource 页面按钮点击 | 位于 Resource 页面 | 点击 Replace with a shader material 按钮 | 用着色器材质替换原有的材质 | 是 | Pass | +| Resource 页面按钮点击 | 位于 Resource 页面 | 点击 Add to Environment 按钮 | 添加场景 | 是 | Pass | +| Resource 页面按钮点击 | 位于 Resource 页面 | 点击 Back 按钮 | 返回主页 | 是 | Pass | +| 主页按钮点击 | 位于主页 | 点击 Controlling and Managing ArkGraphics 3D Scene Animations按钮 | 跳转至 Animation 页面 | 是 | Pass | +| Animation 页面按钮点击 | 位于 Animation 页面 | 点击 Start 按钮 | 开始播放动画 | 是 | Pass | +| Animation 页面按钮点击 | 位于 Animation 页面 | 点击 Pause 按钮 | 暂停播放动画 | 是 | Pass | +| Animation 页面按钮点击 | 位于 Animation 页面 | 点击 Stop 按钮 | 停止播放动画 | 是 | Pass | +| Animation 页面按钮点击 | 位于 Animation 页面 | 点击 Finish 按钮 | 结束播放动画 | 是 | Pass | +| Animation 页面按钮点击 | 位于 Animation 页面 | 点击 Restart 按钮 | 重新播放动画 | 是 | Pass | +| Animation 页面按钮点击 | 位于 Animation 页面 | 点击 seek to 30% progress 按钮 | 从 30% 开始播放动画 | 是 | Pass | +| Animation 页面按钮点击 | 位于 Animation 页面 | 点击 Back 按钮 | 返回主页 | 是 | Pass | \ No newline at end of file diff --git a/graphic/ArkGraphics3D/screenshots/animation.png b/graphic/ArkGraphics3D/screenshots/animation.png new file mode 100644 index 0000000000000000000000000000000000000000..ff89c70716cd8a74676396047fe8aa8e8edd3767 Binary files /dev/null and b/graphic/ArkGraphics3D/screenshots/animation.png differ diff --git a/graphic/ArkGraphics3D/screenshots/index.png b/graphic/ArkGraphics3D/screenshots/index.png new file mode 100644 index 0000000000000000000000000000000000000000..daa0ee795bfe1b6899cfd0134f23f5fe1ed73c58 Binary files /dev/null and b/graphic/ArkGraphics3D/screenshots/index.png differ diff --git a/graphic/ArkGraphics3D/screenshots/resource.png b/graphic/ArkGraphics3D/screenshots/resource.png new file mode 100644 index 0000000000000000000000000000000000000000..08a6d2a4e8779de06ca4b44d10dc48589c3544fb Binary files /dev/null and b/graphic/ArkGraphics3D/screenshots/resource.png differ diff --git a/graphic/ArkGraphics3D/screenshots/scene.png b/graphic/ArkGraphics3D/screenshots/scene.png new file mode 100644 index 0000000000000000000000000000000000000000..391f0b8f5f1ad67ebafa0fbdc15f2a44f598c66f Binary files /dev/null and b/graphic/ArkGraphics3D/screenshots/scene.png differ diff --git a/graphic/DisplaySoloist/.gitignore b/graphic/DisplaySoloist/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..ea27eaff8c3ecef3e9ebe6399a5f9073cd962a7b --- /dev/null +++ b/graphic/DisplaySoloist/.gitignore @@ -0,0 +1,13 @@ +/node_modules +/oh_modules +/local.properties +/.idea +**/build +/.hvigor +.cxx +/.clangd +/.clang-format +/.clang-tidy +**/.test +/.appanalyzer +oh-package-lock.json5 \ No newline at end of file diff --git a/graphic/DisplaySoloist/AppScope/app.json5 b/graphic/DisplaySoloist/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..4059b8b3a87a512b8eb3d79b91c1707159a40ff1 --- /dev/null +++ b/graphic/DisplaySoloist/AppScope/app.json5 @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "app": { + "bundleName": "com.samples.Displaysoloist", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name" + } +} diff --git a/graphic/DisplaySoloist/AppScope/resources/base/element/string.json b/graphic/DisplaySoloist/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..8f27bbd6363b153e19eb343ee29e37f4a2813c8e --- /dev/null +++ b/graphic/DisplaySoloist/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "DisplaySoloist" + } + ] +} diff --git a/graphic/DisplaySoloist/AppScope/resources/base/media/app_icon.png b/graphic/DisplaySoloist/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a39445dc87828b76fed6d2ec470dd455c45319e3 Binary files /dev/null and b/graphic/DisplaySoloist/AppScope/resources/base/media/app_icon.png differ diff --git a/graphic/DisplaySoloist/README.md b/graphic/DisplaySoloist/README.md new file mode 100644 index 0000000000000000000000000000000000000000..7f2a5ac46b5b60e564f17e5bcd878625fb1d50ca --- /dev/null +++ b/graphic/DisplaySoloist/README.md @@ -0,0 +1,85 @@ +# DisplaySoloist分级管控 + +### 介绍 + +本示例通过 DisplaySoloist 系列功能,使用 UI 外的线程对 XComponent 的绘制内容,设置开发者所期望的帧率。使用 [NativeDisplaySoloist](https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/graphics/displaysoloist-native-guidelines.md) 和 [Drawing](https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/graphics/drawing-guidelines.md) 来实现图像绘制和显示。 + +### 效果预览 + +| XComponent | +| :------------------------------------------------------: | +| | + +使用说明 + +1.进入 XComponent 页面,依次点击“**Start**”,三个方块分别按照 30Hz、60Hz、120Hz 移动;点击“**Stop**”动画停止。 + +### 工程目录 + +``` +├──entry/src/main +│ ├──cpp // C++代码区 +│ │ ├──CMakeLists.txt // CMake配置文件 +│ │ ├──napi_init.cpp // Napi模块注册 +│ │ ├──common +│ │ │ └──log_common.h // 日志封装定义文件 +│ │ ├──plugin // 生命周期管理模块 +│ │ │ ├──plugin_manager.cpp +│ │ │ └──plugin_manager.h +│ │ ├──samples // samples渲染模块 +│ │ │ ├──sample_xcomponent.cpp +│ │ │ └──sample_xcomponent.h +│ ├──ets // ets代码区 +│ │ ├──entryability +│ │ │ ├──EntryAbility.ts // 程序入口类 +| | | └──EntryAbility.ets +| | ├──interface +│ │ │ └──XComponentContext.ts // XComponentContext +│ │ ├──pages // 页面文件 +│ │ | └──Index.ets // XComponent页面 +│ │ ├──utils // 工具类 +| ├──resources // 资源文件目录 +``` + +### 具体实现 + +* XComponent:通过在 IDE 中的 Native C++ 工程,在 TS 侧中声明对外接口为 register、unregister 以及 destroy;在 C++ 侧调用 NativeDisplaySoloist 分级管控接口,并在使用 drawing 来绘制期望帧率图像。 + + | 接口名 | 描述 | + | ------------------------------------------- | --------------------------------------------------- | + | OH_DisplaySoloist_Create | 创建一个OH_DisplaySoloist实例 | + | OH_DisplaySoloist_Destroy | 销毁一个OH_DisplaySoloist实例 | + | OH_DisplaySoloist_Start | 设置每帧回调函数,每次vsync信号到来时启动每帧回调 | + | OH_DisplaySoloist_Stop | 停止请求下一次vsync信号,并停止调用回调函数callback | + | OH_DisplaySoloist_SetExpectedFrameRateRange | 设置期望帧率范围 | + + +### 相关权限 + +不涉及。 + +### 依赖 + +不涉及。 + +### 约束与限制 + +1. 本示例仅支持标准系统上运行,支持设备:华为手机。 + +2. HarmonyOS系统:HarmonyOS 5.0.2 Release及以上。 + +3. DevEco Studio版本:DevEco Studio 5.0.2 Release及以上。 + +4. HarmonyOS SDK版本:HarmonyOS 5.0.2 Release及以上。 + +### 下载 + +如需单独下载本工程,执行如下命令: + +``` +git init +git config core.sparsecheckout true +echo code/DocsSample/graphic/DisplaySoloist/ > .git/info/sparse-checkout +git remote add origin https://gitcode.com/openharmony/applications_app_samples.git +git pull origin master +``` \ No newline at end of file diff --git a/graphic/DisplaySoloist/build-profile.json5 b/graphic/DisplaySoloist/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..590145ac3d80c83b0197ada84ece1e876571e1f7 --- /dev/null +++ b/graphic/DisplaySoloist/build-profile.json5 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "app": { + "products": [ + { + "name": "default", + "signingConfig": "default", + "compatibleSdkVersion": "5.0.2(14)", + "targetSdkVersion": "5.0.2(14)", + "runtimeOS": "HarmonyOS", + "buildOption": { + "externalNativeOptions": { + "abiFilters": [ + "arm64-v8a", + "x86_64" + ] + } + } + } + ], + "buildModeSet": [ + { + "name": "debug" + }, + { + "name": "release" + } + ], + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/graphic/DisplaySoloist/code-linter.json5 b/graphic/DisplaySoloist/code-linter.json5 new file mode 100644 index 0000000000000000000000000000000000000000..3311c9280cd317b17b4b2745922184ac805051d8 --- /dev/null +++ b/graphic/DisplaySoloist/code-linter.json5 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "files": [ + "**/*.ets" + ], + "ignore": [ + "**/src/ohosTest/**/*", + "**/src/test/**/*", + "**/src/mock/**/*", + "**/node_modules/**/*", + "**/oh_modules/**/*", + "**/build/**/*", + "**/.preview/**/*" + ], + "ruleSet": [ + "plugin:@performance/recommended", + "plugin:@typescript-eslint/recommended" + ], + "rules": { + } +} \ No newline at end of file diff --git a/graphic/DisplaySoloist/entry/.gitignore b/graphic/DisplaySoloist/entry/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..eadab4e1522296628f32a70228b2c758ecab4759 --- /dev/null +++ b/graphic/DisplaySoloist/entry/.gitignore @@ -0,0 +1,7 @@ +/node_modules +/oh_modules +/.preview +/build +/.cxx +/.test +/oh-package-lock.json5 \ No newline at end of file diff --git a/graphic/DisplaySoloist/entry/build-profile.json5 b/graphic/DisplaySoloist/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..13781d517fa6d16ad7a8348345c632ce2d2d1d61 --- /dev/null +++ b/graphic/DisplaySoloist/entry/build-profile.json5 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "apiType": "stageMode", + "buildOption": { + "externalNativeOptions": { + "path": "./src/main/cpp/CMakeLists.txt", + "arguments": "", + "cppFlags": "", + } + }, + "buildOptionSet": [ + { + "name": "release", + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": false, + "files": [ + "./obfuscation-rules.txt" + ] + } + } + }, + "nativeLib": { + "debugSymbol": { + "strip": true, + "exclude": [] + } + } + }, + ], + "targets": [ + { + "name": "default" + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/graphic/DisplaySoloist/entry/hvigorfile.ts b/graphic/DisplaySoloist/entry/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..03701040981658f09c62d2c71567bc38dda4d37e --- /dev/null +++ b/graphic/DisplaySoloist/entry/hvigorfile.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { hapTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins: [] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/graphic/DisplaySoloist/entry/obfuscation-rules.txt b/graphic/DisplaySoloist/entry/obfuscation-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..272efb6ca3f240859091bbbfc7c5802d52793b0b --- /dev/null +++ b/graphic/DisplaySoloist/entry/obfuscation-rules.txt @@ -0,0 +1,23 @@ +# Define project specific obfuscation rules here. +# You can include the obfuscation configuration files in the current module's build-profile.json5. +# +# For more details, see +# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5 + +# Obfuscation options: +# -disable-obfuscation: disable all obfuscations +# -enable-property-obfuscation: obfuscate the property names +# -enable-toplevel-obfuscation: obfuscate the names in the global scope +# -compact: remove unnecessary blank spaces and all line feeds +# -remove-log: remove all console.* statements +# -print-namecache: print the name cache that contains the mapping from the old names to new names +# -apply-namecache: reuse the given cache file + +# Keep options: +# -keep-property-name: specifies property names that you want to keep +# -keep-global-name: specifies names that you want to keep in the global scope + +-enable-property-obfuscation +-enable-toplevel-obfuscation +-enable-filename-obfuscation +-enable-export-obfuscation \ No newline at end of file diff --git a/graphic/DisplaySoloist/entry/oh-package.json5 b/graphic/DisplaySoloist/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..1182eecc31bffd54beb78b9aee733f9df9aa735f --- /dev/null +++ b/graphic/DisplaySoloist/entry/oh-package.json5 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "name": "entry", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "", + "author": "", + "license": "", + "dependencies": { + "libentry.so": "file:./src/main/cpp/types/libentry" + } +} \ No newline at end of file diff --git a/graphic/DisplaySoloist/entry/src/main/cpp/CMakeLists.txt b/graphic/DisplaySoloist/entry/src/main/cpp/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..0e5253594a889deea00f2e32cdc8cff59ca626a7 --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/main/cpp/CMakeLists.txt @@ -0,0 +1,23 @@ +# the minimum version of CMake. +cmake_minimum_required(VERSION 3.5.0) +project(drawing_test) + +set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) + +include_directories(${NATIVERENDER_ROOT_PATH} + ${NATIVERENDER_ROOT_PATH}/include) + +add_library(entry SHARED + napi_init.cpp + samples/sample_xcomponent.cpp + plugin/plugin_manager.cpp +) +find_library( + # Sets the name of the path variable. + hilog-lib + # Specifies the name of the NDK library that + # you want CMake to locate. + hilog_ndk.z +) +target_link_libraries(entry PUBLIC ${hilog-lib}) +target_link_libraries(entry PUBLIC libace_napi.z.so libnative_drawing.so libnative_window.so libace_ndk.z.so libnative_display_soloist.so) \ No newline at end of file diff --git a/graphic/DisplaySoloist/entry/src/main/cpp/common/log_common.h b/graphic/DisplaySoloist/entry/src/main/cpp/common/log_common.h new file mode 100644 index 0000000000000000000000000000000000000000..fb896663b06a89bf20001789d1ac15b5864979fe --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/main/cpp/common/log_common.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef LOG_COMMON_H +#define LOG_COMMON_H +#include +#define LOG_PRINT_DOMAIN 0xFF00 +#define APP_LOG_DOMAIN 0x0001 +constexpr const char *APP_LOG_TAG = "DisplaySoloistSample"; +#define SAMPLE_LOGI(...) ((void)OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__)) +#define SAMPLE_LOGD(...) ((void)OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__)) +#define SAMPLE_LOGW(...) ((void)OH_LOG_Print(LOG_APP, LOG_WARN, LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__)) +#define SAMPLE_LOGE(...) ((void)OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__)) + +#endif // LOG_COMMON_H diff --git a/graphic/DisplaySoloist/entry/src/main/cpp/napi_init.cpp b/graphic/DisplaySoloist/entry/src/main/cpp/napi_init.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8e3c41842597dbd9332193f106963ef0b5ce4743 --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/main/cpp/napi_init.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include "napi/native_api.h" +#include "common/log_common.h" +#include "plugin/plugin_manager.h" + +EXTERN_C_START +static napi_value Init(napi_env env, napi_value exports) +{ + SAMPLE_LOGI("napi init"); + PluginManager::GetInstance()->Export(env, exports); + return exports; +} +EXTERN_C_END + +static napi_module demoModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Init, + .nm_modname = "entry", + .nm_priv = ((void *)0), + .reserved = {0}, +}; + +extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); } diff --git a/graphic/DisplaySoloist/entry/src/main/cpp/plugin/plugin_manager.cpp b/graphic/DisplaySoloist/entry/src/main/cpp/plugin/plugin_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3e27aa378dffd585e69b5c6fffee391bc8d3ba26 --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/main/cpp/plugin/plugin_manager.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include "common/log_common.h" +#include "plugin_manager.h" + +PluginManager *PluginManager::GetInstance() +{ + static PluginManager pluginManager; + return &pluginManager; +} + +PluginManager::~PluginManager() +{ + SAMPLE_LOGI("~PluginManager"); + for (auto iter = nativeXComponentMap_.begin(); iter != nativeXComponentMap_.end(); ++iter) { + if (iter->second != nullptr) { + delete iter->second; + iter->second = nullptr; + } + } + nativeXComponentMap_.clear(); + + for (auto iter = pluginRenderMap_.begin(); iter != pluginRenderMap_.end(); ++iter) { + if (iter->second != nullptr) { + delete iter->second; + iter->second = nullptr; + } + } + pluginRenderMap_.clear(); +} + +// [Start display_soloist_export_api] +void PluginManager::Export(napi_env env, napi_value exports) +{ + nativeXComponentMap_.clear(); + pluginRenderMap_.clear(); + if ((env == nullptr) || (exports == nullptr)) { + SAMPLE_LOGE("Export: env or exports is null"); + return; + } + + napi_value exportInstance = nullptr; + if (napi_get_named_property(env, exports, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance) != napi_ok) { + SAMPLE_LOGE("Export: napi_get_named_property fail"); + return; + } + + OH_NativeXComponent *nativeXComponent = nullptr; + if (napi_unwrap(env, exportInstance, reinterpret_cast(&nativeXComponent)) != napi_ok) { + SAMPLE_LOGE("Export: napi_unwrap fail"); + return; + } + + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'}; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + if (OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + SAMPLE_LOGE("Export: OH_NativeXComponent_GetXComponentId fail"); + return; + } + + std::string id(idStr); + auto context = PluginManager::GetInstance(); + if ((context != nullptr) && (nativeXComponent != nullptr)) { + context->SetNativeXComponent(id, nativeXComponent); + auto render = context->GetRender(id); + if (render != nullptr) { + render->RegisterCallback(nativeXComponent); + render->Export(env, exports); + } else { + SAMPLE_LOGE("render is nullptr"); + } + } +} +// [End display_soloist_export_api] + +void PluginManager::SetNativeXComponent(std::string &id, OH_NativeXComponent *nativeXComponent) +{ + SAMPLE_LOGI("set native xComponent, ID = %{public}s.", id.c_str()); + if (nativeXComponent == nullptr) { + SAMPLE_LOGE("xcomponent null"); + return; + } + + if (nativeXComponentMap_.find(id) == nativeXComponentMap_.end()) { + nativeXComponentMap_[id] = nativeXComponent; + return; + } + + if (nativeXComponentMap_[id] != nativeXComponent) { + OH_NativeXComponent *tmp = nativeXComponentMap_[id]; + delete tmp; + tmp = nullptr; + nativeXComponentMap_[id] = nativeXComponent; + } +} + +SampleXComponent *PluginManager::GetRender(std::string &id) +{ + if (pluginRenderMap_.find(id) == pluginRenderMap_.end()) { + SampleXComponent *instance = SampleXComponent::GetInstance(id); + pluginRenderMap_[id] = instance; + return instance; + } + return pluginRenderMap_[id]; +} diff --git a/graphic/DisplaySoloist/entry/src/main/cpp/plugin/plugin_manager.h b/graphic/DisplaySoloist/entry/src/main/cpp/plugin/plugin_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..a590755fba10e296ec10e4825fe08abcab486236 --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/main/cpp/plugin/plugin_manager.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef PLUGIN_MANAGER_H +#define PLUGIN_MANAGER_H + +#include +#include +#include +#include +#include +#include "samples/sample_xcomponent.h" + +// [Start display_soloist_create_plugin_manager] +class PluginManager { +public: + ~PluginManager(); + + static PluginManager *GetInstance(); + + void SetNativeXComponent(std::string &id, OH_NativeXComponent *nativeXComponent); + SampleXComponent *GetRender(std::string &id); + void Export(napi_env env, napi_value exports); + +private: + std::unordered_map nativeXComponentMap_; + std::unordered_map pluginRenderMap_; +}; +// [End display_soloist_create_plugin_manager] +#endif // PLUGIN_MANAGER_H diff --git a/graphic/DisplaySoloist/entry/src/main/cpp/samples/sample_xcomponent.cpp b/graphic/DisplaySoloist/entry/src/main/cpp/samples/sample_xcomponent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e1c3970df38fbeb2f60575368fe35f29e9ee40a2 --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/main/cpp/samples/sample_xcomponent.cpp @@ -0,0 +1,472 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include "common/log_common.h" +#include "sample_xcomponent.h" + +static std::unordered_map g_displaySync; + +static void OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window) +{ + SAMPLE_LOGI("OnSurfaceCreatedCB"); + if ((component == nullptr) || (window == nullptr)) { + SAMPLE_LOGE("OnSurfaceCreatedCB: component or window is null"); + return; + } + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'}; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + SAMPLE_LOGE("OnSurfaceCreatedCB: Unable to get XComponent id"); + return; + } + std::string id(idStr); + auto render = SampleXComponent::GetInstance(id); + OHNativeWindow *nativeWindow = static_cast(window); + render->SetNativeWindow(nativeWindow); + + uint64_t width; + uint64_t height; + int32_t xSize = OH_NativeXComponent_GetXComponentSize(component, window, &width, &height); + if ((xSize == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) && (render != nullptr)) { + render->SetHeight(height); + render->SetWidth(width); + SAMPLE_LOGI("xComponent width = %{public}llu, height = %{public}llu", width, height); + } +} + +static void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window) +{ + SAMPLE_LOGI("OnSurfaceDestroyedCB"); + if ((component == nullptr) || (window == nullptr)) { + SAMPLE_LOGE("OnSurfaceDestroyedCB: component or window is null"); + return; + } + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'}; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + SAMPLE_LOGE("OnSurfaceDestroyedCB: Unable to get XComponent id"); + return; + } + std::string id(idStr); + SampleXComponent::Release(id); +} + +// [Start display_soloist_frame_rate_setting_and_subscription_function_registration] +static void TestCallback(long long timestamp, long long targetTimestamp, void *data) +{ + SAMPLE_LOGI("test callback timestamp = %{public}llu, ", timestamp); + OH_NativeXComponent *component = nullptr; + component = static_cast(data); + if (component == nullptr) { + SAMPLE_LOGE("TestCallback: component is null"); + return; + } + + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'}; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + SAMPLE_LOGE("TestCallback: Unable to get XComponent id"); + return; + } + + std::string id(idStr); + auto render = SampleXComponent::GetInstance(id); + OHNativeWindow *nativeWindow = render->GetNativeWindow(); + uint64_t width; + uint64_t height; + + int32_t xSize = OH_NativeXComponent_GetXComponentSize(component, nativeWindow, &width, &height); + if ((xSize == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) && (render != nullptr)) { + render->Prepare(); + render->Create(); + if (id == "xcomponentId_30") { + int offset = 16; + render->ConstructPath(offset, offset, render->defaultOffsetY); + } + if (id == "xcomponentId_120") { + int offset = 4; + render->ConstructPath(offset, offset, render->defaultOffsetY); + } + render->SetPenAndBrush(); + render->DrawPath(); + render->DisPlay(); + render->Destroy(); + } +} +// [End display_soloist_frame_rate_setting_and_subscription_function_registration] + +static std::unordered_map g_instance; + +void SampleXComponent::SetWidth(uint64_t width) { width_ = width; } + +void SampleXComponent::SetHeight(uint64_t height) { height_ = height; } + +void SampleXComponent::SetNativeWindow(OHNativeWindow *nativeWindow) { nativeWindow_ = nativeWindow; } + +OHNativeWindow *SampleXComponent::GetNativeWindow() { return nativeWindow_; } + +void SampleXComponent::Prepare() +{ + if (nativeWindow_ == nullptr) { + SAMPLE_LOGE("nativeWindow_ is nullptr"); + return; + } + int ret = OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow_, &buffer_, &fenceFd_); + SAMPLE_LOGI("request buffer ret = %{public}d", ret); + bufferHandle_ = OH_NativeWindow_GetBufferHandleFromNative(buffer_); + mappedAddr_ = static_cast( + mmap(bufferHandle_->virAddr, bufferHandle_->size, PROT_READ | PROT_WRITE, MAP_SHARED, bufferHandle_->fd, 0)); + if (mappedAddr_ == MAP_FAILED) { + SAMPLE_LOGE("mmap failed"); + } +} + +void SampleXComponent::DisPlay() +{ + void *bitmapAddr = OH_Drawing_BitmapGetPixels(cBitmap_); + uint32_t *value = static_cast(bitmapAddr); + + uint32_t *pixel = static_cast(mappedAddr_); + if (pixel == nullptr) { + SAMPLE_LOGE("pixel is null"); + return; + } + if (value == nullptr) { + SAMPLE_LOGE("value is null"); + return; + } + for (uint32_t x = 0; x < width_; x++) { + for (uint32_t y = 0; y < height_; y++) { + *pixel++ = *value++; + } + } + Region region{nullptr, 0}; + OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow_, buffer_, fenceFd_, region); + int result = munmap(mappedAddr_, bufferHandle_->size); + if (result == -1) { + SAMPLE_LOGE("munmap failed!"); + } +} + +void SampleXComponent::Create() +{ + uint32_t width = static_cast(bufferHandle_->stride / 4); + cBitmap_ = OH_Drawing_BitmapCreate(); + OH_Drawing_BitmapFormat cFormat{COLOR_FORMAT_RGBA_8888, ALPHA_FORMAT_OPAQUE}; + OH_Drawing_BitmapBuild(cBitmap_, width, height_, &cFormat); + + cCanvas_ = OH_Drawing_CanvasCreate(); + OH_Drawing_CanvasBind(cCanvas_, cBitmap_); + OH_Drawing_CanvasClear(cCanvas_, OH_Drawing_ColorSetArgb(0xFF, 0xFF, 0xFF, 0xFF)); +} + +void SampleXComponent::ConstructPath(int x, int y, int offsetY) +{ + float offsetOfAy = 100.0; + float offsetOfCy = 200.0; + + aY = offsetOfAy + offsetY; + cY = offsetOfCy + offsetY; + + if (desc) { + float offset = 1.0; + aX -= x * offset; + bX -= x * offset; + } else { + float offset = 1.0; + aX += x * offset; + bX += x * offset; + } + + if (bX >= width_) { + desc = true; + } + + if (aX <= 0) { + desc = false; + } + + float bY = aY; + float cX = bX; + float dX = aX; + float dY = cY; + + cPath_ = OH_Drawing_PathCreate(); + OH_Drawing_PathMoveTo(cPath_, aX, aY); + OH_Drawing_PathLineTo(cPath_, bX, bY); + OH_Drawing_PathLineTo(cPath_, cX, cY); + OH_Drawing_PathLineTo(cPath_, dX, dY); + + OH_Drawing_PathClose(cPath_); +} + +void SampleXComponent::SetPenAndBrush() +{ + constexpr float penWidth = 10.0f; // pen width 10 + cPen_ = OH_Drawing_PenCreate(); + OH_Drawing_PenSetAntiAlias(cPen_, true); + OH_Drawing_PenSetColor(cPen_, OH_Drawing_ColorSetArgb(0xFF, 0xFF, 0x00, 0x00)); + OH_Drawing_PenSetWidth(cPen_, penWidth); + OH_Drawing_PenSetJoin(cPen_, LINE_ROUND_JOIN); + OH_Drawing_CanvasAttachPen(cCanvas_, cPen_); + + cBrush_ = OH_Drawing_BrushCreate(); + OH_Drawing_BrushSetColor(cBrush_, OH_Drawing_ColorSetArgb(0xFF, 0x00, 0xFF, 0x00)); + + OH_Drawing_CanvasAttachBrush(cCanvas_, cBrush_); +} + +void SampleXComponent::DrawPath() +{ + OH_Drawing_CanvasDrawPath(cCanvas_, cPath_); +} + +void ExecuteDisplaySoloist(std::string id, DisplaySoloist_ExpectedRateRange range, bool useExclusiveThread, + OH_NativeXComponent *nativeXComponent) +{ + OH_DisplaySoloist *nativeDisplaySoloist = nullptr; + if (g_displaySync.find(id) == g_displaySync.end()) { + g_displaySync[id] = OH_DisplaySoloist_Create(useExclusiveThread); + } + nativeDisplaySoloist = g_displaySync[id]; + OH_DisplaySoloist_SetExpectedFrameRateRange(nativeDisplaySoloist, &range); + OH_DisplaySoloist_Start(nativeDisplaySoloist, TestCallback, nativeXComponent); +} + +// [Start display_soloist_napi_register] +napi_value SampleXComponent::NapiRegister(napi_env env, napi_callback_info info) +{ + SAMPLE_LOGI("NapiRegister"); + if ((env == nullptr) || (info == nullptr)) { + SAMPLE_LOGE("NapiRegister: env or info is null"); + return nullptr; + } + + napi_value thisArg; + if (napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr) != napi_ok) { + SAMPLE_LOGE("NapiRegister: napi_get_cb_info fail"); + return nullptr; + } + + napi_value exportInstance; + if (napi_get_named_property(env, thisArg, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance) != napi_ok) { + SAMPLE_LOGE("NapiRegister: napi_get_named_property fail"); + return nullptr; + } + + OH_NativeXComponent *nativeXComponent = nullptr; + if (napi_unwrap(env, exportInstance, reinterpret_cast(&nativeXComponent)) != napi_ok) { + SAMPLE_LOGE("NapiRegister: napi_unwrap fail"); + return nullptr; + } + + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'}; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + if (OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + SAMPLE_LOGE("NapiRegister: Unable to get XComponent id"); + return nullptr; + } + SAMPLE_LOGI("RegisterID = %{public}s", idStr); + std::string id(idStr); + SampleXComponent *render = SampleXComponent().GetInstance(id); + if (render != nullptr) { + DisplaySoloist_ExpectedRateRange range; + bool useExclusiveThread = false; + if (id == "xcomponentId30") { + range = {30, 120, 30}; + } + + if (id == "xcomponentId120") { + range = {30, 120, 120}; + } + ExecuteDisplaySoloist(id, range, useExclusiveThread, nativeXComponent); + } + return nullptr; +} +// [End display_soloist_napi_register] + +napi_value SampleXComponent::NapiUnregister(napi_env env, napi_callback_info info) +{ + SAMPLE_LOGI("NapiUnregister"); + if ((env == nullptr) || (info == nullptr)) { + SAMPLE_LOGE("NapiUnregister: env or info is null"); + return nullptr; + } + + napi_value thisArg; + if (napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr) != napi_ok) { + SAMPLE_LOGE("NapiUnregister: napi_get_cb_info fail"); + return nullptr; + } + + napi_value exportInstance; + if (napi_get_named_property(env, thisArg, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance) != napi_ok) { + SAMPLE_LOGE("NapiUnregister: napi_get_named_property fail"); + return nullptr; + } + + OH_NativeXComponent *nativeXComponent = nullptr; + if (napi_unwrap(env, exportInstance, reinterpret_cast(&nativeXComponent)) != napi_ok) { + SAMPLE_LOGE("NapiUnregister: napi_unwrap fail"); + return nullptr; + } + + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'}; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + if (OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + SAMPLE_LOGE("NapiUnregister: Unable to get XComponent id"); + return nullptr; + } + SAMPLE_LOGI("ID = %{public}s", idStr); + std::string id(idStr); + SampleXComponent *render = SampleXComponent().GetInstance(id); + if (render != nullptr) { + OH_DisplaySoloist_Stop(g_displaySync[id]); + SAMPLE_LOGI("NapiUnregister executed"); + } else { + SAMPLE_LOGE("render is nullptr"); + } + return nullptr; +} + +napi_value SampleXComponent::NapiDestroy(napi_env env, napi_callback_info info) +{ + SAMPLE_LOGI("NapiUnregister"); + if ((env == nullptr) || (info == nullptr)) { + SAMPLE_LOGE("NapiDestroy: env or info is null"); + return nullptr; + } + + napi_value thisArg; + if (napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr) != napi_ok) { + SAMPLE_LOGE("NapiDestroy: napi_get_cb_info fail"); + return nullptr; + } + + napi_value exportInstance; + if (napi_get_named_property(env, thisArg, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance) != napi_ok) { + SAMPLE_LOGE("NapiDestroy: napi_get_named_property fail"); + return nullptr; + } + + OH_NativeXComponent *nativeXComponent = nullptr; + if (napi_unwrap(env, exportInstance, reinterpret_cast(&nativeXComponent)) != napi_ok) { + SAMPLE_LOGE("NapiDestroy: napi_unwrap fail"); + return nullptr; + } + + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'}; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + if (OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + SAMPLE_LOGE("NapiDestroy: Unable to get XComponent id"); + return nullptr; + } + SAMPLE_LOGI("ID = %{public}s", idStr); + std::string id(idStr); + SampleXComponent *render = SampleXComponent().GetInstance(id); + if (render != nullptr) { + OH_DisplaySoloist_Destroy(g_displaySync[id]); + g_displaySync.erase(id); + SAMPLE_LOGI("NapiUnregister executed"); + } else { + SAMPLE_LOGE("render is nullptr"); + } + return nullptr; +} + +SampleXComponent::~SampleXComponent() +{ + OH_Drawing_BrushDestroy(cBrush_); + cBrush_ = nullptr; + OH_Drawing_PenDestroy(cPen_); + cPen_ = nullptr; + OH_Drawing_PathDestroy(cPath_); + cPath_ = nullptr; + OH_Drawing_CanvasDestroy(cCanvas_); + cCanvas_ = nullptr; + OH_Drawing_BitmapDestroy(cBitmap_); + cBitmap_ = nullptr; + + buffer_ = nullptr; + bufferHandle_ = nullptr; + nativeWindow_ = nullptr; + mappedAddr_ = nullptr; +} + +void SampleXComponent::Destroy() +{ + OH_Drawing_BrushDestroy(cBrush_); + cBrush_ = nullptr; + OH_Drawing_PenDestroy(cPen_); + cPen_ = nullptr; + OH_Drawing_PathDestroy(cPath_); + cPath_ = nullptr; + OH_Drawing_CanvasDestroy(cCanvas_); + cCanvas_ = nullptr; + OH_Drawing_BitmapDestroy(cBitmap_); + cBitmap_ = nullptr; +} + +void SampleXComponent::Release(std::string &id) +{ + SampleXComponent *render = SampleXComponent::GetInstance(id); + if (render != nullptr) { + delete render; + render = nullptr; + g_instance.erase(g_instance.find(id)); + } +} + +void SampleXComponent::Export(napi_env env, napi_value exports) +{ + if ((env == nullptr) || (exports == nullptr)) { + SAMPLE_LOGE("Export: env or exports is null"); + return; + } + napi_property_descriptor desc[] = { + {"register", nullptr, SampleXComponent::NapiRegister, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"unregister", nullptr, SampleXComponent::NapiUnregister, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"destroy", nullptr, SampleXComponent::NapiDestroy, nullptr, nullptr, nullptr, napi_default, nullptr}}; + + if (napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc) != napi_ok) { + SAMPLE_LOGE("Export: napi_define_properties failed"); + } +} + +void SampleXComponent::RegisterCallback(OH_NativeXComponent *nativeXComponent) +{ + SAMPLE_LOGI("register callback"); + renderCallback_.OnSurfaceCreated = OnSurfaceCreatedCB; + renderCallback_.OnSurfaceDestroyed = OnSurfaceDestroyedCB; + // Callback must be initialized + renderCallback_.DispatchTouchEvent = nullptr; + renderCallback_.OnSurfaceChanged = nullptr; + OH_NativeXComponent_RegisterCallback(nativeXComponent, &renderCallback_); +} + +SampleXComponent *SampleXComponent::GetInstance(std::string &id) +{ + if (g_instance.find(id) == g_instance.end()) { + SampleXComponent *render = new SampleXComponent(id); + g_instance[id] = render; + return render; + } else { + return g_instance[id]; + } +} \ No newline at end of file diff --git a/graphic/DisplaySoloist/entry/src/main/cpp/samples/sample_xcomponent.h b/graphic/DisplaySoloist/entry/src/main/cpp/samples/sample_xcomponent.h new file mode 100644 index 0000000000000000000000000000000000000000..926d45738ff1e2a9b077ce6af42fc9bc5b4e866c --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/main/cpp/samples/sample_xcomponent.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SAMPLE_XCOMPONENT_H +#define SAMPLE_XCOMPONENT_H +// [Start display_soloist_import_module] +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "napi/native_api.h" +// [End display_soloist_import_module] + +class SampleXComponent { +public: + SampleXComponent() = default; + ~SampleXComponent(); + explicit SampleXComponent(std::string id) : id_(id) {} + static napi_value NapiRegister(napi_env env, napi_callback_info info); + static napi_value NapiUnregister(napi_env env, napi_callback_info info); + static napi_value NapiDestroy(napi_env env, napi_callback_info info); + static void Release(std::string &id); + void DrawPath(); + void SetWidth(uint64_t width); + void SetHeight(uint64_t height); + void SetNativeWindow(OHNativeWindow *nativeWindow); + OHNativeWindow *GetNativeWindow(); + + void Prepare(); + void Create(); + void DisPlay(); + void ConstructPath(int x, int y, int offsetY); + void SetPenAndBrush(); + void Export(napi_env env, napi_value exports); + void RegisterCallback(OH_NativeXComponent *nativeXComponent); + void Destroy(); + static SampleXComponent *GetInstance(std::string &id); + std::string id_; + int defaultOffsetY = 100; + +private: + OH_NativeXComponent_Callback renderCallback_; + + uint64_t width_ = 0; + uint64_t height_ = 0; + + float aX = 0.0; + float aY = 0.0; + float bX = 80.0; + float cY = 0.0; + bool desc = false; + + OH_Drawing_Bitmap *cBitmap_ = nullptr; + OH_Drawing_Canvas *cCanvas_ = nullptr; + + OH_Drawing_Path *cPath_ = nullptr; + OH_Drawing_Brush *cBrush_ = nullptr; + OH_Drawing_Pen *cPen_ = nullptr; + OHNativeWindow *nativeWindow_ = nullptr; + uint32_t *mappedAddr_ = nullptr; + BufferHandle *bufferHandle_ = nullptr; + struct NativeWindowBuffer *buffer_ = nullptr; + int fenceFd_ = 0; +}; + +#endif diff --git a/graphic/DisplaySoloist/entry/src/main/cpp/types/libentry/index.d.ts b/graphic/DisplaySoloist/entry/src/main/cpp/types/libentry/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..72ce2401dc0c60c025d5880dd31761145681f152 --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/main/cpp/types/libentry/index.d.ts @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const add: (a: number, b: number) => number; \ No newline at end of file diff --git a/graphic/DisplaySoloist/entry/src/main/cpp/types/libentry/oh-package.json5 b/graphic/DisplaySoloist/entry/src/main/cpp/types/libentry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..8170db317fc4492825f16f80c00f92bf050d554e --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/main/cpp/types/libentry/oh-package.json5 @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "name": "libentry.so", + "types": "./index.d.ts", + "version": "", + "description": "Please describe the basic information." +} \ No newline at end of file diff --git a/graphic/DisplaySoloist/entry/src/main/ets/entryability/EntryAbility.ets b/graphic/DisplaySoloist/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..1f6370af7c021fe7cd5a2367babcf15706a18bfb --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/main/ets/entryability/EntryAbility.ets @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { window } from '@kit.ArkUI'; + +export default class EntryAbility extends UIAbility { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); + } + + onDestroy(): void { + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); + } + + onWindowStageCreate(windowStage: window.WindowStage): void { + // Main window is created, set main page for this ability + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + + windowStage.loadContent('pages/Index', (err) => { + if (err.code) { + hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); + return; + } + hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.'); + }); + } + + onWindowStageDestroy(): void { + // Main window is destroyed, release UI related resources + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); + } + + onForeground(): void { + // Ability has brought to foreground + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); + } + + onBackground(): void { + // Ability has back to background + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); + } +}; diff --git a/graphic/DisplaySoloist/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/graphic/DisplaySoloist/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..be794f48ccffc46278e76ce3493088a647b0d470 --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit'; + +export default class EntryBackupAbility extends BackupExtensionAbility { + async onBackup() { + hilog.info(0x0000, 'testTag', 'onBackup ok'); + } + + async onRestore(bundleVersion: BundleVersion) { + hilog.info(0x0000, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); + } +} \ No newline at end of file diff --git a/graphic/DisplaySoloist/entry/src/main/ets/interface/XComponentContext.ts b/graphic/DisplaySoloist/entry/src/main/ets/interface/XComponentContext.ts new file mode 100644 index 0000000000000000000000000000000000000000..02bc5d0d38229b5aed260bcf900057b86194059b --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/main/ets/interface/XComponentContext.ts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// [Start display_soloist_export_interface_xcomponent_context] +export default interface XComponentContext { + register(): void; + + unregister(): void; + + destroy(): void; +}; +// [End display_soloist_export_interface_xcomponent_context] diff --git a/graphic/DisplaySoloist/entry/src/main/ets/pages/Index.ets b/graphic/DisplaySoloist/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..6d29fe87e7ef05fbbf6faac861b34e3c320e57ba --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// [Start display_soloist_create_xcomponent] +import XComponentContext from '../interface/XComponentContext'; +import Logger from '../utils/Logger'; + +const TAG = '[XComponentDisplaySoloist]'; + +@Entry +@Component +struct Index { + private xComponentContext1: XComponentContext | undefined = undefined; + private xComponentContext2: XComponentContext | undefined = undefined; + + // [StartExclude display_soloist_create_xcomponent] + // [Start display_soloist_disappear] + aboutToDisappear(): void { + Logger.info(TAG, 'aboutToDisappear'); + if (this.xComponentContext1) { + this.xComponentContext1.unregister(); + this.xComponentContext1.destroy(); + } + if (this.xComponentContext2) { + this.xComponentContext2.unregister(); + this.xComponentContext2.destroy(); + } + } + // [End display_soloist_disappear] + // [EndExclude display_soloist_create_xcomponent] + + build() { + Column() { + Row() { + // [StartExclude display_soloist_create_xcomponent] + Text('30fps') + .fontWeight(FontWeight.Bold) + .fontSize(12) + .fontColor(Color.Red) + .textAlign(TextAlign.End) + .width(40) + .height(30) + // [EndExclude display_soloist_create_xcomponent] + + XComponent({ + id: 'xcomponentId_30', + type: XComponentType.SURFACE, + libraryname: 'entry' + }) + .onLoad((xComponentContext) => { + this.xComponentContext1 = xComponentContext as XComponentContext; + }).width('640px') + .backgroundColor(Color.White) + }.height('40%') + + Row() { + // [StartExclude display_soloist_create_xcomponent] + Text('120fps') + .fontWeight(FontWeight.Bold) + .fontSize(12) + .fontColor(Color.Red) + .textAlign(TextAlign.End) + .width(40) + .height(30) + // [EndExclude display_soloist_create_xcomponent] + + XComponent({ + id: 'xcomponentId_120', + type: XComponentType.SURFACE, + libraryname: 'entry' + }) + .onLoad((xComponentContext) => { + this.xComponentContext2 = xComponentContext as XComponentContext; + }).width('640px') + .backgroundColor(Color.White) + }.height('40%') + // [End display_soloist_create_xcomponent] + + // [Start display_soloist_start_and_stop] + Row() { + Button('Start') + .id('Start') + .fontSize(14) + .fontWeight(500) + .margin({ bottom: 20, right: 6, left: 6 }) + .onClick(() => { + if (this.xComponentContext1) { + this.xComponentContext1.register(); + } + if (this.xComponentContext2) { + this.xComponentContext2.register(); + } + }) + .width('30%') + .height(40) + .shadow(ShadowStyle.OUTER_DEFAULT_LG) + + Button('Stop') + .id('Stop') + .fontSize(14) + .fontWeight(500) + .margin({ bottom: 20, left: 6 }) + .onClick(() => { + if (this.xComponentContext1) { + this.xComponentContext1.unregister(); + } + if (this.xComponentContext2) { + this.xComponentContext2.unregister(); + } + }) + .width('30%') + .height(40) + .shadow(ShadowStyle.OUTER_DEFAULT_LG) + + } + .justifyContent(FlexAlign.SpaceEvenly) + .width('100%') + .height('20%') + // [End display_soloist_start_and_stop] + } + } +} \ No newline at end of file diff --git a/graphic/DisplaySoloist/entry/src/main/ets/utils/Logger.ets b/graphic/DisplaySoloist/entry/src/main/ets/utils/Logger.ets new file mode 100644 index 0000000000000000000000000000000000000000..985faa3befd8c79682b75decee602bdcacc9f184 --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/main/ets/utils/Logger.ets @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import hilog from '@ohos.hilog'; + +class Logger { + private domain: number; + private prefix: string; + private format: string = '%{public}s, %{public}s'; + + constructor(prefix: string) { + this.prefix = prefix; + this.domain = 0xFF00; + } + + debug(...args: string[]) { + hilog.debug(this.domain, this.prefix, this.format, args); + } + + info(...args: string[]) { + hilog.info(this.domain, this.prefix, this.format, args); + } + + warn(...args: string[]) { + hilog.warn(this.domain, this.prefix, this.format, args); + } + + error(...args: string[]) { + hilog.error(this.domain, this.prefix, this.format, args); + } +} + +export default new Logger('[Sample_DisplaySoloist]'); \ No newline at end of file diff --git a/graphic/DisplaySoloist/entry/src/main/module.json5 b/graphic/DisplaySoloist/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..ca3c9ba3157fbb51f3b8cba57252aee35e6203d0 --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/main/module.json5 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "module": { + "name": "entry", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "EntryAbility", + "deviceTypes": [ + "default", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "abilities": [ + { + "name": "EntryAbility", + "srcEntry": "./ets/entryability/EntryAbility.ets", + "description": "$string:EntryAbility_desc", + "icon": "$media:layered_image", + "label": "$string:EntryAbility_label", + "startWindowIcon": "$media:startIcon", + "startWindowBackground": "$color:start_window_background", + "exported": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ], + "extensionAbilities": [ + { + "name": "EntryBackupAbility", + "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets", + "type": "backup", + "exported": false, + "metadata": [ + { + "name": "ohos.extension.backup", + "resource": "$profile:backup_config" + } + ] + } + ] + } +} \ No newline at end of file diff --git a/graphic/DisplaySoloist/entry/src/main/resources/base/element/color.json b/graphic/DisplaySoloist/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02 --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/main/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + } + ] +} \ No newline at end of file diff --git a/graphic/DisplaySoloist/entry/src/main/resources/base/element/string.json b/graphic/DisplaySoloist/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..7d5308ce719b744fc52c655c8d2b40fcd434cb44 --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/main/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "Sample_DisplaySoloist" + } + ] +} \ No newline at end of file diff --git a/graphic/DisplaySoloist/entry/src/main/resources/base/media/background.png b/graphic/DisplaySoloist/entry/src/main/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..f939c9fa8cc8914832e602198745f592a0dfa34d Binary files /dev/null and b/graphic/DisplaySoloist/entry/src/main/resources/base/media/background.png differ diff --git a/graphic/DisplaySoloist/entry/src/main/resources/base/media/foreground.png b/graphic/DisplaySoloist/entry/src/main/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..4483ddad1f079e1089d685bd204ee1cfe1d01902 Binary files /dev/null and b/graphic/DisplaySoloist/entry/src/main/resources/base/media/foreground.png differ diff --git a/graphic/DisplaySoloist/entry/src/main/resources/base/media/layered_image.json b/graphic/DisplaySoloist/entry/src/main/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..4f9ad6307a2bc56beb6d0fce0a49cbf213b20a74 --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/main/resources/base/media/layered_image.json @@ -0,0 +1,6 @@ +{ + "layered-image": { + "background": "$media:background", + "foreground": "$media:foreground" + } +} \ No newline at end of file diff --git a/graphic/DisplaySoloist/entry/src/main/resources/base/media/startIcon.png b/graphic/DisplaySoloist/entry/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b Binary files /dev/null and b/graphic/DisplaySoloist/entry/src/main/resources/base/media/startIcon.png differ diff --git a/graphic/DisplaySoloist/entry/src/main/resources/base/profile/backup_config.json b/graphic/DisplaySoloist/entry/src/main/resources/base/profile/backup_config.json new file mode 100644 index 0000000000000000000000000000000000000000..78f40ae7c494d71e2482278f359ec790ca73471a --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/main/resources/base/profile/backup_config.json @@ -0,0 +1,3 @@ +{ + "allowToBackupRestore": true +} \ No newline at end of file diff --git a/graphic/DisplaySoloist/entry/src/main/resources/base/profile/main_pages.json b/graphic/DisplaySoloist/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..1898d94f58d6128ab712be2c68acc7c98e9ab9ce --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,5 @@ +{ + "src": [ + "pages/Index" + ] +} diff --git a/graphic/DisplaySoloist/entry/src/main/resources/en_US/element/string.json b/graphic/DisplaySoloist/entry/src/main/resources/en_US/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..7d5308ce719b744fc52c655c8d2b40fcd434cb44 --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/main/resources/en_US/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "Sample_DisplaySoloist" + } + ] +} \ No newline at end of file diff --git a/graphic/DisplaySoloist/entry/src/main/resources/zh_CN/element/string.json b/graphic/DisplaySoloist/entry/src/main/resources/zh_CN/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..314e0029f8d5a580142040c3fbd9f063faa6bc83 --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/main/resources/zh_CN/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "模块描述" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "Sample_DisplaySoloist" + } + ] +} \ No newline at end of file diff --git a/graphic/DisplaySoloist/entry/src/mock/Libentry.mock.ets b/graphic/DisplaySoloist/entry/src/mock/Libentry.mock.ets new file mode 100644 index 0000000000000000000000000000000000000000..44d5c96308f6f1f6d4a0919017a153c648a1db8e --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/mock/Libentry.mock.ets @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +const nativeMock: Record = { + 'add': (a: number, b: number) => { + return a + b; + }, +}; + +export default nativeMock; \ No newline at end of file diff --git a/graphic/DisplaySoloist/entry/src/mock/mock-config.json5 b/graphic/DisplaySoloist/entry/src/mock/mock-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..a1e6f06e0cbdf8485bcab6838e9f88ea81ef5a2b --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/mock/mock-config.json5 @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "libentry.so": { + "source": "src/mock/Libentry.mock.ets" + } +} \ No newline at end of file diff --git a/graphic/DisplaySoloist/entry/src/ohosTest/ets/test/Ability.test.ets b/graphic/DisplaySoloist/entry/src/ohosTest/ets/test/Ability.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..8648e182ac088cd3b30d9bdd713028b0e6a29aba --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/ohosTest/ets/test/Ability.test.ets @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { beforeAll, describe, expect, it } from '@ohos/hypium'; +import { abilityDelegatorRegistry, Driver, ON } from '@kit.TestKit'; +import Logger from '../utils/Logger'; + +const TAG = '[Sample_DisplaySoloist]'; +const BUNDLE = 'MyApp_' +const bundleName = abilityDelegatorRegistry.getArguments().bundleName; +const DELAYMS_1S = 1000; +const DELAYMS_5S = 5000; + +export default function abilityTest() { + describe('AbilityTest', () => { + beforeAll(async (done: Function) => { + Logger.info(TAG, BUNDLE + 'StartAbility_001, begin'); + let abilityDelegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator(); + try { + await abilityDelegator.startAbility({ + bundleName: bundleName, + abilityName: 'EntryAbility' + }); + } catch (err) { + Logger.info(TAG, `beforeAll exception = ${JSON.stringify(err)}`); + } + + Logger.info(TAG, BUNDLE + 'StartAbility_001, end'); + done(); + }); + + /** + * @tc.number:SUB_GRAPHIC_2D_HGM_DISPLAYSOLOIST_0100 + * @tc.name:DisplaySoloist_001 + * @tc.desc:DisplaySoloist + * @tc.size:MediumTest + * @tc.type:Function + * @tc.level:Level 1 + */ + it(BUNDLE + 'DisplaySoloist_001', 0, async (done: Function) => { + try { + Logger.info(TAG, BUNDLE + 'DisplaySoloist_001 begin'); + + let driver = Driver.create(); + await driver.delayMs(DELAYMS_1S); + + await driver.assertComponentExist(ON.id('Start')); + let startButton = await driver.findComponent(ON.id('Start')); + await startButton.click(); + await driver.delayMs(DELAYMS_5S); + + await driver.assertComponentExist(ON.id('Stop')); + let stopButton = await driver.findComponent(ON.id('Stop')); + await stopButton.click(); + await driver.delayMs(DELAYMS_1S); + + Logger.info(TAG, BUNDLE + 'DisplaySoloist_001 end'); + done(); + } catch (error) { + Logger.info(TAG, `DisplaySoloist_001 exception = ${JSON.stringify(error)}`); + expect().assertFail(); + } + }); + }) +} \ No newline at end of file diff --git a/graphic/DisplaySoloist/entry/src/ohosTest/ets/test/List.test.ets b/graphic/DisplaySoloist/entry/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..3be23423391686fa8b1926d5a874e3bda4798df3 --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/ohosTest/ets/test/List.test.ets @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import abilityTest from './Ability.test'; + +export default function testsuite() { + abilityTest(); +} \ No newline at end of file diff --git a/graphic/DisplaySoloist/entry/src/ohosTest/ets/utils/Logger.ets b/graphic/DisplaySoloist/entry/src/ohosTest/ets/utils/Logger.ets new file mode 100644 index 0000000000000000000000000000000000000000..01dc553e4ddf4ced95d8aee5d37f28be94d48556 --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/ohosTest/ets/utils/Logger.ets @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import hilog from '@ohos.hilog'; + +class Logger { + private domain: number = 0xF811; + private prefix: string = ''; + private format: string = '%{public}s, %{public}s'; + + constructor(prefix: string) { + this.prefix = prefix; + this.domain = 0xF811; + } + + debug(...args: string[]): void { + hilog.debug(this.domain, this.prefix, this.format, args); + } + + info(...args: string[]): void { + hilog.info(this.domain, this.prefix, this.format, args); + } + + warn(...args: string[]): void { + hilog.warn(this.domain, this.prefix, this.format, args); + } + + error(...args: string[]): void { + hilog.error(this.domain, this.prefix, this.format, args); + } +} + +export default new Logger('[Sample_DisplaySoloist]'); \ No newline at end of file diff --git a/graphic/DisplaySoloist/entry/src/ohosTest/module.json5 b/graphic/DisplaySoloist/entry/src/ohosTest/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..944ed99859bbc89eac2d57af2b3600881bb5a47c --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/ohosTest/module.json5 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "module": { + "name": "entry_test", + "type": "feature", + "deviceTypes": [ + "default", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false + } +} diff --git a/graphic/DisplaySoloist/entry/src/test/List.test.ets b/graphic/DisplaySoloist/entry/src/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..3bc7c739d1957b3a778de67db8992240584b6692 --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/test/List.test.ets @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import localUnitTest from './LocalUnit.test'; + +export default function testsuite() { + localUnitTest(); +} \ No newline at end of file diff --git a/graphic/DisplaySoloist/entry/src/test/LocalUnit.test.ets b/graphic/DisplaySoloist/entry/src/test/LocalUnit.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..1d9c6cdccf0c5b68b0684adbd304a41888ea9e9c --- /dev/null +++ b/graphic/DisplaySoloist/entry/src/test/LocalUnit.test.ets @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from '@ohos/hypium'; + +export default function localUnitTest() { + describe('localUnitTest', () => { + // Defines a test suite. Two parameters are supported: test suite name and test suite function. + beforeAll(() => { + // Presets an action, which is performed only once before all test cases of the test suite start. + // This API supports only one parameter: preset action function. + }); + beforeEach(() => { + // Presets an action, which is performed before each unit test case starts. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: preset action function. + }); + afterEach(() => { + // Presets a clear action, which is performed after each unit test case ends. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: clear action function. + }); + afterAll(() => { + // Presets a clear action, which is performed after all test cases of the test suite end. + // This API supports only one parameter: clear action function. + }); + it('assertContain', 0, () => { + // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. + let a = 'abc'; + let b = 'b'; + // Defines a variety of assertion methods, which are used to declare expected boolean conditions. + expect(a).assertContain(b); + expect(a).assertEqual(a); + }); + }); +} \ No newline at end of file diff --git a/graphic/DisplaySoloist/hvigor/hvigor-config.json5 b/graphic/DisplaySoloist/hvigor/hvigor-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..87990affc4f62f7c76c246428c40272d3be0a7c7 --- /dev/null +++ b/graphic/DisplaySoloist/hvigor/hvigor-config.json5 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "modelVersion": "5.0.0", + "dependencies": { + }, + "execution": { + // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | false ]. Default: "normal" */ + // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */ + // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */ + // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */ + // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */ + }, + "logging": { + // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */ + }, + "debugging": { + // "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */ + }, + "nodeOptions": { + // "maxOldSpaceSize": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/ + // "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/ + } +} diff --git a/graphic/DisplaySoloist/hvigorfile.ts b/graphic/DisplaySoloist/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..b74abd874f6bb24520d387f59036a41df1dde68a --- /dev/null +++ b/graphic/DisplaySoloist/hvigorfile.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { appTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins: [] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/graphic/DisplaySoloist/oh-package.json5 b/graphic/DisplaySoloist/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..7a7fe7781e61280b6e0a6f437d4a7a6a41b2afcd --- /dev/null +++ b/graphic/DisplaySoloist/oh-package.json5 @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "modelVersion": "5.0.0", + "description": "Please describe the basic information.", + "dependencies": { + }, + "devDependencies": { + "@ohos/hypium": "1.0.19", + "@ohos/hamock": "1.0.0" + } +} diff --git a/graphic/DisplaySoloist/ohosTest.md b/graphic/DisplaySoloist/ohosTest.md new file mode 100644 index 0000000000000000000000000000000000000000..0f0434f97e281105559249a8032a213e74af275a --- /dev/null +++ b/graphic/DisplaySoloist/ohosTest.md @@ -0,0 +1,13 @@ +# DisplaySoloist测试用例归档 + +## 用例表 + +| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 | +|------|--------|-------------------|------------------------------|------|------| +| 拉起应用 | 设备正常运行 | | 成功拉起应用 | 是 | Pass | +| 按钮点击 | 位于主页 | 点击 30hz 右侧 Start | 方块按照 30hz 频率移动,同时按钮显示为 Stop | 是 | Pass | +| 按钮点击 | 位于主页 | 点击 30hz 右侧 Stop | 方块停止移动,同时按钮显示为 Start | 是 | Pass | +| 按钮点击 | 位于主页 | 点击 60hz 右侧 Start | 方块按照 60hz 频率移动,同时按钮显示为 Stop | 是 | Pass | +| 按钮点击 | 位于主页 | 点击 60hz 右侧 Stop | 方块停止移动,同时按钮显示为 Start | 是 | Pass | +| 按钮点击 | 位于主页 | 点击 120hz 右侧 Start | 方块按照 120hz 频率移动,同时按钮显示为 Stop | 是 | Pass | +| 按钮点击 | 位于主页 | 点击 120hz 右侧 Stop | 方块停止移动,同时按钮显示为 Start | 是 | Pass | \ No newline at end of file diff --git a/graphic/DisplaySoloist/screenshots/device/index.png b/graphic/DisplaySoloist/screenshots/device/index.png new file mode 100644 index 0000000000000000000000000000000000000000..1eacc005d89abe95a1f1e3faee98196afd3e94ff Binary files /dev/null and b/graphic/DisplaySoloist/screenshots/device/index.png differ diff --git a/graphic/DisplaySync/.gitignore b/graphic/DisplaySync/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..08d606210b3993e8f1f4535767bb3459b7b1d208 --- /dev/null +++ b/graphic/DisplaySync/.gitignore @@ -0,0 +1,13 @@ +/node_modules +/oh_modules +/local.properties +/.idea +**/build +/.hvigor +.cxx +/.clangd +/.clang-format +/.clang-tidy +**/.test +/.appanalyzer +/oh-package-lock.json5 \ No newline at end of file diff --git a/graphic/DisplaySync/AppScope/app.json5 b/graphic/DisplaySync/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..4a01f308a8af6cbae4932e82d7270c9c39fd3a82 --- /dev/null +++ b/graphic/DisplaySync/AppScope/app.json5 @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "app": { + "bundleName": "com.samples.displaysync", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name" + } +} diff --git a/graphic/DisplaySync/AppScope/resources/base/element/string.json b/graphic/DisplaySync/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..ba13327659cfcbc5e31f01e3ab118d7c90683ef4 --- /dev/null +++ b/graphic/DisplaySync/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "DisplaySync" + } + ] +} diff --git a/graphic/DisplaySync/AppScope/resources/base/media/app_icon.png b/graphic/DisplaySync/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a39445dc87828b76fed6d2ec470dd455c45319e3 Binary files /dev/null and b/graphic/DisplaySync/AppScope/resources/base/media/app_icon.png differ diff --git a/graphic/DisplaySync/README.md b/graphic/DisplaySync/README.md new file mode 100644 index 0000000000000000000000000000000000000000..eb6af3b663d27143a5217104b1cd28bab57ff397 --- /dev/null +++ b/graphic/DisplaySync/README.md @@ -0,0 +1,114 @@ +# DisplaySync + +### 介绍 + +本示例通过 DisplaySync 系列功能,对请求动画绘制帧率、请求 UI 绘制帧率和请求自绘制内容绘制帧率设置开发者所期望的帧率。 + +本示例主要展示了 DisplaySync 系列能力,使用 [ExpectedFrameRateRange](https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/reference/apis-arkui/arkui-ts/ts-explicit-animation.md#expectedframeraterange11) 属性来配置显性动画和属性动画的帧率;利用 [@ohos.graphics.displaySync](https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/reference/apis-arkgraphics2d/js-apis-graphics-displaySync.md) 方法来为独立的帧率绘制、更新操作UI界面;采用 [XComponent](https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/ui/napi-xcomponent-guidelines.md) 组件进行开发,从而可以请求独立的绘制帧率进行内容开发。 + +### 效果预览 + +| 初始页 | 请求动画绘制帧率 | 请求 UI 绘制帧率 | 请求自绘制内容绘制帧率 | +|:--------------------------------------------------------:|:------------------------------------------------------------:|:----------------------------------------------------:|:-------------------------------------------------------------:| +| | | | | + +使用说明 + +1.在初始页面点击“**Requesting Frame Rates for Animations**”,进入请求动画绘制帧率页面,点击“**Start**”,三个方块分别按照30Hz、40Hz、60Hz移动;点击“**Back**”返回初始页面。 + +2.在初始页面点击“**Requesting Frame Rates for UI Components**”,进入请求 UI 绘制帧率页面,点击“**Start**”,数字“**30**”按照30Hz帧率放大缩小,数字“**60**”按照60Hz帧率放大缩小;点击“**Stop**”绘制停止;点击“**Back**”返回初始页面。 + +3.在初始页面点击“**Requesting Frame Rates for Custom Content**”,进入请求自绘制内容绘制帧率页面,点击“**Start**”,两个方块分别按照30Hz、120Hz移动;点击“**Stop**”动画停止;点击“**Back**”返回初始页面。 + +### 工程目录 + +``` +├──entry/src/main +│ ├──cpp // C++代码区 +│ │ ├──CMakeLists.txt // CMake配置文件 +│ │ ├──napi_init.cpp // Napi模块注册 +│ │ ├──common +│ │ │ └──log_common.h // 日志封装定义文件 +│ │ ├──plugin // 生命周期管理模块 +│ │ │ ├──plugin_manager.cpp +│ │ │ └──plugin_manager.h +│ │ ├──samples // samples渲染模块 +│ │ │ ├──sample_xcomponent.cpp +│ │ │ └──sample_xcomponent.h +│ ├──ets // ets代码区 +│ │ ├──entryability +│ │ │ ├──EntryAbility.ts // 程序入口类 +| | | └──EntryAbility.ets +| | ├──interface +│ │ │ └──XComponentContext.ts // XComponentContext +│ │ ├──DispalySync // 业务页面目录 +│ │ | ├──PropertyAnimationDisplaySync.ets // 属性动画页面 +│ │ | ├──CustomDrawDisplaySync.ets // 自绘制页面 +│ │ | ├──XComponentDisplaySync.ets // XComponent页面 +│ │ ├──pages // 页面文件 +│ │ | ├──Index.ets // 初始页面 +│ │ ├──utils // 工具类 +| ├──resources // 资源文件目录 +``` + +### 具体实现 + +* 请求动画绘制帧率:通过 animation 和 animateTo 接口的参数——expectedFrameRateRange,来设置动画刷新率区间、预期刷新率。其作为动画的属性之一,主要作用于动画场景。 + + * 涉及到的相关接口: + + | 新增动画属性 | 描述 | + | :--------------------: | :----------------------------------------------------------: | + | expectedFrameRateRange | animation和animateTo接口的动画属性参数中可选配置expectedFrameRateRange参数 | +* 请求 UI 绘制帧率:通过调用 [@ohos.graphics.displaySync ](https://docs.openharmony.cn/pages/v4.1/zh-cn/application-dev/reference/apis-arkgraphics2d/js-apis-graphics-displaySync.md)接口,来注册回调和设置刷新区间并控制回调周期。 + + * 涉及到的相关接口: + + 通过 `import displaySync from '@ohos.graphics.displaySync` 表达式引入, + + | 接口名 | 描述 | + | ------------------------------------------------------------ | -------------------------- | + | Create(): DisplaySync | 创建一个DisplaySync实例 | + | setExpectedFrameRateRange(rateRange: ExpectedFrameRateRange): void | 设置期望帧率 | + | on(type: 'frame', callback: Callback): void | 设置自定义绘制内容回调函数 | + | off(type: 'frame', callback?: Callback): void | 清除自定义绘制内容回调函数 | + | start(): void | DisplaySync使能 | + | stop(): void | DisplaySync失能 | + +* 请求自绘制内容绘制帧率:通过在 IDE 中的 Native c++ 工程,在 c++ 代码中定义对外接口为 register 和 unregister,并调用新增的 CAPI 接口,可在页面上使用 drawing 根据设定的期望帧率来绘制。 + + | 接口名 | 描述 | + | --------------------------------------------- | ---------------- | + | OH_NativeXComponent_SetExpectedFrameRateRange | 设置期望帧率范围 | + | OH_NativeXComponent_RegisterOnFrameCallback | 注册更新回调 | + | OH_NativeXComponent_UnregisterOnFrameCallback | 取消更新回调 | + +### 相关权限 + +不涉及。 + +### 依赖 + +不涉及。 + +### 约束与限制 + +1. 本示例仅支持标准系统上运行,支持设备:华为手机。 + +2. HarmonyOS系统:HarmonyOS 5.0.2 Release及以上。 + +3. DevEco Studio版本:DevEco Studio 5.0.2 Release及以上。 + +4. HarmonyOS SDK版本:HarmonyOS 5.0.2 Release及以上。 + +### 下载 + +如需单独下载本工程,执行如下命令: + +``` +git init +git config core.sparsecheckout true +echo code/DocsSample/graphic/DisplaySync/ > .git/info/sparse-checkout +git remote add origin https://gitcode.com/openharmony/applications_app_samples.git +git pull origin master +``` \ No newline at end of file diff --git a/graphic/DisplaySync/build-profile.json5 b/graphic/DisplaySync/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..590145ac3d80c83b0197ada84ece1e876571e1f7 --- /dev/null +++ b/graphic/DisplaySync/build-profile.json5 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "app": { + "products": [ + { + "name": "default", + "signingConfig": "default", + "compatibleSdkVersion": "5.0.2(14)", + "targetSdkVersion": "5.0.2(14)", + "runtimeOS": "HarmonyOS", + "buildOption": { + "externalNativeOptions": { + "abiFilters": [ + "arm64-v8a", + "x86_64" + ] + } + } + } + ], + "buildModeSet": [ + { + "name": "debug" + }, + { + "name": "release" + } + ], + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/graphic/DisplaySync/code-linter.json5 b/graphic/DisplaySync/code-linter.json5 new file mode 100644 index 0000000000000000000000000000000000000000..3311c9280cd317b17b4b2745922184ac805051d8 --- /dev/null +++ b/graphic/DisplaySync/code-linter.json5 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "files": [ + "**/*.ets" + ], + "ignore": [ + "**/src/ohosTest/**/*", + "**/src/test/**/*", + "**/src/mock/**/*", + "**/node_modules/**/*", + "**/oh_modules/**/*", + "**/build/**/*", + "**/.preview/**/*" + ], + "ruleSet": [ + "plugin:@performance/recommended", + "plugin:@typescript-eslint/recommended" + ], + "rules": { + } +} \ No newline at end of file diff --git a/graphic/DisplaySync/entry/.gitignore b/graphic/DisplaySync/entry/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5 --- /dev/null +++ b/graphic/DisplaySync/entry/.gitignore @@ -0,0 +1,6 @@ +/node_modules +/oh_modules +/.preview +/build +/.cxx +/.test \ No newline at end of file diff --git a/graphic/DisplaySync/entry/build-profile.json5 b/graphic/DisplaySync/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..9e8e21e08d3eb74b86a0d190c9a29a7994bae19c --- /dev/null +++ b/graphic/DisplaySync/entry/build-profile.json5 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "apiType": "stageMode", + "buildOption": { + "externalNativeOptions": { + "path": "./src/main/cpp/CMakeLists.txt", + "arguments": "", + "cppFlags": "", + } + }, + "buildOptionSet": [ + { + "name": "release", + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": false, + "files": [ + "./obfuscation-rules.txt" + ] + } + } + } + }, + ], + "targets": [ + { + "name": "default" + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/graphic/DisplaySync/entry/hvigorfile.ts b/graphic/DisplaySync/entry/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..03701040981658f09c62d2c71567bc38dda4d37e --- /dev/null +++ b/graphic/DisplaySync/entry/hvigorfile.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { hapTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins: [] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/graphic/DisplaySync/entry/obfuscation-rules.txt b/graphic/DisplaySync/entry/obfuscation-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..272efb6ca3f240859091bbbfc7c5802d52793b0b --- /dev/null +++ b/graphic/DisplaySync/entry/obfuscation-rules.txt @@ -0,0 +1,23 @@ +# Define project specific obfuscation rules here. +# You can include the obfuscation configuration files in the current module's build-profile.json5. +# +# For more details, see +# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5 + +# Obfuscation options: +# -disable-obfuscation: disable all obfuscations +# -enable-property-obfuscation: obfuscate the property names +# -enable-toplevel-obfuscation: obfuscate the names in the global scope +# -compact: remove unnecessary blank spaces and all line feeds +# -remove-log: remove all console.* statements +# -print-namecache: print the name cache that contains the mapping from the old names to new names +# -apply-namecache: reuse the given cache file + +# Keep options: +# -keep-property-name: specifies property names that you want to keep +# -keep-global-name: specifies names that you want to keep in the global scope + +-enable-property-obfuscation +-enable-toplevel-obfuscation +-enable-filename-obfuscation +-enable-export-obfuscation \ No newline at end of file diff --git a/graphic/DisplaySync/entry/oh-package.json5 b/graphic/DisplaySync/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..c2964381037433502863a5e14ed1c9ad5e267297 --- /dev/null +++ b/graphic/DisplaySync/entry/oh-package.json5 @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "name": "entry", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "", + "author": "", + "license": "", + "dependencies": {} +} + diff --git a/graphic/DisplaySync/entry/src/main/cpp/CMakeLists.txt b/graphic/DisplaySync/entry/src/main/cpp/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..cd73ec36d8c9197555560566981324534d12a49a --- /dev/null +++ b/graphic/DisplaySync/entry/src/main/cpp/CMakeLists.txt @@ -0,0 +1,20 @@ +# the minimum version of CMake. +cmake_minimum_required(VERSION 3.4.1) +project(drawing_test) + +set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) + +include_directories(${NATIVERENDER_ROOT_PATH} + ${NATIVERENDER_ROOT_PATH}/include) + +add_library(entry SHARED + napi_init.cpp + samples/sample_xcomponent.cpp + plugin/plugin_manager.cpp +) +find_library( + hilog-lib + hilog_ndk.z +) +target_link_libraries(entry PUBLIC ${hilog-lib}) +target_link_libraries(entry PUBLIC libace_napi.z.so libnative_drawing.so libnative_window.so libace_ndk.z.so) \ No newline at end of file diff --git a/graphic/DisplaySync/entry/src/main/cpp/common/log_common.h b/graphic/DisplaySync/entry/src/main/cpp/common/log_common.h new file mode 100644 index 0000000000000000000000000000000000000000..ab802e81de7a05b901da57cbb3e8f5de46180bfd --- /dev/null +++ b/graphic/DisplaySync/entry/src/main/cpp/common/log_common.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef LOG_COMMON_H +#define LOG_COMMON_H +#include +#define LOG_PRINT_DOMAIN 0xFF00 +#define APP_LOG_DOMAIN 0x0001 +constexpr const char *APP_LOG_TAG = "DisplaySyncSample"; +#define SAMPLE_LOGI(...) ((void)OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__)) +#define SAMPLE_LOGD(...) ((void)OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__)) +#define SAMPLE_LOGW(...) ((void)OH_LOG_Print(LOG_APP, LOG_WARN, LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__)) +#define SAMPLE_LOGE(...) ((void)OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__)) + +#endif // LOG_COMMON_H diff --git a/graphic/DisplaySync/entry/src/main/cpp/napi_init.cpp b/graphic/DisplaySync/entry/src/main/cpp/napi_init.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dc7146d1429eb6720309fb11a72cd6ab9326d341 --- /dev/null +++ b/graphic/DisplaySync/entry/src/main/cpp/napi_init.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "napi/native_api.h" +#include "plugin/plugin_manager.h" + +#undef LOG_DOMIN +#undef LOG_TAG +#define LOG_DOMIN 0X0000 +#define LOG_TAG "NAPI_INIT" + +EXTERN_C_START +static napi_value Init(napi_env env, napi_value exports) +{ + PluginManager::GetInstance()->Export(env, exports); + return exports; +} +EXTERN_C_END + +static napi_module demoModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Init, + .nm_modname = "entry", + .nm_priv = ((void *)0), + .reserved = {0}, +}; + +extern "C" __attribute__((constructor)) void RegisterEntryModule(void) +{ + napi_module_register(&demoModule); +} diff --git a/graphic/DisplaySync/entry/src/main/cpp/plugin/plugin_manager.cpp b/graphic/DisplaySync/entry/src/main/cpp/plugin/plugin_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d0f2741446449f4ef9bbc8ac3004b25647b559f9 --- /dev/null +++ b/graphic/DisplaySync/entry/src/main/cpp/plugin/plugin_manager.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include "common/log_common.h" +#include "plugin_manager.h" + +PluginManager *PluginManager::GetInstance() +{ + static PluginManager pluginManager; + return &pluginManager; +} + +PluginManager::~PluginManager() +{ + SAMPLE_LOGI("~PluginManager"); + for (auto iter = nativeXComponentMap_.begin(); iter != nativeXComponentMap_.end(); ++iter) { + if (iter->second != nullptr) { + delete iter->second; + iter->second = nullptr; + } + } + nativeXComponentMap_.clear(); + + for (auto iter = pluginRenderMap_.begin(); iter != pluginRenderMap_.end(); ++iter) { + if (iter->second != nullptr) { + delete iter->second; + iter->second = nullptr; + } + } + pluginRenderMap_.clear(); +} + +void PluginManager::Export(napi_env env, napi_value exports) +{ + nativeXComponentMap_.clear(); + pluginRenderMap_.clear(); + if ((env == nullptr) || (exports == nullptr)) { + SAMPLE_LOGE("Export: env or exports is null"); + return; + } + + napi_value exportInstance = nullptr; + if (napi_get_named_property(env, exports, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance) != napi_ok) { + SAMPLE_LOGE("Export: napi_get_named_property fail"); + return; + } + + OH_NativeXComponent *nativeXComponent = nullptr; + if (napi_unwrap(env, exportInstance, reinterpret_cast(&nativeXComponent)) != napi_ok) { + SAMPLE_LOGE("Export: napi_unwrap fail"); + return; + } + + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'}; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + if (OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + SAMPLE_LOGE("Export: OH_NativeXComponent_GetXComponentId fail"); + return; + } + + std::string id(idStr); + auto context = PluginManager::GetInstance(); + if ((context != nullptr) && (nativeXComponent != nullptr)) { + context->SetNativeXComponent(id, nativeXComponent); + auto render = context->GetRender(id); + if (render != nullptr) { + render->RegisterCallback(nativeXComponent); + render->Export(env, exports); + } else { + SAMPLE_LOGE("render is nullptr"); + } + } +} + +void PluginManager::SetNativeXComponent(std::string &id, OH_NativeXComponent *nativeXComponent) +{ + SAMPLE_LOGI("set native xComponent, ID = %{public}s.", id.c_str()); + if (nativeXComponent == nullptr) { + SAMPLE_LOGE("xcomponent null"); + return; + } + + if (nativeXComponentMap_.find(id) == nativeXComponentMap_.end()) { + nativeXComponentMap_[id] = nativeXComponent; + return; + } + + if (nativeXComponentMap_[id] != nativeXComponent) { + OH_NativeXComponent *tmp = nativeXComponentMap_[id]; + delete tmp; + tmp = nullptr; + nativeXComponentMap_[id] = nativeXComponent; + } +} + +SampleXComponent *PluginManager::GetRender(std::string &id) +{ + if (pluginRenderMap_.find(id) == pluginRenderMap_.end()) { + SampleXComponent *instance = SampleXComponent::GetInstance(id); + pluginRenderMap_[id] = instance; + return instance; + } + return pluginRenderMap_[id]; +} + diff --git a/graphic/DisplaySync/entry/src/main/cpp/plugin/plugin_manager.h b/graphic/DisplaySync/entry/src/main/cpp/plugin/plugin_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..37f2a91ac8088c6ef74d6440e98902a23e650f46 --- /dev/null +++ b/graphic/DisplaySync/entry/src/main/cpp/plugin/plugin_manager.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef PLUGIN_MANAGER_H +#define PLUGIN_MANAGER_H + +#include +#include +#include +#include +#include +#include "samples/sample_xcomponent.h" + +class PluginManager { +public: + ~PluginManager(); + + static PluginManager *GetInstance(); + + void SetNativeXComponent(std::string &id, OH_NativeXComponent *nativeXComponent); + SampleXComponent *GetRender(std::string &id); + void Export(napi_env env, napi_value exports); + +private: + std::unordered_map nativeXComponentMap_; + std::unordered_map pluginRenderMap_; +}; +#endif // PLUGIN_MANAGER_H diff --git a/graphic/DisplaySync/entry/src/main/cpp/samples/sample_xcomponent.cpp b/graphic/DisplaySync/entry/src/main/cpp/samples/sample_xcomponent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dae5962f7ae35a7ecacab6d8c5aa653a4d75c7cd --- /dev/null +++ b/graphic/DisplaySync/entry/src/main/cpp/samples/sample_xcomponent.cpp @@ -0,0 +1,435 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include "common/log_common.h" +#include "sample_xcomponent.h" + +static void OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window) +{ + SAMPLE_LOGI("OnSurfaceCreatedCB"); + if ((component == nullptr) || (window == nullptr)) { + SAMPLE_LOGE("OnSurfaceCreatedCB: component or window is null"); + return; + } + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'}; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + SAMPLE_LOGE("OnSurfaceCreatedCB: Unable to get XComponent id"); + return; + } + std::string id(idStr); + auto render = SampleXComponent::GetInstance(id); + OHNativeWindow *nativeWindow = static_cast(window); + render->SetNativeWindow(nativeWindow); + + uint64_t width; + uint64_t height; + int32_t xSize = OH_NativeXComponent_GetXComponentSize(component, window, &width, &height); + if ((xSize == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) && (render != nullptr)) { + render->SetHeight(height); + render->SetWidth(width); + SAMPLE_LOGI("xComponent width = %{public}lu, height = %{public}llu", width, height); + } +} + +static void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window) +{ + SAMPLE_LOGI("OnSurfaceDestroyedCB"); + if ((component == nullptr) || (window == nullptr)) { + SAMPLE_LOGE("OnSurfaceDestroyedCB: component or window is null"); + return; + } + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'}; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + SAMPLE_LOGE("OnSurfaceDestroyedCB: Unable to get XComponent id"); + return; + } + std::string id(idStr); + SampleXComponent::Release(id); +} + +// Start display_sync_napi_frame_rate_setting_and_subscription_function_registration] +static void TestCallback(OH_NativeXComponent *component, uint64_t timestamp, uint64_t targetTimestamp) +{ + SAMPLE_LOGI("test callback timestamp = %{public}llu, targetTimestamp = %{public}llu", timestamp, targetTimestamp); + if (component == nullptr) { + SAMPLE_LOGE("TestCallback: component is null"); + return; + } + + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'}; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + SAMPLE_LOGE("TestCallback: Unable to get XComponent id"); + return; + } + + std::string id(idStr); + auto render = SampleXComponent::GetInstance(id); + OHNativeWindow *nativeWindow = render->GetNativeWindow(); + uint64_t width; + uint64_t height; + + int32_t xSize = OH_NativeXComponent_GetXComponentSize(component, nativeWindow, &width, &height); + if ((xSize == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) && (render != nullptr)) { + render->Prepare(); + render->Create(); + if (id == "xcomponentId_30") { + int offset = 16; + render->ConstructPath(offset, offset, render->defaultOffsetY); + } + if (id == "xcomponentId_120") { + int offset = 4; + render->ConstructPath(offset, offset, render->defaultOffsetY); + } + render->SetPenAndBrush(); + render->DrawPath(); + render->DisPlay(); + render->Destroy(); + } +} +// End display_sync_napi_frame_rate_setting_and_subscription_function_registration] + +static std::unordered_map g_instance; + +void SampleXComponent::SetWidth(uint64_t width) +{ + width_ = width; +} + +void SampleXComponent::SetHeight(uint64_t height) +{ + height_ = height; +} + +void SampleXComponent::SetNativeWindow(OHNativeWindow *nativeWindow) +{ + nativeWindow_ = nativeWindow; +} + +OHNativeWindow *SampleXComponent::GetNativeWindow() +{ + return nativeWindow_; +} + +void SampleXComponent::Prepare() +{ + if (nativeWindow_ == nullptr) { + SAMPLE_LOGE("nativeWindow_ is nullptr"); + return; + } + int ret = OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow_, &buffer_, &fenceFd_); + SAMPLE_LOGI("request buffer ret = %{public}d", ret); + bufferHandle_ = OH_NativeWindow_GetBufferHandleFromNative(buffer_); + mappedAddr_ = static_cast( + mmap(bufferHandle_->virAddr, bufferHandle_->size, PROT_READ | PROT_WRITE, MAP_SHARED, bufferHandle_->fd, 0)); + if (mappedAddr_ == MAP_FAILED) { + SAMPLE_LOGE("mmap failed"); + } +} + +void SampleXComponent::DisPlay() +{ + void *bitmapAddr = OH_Drawing_BitmapGetPixels(cBitmap_); + uint32_t *value = static_cast(bitmapAddr); + + uint32_t *pixel = static_cast(mappedAddr_); + if (pixel == nullptr) { + SAMPLE_LOGE("pixel is null"); + return; + } + if (value == nullptr) { + SAMPLE_LOGE("value is null"); + return; + } + for (uint32_t x = 0; x < width_; x++) { + for (uint32_t y = 0; y < height_; y++) { + *pixel++ = *value++; + } + } + Region region {nullptr, 0}; + OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow_, buffer_, fenceFd_, region); + int result = munmap(mappedAddr_, bufferHandle_->size); + if (result == -1) { + SAMPLE_LOGE("munmap failed!"); + } +} + +void SampleXComponent::Create() +{ + uint32_t width = static_cast(bufferHandle_->stride / 4); + cBitmap_ = OH_Drawing_BitmapCreate(); + OH_Drawing_BitmapFormat cFormat {COLOR_FORMAT_RGBA_8888, ALPHA_FORMAT_OPAQUE}; + OH_Drawing_BitmapBuild(cBitmap_, width, height_, &cFormat); + + cCanvas_ = OH_Drawing_CanvasCreate(); + OH_Drawing_CanvasBind(cCanvas_, cBitmap_); + OH_Drawing_CanvasClear(cCanvas_, OH_Drawing_ColorSetArgb(0xFF, 0xFF, 0xFF, 0xFF)); +} + +void SampleXComponent::ConstructPath(int x, int y, int offsetY) +{ + float offsetOfAy = 100.0; + float offsetOfCy = 200.0; + float offsetOfX = 1.0; + + aY = offsetOfAy + offsetY; + cY = offsetOfCy + offsetY; + + if (desc) { + aX -= x * offsetOfX; + bX -= x * offsetOfX; + } else { + aX += x * offsetOfX; + bX += x * offsetOfX; + } + + if (bX >= width_) { + desc = true; + } + + if (aX <= 0) { + desc = false; + } + + float bY = aY; + float cX = bX; + float dX = aX; + float dY = cY; + + cPath_ = OH_Drawing_PathCreate(); + OH_Drawing_PathMoveTo(cPath_, aX, aY); + OH_Drawing_PathLineTo(cPath_, bX, bY); + OH_Drawing_PathLineTo(cPath_, cX, cY); + OH_Drawing_PathLineTo(cPath_, dX, dY); + + OH_Drawing_PathClose(cPath_); +} + +void SampleXComponent::SetPenAndBrush() +{ + constexpr float penWidth = 10.0f; + cPen_ = OH_Drawing_PenCreate(); + OH_Drawing_PenSetAntiAlias(cPen_, true); + OH_Drawing_PenSetColor(cPen_, OH_Drawing_ColorSetArgb(0xFF, 0xFF, 0x00, 0x00)); + OH_Drawing_PenSetWidth(cPen_, penWidth); + OH_Drawing_PenSetJoin(cPen_, LINE_ROUND_JOIN); + OH_Drawing_CanvasAttachPen(cCanvas_, cPen_); + + cBrush_ = OH_Drawing_BrushCreate(); + OH_Drawing_BrushSetColor(cBrush_, OH_Drawing_ColorSetArgb(0xFF, 0x00, 0xFF, 0x00)); + + OH_Drawing_CanvasAttachBrush(cCanvas_, cBrush_); +} + +void SampleXComponent::DrawPath() +{ + OH_Drawing_CanvasDrawPath(cCanvas_, cPath_); +} + +// [Start display_sync_napi_register] +napi_value SampleXComponent::NapiRegister(napi_env env, napi_callback_info info) +{ + // [StartExclude display_sync_napi_register] + SAMPLE_LOGI("NapiRegister"); + if ((env == nullptr) || (info == nullptr)) { + SAMPLE_LOGE("NapiRegister: env or info is null"); + return nullptr; + } + + napi_value thisArg; + if (napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr) != napi_ok) { + SAMPLE_LOGE("NapiRegister: napi_get_cb_info fail"); + return nullptr; + } + + napi_value exportInstance; + if (napi_get_named_property(env, thisArg, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance) != napi_ok) { + SAMPLE_LOGE("NapiRegister: napi_get_named_property fail"); + return nullptr; + } + + OH_NativeXComponent *nativeXComponent = nullptr; + if (napi_unwrap(env, exportInstance, reinterpret_cast(&nativeXComponent)) != napi_ok) { + SAMPLE_LOGE("NapiRegister: napi_unwrap fail"); + return nullptr; + } + + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'}; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + if (OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + SAMPLE_LOGE("NapiRegister: Unable to get XComponent id"); + return nullptr; + } + SAMPLE_LOGI("RegisterID = %{public}s", idStr); + std::string id(idStr); + SampleXComponent *render = SampleXComponent().GetInstance(id); + if (render != nullptr) { + if (id == "xcomponentId_30") { + OH_NativeXComponent_ExpectedRateRange range = {30, 120, 30}; + OH_NativeXComponent_SetExpectedFrameRateRange(nativeXComponent, &range); + } + + if (id == "xcomponentId_120") { + OH_NativeXComponent_ExpectedRateRange range = {30, 120, 120}; + OH_NativeXComponent_SetExpectedFrameRateRange(nativeXComponent, &range); + } + // [EndExclude display_sync_napi_register] + render->RegisterOnFrameCallback(nativeXComponent); + // [StartExclude display_sync_napi_register] + } + return nullptr; + // [EndExclude display_sync_napi_register] +} +// [End display_sync_napi_register] + +// [Start display_sync_napi_unregister] +napi_value SampleXComponent::NapiUnregister(napi_env env, napi_callback_info info) +{ + // [StartExclude display_sync_napi_unregister] + SAMPLE_LOGI("NapiUnregister"); + if ((env == nullptr) || (info == nullptr)) { + SAMPLE_LOGE("NapiUnregister: env or info is null"); + return nullptr; + } + + napi_value thisArg; + if (napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr) != napi_ok) { + SAMPLE_LOGE("NapiUnregister: napi_get_cb_info fail"); + return nullptr; + } + + napi_value exportInstance; + if (napi_get_named_property(env, thisArg, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance) != napi_ok) { + SAMPLE_LOGE("NapiUnregister: napi_get_named_property fail"); + return nullptr; + } + + OH_NativeXComponent *nativeXComponent = nullptr; + if (napi_unwrap(env, exportInstance, reinterpret_cast(&nativeXComponent)) != napi_ok) { + SAMPLE_LOGE("NapiUnregister: napi_unwrap fail"); + return nullptr; + } + + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'}; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + if (OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + SAMPLE_LOGE("NapiUnregister: Unable to get XComponent id"); + return nullptr; + } + SAMPLE_LOGI("ID = %{public}s", idStr); + std::string id(idStr); + SampleXComponent *render = SampleXComponent().GetInstance(id); + if (render != nullptr) { + // [EndExclude display_sync_napi_unregister] + OH_NativeXComponent_UnregisterOnFrameCallback(nativeXComponent); + // [StartExclude display_sync_napi_unregister] + SAMPLE_LOGI("NapiUnregister executed"); + } else { + SAMPLE_LOGE("render is nullptr"); + } + return nullptr; + // [EndExclude display_sync_napi_unregister] +} +// [End display_sync_napi_unregister] + +SampleXComponent::~SampleXComponent() +{ + OH_Drawing_BrushDestroy(cBrush_); + cBrush_ = nullptr; + OH_Drawing_PenDestroy(cPen_); + cPen_ = nullptr; + OH_Drawing_PathDestroy(cPath_); + cPath_ = nullptr; + OH_Drawing_CanvasDestroy(cCanvas_); + cCanvas_ = nullptr; + OH_Drawing_BitmapDestroy(cBitmap_); + cBitmap_ = nullptr; + + buffer_ = nullptr; + bufferHandle_ = nullptr; + nativeWindow_ = nullptr; + mappedAddr_ = nullptr; +} + +void SampleXComponent::Destroy() +{ + OH_Drawing_BrushDestroy(cBrush_); + cBrush_ = nullptr; + OH_Drawing_PenDestroy(cPen_); + cPen_ = nullptr; + OH_Drawing_PathDestroy(cPath_); + cPath_ = nullptr; + OH_Drawing_CanvasDestroy(cCanvas_); + cCanvas_ = nullptr; + OH_Drawing_BitmapDestroy(cBitmap_); + cBitmap_ = nullptr; +} + +void SampleXComponent::Release(std::string &id) +{ + SampleXComponent *render = SampleXComponent::GetInstance(id); + if (render != nullptr) { + delete render; + render = nullptr; + g_instance.erase(g_instance.find(id)); + } +} + +void SampleXComponent::Export(napi_env env, napi_value exports) +{ + if ((env == nullptr) || (exports == nullptr)) { + SAMPLE_LOGE("Export: env or exports is null"); + return; + } + napi_property_descriptor desc[] = { + {"register", nullptr, SampleXComponent::NapiRegister, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"unregister", nullptr, SampleXComponent::NapiUnregister, nullptr, nullptr, nullptr, napi_default, nullptr}}; + if (napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc) != napi_ok) { + SAMPLE_LOGE("Export: napi_define_properties failed"); + } +} + +void SampleXComponent::RegisterCallback(OH_NativeXComponent *nativeXComponent) +{ + SAMPLE_LOGI("register callback"); + renderCallback_.OnSurfaceCreated = OnSurfaceCreatedCB; + renderCallback_.OnSurfaceDestroyed = OnSurfaceDestroyedCB; + renderCallback_.DispatchTouchEvent = nullptr; + renderCallback_.OnSurfaceChanged = nullptr; + OH_NativeXComponent_RegisterCallback(nativeXComponent, &renderCallback_); +} + +// [Start display_sync_register_on_frame_callback] +void SampleXComponent::RegisterOnFrameCallback(OH_NativeXComponent *nativeXComponent) +{ + SAMPLE_LOGI("register onFrameCallback"); + OH_NativeXComponent_RegisterOnFrameCallback(nativeXComponent, TestCallback); +} +// [End display_sync_register_on_frame_callback] + +SampleXComponent *SampleXComponent::GetInstance(std::string &id) +{ + if (g_instance.find(id) == g_instance.end()) { + SampleXComponent *render = new SampleXComponent(id); + g_instance[id] = render; + return render; + } else { + return g_instance[id]; + } +} \ No newline at end of file diff --git a/graphic/DisplaySync/entry/src/main/cpp/samples/sample_xcomponent.h b/graphic/DisplaySync/entry/src/main/cpp/samples/sample_xcomponent.h new file mode 100644 index 0000000000000000000000000000000000000000..c5837519797da3841ee531a8675ec948f95fd430 --- /dev/null +++ b/graphic/DisplaySync/entry/src/main/cpp/samples/sample_xcomponent.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SAMPLE_XCOMPONENT_H +#define SAMPLE_XCOMPONENT_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "napi/native_api.h" + +class SampleXComponent { +public: + SampleXComponent() = default; + ~SampleXComponent(); + explicit SampleXComponent(std::string id) : id_(id) {} + static napi_value NapiRegister(napi_env env, napi_callback_info info); + static napi_value NapiUnregister(napi_env env, napi_callback_info info); + static void Release(std::string &id); + void DrawPath(); + void SetWidth(uint64_t width); + void SetHeight(uint64_t height); + void SetNativeWindow(OHNativeWindow *nativeWindow); + OHNativeWindow *GetNativeWindow(); + + void Prepare(); + void Create(); + void DisPlay(); + void ConstructPath(int x, int y, int offsetY); + void SetPenAndBrush(); + void Export(napi_env env, napi_value exports); + void RegisterCallback(OH_NativeXComponent *nativeXComponent); + void RegisterOnFrameCallback(OH_NativeXComponent *nativeXComponent); + void Destroy(); + static SampleXComponent *GetInstance(std::string &id); + std::string id_; + int defaultOffsetY = 200; + +private: + OH_NativeXComponent_Callback renderCallback_; + + uint64_t width_ = 0; + uint64_t height_ = 0; + + float aX = 0.0; + float aY = 0.0; + float bX = 80.0; + float cY = 0.0; + bool desc = false; + + OH_Drawing_Bitmap *cBitmap_ = nullptr; + OH_Drawing_Canvas *cCanvas_ = nullptr; + + OH_Drawing_Path *cPath_ = nullptr; + OH_Drawing_Brush *cBrush_ = nullptr; + OH_Drawing_Pen *cPen_ = nullptr; + OHNativeWindow *nativeWindow_ = nullptr; + uint32_t *mappedAddr_ = nullptr; + BufferHandle *bufferHandle_ = nullptr; + struct NativeWindowBuffer *buffer_ = nullptr; + int fenceFd_ = 0; +}; + +#endif diff --git a/graphic/DisplaySync/entry/src/main/cpp/types/libentry/index.d.ts b/graphic/DisplaySync/entry/src/main/cpp/types/libentry/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..72ce2401dc0c60c025d5880dd31761145681f152 --- /dev/null +++ b/graphic/DisplaySync/entry/src/main/cpp/types/libentry/index.d.ts @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const add: (a: number, b: number) => number; \ No newline at end of file diff --git a/graphic/DisplaySync/entry/src/main/cpp/types/libentry/oh-package.json5 b/graphic/DisplaySync/entry/src/main/cpp/types/libentry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..65023700b293f7d0c8f1427c4a5ce0f480741e4d --- /dev/null +++ b/graphic/DisplaySync/entry/src/main/cpp/types/libentry/oh-package.json5 @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "name": "libentry.so", + "types": "./Index.d.ts", + "version": "1.0.0", + "description": "Please describe the basic information." +} \ No newline at end of file diff --git a/graphic/DisplaySync/entry/src/main/ets/DispalySync/CustomDrawDisplaySync.ets b/graphic/DisplaySync/entry/src/main/ets/DispalySync/CustomDrawDisplaySync.ets new file mode 100644 index 0000000000000000000000000000000000000000..190d0eaf05849d4a1cb9859c8b6f76245d29c3d5 --- /dev/null +++ b/graphic/DisplaySync/entry/src/main/ets/DispalySync/CustomDrawDisplaySync.ets @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// [Start display_sync_by_ui_import_module] +import { displaySync } from '@kit.ArkGraphics2D'; +// [End display_sync_by_ui_import_module] +import { router } from '@kit.ArkUI'; + +// [Start display_sync_by_ui_complete_example] +// [Start display_sync_create_object] +@Entry +@Component +struct Index { + // [StartExclude display_sync_create_object] + @State drawFirstSize: number = 25; + @State drawSecondSize: number = 25; + // [EndExclude display_sync_create_object] + private backDisplaySyncSlow: displaySync.DisplaySync | undefined = undefined; + private backDisplaySyncFast: displaySync.DisplaySync | undefined = undefined; +// [End display_sync_create_object] + private isBigger_30: boolean = true; + private isBigger_60: boolean = true; + + // [Start display_sync_create_text_component] + @Builder + doSomeRenderFirst() { + Text('30') + .fontSize(this.drawFirstSize) + } + + @Builder + doSomeRenderSecond() { + Text('60') + .fontSize(this.drawSecondSize) + } + // [End display_sync_create_text_component] + + // [Start display_sync_frame_rate_setting_and_subscription_function_registration] + CreateDisplaySyncSlow() { + let range: ExpectedFrameRateRange = { + expected: 30, + min: 0, + max: 120 + }; + + let draw30 = (intervalInfo: displaySync.IntervalInfo) => { + if (this.isBigger_30) { + this.drawFirstSize += 1; + if (this.drawFirstSize > 150) { + this.isBigger_30 = false; + } + } else { + this.drawFirstSize -= 1; + if (this.drawFirstSize < 25) { + this.isBigger_30 = true; + } + } + }; + + this.backDisplaySyncSlow = displaySync.create(); + this.backDisplaySyncSlow.setExpectedFrameRateRange(range); + this.backDisplaySyncSlow.on("frame", draw30); + } + // [End display_sync_frame_rate_setting_and_subscription_function_registration] + + CreateDisplaySyncFast() { + let range: ExpectedFrameRateRange = { + expected: 60, + min: 0, + max: 120 + }; + + let draw60 = (intervalInfo: displaySync.IntervalInfo) => { + if (this.isBigger_60) { + this.drawSecondSize += 1; + if (this.drawSecondSize > 150) { + this.isBigger_60 = false; + } + } else { + this.drawSecondSize -= 1; + if (this.drawSecondSize < 25) { + this.isBigger_60 = true; + } + } + }; + + this.backDisplaySyncFast = displaySync.create(); + this.backDisplaySyncFast.setExpectedFrameRateRange(range); + this.backDisplaySyncFast.on("frame", draw60); + } + + // [Start display_sync_call_stop] + aboutToDisappear() { + if (this.backDisplaySyncSlow) { + this.backDisplaySyncSlow.stop(); + this.backDisplaySyncSlow = undefined; + } + if (this.backDisplaySyncFast) { + this.backDisplaySyncFast.stop(); + this.backDisplaySyncFast = undefined; + } + } + // [End display_sync_call_stop] + + build() { + Column() { + Row() { + this.doSomeRenderFirst(); + } + .height('40%') + + Row() { + this.doSomeRenderSecond(); + } + .height('40%') + + Row() { + // [Start display_sync_start_per_frame_callback] + Button('Start') + .id('CustomDrawStart') + .fontSize(14) + .fontWeight(500) + .margin({ bottom: 10, left: 5 }) + .fontColor(Color.White) + .onClick((): void => { + if (this.backDisplaySyncSlow == undefined) { + this.CreateDisplaySyncSlow(); + } + if (this.backDisplaySyncFast == undefined) { + this.CreateDisplaySyncFast(); + } + if (this.backDisplaySyncSlow) { + this.backDisplaySyncSlow.start(); + } + if (this.backDisplaySyncFast) { + this.backDisplaySyncFast.start(); + } + }) + .width('20%') + .height(40) + .shadow(ShadowStyle.OUTER_DEFAULT_LG) + // [End display_sync_start_per_frame_callback] + + // [Start display_sync_stop_per_frame_callback] + Button('Stop') + .id('CustomDrawStop') + .fontSize(14) + .fontWeight(500) + .margin({ bottom: 10, left: 5 }) + .fontColor(Color.White) + .onClick((): void => { + if (this.backDisplaySyncSlow) { + this.backDisplaySyncSlow.stop(); + } + if (this.backDisplaySyncFast) { + this.backDisplaySyncFast.stop(); + } + }) + .width('20%') + .height(40) + .shadow(ShadowStyle.OUTER_DEFAULT_LG) + // [End display_sync_stop_per_frame_callback] + + Button('Back') + .id('CustomDrawBack') + .fontSize(14) + .fontWeight(500) + .margin({ bottom: 10, left: 5 }) + .fontColor(Color.White) + .onClick((): void => { + if (this.backDisplaySyncSlow) { + this.backDisplaySyncSlow.stop(); + } + if (this.backDisplaySyncFast) { + this.backDisplaySyncFast.stop(); + } + router.back(); + }) + .width('20%') + .height(40) + .shadow(ShadowStyle.OUTER_DEFAULT_LG) + } + .width('100%') + .justifyContent(FlexAlign.Center) + .shadow(ShadowStyle.OUTER_DEFAULT_SM) + .alignItems(VerticalAlign.Bottom) + .layoutWeight(1) + } + } +} +// [End display_sync_by_ui_complete_example] \ No newline at end of file diff --git a/graphic/DisplaySync/entry/src/main/ets/DispalySync/PropertyAnimationDisplaySync.ets b/graphic/DisplaySync/entry/src/main/ets/DispalySync/PropertyAnimationDisplaySync.ets new file mode 100644 index 0000000000000000000000000000000000000000..3eb15f8e0b844351e95250d25e503636ca758c86 --- /dev/null +++ b/graphic/DisplaySync/entry/src/main/ets/DispalySync/PropertyAnimationDisplaySync.ets @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { router } from '@kit.ArkUI'; + +// [Start display_sync_by_property_animation_complete_example] +@Entry +@Component +struct AnimationToAnimationDemo { + @State isAnimation: boolean = false; + @State translateX1: number = -100; + @State translateX2: number = -100; + @State translateX3: number = -100; + uiContext: UIContext | undefined = undefined; + + aboutToAppear() { + this.uiContext = this.getUIContext(); + if (!this.uiContext) { + console.warn('no uiContext'); + return; + } + } + + build() { + Column() { + Row() { + Text('30') + .fontWeight(FontWeight.Bold) + .fontSize(16) + .fontColor(Color.White) + .textAlign(TextAlign.Center) + .borderRadius(10) + .backgroundColor(0xF56C6C) + .width(80) + .height(80) + .translate({ x: this.translateX1 }) + } + .height('20%') + + Row() { + Text('40') + .fontWeight(FontWeight.Bold) + .fontSize(16) + .fontColor(Color.White) + .textAlign(TextAlign.Center) + .borderRadius(10) + .backgroundColor(0x2E8B57) + .width(80) + .height(80) + .translate({ x: this.translateX2 }) + } + .height('20%') + + Row() { + // [Start display_sync_property_animation] + Text('60') + // [StartExclude display_sync_property_animation] + .fontWeight(FontWeight.Bold) + .fontSize(16) + .fontColor(Color.White) + .textAlign(TextAlign.Center) + .borderRadius(10) + .backgroundColor(0x008B8B) + .width(80) + .height(80) + .translate({ x: this.translateX3 }) + // [EndExclude display_sync_property_animation] + .animation({ + duration: 1200, + iterations: 10, + playMode: PlayMode.AlternateReverse, + expectedFrameRateRange: { + expected: 60, + min: 0, + max: 120, + }, + }) + // [End display_sync_property_animation] + } + .height('20%') + + Row() { + // [Start display_sync_explicit_animation] + Button('Start') + // [StartExclude display_sync_explicit_animation] + .id('PropertyAnimationStart') + .fontSize(14) + .fontWeight(500) + .margin({ bottom: 10, left: 5 }) + .fontColor(Color.White) + .onClick(() => { + this.isAnimation = !this.isAnimation; + this.translateX3 = this.isAnimation ? 100 : -100; + // [EndExclude display_sync_explicit_animation] + + this.uiContext?.animateTo({ + duration: 1200, + iterations: 10, + playMode: PlayMode.AlternateReverse, + expectedFrameRateRange: { + expected: 30, + min: 0, + max: 120, + }, + }, () => { + this.translateX1 = this.isAnimation ? 100 : -100; + }) + // [End display_sync_explicit_animation] + + this.uiContext?.animateTo({ + duration: 1200, + iterations: 10, + playMode: PlayMode.AlternateReverse, + expectedFrameRateRange: { + expected: 40, + min: 0, + max: 120, + }, + }, () => { + this.translateX2 = this.isAnimation ? 100 : -100; + }) + }) + .width('40%') + .height(40) + .shadow(ShadowStyle.OUTER_DEFAULT_LG) + + Button('Back') + .id('PropertyAnimationBack') + .fontSize(14) + .fontWeight(500) + .margin({ bottom: 10, left: 5 }) + .fontColor(Color.White) + .onClick((): void => { + router.back(); + }) + .width('40%') + .height(40) + .shadow(ShadowStyle.OUTER_DEFAULT_LG) + } + .width('100%') + .justifyContent(FlexAlign.Center) + .shadow(ShadowStyle.OUTER_DEFAULT_SM) + .alignItems(VerticalAlign.Bottom) + .layoutWeight(1) + } + .width('100%') + .justifyContent(FlexAlign.Center) + .shadow(ShadowStyle.OUTER_DEFAULT_SM) + .layoutWeight(1) + } +} +// [End display_sync_by_property_animation_complete_example] \ No newline at end of file diff --git a/graphic/DisplaySync/entry/src/main/ets/DispalySync/XComponentDisplaySync.ets b/graphic/DisplaySync/entry/src/main/ets/DispalySync/XComponentDisplaySync.ets new file mode 100644 index 0000000000000000000000000000000000000000..96016ea26cf463e9df8c4770507cfd9cb3514af1 --- /dev/null +++ b/graphic/DisplaySync/entry/src/main/ets/DispalySync/XComponentDisplaySync.ets @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// [Start display_sync_create_xcomponent] +import XComponentContext from '../interface/XComponentContext'; +import { router } from '@kit.ArkUI'; + +@Entry +@Component +struct Index { + private xComponentContext1: XComponentContext | undefined = undefined; + private xComponentContext2: XComponentContext | undefined = undefined; + + build() { + Column() { + Row() { + // [StartExclude display_sync_create_xcomponent] + Text('30fps') + .fontWeight(FontWeight.Bold) + .fontSize(12) + .fontColor(Color.Red) + .textAlign(TextAlign.End) + .width(40) + .height(30) + // [EndExclude display_sync_create_xcomponent] + + XComponent({ + id: 'xcomponentId_30', + type: XComponentType.SURFACE, + libraryname: 'entry' + }) + .onLoad((xComponentContext) => { + this.xComponentContext1 = xComponentContext as XComponentContext; + }).width('640px') + .backgroundColor(Color.White) + + + }.height('40%') + + + Row() { + // [StartExclude display_sync_create_xcomponent] + Text('120fps') + .fontWeight(FontWeight.Bold) + .fontSize(12) + .fontColor(Color.Red) + .textAlign(TextAlign.End) + .width(40) + .height(30) + // [EndExclude display_sync_create_xcomponent] + + XComponent({ + id: 'xcomponentId_120', + type: XComponentType.SURFACE, + libraryname: 'entry' + }) + .onLoad((xComponentContext) => { + this.xComponentContext2 = xComponentContext as XComponentContext; + }).width('640px') + .backgroundColor(Color.White) + }.height('40%') + // [End display_sync_create_xcomponent] + + // [Start display_sync_start_and_stop_per_frame_callback] + Row() { + Button('Start') + .id('Start') + .fontSize(14) + .fontWeight(500) + .margin({ bottom: 20, right: 6, left: 6 }) + .onClick(() => { + if (this.xComponentContext1) { + this.xComponentContext1.register(); + } + if (this.xComponentContext2) { + this.xComponentContext2.register(); + } + }) + .width('30%') + .height(40) + .shadow(ShadowStyle.OUTER_DEFAULT_LG) + + Button('Stop') + .id('Stop') + .fontSize(14) + .fontWeight(500) + .margin({ bottom: 20, left: 6 }) + .onClick(() => { + if (this.xComponentContext1) { + this.xComponentContext1.unregister(); + } + if (this.xComponentContext2) { + this.xComponentContext2.unregister(); + } + }) + .width('30%') + .height(40) + .shadow(ShadowStyle.OUTER_DEFAULT_LG) + // [End display_sync_start_and_stop_per_frame_callback] + + Button('Back') + .id('Back') + .fontSize(14) + .fontWeight(500) + .margin({ bottom: 20, left: 6 }) + .onClick((): void => { + if (this.xComponentContext1) { + this.xComponentContext1.unregister(); + } + if (this.xComponentContext2) { + this.xComponentContext2.unregister(); + } + router.back(); + }) + .width('30%') + .height(40) + .shadow(ShadowStyle.OUTER_DEFAULT_LG) + } + .width('100%') + .height('20%') + } + } +} \ No newline at end of file diff --git a/graphic/DisplaySync/entry/src/main/ets/entryability/EntryAbility.ets b/graphic/DisplaySync/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..a32a8361c7fcad66acf12208583e198fc4e68dab --- /dev/null +++ b/graphic/DisplaySync/entry/src/main/ets/entryability/EntryAbility.ets @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { window } from '@kit.ArkUI'; + +export default class EntryAbility extends UIAbility { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); + } + + onDestroy(): void { + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); + } + + onWindowStageCreate(windowStage: window.WindowStage): void { + // Main window is created, set main page for this ability + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + + windowStage.loadContent('pages/Index', (err) => { + if (err.code) { + hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); + return; + } + hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.'); + }); + } + + onWindowStageDestroy(): void { + // Main window is destroyed, release UI related resources + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); + } + + onForeground(): void { + // Ability has brought to foreground + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); + } + + onBackground(): void { + // Ability has back to background + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); + } +} diff --git a/graphic/DisplaySync/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/graphic/DisplaySync/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..be794f48ccffc46278e76ce3493088a647b0d470 --- /dev/null +++ b/graphic/DisplaySync/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit'; + +export default class EntryBackupAbility extends BackupExtensionAbility { + async onBackup() { + hilog.info(0x0000, 'testTag', 'onBackup ok'); + } + + async onRestore(bundleVersion: BundleVersion) { + hilog.info(0x0000, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); + } +} \ No newline at end of file diff --git a/graphic/DisplaySync/entry/src/main/ets/interface/XComponentContext.ts b/graphic/DisplaySync/entry/src/main/ets/interface/XComponentContext.ts new file mode 100644 index 0000000000000000000000000000000000000000..7bdd8fbc305da2d3324d14f82d3063b1c5881399 --- /dev/null +++ b/graphic/DisplaySync/entry/src/main/ets/interface/XComponentContext.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// [Start display_sync_export_interface_xcomponent_context] +export default interface XComponentContext { + register(): void; + + unregister(): void; +}; +// [End display_sync_export_interface_xcomponent_context] diff --git a/graphic/DisplaySync/entry/src/main/ets/pages/Index.ets b/graphic/DisplaySync/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..a4a4ba0bb94f53b96cda8e58c870894fb5c88178 --- /dev/null +++ b/graphic/DisplaySync/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { router } from '@kit.ArkUI'; +import { hilog } from '@kit.PerformanceAnalysisKit'; + +@Entry +@Component +struct Index { + build() { + Column({ space: 20 }) { + Button("Requesting Frame Rates for Animations") + .id("AnimationFpsRequest") + .fontSize(16) + .fontWeight(500) + .margin({ top: 200, left: 6 }) + .onClick((): void => { + router.pushUrl({ + url: 'DispalySync/PropertyAnimationDisplaySync' + }, router.RouterMode.Standard, (err) => { + if (err) { + hilog.error(0x0001, "router.pushUrl", + "Invoke replaceUrl failed, code is %{public}s, message is %{public}s", + err.code, err.message); + return; + } + hilog.info(0x0002, "router.pushUrl", "Invoke replaceUrl succeeded."); + }); + }) + .width('80%') + .height(40) + + + Button('Requesting Frame Rates for UI Components') + .id('UiFpsRequest') + .fontSize(16) + .fontWeight(500) + .margin({ top: 20, left: 6 }) + .onClick((): void => { + router.pushUrl({ + url: 'DispalySync/CustomDrawDisplaySync' + }, router.RouterMode.Standard, (err) => { + if (err) { + hilog.error(0x0001, "router.pushUrl", + "Invoke replaceUrl failed, code is %{public}s, message is %{public}s.", + err.code, err.message); + return; + } + hilog.info(0x0002, "router.pushUrl", "Invoke replaceUrl succeeded."); + }); + }) + .width('80%') + .height(40) + + Button('Requesting Frame Rates for Custom Content') + .id('XComponent') + .fontSize(16) + .fontWeight(500) + .margin({ top: 20, left: 6 }) + .onClick((): void => { + router.pushUrl({ + url: 'DispalySync/XComponentDisplaySync' + }, router.RouterMode.Single, (err) => { + if (err) { + hilog.error(0x0001, "router.pushUrl", + "Invoke replaceUrl failed, code is %{public}s, message is %{public}s.", + err.code, err.message); + return; + } + hilog.info(0x0002, "router.pushUrl", "Invoke replaceUrl succeeded."); + }); + }) + .width('80%') + .height(40) + } + .width('100%') + } +} \ No newline at end of file diff --git a/graphic/DisplaySync/entry/src/main/ets/utils/Logger.ets b/graphic/DisplaySync/entry/src/main/ets/utils/Logger.ets new file mode 100644 index 0000000000000000000000000000000000000000..517c8134a93796f5deb554eef31d92c391df9b17 --- /dev/null +++ b/graphic/DisplaySync/entry/src/main/ets/utils/Logger.ets @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import hilog from '@ohos.hilog'; + +class Logger { + private domain: number; + private prefix: string; + private format: string = '%{public}s, %{public}s'; + + constructor(prefix: string) { + this.prefix = prefix; + this.domain = 0xFF00; + } + + debug(...args: string[]) { + hilog.debug(this.domain, this.prefix, this.format, args); + } + + info(...args: string[]) { + hilog.info(this.domain, this.prefix, this.format, args); + } + + warn(...args: string[]) { + hilog.warn(this.domain, this.prefix, this.format, args); + } + + error(...args: string[]) { + hilog.error(this.domain, this.prefix, this.format, args); + } +} + +export default new Logger('[Sample_DisplaySync]'); \ No newline at end of file diff --git a/graphic/DisplaySync/entry/src/main/module.json5 b/graphic/DisplaySync/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..ca3c9ba3157fbb51f3b8cba57252aee35e6203d0 --- /dev/null +++ b/graphic/DisplaySync/entry/src/main/module.json5 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "module": { + "name": "entry", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "EntryAbility", + "deviceTypes": [ + "default", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "abilities": [ + { + "name": "EntryAbility", + "srcEntry": "./ets/entryability/EntryAbility.ets", + "description": "$string:EntryAbility_desc", + "icon": "$media:layered_image", + "label": "$string:EntryAbility_label", + "startWindowIcon": "$media:startIcon", + "startWindowBackground": "$color:start_window_background", + "exported": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ], + "extensionAbilities": [ + { + "name": "EntryBackupAbility", + "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets", + "type": "backup", + "exported": false, + "metadata": [ + { + "name": "ohos.extension.backup", + "resource": "$profile:backup_config" + } + ] + } + ] + } +} \ No newline at end of file diff --git a/graphic/DisplaySync/entry/src/main/resources/base/element/color.json b/graphic/DisplaySync/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02 --- /dev/null +++ b/graphic/DisplaySync/entry/src/main/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + } + ] +} \ No newline at end of file diff --git a/graphic/DisplaySync/entry/src/main/resources/base/element/string.json b/graphic/DisplaySync/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..aa6d9f08b231e8d865a6328a2f28ec92a2acf753 --- /dev/null +++ b/graphic/DisplaySync/entry/src/main/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "Sample_DisplaySync" + } + ] +} \ No newline at end of file diff --git a/graphic/DisplaySync/entry/src/main/resources/base/media/background.png b/graphic/DisplaySync/entry/src/main/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..f939c9fa8cc8914832e602198745f592a0dfa34d Binary files /dev/null and b/graphic/DisplaySync/entry/src/main/resources/base/media/background.png differ diff --git a/graphic/DisplaySync/entry/src/main/resources/base/media/foreground.png b/graphic/DisplaySync/entry/src/main/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..4483ddad1f079e1089d685bd204ee1cfe1d01902 Binary files /dev/null and b/graphic/DisplaySync/entry/src/main/resources/base/media/foreground.png differ diff --git a/graphic/DisplaySync/entry/src/main/resources/base/media/layered_image.json b/graphic/DisplaySync/entry/src/main/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..4f9ad6307a2bc56beb6d0fce0a49cbf213b20a74 --- /dev/null +++ b/graphic/DisplaySync/entry/src/main/resources/base/media/layered_image.json @@ -0,0 +1,6 @@ +{ + "layered-image": { + "background": "$media:background", + "foreground": "$media:foreground" + } +} \ No newline at end of file diff --git a/graphic/DisplaySync/entry/src/main/resources/base/media/startIcon.png b/graphic/DisplaySync/entry/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b Binary files /dev/null and b/graphic/DisplaySync/entry/src/main/resources/base/media/startIcon.png differ diff --git a/graphic/DisplaySync/entry/src/main/resources/base/profile/backup_config.json b/graphic/DisplaySync/entry/src/main/resources/base/profile/backup_config.json new file mode 100644 index 0000000000000000000000000000000000000000..78f40ae7c494d71e2482278f359ec790ca73471a --- /dev/null +++ b/graphic/DisplaySync/entry/src/main/resources/base/profile/backup_config.json @@ -0,0 +1,3 @@ +{ + "allowToBackupRestore": true +} \ No newline at end of file diff --git a/graphic/DisplaySync/entry/src/main/resources/base/profile/main_pages.json b/graphic/DisplaySync/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..5c9db65f6d7ead000603ce2adeb339950d73d3a1 --- /dev/null +++ b/graphic/DisplaySync/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,8 @@ +{ + "src": [ + "pages/Index", + "DispalySync/CustomDrawDisplaySync", + "DispalySync/PropertyAnimationDisplaySync", + "DispalySync/XComponentDisplaySync" + ] +} diff --git a/graphic/DisplaySync/entry/src/main/resources/en_US/element/string.json b/graphic/DisplaySync/entry/src/main/resources/en_US/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..aa6d9f08b231e8d865a6328a2f28ec92a2acf753 --- /dev/null +++ b/graphic/DisplaySync/entry/src/main/resources/en_US/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "Sample_DisplaySync" + } + ] +} \ No newline at end of file diff --git a/graphic/DisplaySync/entry/src/main/resources/zh_CN/element/string.json b/graphic/DisplaySync/entry/src/main/resources/zh_CN/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..3e449654fc7b0aec6c38a3c7b84531a29e79d203 --- /dev/null +++ b/graphic/DisplaySync/entry/src/main/resources/zh_CN/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "模块描述" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "Sample_DisplaySync" + } + ] +} \ No newline at end of file diff --git a/graphic/DisplaySync/entry/src/mock/mock-config.json5 b/graphic/DisplaySync/entry/src/mock/mock-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..e4eb8bbe4e5836577a13067db5f0fede18aa5c8c --- /dev/null +++ b/graphic/DisplaySync/entry/src/mock/mock-config.json5 @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ +} \ No newline at end of file diff --git a/graphic/DisplaySync/entry/src/ohosTest/ets/test/Ability.test.ets b/graphic/DisplaySync/entry/src/ohosTest/ets/test/Ability.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..c6ab165ab2c738d9163a608dc674bccb2ce68e9c --- /dev/null +++ b/graphic/DisplaySync/entry/src/ohosTest/ets/test/Ability.test.ets @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { describe, expect, it } from '@ohos/hypium'; +import { abilityDelegatorRegistry, Driver, ON } from '@kit.TestKit'; +import Logger from '../utils/Logger'; + +const TAG = '[Sample_DisplaySync]'; +const BUNDLE = 'MyApp_' +const DELAYMS_1S = 1000; +const DELAYMS_2S = 2000; +const DELAYMS_5S = 5000; + +const bundleName = abilityDelegatorRegistry.getArguments().bundleName; + +export default function abilityTest() { + describe('AbilityTest', () => { + it(BUNDLE + 'StartAbility_001, begin', 0, async (done: Function) => { + Logger.info(TAG, BUNDLE + 'StartAbility_001'); + let abilityDelegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator(); + try { + await abilityDelegator.startAbility({ + bundleName: bundleName, + abilityName: 'EntryAbility' + }); + } catch (err) { + Logger.info(TAG, `beforeAll exception = ${JSON.stringify(err)}`); + } + + Logger.info(TAG, BUNDLE + 'StartAbility_001, end'); + done(); + }); + + /** + * @tc.number:SUB_GRAPHIC_2D_HGM_DISPLAYSYNC_0200 + * @tc.name:PropertyAnimation_001 + * @tc.desc:PropertyAnimation + * @tc.size:MediumTest + * @tc.type:Function + * @tc.level:Level 1 + */ + it(BUNDLE + 'PropertyAnimation_001', 0, async (done: Function) => { + try { + Logger.info(TAG, BUNDLE + 'PropertyAnimation_001 beg' + + 'in'); + + let driver = Driver.create(); + await driver.delayMs(DELAYMS_2S); + + await driver.assertComponentExist(ON.id('AnimationFpsRequest')); + let propertyAnimationButton = await driver.findComponent(ON.id('AnimationFpsRequest')); + await propertyAnimationButton.click(); + await driver.delayMs(DELAYMS_2S); + + await driver.assertComponentExist(ON.id('PropertyAnimationStart')); + let startButton = await driver.findComponent(ON.id('PropertyAnimationStart')); + await startButton.click(); + await driver.delayMs(DELAYMS_5S); + + await driver.assertComponentExist(ON.id('PropertyAnimationBack')); + let backButton = await driver.findComponent(ON.id('PropertyAnimationBack')); + await backButton.click(); + await driver.delayMs(DELAYMS_1S); + + Logger.info(TAG, BUNDLE + 'PropertyAnimation_001 end'); + done(); + } catch (error) { + expect().assertFail(); + } + }); + + it(BUNDLE + 'UiFpsRequest_001', 0, async (done: Function) => { + try { + Logger.info(TAG, BUNDLE + 'UiFpsRequest_001, begin'); + + let driver = Driver.create(); + await driver.delayMs(DELAYMS_2S); + + await driver.assertComponentExist(ON.id('UiFpsRequest')); + let customDrawButton = await driver.findComponent(ON.id('UiFpsRequest')); + + await customDrawButton.click(); + await driver.delayMs(DELAYMS_2S); + + await driver.assertComponentExist(ON.id('CustomDrawStart')); + let startButton = await driver.findComponent(ON.id('CustomDrawStart')); + + await startButton.click(); + await driver.delayMs(DELAYMS_2S); + + await driver.assertComponentExist(ON.id('CustomDrawStop')); + let stopButton = await driver.findComponent(ON.id('CustomDrawStop')); + + await stopButton.click(); + await driver.delayMs(DELAYMS_2S); + + await driver.assertComponentExist(ON.id('CustomDrawBack')); + let backButton = await driver.findComponent(ON.id('CustomDrawBack')); + + await backButton.click(); + await driver.delayMs(DELAYMS_1S); + + Logger.info(TAG, BUNDLE + 'UiFpsRequest_001 end'); + done(); + } catch (error) { + expect().assertFail(); + } + }); + + /** + * @tc.number:SUB_GRAPHIC_2D_HGM_DISPLAYSYNC_0100 + * @tc.name:CustomDraw_001 + * @tc.desc:CustomDraw + * @tc.size:MediumTest + * @tc.type:Function + * @tc.level:Level 1 + */ + it(BUNDLE + 'CustomDraw_001', 0, async (done: Function) => { + try { + Logger.info(TAG, BUNDLE + 'CustomDraw_001 begin'); + + let driver = Driver.create(); + await driver.delayMs(DELAYMS_2S); + + await driver.assertComponentExist(ON.id('XComponent')); + + let customDrawButton = await driver.findComponent(ON.id('XComponent')); + + await customDrawButton.click(); + await driver.delayMs(DELAYMS_2S); + + await driver.assertComponentExist(ON.id('Start')); + + let startButton = await driver.findComponent(ON.id('Start')); + + await startButton.click(); + await driver.delayMs(DELAYMS_2S); + + await driver.assertComponentExist(ON.id('Stop')); + + let stopButton = await driver.findComponent(ON.id('Stop')); + + await stopButton.click(); + await driver.delayMs(DELAYMS_2S); + + await driver.assertComponentExist(ON.id('Back')); + + let backButton = await driver.findComponent(ON.id('Back')); + + await backButton.click(); + await driver.delayMs(DELAYMS_1S); + + Logger.info(TAG, BUNDLE + 'CustomDraw_001 end'); + done(); + } catch (error) { + expect().assertFail(); + } + }); + }) +} \ No newline at end of file diff --git a/graphic/DisplaySync/entry/src/ohosTest/ets/test/List.test.ets b/graphic/DisplaySync/entry/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..3be23423391686fa8b1926d5a874e3bda4798df3 --- /dev/null +++ b/graphic/DisplaySync/entry/src/ohosTest/ets/test/List.test.ets @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import abilityTest from './Ability.test'; + +export default function testsuite() { + abilityTest(); +} \ No newline at end of file diff --git a/graphic/DisplaySync/entry/src/ohosTest/ets/utils/Logger.ets b/graphic/DisplaySync/entry/src/ohosTest/ets/utils/Logger.ets new file mode 100644 index 0000000000000000000000000000000000000000..687ca76b70124c6398f5d60b017979645dbc774a --- /dev/null +++ b/graphic/DisplaySync/entry/src/ohosTest/ets/utils/Logger.ets @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import hilog from '@ohos.hilog'; + +class Logger { + private domain: number = 0xF811; + private prefix: string = ''; + private format: string = '%{public}s, %{public}s'; + + constructor(prefix: string) { + this.prefix = prefix; + this.domain = 0xF811; + } + + debug(...args: string[]): void { + hilog.debug(this.domain, this.prefix, this.format, args); + } + + info(...args: string[]): void { + hilog.info(this.domain, this.prefix, this.format, args); + } + + warn(...args: string[]): void { + hilog.warn(this.domain, this.prefix, this.format, args); + } + + error(...args: string[]): void { + hilog.error(this.domain, this.prefix, this.format, args); + } +} + +export default new Logger('[Sample_DisplaySync]'); \ No newline at end of file diff --git a/graphic/DisplaySync/entry/src/ohosTest/module.json5 b/graphic/DisplaySync/entry/src/ohosTest/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..944ed99859bbc89eac2d57af2b3600881bb5a47c --- /dev/null +++ b/graphic/DisplaySync/entry/src/ohosTest/module.json5 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "module": { + "name": "entry_test", + "type": "feature", + "deviceTypes": [ + "default", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false + } +} diff --git a/graphic/DisplaySync/entry/src/test/List.test.ets b/graphic/DisplaySync/entry/src/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..3bc7c739d1957b3a778de67db8992240584b6692 --- /dev/null +++ b/graphic/DisplaySync/entry/src/test/List.test.ets @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import localUnitTest from './LocalUnit.test'; + +export default function testsuite() { + localUnitTest(); +} \ No newline at end of file diff --git a/graphic/DisplaySync/entry/src/test/LocalUnit.test.ets b/graphic/DisplaySync/entry/src/test/LocalUnit.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..1d9c6cdccf0c5b68b0684adbd304a41888ea9e9c --- /dev/null +++ b/graphic/DisplaySync/entry/src/test/LocalUnit.test.ets @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from '@ohos/hypium'; + +export default function localUnitTest() { + describe('localUnitTest', () => { + // Defines a test suite. Two parameters are supported: test suite name and test suite function. + beforeAll(() => { + // Presets an action, which is performed only once before all test cases of the test suite start. + // This API supports only one parameter: preset action function. + }); + beforeEach(() => { + // Presets an action, which is performed before each unit test case starts. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: preset action function. + }); + afterEach(() => { + // Presets a clear action, which is performed after each unit test case ends. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: clear action function. + }); + afterAll(() => { + // Presets a clear action, which is performed after all test cases of the test suite end. + // This API supports only one parameter: clear action function. + }); + it('assertContain', 0, () => { + // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. + let a = 'abc'; + let b = 'b'; + // Defines a variety of assertion methods, which are used to declare expected boolean conditions. + expect(a).assertContain(b); + expect(a).assertEqual(a); + }); + }); +} \ No newline at end of file diff --git a/graphic/DisplaySync/hvigor/hvigor-config.json5 b/graphic/DisplaySync/hvigor/hvigor-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..87990affc4f62f7c76c246428c40272d3be0a7c7 --- /dev/null +++ b/graphic/DisplaySync/hvigor/hvigor-config.json5 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "modelVersion": "5.0.0", + "dependencies": { + }, + "execution": { + // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | false ]. Default: "normal" */ + // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */ + // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */ + // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */ + // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */ + }, + "logging": { + // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */ + }, + "debugging": { + // "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */ + }, + "nodeOptions": { + // "maxOldSpaceSize": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/ + // "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/ + } +} diff --git a/graphic/DisplaySync/hvigorfile.ts b/graphic/DisplaySync/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..b74abd874f6bb24520d387f59036a41df1dde68a --- /dev/null +++ b/graphic/DisplaySync/hvigorfile.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { appTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins: [] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/graphic/DisplaySync/oh-package.json5 b/graphic/DisplaySync/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..7a7fe7781e61280b6e0a6f437d4a7a6a41b2afcd --- /dev/null +++ b/graphic/DisplaySync/oh-package.json5 @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "modelVersion": "5.0.0", + "description": "Please describe the basic information.", + "dependencies": { + }, + "devDependencies": { + "@ohos/hypium": "1.0.19", + "@ohos/hamock": "1.0.0" + } +} diff --git a/graphic/DisplaySync/ohosTest.md b/graphic/DisplaySync/ohosTest.md new file mode 100644 index 0000000000000000000000000000000000000000..a9138197dd9bf1a47499832bc535eebcff7d87c9 --- /dev/null +++ b/graphic/DisplaySync/ohosTest.md @@ -0,0 +1,19 @@ +# DisplaySync测试用例归档 + +## 用例表 + +| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 | +|-----------------|-----------------|----------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------|------|------| +| 拉起应用 | 设备正常运行 | | 成功拉起应用 | 是 | Pass | +| 主页展示 | 设备正常运行 | | 展示 Requesting Frame Rates for Animations、Requesting Frame Rates for UI Components、Requesting Frame Rates for Custom Content 按钮 | 是 | Pass | +| 主页按钮点击 | 位于主页 | 点击 Requesting Frame Rates for Animations | 跳转至请求动画绘制帧率页面 | 是 | Pass | +| 动画绘制帧率开始 | 位于动画绘制帧率面 | 点击Start | 三个方块分别按照30hz、40hz、60hz频率来回移动 | 是 | Pass | +| 动画绘制帧率返回主页 | 位于动画绘制帧率页面 | 点击Back | 回到主页 | 是 | Pass | +| 主页按钮点击 | 位于主页 | 点击 Requesting Frame Rates for UI Components | 跳转请求 UI 绘制帧率页面 | 是 | Pass | +| 请求 UI 绘制帧率开始 | 位于请求 UI 绘制帧率 | 点击 Start | 数字 30、60 分别按照 30hz、60hz 频率放大缩小 | 是 | Pass | +| 请求 UI 绘制帧率停止 | 位于请求 UI 绘制帧率 | 点击 Stop | 数字 30、60 变化停止 | 是 | Pass | +| 请求 UI 绘制帧率返回 | 位于请求 UI 绘制帧率 | 点击 Back | 回到主页 | 是 | Pass | +| 主页按钮点击 | 位于主页 | 点击 Requesting Frame Rates for Custom Content | 跳转 请求自绘制内容绘制帧率 页面 | 是 | Pass | +| 请求自绘制内容绘制帧率开始 | 位于请求自绘制内容绘制帧率页面 | 点击Start | 两个方块分别按照 30hz、120hz 频率来回移动 | 是 | pass | +| 请求自绘制内容绘制帧率停止 | 位于请求自绘制内容绘制帧率页面 | 点击Stop | 两个方块移动停止 | 是 | pass | +| 请求自绘制内容绘制帧率返回主页 | 位于请求自绘制内容绘制帧率页面 | 点击Back | 回到主页 | 是 | pass | \ No newline at end of file diff --git a/graphic/DisplaySync/screenshots/device/UI.png b/graphic/DisplaySync/screenshots/device/UI.png new file mode 100644 index 0000000000000000000000000000000000000000..edaa1bd7b952da56ada1f17f230bedc87f3b4d6b Binary files /dev/null and b/graphic/DisplaySync/screenshots/device/UI.png differ diff --git a/graphic/DisplaySync/screenshots/device/XComponent.png b/graphic/DisplaySync/screenshots/device/XComponent.png new file mode 100644 index 0000000000000000000000000000000000000000..77d32d82edab02be8a93f43561283454764744f9 Binary files /dev/null and b/graphic/DisplaySync/screenshots/device/XComponent.png differ diff --git a/graphic/DisplaySync/screenshots/device/animation.png b/graphic/DisplaySync/screenshots/device/animation.png new file mode 100644 index 0000000000000000000000000000000000000000..ec438b209234337590d796a9fa445f08f6d5f9a2 Binary files /dev/null and b/graphic/DisplaySync/screenshots/device/animation.png differ diff --git a/graphic/DisplaySync/screenshots/device/index.png b/graphic/DisplaySync/screenshots/device/index.png new file mode 100644 index 0000000000000000000000000000000000000000..d8949b46e924459b59871c0351703ba0b8fedeee Binary files /dev/null and b/graphic/DisplaySync/screenshots/device/index.png differ