五角星Demo

This commit is contained in:
JackLee 2026-02-25 15:30:46 +08:00
parent add8cd10bd
commit 898c2633e0
85 changed files with 2838 additions and 569 deletions

View File

@ -1,31 +1,18 @@
{ {
"apiType": "stageMode", "apiType": "stageMode",
"buildOption": { "buildOption": {
"resOptions": {
"copyCodeResource": {
"enable": false
},
},
"externalNativeOptions": { "externalNativeOptions": {
"path": "./src/main/cpp/CMakeLists.txt", "path": "./src/main/cpp/CMakeLists.txt",
"arguments": "-DCMAKE_BUILD_TYPE=Release", "arguments": "",
"cppFlags": "", "cppFlags": "",
"abiFilters": [ "abiFilters": [
"x86_64" "x86_64"
], ]
},
"arkOptions": {
"runtimeOnly" : {
"packages": [
"libopencax.so"
]
}
} }
}, },
"buildOptionSet": [ "buildOptionSet": [
{ {
"name": "release", "name": "release",
"debuggable": true,
"arkOptions": { "arkOptions": {
"obfuscation": { "obfuscation": {
"ruleOptions": { "ruleOptions": {
@ -46,7 +33,7 @@
], ],
"targets": [ "targets": [
{ {
"name": "default", "name": "default"
}, },
{ {
"name": "ohosTest", "name": "ohosTest",

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -17,7 +17,7 @@
# -keep-property-name: specifies property names that you want to keep # -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 # -keep-global-name: specifies names that you want to keep in the global scope
#-enable-property-obfuscation -enable-property-obfuscation
#-enable-toplevel-obfuscation -enable-toplevel-obfuscation
#-enable-filename-obfuscation -enable-filename-obfuscation
#-enable-export-obfuscation -enable-export-obfuscation

View File

@ -9,13 +9,9 @@ add_definitions(-DOHOS_PLATFORM)
include_directories(${NATIVERENDER_ROOT_PATH} include_directories(${NATIVERENDER_ROOT_PATH}
${NATIVERENDER_ROOT_PATH}/include ${NATIVERENDER_ROOT_PATH}/include
${NATIVERENDER_ROOT_PATH}/include/opencascade ${NATIVERENDER_ROOT_PATH}/include/opencascade
${NATIVERENDER_ROOT_PATH}/include/Add
) )
set(CMAKE_SKIP_BUILD_RPATH FALSE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
set(CMAKE_BUILD_RPATH_USE_ORIGIN "\${ORIGIN}")
set(CMAKE_INSTALL_RPATH "\${ORIGIN}")
# OCCT # OCCT
set(OCCT_VERSION "7.9") set(OCCT_VERSION "7.9")
set(OCCT_LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../libs/${OHOS_ARCH}) set(OCCT_LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../libs/${OHOS_ARCH})
@ -29,28 +25,19 @@ foreach(LIB_NAME ${OCCT_CORE_LIBS})
list(APPEND OCCT_IMPORTED_LIBS ${OCCT_LIB_DIR}/lib${LIB_NAME}.so.${OCCT_VERSION}) list(APPEND OCCT_IMPORTED_LIBS ${OCCT_LIB_DIR}/lib${LIB_NAME}.so.${OCCT_VERSION})
endforeach() endforeach()
#THIRD_PARTY_LIBS
set(THIRD_PARTY_LIBS
${OCCT_LIB_DIR}/libfreetype.so.6
${OCCT_LIB_DIR}/libexpat.so.1
${OCCT_LIB_DIR}/libfontconfig.so.1
${OCCT_LIB_DIR}/libbrotlidec.so.1
${OCCT_LIB_DIR}/libbrotlicommon.so.1
${OCCT_LIB_DIR}/libbrotlienc.so.1
${OCCT_LIB_DIR}/libpng16.so.16
${OCCT_LIB_DIR}/libbz2.so.1.0
${OCCT_LIB_DIR}/libz.so.1
)
# #
add_library(opencax SHARED add_library(opencax SHARED
# Header # Header
EGLCore/EGLCore.h NativeEGLOCCT/EGLConst.h
OCCTRender/OCCTRender.h NativeEGLOCCT/EGLCore.h
OCCTRenderThread/OCCTRenderThread.h NativeEGLOCCT/EGLRender.h
NativeEGLOCCT/NativeRender.h
NativeEGLOCCT/NativeManager.h
# Cpp Src # Cpp Src
EGLCore/EGLCore.cpp NativeEGLOCCT/EGLCore.cpp
OCCTRender/OCCTRender.cpp NativeEGLOCCT/EGLRender.cpp
OCCTRenderThread/OCCTRenderThread.cpp NativeEGLOCCT/NativeRender.cpp
NativeEGLOCCT/NativeManager.cpp
napi_init.cpp napi_init.cpp
) )
@ -72,6 +59,6 @@ target_link_libraries(opencax PUBLIC
${GLES-lib} ${GLES-lib}
#OCCT #OCCT
${OCCT_IMPORTED_LIBS} ${OCCT_IMPORTED_LIBS}
${THIRD_PARTY_LIBS} ${OCCT_LIB_DIR}/libNativeAdd.so
) )

View File

@ -1,74 +0,0 @@
//
// Created on 2026/2/18.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".
#include "EGLCore.h"
#include <GLES3/gl3.h>
#include <iostream>
EGLCore::EGLCore() : m_display(EGL_NO_DISPLAY), m_context(EGL_NO_CONTEXT), m_surface(EGL_NO_SURFACE) {}
EGLCore::~EGLCore() {
release();
}
bool EGLCore::init(EGLNativeWindowType window) {
m_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (m_display == EGL_NO_DISPLAY) return false;
if (!eglInitialize(m_display, nullptr, nullptr)) return false;
const EGLint attribs[] = {
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_BLUE_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_RED_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_DEPTH_SIZE, 16,
EGL_NONE
};
EGLConfig config;
EGLint numConfigs;
eglChooseConfig(m_display, attribs, &config, 1, &numConfigs);
const EGLint contextAttribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 3,
EGL_NONE
};
m_context = eglCreateContext(m_display, config, EGL_NO_CONTEXT, contextAttribs);
if (m_context == EGL_NO_CONTEXT) return false;
m_surface = eglCreateWindowSurface(m_display, config, window, nullptr);
if (m_surface == EGL_NO_SURFACE) return false;
m_initialized = true;
return true;
}
void EGLCore::makeCurrent() {
if (m_initialized) {
eglMakeCurrent(m_display, m_surface, m_surface, m_context);
}
}
void EGLCore::swapBuffers() {
if (m_initialized) {
eglSwapBuffers(m_display, m_surface);
}
}
void EGLCore::release() {
if (m_display != EGL_NO_DISPLAY) {
eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (m_context != EGL_NO_CONTEXT) eglDestroyContext(m_display, m_context);
if (m_surface != EGL_NO_SURFACE) eglDestroySurface(m_display, m_surface);
eglTerminate(m_display);
}
m_display = EGL_NO_DISPLAY;
m_context = EGL_NO_CONTEXT;
m_surface = EGL_NO_SURFACE;
m_initialized = false;
}

View File

@ -1,29 +0,0 @@
//
// Created on 2026/2/18.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".
#ifndef EGLCORE_H
#define EGLCORE_H
#include <EGL/egl.h>
#include <EGL/eglext.h>
class EGLCore {
public:
EGLCore();
~EGLCore();
bool init(EGLNativeWindowType window);
void makeCurrent();
void swapBuffers();
void release();
private:
EGLDisplay m_display;
EGLContext m_context;
EGLSurface m_surface;
bool m_initialized = false;
};
#endif // EGLCORE_H

View File

@ -0,0 +1,159 @@
/*
* 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.
*/
#ifndef NATIVEXCOMPONENT_EGLCONST_H
#define NATIVEXCOMPONENT_EGLCONST_H
// [Start egl_const_h]
// EGLConst.h
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES3/gl3.h>
const unsigned int LOG_PRINT_DOMAIN = 0xFF00;
/**
* Program
*/
const GLuint PROGRAM_ERROR = 0;
/**
*
*/
const GLint POSITION_ERROR = -1;
/**
* x坐标
*/
const int DEFAULT_X_POSITION = 0;
/**
* y坐标
*/
const int DEFAULT_Y_POSITION = 0;
/**
* Gl
*/
const GLfloat GL_RED_DEFAULT = 0.0;
/**
* Gl 绿
*/
const GLfloat GL_GREEN_DEFAULT = 0.0;
/**
* Gl
*/
const GLfloat GL_BLUE_DEFAULT = 0.0;
/**
* Gl
*/
const GLfloat GL_ALPHA_DEFAULT = 1.0;
/**
* Pointer
*/
const GLint POINTER_SIZE = 2;
/**
* Triangle fan
*/
const GLsizei TRIANGLE_FAN_SIZE = 4;
/**
* 50%
*/
const float FIFTY_PERCENT = 0.5;
/**
*
*/
const char POSITION_NAME[] = "a_position";
// [StartExclude egl_const_h]
/**
* numeric value 0.
*/
const int NUM_0 = 0;
/**
* numeric value 4.
*/
const int NUM_4 = 4;
// [EndExclude egl_const_h]
/**
* #f4f4f4.
*/
const GLfloat BACKGROUND_COLOR[] = {244.0f / 255, 244.0f / 255, 244.0f / 255, 1.0f};
// [StartExclude egl_const_h]
/**
* Background color #ffffff00.
*/
const GLfloat TRANSPARENT_COLOR[] = {255.0f / 255, 255.0f / 255, 255.0f / 255, 0.0f};
// [EndExclude egl_const_h]
/**
* Draw #7E8FFB.
*/
const GLfloat DRAW_COLOR[] = {126.0f / 255, 143.0f / 255, 251.0f / 255, 1.0f};
/**
* Change #92D6CC.
*/
const GLfloat CHANGE_COLOR[] = {146.0f / 255, 214.0f / 255, 204.0f / 255, 1.0f};
/**
*
*/
const GLfloat BACKGROUND_RECTANGLE_VERTICES[] = {-1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f};
const EGLint ATTRIB_LIST[] = {
// 键,值。
EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
// 结束。
EGL_NONE};
const EGLint CONTEXT_ATTRIBS[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
/**
*
*/
const char VERTEX_SHADER[] = "#version 300 es\n"
"layout(location = 0) in vec4 a_position;\n"
"layout(location = 1) in vec4 a_color; \n"
"out vec4 v_color; \n"
"void main() \n"
"{ \n"
" gl_Position = a_position; \n"
" v_color = a_color; \n"
"} \n";
/**
*
*/
const char FRAGMENT_SHADER[] = "#version 300 es\n"
"precision mediump float; \n"
"in vec4 v_color; \n"
"out vec4 fragColor; \n"
"void main() \n"
"{ \n"
" fragColor = v_color; \n"
"} \n";
// [End egl_const_h]
#endif // NATIVEXCOMPONENT_EGLCONST_H

View File

@ -0,0 +1,646 @@
/*
* 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.
*/
#include "EGLCore.h"
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <EGL/eglplatform.h>
#include <GLES3/gl3.h>
#include <cmath>
#include <cstdio>
#include <hilog/log.h>
#include "common.h"
namespace NativeOpenCAX {
namespace {
constexpr int32_t NUM_4 = 4;
/**
* Vertex shader.
*/
const char VERTEX_SHADER[] = "#version 300 es\n"
"layout(location = 0) in vec4 a_position;\n"
"layout(location = 1) in vec4 a_color; \n"
"out vec4 v_color; \n"
"void main() \n"
"{ \n"
" gl_Position = a_position; \n"
" v_color = a_color; \n"
"} \n";
/**
* Fragment shader.
*/
const char FRAGMENT_SHADER[] = "#version 300 es\n"
"precision mediump float; \n"
"in vec4 v_color; \n"
"out vec4 fragColor; \n"
"void main() \n"
"{ \n"
" fragColor = v_color; \n"
"} \n";
// [Start native_color]
/**
* #f4f4f4.
*/
const GLfloat BACKGROUND_COLOR[] = {244.0f / 255, 244.0f / 255, 244.0f / 255, 1.0f};
/**
* #7E8FFB.
*/
const GLfloat DRAW_COLOR[] = {126.0f / 255, 143.0f / 255, 251.0f / 255, 1.0f};
/**
* #92D6CC.
*/
const GLfloat CHANGE_COLOR[] = {146.0f / 255, 214.0f / 255, 204.0f / 255, 1.0f};
/**
*
*/
const GLfloat BACKGROUND_RECTANGLE_VERTICES[] = {
-1.0f, 1.0f,
1.0f, 1.0f,
1.0f, -1.0f,
-1.0f, -1.0f};
// [End native_color]
/**
* Get context parameter count.
*/
const size_t GET_CONTEXT_PARAM_CNT = 1;
/**
* Fifty percent.
*/
const float FIFTY_PERCENT = 0.5;
/**
* Pointer size.
*/
const GLint POINTER_SIZE = 2;
/**
* Triangle fan size.
*/
const GLsizei TRIANGLE_FAN_SIZE = 4;
/**
* Egl red size default.
*/
const int EGL_RED_SIZE_DEFAULT = 8;
/**
* Egl green size default.
*/
const int EGL_GREEN_SIZE_DEFAULT = 8;
/**
* Egl blue size default.
*/
const int EGL_BLUE_SIZE_DEFAULT = 8;
/**
* Egl alpha size default.
*/
const int EGL_ALPHA_SIZE_DEFAULT = 8;
/**
* Default x position.
*/
const int DEFAULT_X_POSITION = 0;
/**
* Default y position.
*/
const int DEFAULT_Y_POSITION = 0;
/**
* Gl red default.
*/
const GLfloat GL_RED_DEFAULT = 0.0;
/**
* Gl green default.
*/
const GLfloat GL_GREEN_DEFAULT = 0.0;
/**
* Gl blue default.
*/
const GLfloat GL_BLUE_DEFAULT = 0.0;
/**
* Gl alpha default.
*/
const GLfloat GL_ALPHA_DEFAULT = 1.0;
/**
* Program error.
*/
const GLuint PROGRAM_ERROR = 0;
/**
* Shape vertices size.
*/
const int SHAPE_VERTICES_SIZE = 8;
/**
* Position handle name.
*/
const char POSITION_NAME[] = "a_position";
/**
* Position error.
*/
const GLint POSITION_ERROR = -1;
/**
* Config attribute list.
*/
const EGLint ATTRIB_LIST[] = {
// Key,value.
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RED_SIZE, EGL_RED_SIZE_DEFAULT,
EGL_GREEN_SIZE, EGL_GREEN_SIZE_DEFAULT,
EGL_BLUE_SIZE, EGL_BLUE_SIZE_DEFAULT,
EGL_ALPHA_SIZE, EGL_ALPHA_SIZE_DEFAULT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
// End.
EGL_NONE};
/**
* Context attributes.
*/
const EGLint CONTEXT_ATTRIBS[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE};
} // namespace
// [Start native_create_context_init]
bool EGLCore::EglContextInit(void* window, int width, int height)
{
// [StartExclude native_create_context_init]
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "EGLCore", "EglContextInit execute");
if ((window == nullptr) || (width <= 0) || (height <= 0)) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "EglContextInit: param error");
return false;
}
// [EndExclude native_create_context_init]
UpdateSize(width, height);
eglWindow_ = static_cast<EGLNativeWindowType>(window);
// 初始化display
eglDisplay_ = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (eglDisplay_ == EGL_NO_DISPLAY) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglGetDisplay: unable to get EGL display");
return false;
}
// 初始化EGL
EGLint majorVersion;
EGLint minorVersion;
if (!eglInitialize(eglDisplay_, &majorVersion, &minorVersion)) {
OH_LOG_Print(
LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglInitialize: unable to get initialize EGL display");
return false;
}
// 选择配置
const EGLint maxConfigSize = 1;
EGLint numConfigs;
if (!eglChooseConfig(eglDisplay_, ATTRIB_LIST, &eglConfig_, maxConfigSize, &numConfigs)) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglChooseConfig: unable to choose configs");
return false;
}
// 创建环境
return CreateEnvironment();
}
// [End native_create_context_init]
// [Start native_create_environment]
bool EGLCore::CreateEnvironment()
{
// 创建Surface
if (eglWindow_ == nullptr) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglWindow_ is null");
return false;
}
eglSurface_ = eglCreateWindowSurface(eglDisplay_, eglConfig_, eglWindow_, NULL);
if (eglSurface_ == nullptr) {
OH_LOG_Print(
LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglCreateWindowSurface: unable to create surface");
return false;
}
// 创建context
eglContext_ = eglCreateContext(eglDisplay_, eglConfig_, EGL_NO_CONTEXT, CONTEXT_ATTRIBS);
if (!eglMakeCurrent(eglDisplay_, eglSurface_, eglSurface_, eglContext_)) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglMakeCurrent failed");
return false;
}
// 创建program
program_ = CreateProgram(VERTEX_SHADER, FRAGMENT_SHADER);
if (program_ == PROGRAM_ERROR) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "CreateProgram: unable to create program");
return false;
}
return true;
}
// [End native_create_environment]
// [Start native_background]
// 绘制背景颜色
void EGLCore::Background()
{
GLint position = PrepareDraw();
if (position == POSITION_ERROR) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Background get position failed");
return;
}
if (!ExecuteDraw(position, BACKGROUND_COLOR,
BACKGROUND_RECTANGLE_VERTICES, sizeof(BACKGROUND_RECTANGLE_VERTICES))) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Background execute draw failed");
return;
}
if (!FinishDraw()) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Background FinishDraw failed");
return;
}
}
// [End native_background]
// [Start native_draw]
void EGLCore::Draw(int& hasDraw)
{
flag_ = false;
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "EGLCore", "Draw");
GLint position = PrepareDraw();
if (position == POSITION_ERROR) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Draw get position failed");
return;
}
// 绘制背景
if (!ExecuteDraw(position, BACKGROUND_COLOR,
BACKGROUND_RECTANGLE_VERTICES, sizeof(BACKGROUND_RECTANGLE_VERTICES))) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Draw execute draw background failed");
return;
}
// 将五角星分为五个四边形,计算其中一个四边形的四个顶点
GLfloat rotateX = 0;
GLfloat rotateY = FIFTY_PERCENT * height_;
GLfloat centerX = 0;
// Convert DEG(54° & 18°) to RAD
GLfloat centerY = -rotateY * (M_PI / 180 * 54) * (M_PI / 180 * 18);
// Convert DEG(18°) to RAD
GLfloat leftX = -rotateY * (M_PI / 180 * 18);
GLfloat leftY = 0;
// Convert DEG(18°) to RAD
GLfloat rightX = rotateY * (M_PI / 180 * 18);
GLfloat rightY = 0;
// 确定绘制四边形的顶点,使用绘制区域的百分比表示
const GLfloat shapeVertices[] = { centerX / width_, centerY / height_, leftX / width_, leftY / height_,
rotateX / width_, rotateY / height_, rightX / width_, rightY / height_ };
if (!ExecuteDrawStar(position, DRAW_COLOR, shapeVertices, sizeof(shapeVertices))) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Draw execute draw shape failed");
return;
}
// Convert DEG(72°) to RAD
GLfloat rad = M_PI / 180 * 72;
// Rotate four times
// 在文件egl_core.cpp中定义NUM_4的值为4
for (int i = 0; i < NUM_4; ++i) {
// 旋转得其他四个四边形的顶点
Rotate2d(centerX, centerY, &rotateX, &rotateY, rad);
Rotate2d(centerX, centerY, &leftX, &leftY, rad);
Rotate2d(centerX, centerY, &rightX, &rightY, rad);
// 确定绘制四边形的顶点,使用绘制区域的百分比表示
const GLfloat shapeVertices[] = { centerX / width_, centerY / height_, leftX / width_, leftY / height_,
rotateX / width_, rotateY / height_, rightX / width_, rightY / height_ };
// 绘制图形
if (!ExecuteDrawStar(position, DRAW_COLOR, shapeVertices, sizeof(shapeVertices))) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Draw execute draw shape failed");
return;
}
}
// 结束绘制
if (!FinishDraw()) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Draw FinishDraw failed");
return;
}
hasDraw = 1;
flag_ = true;
}
// [End native_draw]
// [Start native_change_color]
void EGLCore::ChangeColor(int& hasChangeColor)
{
if (!flag_) {
return;
}
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "EGLCore", "ChangeColor");
GLint position = PrepareDraw();
if (position == POSITION_ERROR) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "ChangeColor get position failed");
return;
}
// 绘制背景
if (!ExecuteDraw(position, BACKGROUND_COLOR,
BACKGROUND_RECTANGLE_VERTICES, sizeof(BACKGROUND_RECTANGLE_VERTICES))) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "ChangeColor execute draw background failed");
return;
}
// 确定绘制四边形的顶点,使用绘制区域的百分比表示
GLfloat rotateX = 0;
GLfloat rotateY = FIFTY_PERCENT * height_;
GLfloat centerX = 0;
// Convert DEG(54° & 18°) to RAD
GLfloat centerY = -rotateY * (M_PI / 180 * 54) * (M_PI / 180 * 18);
// Convert DEG(18°) to RAD
GLfloat leftX = -rotateY * (M_PI / 180 * 18);
GLfloat leftY = 0;
// Convert DEG(18°) to RAD
GLfloat rightX = rotateY * (M_PI / 180 * 18);
GLfloat rightY = 0;
// 确定绘制四边形的顶点,使用绘制区域的百分比表示
const GLfloat shapeVertices[] = { centerX / width_, centerY / height_, leftX / width_, leftY / height_,
rotateX / width_, rotateY / height_, rightX / width_, rightY / height_ };
// 使用新的颜色绘制
if (!ExecuteDrawNewStar(0, CHANGE_COLOR, shapeVertices, sizeof(shapeVertices))) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Draw execute draw shape failed");
return;
}
// Convert DEG(72°) to RAD
GLfloat rad = M_PI / 180 * 72;
// Rotate four times
// 在文件egl_core.cpp中定义NUM_4的值为4
for (int i = 0; i < NUM_4; ++i) {
// 旋转得其他四个四边形的顶点
Rotate2d(centerX, centerY, &rotateX, &rotateY, rad);
Rotate2d(centerX, centerY, &leftX, &leftY, rad);
Rotate2d(centerX, centerY, &rightX, &rightY, rad);
// 确定绘制四边形的顶点,使用绘制区域的百分比表示
const GLfloat shapeVertices[] = { centerX / width_, centerY / height_, leftX / width_, leftY / height_,
rotateX / width_, rotateY / height_, rightX / width_, rightY / height_ };
// 使用新的颜色绘制
if (!ExecuteDrawNewStar(position, CHANGE_COLOR, shapeVertices, sizeof(shapeVertices))) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Draw execute draw shape failed");
return;
}
}
// 结束绘制
if (!FinishDraw()) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "ChangeColor FinishDraw failed");
}
hasChangeColor = 1;
}
// [StartExclude native_change_color]
// [Start native_prepare_draw]
// 绘前准备获取position创建成功时position值从0开始
GLint EGLCore::PrepareDraw()
{
if ((eglDisplay_ == nullptr) || (eglSurface_ == nullptr) || (eglContext_ == nullptr) ||
(!eglMakeCurrent(eglDisplay_, eglSurface_, eglSurface_, eglContext_))) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "PrepareDraw: param error");
return POSITION_ERROR;
}
// 该gl函数没有返回值。
glViewport(DEFAULT_X_POSITION, DEFAULT_Y_POSITION, width_, height_);
glClearColor(GL_RED_DEFAULT, GL_GREEN_DEFAULT, GL_BLUE_DEFAULT, GL_ALPHA_DEFAULT);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program_);
return glGetAttribLocation(program_, POSITION_NAME);
}
// [End native_prepare_draw]
// [Start native_execute_draw]
// 依据传入参数在指定区域绘制指定颜色
bool EGLCore::ExecuteDraw(GLint position, const GLfloat* color, const GLfloat shapeVertices[], unsigned long vertSize)
{
if ((position > 0) || (color == nullptr) || (vertSize / sizeof(shapeVertices[0])) != SHAPE_VERTICES_SIZE) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "ExecuteDraw: param error");
return false;
}
// 该gl函数没有返回值。
glVertexAttribPointer(position, POINTER_SIZE, GL_FLOAT, GL_FALSE, 0, shapeVertices);
glEnableVertexAttribArray(position);
glVertexAttrib4fv(1, color);
glDrawArrays(GL_TRIANGLE_FAN, 0, TRIANGLE_FAN_SIZE);
glDisableVertexAttribArray(position);
return true;
}
// [End native_execute_draw]
bool EGLCore::ExecuteDrawStar(
GLint position, const GLfloat* color, const GLfloat shapeVertices[], unsigned long vertSize)
{
if ((position > 0) || (color == nullptr) || (vertSize / sizeof(shapeVertices[0])) != SHAPE_VERTICES_SIZE) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "ExecuteDraw: param error");
return false;
}
// The gl function has no return value.
glVertexAttribPointer(position, POINTER_SIZE, GL_FLOAT, GL_FALSE, 0, shapeVertices);
glVertexAttribPointer(1, POINTER_SIZE, GL_FLOAT, GL_FALSE, 0, color);
glEnableVertexAttribArray(position);
glEnableVertexAttribArray(1);
glVertexAttrib4fv(1, color);
glDrawArrays(GL_TRIANGLE_FAN, 0, TRIANGLE_FAN_SIZE);
glDisableVertexAttribArray(position);
glDisableVertexAttribArray(1);
return true;
}
// [EndExclude native_change_color]
bool EGLCore::ExecuteDrawNewStar(
GLint position, const GLfloat* color, const GLfloat shapeVertices[], unsigned long vertSize)
{
if ((position > 0) || (color == nullptr) || (vertSize / sizeof(shapeVertices[0])) != SHAPE_VERTICES_SIZE) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "ExecuteDraw: param error");
return false;
}
// 该gl函数没有返回值。
glVertexAttribPointer(position, POINTER_SIZE, GL_FLOAT, GL_FALSE, 0, shapeVertices);
glEnableVertexAttribArray(position);
glVertexAttrib4fv(1, color);
glDrawArrays(GL_TRIANGLE_FAN, 0, TRIANGLE_FAN_SIZE);
glDisableVertexAttribArray(position);
return true;
}
// [End native_change_color]
void EGLCore::Rotate2d(GLfloat centerX, GLfloat centerY, GLfloat* rotateX, GLfloat* rotateY, GLfloat theta)
{
GLfloat tempX = cos(theta) * (*rotateX - centerX) - sin(theta) * (*rotateY - centerY);
GLfloat tempY = sin(theta) * (*rotateX - centerX) + cos(theta) * (*rotateY - centerY);
*rotateX = tempX + centerX;
*rotateY = tempY + centerY;
}
// [Start native_finish_draw]
// 结束绘制操作
bool EGLCore::FinishDraw()
{
// 强制刷新缓冲
glFlush();
glFinish();
return eglSwapBuffers(eglDisplay_, eglSurface_);
}
// [End native_finish_draw]
// [Start native_load_shader]
GLuint EGLCore::LoadShader(GLenum type, const char* shaderSrc)
{
if ((type <= 0) || (shaderSrc == nullptr)) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "glCreateShader type or shaderSrc error");
return PROGRAM_ERROR;
}
GLuint shader = glCreateShader(type);
if (shader == 0) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "glCreateShader unable to load shader");
return PROGRAM_ERROR;
}
// 该gl函数没有返回值。
glShaderSource(shader, 1, &shaderSrc, nullptr);
glCompileShader(shader);
GLint compiled;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
if (compiled != 0) {
return shader;
}
GLint infoLen = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen <= 1) {
glDeleteShader(shader);
return PROGRAM_ERROR;
}
char* infoLog = (char*)malloc(sizeof(char) * (infoLen + 1));
if (infoLog != nullptr) {
memset(infoLog, 0, infoLen + 1);
glGetShaderInfoLog(shader, infoLen, nullptr, infoLog);
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "glCompileShader error = %s", infoLog);
free(infoLog);
infoLog = nullptr;
}
glDeleteShader(shader);
return PROGRAM_ERROR;
}
// [End native_load_shader]
// [Start native_create_program]
GLuint EGLCore::CreateProgram(const char* vertexShader, const char* fragShader)
{
if ((vertexShader == nullptr) || (fragShader == nullptr)) {
OH_LOG_Print(
LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "createProgram: vertexShader or fragShader is null");
return PROGRAM_ERROR;
}
GLuint vertex = LoadShader(GL_VERTEX_SHADER, vertexShader);
if (vertex == PROGRAM_ERROR) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "createProgram vertex error");
return PROGRAM_ERROR;
}
GLuint fragment = LoadShader(GL_FRAGMENT_SHADER, fragShader);
if (fragment == PROGRAM_ERROR) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "createProgram fragment error");
return PROGRAM_ERROR;
}
GLuint program = glCreateProgram();
if (program == PROGRAM_ERROR) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "createProgram program error");
glDeleteShader(vertex);
glDeleteShader(fragment);
return PROGRAM_ERROR;
}
// 该gl函数没有返回值。
glAttachShader(program, vertex);
glAttachShader(program, fragment);
glLinkProgram(program);
GLint linked;
glGetProgramiv(program, GL_LINK_STATUS, &linked);
if (linked != 0) {
glDeleteShader(vertex);
glDeleteShader(fragment);
return program;
}
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "createProgram linked error");
GLint infoLen = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
char* infoLog = (char*)malloc(sizeof(char) * (infoLen + 1));
memset(infoLog, 0, infoLen + 1);
glGetProgramInfoLog(program, infoLen, nullptr, infoLog);
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "glLinkProgram error = %s", infoLog);
free(infoLog);
infoLog = nullptr;
}
glDeleteShader(vertex);
glDeleteShader(fragment);
glDeleteProgram(program);
return PROGRAM_ERROR;
}
// [End native_create_program]
// [Start native_update_size]
void EGLCore::UpdateSize(int width, int height)
{
// width_和height_在头文件中定义
width_ = width;
height_ = height;
if (width_ > 0) {
widthPercent_ = FIFTY_PERCENT * height_ / width_;
}
}
// [End native_update_size]
// [Start native_release]
void EGLCore::Release()
{
// 释放Surface
if ((eglDisplay_ == nullptr) || (eglSurface_ == nullptr) || (!eglDestroySurface(eglDisplay_, eglSurface_))) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Release eglDestroySurface failed");
}
// 释放context
if ((eglDisplay_ == nullptr) || (eglContext_ == nullptr) || (!eglDestroyContext(eglDisplay_, eglContext_))) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Release eglDestroyContext failed");
}
// 释放display
if ((eglDisplay_ == nullptr) || (!eglTerminate(eglDisplay_))) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Release eglTerminate failed");
}
}
// [End native_release]
} // namespace NativeXComponentSample

