mirror of
https://github.com/smallmain/cocos-enhance-kit.git
synced 2025-01-14 15:01:07 +00:00
304 lines
12 KiB
C++
304 lines
12 KiB
C++
/****************************************************************************
|
|
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
|
|
|
http://www.cocos.com
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated engine source code (the "Software"), a limited,
|
|
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
|
to use Cocos Creator solely to develop games on your target platforms. You shall
|
|
not use Cocos Creator software for developing other software or tools that's
|
|
used for developing games. You are not granted to publish, distribute,
|
|
sublicense, and/or sell copies of Cocos Creator.
|
|
|
|
The software or tools in this License Agreement are licensed, not sold.
|
|
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
THE SOFTWARE.
|
|
****************************************************************************/
|
|
#include "platform/openharmony/OpenHarmonyPlatform.h"
|
|
#include "platform/CCPlatformDefine.h"
|
|
|
|
#include <ace/xcomponent/native_interface_xcomponent.h>
|
|
#include <napi/native_api.h>
|
|
|
|
#include "cocos2d.h"
|
|
|
|
#include "cocos/scripting/js-bindings/manual/jsb_module_register.hpp"
|
|
#include "cocos/scripting/js-bindings/manual/jsb_global.h"
|
|
#include "cocos/scripting/js-bindings/event/EventDispatcher.h"
|
|
#include "cocos/scripting/js-bindings/manual/jsb_classtype.hpp"
|
|
#include "base/CCScheduler.h"
|
|
#include "cocos/scripting/js-bindings/event/EventDispatcher.h"
|
|
|
|
#include <sstream>
|
|
#include <chrono>
|
|
|
|
namespace {
|
|
void sendMsgToWorker(const cocos2d::MessageType& type, void* component, void* window) {
|
|
cocos2d::OpenHarmonyPlatform* platform = cocos2d::OpenHarmonyPlatform::getInstance();
|
|
cocos2d::WorkerMessageData data{type, static_cast<void*>(component), window};
|
|
platform->enqueue(data);
|
|
}
|
|
|
|
void onSurfaceCreatedCB(OH_NativeXComponent* component, void* window) {
|
|
sendMsgToWorker(cocos2d::MessageType::WM_XCOMPONENT_SURFACE_CREATED, component, window);
|
|
}
|
|
|
|
void dispatchTouchEventCB(OH_NativeXComponent* component, void* window) {
|
|
OH_NativeXComponent_TouchEvent touchEvent;
|
|
int32_t ret = OH_NativeXComponent_GetTouchEvent(component, window, &touchEvent);
|
|
if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
|
|
return;
|
|
}
|
|
cocos2d::TouchEvent* ev = new cocos2d::TouchEvent;
|
|
if (touchEvent.type == OH_NATIVEXCOMPONENT_DOWN) {
|
|
ev->type = cocos2d::TouchEvent::Type::BEGAN;
|
|
} else if (touchEvent.type == OH_NATIVEXCOMPONENT_MOVE) {
|
|
ev->type = cocos2d::TouchEvent::Type::MOVED;
|
|
} else if (touchEvent.type == OH_NATIVEXCOMPONENT_UP) {
|
|
ev->type = cocos2d::TouchEvent::Type::ENDED;
|
|
} else if (touchEvent.type == OH_NATIVEXCOMPONENT_CANCEL) {
|
|
ev->type = cocos2d::TouchEvent::Type::CANCELLED;
|
|
}
|
|
for(int i = 0; i < touchEvent.numPoints; ++i) {
|
|
cocos2d::TouchInfo touchInfo;
|
|
touchInfo.index = touchEvent.touchPoints[i].id;
|
|
touchInfo.x = touchEvent.touchPoints[i].x;
|
|
touchInfo.y = touchEvent.touchPoints[i].y;
|
|
if (touchEvent.id == touchInfo.index) {
|
|
ev->touches.push_back(touchInfo);
|
|
}
|
|
}
|
|
sendMsgToWorker(cocos2d::MessageType::WM_XCOMPONENT_TOUCH_EVENT, reinterpret_cast<void*>(ev), window);
|
|
}
|
|
|
|
void onSurfaceChangedCB(OH_NativeXComponent* component, void* window) {
|
|
sendMsgToWorker(cocos2d::MessageType::WM_XCOMPONENT_SURFACE_CHANGED, component, window);
|
|
}
|
|
|
|
void onSurfaceDestroyedCB(OH_NativeXComponent* component, void* window) {
|
|
sendMsgToWorker(cocos2d::MessageType::WM_XCOMPONENT_SURFACE_DESTROY, component, window);
|
|
}
|
|
|
|
bool setCanvasCallback(se::Object* global) {
|
|
cocos2d::OpenHarmonyPlatform* platform = cocos2d::OpenHarmonyPlatform::getInstance();
|
|
uint32_t innerWidth = (uint32_t)platform->width_;
|
|
uint32_t innerHeight = (uint32_t)platform->height_;
|
|
global->setProperty("innerWidth", se::Value(innerWidth));
|
|
global->setProperty("innerHeight", se::Value(innerHeight));
|
|
LOGD("exit setCanvasCallback setCanvasCallback");
|
|
return true;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
namespace cocos2d {
|
|
|
|
OpenHarmonyPlatform::OpenHarmonyPlatform() {
|
|
_callback.OnSurfaceCreated = onSurfaceCreatedCB;
|
|
_callback.OnSurfaceChanged = onSurfaceChangedCB;
|
|
_callback.OnSurfaceDestroyed = onSurfaceDestroyedCB;
|
|
_callback.DispatchTouchEvent = dispatchTouchEventCB;
|
|
}
|
|
|
|
int32_t OpenHarmonyPlatform::init() {
|
|
return 0;
|
|
}
|
|
|
|
OpenHarmonyPlatform* OpenHarmonyPlatform::getInstance() {
|
|
static OpenHarmonyPlatform platform;
|
|
return &platform;
|
|
}
|
|
|
|
int32_t OpenHarmonyPlatform::run(int argc, const char** argv) {
|
|
LOGD("begin openharmonyplatform run");
|
|
|
|
int width = static_cast<int>(width_);
|
|
int height = static_cast<int>(height_);
|
|
g_app = new AppDelegate(width, height);
|
|
g_app->applicationDidFinishLaunching();
|
|
EventDispatcher::init();
|
|
g_started = true;
|
|
LOGD("end openharmonyplatform run");
|
|
return 0;
|
|
}
|
|
|
|
void OpenHarmonyPlatform::setNativeXComponent(OH_NativeXComponent* component) {
|
|
_component = component;
|
|
OH_NativeXComponent_RegisterCallback(_component, &_callback);
|
|
}
|
|
|
|
void OpenHarmonyPlatform::enqueue(const WorkerMessageData& msg) {
|
|
_messageQueue.enqueue(msg);
|
|
triggerMessageSignal();
|
|
}
|
|
|
|
void OpenHarmonyPlatform::triggerMessageSignal() {
|
|
if(_workerLoop != nullptr) {
|
|
// It is possible that when the message is sent, the worker thread has not yet started.
|
|
uv_async_send(&_messageSignal);
|
|
}
|
|
}
|
|
|
|
bool OpenHarmonyPlatform::dequeue(WorkerMessageData* msg) {
|
|
return _messageQueue.dequeue(msg);
|
|
}
|
|
|
|
// static
|
|
void OpenHarmonyPlatform::onMessageCallback(const uv_async_t* /* req */) {
|
|
void* window = nullptr;
|
|
WorkerMessageData msgData;
|
|
OpenHarmonyPlatform* platform = OpenHarmonyPlatform::getInstance();
|
|
|
|
while (true) {
|
|
//loop until all msg dispatch
|
|
if (!platform->dequeue(reinterpret_cast<WorkerMessageData*>(&msgData))) {
|
|
// Queue has no data
|
|
break;
|
|
}
|
|
|
|
if ((msgData.type >= MessageType::WM_XCOMPONENT_SURFACE_CREATED) && (msgData.type <= MessageType::WM_XCOMPONENT_SURFACE_DESTROY)) {
|
|
if (msgData.type == MessageType::WM_XCOMPONENT_TOUCH_EVENT) {
|
|
TouchEvent* ev = reinterpret_cast<TouchEvent*>(msgData.data);
|
|
EventDispatcher::dispatchTouchEvent(*ev);
|
|
delete ev;
|
|
ev = nullptr;
|
|
} else if (msgData.type == MessageType::WM_XCOMPONENT_SURFACE_CREATED) {
|
|
OH_NativeXComponent* nativexcomponet = reinterpret_cast<OH_NativeXComponent*>(msgData.data);
|
|
CC_ASSERT(nativexcomponet != nullptr);
|
|
platform->onSurfaceCreated(nativexcomponet, msgData.window);
|
|
} else if (msgData.type == MessageType::WM_XCOMPONENT_SURFACE_CHANGED) {
|
|
OH_NativeXComponent* nativexcomponet = reinterpret_cast<OH_NativeXComponent*>(msgData.data);
|
|
CC_ASSERT(nativexcomponet != nullptr);
|
|
platform->onSurfaceChanged(nativexcomponet, msgData.window);
|
|
} else if (msgData.type == MessageType::WM_XCOMPONENT_SURFACE_DESTROY) {
|
|
OH_NativeXComponent* nativexcomponet = reinterpret_cast<OH_NativeXComponent*>(msgData.data);
|
|
CC_ASSERT(nativexcomponet != nullptr);
|
|
platform->onSurfaceDestroyed(nativexcomponet, msgData.window);
|
|
} else {
|
|
CC_ASSERT(false);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (msgData.type == MessageType::WM_APP_SHOW) {
|
|
platform->onShowNative();
|
|
} else if (msgData.type == MessageType::WM_APP_HIDE) {
|
|
platform->onHideNative();
|
|
} else if (msgData.type == MessageType::WM_APP_DESTROY) {
|
|
platform->onDestroyNative();
|
|
}
|
|
}
|
|
}
|
|
|
|
void OpenHarmonyPlatform::onCreateNative(napi_env env, uv_loop_t* loop) {
|
|
LOGD("OpenHarmonyPlatform::onCreateNative");
|
|
}
|
|
|
|
void OpenHarmonyPlatform::onShowNative() {
|
|
LOGD("OpenHarmonyPlatform::onShowNative");
|
|
EventDispatcher::dispatchOnResumeEvent();
|
|
}
|
|
|
|
void OpenHarmonyPlatform::onHideNative() {
|
|
LOGD("OpenHarmonyPlatform::onHideNative");
|
|
EventDispatcher::dispatchOnPauseEvent();
|
|
}
|
|
|
|
void OpenHarmonyPlatform::onDestroyNative() {
|
|
LOGD("OpenHarmonyPlatform::onDestroyNative");
|
|
}
|
|
|
|
void OpenHarmonyPlatform::timerCb(uv_timer_t* handle) {
|
|
if(OpenHarmonyPlatform::getInstance()->eglCore_ != nullptr){
|
|
OpenHarmonyPlatform::getInstance()->tick();
|
|
OpenHarmonyPlatform::getInstance()->eglCore_->Update();
|
|
}
|
|
}
|
|
|
|
void OpenHarmonyPlatform::workerInit(napi_env env, uv_loop_t* loop) {
|
|
_workerLoop = loop;
|
|
if (_workerLoop) {
|
|
uv_async_init(_workerLoop, &_messageSignal, reinterpret_cast<uv_async_cb>(OpenHarmonyPlatform::onMessageCallback));
|
|
if (!_messageQueue.empty()) {
|
|
triggerMessageSignal(); // trigger the signal to handle the pending message
|
|
}
|
|
}
|
|
}
|
|
|
|
void OpenHarmonyPlatform::requestVSync() {
|
|
// OH_NativeVSync_RequestFrame(OpenHarmonyPlatform::getInstance()->_nativeVSync, OnVSync, nullptr);
|
|
if (_workerLoop) {
|
|
// Todo: Starting the timer in this way is inaccurate and will be fixed later.
|
|
uv_timer_init(_workerLoop, &_timerHandle);
|
|
// The tick function needs to be called as quickly as possible because it is controlling the frame rate inside the engine.
|
|
uv_timer_start(&_timerHandle, &OpenHarmonyPlatform::timerCb, 0, 1);
|
|
}
|
|
}
|
|
|
|
int32_t OpenHarmonyPlatform::loop() {
|
|
return 0;
|
|
}
|
|
|
|
void OpenHarmonyPlatform::onSurfaceCreated(OH_NativeXComponent* component, void* window) {
|
|
eglCore_ = new EGLCore();
|
|
int32_t ret=OH_NativeXComponent_GetXComponentSize(component, window, &width_, &height_);
|
|
if (ret == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
|
|
eglCore_->GLContextInit(window, width_, height_);
|
|
se::ScriptEngine *scriptEngine = se::ScriptEngine::getInstance();
|
|
scriptEngine->addRegisterCallback(setCanvasCallback);
|
|
if(g_app!=nullptr){
|
|
OpenHarmonyPlatform* platform = OpenHarmonyPlatform::getInstance();
|
|
g_app->updateViewSize(static_cast<float>(platform->width_), static_cast<float>(platform->height_));
|
|
}
|
|
LOGD("egl init finished.");
|
|
}
|
|
}
|
|
|
|
void OpenHarmonyPlatform::onSurfaceChanged(OH_NativeXComponent* component, void* window) {
|
|
int32_t ret = OH_NativeXComponent_GetXComponentSize(component, window, &width_, &height_);
|
|
// nativeOnSizeChanged is firstly called before Application initiating.
|
|
if (g_app != nullptr) {
|
|
g_app->updateViewSize(width_, height_);
|
|
}
|
|
}
|
|
|
|
void OpenHarmonyPlatform::onSurfaceDestroyed(OH_NativeXComponent* component, void* window) {
|
|
}
|
|
|
|
void OpenHarmonyPlatform::setPreferedFramePersecond(int fps) {
|
|
if (fps == 0) {
|
|
return;
|
|
}
|
|
_prefererredNanosecondsPerFrame = static_cast<long>(1.0 / fps * NANOSECONDS_PER_SECOND); // NOLINT(google-runtime-int)
|
|
}
|
|
|
|
void OpenHarmonyPlatform::tick() {
|
|
static std::chrono::steady_clock::time_point prevTime;
|
|
static std::chrono::steady_clock::time_point now;
|
|
static float dt = 0.f;
|
|
static double dtNS = NANOSECONDS_60FPS;
|
|
if (dtNS < static_cast<double>(_prefererredNanosecondsPerFrame)) {
|
|
std::this_thread::sleep_for(std::chrono::nanoseconds(
|
|
_prefererredNanosecondsPerFrame - static_cast<int64_t>(dtNS)));
|
|
dtNS = static_cast<double>(_prefererredNanosecondsPerFrame);
|
|
}
|
|
prevTime = std::chrono::steady_clock::now();
|
|
std::shared_ptr<Scheduler> scheduler = g_app->getScheduler();
|
|
scheduler->update(dt);
|
|
EventDispatcher::dispatchTickEvent(dt);
|
|
PoolManager::getInstance()->getCurrentPool()->clear();
|
|
now = std::chrono::steady_clock::now();
|
|
dtNS = dtNS * 0.1 + 0.9 * static_cast<double>(std::chrono::duration_cast<std::chrono::nanoseconds>(now - prevTime).count());
|
|
dt = static_cast<float>(dtNS) / NANOSECONDS_PER_SECOND;
|
|
}
|
|
|
|
}; // namespace cc
|