OpenGL三棱椎
介绍
XComponent控件常用于相机预览流的显示和游戏画面的绘制,在HarmonyOS上,可以配合Native Window创建OpenGL开发环境,并最终将OpenGL绘制的图形显示到XComponent控件。本示例基于"Native C++"模板,调用OpenGL(OpenGL ES)图形库相关API绘制3D图形(三棱锥),并将结果渲染到页面的XComponent控件中进行展示。同时,可以点击自动旋转按钮可以自动旋转,点击阻尼旋转可以减速旋转直至停止旋转,还可以在屏幕上通过触摸滑动手势对三棱锥进行旋转,最终得到不同角度的图形并显示到页面。
效果预览
使用说明
应用界面中展示了XComponent相关控件的使用,及采用OpenGL (OpenGL ES)相关标准API绘制3D图形(三棱锥,3D渲染的光源用的是简单的线性光源)。此外,可在屏幕触摸滑动,以使三棱锥进行旋转,其中主要采用了napi接口来更新3D图形的旋转角度。
工程目录
├──entry/src/main/cpp/
│ ├──CMakeLists.txt // cmake编译配置
│ ├──app_napi.cpp // 调用native接口
│ ├──include
│ │ ├──app_napi.h
│ │ ├──tetrahedron.h
│ │ ├──frame_handle.h
│ │ └──util
│ │ ├──log.h
│ │ ├──napi_manager.h
│ │ ├──napi_util.h
│ │ └──native_common.h
│ ├──module.cpp // napi模块注册
│ ├──napi_manager.cpp
│ ├──napi_util.cpp
│ ├──frame_handle.cpp
│ ├──tetrahedron.cpp // OpenGL (ES) 三棱锥实现
│ └──type
│ └──libentry
│ ├──oh-package.json5
│ └──tetrahedron_napi.d.ts // 接口导出
├──entry/src/main/ets
│ ├──entryability
│ │ └──EntryAbility.ets
│ ├──pages
│ │ └──Index.ets // 首页
│ └──utils
│ └──Logger.ets // 日志工具
└──entry/src/main/resources // 应用静态资源目录
具体实现
通过在IDE中创建Native C++工程,在C++代码中定义接口为Init和Update用于3D图形绘制环境的初始化和图形渲染更新,并映射NAPI相关接口UpdateAngle。ArkTS侧主要利用XComponent控件实现Index.ets,C++侧主要采用OpenGL ES相关标准API实现三棱锥的绘制流程相关代码,并可与ArkTS进行交互。
应用启动时,NAPI模块也相应进行初始化,此时可通过C++侧的OH_NativeXComponent_GetXComponentId()接口,获取到当前XComponent控件的控件指针,并给到C++侧三棱锥绘制相关的Init和Update函数,实现3D图形显示。同时,为实现三棱锥的触摸屏滑动旋转效果,在C++代码中映射的NAPI接口UpdateAngle给到ArkTS侧调用。ArkTS侧需在导入NAPI模块"libtetrahedron_napi.so"正确的前提下,通过调用src/main/cpp/type/libentry/tetrahedron_napi.d.ts中声明的UpdateAngle接口更新三棱锥旋转角度。
主要源码参考:[napi_manager.cpp]
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <cstdint>
#include <string>
#include <cstdio>
#include "log.h"
#include "napi_manager.h"
enum class ContextType {
APP_LIFECYCLE = 0,
JS_PAGE_LIFECYCLE,
};
NapiManager NapiManager::manager_;
napi_value NapiManager::GetContext(napi_env env, napi_callback_info info)
{
napi_status status;
napi_value exports;
size_t argc = 1;
napi_value args[1];
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, nullptr, nullptr));
if (argc != 1) {
napi_throw_type_error(env, NULL, "Wrong number of arguments");
return nullptr;
}
napi_valuetype valuetype;
status = napi_typeof(env, args[0], &valuetype);
if (status != napi_ok) {
return nullptr;
}
if (valuetype != napi_number) {
napi_throw_type_error(env, NULL, "Wrong arguments");
return nullptr;
}
int64_t value;
NAPI_CALL(env, napi_get_value_int64(env, args[0], &value));
NAPI_CALL(env, napi_create_object(env, &exports));
switch (value) {
case int64_t(ContextType::APP_LIFECYCLE):
{
/* AppInit对应EntryAbility.ts中的应用生命周期: onCreate, onShow, onHide, onDestroy */
LOGD("GetContext APP_LIFECYCLE");
/* Register App Lifecycle */
napi_property_descriptor desc[] = {
DECLARE_NAPI_FUNCTION("onCreate", NapiManager::NapiOnCreate),
DECLARE_NAPI_FUNCTION("onShow", NapiManager::NapiOnShow),
DECLARE_NAPI_FUNCTION("onHide", NapiManager::NapiOnHide),
DECLARE_NAPI_FUNCTION("onDestroy", NapiManager::NapiOnDestroy),
};
NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
}
break;
case int64_t(ContextType::JS_PAGE_LIFECYCLE):
{
/* JS Page */
LOGD("GetContext JS_PAGE_LIFECYCLE");
napi_property_descriptor desc[] = {
DECLARE_NAPI_FUNCTION("onPageShow", NapiManager::NapiOnPageShow),
DECLARE_NAPI_FUNCTION("onPageHide", NapiManager::NapiOnPageHide),
};
NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
}
break;
default:
LOGE("unknown type");
}
return exports;
}
bool NapiManager::Export(napi_env env, napi_value exports)
{
napi_status status;
napi_value exportInstance = nullptr;
OH_NativeXComponent *nativeXComponent = nullptr;
int32_t ret;
char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { };
uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
status = napi_get_named_property(env, exports, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance);
if (status != napi_ok) {
return false;
}
status = napi_unwrap(env, exportInstance, reinterpret_cast<void**>(&nativeXComponent));
if (status != napi_ok) {
return false;
}
ret = OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize);
if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
return false;
}
std::string id(idStr);
auto context = NapiManager::GetInstance();
if (context) {
context->SetNativeXComponent(id, nativeXComponent);
auto app = context->GetApp(id);
app->SetNativeXComponent(nativeXComponent);
app->Export(env, exports);
return true;
}
return false;
}
void NapiManager::SetNativeXComponent(std::string& id, OH_NativeXComponent* nativeXComponent)
{
if (nativeXComponentMap_.find(id) == nativeXComponentMap_.end()) {
nativeXComponentMap_[id] = nativeXComponent;
} else {
if (nativeXComponentMap_[id] != nativeXComponent) {
nativeXComponentMap_[id] = nativeXComponent;
}
}
}
OH_NativeXComponent* NapiManager::GetNativeXComponent(std::string& id)
{
if (nativeXComponentMap_.find(id) == nativeXComponentMap_.end()) {
return nullptr;
} else {
return nativeXComponentMap_[id];
}
}
AppNapi* NapiManager::GetApp(std::string& id)
{
if (appNapiMap_.find(id) == appNapiMap_.end()) {
AppNapi* instance = AppNapi::GetInstance(id);
appNapiMap_[id] = instance;
return instance;
} else {
return appNapiMap_[id];
}
}
void NapiManager::MainOnMessage(const uv_async_t* req)
{
LOGD("MainOnMessage Triggered");
}
napi_value NapiManager::NapiOnCreate(napi_env env, napi_callback_info info)
{
LOGD("NapiManager::NapiOnCreate");
uv_loop_t* loop = nullptr;
NAPI_CALL(env, napi_get_uv_event_loop(env, &loop));
NapiManager::GetInstance()->OnCreateNative(env, loop);
return nullptr;
}
napi_value NapiManager::NapiOnShow(napi_env env, napi_callback_info info)
{
NapiManager::GetInstance()->OnShowNative();
return nullptr;
}
napi_value NapiManager::NapiOnHide(napi_env env, napi_callback_info info)
{
NapiManager::GetInstance()->OnHideNative();
return nullptr;
}
napi_value NapiManager::NapiOnDestroy(napi_env env, napi_callback_info info)
{
NapiManager::GetInstance()->OnDestroyNative();
return nullptr;
}
void NapiManager::OnCreateNative(napi_env env, uv_loop_t* loop)
{
mainEnv_ = env;
mainLoop_ = loop;
if (mainLoop_) {
uv_async_init(mainLoop_, &mainOnMessageSignal_, reinterpret_cast<uv_async_cb>(NapiManager::MainOnMessage));
}
}
void NapiManager::OnShowNative()
{
LOGD("NapiManager::OnShowNative");
}
void NapiManager::OnHideNative()
{
LOGD("NapiManager::OnHideNative");
}
void NapiManager::OnDestroyNative()
{
LOGD("NapiManager::OnDestroyNative");
}
napi_value NapiManager::NapiOnPageShow(napi_env env, napi_callback_info info)
{
LOGD("NapiManager::NapiOnPageShow");
return nullptr;
}
napi_value NapiManager::NapiOnPageHide(napi_env env, napi_callback_info info)
{
LOGD("NapiManager::NapiOnPageHide");
return nullptr;
}
void NapiManager::OnPageShowNative()
{
LOGD("NapiManager::OnPageShowNative");
}
void NapiManager::OnPageHideNative()
{
LOGD("NapiManager::OnPageHideNative");
}
源码:[app_napi.cpp]
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <js_native_api.h>
#include <js_native_api_types.h>
#include <cstdint>
#include "native_common.h"
#include "log.h"
#include "napi_manager.h"
#include "tetrahedron.h"
#include "app_napi.h"
std::unordered_map<std::string, AppNapi*> AppNapi::instance_;
OH_NativeXComponent_Callback AppNapi::callback_;
FrameHandle AppNapi::frame_handle_;
static Tetrahedron *tetrahedron_;
uint32_t AppNapi::isCreated_ = 0;
uint32_t AppNapi::xcHeight_ = 0;
uint32_t AppNapi::xcWidth_ = 0;
double AppNapi::off_x = 0;
double AppNapi::off_y = 0;
uint32_t AppNapi::toolType_ = 5;
uint32_t AppNapi::mousecallback_ = 0;
float AppNapi::tiltX_ = 0;
float AppNapi::tiltY_ = 0;
uint32_t AppNapi::touchType = 4;
OH_NativeXComponent_TouchEvent AppNapi::testTouchEvent_;
OH_NativeXComponent_MouseEvent AppNapi::testMouseEvent_;
OH_NativeXComponent_MouseEvent_Callback AppNapi::mouseEventcallback_;
Tetrahedron *AppNapi::getTetrahedron(void)
{
return tetrahedron_;
}
FrameHandle &AppNapi::getFrameHanlde(void)
{
return frame_handle_;
}
static int Normalize(int angle)
{
int ret = angle % CIRCUMFERENCE_DEGREE;
if (ret < 0) {
ret += CIRCUMFERENCE_DEGREE;
}
return ret;
}
static void OnFrameCB(OH_NativeXComponent* component, uint64_t timestamp, uint64_t targetTimestamp) {
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 instance = AppNapi::GetInstance(id);
instance->getFrameHanlde().OnFrameHandle(timestamp, targetTimestamp);
}
static void OnSurfaceCreatedCB(OH_NativeXComponent* component, void* window)
{
LOGE("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);
auto instance = AppNapi::GetInstance(id);
instance->OnSurfaceCreated(component, window);
}
static void OnSurfaceChangedCB(OH_NativeXComponent* component, void* window)
{
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 instance = AppNapi::GetInstance(id);
instance->OnSurfaceChanged(component, window);
}
static void OnSurfaceDestroyedCB(OH_NativeXComponent* component, void* window)
{
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 instance = AppNapi::GetInstance(id);
tetrahedron_->Quit();
instance->OnSurfaceDestroyed(component, window);
}
static void DispatchTouchEventCB(OH_NativeXComponent* component, void* window)
{
LOGE("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);
auto instance = AppNapi::GetInstance(id);
instance->DispatchTouchEvent(component, window);
}
static void DispatchMouseEventCB(OH_NativeXComponent* component, void* window)
{
LOGD("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;
}
std::string id(idStr);
auto instance = AppNapi::GetInstance(id);
instance->DispatchMouseEvent(component, window);
}
AppNapi::AppNapi(std::string& id)
{
id_ = id;
component_ = nullptr;
auto appCallback = AppNapi::GetNXComponentCallback();
appCallback->OnSurfaceCreated = OnSurfaceCreatedCB;
appCallback->OnSurfaceChanged = OnSurfaceChangedCB;
appCallback->OnSurfaceDestroyed = OnSurfaceDestroyedCB;
appCallback->DispatchTouchEvent = DispatchTouchEventCB;
auto appMouseEventCallback = AppNapi::GetNXComponentMouseEventCallback();
appMouseEventCallback->DispatchMouseEvent = DispatchMouseEventCB;
tetrahedron_ = new Tetrahedron(id);
frame_handle_.Init(this, tetrahedron_);
}
AppNapi* AppNapi::GetInstance(std::string& id)
{
if (instance_.find(id) == instance_.end()) {
AppNapi* instance = new AppNapi(id);
instance_[id] = instance;
return instance;
} else {
return instance_[id];
}
}
OH_NativeXComponent_Callback* AppNapi::GetNXComponentCallback()
{
return &AppNapi::callback_;
}
OH_NativeXComponent_MouseEvent_Callback* AppNapi::GetNXComponentMouseEventCallback()
{
return &AppNapi::mouseEventcallback_;
}
void AppNapi::SetNativeXComponent(OH_NativeXComponent* component)
{
component_ = component;
OH_NativeXComponent_RegisterCallback(component_, &AppNapi::callback_);
uint32_t mousecallback = OH_NativeXComponent_RegisterMouseEventCallback(component_,
&AppNapi::mouseEventcallback_);
mousecallback_ = mousecallback;
}
void AppNapi::OnSurfaceCreated(OH_NativeXComponent* component, void* window)
{
LOGE("AppNapi::OnSurfaceCreated");
OH_NativeXComponent_RegisterOnFrameCallback(component, OnFrameCB);
int32_t ret = OH_NativeXComponent_GetXComponentSize(component, window, &width_, &height_);
LOGE("Offset : x = %{public}f, y = %{public}f ", x_, y_);
if (ret == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
tetrahedron_->Init(window, width_, height_);
tetrahedron_->Update(angleX_, angleY_);
isCreated_++;
xcHeight_ = height_;
xcWidth_ = width_;
LOGE("AppNapi::OnSurfaceCreated success ");
} else {
LOGE("AppNapi::OnSurfaceCreated failed");
}
}
void AppNapi::OnSurfaceChanged(OH_NativeXComponent* component, void* window)
{
LOGE("AppNapi::OnSurfaceChanged");
int32_t ret = OH_NativeXComponent_GetXComponentSize(component, window, &width_, &height_);
int32_t ret1;
if (ret == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
xcHeight_ = height_;
xcWidth_ = width_;
LOGE("after width = %{public}d, height = %{public}d", xcWidth_, xcHeight_);
ret1= OH_NativeXComponent_GetXComponentOffset(component, window, &x_, &y_);
off_x = x_;
off_y = y_;
if (ret1 == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
LOGE("Offset : x = %{public}lf, y = %{public}lf ", off_x, off_y);
} else {
LOGE("Offset get failed");
}
LOGE("AppNapi::GetOffset ");
LOGE("Offset : x = %{public}lf, y = %{public}lf ", off_x, off_y);
}
}
void AppNapi::OnSurfaceDestroyed(OH_NativeXComponent* component, void* window)
{
LOGE("AppNapi::OnSurfaceDestroyed");
isCreated_--;
LOGE("AppNapi::OnSurfaceDestroyed iscreated %{public}d", isCreated_);
}
void AppNapi::DispatchTouchEvent(OH_NativeXComponent* component, void* window)
{
int32_t ret = OH_NativeXComponent_GetTouchEvent(component, window, &touchEvent_);
if (ret == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
testTouchEvent_ = touchEvent_;
LOGE("Touch Info : x = %{public}f, y = %{public}f screenx = %{public}f, screeny = %{public}f",
touchEvent_.x, touchEvent_.y, touchEvent_.screenX, touchEvent_.screenY);
for (uint32_t i = 0; i < touchEvent_.numPoints; i++) {
LOGE("Touch Info : dots[%{public}d] id %{public}d x = %{public}f, y = %{public}f", i,
touchEvent_.touchPoints[i].id, touchEvent_.touchPoints[i].x, touchEvent_.touchPoints[i].y);
LOGE("Touch Info : screenx = %{public}f, screeny = %{public}f",
touchEvent_.touchPoints[i].screenX, touchEvent_.touchPoints[i].screenY);
OH_NativeXComponent_TouchPointToolType toolType;
float tiltX = 123.0;
float tiltY = 321.0;
int32_t ret1;
int32_t ret2;
int32_t ret3;
ret1 = OH_NativeXComponent_GetTouchPointToolType(component, i, &toolType);
ret2 = OH_NativeXComponent_GetTouchPointTiltX(component, i, &tiltX);
ret3 = OH_NativeXComponent_GetTouchPointTiltY(component, i, &tiltY);
toolType_ = toolType;
tiltX_ = tiltX;
tiltY_ = tiltY;
LOGE("Touch Info : [%{public}d] %{public}u, %{public}f, %{public}f",
i, toolType, tiltX, tiltY);
}
} else {
LOGE("Touch fail");
}
}
void AppNapi::DispatchMouseEvent(OH_NativeXComponent* component, void* window)
{
int32_t ret = OH_NativeXComponent_GetMouseEvent(component, window, &mouseEvent_);
LOGE("Mouse Info DispatchMouseEvent");
if (ret == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
testMouseEvent_ = mouseEvent_;
LOGE("Mouse Info : x = %{public}f, y = %{public}f screenx = %{public}f, screeny = %{public}f",
mouseEvent_.x, mouseEvent_.y, mouseEvent_.screenX, mouseEvent_.screenY);
LOGE("Mouse Info : action = %{public}d, button = %{public}d", mouseEvent_.action, mouseEvent_.button);
} else {
LOGE("Mouse Info fail");
}
}
napi_value AppNapi::UpdateAngle(napi_env env, napi_callback_info info)
{
LOGE("Update");
size_t requireArgc = 2;
size_t argc = 2;
int speed = 3;
napi_value args[2] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
napi_valuetype valuetype0;
napi_typeof(env, args[0], &valuetype0);
napi_valuetype valuetype1;
napi_typeof(env, args[1], &valuetype1);
double offsetX;
napi_get_value_double(env, args[0], &offsetX);
double offsetY;
napi_get_value_double(env, args[1], &offsetY);
float tetrahedron_angleX = tetrahedron_->GetAngleX();
float tetrahedron_angleY = tetrahedron_->GetAngleY();
if (offsetY < 0) {
tetrahedron_angleX = tetrahedron_angleX + speed;
} else {
tetrahedron_angleX = tetrahedron_angleX - speed;
}
if (offsetX < 0) {
tetrahedron_angleY = tetrahedron_angleY + speed;
} else {
tetrahedron_angleY = tetrahedron_angleY - speed;
}
tetrahedron_angleY = Normalize(tetrahedron_angleY);
tetrahedron_angleX = Normalize(tetrahedron_angleX);
tetrahedron_->Update(tetrahedron_angleX, tetrahedron_angleY);
napi_value ret;
napi_create_array(env, &ret);
napi_value num;
napi_create_int32(env, tetrahedron_angleX, &num);
napi_set_element(env, ret, 0, num);
napi_create_int32(env, tetrahedron_angleY, &num);
napi_set_element(env, ret, 1, num);
return ret;
}
napi_value AppNapi::SetRotate(napi_env env, napi_callback_info info) {
LOGE("SetRotate");
size_t argc = 1;
napi_value args[1] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
napi_valuetype valuetype0;
napi_typeof(env, args[0], &valuetype0);
int mode;
napi_get_value_int32(env, args[0], &mode);
frame_handle_.SetRotate((RotateMode)mode);
napi_value ret;
napi_get_null(env, &ret);
return ret;
}
napi_value AppNapi::Quit(napi_env env, napi_callback_info info)
{
LOGE("AppNapi -> Quit");
napi_value exportInstance;
napi_value thisArg;
napi_status status;
OH_NativeXComponent *nativeXComponent = nullptr;
int32_t ret;
char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {};
uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
tetrahedron_->Quit();
NAPI_CALL(env, napi_get_cb_info(env, info, NULL, NULL, &thisArg, NULL));
status = napi_get_named_property(env, thisArg, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance);
if (status != napi_ok) {
return nullptr;
}
status = napi_unwrap(env, exportInstance, reinterpret_cast<void**>(&nativeXComponent));
if (status != napi_ok) {
return nullptr;
}
ret = OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize);
if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
return nullptr;
}
return 0;
}
napi_value AppNapi::GetXComponentId(napi_env env, napi_callback_info info)
{
napi_value thisArg;
napi_status status;
napi_value exportInstance;
OH_NativeXComponent *nativeXComponent = nullptr;
int32_t ret;
char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {};
uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
NAPI_CALL(env, napi_get_cb_info(env, info, NULL, NULL, &thisArg, NULL));
status = napi_get_named_property(env, thisArg, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance);
status = napi_unwrap(env, exportInstance, reinterpret_cast<void**>(&nativeXComponent));
ret = OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize);
if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
return nullptr;
}
std::string id(idStr);
napi_value output;
NAPI_CALL(env, napi_create_string_utf8(env, idStr, id.length(), &output));
return output;
}
napi_value AppNapi::GetXComponentSize_Height(napi_env env, napi_callback_info info)
{
LOGE("running AppNapi::GetXComponentSize_Height");
napi_value output;
NAPI_CALL(env, napi_create_uint32(env, xcHeight_, &output));
LOGE(" GetXComponentSize_Height %{public}d ", xcHeight_);
return output;
}
napi_value AppNapi::GetXComponentSize_Width(napi_env env, napi_callback_info info)
{
LOGE("running AppNapi::GetXComponentSize_Width");
napi_value output;
NAPI_CALL(env, napi_create_uint32(env, xcWidth_, &output));
LOGE(" GetXComponentSize_Width %{public}d ", xcWidth_);
return output;
}
napi_value AppNapi::GetXComponentOffset_x(napi_env env, napi_callback_info info)
{
LOGE("running AppNapi::GetXComponentOffset_x");
napi_value output;
NAPI_CALL(env, napi_create_double(env, off_x, &output));
LOGE("GetXComponentOffset_x : %{public}f", off_x);
return output;
}
napi_value AppNapi::GetXComponentOffset_y(napi_env env, napi_callback_info info)
{
LOGE("running AppNapi::GetXComponentOffset_y");
napi_value output;
NAPI_CALL(env, napi_create_double(env, off_y, &output));
LOGE("GetXComponentOffset_y : %{public}f", off_y);
return output;
}
napi_value AppNapi::GetXComponentpointtool_tiltx(napi_env env, napi_callback_info info)
{
LOGE("running AppNapi::GetXComponentpointtool_tiltx");
napi_value output;
NAPI_CALL(env, napi_create_double(env, tiltX_, &output));
LOGE("GetXComponentpointtool_tiltx : %{public}f", tiltX_);
return output;
}
napi_value AppNapi::GetXComponentpointtool_tilty(napi_env env, napi_callback_info info)
{
LOGE("running AppNapi::GetXComponentpointtool_tilty");
napi_value output;
NAPI_CALL(env, napi_create_double(env, tiltY_, &output));
LOGE("GetXComponentpointtool_tilty : %{public}f", tiltY_);
return output;
}
napi_value AppNapi::GetXComponentpointtool_type(napi_env env, napi_callback_info info)
{
LOGE("running AppNapi::GetXComponentpointtool_type");
napi_value output;
NAPI_CALL(env, napi_create_double(env, toolType_, &output));
LOGE("GetXComponentpointtool_type : %{public}u", toolType_);
return output;
}
napi_value AppNapi::GetXComponent_TouchEvent(napi_env env, napi_callback_info info)
{
LOGE("running AppNapi::GetXComponent_TouchEvent");
napi_value surf_x;
napi_value surf_y;
napi_value t_type;
NAPI_CALL(env, napi_create_double(env, testTouchEvent_.x, &(surf_x)));
NAPI_CALL(env, napi_create_double(env, testTouchEvent_.y, &(surf_y)));
NAPI_CALL(env, napi_create_uint32(env, testTouchEvent_.type, &(t_type)));
napi_value obj;
NAPI_CALL(env, napi_create_object(env, &obj));
NAPI_CALL(env, napi_set_named_property(env, obj, "surface_X", surf_x));
NAPI_CALL(env, napi_set_named_property(env, obj, "surface_Y", surf_y));
NAPI_CALL(env, napi_set_named_property(env, obj, "touchType", t_type));
return obj;
}
napi_value AppNapi::GetXComponent_MouseEvent(napi_env env, napi_callback_info info)
{
LOGE("running AppNapi::GetXComponent_MouseEvent");
napi_value surf_x;
napi_value surf_y;
napi_value t_button;
NAPI_CALL(env, napi_create_double(env, testMouseEvent_.x, &(surf_x)));
NAPI_CALL(env, napi_create_double(env, testMouseEvent_.y, &(surf_y)));
NAPI_CALL(env, napi_create_uint32(env, testMouseEvent_.button, &(t_button)));
napi_value obj;
NAPI_CALL(env, napi_create_object(env, &obj));
NAPI_CALL(env, napi_set_named_property(env, obj, "surface_X1", surf_x)); // float x
NAPI_CALL(env, napi_set_named_property(env, obj, "surface_Y1", surf_y)); // float y
NAPI_CALL(env, napi_set_named_property(env, obj, "mousebutton", t_button)); // int32_t
return obj;
}
napi_value AppNapi::GetXComponent_RegisterMouseEventCallback(napi_env env, napi_callback_info info)
{
LOGE("running AppNapi::GetXComponent_RegisterMouseEventCallback");
napi_value callback_;
NAPI_CALL(env, napi_create_double(env, mousecallback_, &(callback_)));
napi_value obj;
NAPI_CALL(env, napi_create_object(env, &obj));
NAPI_CALL(env, napi_set_named_property(env, obj, "MouseCallback_", callback_)); // float x
return obj;
}
napi_value AppNapi::Export(napi_env env, napi_value exports)
{
LOGE("AppNapi::Export");
// Register NAPI
napi_property_descriptor desc[] = {
DECLARE_NAPI_FUNCTION("Quit", AppNapi::Quit),
DECLARE_NAPI_FUNCTION("GetXComponentId", AppNapi::GetXComponentId),
DECLARE_NAPI_FUNCTION("GetXComponentSize_Height", AppNapi::GetXComponentSize_Height),
DECLARE_NAPI_FUNCTION("GetXComponentSize_Width", AppNapi::GetXComponentSize_Width),
DECLARE_NAPI_FUNCTION("GetXComponentOffset_x", AppNapi::GetXComponentOffset_x),
DECLARE_NAPI_FUNCTION("GetXComponentOffset_y", AppNapi::GetXComponentOffset_y),
DECLARE_NAPI_FUNCTION("GetXComponent_TouchEvent", AppNapi::GetXComponent_TouchEvent),
DECLARE_NAPI_FUNCTION("GetXComponent_MouseEvent", AppNapi::GetXComponent_MouseEvent),
DECLARE_NAPI_FUNCTION("GetXComponentpointtool_tilty", AppNapi::GetXComponentpointtool_tilty),
DECLARE_NAPI_FUNCTION("GetXComponentpointtool_type", AppNapi::GetXComponentpointtool_type),
DECLARE_NAPI_FUNCTION("GetXComponentpointtool_tiltx", AppNapi::GetXComponentpointtool_tiltx),
DECLARE_NAPI_FUNCTION("GetXComponent_RegisterMouseEventCallback",
AppNapi::GetXComponent_RegisterMouseEventCallback),
};
NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
return exports;
}
源码:[tetrahedron.cpp]
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <GLES3/gl31.h>
#include <bits/alltypes.h>
#include <cmath>
#include "log.h"
#include "tetrahedron.h"
static char g_vertexShader[] =
"attribute vec4 a_pos;\n"
"attribute vec4 a_color;\n"
"attribute vec4 a_normal;\n"
"uniform vec3 u_lightColor;\n"
"uniform vec3 u_lightDirection;\n"
"uniform mat4 a_mx;\n"
"uniform mat4 a_my;\n"
"varying vec4 v_color;\n"
"void main() {\n"
" float radian = radians(30.0);\n"
" float cos = cos(radian);\n"
" float sin = sin(radian);\n"
" gl_Position = a_mx * a_my * vec4(a_pos.x, a_pos.y, a_pos.z, 1.0);\n"
" vec3 normal = normalize((a_mx * a_my * a_normal).xyz);\n"
" float dot = max(dot(u_lightDirection, normal), 0.0);\n"
" vec3 reflectedLight = u_lightColor * a_color.rgb * dot;\n"
" v_color = vec4(reflectedLight, a_color.a);\n"
"}\n\0";
static char g_fragmentShader[] =
"precision mediump float;\n"
"varying vec4 v_color;\n"
"void main() {\n"
" gl_FragColor = v_color;\n"
"}\n\0";
/* 创建顶点位置数据数组vertexData */
static float g_vertexData[] = {
-0.75, -0.50, -0.43, 0.75, -0.50, -0.43, 0.00, -0.50, 0.87, 0.75, -0.50, -0.43,
0.00, -0.50, 0.87, 0.00, 1.00, 0.00, 0.00, -0.50, 0.87, 0.00, 1.00, 0.00,
-0.75, -0.50, -0.43, 0.00, 1.00, 0.00, -0.75, -0.50, -0.43, 0.75, -0.50, -0.43,
};
/* 创建顶点颜色数组colorData */
static float g_colorData[] = {
1, 0, 0, 1, 0, 0, 1, 0, 0, /* 红色——面1 */
1, 0, 0, 1, 0, 0, 1, 0, 0, /* 红色——面2 */
1, 0, 0, 1, 0, 0, 1, 0, 0, /* 红色——面3 */
1, 0, 0, 1, 0, 0, 1, 0, 0 /* 红色——面4 */
};
/* 顶点法向量数组normalData */
static float g_normalData[] = {
0.00, -1.00, 0.00, 0.00, -1.00, 0.00, 0.00, -1.00, 0.00, -0.83, -0.28, -0.48,
-0.83, -0.28, -0.48, -0.83, -0.28, -0.48, -0.83, 0.28, 0.48, -0.83, 0.28, 0.48,
-0.83, 0.28, 0.48, 0.00, -0.28, 0.96, 0.00, -0.28, 0.96, 0.00, -0.28, 0.96,
};
namespace {
EGLConfig getConfig(int version, EGLDisplay eglDisplay)
{
int attribList[] = {
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
};
EGLConfig configs = NULL;
int configsNum;
if (!eglChooseConfig(eglDisplay, attribList, &configs, 1, &configsNum)) {
LOGE("eglChooseConfig ERROR");
return NULL;
}
return configs;
}
void enableVertexAttrib(GLuint index, float *data, int32_t len)
{
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, len, data, GL_STATIC_DRAW);
glVertexAttribPointer(index, TRIANGLES_POINT, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(index);
return;
}
}
GLuint Tetrahedron::LoadShader(GLenum type, const char *shaderSrc)
{
GLuint shader;
GLint compiled;
shader = glCreateShader(type);
if (shader == 0) {
LOGE("LoadShader shader error");
return 0;
}
glShaderSource(shader, 1, &shaderSrc, nullptr);
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
if (!compiled) {
GLint infoLen = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
std::string infoLog(infoLen, '\0');
glGetShaderInfoLog(shader, infoLen, nullptr, (GLchar *)&infoLog);
LOGE("Error compiling shader:%{public}s\n", infoLog.c_str());
}
glDeleteShader(shader);
return 0;
}
return shader;
}
GLuint Tetrahedron::CreateProgram(const char *vertexShader, const char *fragShader)
{
GLuint vertex;
GLuint fragment;
GLuint program;
GLint linked;
vertex = LoadShader(GL_VERTEX_SHADER, vertexShader);
if (vertex == 0) {
LOGE("LoadShader: vertexShader error");
return 0;
}
fragment = LoadShader(GL_FRAGMENT_SHADER, fragShader);
if (fragment == 0) {
LOGE("LoadShader: fragShader error");
glDeleteShader(vertex);
return 0;
}
program = glCreateProgram();
if (program == 0) {
LOGE("CreateProgram program error");
glDeleteShader(vertex);
glDeleteShader(fragment);
return 0;
}
glAttachShader(program, vertex);
glAttachShader(program, fragment);
glLinkProgram(program);
glGetProgramiv(program, GL_LINK_STATUS, &linked);
if (!linked) {
LOGE("CreateProgram linked error");
GLint infoLen = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
std::string infoLog(infoLen, '\0');
glGetProgramInfoLog(program, infoLen, nullptr, (GLchar *)&infoLog);
LOGE("Error linking program:%{public}s\n", infoLog.c_str());
}
glDeleteShader(vertex);
glDeleteShader(fragment);
glDeleteProgram(program);
return 0;
}
glDeleteShader(vertex);
glDeleteShader(fragment);
return program;
}
int32_t Tetrahedron::Init(void *window, int32_t width, int32_t height)
{
LOGI("Init window = %{public}p, w = %{public}d, h = %{public}d.", window, width, height);
mEglWindow = reinterpret_cast<EGLNativeWindowType>(window);
mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (mEGLDisplay == EGL_NO_DISPLAY) {
LOGE("unable to get EGL display.");
return -1;
}
EGLint eglMajVers, eglMinVers;
if (!eglInitialize(mEGLDisplay, &eglMajVers, &eglMinVers)) {
mEGLDisplay = EGL_NO_DISPLAY;
LOGE("unable to initialize display");
return -1;
}
int version = 3;
mEGLConfig = getConfig(version, mEGLDisplay);
if (mEGLConfig == nullptr) {
LOGE("GLContextInit config ERROR");
return -1;
}
EGLint winAttribs[] = {EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR, EGL_NONE};
if (mEglWindow) {
mEGLSurface = eglCreateWindowSurface(mEGLDisplay, mEGLConfig, mEglWindow, winAttribs);
if (mEGLSurface == nullptr) {
LOGE("eglCreateContext eglSurface is null");
return -1;
}
}
/* Create EGLContext from */
int attrib3_list[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
mEGLContext = eglCreateContext(mEGLDisplay, mEGLConfig, mSharedEGLContext, attrib3_list);
if (!eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext)) {
LOGE("eglMakeCurrent error = %{public}d", eglGetError());
}
mProgramHandle = CreateProgram(g_vertexShader, g_fragmentShader);
if (!mProgramHandle) {
LOGE("Could not create CreateProgram");
return -1;
}
LOGI("Init success.");
return 0;
}
void Tetrahedron::Update(float angleXOffset, float angleYOffset)
{
const float pi = 3.141592;
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(mProgramHandle);
GLint aPos = glGetAttribLocation(mProgramHandle, "a_pos");
GLint aColor = glGetAttribLocation(mProgramHandle, "a_color");
GLint aNormal = glGetAttribLocation(mProgramHandle, "a_normal");
GLint uLightColor = glGetUniformLocation(mProgramHandle, "u_lightColor");
GLint uLightDirection = glGetUniformLocation(mProgramHandle, "u_lightDirection");
GLint aMx = glGetUniformLocation(mProgramHandle, "a_mx");
GLint aMy = glGetUniformLocation(mProgramHandle, "a_my");
angleX = angleXOffset;
angleY = angleYOffset;
/* y轴旋转度 */
float radianY = (angleY * pi) / 180.0;
float cosY = cosf(radianY);
float sinY = sinf(radianY);
float myArr[] = {
cosY, 0, -sinY, 0,
0, 1, 0, 0,
sinY, 0, cosY, 0,
0, 0, 0, 1
};
glUniformMatrix4fv(aMy, 1, false, myArr);
/* x轴旋转度 */
float radianX = (angleX * pi) / 180.0;
float cosX = cosf(radianX);
float sinX = sinf(radianX);
float mxArr[] = {
1, 0, 0, 0, 0, cosX, -sinX, 0, 0, sinX, cosX, 0, 0, 0, 0, 1
};
glUniformMatrix4fv(aMx, 1, false, mxArr);
/* 给平行光传入颜色和方向数据,RGB(1,1,1),单位向量(x,y,z) */
glUniform3f(uLightColor, 1.0, 1.0, 1.0);
/* 保证向量(x,y,z)的长度为1,即单位向量 */
float x = 2.0 / sqrt(15);
float y = 2.0 / sqrt(15);
float z = 3.0 / sqrt(15);
glUniform3f(uLightDirection, x, -y, z);
/* 创建缓冲区buffer,传入顶点位置数据g_vertexData */
enableVertexAttrib(aPos, g_vertexData, sizeof(g_vertexData));
enableVertexAttrib(aNormal, g_normalData, sizeof(g_normalData));
/* 创建缓冲区colorBuffer,传入顶点颜色数据g_colorData */
enableVertexAttrib(aColor, g_colorData, sizeof(g_colorData));
/* 执行绘制之前,一定要开启深度测试,以免颜色混乱 */
glEnable(GL_DEPTH_TEST);
/* 执行绘制并更新 */
glDrawArrays(GL_TRIANGLES, 0, TETRAHEDRON_POINT);
eglSwapBuffers(mEGLDisplay, mEGLSurface);
}
float Tetrahedron::GetAngleX()
{
return angleX;
}
float Tetrahedron::GetAngleY()
{
return angleY;
}
int32_t Tetrahedron::Quit(void)
{
EGLBoolean ret = eglDestroySurface(mEGLDisplay, mEGLSurface);
if (!ret) {
LOGW("eglDestroySurface failure.");
}
ret = eglDestroyContext(mEGLDisplay, mEGLContext);
if (!ret) {
LOGW("eglDestroyContext failure.");
}
ret = eglTerminate(mEGLDisplay);
if (!ret) {
LOGW("eglTerminate failure.");
}
mEGLSurface = NULL;
mEGLContext = NULL;
mEGLDisplay = NULL;
LOGE("Quit success.");
return 0;
}
Native XComponent相关函数如下:
函数名称 | 描述 |
---|---|
OH_NativeXComponent_GetXComponentId(OH_NativeXComponent *component, char *id, uint64_t *size) | 获取ArkUI XComponent的id |
OH_NativeXComponent_GetXComponentSize(OH_NativeXComponent *component, const void *window, uint64_t *width, uint64_t *height) | 获取ArkUI XComponent持有的surface的大小 |
OH_NativeXComponent_GetXComponentOffset(OH_NativeXComponent *component, const void *window, double *x, double *y) | 获取ArkUI XComponent组件相对屏幕左上顶点的偏移量 |
OH_NativeXComponent_GetTouchEvent(OH_NativeXComponent *component, const void *window, OH_NativeXComponent_TouchEvent *touchEvent) | 获取ArkUI XComponent调度的触摸事件 |
OH_NativeXComponent_GetTouchPointToolType(OH_NativeXComponent *component, uint32_t pointIndex, OH_NativeXComponent_TouchPointToolType *toolType) | 获取ArkUI XComponent触摸点工具类型 |
OH_NativeXComponent_GetTouchPointTiltX(OH_NativeXComponent *component, uint32_t pointIndex, float *tiltX) | 获取ArkUI XComponent触摸点倾斜与X轴角度 |
OH_NativeXComponent_GetTouchPointTiltY(OH_NativeXComponent *component, uint32_t pointIndex, float *tiltY) | 获取ArkUI XComponent触摸点倾斜与Y轴角度 |
OH_NativeXComponent_GetMouseEvent(OH_NativeXComponent *component, const void *window, OH_NativeXComponent_MouseEvent *mouseEvent) | 获取ArkUI XComponent调度的鼠标事件 |
OH_NativeXComponent_RegisterCallback(OH_NativeXComponent *component, OH_NativeXComponent_Callback *callback) | 实例注册回调 |
OH_NativeXComponent_RegisterMouseEventCallback(OH_NativeXComponent *component, OH_NativeXComponent_MouseEvent_Callback *callback) | 实例注册鼠标事件回调 |
以上就是本篇文章所带来的鸿蒙开发中一小部分技术讲解;想要学习完整的鸿蒙全栈技术。可以在结尾找我可全部拿到!
下面是鸿蒙的完整学习路线,展示如下:
除此之外,根据这个学习鸿蒙全栈学习路线,也附带一整套完整的学习【文档+视频】,内容包含如下:
内容包含了:(ArkTS、ArkUI、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、鸿蒙南向开发、鸿蒙项目实战)等技术知识点。帮助大家在学习鸿蒙路上快速成长!
鸿蒙【北向应用开发+南向系统层开发】文档
鸿蒙【基础+实战项目】视频
鸿蒙面经
为了避免大家在学习过程中产生更多的时间成本,对比我把以上内容全部放在了↓↓↓想要的可以自拿喔!谢谢大家观看!