View File

@ -0,0 +1,60 @@
/*
* 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.
*/
#ifndef NATIVE_XCOMPONENT_EGL_CORE_H
#define NATIVE_XCOMPONENT_EGL_CORE_H
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES3/gl3.h>
#include "string"
namespace NativeOpenCAX {
class EGLCore {
public:
explicit EGLCore() {}
~EGLCore() {}
bool EglContextInit(void* window, int width, int height);
bool CreateEnvironment();
void Draw(int& hasDraw);
void Background();
void ChangeColor(int& hasChangeColor);
void Release();
void UpdateSize(int width, int height);
private:
GLuint LoadShader(GLenum type, const char* shaderSrc);
GLuint CreateProgram(const char* vertexShader, const char* fragShader);
GLint PrepareDraw();
bool ExecuteDraw(GLint position, const GLfloat* color, const GLfloat shapeVertices[], unsigned long vertSize);
bool ExecuteDrawStar(GLint position, const GLfloat* color, const GLfloat shapeVertices[], unsigned long vertSize);
bool ExecuteDrawNewStar(GLint position, const GLfloat* color,
const GLfloat shapeVertices[], unsigned long vertSize);
void Rotate2d(GLfloat centerX, GLfloat centerY, GLfloat* rotateX, GLfloat* rotateY, GLfloat theta);
bool FinishDraw();
private:
EGLNativeWindowType eglWindow_;
EGLDisplay eglDisplay_ = EGL_NO_DISPLAY;
EGLConfig eglConfig_ = EGL_NO_CONFIG_KHR;
EGLSurface eglSurface_ = EGL_NO_SURFACE;
EGLContext eglContext_ = EGL_NO_CONTEXT;
GLuint program_;
bool flag_ = false;
int width_;
int height_;
GLfloat widthPercent_;
};
} // namespace NativeXComponentSample
#endif // NATIVE_XCOMPONENT_EGL_CORE_H

