> 模板版本：v0.3.0

<p align="center">
  <h1 align="center"> <code>@ohmi/gl-react-native</code> </h1>
</p>


本项目基于 [gl-react-native@2.57.1](https://github.com/gre/gl-react-native-v2) 开发。

## 1.安装与使用

进入到工程目录并输入以下命令：

<!-- tabs:start -->

#### npm

```bash
npm install @ohmi/gl-react-native
```

#### yarn

```bash
yarn add @ohmi/gl-react-native
```

<!-- tabs:end -->

下面的代码展示了这个库的基本使用场景：

> [!WARNING] 使用时 import 的库名不变。

```js
import React, { useState } from 'react';
import { View, Text, StyleSheet, Button, ScrollView } from 'react-native';
import { Shaders, Node } from 'gl-react';
import { Surface } from 'gl-react-native';
import { TestSuite, Tester, TestCase } from '@rnoh/testerino';

export default function helloGL() {
  let [flag, setFlag] = useState(false)
  let [flag1, setFlag1] = useState(false)
  let [draw, setDraw] = useState(null)
  const shaders = Shaders.create({
    helloBlue: {
      frag: `
            precision highp float;
            varying vec2 uv;
            void main() {
              gl_FragColor = vec4(uv.x, uv.y, 0.5, 1.0);
            }
            `
    }
  });
  return (
    <ScrollView>
      <Tester>
        <TestSuite name="helloGl">
          <TestCase itShould="渐变,Surface-width,Surface-height,Node-sync,Node-backbuffering,Node-blendFunc,Node-clear,Node-onDraw" tags={['C_API']}>
            <Surface width={300} height={300}
              autoRedraw={true}
            >
              <Node
                width={100}
                height={100}
                sync={flag}
                backbuffering={flag1}
                shader={shaders.helloBlue}
                clear={{color:[0,0,255,0.3]}}
                onDraw={(item) => {
                  if (item) {
                    alert('执行onDraw')
                  }
                  setDraw(item)
                }}
              />
            </Surface>
            <View style={styles.view}>
              <Text>helloGL</Text>
              <Text>shader:gl_FragColor = vec4(uv.x, uv.y, 0.5, 1.0);</Text>
              <Text>Surface-width:300</Text>
              <Text>Surface-height:300</Text>
              <Text>Node-sync:{`${flag}`}</Text>
              <Text>Node-backbuffering:{`${flag1}`}</Text>
              <Text>Node-blendFunc:['srcAlpha', 'oneMinusSrcAlpha']</Text>
              <Text>Node-onDraw:{`${draw}`}</Text>
            </View>
            <View style={{ marginTop: 20 }}>
              <Button title='sync' onPress={() => {
                setFlag(!flag)
              }} />
              <Button title='backbuffering' onPress={() => {
                setFlag1(!flag1)
              }} />
            </View>
          </TestCase>
        </TestSuite>
      </Tester>
    </ScrollView>
  );
};
const styles = StyleSheet.create({
  view: {
    marginBottom: 10,
  },
  text: {
    color: 'white'
  }
});
```

## 2.Manual Link

此步骤为手动配置原生依赖项的指导。

首先需要使用 DevEco Studio 打开项目里的 HarmonyOS 工程 `harmony`。

### 2.1.Overrides RN SDK

为了让工程依赖同一个版本的 RN SDK，需要在工程根目录的 `oh-package.json5` 添加 overrides 字段，指向工程需要使用的 RN SDK 版本。替换的版本既可以是一个具体的版本号，也可以是一个模糊版本，还可以是本地存在的 HAR 包或源码目录。

关于该字段的作用请阅读[官方说明](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-oh-package-json5-V5#zh-cn_topic_0000001792256137_overrides)

```json
{
  ...
  "overrides": {
    "@rnoh/react-native-openharmony": "^0.72.38" // ohpm 在线版本
    // "@rnoh/react-native-openharmony" : "./react_native_openharmony.har" // 指向本地 har 包的路径
    // "@rnoh/react-native-openharmony" : "./react_native_openharmony" // 指向源码路径
  }
}
```

### 2.2.引入原生端代码

目前有两种方法：

- 通过 har 包引入；
- 直接链接源码。

方法一：通过 har 包引入（推荐）

> [!TIP] har 包位于三方库安装路径的 `harmony` 文件夹下。

打开 `entry/oh-package.json5`，添加以下依赖

```json
"dependencies": {
    "@ohmi/gl-react-native": "file:../../node_modules/@ohmi/gl-react-native/harmony/glRN.har"
  }
```

点击右上角的 `sync` 按钮

或者在命令行终端执行：

```bash
cd entry
ohpm install
```

### 2.3.配置 CMakeLists 和引入 ToolbarAndroidPackage

打开 `entry/src/main/cpp/CMakeLists.txt`，添加：

```diff
project(rnapp)
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_SKIP_BUILD_RPATH TRUE)
set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(NODE_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../node_modules")
+ set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
set(RNOH_CPP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../react-native-harmony/harmony/cpp")
set(LOG_VERBOSITY_LEVEL 1)
set(CMAKE_ASM_FLAGS "-Wno-error=unused-command-line-argument -Qunused-arguments")
set(CMAKE_CXX_FLAGS "-fstack-protector-strong -Wl,-z,relro,-z,now,-z,noexecstack -s -fPIE -pie")
set(WITH_HITRACE_SYSTRACE 1) # for other CMakeLists.txt files to use
add_compile_definitions(WITH_HITRACE_SYSTRACE)

# RNOH_BEGIN: manual_package_linking_1
add_subdirectory("../../../../sample_package/src/main/cpp" ./sample-package)
+ add_subdirectory("${OH_MODULES}/@ohmi/gl-react-native/src/main/cpp" ./glRN)
# RNOH_END: manual_package_linking_1

add_library(rnoh_app SHARED
    "./PackageProvider.cpp"
    "${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp"
)

target_link_libraries(rnoh_app PUBLIC rnoh)

# RNOH_BEGIN: link_packages
target_link_libraries(rnoh_app PUBLIC rnoh_sample_package)
+ target_link_libraries(rnoh_app PUBLIC rnoh_glRN)
# RNOH_END: link_packages
```

打开 `entry/src/main/cpp/PackageProvider.cpp`，添加：

```diff
...
+ #include "GLRNPackage.h"

using namespace rnoh;

std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
    return {
      ...
+     std::make_shared<GLRNPackage>(ctx)
    };
}
```

### 2.4.在 ArkTs 侧引入 RNCCheckBoxPackage

> [!TIP] 版本 v0.2.22 及以上需要

打开 `entry/src/main/ets/RNPackagesFactory.ts`，添加：

```diff
  ...
+ import { GLRNPackage } from '@ohmi/gl-react-native/ts';

export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
  return [
+   return [new GLRNPackage(ctx)];
  ];
}

```

### 2.5.在 ArkTs 侧引入 RNCToolbarAndroid 组件

找到 **function buildCustomRNComponent()**，一般位于 `entry/src/main/ets/pages/index.ets` 或 `entry/src/main/ets/rn/LoadBundle.ets`，添加：

```diff
  ...
+ import { RNCGLCanvas } from '@ohmi/gl-react-native'

  @Builder
  function buildCustomRNComponent(ctx: ComponentBuilderContext) {
    ...
+   if (ctx.componentName === RNCGLCanvas.NAME) {
+     RNCGLCanvas({
+      ctx: ctx.rnComponentContext,
+      tag: ctx.tag
+     })
+   }
    ...
  }
  ...
```

> [!TIP] 本库使用了混合方案，需要添加组件名。

在`entry/src/main/ets/pages/index.ets` 或 `entry/src/main/ets/rn/LoadBundle.ets` 找到常量 `arkTsComponentNames` 在其数组里添加组件名

```diff
const arkTsComponentNames: Array<string> = [
  ...
+ RNCGLCanvas.NAME
];
```

### 2.6.运行

点击右上角的 `sync` 按钮

或者在终端执行：

```bash
cd entry
ohpm install
```

然后编译、运行即可。

## 3.约束与限制

### 3.1兼容性

要使用此库，需要使用正确的 React-Native 和 RNOH 版本。另外，还需要使用配套的 DevEco Studio 和 手机 ROM。

请到三方库相应的 Releases 发布地址查看 Release 配套的版本信息：[@ohmi/gl-react-native Releases](https://gitee.com/kunyuan-hongke/gl-react-native)

## 4.属性

[!TIP] "Platform"列表示该属性在原三方库上支持的平台。

[!TIP] "HarmonyOS Support"列为 yes 表示 HarmonyOS 平台支持该属性；no 则表示不支持；partially 表示部分支持。使用方法跨平台一致，效果对标 iOS 或 Android 的效果。

| component/API(组件或者API名称)                   | 描述 (Description)                                           | 类型 (Type)     | 是否必填 (Required) | 平台 (Platform) | 支持鸿蒙系统 (HarmonyOS Support) |
| ------------------------------------------------ | ------------------------------------------------------------ | --------------- | ------------------- | --------------- | -------------------------------- |
| children（为Surface下的子节点）                  | 渲染一些 Node 和/或 Bus 的 React 元素树                      | 元素(node)      | yes                 | 所有平台 (All)  | 是 (yes)                         |
| width                                            | 指定 Surface 的宽度                                          | 数字(number)    | yes                 | 所有平台 (All)  | 是 (yes)                         |
| height                                           | 指定 Surface 的高度                                          | 数字(number)    | yes                 | 所有平台 (All)  | 是 (yes)                         |
| style                                            | 传递到底层 <canvas/> 或 <View/> 的 CSS 样式                  | 对象(object)    | no                  | 所有平台 (All)  | 是 (yes)                         |
| preload                                          | 在 Surface 开始渲染之前要预加载的事物数组。帮助避免闪烁并提供渲染初始状态所需的纹理 | 数组（array）   | no                  | 所有平台 (All)  | 否 (No)                          |
| onLoadError                                      | Surface 最初无法加载时调用的回调                             | 函数(function)  | no                  | 所有平台 (All)  | 否(No)                           |
| onContextLost                                    | 当 Surface 上下文丢失时调用的回调                            | 函数(function)  | no                  | 所有平台 (All)  | 否 (No)                          |
| onContextRestored                                | Surface 恢复并准备就绪时调用的回调                           | 函数(function)  | no                  | 所有平台 (All)  | 是 (yes)                         |
| onLoad                                           | 在 Surface 准备就绪且刚渲染后调用的回调                      | 函数(function)  | no                  | 所有平台 (All)  | 部分支持 (partially)             |
| onProgress                                       | 在资源加载过程中，该回调函数会返回加载进度信息               | 函数(function)  | no                  | 所有平台 (All)  | 部分支持 (partially)             |
| shader                                           | 指定使用的着色器对象，通过 Shaders.create 方法创建           | 对象(object)    | yes                 | 所有平台 (All)  | 是 (yes)                         |
| uniforms                                         | 传递给着色器的统一变量，是一个 JavaScript 对象，键为统一变量名，值为对应的值 | 对象(object)    | no                  | 所有平台 (All)  | 是 (yes)                         |
| uniformsOptions                                  | 允许配置 sampler2D 纹理的插值等属性                          | 对象(object)    | no                  | 所有平台 (All)  | 否 (No)                          |
| width                                            | 以实际像素为单位的宽度                                       | 数字(number)    | no                  | 所有平台 (All)  | 是 (yes)                         |
| height                                           | 以实际像素单位表示的高度                                     | 数字(number)    | no                  | 所有平台 (All)  | 是 (yes)                         |
| sync                                             | 如果为 true，则 React 更新将始终强制同步重绘 Node 帧缓冲区   | 布尔（Boolean） | no                  | 所有平台 (All)  | 否 (No)                          |
| backbuffering                                    | 可选属性，启用后缓冲功能，允许在统一变量中使用 Backbuffer 来获取上一帧缓冲区的纹理状态 | 布尔（Boolean） | no                  | 所有平台 (All)  | 否 (No)                          |
| blendFunc                                        | 配置要使用的混合函数                                         | 函数(function)  | no                  | 所有平台 (All)  | 否(No)                           |
| clear                                            | 可选属性，配置清除操作                                       | 对象(object)    | no                  | 所有平台 (All)  | 否 (No)                          |
| onDraw                                           | 每次为此节点生成绘制时调用的回调                             | 函数(function)  | no                  | 所有平台 (All)  | 否 (No)                          |
| children（为Node的子元素在uniforms里面进行体现） | 在高级用例中，您可以渲染 Bus 或内容以供 Node 使用            | 对象(object)    | no                  | 所有平台 (All)  | 是 (yes)                         |

## 5.遗留问题

## 6.其他

## 7.开源协议

本项目基于 [The MIT License (MIT)](https://gitee.com/kunyuan-hongke/gl-react-native/blob/master/LICENSE) ，请自由地享受和参与开源。