View File

@ -0,0 +1,329 @@
/*
* 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.
*/
// [Start egl_render]
// EGLRender.cpp
#include "EGLRender.h"
#include "EGLConst.h"
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES3/gl3.h>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <hilog/log.h>
#include <iostream>
namespace {
void Rotate2d(GLfloat centerX, GLfloat centerY, GLfloat *rotateX, GLfloat *rotateY, GLfloat theta)
{
GLfloat tempX = cos(theta) * (*rotateX - centerX) - sin(theta) * (*rotateY - centerY);
GLfloat tempY = sin(theta) * (*rotateX - centerX) + cos(theta) * (*rotateY - centerY);
*rotateX = tempX + centerX;
*rotateY = tempY + centerY;
}
GLuint LoadShader(GLenum type, const char *shaderSrc)
{
if ((type <= 0) || (shaderSrc == nullptr)) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLRender", "glCreateShader type or shaderSrc error");
return PROGRAM_ERROR;
}
GLuint shader = glCreateShader(type);
if (shader == 0) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLRender", "glCreateShader unable to load shader");
return PROGRAM_ERROR;
}
// The gl function has no return value.
glShaderSource(shader, 1, &shaderSrc, nullptr);
glCompileShader(shader);
GLint compiled;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
if (compiled != 0) {
return shader;
}
GLint infoLen = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen <= 1) {
glDeleteShader(shader);
return PROGRAM_ERROR;
}
char *infoLog = (char *)malloc(sizeof(char) * (infoLen + 1));
if (infoLog != nullptr) {
memset(infoLog, 0, infoLen + 1);
glGetShaderInfoLog(shader, infoLen, nullptr, infoLog);
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLRender", "glCompileShader error = %s", infoLog);
free(infoLog);
infoLog = nullptr;
}
glDeleteShader(shader);
return PROGRAM_ERROR;
}
// 创建program
GLuint CreateProgram(const char *vertexShader, const char *fragShader)
{
if ((vertexShader == nullptr) || (fragShader == nullptr)) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLRender",
"createProgram: vertexShader or fragShader is null");
return PROGRAM_ERROR;
}
GLuint vertex = LoadShader(GL_VERTEX_SHADER, vertexShader);
if (vertex == PROGRAM_ERROR) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLRender", "createProgram vertex error");
return PROGRAM_ERROR;
}
GLuint fragment = LoadShader(GL_FRAGMENT_SHADER, fragShader);
if (fragment == PROGRAM_ERROR) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLRender", "createProgram fragment error");
return PROGRAM_ERROR;
}
GLuint program = glCreateProgram();
if (program == PROGRAM_ERROR) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLRender", "createProgram program error");
glDeleteShader(vertex);
glDeleteShader(fragment);
return PROGRAM_ERROR;
}
// 该gl函数没有返回值。
glAttachShader(program, vertex);
glAttachShader(program, fragment);
glLinkProgram(program);
GLint linked;
glGetProgramiv(program, GL_LINK_STATUS, &linked);
if (linked != 0) {
glDeleteShader(vertex);
glDeleteShader(fragment);
return program;
}
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLRender", "createProgram linked error");
GLint infoLen = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
char *infoLog = (char *)malloc(sizeof(char) * (infoLen + 1));
memset(infoLog, 0, infoLen + 1);
glGetProgramInfoLog(program, infoLen, nullptr, infoLog);
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLRender", "glLinkProgram error = %s", infoLog);
free(infoLog);
infoLog = nullptr;
}
glDeleteShader(vertex);
glDeleteShader(fragment);
glDeleteProgram(program);
return PROGRAM_ERROR;
}
} // namespace
bool EGLRender::SetUpEGLContext(void *window)
{
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "EGLRender", "EglContextInit execute");
eglWindow_ = (EGLNativeWindowType)(window);
// 初始化display。
eglDisplay_ = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (eglDisplay_ == EGL_NO_DISPLAY) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLRender", "eglGetDisplay: unable to get EGL display");
return false;
}
EGLint majorVersion;
EGLint minorVersion;
if (!eglInitialize(eglDisplay_, &majorVersion, &minorVersion)) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLRender",
"eglInitialize: unable to get initialize EGL display");
return false;
};
// 选择配置。
const EGLint maxConfigSize = 1;
EGLint numConfigs;
if (!eglChooseConfig(eglDisplay_, ATTRIB_LIST, &eglConfig_, maxConfigSize, &numConfigs)) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLRender", "eglChooseConfig: unable to choose configs");
return false;
};
// 创建环境。
// 创建 Surface。
eglSurface_ = eglCreateWindowSurface(eglDisplay_, eglConfig_, eglWindow_, NULL);
if (eglSurface_ == nullptr) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLRender",
"eglCreateWindowSurface: unable to create surface");
return false;
}
if (eglSurface_ == nullptr) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLRender",
"eglCreateWindowSurface: unable to create surface");
return false;
}
// 创建上下文。
eglContext_ = eglCreateContext(eglDisplay_, eglConfig_, EGL_NO_CONTEXT, CONTEXT_ATTRIBS);
if (!eglMakeCurrent(eglDisplay_, eglSurface_, eglSurface_, eglContext_)) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLRender", "eglMakeCurrent failed");
return false;
}
return true;
}
GLint EGLRender::PrepareDraw()
{
if ((eglDisplay_ == nullptr) || (eglSurface_ == nullptr) || (eglContext_ == nullptr) ||
(!eglMakeCurrent(eglDisplay_, eglSurface_, eglSurface_, eglContext_))) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLRender", "PrepareDraw: param error");
return POSITION_ERROR;
}
// 该gl函数没有返回值。
glViewport(DEFAULT_X_POSITION, DEFAULT_Y_POSITION, width_, height_);
glClearColor(GL_RED_DEFAULT, GL_GREEN_DEFAULT, GL_BLUE_DEFAULT, GL_ALPHA_DEFAULT);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program_);
return glGetAttribLocation(program_, POSITION_NAME);
}
// 绘制五角星
void EGLRender::DrawStar(bool drawColor)
{
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "EGLRender", "Draw");
GLint position = PrepareDraw();
if (position == POSITION_ERROR) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLRender", "Draw get position failed");
return;
}
// 绘制背景
if (!ExecuteDraw(position, BACKGROUND_COLOR, BACKGROUND_RECTANGLE_VERTICES)) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLRender", "Draw execute draw background failed");
return;
}
// 将其划分为五个四边形,并计算其中一个四边形的顶点
GLfloat rotateX = 0;
GLfloat rotateY = FIFTY_PERCENT * height_;
GLfloat centerX = 0;
// 将角度 54° 和 18° 转换为弧度
GLfloat centerY = -rotateY * (M_PI / 180 * 54) * (M_PI / 180 * 18);
// 将角度 18° 转换为弧度
GLfloat leftX = -rotateY * (M_PI / 180 * 18);
GLfloat leftY = 0;
// 将角度 18° 转换为弧度
GLfloat rightX = rotateY * (M_PI / 180 * 18);
GLfloat rightY = 0;
// 确定绘制四边形的顶点,使用绘制区域的百分比表示
const GLfloat shapeVertices[] = {centerX / width_, centerY / height_, leftX / width_, leftY / height_,
rotateX / width_, rotateY / height_, rightX / width_, rightY / height_};
auto color = drawColor ? DRAW_COLOR : CHANGE_COLOR;
if (!ExecuteDraw(position, color, shapeVertices)) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLRender", "Draw execute draw shape failed");
return;
}
// 将角度 72° 转换为弧度
GLfloat rad = M_PI / 180 * 72;
// 旋转四次。
// 在头文件EGLConst.h中定义NUM_0的值为0NUM_4的值为4
for (int i = NUM_0; i < NUM_4; ++i) {
// 旋转得其他四个四边形的顶点
Rotate2d(centerX, centerY, &rotateX, &rotateY, rad);
Rotate2d(centerX, centerY, &leftX, &leftY, rad);
Rotate2d(centerX, centerY, &rightX, &rightY, rad);
// 确定绘制四边形的顶点,使用绘制区域的百分比表示
const GLfloat shapeVertices[] = {centerX / width_, centerY / height_, leftX / width_, leftY / height_,
rotateX / width_, rotateY / height_, rightX / width_, rightY / height_};
// 绘制图形
if (!ExecuteDraw(position, color, shapeVertices)) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLRender", "Draw execute draw shape failed");
return;
}
}
// 将绘制命令提交给GPUGPU执行完成后将渲染结果显示到屏幕
glFlush();
glFinish();
if (!eglSwapBuffers(eglDisplay_, eglSurface_)) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLRender", "Draw FinishDraw failed");
return;
}
}
// [StartExclude egl_render]
void EGLRender::Clear()
{
if ((eglDisplay_ == nullptr) || (eglSurface_ == nullptr) || (eglContext_ == nullptr) ||
(!eglMakeCurrent(eglDisplay_, eglSurface_, eglSurface_, eglContext_))) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLRender", "PrepareDraw: param error");
return;
}
// The gl function has no return value.
glViewport(DEFAULT_X_POSITION, DEFAULT_Y_POSITION, width_, height_);
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
glFlush();
glFinish();
eglSwapBuffers(eglDisplay_, eglSurface_);
}
// [EndExclude egl_render]
bool EGLRender::ExecuteDraw(GLint position, const GLfloat *color, const GLfloat shapeVertices[])
{
if ((position > 0) || (color == nullptr)) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLRender", "ExecuteDraw: param error");
return false;
}
// 该gl函数没有返回值。
glVertexAttribPointer(position, POINTER_SIZE, GL_FLOAT, GL_FALSE, 0, shapeVertices);
glEnableVertexAttribArray(position);
glVertexAttrib4fv(1, color);
glDrawArrays(GL_TRIANGLE_FAN, 0, TRIANGLE_FAN_SIZE);
glDisableVertexAttribArray(position);
return true;
}
void EGLRender::SetEGLWindowSize(int width, int height)
{
width_ = width;
height_ = height;
}
// 释放相关资源
void EGLRender::DestroySurface()
{
if ((eglDisplay_ == nullptr) || (eglSurface_ == nullptr) || (!eglDestroySurface(eglDisplay_, eglSurface_))) {
OH_LOG_Print(LOG_APP, LOG_ERROR, 0xff00, "EGLRender", "Release eglDestroySurface failed");
}
if ((eglDisplay_ == nullptr) || (eglContext_ == nullptr) || (!eglDestroyContext(eglDisplay_, eglContext_))) {
OH_LOG_Print(LOG_APP, LOG_ERROR, 0xff00, "EGLRender", "Release eglDestroySurface failed");
}
if ((eglDisplay_ == nullptr) || (!eglTerminate(eglDisplay_))) {
OH_LOG_Print(LOG_APP, LOG_ERROR, 0xff00, "EGLRender", "Release eglDestroySurface failed");
}
eglDisplay_ = EGL_NO_DISPLAY;
eglSurface_ = EGL_NO_SURFACE;
eglContext_ = EGL_NO_CONTEXT;
}
// [End egl_render]

View File

@ -0,0 +1,53 @@
/*
* 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.
*/
#ifndef NATIVEXCOMPONENT_EGLRENDER_H
#define NATIVEXCOMPONENT_EGLRENDER_H
// [Start egl_render_h]
// EGLRender.h
#include "EGLConst.h"
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <EGL/eglplatform.h>
#include <GLES3/gl3.h>
#include <string>
class EGLRender {
public:
bool SetUpEGLContext(void *window);
void SetEGLWindowSize(int width, int height);
void DrawStar(bool drawColor);
void DestroySurface();
// [StartExclude egl_render_h]
void Clear();
// [EndExclude egl_render_h]
std::string xcomponentId;
EGLNativeWindowType eglWindow_;
EGLDisplay eglDisplay_ = EGL_NO_DISPLAY;
EGLConfig eglConfig_ = EGL_NO_CONFIG_KHR;
EGLSurface eglSurface_ = EGL_NO_SURFACE;
EGLContext eglContext_ = EGL_NO_CONTEXT;
GLuint program_;
int width_ = 0;
int height_ = 0;
private:
GLint PrepareDraw();
bool ExecuteDraw(GLint position, const GLfloat *color, const GLfloat shapeVertices[]);
};
// [End egl_render_h]
#endif // NATIVEXCOMPONENT_EGLRENDER_H

View File

@ -0,0 +1,670 @@
/*
* 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.
*/
#include "NativeManager.h"
#include <ace/xcomponent/native_interface_xcomponent.h>
#include <cstdint>
#include <cstdio>
#include <hilog/log.h>
#include <string>
#include "arkui/native_node.h"
#include "arkui/native_node_napi.h"
#include "arkui/native_interface.h"
#include "common.h"
#define COLUMN_MARGIN 10
#define XC_WIDTH 800
#define XC_HEIGHT 600
#define ARG_CNT 2
namespace NativeOpenCAX {
// [Start plugin_manager_cpp]
// plugin_manager.cpp
std::unordered_map<std::string, ArkUI_NodeHandle> NativeManager::nodeHandleMap_;
std::unordered_map<void *, OH_ArkUI_SurfaceCallback *> NativeManager::callbackMap_;
std::unordered_map<void *, OH_ArkUI_SurfaceHolder *> NativeManager::surfaceHolderMap_;
ArkUI_AccessibilityProvider *NativeManager::provider_ = nullptr;
ArkUI_NativeNodeAPI_1 *nodeAPI = reinterpret_cast<ArkUI_NativeNodeAPI_1 *>(
OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_NODE, "ArkUI_NativeNodeAPI_1"));
// [StartExclude plugin_manager_cpp]
NativeManager NativeManager::pluginManager_;
OH_NativeXComponent_Callback NativeManager::callback_;
ArkUI_NodeHandle xc;
int32_t NativeManager::hasDraw_ = 0;
int32_t NativeManager::hasChangeColor_ = 0;
NativeManager::~NativeManager()
{
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", "~NativeManager");
nativeXComponentMap_.clear();
if (eglcore_ != nullptr) {
delete eglcore_;
eglcore_ = nullptr;
}
for (auto iter = pluginManagerMap_.begin(); iter != pluginManagerMap_.end(); ++iter) {
if (iter->second != nullptr) {
delete iter->second;
iter->second = nullptr;
}
}
pluginManagerMap_.clear();
}
// [Start surface_holder]
void OnSurfaceCreatedNative(OH_ArkUI_SurfaceHolder *holder)
{
auto window = OH_ArkUI_XComponent_GetNativeWindow(holder); // 获取native window
auto render = reinterpret_cast<EGLRender*>(OH_ArkUI_SurfaceHolder_GetUserData(holder));
render->SetUpEGLContext(window); // 初始化egl环境
}
void OnSurfaceChangedNative(OH_ArkUI_SurfaceHolder *holder, uint64_t width, uint64_t height)
{
EGLRender* render = reinterpret_cast<EGLRender*>(OH_ArkUI_SurfaceHolder_GetUserData(holder));
render->SetEGLWindowSize(width, height); // 设置绘制区域大小
render->DrawStar(true); // 绘制五角星
}
void OnSurfaceDestroyedNative(OH_ArkUI_SurfaceHolder *holder)
{
OH_LOG_Print(LOG_APP, LOG_ERROR, 0xff00, "onBind", "on destroyed");
EGLRender* render = reinterpret_cast<EGLRender*>(OH_ArkUI_SurfaceHolder_GetUserData(holder));
render->DestroySurface(); // 销毁eglSurface相关资源
}
void OnSurfaceShowNative(OH_ArkUI_SurfaceHolder *holder)
{
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "onBind", "on surface show");
}
void OnSurfaceHideNative(OH_ArkUI_SurfaceHolder *holder)
{
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "onBind", "on surface hide");
}
void OnFrameCallbackNative(ArkUI_NodeHandle node, uint64_t timestamp, uint64_t targetTimestamp)
{
if (!NativeManager::surfaceHolderMap_.count(node)) {
return;
}
static uint64_t count = 0;
count++;
// 在头文件plugin_manager.h中定义FRAME_COUNT的值为50
if (count % FRAME_COUNT == 0) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "onBind", "OnFrameCallback count = %{public}ld", count);
}
}
void onEvent(ArkUI_NodeEvent *event)
{
auto eventType = OH_ArkUI_NodeEvent_GetEventType(event); // 获取组件事件类型
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "onBind", "on event");
if (eventType == NODE_TOUCH_EVENT) {
ArkUI_NodeHandle handle = OH_ArkUI_NodeEvent_GetNodeHandle(event); // 获取触发该事件的组件对象
auto holder = NativeManager::surfaceHolderMap_[handle];
EGLRender* render = reinterpret_cast<EGLRender*>(OH_ArkUI_SurfaceHolder_GetUserData(holder));
render->DrawStar(false); // 绘制五角星
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "onBind", "on touch");
}
}
// [End surface_holder]
// [EndExclude plugin_manager_cpp]
static std::string value2String(napi_env env, napi_value value)
{
size_t stringSize = 0;
napi_get_value_string_utf8(env, value, nullptr, 0, &stringSize);
std::string valueString;
valueString.resize(stringSize);
napi_get_value_string_utf8(env, value, &valueString[0], stringSize+1, &stringSize);
return valueString;
}
// [StartExclude plugin_manager_cpp]
napi_value NativeManager::GetXComponentStatus(napi_env env, napi_callback_info info)
{
napi_value hasDraw;
napi_value hasChangeColor;
napi_status ret = napi_create_int32(env, hasDraw_, &(hasDraw));
if (ret != napi_ok) {
OH_LOG_Print(
LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "GetXComponentStatus", "napi_create_int32 hasDraw_ error");
return nullptr;
}
ret = napi_create_int32(env, hasChangeColor_, &(hasChangeColor));
if (ret != napi_ok) {
OH_LOG_Print(
LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "GetXComponentStatus", "napi_create_int32 hasChangeColor_ error");
return nullptr;
}
napi_value obj;
ret = napi_create_object(env, &obj);
if (ret != napi_ok) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "GetXComponentStatus", "napi_create_object error");
return nullptr;
}
ret = napi_set_named_property(env, obj, "hasDraw", hasDraw);
if (ret != napi_ok) {
OH_LOG_Print(
LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "GetXComponentStatus", "napi_set_named_property hasDraw error");
return nullptr;
}
ret = napi_set_named_property(env, obj, "hasChangeColor", hasChangeColor);
if (ret != napi_ok) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "GetXComponentStatus",
"napi_set_named_property hasChangeColor error");
return nullptr;
}
return obj;
}
// [Start plugin_draw_pattern]
napi_value NativeManager::NapiDrawPattern(napi_env env, napi_callback_info info)
{
// [StartExclude plugin_draw_pattern]
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "NativeManager", "NapiDrawPattern");
if ((env == nullptr) || (info == nullptr)) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "NativeManager", "NapiDrawPattern: env or info is null");
return nullptr;
}
// [EndExclude plugin_draw_pattern]
// 获取环境变量参数
napi_value thisArg;
if (napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr) != napi_ok) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "NativeManager", "NapiDrawPattern: napi_get_cb_info fail");
return nullptr;
}
auto *pluginManger = NativeManager::GetInstance();
// 调用绘制方法
pluginManger->eglcore_->Draw(hasDraw_);
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "NativeManager", "render->eglCore_->Draw() executed");
return nullptr;
}
// [End plugin_draw_pattern]
// [Start plugin_on_surface_created]
// 定义一个函数OnSurfaceCreatedCB(),封装初始化环境与绘制背景
void OnSurfaceCreatedCB(OH_NativeXComponent* component, void* window)
{
// [StartExclude plugin_on_surface_created]
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "XComponent_Native", "OnSurfaceCreatedCB");
int32_t ret;
char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {};
uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
ret = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize);
if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
return;
}
std::string id(idStr);
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "XComponent_Native", "OnSurfaceCreatedCB id=%{public}s",
id.c_str());
// [EndExclude plugin_on_surface_created]
// 初始化环境与绘制背景
auto *pluginManger = NativeManager::GetInstance();
pluginManger->OnSurfaceCreated(component, window);
}
// [End plugin_on_surface_created]
// [Start plugin_on_surface_changed]
// 定义一个函数OnSurfaceChangedCB()
void OnSurfaceChangedCB(OH_NativeXComponent* component, void* window)
{
// [StartExclude plugin_on_surface_changed]
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "XComponent_Native", "OnSurfaceChangedCB");
int32_t ret;
char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {};
uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
ret = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize);
if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
return;
}
std::string id(idStr);
// [EndExclude plugin_on_surface_changed]
auto *pluginManger = NativeManager::GetInstance();
// 封装OnSurfaceChanged方法
pluginManger->OnSurfaceChanged(component, window);
}
// [End plugin_on_surface_changed]
// [Start plugin_on_surface_destroyed]
// 定义一个函数OnSurfaceDestroyedCB()将NativeRender类内释放资源的方法Release()封装在其中
void OnSurfaceDestroyedCB(OH_NativeXComponent* component, void* window)
{
// [StartExclude plugin_on_surface_destroyed]
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", "OnSurfaceDestroyedCB");
int32_t ret;
char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {};
uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
ret = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize);
if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
return;
}
std::string id(idStr);
// [EndExclude plugin_on_surface_destroyed]
auto *pluginManger = NativeManager::GetInstance();
pluginManger->OnSurfaceDestroyed(component, window);
}
// [End plugin_on_surface_destroyed]
// [Start plugin_dispatch_touch_event]
// 定义一个函数DispatchTouchEventCB(),响应触摸事件时触发该回调
void DispatchTouchEventCB(OH_NativeXComponent* component, void* window)
{
// [StartExclude plugin_dispatch_touch_event]
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", "DispatchTouchEventCB");
int32_t ret;
char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {};
uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
ret = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize);
if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
return;
}
std::string id(idStr);
// [EndExclude plugin_dispatch_touch_event]
auto *pluginManger = NativeManager::GetInstance();
pluginManger->DispatchTouchEvent(component, window);
}
// [End plugin_dispatch_touch_event]
NativeManager::NativeManager()
{
eglcore_ = new EGLCore();
callback_.OnSurfaceCreated = OnSurfaceCreatedCB;
callback_.OnSurfaceChanged = OnSurfaceChangedCB;
callback_.OnSurfaceDestroyed = OnSurfaceDestroyedCB;
callback_.DispatchTouchEvent = DispatchTouchEventCB;
}
// [Start plugin_create_native_node]
ArkUI_NodeHandle CreateNodeHandle(const std::string &tag)
{
ArkUI_NodeHandle column = nodeAPI->createNode(ARKUI_NODE_RELATIVE_CONTAINER);
ArkUI_NumberValue value[] = {480};
ArkUI_NumberValue value1[] = {{.u32 = 15}, {.f32 = 15}};
ArkUI_AttributeItem item = {value, 1, "changeSize"};
ArkUI_AttributeItem item1 = {value1, 2};
nodeAPI->setAttribute(column, NODE_WIDTH, &item);
value[0].f32 = COLUMN_MARGIN;
nodeAPI->setAttribute(column, NODE_MARGIN, &item);
// 创建XComponent组件
xc = nodeAPI->createNode(ARKUI_NODE_XCOMPONENT);
// 设置XComponent组件属性
value[0].u32 = ARKUI_XCOMPONENT_TYPE_SURFACE;
nodeAPI->setAttribute(xc, NODE_XCOMPONENT_TYPE, &item);
nodeAPI->setAttribute(xc, NODE_XCOMPONENT_ID, &item);
nodeAPI->setAttribute(xc, NODE_XCOMPONENT_SURFACE_SIZE, &item1);
ArkUI_NumberValue focusable[] = {1};
focusable[0].i32 = 1;
ArkUI_AttributeItem focusableItem = {focusable, 1};
nodeAPI->setAttribute(xc, NODE_FOCUSABLE, &focusableItem);
ArkUI_NumberValue valueSize[] = {480};
ArkUI_AttributeItem itemSize = {valueSize, 1};
valueSize[0].f32 = XC_WIDTH;
nodeAPI->setAttribute(xc, NODE_WIDTH, &itemSize);
valueSize[0].f32 = XC_HEIGHT;
nodeAPI->setAttribute(xc, NODE_HEIGHT, &itemSize);
ArkUI_AttributeItem item2 = {value, 1, "ndkxcomponent"};
nodeAPI->setAttribute(xc, NODE_ID, &item2);
auto *nativeXComponent = OH_NativeXComponent_GetNativeXComponent(xc);
if (!nativeXComponent) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "NativeManager", "GetNativeXComponent error");
return column;
}
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "NativeManager", "GetNativeXComponent success");
// 注册XComponent回调函数
OH_NativeXComponent_RegisterCallback(nativeXComponent, &NativeManager::callback_);
auto typeRet = nodeAPI->getAttribute(xc, NODE_XCOMPONENT_TYPE);
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "NativeManager", "xcomponent type: %{public}d",
typeRet->value[0].i32);
auto idRet = nodeAPI->getAttribute(xc, NODE_XCOMPONENT_ID);
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "NativeManager", "xcomponent id: %{public}s",
idRet->string);
nodeAPI->addChild(column, xc);
return column;
}
napi_value NativeManager::createNativeNode(napi_env env, napi_callback_info info)
{
if ((env == nullptr) || (info == nullptr)) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "NativeManager", "CreateNativeNode env or info is null");
return nullptr;
}
size_t argCnt = 2;
napi_value args[2] = { nullptr, nullptr };
if (napi_get_cb_info(env, info, &argCnt, args, nullptr, nullptr) != napi_ok) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "NativeManager", "CreateNativeNode napi_get_cb_info failed");
}
if (argCnt != ARG_CNT) {
napi_throw_type_error(env, NULL, "Wrong number of arguments");
return nullptr;
}
ArkUI_NodeContentHandle nodeContentHandle_ = nullptr;
OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &nodeContentHandle_);
nodeAPI = reinterpret_cast<ArkUI_NativeNodeAPI_1*>(
OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_NODE, "ArkUI_NativeNodeAPI_1")
);
std::string tag = value2String(env, args[1]);
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "NativeManager", "tag=%{public}s", tag.c_str());
int32_t ret = OH_ArkUI_NodeContent_SetUserData(nodeContentHandle_, new std::string(tag));
if (ret != ARKUI_ERROR_CODE_NO_ERROR) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "NativeManager", "setUserData failed error=%{public}d", ret);
}
if (nodeAPI != nullptr && nodeAPI->createNode != nullptr && nodeAPI->addChild != nullptr) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "NativeManager",
"CreateNativeNode tag=%{public}s", tag.c_str());
auto nodeContentEvent = [](ArkUI_NodeContentEvent *event) {
ArkUI_NodeContentHandle handle = OH_ArkUI_NodeContentEvent_GetNodeContentHandle(event);
std::string *userDate = reinterpret_cast<std::string*>(OH_ArkUI_NodeContent_GetUserData(handle));
if (OH_ArkUI_NodeContentEvent_GetEventType(event) == NODE_CONTENT_EVENT_ON_ATTACH_TO_WINDOW) {
ArkUI_NodeHandle testNode;
if (userDate) {
testNode = CreateNodeHandle(*userDate);
delete userDate;
userDate = nullptr;
} else {
testNode = CreateNodeHandle("noUserData");
}
OH_ArkUI_NodeContent_AddNode(handle, testNode);
}
};
OH_ArkUI_NodeContent_RegisterCallback(nodeContentHandle_, nodeContentEvent);
}
return nullptr;
}
// [End plugin_create_native_node]
void NativeManager::OnSurfaceCreated(OH_NativeXComponent* component, void* window)
{
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "XComponent_Native", "NativeManager::OnSurfaceCreated");
int32_t ret;
char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {};
uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
ret = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize);
ret = OH_NativeXComponent_GetXComponentSize(component, window, &width_, &height_);
if (ret == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
eglcore_->EglContextInit(window, width_, height_);
eglcore_->Background();
}
}
void NativeManager::OnSurfaceDestroyed(OH_NativeXComponent* component, void* window)
{
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "XComponent_Native", "NativeManager::OnSurfaceDestroyed");
}
void NativeManager::DispatchTouchEvent(OH_NativeXComponent* component, void* window)
{
int32_t ret = OH_NativeXComponent_GetTouchEvent(component, window, &touchEvent_);
if (ret == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
float tiltX = 2.2;
float tiltY = 2.2;
OH_NativeXComponent_TouchPointToolType toolType =
OH_NativeXComponent_TouchPointToolType::OH_NATIVEXCOMPONENT_TOOL_TYPE_LENS;
OH_NativeXComponent_GetTouchPointToolType(component, 0, &toolType);
OH_NativeXComponent_GetTouchPointTiltX(component, 0, &tiltX);
OH_NativeXComponent_GetTouchPointTiltY(component, 0, &tiltY);
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "XComponent_Native",
"Touch Info : x=%{public}f, y=%{public}f screenx=%{public}f, screeny=%{public}f,"
"type=%{public}d, force=%{public}f, tiltX=%{public}f, tiltY=%{public}f, toolType=%{public}d",
touchEvent_.x, touchEvent_.y, touchEvent_.screenX,
touchEvent_.screenY, touchEvent_.type, touchEvent_.force, tiltX, tiltY, toolType);
if (touchEvent_.type == OH_NativeXComponent_TouchEventType::OH_NATIVEXCOMPONENT_UP) {
eglcore_->ChangeColor(hasChangeColor_);
}
} else {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "XComponent_Native", "touch fail");
}
int32_t size = 0;
OH_NativeXComponent_HistoricalPoint *points = nullptr;
if (OH_NativeXComponent_GetHistoricalPoints(component, window, &size, &points) ==
OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "XComponent_Native", "HistoricalPoints size=%{public}d",
size);
for (auto i = 0; i < size; i++) {
auto point = points[i];
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "XComponent_Native",
"HistoricalPoint %{public}d Info : id=%{public}d, x=%{public}f, y=%{public}f, "
"type=%{public}d, timeStamp=%{public}lld, sourceTool=%{public}d",
i, point.id, point.x, point.y, point.type, point.timeStamp, point.sourceTool);
}
}
}
void NativeManager::OnSurfaceChanged(OH_NativeXComponent* component, void* window)
{
int32_t ret = OH_NativeXComponent_GetXComponentSize(component, window, &width_, &height_);
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "XComponent_Native",
"OnSurfaceChanged ret=%{public}d width=%{public}lu, height=%{public}lu", ret, width_, height_);
}
napi_value NativeManager::GetContext(napi_env env, napi_callback_info info)
{
if ((env == nullptr) || (info == nullptr)) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "NativeManager", "GetContext env or info is null");
return nullptr;
}
size_t argCnt = 1;
napi_value args[1] = { nullptr };
if (napi_get_cb_info(env, info, &argCnt, args, nullptr, nullptr) != napi_ok) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "NativeManager", "GetContext napi_get_cb_info failed");
}
if (argCnt != 1) {
napi_throw_type_error(env, NULL, "Wrong number of arguments");
return nullptr;
}
napi_valuetype valuetype;
if (napi_typeof(env, args[0], &valuetype) != napi_ok) {
napi_throw_type_error(env, NULL, "napi_typeof failed");
return nullptr;
}
if (valuetype != napi_number) {
napi_throw_type_error(env, NULL, "Wrong type of arguments");
return nullptr;
}
int64_t value;
if (napi_get_value_int64(env, args[0], &value) != napi_ok) {
napi_throw_type_error(env, NULL, "napi_get_value_int64 failed");
return nullptr;
}
napi_value exports;
if (napi_create_object(env, &exports) != napi_ok) {
napi_throw_type_error(env, NULL, "napi_create_object failed");
return nullptr;
}
return exports;
}
void NativeManager::SetNativeXComponent(std::string& id, OH_NativeXComponent* nativeXComponent)
{
if (nativeXComponent == nullptr) {
return;
}
nativeXComponentMap_[id] = nativeXComponent;
}
// [EndExclude plugin_manager_cpp]
napi_value NativeManager::BindNode(napi_env env, napi_callback_info info)
{
size_t argc = 2;
napi_value args[2] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
std::string nodeId = value2String(env, args[0]);
ArkUI_NodeHandle handle;
OH_ArkUI_GetNodeHandleFromNapiValue(env, args[1], &handle); // 获取 nodeHandle
OH_ArkUI_SurfaceHolder *holder = OH_ArkUI_SurfaceHolder_Create(handle); // 获取 SurfaceHolder
nodeHandleMap_[nodeId] = handle;
surfaceHolderMap_[handle] = holder;
auto callback = OH_ArkUI_SurfaceCallback_Create(); // 创建 SurfaceCallback
callbackMap_[holder] = callback;
auto render = new EGLRender();
OH_ArkUI_SurfaceHolder_SetUserData(holder, render); // 将render保存在holder中
OH_ArkUI_SurfaceCallback_SetSurfaceCreatedEvent(callback, OnSurfaceCreatedNative); // 注册OnSurfaceCreated回调
OH_ArkUI_SurfaceCallback_SetSurfaceChangedEvent(callback, OnSurfaceChangedNative); // 注册OnSurfaceChanged回调
OH_ArkUI_SurfaceCallback_SetSurfaceDestroyedEvent(callback, OnSurfaceDestroyedNative); // 注册OnSurfaceDestroyed回调
OH_ArkUI_SurfaceCallback_SetSurfaceShowEvent(callback, OnSurfaceShowNative); // 注册OnSurfaceShow回调
OH_ArkUI_SurfaceCallback_SetSurfaceHideEvent(callback, OnSurfaceHideNative); // 注册OnSurfaceHide回调
OH_ArkUI_XComponent_RegisterOnFrameCallback(handle, OnFrameCallbackNative); // 注册OnFrameCallback回调
OH_ArkUI_SurfaceHolder_AddSurfaceCallback(holder, callback); // 注册SurfaceCallback回调
if (!nodeAPI->addNodeEventReceiver(handle, onEvent)) { // 添加事件监听,返回成功码 0
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "onBind", "addNodeEventReceiver error");
}
if (!nodeAPI->registerNodeEvent(handle, NODE_TOUCH_EVENT, 0, nullptr)) { // 用C接口注册touch事件返回成功码 0
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "onBind", "registerTouchEvent error");
}
provider_ = OH_ArkUI_AccessibilityProvider_Create(handle); // 创建一个ArkUI_AccessibilityProvider类型的对象
/**
* ArkUI_AccessibilityProvider后
* https://gitcode.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/ndk-accessibility-xcomponent.md
* **/
return nullptr;
}
napi_value NativeManager::UnbindNode(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value args[1] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
std::string nodeId = value2String(env, args[0]);
ArkUI_NodeHandle node;
if (nodeHandleMap_.find(nodeId) == nodeHandleMap_.end()) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "SetNeedSoftKeyboard", "nodeId not exit error");
return nullptr;
}
node = nodeHandleMap_[nodeId];
OH_ArkUI_XComponent_UnregisterOnFrameCallback(node); // 解注册帧回调
OH_ArkUI_AccessibilityProvider_Dispose(provider_); // 销毁 ArkUI_AccessibilityProvider
auto holder = surfaceHolderMap_[node];
if (NativeManager::callbackMap_.count(holder)) {
auto callback = NativeManager::callbackMap_[holder];
OH_ArkUI_SurfaceHolder_RemoveSurfaceCallback(holder, callback); // 移除SurfaceCallback
OH_ArkUI_SurfaceCallback_Dispose(callback); // 销毁surfaceCallback
NativeManager::callbackMap_.erase(holder);
}
auto render = reinterpret_cast<NativeRender*>(OH_ArkUI_SurfaceHolder_GetUserData(holder));
delete render; // 销毁EGLRender对象
OH_ArkUI_SurfaceHolder_Dispose(holder); // 销毁surfaceHolder
nodeAPI->disposeNode(node); // 销毁nodeHandle
nodeHandleMap_.erase(nodeId);
return nullptr;
}
napi_value NativeManager::SetFrameRate(napi_env env, napi_callback_info info)
{
size_t argc = 4;
napi_value args[4] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
std::string nodeId = value2String(env, args[0]);
auto node = nodeHandleMap_[nodeId];
int32_t min = 0;
napi_get_value_int32(env, args[FIRST_ARG], &min);
int32_t max = 0;
napi_get_value_int32(env, args[SECOND_ARG], &max);
int32_t expected = 0;
napi_get_value_int32(env, args[THIRD_ARG], &expected);
OH_NativeXComponent_ExpectedRateRange range = {.min = min, .max = max, .expected = expected};
OH_ArkUI_XComponent_SetExpectedFrameRateRange(node, range); // 设置期望帧率
return nullptr;
}
napi_value NativeManager::SetNeedSoftKeyboard(napi_env env, napi_callback_info info)
{
size_t argc = 2;
napi_value args[2] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
std::string nodeId = value2String(env, args[0]);
ArkUI_NodeHandle node;
if (nodeHandleMap_.find(nodeId) == nodeHandleMap_.end()) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "SetNeedSoftKeyboard", "nodeId not exit error");
return nullptr;
}
node = nodeHandleMap_[nodeId];
bool needSoftKeyboard = false;
napi_get_value_bool(env, args[1], &needSoftKeyboard);
OH_ArkUI_XComponent_SetNeedSoftKeyboard(node, needSoftKeyboard); // 设置是否需要软键盘
return nullptr;
}
// [End plugin_manager_cpp]
napi_value NativeManager::Initialize(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value args[1] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
std::string nodeId = value2String(env, args[0]);
ArkUI_NodeHandle node;
if (nodeHandleMap_.find(nodeId) == nodeHandleMap_.end()) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "SetNeedSoftKeyboard", "nodeId not exit error");
return nullptr;
}
node = nodeHandleMap_[nodeId];
bool autoInitialize = 1;
OH_ArkUI_XComponent_SetAutoInitialize(node, autoInitialize);
OH_ArkUI_XComponent_Initialize(node);
bool isInitialized;
OH_ArkUI_XComponent_IsInitialized(node, &isInitialized);
auto holder = surfaceHolderMap_[node];
EGLRender* render = reinterpret_cast<EGLRender*>(OH_ArkUI_SurfaceHolder_GetUserData(holder));
render->DrawStar(true); // 绘制五角星
return nullptr;
}
napi_value NativeManager::Finalize(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value args[1] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
std::string nodeId = value2String(env, args[0]);
ArkUI_NodeHandle node;
if (nodeHandleMap_.find(nodeId) == nodeHandleMap_.end()) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "SetNeedSoftKeyboard", "nodeId not exit error");
return nullptr;
}
node = nodeHandleMap_[nodeId];
auto holder = surfaceHolderMap_[node];
EGLRender* render = reinterpret_cast<EGLRender*>(OH_ArkUI_SurfaceHolder_GetUserData(holder));
render->Clear();
OH_ArkUI_XComponent_Finalize(node);
return nullptr;
}
napi_value NativeManager::DrawStar(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value args[1] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
std::string nodeId = value2String(env, args[0]);
ArkUI_NodeHandle node;
if (nodeHandleMap_.find(nodeId) == nodeHandleMap_.end()) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "SetNeedSoftKeyboard", "nodeId not exit error");
return nullptr;
}
node = nodeHandleMap_[nodeId];
auto holder = surfaceHolderMap_[node];
EGLRender* render = reinterpret_cast<EGLRender*>(OH_ArkUI_SurfaceHolder_GetUserData(holder));
OH_LOG_Print(LOG_APP, LOG_ERROR, 0xff00, "onBind", "YGB DrawStar w:[%{public}d],h[%{public}d]", render->width_,
render->height_);
render->DrawStar(true); // 绘制五角星
return nullptr;
}
} // namespace NativeXComponentSample

View File

@ -0,0 +1,108 @@
/*
* 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.
*/
#ifndef NATIVE_XCOMPONENT_PLUGIN_MANAGER_H
#define NATIVE_XCOMPONENT_PLUGIN_MANAGER_H
#include <ace/xcomponent/native_interface_xcomponent.h>
#include <cstdint>
#include <js_native_api.h>
#include <js_native_api_types.h>
#include <napi/native_api.h>
#include <string>
#include <unordered_map>
#include "EGLCore.h"
#include "EGLRender.h"
#include "arkui/native_node.h"
#include "arkui/native_node_napi.h"
#include "NativeRender.h"
// [Start plugin_manager_h_part]
// plugin_manager.h
namespace NativeOpenCAX {
// [StartExclude plugin_manager_h_part]
constexpr const int FIRST_ARG = 1;
constexpr const int SECOND_ARG = 2;
constexpr const int THIRD_ARG = 3;
constexpr const int FRAME_COUNT = 50;
// [Start plugin_manager_h]
// 在头文件中定义NativeManager类
// [EndExclude plugin_manager_h_part]
class NativeManager {
public:
// [StartExclude plugin_manager_h_part]
static OH_NativeXComponent_Callback callback_;
NativeManager();
~NativeManager();
static NativeManager* GetInstance()
{
return &NativeManager::pluginManager_;
}
static napi_value createNativeNode(napi_env env, napi_callback_info info);
static napi_value GetXComponentStatus(napi_env env, napi_callback_info info);
static napi_value NapiDrawPattern(napi_env env, napi_callback_info info);
// [StartExclude plugin_manager_h]
static napi_value GetContext(napi_env env, napi_callback_info info);
// [EndExclude plugin_manager_h_part]
static napi_value BindNode(napi_env env, napi_callback_info info);
static napi_value UnbindNode(napi_env env, napi_callback_info info);
static napi_value SetFrameRate(napi_env env, napi_callback_info info);
static napi_value SetNeedSoftKeyboard(napi_env env, napi_callback_info info);
// [StartExclude plugin_manager_h_part]
static napi_value Initialize(napi_env env, napi_callback_info info);
static napi_value Finalize(napi_env env, napi_callback_info info);
static napi_value DrawStar(napi_env env, napi_callback_info info);
// [EndExclude plugin_manager_h]
// CApi XComponent
void OnSurfaceChanged(OH_NativeXComponent* component, void* window);
void OnSurfaceDestroyed(OH_NativeXComponent* component, void* window);
void DispatchTouchEvent(OH_NativeXComponent* component, void* window);
void OnSurfaceCreated(OH_NativeXComponent* component, void* window);
// [StartExclude plugin_manager_h]
void SetNativeXComponent(std::string& id, OH_NativeXComponent* nativeXComponent);
NativeRender* GetRender(std::string& id);
void Export(napi_env env, napi_value exports);
// [EndExclude plugin_manager_h]
private:
static NativeManager pluginManager_;
std::unordered_map<std::string, OH_NativeXComponent*> nativeXComponentMap_;
// [StartExclude plugin_manager_h]
std::unordered_map<std::string, NativeRender*> pluginRenderMap_;
// [EndExclude plugin_manager_h]
std::unordered_map<std::string, NativeManager*> pluginManagerMap_;
// [EndExclude plugin_manager_h_part]
public:
// [StartExclude plugin_manager_h_part]
EGLCore *eglcore_;
uint64_t width_;
uint64_t height_;
OH_NativeXComponent_TouchEvent touchEvent_;
static int32_t hasDraw_;
static int32_t hasChangeColor_;
// [EndExclude plugin_manager_h_part]
// [StartExclude plugin_manager_h]
static std::unordered_map<std::string, ArkUI_NodeHandle> nodeHandleMap_;
static std::unordered_map<void *, OH_ArkUI_SurfaceCallback *> callbackMap_;
static std::unordered_map<void *, OH_ArkUI_SurfaceHolder *> surfaceHolderMap_;
static ArkUI_AccessibilityProvider *provider_;
// [EndExclude plugin_manager_h]
};
// [End plugin_manager_h]
} // namespace NativeXComponentSample
// [End plugin_manager_h_part]
#endif // NATIVE_XCOMPONENT_PLUGIN_MANAGER_H

View File

@ -0,0 +1,575 @@
/*
* 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.
*/
#include <cstdint>
#include <hilog/log.h>
#include <js_native_api.h>
#include <js_native_api_types.h>
#include <string>
#include "common.h"
#include "NativeManager.h"
#include "NativeRender.h"
#define EXPECTED_FRAME_RATE 30
namespace NativeOpenCAX {
namespace {
void OnSurfaceCreatedCB(OH_NativeXComponent* component, void* window)
{
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "OnSurfaceCreatedCB");
if ((component == nullptr) || (window == nullptr)) {
OH_LOG_Print(
LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", "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) {
OH_LOG_Print(
LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", "OnSurfaceCreatedCB: Unable to get XComponent id");
return;
}
std::string id(idStr);
auto render = NativeRender::GetInstance(id);
uint64_t width;
uint64_t height;
int32_t xSize = OH_NativeXComponent_GetXComponentSize(component, window, &width, &height);
if ((xSize == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) && (render != nullptr)) {
if (render->eglCore_->EglContextInit(window, width, height)) {
render->eglCore_->Background();
}
}
}
void OnSurfaceChangedCB(OH_NativeXComponent* component, void* window)
{
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "OnSurfaceChangedCB");
if ((component == nullptr) || (window == nullptr)) {
OH_LOG_Print(
LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", "OnSurfaceChangedCB: 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) {
OH_LOG_Print(
LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", "OnSurfaceChangedCB: Unable to get XComponent id");
return;
}
std::string id(idStr);
auto render = NativeRender::GetInstance(id);
if (render != nullptr) {
render->OnSurfaceChanged(component, window);
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "surface changed");
}
}
void OnSurfaceDestroyedCB(OH_NativeXComponent* component, void* window)
{
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "OnSurfaceDestroyedCB");
if ((component == nullptr) || (window == nullptr)) {
OH_LOG_Print(
LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", "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) {
OH_LOG_Print(
LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", "OnSurfaceDestroyedCB: Unable to get XComponent id");
return;
}
std::string id(idStr);
NativeRender::Release(id);
}
void DispatchTouchEventCB(OH_NativeXComponent* component, void* window)
{
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "DispatchTouchEventCB");
if ((component == nullptr) || (window == nullptr)) {
OH_LOG_Print(
LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", "DispatchTouchEventCB: 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) {
OH_LOG_Print(
LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", "DispatchTouchEventCB: Unable to get XComponent id");
return;
}
std::string id(idStr);
NativeRender* render = NativeRender::GetInstance(id);
if (render != nullptr) {
render->OnTouchEvent(component, window);
}
}
void DispatchMouseEventCB(OH_NativeXComponent* component, void* window)
{
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "DispatchMouseEventCB");
int32_t ret;
char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {};
uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
ret = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize);
if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
return;
}
OH_NativeXComponent_ExtraMouseEventInfo* mouseEventInfo = NULL;
ret = OH_NativeXComponent_GetExtraMouseEventInfo(component, &mouseEventInfo);
if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
return;
}
uint64_t mouseKey;
ret = OH_NativeXComponent_GetMouseEventModifierKeyStates(mouseEventInfo, &mouseKey);
if (ret == OH_NATIVEXCOMPONENT_RESULT_FAILED || ret == OH_NATIVEXCOMPONENT_RESULT_BAD_PARAMETER) {
return;
}
std::string id(idStr);
auto render = NativeRender::GetInstance(id);
if (render != nullptr) {
render->OnMouseEvent(component, window);
}
}
void DispatchHoverEventCB(OH_NativeXComponent* component, bool isHover)
{
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "DispatchHoverEventCB");
int32_t ret;
char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {};
uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
ret = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize);
if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
return;
}
std::string id(idStr);
auto render = NativeRender::GetInstance(id);
if (render != nullptr) {
render->OnHoverEvent(component, isHover);
}
}
void OnFocusEventCB(OH_NativeXComponent* component, void* window)
{
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "OnFocusEventCB");
int32_t ret;
char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {};
uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
ret = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize);
if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
return;
}
std::string id(idStr);
auto render = NativeRender::GetInstance(id);
if (render != nullptr) {
render->OnFocusEvent(component, window);
}
}
void OnBlurEventCB(OH_NativeXComponent* component, void* window)
{
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "OnBlurEventCB");
int32_t ret;
char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {};
uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
ret = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize);
if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
return;
}
std::string id(idStr);
auto render = NativeRender::GetInstance(id);
if (render != nullptr) {
render->OnBlurEvent(component, window);
}
}
void OnKeyEventCB(OH_NativeXComponent* component, void* window)
{
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "OnKeyEventCB");
int32_t ret;
char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {};
uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
ret = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize);
if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
return;
}
std::string id(idStr);
auto render = NativeRender::GetInstance(id);
if (render != nullptr) {
render->OnKeyEvent(component, window);
}
}
} // namespace
std::unordered_map<std::string, NativeRender*> NativeRender::instance_;
int32_t NativeRender::hasDraw_ = 0;
int32_t NativeRender::hasChangeColor_ = 0;
NativeRender::NativeRender(std::string& id)
{
this->id_ = id;
this->eglCore_ = new EGLCore();
}
NativeRender* NativeRender::GetInstance(std::string& id)
{
if (instance_.find(id) == instance_.end()) {
NativeRender* instance = new NativeRender(id);
instance_[id] = instance;
return instance;
} else {
return instance_[id];
}
}
void NativeRender::Export(napi_env env, napi_value exports)
{
if ((env == nullptr) || (exports == nullptr)) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "NativeRender", "Export: env or exports is null");
return;
}
napi_property_descriptor desc[] = {
{"drawPatternX", nullptr, NativeRender::NapiDrawPattern, nullptr, nullptr,
nullptr, napi_default, nullptr},
{"getStatusX", nullptr, NativeRender::TestGetXComponentStatus, nullptr, nullptr,
nullptr, napi_default, nullptr}};
if (napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc) != napi_ok) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "NativeRender", "Export: napi_define_properties failed");
}
}
// NAPI registration method type napi_callback. If no value is returned, nullptr is returned.
napi_value NativeRender::NapiDrawPattern(napi_env env, napi_callback_info info)
{
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "NativeRender", "NapiDrawPattern");
if ((env == nullptr) || (info == nullptr)) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "NativeRender", "NapiDrawPattern: env or info is null");
return nullptr;
}
napi_value thisArg;
if (napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr) != napi_ok) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "NativeRender", "NapiDrawPattern: napi_get_cb_info fail");
return nullptr;
}
napi_value exportInstance;
if (napi_get_named_property(env, thisArg, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance) != napi_ok) {
OH_LOG_Print(
LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "NativeRender", "NapiDrawPattern: napi_get_named_property fail");
return nullptr;
}
OH_NativeXComponent* nativeXComponent = nullptr;
if (napi_unwrap(env, exportInstance, reinterpret_cast<void**>(&nativeXComponent)) != napi_ok) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "NativeRender", "NapiDrawPattern: 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) {
OH_LOG_Print(
LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "NativeRender", "NapiDrawPattern: Unable to get XComponent id");
return nullptr;
}
std::string id(idStr);
NativeRender* render = NativeRender::GetInstance(id);
if (render != nullptr) {
render->eglCore_->Draw(hasDraw_);
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "NativeRender", "render->eglCore_->Draw() executed");
}
return nullptr;
}
void NativeRender::Release(std::string& id)
{
NativeRender* render = NativeRender::GetInstance(id);
if (render != nullptr) {
render->eglCore_->Release();
delete render->eglCore_;
render->eglCore_ = nullptr;
instance_.erase(instance_.find(id));
}
}
void NativeRender::OnSurfaceChanged(OH_NativeXComponent* component, void* window)
{
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) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", "OnSurfaceChanged: Unable to get XComponent id");
return;
}
std::string id(idStr);
NativeRender* render = NativeRender::GetInstance(id);
double offsetX;
double offsetY;
OH_NativeXComponent_GetXComponentOffset(component, window, &offsetX, &offsetY);
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "OH_NativeXComponent_GetXComponentOffset",
"offsetX = %{public}lf, offsetY = %{public}lf", offsetX, offsetY);
uint64_t width;
uint64_t height;
OH_NativeXComponent_GetXComponentSize(component, window, &width, &height);
if (render != nullptr) {
render->eglCore_->UpdateSize(width, height);
}
}
void SampleCallback(OH_NativeXComponent* component, uint64_t timestamp, uint64_t targettimestamp)
{
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "SampleCallback", "SampleCallback");
}
void SampleInputeventCallback(OH_NativeXComponent *component, ArkUI_UIInputEvent *event, ArkUI_UIInputEvent_Type type)
{
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "SampleInputeventCallback", "SampleInputeventCallback");
}
HitTestMode SampleInterceptCallback(OH_NativeXComponent *component, ArkUI_UIInputEvent *event)
{
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "SampleInterceptCallback", "SampleInterceptCallback");
return HTM_DEFAULT;
}
void SampleSurfaceShowCallback(OH_NativeXComponent *component, void* window)
{
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "SampleSurfaceShowCallback", "SampleSurfaceShowCallback");
}
bool SampleCallbackWithResult(OH_NativeXComponent *component, void* window)
{
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "SampleCallbackWithResult", "SampleCallbackWithResult");
return false;
}
void SampleAnalyzer(ArkUI_NodeHandle node, ArkUI_XComponent_ImageAnalyzerState statusCode, void* userData)
{
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "SampleAnalyzer", "SampleAnalyzer");
}
void MyContentHandler(ArkUI_NodeContentEvent* event)
{
// 处理内容变化
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "MyContentHandler", "MyContentHandler");
}
void NativeRender::OnTouchEvent(OH_NativeXComponent* component, void* window)
{
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) {
OH_LOG_Print(
LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", "DispatchTouchEventCB: Unable to get XComponent id");
return;
}
OH_NativeXComponent_TouchEvent_SourceTool sourceTool = OH_NATIVEXCOMPONENT_SOURCETOOL_UNKNOWN;
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "OnTouchEvent",
"touch info: OH_NATIVEXCOMPONENT_SOURCETOOL_UNKNOWN = %{public}d", sourceTool);
OH_NativeXComponent_TouchEvent touchEvent;
OH_NativeXComponent_GetTouchEvent(component, window, &touchEvent);
std::string id(idStr);
NativeRender* render = NativeRender::GetInstance(id);
if (render != nullptr && touchEvent.type == OH_NativeXComponent_TouchEventType::OH_NATIVEXCOMPONENT_UP) {
render->eglCore_->ChangeColor(hasChangeColor_);
}
float tiltX = 0.0f;
float tiltY = 0.0f;
OH_NativeXComponent_TouchPointToolType toolType =
OH_NativeXComponent_TouchPointToolType::OH_NATIVEXCOMPONENT_TOOL_TYPE_UNKNOWN;
OH_NativeXComponent_GetTouchPointToolType(component, 0, &toolType);
OH_NativeXComponent_GetTouchPointTiltX(component, 0, &tiltX);
OH_NativeXComponent_GetTouchPointTiltY(component, 0, &tiltY);
float windowX = 0;
float windowY = 0;
float displayX = 0;
float displayY = 0;
OH_NativeXComponent_GetTouchPointWindowX(component, 0, &windowX);
OH_NativeXComponent_GetTouchPointWindowY(component, 0, &windowY);
OH_NativeXComponent_GetTouchPointDisplayX(component, 0, &displayX);
OH_NativeXComponent_GetTouchPointDisplayY(component, 0, &displayY);
int32_t pointId = 0;
OH_NativeXComponent_EventSourceType sourceType;
OH_NativeXComponent_GetTouchEventSourceType(component, pointId, &sourceType);
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "OnTouchEvent",
"touch info: toolType = %{public}d, tiltX = %{public}lf, tiltY = %{public}lf", toolType, tiltX, tiltY);
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "OnTouchEvent",
"touch info: max_touch_points_number = %{public}d", OH_MAX_TOUCH_POINTS_NUMBER);
OnTouchEventPartTwo(component, window);
ArkUI_NodeHandle node; // 此处需要绑定node
void* userData; // 此处需要绑定userData
OH_ArkUI_XComponent_StartImageAnalyzer(node, userData, SampleAnalyzer);
OH_ArkUI_XComponent_StopImageAnalyzer(node);
// ArkUI_NodeContentCallback 的具体使用请搜索 OH_ArkUI_NodeContent_RegisterCallback
// ArkUI_NodeContentCallback callback1 = MyContentHandler;
return;
}
void NativeRender::OnTouchEventPartTwo(OH_NativeXComponent* component, void* window)
{
int32_t min = EXPECTED_FRAME_RATE;
int32_t max = EXPECTED_FRAME_RATE;
int32_t expected = EXPECTED_FRAME_RATE;
OH_NativeXComponent_ExpectedRateRange range = {.min = min, .max = max, .expected = expected};
OH_NativeXComponent_SetExpectedFrameRateRange(component, &range);
bool needSoftKeyboard = 0;
OH_NativeXComponent_SetNeedSoftKeyboard(component, needSoftKeyboard);
OH_NativeXComponent_RegisterOnFrameCallback(component, SampleCallback);
OH_NativeXComponent_UnregisterOnFrameCallback(component);
ArkUI_UIInputEvent_Type type = ARKUI_UIINPUTEVENT_TYPE_UNKNOWN;
OH_NativeXComponent_RegisterUIInputEventCallback(component, SampleInputeventCallback, type);
ArkUI_AccessibilityProvider* sampleHandle; // 此处需要绑定handle
OH_NativeXComponent_GetNativeAccessibilityProvider(component, &sampleHandle);
OH_NativeXComponent_RegisterOnTouchInterceptCallback(component, SampleInterceptCallback);
OH_NativeXComponent_RegisterSurfaceShowCallback(component, SampleSurfaceShowCallback);
OH_NativeXComponent_RegisterSurfaceHideCallback(component, SampleSurfaceShowCallback);
OH_NativeXComponent_RegisterKeyEventCallbackWithResult(component, SampleCallbackWithResult);
OH_NativeXComponent_RegisterKeyEventCallbackWithResult(component, SampleCallbackWithResult);
return;
}
void NativeRender::RegisterCallback(OH_NativeXComponent* nativeXComponent)
{
renderCallback_.OnSurfaceCreated = OnSurfaceCreatedCB;
renderCallback_.OnSurfaceChanged = OnSurfaceChangedCB;
renderCallback_.OnSurfaceDestroyed = OnSurfaceDestroyedCB;
renderCallback_.DispatchTouchEvent = DispatchTouchEventCB;
OH_NativeXComponent_RegisterCallback(nativeXComponent, &renderCallback_);
mouseCallback_.DispatchMouseEvent = DispatchMouseEventCB;
mouseCallback_.DispatchHoverEvent = DispatchHoverEventCB;
OH_NativeXComponent_RegisterMouseEventCallback(nativeXComponent, &mouseCallback_);
OH_NativeXComponent_RegisterFocusEventCallback(nativeXComponent, OnFocusEventCB);
OH_NativeXComponent_RegisterKeyEventCallback(nativeXComponent, OnKeyEventCB);
OH_NativeXComponent_RegisterBlurEventCallback(nativeXComponent, OnBlurEventCB);
}
void NativeRender::OnMouseEvent(OH_NativeXComponent* component, void* window)
{
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "NativeRender", "OnMouseEvent");
OH_NativeXComponent_MouseEvent mouseEvent;
int32_t ret = OH_NativeXComponent_GetMouseEvent(component, window, &mouseEvent);
if (ret == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "NativeRender",
"MouseEvent Info: x = %{public}f, y = %{public}f, action = %{public}d, button = %{public}d", mouseEvent.x,
mouseEvent.y, mouseEvent.action, mouseEvent.button);
} else {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "NativeRender", "GetMouseEvent error");
}
}
void NativeRender::OnHoverEvent(OH_NativeXComponent* component, bool isHover)
{
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "NativeRender", "OnHoverEvent isHover_ = %{public}d", isHover);
}
void NativeRender::OnFocusEvent(OH_NativeXComponent* component, void* window)
{
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "NativeRender", "OnFocusEvent");
}
void NativeRender::OnBlurEvent(OH_NativeXComponent* component, void* window)
{
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "NativeRender", "OnBlurEvent");
}
void NativeRender::OnKeyEvent(OH_NativeXComponent* component, void* window)
{
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "NativeRender", "OnKeyEvent");
OH_NativeXComponent_KeyEvent* keyEvent = nullptr;
if (OH_NativeXComponent_GetKeyEvent(component, &keyEvent) >= 0) {
OH_NativeXComponent_KeyAction action;
OH_NativeXComponent_GetKeyEventAction(keyEvent, &action);
OH_NativeXComponent_KeyCode code;
OH_NativeXComponent_GetKeyEventCode(keyEvent, &code);
OH_NativeXComponent_EventSourceType sourceType;
OH_NativeXComponent_GetKeyEventSourceType(keyEvent, &sourceType);
int64_t deviceId;
OH_NativeXComponent_GetKeyEventDeviceId(keyEvent, &deviceId);
int64_t timeStamp;
OH_NativeXComponent_GetKeyEventTimestamp(keyEvent, &timeStamp);
uint64_t keys;
OH_NativeXComponent_GetKeyEventModifierKeyStates(keyEvent, &keys);
bool isNumLockOn;
OH_NativeXComponent_GetKeyEventNumLockState(keyEvent, &isNumLockOn);
bool isCapsLockOn;
OH_NativeXComponent_GetKeyEventCapsLockState(keyEvent, &isCapsLockOn);
bool isScrollLockOn;
OH_NativeXComponent_GetKeyEventScrollLockState(keyEvent, &isScrollLockOn);
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "NativeRender",
"KeyEvent Info: action=%{public}d, code=%{public}d, sourceType=%{public}d, deviceId=%{public}ld, "
"timeStamp=%{public}ld",
action, code, sourceType, deviceId, timeStamp);
} else {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "NativeRender", "GetKeyEvent error");
}
}
napi_value NativeRender::TestGetXComponentStatus(napi_env env, napi_callback_info info)
{
napi_value hasDraw;
napi_value hasChangeColor;
napi_status ret = napi_create_int32(env, hasDraw_, &(hasDraw));
if (ret != napi_ok) {
OH_LOG_Print(
LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "TestGetXComponentStatus", "napi_create_int32 hasDraw_ error");
return nullptr;
}
ret = napi_create_int32(env, hasChangeColor_, &(hasChangeColor));
if (ret != napi_ok) {
OH_LOG_Print(
LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "TestGetXComponentStatus", "napi_create_int32 hasChangeColor_ error");
return nullptr;
}
napi_value obj;
ret = napi_create_object(env, &obj);
if (ret != napi_ok) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "TestGetXComponentStatus", "napi_create_object error");
return nullptr;
}
ret = napi_set_named_property(env, obj, "hasDraw", hasDraw);
if (ret != napi_ok) {
OH_LOG_Print(
LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "TestGetXComponentStatus", "napi_set_named_property hasDraw error");
return nullptr;
}
ret = napi_set_named_property(env, obj, "hasChangeColor", hasChangeColor);
if (ret != napi_ok) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "TestGetXComponentStatus",
"napi_set_named_property hasChangeColor error");
return nullptr;
}
return obj;
}
} // namespace NativeXComponentSample

View File

@ -0,0 +1,65 @@
/*
* 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.
*/
#ifndef NATIVE_XCOMPONENT_PLUGIN_RENDER_H
#define NATIVE_XCOMPONENT_PLUGIN_RENDER_H
#include <ace/xcomponent/native_interface_xcomponent.h>
#include <napi/native_api.h>
#include <string>
#include <unordered_map>
#include "EGLCore.h"
namespace NativeOpenCAX {
class NativeRender {
public:
explicit NativeRender(std::string& id);
~NativeRender()
{
if (eglCore_ != nullptr) {
eglCore_->Release();
delete eglCore_;
eglCore_ = nullptr;
}
}
static NativeRender* GetInstance(std::string& id);
static void Release(std::string& id);
static napi_value NapiDrawPattern(napi_env env, napi_callback_info info);
static napi_value TestGetXComponentStatus(napi_env env, napi_callback_info info);
void Export(napi_env env, napi_value exports);
void OnSurfaceChanged(OH_NativeXComponent* component, void* window);
void OnTouchEvent(OH_NativeXComponent* component, void* window);
void OnTouchEventPartTwo(OH_NativeXComponent* component, void* window);
void OnMouseEvent(OH_NativeXComponent* component, void* window);
void OnHoverEvent(OH_NativeXComponent* component, bool isHover);
void OnFocusEvent(OH_NativeXComponent* component, void* window);
void OnBlurEvent(OH_NativeXComponent* component, void* window);
void OnKeyEvent(OH_NativeXComponent* component, void* window);
void RegisterCallback(OH_NativeXComponent* nativeXComponent);
void ShowSample(OH_NativeXComponent* component);
public:
static std::unordered_map<std::string, NativeRender*> instance_;
EGLCore* eglCore_;
std::string id_;
static int32_t hasDraw_;
static int32_t hasChangeColor_;
private:
OH_NativeXComponent_Callback renderCallback_;
OH_NativeXComponent_MouseEvent_Callback mouseCallback_;
};
} // namespace NativeXComponentSample
#endif // NATIVE_XCOMPONENT_PLUGIN_RENDER_H

View File

@ -0,0 +1,31 @@
/*
* 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 NATIVE_XCOMPONENT_COMMON_H
#define NATIVE_XCOMPONENT_COMMON_H
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <EGL/eglplatform.h>
#include <GLES3/gl3.h>
#include <napi/native_api.h>
namespace NativeOpenCAX {
/**
* Log print domain.
*/
const unsigned int LOG_PRINT_DOMAIN = 0xFF00;
} // namespace NativeXComponentSample
#endif // NATIVE_XCOMPONENT_COMMON_H

View File

@ -1,94 +0,0 @@
//
// Created on 2026/2/18.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".
#include "OCCTRender.h"
#include <GLES3/gl3.h> // ← 提供 glViewport, glClear 等
#include <EGL/egl.h>
// OCCT 基础
#include <TDocStd_Document.hxx>
#include <TDF_Label.hxx>
#include <TDF_LabelSequence.hxx>
// XCAF 应用框架
#include <XCAFApp_Application.hxx>
#include <XCAFDoc_DocumentTool.hxx> // ← 解决当前错误
#include <XCAFDoc_ShapeTool.hxx> // ← 配套使用
// STEP 导入
#include <STEPCAFControl_Reader.hxx>
#include <IFSelect_ReturnStatus.hxx>
// 可视化
#include <AIS_Shape.hxx>
#include <AIS_InteractiveContext.hxx>
#include <V3d_View.hxx>
OCCTRender::OCCTRender(int width, int height)
: m_width(width), m_height(height)
{
// 创建一个“虚拟”的 DisplayConnectionHarmonyOS 无 X11/Wayland
Handle(Aspect_DisplayConnection) aDispConnection;
// 关键:设置 OpenGl_GraphicDriver 复用当前 OpenGL context
// 第二个参数 'theIsOwnsContext' 设为 false表示不创建新 context
Handle(OpenGl_GraphicDriver) aDriver = new OpenGl_GraphicDriver(aDispConnection, false);
m_viewer = new V3d_Viewer(aDriver);
m_view = m_viewer->CreateView();
m_context = new AIS_InteractiveContext(m_viewer);
m_view->SetBackgroundColor(Quantity_NOC_BLACK);
m_view->Camera()->SetProjectionType(Graphic3d_Camera::Projection_Perspective);
m_view->SetImmediateUpdate(false); // 禁用自动 redraw/swap
}
OCCTRender::~OCCTRender() {
// OCCT 对象由 Handle 自动管理,通常无需手动 delete
}
void OCCTRender::render()
{
if (m_width <= 0 || m_height <= 0) return;
// 设置 OpenGL viewport由 EGLCore 控制 surface此处仅设置视口
glViewport(0, 0, m_width, m_height);
// 更新相机宽高比
m_view->Camera()->SetAspect(static_cast<Standard_Real>(m_width) / m_height);
// 让 OCCT 渲染到当前 OpenGL context 的 default framebuffer
m_view->Redraw();
// 注意:不要调用 RedrawImmediate(),也不要 swap buffer由 EGLCore 负责)
}
void OCCTRender::loadModel(const char* stepPath) {
m_context->RemoveAll(false);
auto app = XCAFApp_Application::GetApplication();
m_doc = new TDocStd_Document("XmlXCAF"); // ← 关键修改
app->NewDocument("XmlXCAF", m_doc); // ← 保持一致
STEPCAFControl_Reader reader;
IFSelect_ReturnStatus status = reader.ReadFile(stepPath);
if (status == IFSelect_RetDone) {
reader.Transfer(m_doc);
Handle(XCAFDoc_ShapeTool) shapeTool = XCAFDoc_DocumentTool::ShapeTool(m_doc->Main());
if (!shapeTool.IsNull()) {
TDF_LabelSequence labels;
shapeTool->GetFreeShapes(labels);
for (Standard_Integer i = 1; i <= labels.Length(); ++i) {
TopoDS_Shape shape;
if (shapeTool->GetShape(labels.Value(i), shape)) {
Handle(AIS_Shape) aisShape = new AIS_Shape(shape);
m_context->Display(aisShape, false);
}
}
}
}
m_view->FitAll();
}
void OCCTRender::rotateCamera(float deltaX, float deltaY) {
m_view->Rotate(deltaX * 0.01f, deltaY * 0.01f, 0.0f, true); // 相对旋转
}

View File

@ -1,44 +0,0 @@
//
// Created on 2026/2/18.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".
/*
* Copyright (c) 2026 Your Company. All rights reserved.
* Description: OCCT rendering logic encapsulation.
*/
#ifndef OCCT_RENDER_H
#define OCCT_RENDER_H
#include <Graphic3d_GraphicDriver.hxx>
#include <V3d_View.hxx>
#include <V3d_Viewer.hxx>
#include <AIS_InteractiveContext.hxx>
#include <OpenGl_GraphicDriver.hxx>
#include <XCAFApp_Application.hxx>
#include <STEPCAFControl_Reader.hxx>
#include <TDocStd_Document.hxx>
#include <XCAFDoc_ShapeTool.hxx>
#include <AIS_Shape.hxx>
class OCCTRender {
public:
OCCTRender(int width, int height); // 保持接口不变
~OCCTRender();
void loadModel(const char* stepPath);
void render();
void updateSize(int width, int height);
void rotateCamera(float deltaX, float deltaY);
private:
Handle(V3d_Viewer) m_viewer;
Handle(V3d_View) m_view;
Handle(AIS_InteractiveContext) m_context;
Handle(TDocStd_Document) m_doc;
int m_width;
int m_height;
};
#endif // OCCT_RENDER_H

View File

@ -1,73 +0,0 @@
//
// Created on 2026/2/18.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".
#include "OCCTRenderThread.h"
#include <unistd.h> // for usleep
OCCTRenderThread::OCCTRenderThread(EGLNativeWindowType window, int width, int height)
: m_window(window), m_width(width), m_height(height) {}
OCCTRenderThread::~OCCTRenderThread() {
stop();
delete m_occtRender;
}
void OCCTRenderThread::start() {
m_running = true;
m_thread = std::thread(&OCCTRenderThread::renderLoop, this);
}
void OCCTRenderThread::stop() {
m_running = false;
if (m_thread.joinable()) {
m_thread.join();
}
}
void OCCTRenderThread::loadModel(const char* path) {
std::lock_guard<std::mutex> lock(m_mutex);
m_pendingModelPath = std::string(path);
m_hasPendingModel = true;
}
void OCCTRenderThread::onMouseEvent(float dx, float dy) {
m_deltaX += dx;
m_deltaY += dy;
m_hasMouseInput = true;
}
void OCCTRenderThread::renderLoop() {
if (!m_eglCore.init(m_window)) {
return;
}
m_occtRender = new OCCTRender(m_width, m_height);
while (m_running) {
m_eglCore.makeCurrent();
// Handle model loading
if (m_hasPendingModel) {
std::lock_guard<std::mutex> lock(m_mutex);
m_occtRender->loadModel(m_pendingModelPath.c_str());
m_hasPendingModel = false;
}
// Handle mouse rotation
if (m_hasMouseInput.exchange(false)) {
m_occtRender->rotateCamera(m_deltaX, m_deltaY);
m_deltaX = m_deltaY = 0.0f;
}
m_occtRender->render();
m_eglCore.swapBuffers();
usleep(16000); // ~60 FPS
}
delete m_occtRender;
m_occtRender = nullptr;
m_eglCore.release();
}

View File

@ -1,45 +0,0 @@
//
// Created on 2026/2/18.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".
#ifndef OCCT_RENDER_THREAD_H
#define OCCT_RENDER_THREAD_H
#include <thread>
#include <atomic>
#include <mutex>
#include "EGLCore/EGLCore.h"
#include "OCCTRender/OCCTRender.h"
class OCCTRenderThread {
public:
OCCTRenderThread(EGLNativeWindowType window, int width, int height);
~OCCTRenderThread();
void start();
void stop();
void loadModel(const char* path);
void onMouseEvent(float dx, float dy);
private:
void renderLoop();
std::thread m_thread;
std::atomic<bool> m_running{false};
EGLNativeWindowType m_window;
int m_width, m_height;
EGLCore m_eglCore;
OCCTRender* m_occtRender = nullptr;
std::mutex m_mutex;
std::string m_pendingModelPath;
std::atomic<bool> m_hasPendingModel{false};
float m_deltaX = 0.0f, m_deltaY = 0.0f;
std::atomic<bool> m_hasMouseInput{false};
};
#endif //OCCT_RENDER_THREAD_H

View File

@ -1,12 +0,0 @@
按照下面要求生成实现代码:
1-HarmonyOS API 版本:22
2-OpenGL ES 版本:3.0
3-OCCT 版本:7.9.3
4-分别用类名字为EGLCore OCCTRenderThread OCCTRender实现
5-实现主线程和渲染线程分离.渲染线程循环渲染
6-实现通过loadmodel加载step文件进行渲染step模型
7-实现鼠标旋转相机观察渲染的模型.
8-Arkui通过XComponent的Native进行调用实现.
9-不得使用android的实现代码.使用鸿蒙原生API实现
10-在napi_init.cpp文件中写出给arkui调用的函数.包括回调函数
11-在Index.d.ts文件中写出暴露给arkui调用的代码

View File

@ -0,0 +1,10 @@
//
// Created on 2024/10/12.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".
#ifndef NATIVESOINTEGRATION_ADD_H
#define NATIVESOINTEGRATION_ADD_H
double Add(double a, double b);
#endif // NATIVESOINTEGRATION_ADD_H

View File

@ -1,128 +1,73 @@
#include "napi/native_api.h" #include "napi/native_api.h"
#include "OCCTRenderThread/OCCTRenderThread.h" #include "hilog/log.h"
#include <map> #include "Add/Add.h"
#include <string> #include "NativeEGLOCCT/common.h"
#include "NativeEGLOCCT/NativeManager.h"
#define LOG_TAG "NAPI_INIT" static napi_value NativeLoadSoTest(napi_env env, napi_callback_info info)
#define LOGI(...) (LOG_TAG, __VA_ARGS__) {
//存储 XComponent ID 到 OCCTRenderThread 实例的映射
static std::map<std::string, OCCTRenderThread*> g_renderThreads;
//NAPI: 初始化渲染器(绑定 XComponent
static napi_value InitRenderer(napi_env env, napi_callback_info info) {
size_t argc = 3;
napi_value args[3];
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
// 参数1: xcomponentId (string)
char xcompId[256];
size_t xcompIdLen;
napi_get_value_string_utf8(env, args[0], xcompId, sizeof(xcompId), &xcompIdLen);
// 参数2: nativeWindow (EGLNativeWindowType, 实际是 void*)
EGLNativeWindowType window = nullptr;
napi_get_value_external(env, args[1], reinterpret_cast<void**>(&window));
// 参数3: { width, height }
int32_t width = 0, height = 0;
napi_valuetype type;
napi_typeof(env, args[2], &type);
if (type == napi_object) {
napi_value w, h;
napi_get_named_property(env, args[2], "width", &w);
napi_get_named_property(env, args[2], "height", &h);
napi_get_value_int32(env, w, &width);
napi_get_value_int32(env, h, &height);
}
// 创建渲染线程
LOGI('Init RenderThread');
auto* renderThread = new OCCTRenderThread(window, width, height);
renderThread->start();
LOGI('Deno Init RenderThread');
g_renderThreads[std::string(xcompId)] = renderThread;
return nullptr;
}
// NAPI: 加载 STEP 模型
static napi_value LoadModel(napi_env env, napi_callback_info info) {
LOGI('Start LoadModel');
size_t argc = 2; size_t argc = 2;
napi_value args[2]; napi_value args[2] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
char xcompId[256]; napi_valuetype valuetype0;
size_t len; napi_typeof(env, args[0], &valuetype0);
napi_get_value_string_utf8(env, args[0], xcompId, sizeof(xcompId), &len);
char modelPath[1024]; napi_valuetype valuetype1;
size_t pathLen; napi_typeof(env, args[1], &valuetype1);
napi_get_value_string_utf8(env, args[1], modelPath, sizeof(modelPath), &pathLen);
LOGI('Find RenderThread');
auto it = g_renderThreads.find(std::string(xcompId));
if (it != g_renderThreads.end()) {
LOGI('LoadModel Began');
it->second->loadModel(modelPath);
}
return nullptr; double value0;
napi_get_value_double(env, args[0], &value0);
double value1;
napi_get_value_double(env, args[1], &value1);
auto _sum=Add(value0,value1);
napi_value sum;
napi_create_double(env, _sum, &sum);
return sum;
} }
namespace NativeOpenCAX {
// NAPI: 鼠标/触摸事件(可选,用于旋转)
static napi_value OnMouseEvent(napi_env env, napi_callback_info info) {
size_t argc = 3;
napi_value args[3];
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
char xcompId[256];
size_t len;
napi_get_value_string_utf8(env, args[0], xcompId, sizeof(xcompId), &len);
double dx, dy;
napi_get_value_double(env, args[1], &dx);
napi_get_value_double(env, args[2], &dy);
auto it = g_renderThreads.find(std::string(xcompId));
if (it != g_renderThreads.end()) {
it->second->onMouseEvent(static_cast<float>(dx), static_cast<float>(dy));
}
return nullptr;
}
// NAPI: 销毁渲染器
static napi_value DestroyRenderer(napi_env env, napi_callback_info info) {
size_t argc = 1;
napi_value args[1];
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
char xcompId[256];
size_t len;
napi_get_value_string_utf8(env, args[0], xcompId, sizeof(xcompId), &len);
auto it = g_renderThreads.find(std::string(xcompId));
if (it != g_renderThreads.end()) {
it->second->stop();
delete it->second;
g_renderThreads.erase(it);
}
return nullptr;
}
EXTERN_C_START EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) { static napi_value Init(napi_env env, napi_value exports) {
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Init", "Init begins");
if ((env == nullptr) || (exports == nullptr)) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Init", "env or exports is null");
return nullptr;
}
napi_property_descriptor desc[] = { napi_property_descriptor desc[] = {
{"initRenderer", nullptr, InitRenderer,nullptr, nullptr, nullptr, napi_default, nullptr}, // [StartExclude napi_init_part]
{"loadModel", nullptr, LoadModel,nullptr, nullptr, nullptr, napi_default, nullptr}, {"createNativeNode", nullptr, NativeManager::createNativeNode, nullptr, nullptr, nullptr,
{"onMouseEvent", nullptr, OnMouseEvent,nullptr, nullptr, nullptr, napi_default, nullptr}, napi_default, nullptr },
{"destroyRenderer", nullptr, DestroyRenderer,nullptr, nullptr, nullptr, napi_default, nullptr}, {"getStatus", nullptr, NativeManager::GetXComponentStatus, nullptr, nullptr,
nullptr, napi_default, nullptr},
{"drawPattern", nullptr, NativeManager::NapiDrawPattern, nullptr, nullptr,
nullptr, napi_default, nullptr},
// [StartExclude napi_init]
{"getContext", nullptr, NativeManager::GetContext, nullptr, nullptr, nullptr,
napi_default, nullptr },
// [EndExclude napi_init_part]
{"bindNode", nullptr, NativeManager::BindNode, nullptr, nullptr, nullptr, napi_default, nullptr},
{"unbindNode", nullptr, NativeManager::UnbindNode, nullptr, nullptr, nullptr, napi_default, nullptr},
{"setFrameRate", nullptr, NativeManager::SetFrameRate, nullptr, nullptr, nullptr, napi_default, nullptr},
{"setNeedSoftKeyboard", nullptr, NativeManager::SetNeedSoftKeyboard, nullptr, nullptr, nullptr, napi_default,
nullptr},
// [StartExclude napi_init_part]
{"initialize", nullptr, NativeManager::Initialize, nullptr, nullptr, nullptr, napi_default, nullptr},
{"finalize", nullptr, NativeManager::Finalize, nullptr, nullptr, nullptr, napi_default, nullptr},
{"drawStar", nullptr, NativeManager::DrawStar, nullptr, nullptr, nullptr, napi_default, nullptr},
{"nativeLoadTest", nullptr, NativeLoadSoTest, nullptr, nullptr, nullptr, napi_default, nullptr},
}; };
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); napi_status status = napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
if (status != napi_ok) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Init", "Failed to define properties.");
return nullptr;
}
return exports; return exports;
} }
EXTERN_C_END EXTERN_C_END
// 编写接口的描述信息,根据实际需要可以修改对应参数 // 编写接口的描述信息,根据实际需要可以修改对应参数
@ -135,9 +80,9 @@ static napi_module OpenCAXModel = {
.nm_priv = ((void*)0), .nm_priv = ((void*)0),
.reserved = { 0 } .reserved = { 0 }
}; };
}
extern "C" __attribute__((visibility("default"))) extern "C" __attribute__((constructor))
void RegisterOpenCAXModule(void) void RegisterOpenCAXModule(void)
{ {
napi_module_register(&OpenCAXModel); napi_module_register(&NativeOpenCAX::OpenCAXModel);
} }

View File

@ -1,5 +1,30 @@
// Index.d.ts /*
export const initRenderer:(id: string, nativeWindow: any, size: { width: number; height: number }) => void; * Copyright (c) 2024 Huawei Device Co., Ltd.
export const loadModel:(id: string, modelPath: string)=> void; * Licensed under the Apache License, Version 2.0 (the "License");
export const onMouseEvent:(id: string, dx: number, dy: number)=> void; * you may not use this file except in compliance with the License.
export const destroyRenderer:(id: string)=> void; * 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 { NodeContent } from '@ohos.arkui.node';
type XComponentContextStatus = {
hasDraw: boolean,
hasChangeColor: boolean
};
export const createNativeNode: (content: NodeContent, tag: string) => void;
export const getStatus: () => XComponentContextStatus;
export const drawPattern: () => void;
export const bindNode: (id: string, node: object) => void;
export const unbindNode: (id: string) => void;
export const setFrameRate: (id: string, min: number, max: number, expected: number) => void;
export const setNeedSoftKeyboard: (id: string, needSoftKeyborad: boolean) => void;
export const initialize: (id: string) => void;
export const finalize: (id: string) => void;
export const drawStar: (id: string) => void;

View File

@ -1,22 +1,36 @@
import { hilog } from '@kit.PerformanceAnalysisKit'; import { hilog } from '@kit.PerformanceAnalysisKit';
import fs from '@ohos.file.fs'; import fs from '@ohos.file.fs';
import fileIO from '@ohos.fileio'; import fileIO from '@ohos.fileio';
import { Context } from '@kit.AbilityKit'; import {NodeContent} from '@kit.ArkUI';
//import NaviteOCCT from 'libopencax.so'; import NativeOpenCAX from 'libopencax.so';
const DOMAIN = 0x0000; const DOMAIN = 0x0000;
const TAG = 'ModelView'; const TAG = 'ModelView';
function NativeLoadModelTest(){
try {
hilog.info(0x0000, 'ModelView', `[NDK] 模块类型: ${typeof NativeOpenCAX}`);
hilog.info(0x0000, 'ModelView', `[NDK] 模块值: ${JSON.stringify(NativeOpenCAX)}`);
hilog.info(0x0000, 'ModelView', `[NDK] 所有属性: ${Object.keys(NativeOpenCAX).join(', ')}`);
//hilog.info(0x0000, 'ModelView', `[NDK] 模块函数加法测试结果: ${NativeOpenCAX.nativeLoadTest(2, 22)}`);
if (!NativeOpenCAX) throw new Error("模块为 undefined");
} catch (e) {
console.error(`[NDK] 加载失败: ${e.message}`, e);
// 此处会触发你看到的错误
}
}
@Component @Component
export struct ModelView { export struct ModelView {
private displayController: XComponentController = new XComponentController(); private displayController: XComponentController = new XComponentController();
private displayContrId: string = 'OCCTRenderer' private displayContrId: string = 'OCCTRender';
@State modelPath: string = ''; @State modelPath: string = '';
@State modelName:string='model.step'; @State modelName:string='model.step';
@State nativeWindow:string=''; @State currentStatus: string = 'init';
@State loadStatus: string = '未测试'; private nodeContent: NodeContent = new NodeContent();
aboutToAppear() { aboutToAppear() {
NativeOpenCAX.createNativeNode(this.nodeContent,'CreatNativeNode');
this.copyRawFileToSandbox(); this.copyRawFileToSandbox();
} }
async copyRawFileToSandbox() { async copyRawFileToSandbox() {
@ -52,41 +66,17 @@ export struct ModelView {
Button('加载模型').onClick(()=>{ Button('加载模型').onClick(()=>{
try { try {
console.info('Model copied to:', this.modelPath); console.info('Model copied to:', this.modelPath);
// 调用 native 加载 NativeOpenCAX.drawPattern();
//OCCTRender.loadModel(this.displayContrId, this.modelPath); //NativeOpenCAX.loadModel(this.displayContrId,this.modelPath);
} catch (e) { } catch (e) {
hilog.error(0x0000, 'ModelView', `LoadModel Failed: ${JSON.stringify(e)}`); hilog.error(0x0000, 'ModelView', `LoadModel Failed: ${JSON.stringify(e)}`);
} }
}) })
Button('测试模块加载').onClick(()=>{ Button('模块&&so库加载测试').onClick(()=>{
try { NativeLoadModelTest();
const NaviteOCCT = import("libopencax.so")
console.info(`[NDK] 模块类型: ${typeof NaviteOCCT}`);
console.info(`[NDK] 模块值: ${JSON.stringify(NaviteOCCT)}`);
console.info(`[NDK] 所有属性: ${Object.keys(NaviteOCCT).join(', ')}`);
if (!NaviteOCCT) throw new Error("模块为 undefined");
} catch (e) {
console.error(`[NDK] 加载失败: ${e.message}`, e);
// 此处会触发你看到的错误
}
})
Button('测试so是否存在').onClick(()=>{
try {
fs.accessSync('libs/x86_64/libopencax.so');
console.info("动态库存在!");
} catch (e) {
console.error("动态库不存在!");
}
}) })
} }
XComponent({ ContentSlot(this.nodeContent);
id: this.displayContrId,
type: 'surface',
controller: this.displayController
})
.width('100%')
.height('100%')
.backgroundColor('#333333');
} }
.width('100%') .width('100%')
.height('100%'); .height('100%');

View File

@ -26,7 +26,7 @@
"entity.system.home" "entity.system.home"
], ],
"actions": [ "actions": [
"ohos.want.action.home" "action.system.home"
] ]
} }
] ]