3.6.3 native目录

This commit is contained in:
lujun 2023-02-11 22:09:50 +08:00
parent fa7a606f33
commit 4d9a0f87e8
33 changed files with 7086 additions and 0 deletions

View File

@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 3.8)
option(APP_NAME "Project Name" "ui-sorting-group")
project(${APP_NAME} CXX)
set(CC_LIB_NAME cocos)
set(CC_PROJECT_DIR ${CMAKE_CURRENT_LIST_DIR})
set(CC_PROJ_SOURCES)
set(CC_COMMON_SOURCES)
set(CC_ALL_SOURCES)
include(${CMAKE_CURRENT_LIST_DIR}/../common/CMakeLists.txt)
cc_android_before_target(${CC_LIB_NAME})
add_library(${CC_LIB_NAME} SHARED ${CC_ALL_SOURCES})
cc_android_after_target(${CC_LIB_NAME})

View File

@ -0,0 +1 @@
# Supported for Cocos Service!

View File

@ -0,0 +1 @@
# Supported for Cocos Service!

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lcc.test"
android:installLocation="auto">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<application
android:extractNativeLibs="true"
android:allowBackup="true"
android:label="@string/app_name"
android:usesCleartextTraffic="true"
android:icon="@mipmap/ic_launcher">
<!-- Tell CocosNativeActivity the name of our .so -->
<meta-data android:name="android.app.lib_name"
android:value="cocos" />
<activity
android:name="com.cocos.game.AppActivity"
android:screenOrientation="sensorLandscape"
android:configChanges="orientation|keyboardHidden|screenSize|screenLayout"
android:label="@string/app_name"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:launchMode="singleTask"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.cocos.lib.CocosEditBoxActivity"
android:configChanges="orientation|keyboardHidden|screenSize|screenLayout"
android:screenOrientation="behind"
android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen" />
</application>
</manifest>

View File

@ -0,0 +1,104 @@
import org.apache.tools.ant.taskdefs.condition.Os
apply plugin: 'com.android.application'
RES_PATH = RES_PATH.replace("\\", "/")
COCOS_ENGINE_PATH = COCOS_ENGINE_PATH.replace("\\", "/")
buildDir = "${RES_PATH}/proj/build/$project.name"
android {
compileSdkVersion PROP_COMPILE_SDK_VERSION.toInteger()
buildToolsVersion PROP_BUILD_TOOLS_VERSION
ndkPath PROP_NDK_PATH
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
defaultConfig {
applicationId APPLICATION_ID
minSdkVersion PROP_MIN_SDK_VERSION
targetSdkVersion PROP_TARGET_SDK_VERSION
versionCode 1
versionName "1.0"
externalNativeBuild {
cmake {
targets "cocos"
arguments "-DRES_DIR=${RES_PATH}", "-DCOCOS_X_PATH=${COCOS_ENGINE_PATH}", "-DANDROID_STL=c++_static", "-DANDROID_TOOLCHAIN=clang", "-DANDROID_ARM_NEON=TRUE", "-DANDROID_LD=gold"
}
ndk { abiFilters PROP_APP_ABI.split(':') }
}
}
sourceSets.main {
java.srcDirs "../src", "src"
res.srcDirs "../res", 'res'
jniLibs.srcDirs "../libs", 'libs'
manifest.srcFile "AndroidManifest.xml"
assets.srcDir "${RES_PATH}/data"
jniLibs {
// Vulkan validation layer
// srcDir "${android.ndkDirectory}/sources/third_party/vulkan/src/build-android/jniLibs"
}
}
externalNativeBuild {
cmake {
path "../CMakeLists.txt"
buildStagingDirectory "${RES_PATH}/proj/build"
}
}
signingConfigs {
release {
if (project.hasProperty("RELEASE_STORE_FILE") && !RELEASE_STORE_FILE.isEmpty()) {
storeFile file(RELEASE_STORE_FILE)
storePassword RELEASE_STORE_PASSWORD
keyAlias RELEASE_KEY_ALIAS
keyPassword RELEASE_KEY_PASSWORD
}
}
}
buildTypes {
release {
debuggable false
jniDebuggable false
renderscriptDebuggable false
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
if (project.hasProperty("RELEASE_STORE_FILE")) {
signingConfig signingConfigs.release
}
externalNativeBuild {
cmake {
// switch HIDE_SYMBOLS to OFF to skip compilation flag `-fvisibility=hidden`
arguments "-DHIDE_SYMBOLS=ON"
}
}
// resValue "string", "app_name", PROP_APP_NAME
}
debug {
debuggable true
jniDebuggable true
renderscriptDebuggable true
// resValue "string", "app_name", "${PROP_APP_NAME}-dbg"
// applicationIdSuffix ".debug"
}
}
}
dependencies {
implementation fileTree(dir: '../libs', include: ['*.jar','*.aar'])
implementation fileTree(dir: 'libs', include: ['*.jar','*.aar'])
implementation fileTree(dir: "${COCOS_ENGINE_PATH}/cocos/platform/android/java/libs", include: ['*.jar'])
implementation project(':libservice')
implementation project(':libcocos')
}

View File

@ -0,0 +1,42 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in E:\developSoftware\Android\SDK/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Proguard Cocos2d-x-lite for release
-keep public class com.cocos.** { *; }
-dontwarn com.cocos.**
# Proguard Apache HTTP for release
-keep class org.apache.http.** { *; }
-dontwarn org.apache.http.**
# Proguard okhttp for release
-keep class okhttp3.** { *; }
-dontwarn okhttp3.**
-keep class okio.** { *; }
-dontwarn okio.**
# Proguard Android Webivew for release. you can comment if you are not using a webview
-keep public class android.net.http.SslError
-keep public class android.webkit.WebViewClient
-keep public class com.google.** { *; }
-dontwarn android.webkit.WebView
-dontwarn android.net.http.SslError
-dontwarn android.webkit.WebViewClient

View File

@ -0,0 +1,125 @@
/****************************************************************************
Copyright (c) 2015-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
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.
****************************************************************************/
package com.cocos.game;
import android.os.Bundle;
import android.content.Intent;
import android.content.res.Configuration;
import com.cocos.service.SDKWrapper;
import com.cocos.lib.CocosActivity;
public class AppActivity extends CocosActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// DO OTHER INITIALIZATION BELOW
SDKWrapper.shared().init(this);
}
@Override
protected void onResume() {
super.onResume();
SDKWrapper.shared().onResume();
}
@Override
protected void onPause() {
super.onPause();
SDKWrapper.shared().onPause();
}
@Override
protected void onDestroy() {
super.onDestroy();
// Workaround in https://stackoverflow.com/questions/16283079/re-launch-of-activity-on-home-button-but-only-the-first-time/16447508
if (!isTaskRoot()) {
return;
}
SDKWrapper.shared().onDestroy();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
SDKWrapper.shared().onActivityResult(requestCode, resultCode, data);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
SDKWrapper.shared().onNewIntent(intent);
}
@Override
protected void onRestart() {
super.onRestart();
SDKWrapper.shared().onRestart();
}
@Override
protected void onStop() {
super.onStop();
SDKWrapper.shared().onStop();
}
@Override
public void onBackPressed() {
SDKWrapper.shared().onBackPressed();
super.onBackPressed();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
SDKWrapper.shared().onConfigurationChanged(newConfig);
super.onConfigurationChanged(newConfig);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
SDKWrapper.shared().onRestoreInstanceState(savedInstanceState);
super.onRestoreInstanceState(savedInstanceState);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
SDKWrapper.shared().onSaveInstanceState(outState);
super.onSaveInstanceState(outState);
}
@Override
protected void onStart() {
SDKWrapper.shared().onStart();
super.onStart();
}
@Override
public void onLowMemory() {
SDKWrapper.shared().onLowMemory();
super.onLowMemory();
}
}

View File

@ -0,0 +1,8 @@
{
"ndk_module_path" :[
"${COCOS_ROOT}",
"${COCOS_ROOT}/cocos",
"${COCOS_ROOT}/external"
],
"copy_resources": []
}

View File

@ -0,0 +1,31 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
mavenCentral()
// jcenter() // keeped as anchor, will be removed soon
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
mavenCentral()
// jcenter() // keeped as anchor, will be removed soon
flatDir {
dirs 'libs'
}
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dist="http://schemas.android.com/apk/distribution"
package="com.lcc.test"
android:installLocation="auto">
<dist:module dist:instant="true" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<application
android:extractNativeLibs="true"
android:allowBackup="true"
android:label="@string/app_name"
android:supportsRtl="true"
android:icon="@mipmap/ic_launcher">
<meta-data
android:name="aia-compat-api-min-version"
android:value="1" />
<!-- Tell CocosNativeActivity the name of our .so -->
<meta-data android:name="android.app.lib_name"
android:value="cocos" />
<activity
android:name="com.cocos.game.InstantActivity"
android:screenOrientation="sensorLandscape"
android:configChanges="orientation|keyboardHidden|screenSize|screenLayout"
android:label="@string/app_name"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:launchMode="singleTask"
android:exported="true">
<intent-filter android:order="1">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.cocos.lib.CocosEditBoxActivity"
android:configChanges="orientation|keyboardHidden|screenSize|screenLayout"
android:screenOrientation="behind"
android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen" />
</application>
</manifest>

View File

@ -0,0 +1,101 @@
import org.apache.tools.ant.taskdefs.condition.Os
apply plugin: 'com.android.application'
RES_PATH = RES_PATH.replace("\\", "/")
COCOS_ENGINE_PATH = COCOS_ENGINE_PATH.replace("\\", "/")
buildDir = "${RES_PATH}/proj/build/$project.name"
android {
compileSdkVersion PROP_COMPILE_SDK_VERSION.toInteger()
buildToolsVersion PROP_BUILD_TOOLS_VERSION
ndkPath PROP_NDK_PATH
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
defaultConfig {
applicationId "com.lcc.test"
minSdkVersion PROP_MIN_SDK_VERSION
targetSdkVersion PROP_TARGET_SDK_VERSION
versionCode 1
versionName "1.0"
externalNativeBuild {
cmake {
targets "cocos"
arguments "-DRES_DIR=${RES_PATH}", "-DCOCOS_X_PATH=${COCOS_ENGINE_PATH}","-DANDROID_STL=c++_static", "-DANDROID_TOOLCHAIN=clang", "-DANDROID_ARM_NEON=TRUE", "-DANDROID_LD=gold"
cppFlags "-frtti -fexceptions -fsigned-char -DANDROID_INSTANT=1"
}
ndk { abiFilters PROP_APP_ABI.split(':') }
}
}
sourceSets.main {
java.srcDirs "../src", "src"
res.srcDirs "../res", 'res'
jniLibs.srcDirs "../libs", 'libs'
manifest.srcFile "AndroidManifest.xml"
assets.srcDir "${RES_PATH}/data"
}
externalNativeBuild {
cmake {
path "../CMakeLists.txt"
buildStagingDirectory "${RES_PATH}/proj/build"
}
}
signingConfigs {
release {
if (project.hasProperty("RELEASE_STORE_FILE") && !RELEASE_STORE_FILE.isEmpty()) {
storeFile file(RELEASE_STORE_FILE)
storePassword RELEASE_STORE_PASSWORD
keyAlias RELEASE_KEY_ALIAS
keyPassword RELEASE_KEY_PASSWORD
}
}
}
buildTypes {
release {
debuggable false
jniDebuggable false
renderscriptDebuggable false
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
if (project.hasProperty("RELEASE_STORE_FILE")) {
signingConfig signingConfigs.release
}
externalNativeBuild {
cmake {
// switch HIDE_SYMBOLS to OFF to skip compilation flag `-fvisibility=hidden`
arguments "-DHIDE_SYMBOLS=ON"
}
}
// resValue "string", "app_name", PROP_APP_NAME
}
debug {
debuggable true
jniDebuggable true
renderscriptDebuggable true
// resValue "string", "app_name", "${PROP_APP_NAME}-dbg"
// applicationIdSuffix ".debug"
}
}
}
dependencies {
implementation fileTree(dir: '../libs', include: ['*.jar','*.aar'])
implementation fileTree(dir: 'libs', include: ['*.jar','*.aar'])
implementation fileTree(dir: "${COCOS_ENGINE_PATH}/cocos/platform/android/java/libs", include: ['*.jar'])
implementation project(':libservice')
implementation project(':libcocos')
}

View File

@ -0,0 +1,42 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in E:\developSoftware\Android\SDK/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Proguard Cocos2d-x-lite for release
-keep public class com.cocos.** { *; }
-dontwarn com.cocos.**
# Proguard Apache HTTP for release
-keep class org.apache.http.** { *; }
-dontwarn org.apache.http.**
# Proguard okhttp for release
-keep class okhttp3.** { *; }
-dontwarn okhttp3.**
-keep class okio.** { *; }
-dontwarn okio.**
# Proguard Android Webivew for release. you can comment if you are not using a webview
-keep public class android.net.http.SslError
-keep public class android.webkit.WebViewClient
-keep public class com.google.** { *; }
-dontwarn android.webkit.WebView
-dontwarn android.net.http.SslError
-dontwarn android.webkit.WebViewClient

View File

@ -0,0 +1,125 @@
/****************************************************************************
Copyright (c) 2015-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
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.
****************************************************************************/
package com.cocos.game;
import android.os.Bundle;
import android.content.Intent;
import android.content.res.Configuration;
import com.cocos.service.SDKWrapper;
import com.cocos.lib.CocosActivity;
public class InstantActivity extends CocosActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// DO OTHER INITIALIZATION BELOW
SDKWrapper.shared().init(this);
}
@Override
protected void onResume() {
super.onResume();
SDKWrapper.shared().onResume();
}
@Override
protected void onPause() {
super.onPause();
SDKWrapper.shared().onPause();
}
@Override
protected void onDestroy() {
super.onDestroy();
// Workaround in https://stackoverflow.com/questions/16283079/re-launch-of-activity-on-home-button-but-only-the-first-time/16447508
if (!isTaskRoot()) {
return;
}
SDKWrapper.shared().onDestroy();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
SDKWrapper.shared().onActivityResult(requestCode, resultCode, data);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
SDKWrapper.shared().onNewIntent(intent);
}
@Override
protected void onRestart() {
super.onRestart();
SDKWrapper.shared().onRestart();
}
@Override
protected void onStop() {
super.onStop();
SDKWrapper.shared().onStop();
}
@Override
public void onBackPressed() {
SDKWrapper.shared().onBackPressed();
super.onBackPressed();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
SDKWrapper.shared().onConfigurationChanged(newConfig);
super.onConfigurationChanged(newConfig);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
SDKWrapper.shared().onRestoreInstanceState(savedInstanceState);
super.onRestoreInstanceState(savedInstanceState);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
SDKWrapper.shared().onSaveInstanceState(outState);
super.onSaveInstanceState(outState);
}
@Override
protected void onStart() {
SDKWrapper.shared().onStart();
super.onStart();
}
@Override
public void onLowMemory() {
SDKWrapper.shared().onLowMemory();
super.onLowMemory();
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

@ -0,0 +1,3 @@
<resources>
<string name="app_name" translatable="false">ui-sorting-group</string>
</resources>

View File

@ -0,0 +1,54 @@
enable_language(C ASM)
set(DEVELOPMENT_TEAM "" CACHE STRING "APPLE Developtment Team")
set(RES_DIR "" CACHE STRING "Resource path")
set(COCOS_X_PATH "" CACHE STRING "Path to engine/native/")
set(TARGET_OSX_VERSION "10.14" CACHE STRING "Target MacOSX version" FORCE)
set(TARGET_IOS_VERSION "11.0" CACHE STRING "Target iOS version" FORCE)
set(CMAKE_CXX_STANDARD 17)
option(CC_DEBUG_FORCE "Force enable CC_DEBUG in release mode" OFF)
option(USE_SE_V8 "Use V8 JavaScript Engine" ON)
option(USE_V8_DEBUGGER "Compile v8 inspector ws server" ON)
option(USE_V8_DEBUGGER_FORCE "Force enable debugger in release mode" OFF)
option(USE_SOCKET "Enable WebSocket & SocketIO" ON)
option(USE_AUDIO "Enable Audio" ON) #Enable AudioEngine
option(USE_EDIT_BOX "Enable EditBox" ON)
option(USE_SE_JSC "Use JavaScriptCore on MacOSX/iOS" OFF)
option(USE_VIDEO "Enable VideoPlayer Component" ON)
option(USE_WEBVIEW "Enable WebView Component" ON)
option(USE_MIDDLEWARE "Enable Middleware" ON)
option(USE_DRAGONBONES "Enable Dragonbones" ON)
option(USE_SPINE "Enable Spine" ON)
option(USE_WEBSOCKET_SERVER "Enable WebSocket Server" OFF)
option(USE_JOB_SYSTEM_TASKFLOW "Use taskflow as job system backend" OFF)
option(USE_JOB_SYSTEM_TBB "Use tbb as job system backend" OFF)
option(USE_PHYSICS_PHYSX "Use PhysX Physics" ON)
option(USE_OCCLUSION_QUERY "Use Occlusion Query" ON)
option(USE_DEBUG_RENDERER "Use Debug Renderer" ON)
option(USE_GEOMETRY_RENDERER "Use Geometry Renderer" ON)
option(USE_WEBP "Use Webp" ON)
if(NOT RES_DIR)
message(FATAL_ERROR "RES_DIR is not set!")
endif()
include(${RES_DIR}/proj/cfg.cmake)
if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/localCfg.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/localCfg.cmake)
endif()
if(NOT COCOS_X_PATH)
message(FATAL_ERROR "COCOS_X_PATH is not set!")
endif()
# lcc-ui-sorting-group native
include(${CMAKE_CURRENT_LIST_DIR}/../lcc-ui-sorting-group-native/CMakeLists.txt)
include(${COCOS_X_PATH}/CMakeLists.txt)
list(APPEND CC_COMMON_SOURCES
${CMAKE_CURRENT_LIST_DIR}/Classes/Game.h
${CMAKE_CURRENT_LIST_DIR}/Classes/Game.cpp
)

View File

@ -0,0 +1,65 @@
/****************************************************************************
Copyright (c) 2017-2018 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 "Game.h"
#ifndef GAME_NAME
#define GAME_NAME "CocosGame";
#endif
#ifndef SCRIPT_XXTEAKEY
#define SCRIPT_XXTEAKEY "";
#endif
Game::Game() = default;
int Game::init() {
_windowInfo.title = GAME_NAME;
// configurate window size
// _windowInfo.height = 600;
// _windowInfo.width = 800;
#if CC_DEBUG
_debuggerInfo.enabled = true;
#else
_debuggerInfo.enabled = false;
#endif
_debuggerInfo.port = 6086;
_debuggerInfo.address = "0.0.0.0";
_debuggerInfo.pauseOnStart = false;
_xxteaKey = SCRIPT_XXTEAKEY;
BaseGame::init();
return 0;
}
void Game::onPause() { BaseGame::onPause(); }
void Game::onResume() { BaseGame::onResume(); }
void Game::onClose() { BaseGame::onClose(); }
CC_REGISTER_APPLICATION(Game);

View File

@ -0,0 +1,44 @@
/****************************************************************************
Copyright (c) 2018 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.
****************************************************************************/
#pragma once
#include "cocos/cocos.h"
/**
@brief The cocos2d Application.
The reason for implement as private inheritance is to hide some interface call
by Director.
*/
class Game : public cc::BaseGame {
public:
Game();
int init() override;
// bool init() override;
void onPause() override;
void onResume() override;
void onClose() override;
};

View File

@ -0,0 +1 @@
{"version":"3.6.3","skipCheck":false}

View File

@ -0,0 +1,3 @@
## Add or overwrite options from cfg.cmake.
## This file is ignored from git.
# set(NODE_EXECUTABLE /opt/...)

View File

@ -0,0 +1,36 @@
if(NOT DEFINED COCOS_SOURCE_PLUGIN_EXCULDE)
set(COCOS_SOURCE_PLUGIN_EXCULDE)
endif()
if(NOT DEFINED COCOS_SOURCE_PLUGIN_LIST)
set(COCOS_SOURCE_PLUGIN_LIST)
endif()
if(NOT DEFINED COCOS_SOURCE_PLUGIN_INCLUDES)
set(COCOS_SOURCE_PLUGIN_INCLUDES)
endif()
#
list(APPEND COCOS_SOURCE_PLUGIN_EXCULDE
"${COCOS_X_PATH}/cocos/2d/renderer/Batcher2d.h"
"${COCOS_X_PATH}/cocos/2d/renderer/Batcher2d.cpp"
"${COCOS_X_PATH}/cocos/2d/renderer/RenderEntity.h"
"${COCOS_X_PATH}/cocos/2d/renderer/RenderEntity.cpp"
"${COCOS_X_PATH}/cocos/core/scene-graph/Node.h"
"${COCOS_X_PATH}/cocos/core/scene-graph/Node.cpp"
)
#
list(APPEND COCOS_SOURCE_PLUGIN_LIST
"${CMAKE_CURRENT_LIST_DIR}/native/cocos/2d/renderer/Batcher2d.h"
"${CMAKE_CURRENT_LIST_DIR}/native/cocos/2d/renderer/Batcher2d.cpp"
"${CMAKE_CURRENT_LIST_DIR}/native/cocos/2d/renderer/RenderEntity.h"
"${CMAKE_CURRENT_LIST_DIR}/native/cocos/2d/renderer/RenderEntity.cpp"
"${CMAKE_CURRENT_LIST_DIR}/native/cocos/core/scene-graph/Node.h"
"${CMAKE_CURRENT_LIST_DIR}/native/cocos/core/scene-graph/Node.cpp"
)
#
list(APPEND COCOS_SOURCE_PLUGIN_INCLUDES
"${CMAKE_CURRENT_LIST_DIR}/native"
"${CMAKE_CURRENT_LIST_DIR}/native/cocos"
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,660 @@
/****************************************************************************
Copyright (c) 2019-2021 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 "2d/renderer/Batcher2d.h"
#include "application/ApplicationManager.h"
#include "base/TypeDef.h"
#include "core/Root.h"
#include "editor-support/MiddlewareManager.h"
#include "renderer/pipeline/Define.h"
#include "scene/Pass.h"
#include <algorithm>
namespace cc {
Batcher2d::Batcher2d() : Batcher2d(nullptr) {
}
Batcher2d::Batcher2d(Root* root)
: _drawBatchPool([]() { return ccnew scene::DrawBatch2D(); }, [](auto* obj) { delete obj; }, 10U) {
if (root == nullptr) {
root = Root::getInstance();
}
_root = root;
_device = _root->getDevice();
_stencilManager = StencilManager::getInstance();
// LCC_UI_SORTING_GROUP
rendererCache.reserve(1024);
rendererOrder = false;
}
Batcher2d::~Batcher2d() { // NOLINT
_drawBatchPool.destroy();
for (auto iter : _descriptorSetCache) {
delete iter.second;
}
for (auto* drawBatch : _batches) {
delete drawBatch;
}
_attributes.clear();
if(_maskClearModel != nullptr) {
Root::getInstance()->destroyModel(_maskClearModel);
_maskClearModel = nullptr;
}
if (_maskModelMesh != nullptr) {
_maskModelMesh->destroy();
_maskModelMesh = nullptr;
}
_maskClearMtl = nullptr;
_maskAttributes.clear();
}
void Batcher2d::syncMeshBuffersToNative(uint16_t accId, ccstd::vector<UIMeshBuffer*>&& buffers) {
_meshBuffersMap[accId] = std::move(buffers);
}
UIMeshBuffer* Batcher2d::getMeshBuffer(uint16_t accId, uint16_t bufferId) { // NOLINT(bugprone-easily-swappable-parameters)
const auto& map = _meshBuffersMap[accId];
return map[bufferId];
}
gfx::Device* Batcher2d::getDevice() {
if (_device == nullptr) {
_device = Root::getInstance()->getDevice();
}
return _device;
}
void Batcher2d::updateDescriptorSet() {
}
void Batcher2d::syncRootNodesToNative(ccstd::vector<Node*>&& rootNodes) {
_rootNodeArr = std::move(rootNodes);
}
void Batcher2d::fillBuffersAndMergeBatches() {
for (auto* rootNode : _rootNodeArr) {
walk(rootNode, 1, true, 0);
// CC_LOG_INFO("-------------- flushRendererCache 1 -------------- %d", _rootNodeArr.size());
flushRendererCache(); // LCC_UI_SORTING_GROUP
generateBatch(_currEntity, _currDrawInfo);
}
}
void Batcher2d::walk(Node* node, float parentOpacity, bool cacheEnable, float sortingPriority) { // NOLINT(misc-no-recursion)
if (!node->isActiveInHierarchy()) {
return;
}
sortingPriority = node->isUISortingEnabled() ? node->getUISortingPriority() : sortingPriority;
bool breakWalk = false;
auto* entity = static_cast<RenderEntity*>(node->getUserData());
if (entity) {
if (entity->getColorDirty()) {
float localOpacity = entity->getLocalOpacity();
float localColorAlpha = entity->getColorAlpha();
entity->setOpacity(parentOpacity * localOpacity * localColorAlpha);
entity->setColorDirty(false);
entity->setVBColorDirty(true);
}
// LCC_UI_SORTING_GROUP
if (entity->isEnabled()) {
if(entity->getIsMask() || !cacheEnable){
// CC_LOG_INFO("-------------- flushRendererCache 2 --------------");
flushRendererCache();
uint32_t size = entity->getRenderDrawInfosSize();
for (uint32_t i = 0; i < size; i++) {
auto* drawInfo = entity->getRenderDrawInfoAt(i);
handleDrawInfo(entity, drawInfo, node);
}
entity->setVBColorDirty(false);
}else{
rendererCache.push_back(entity);
entity->setRenderPriority(sortingPriority);
if(sortingPriority != 0){
rendererOrder = true;
}
}
}
if (entity->getRenderEntityType() == RenderEntityType::CROSSED) {
breakWalk = true;
}
}
if (!breakWalk) {
const auto& children = node->getChildren();
float thisOpacity = entity ? entity->getOpacity() : parentOpacity;
for (const auto& child : children) {
// we should find parent opacity recursively upwards if it doesn't have an entity.
walk(child, thisOpacity, cacheEnable, sortingPriority);
}
}
// post assembler
if (_stencilManager->getMaskStackSize() > 0 && entity && entity->isEnabled()) {
handlePostRender(entity);
}
}
void Batcher2d::handlePostRender(RenderEntity* entity) {
bool isMask = entity->getIsMask();
if (isMask) {
// CC_LOG_INFO("-------------- flushRendererCache 3 --------------");
flushRendererCache(); // LCC_UI_SORTING_GROUP
generateBatch(_currEntity, _currDrawInfo);
resetRenderStates();
_stencilManager->exitMask();
}
}
CC_FORCE_INLINE void Batcher2d::handleComponentDraw(RenderEntity* entity, RenderDrawInfo* drawInfo, Node* node) {
ccstd::hash_t dataHash = drawInfo->getDataHash();
if (drawInfo->getIsMeshBuffer()) {
dataHash = 0;
}
// may slow
bool isMask = entity->getIsMask();
if (isMask) {
// Mask subComp
insertMaskBatch(entity);
} else {
entity->setEnumStencilStage(_stencilManager->getStencilStage());
}
auto tempStage = static_cast<StencilStage>(entity->getStencilStage());
if (_currHash != dataHash || dataHash == 0 || _currMaterial != drawInfo->getMaterial() || _currStencilStage != tempStage) {
// CC_LOG_INFO("handleComponentDraw break %u-%u %p-%p %d-%d", _currHash,dataHash, _currMaterial, drawInfo->getMaterial(), _currStencilStage, tempStage);
// Generate a batch if not batching
generateBatch(_currEntity, _currDrawInfo);
if (!drawInfo->getIsMeshBuffer()) {
UIMeshBuffer* buffer = drawInfo->getMeshBuffer();
if (_currMeshBuffer != buffer) {
_currMeshBuffer = buffer;
_indexStart = _currMeshBuffer->getIndexOffset();
}
}
_currHash = dataHash;
_currMaterial = drawInfo->getMaterial();
_currStencilStage = tempStage;
_currLayer = entity->getNode()->getLayer();
_currEntity = entity;
_currDrawInfo = drawInfo;
_currTexture = drawInfo->getTexture();
_currSampler = drawInfo->getSampler();
if (_currSampler == nullptr) {
_currSamplerHash = 0;
} else {
_currSamplerHash = _currSampler->getHash();
}
}
if (!drawInfo->getIsMeshBuffer()) {
if (node->getChangedFlags() || drawInfo->getVertDirty()) {
fillVertexBuffers(entity, drawInfo);
drawInfo->setVertDirty(false);
}
if (entity->getVBColorDirty()) {
fillColors(entity, drawInfo);
}
fillIndexBuffers(drawInfo);
}
if (isMask) {
_stencilManager->enableMask();
}
}
CC_FORCE_INLINE void Batcher2d::handleModelDraw(RenderEntity* entity, RenderDrawInfo* drawInfo) {
generateBatch(_currEntity, _currDrawInfo);
resetRenderStates();
// stencil stage
gfx::DepthStencilState* depthStencil = nullptr;
ccstd::hash_t dssHash = 0;
Material* renderMat = drawInfo->getMaterial();
bool isMask = entity->getIsMask();
if (isMask) {
//Mask Comp
insertMaskBatch(entity);
} else {
entity->setEnumStencilStage(_stencilManager->getStencilStage());
}
StencilStage entityStage = entity->getEnumStencilStage();
depthStencil = _stencilManager->getDepthStencilState(entityStage, renderMat);
dssHash = _stencilManager->getStencilHash(entityStage);
// Model
auto* model = drawInfo->getModel();
if (model == nullptr) return;
auto stamp = CC_CURRENT_ENGINE()->getTotalFrames();
model->updateTransform(stamp);
model->updateUBOs(stamp);
const auto& subModelList = model->getSubModels();
for (const auto& submodel : subModelList) {
auto* curdrawBatch = _drawBatchPool.alloc();
curdrawBatch->setVisFlags(entity->getNode()->getLayer());
curdrawBatch->setModel(model);
curdrawBatch->setInputAssembler(submodel->getInputAssembler());
curdrawBatch->setDescriptorSet(submodel->getDescriptorSet());
curdrawBatch->fillPass(renderMat, depthStencil, dssHash, &(submodel->getPatches()));
_batches.push_back(curdrawBatch);
}
if(isMask) {
_stencilManager->enableMask();
}
}
CC_FORCE_INLINE void Batcher2d::handleMiddlewareDraw(RenderEntity* entity, RenderDrawInfo* drawInfo) {
auto layer = entity->getNode()->getLayer();
Material* material = drawInfo->getMaterial();
auto* texture = drawInfo->getTexture();
auto* sampler = drawInfo->getSampler();
auto* meshBuffer = drawInfo->getMeshBuffer();
// check for merge draw
auto enableBatch = !entity->getUseLocal();
if (enableBatch && _currTexture == texture && _currMeshBuffer == meshBuffer
&& !_currEntity->getUseLocal()
&& material->getHash() == _currMaterial->getHash()
&& drawInfo->getIndexOffset() == _currDrawInfo->getIndexOffset() + _currDrawInfo->getIbCount()
&& layer == _currLayer) {
auto ibCount = _currDrawInfo->getIbCount();
_currDrawInfo->setIbCount(ibCount + drawInfo->getIbCount());
} else {
generateBatch(_currEntity, _currDrawInfo);
_currLayer = layer;
_currMaterial = material;
_currTexture = texture;
_currMeshBuffer = meshBuffer;
_currEntity = entity;
_currDrawInfo = drawInfo;
_currHash = 0;
}
}
CC_FORCE_INLINE void Batcher2d::handleSubNode(RenderEntity* entity, RenderDrawInfo* drawInfo) { // NOLINT
if (drawInfo->getSubNode()) {
walk(drawInfo->getSubNode(), entity->getOpacity(), false, 0);
}
}
CC_FORCE_INLINE void Batcher2d::handleDrawInfo(RenderEntity* entity, RenderDrawInfo* drawInfo, Node* node) { //NOLINT(misc-no-recursion)
CC_ASSERT(entity);
CC_ASSERT(drawInfo);
RenderDrawInfoType drawInfoType = drawInfo->getEnumDrawInfoType();
switch (drawInfoType) {
case RenderDrawInfoType::COMP:
handleComponentDraw(entity, drawInfo, node);
break;
case RenderDrawInfoType::MODEL:
handleModelDraw(entity, drawInfo);
break;
case RenderDrawInfoType::MIDDLEWARE:
handleMiddlewareDraw(entity, drawInfo);
break;
case RenderDrawInfoType::SUB_NODE:
handleSubNode(entity, drawInfo);
break;
default:
break;
}
}
void Batcher2d::generateBatch(RenderEntity* entity, RenderDrawInfo* drawInfo) {
if (drawInfo == nullptr) {
return;
}
if (drawInfo->getEnumDrawInfoType() == RenderDrawInfoType::MIDDLEWARE) {
generateBatchForMiddleware(entity, drawInfo);
return;
}
if (_currMaterial == nullptr) {
return;
}
gfx::InputAssembler* ia = nullptr;
if (drawInfo->getIsMeshBuffer()) {
// Todo MeshBuffer RenderData
ia = drawInfo->requestIA(getDevice());
_meshRenderDrawInfo.emplace_back(drawInfo);
} else {
UIMeshBuffer* currMeshBuffer = drawInfo->getMeshBuffer();
currMeshBuffer->setDirty(true);
ia = currMeshBuffer->requireFreeIA(getDevice());
uint32_t indexCount = currMeshBuffer->getIndexOffset() - _indexStart;
if (ia == nullptr) {
return;
}
ia->setFirstIndex(_indexStart);
ia->setIndexCount(indexCount);
_indexStart = currMeshBuffer->getIndexOffset();
}
_currMeshBuffer = nullptr;
// stencilStage
gfx::DepthStencilState* depthStencil = nullptr;
ccstd::hash_t dssHash = 0;
StencilStage entityStage = entity->getEnumStencilStage();
depthStencil = _stencilManager->getDepthStencilState(entityStage, _currMaterial);
dssHash = _stencilManager->getStencilHash(entityStage);
auto* curdrawBatch = _drawBatchPool.alloc();
curdrawBatch->setVisFlags(_currLayer);
curdrawBatch->setInputAssembler(ia);
curdrawBatch->fillPass(_currMaterial, depthStencil, dssHash);
const auto& pass = curdrawBatch->getPasses().at(0);
if (entity->getUseLocal()) {
drawInfo->updateLocalDescriptorSet(entity->getRenderTransform(), pass->getLocalSetLayout());
curdrawBatch->setDescriptorSet(drawInfo->getLocalDes());
} else {
curdrawBatch->setDescriptorSet(getDescriptorSet(_currTexture, _currSampler, pass->getLocalSetLayout()));
}
_batches.push_back(curdrawBatch);
}
void Batcher2d::generateBatchForMiddleware(RenderEntity* entity, RenderDrawInfo* drawInfo) {
auto layer = entity->getNode()->getLayer();
auto* material = drawInfo->getMaterial();
auto* texture = drawInfo->getTexture();
auto* sampler = drawInfo->getSampler();
auto* meshBuffer = drawInfo->getMeshBuffer();
//set meshbuffer offset
auto indexOffset = drawInfo->getIndexOffset();
auto indexCount = drawInfo->getIbCount();
indexOffset += indexCount;
if (meshBuffer->getIndexOffset() < indexOffset) {
meshBuffer->setIndexOffset(indexOffset);
}
meshBuffer->setDirty(true);
gfx::InputAssembler* ia = meshBuffer->requireFreeIA(getDevice());
ia->setFirstIndex(drawInfo->getIndexOffset());
ia->setIndexCount(drawInfo->getIbCount());
// stencilstage
auto stencilStage = _stencilManager->getStencilStage();
gfx::DepthStencilState* depthStencil = _stencilManager->getDepthStencilState(stencilStage, material);
ccstd::hash_t dssHash = _stencilManager->getStencilHash(stencilStage);
auto* curdrawBatch = _drawBatchPool.alloc();
curdrawBatch->setVisFlags(_currLayer);
curdrawBatch->setInputAssembler(ia);
curdrawBatch->fillPass(material, depthStencil, dssHash);
const auto& pass = curdrawBatch->getPasses().at(0);
if (entity->getUseLocal()) {
drawInfo->updateLocalDescriptorSet(entity->getNode(), pass->getLocalSetLayout());
curdrawBatch->setDescriptorSet(drawInfo->getLocalDes());
} else {
curdrawBatch->setDescriptorSet(getDescriptorSet(texture, sampler, pass->getLocalSetLayout()));
}
_batches.push_back(curdrawBatch);
// make sure next generateBatch return.
resetRenderStates();
_currMeshBuffer = nullptr;
}
void Batcher2d::resetRenderStates() {
_currMaterial = nullptr;
_currTexture = nullptr;
_currSampler = nullptr;
_currSamplerHash = 0;
_currLayer = 0;
_currEntity = nullptr;
_currDrawInfo = nullptr;
}
gfx::DescriptorSet* Batcher2d::getDescriptorSet(gfx::Texture* texture, gfx::Sampler* sampler, gfx::DescriptorSetLayout* dsLayout) {
ccstd::hash_t hash = 2;
size_t textureHash;
if (texture != nullptr) {
textureHash = boost::hash_value(texture);
ccstd::hash_combine(hash, textureHash);
}
if (sampler != nullptr) {
ccstd::hash_combine(hash, sampler->getHash());
}
auto iter = _descriptorSetCache.find(hash);
if (iter != _descriptorSetCache.end()) {
if (texture != nullptr && sampler != nullptr) {
iter->second->bindTexture(static_cast<uint32_t>(pipeline::ModelLocalBindings::SAMPLER_SPRITE), texture);
iter->second->bindSampler(static_cast<uint32_t>(pipeline::ModelLocalBindings::SAMPLER_SPRITE), sampler);
}
iter->second->forceUpdate();
return iter->second;
}
_dsInfo.layout = dsLayout;
auto* ds = getDevice()->createDescriptorSet(_dsInfo);
if (texture != nullptr && sampler != nullptr) {
ds->bindTexture(static_cast<uint32_t>(pipeline::ModelLocalBindings::SAMPLER_SPRITE), texture);
ds->bindSampler(static_cast<uint32_t>(pipeline::ModelLocalBindings::SAMPLER_SPRITE), sampler);
}
ds->update();
_descriptorSetCache.emplace(hash, ds);
return ds;
}
void Batcher2d::releaseDescriptorSetCache(gfx::Texture* texture, gfx::Sampler* sampler) {
ccstd::hash_t hash = 2;
size_t textureHash;
if (texture != nullptr) {
textureHash = boost::hash_value(texture);
ccstd::hash_combine(hash, textureHash);
}
if (sampler != nullptr) {
ccstd::hash_combine(hash, sampler->getHash());
}
auto iter = _descriptorSetCache.find(hash);
if (iter != _descriptorSetCache.end()) {
delete iter->second;
_descriptorSetCache.erase(hash);
}
}
bool Batcher2d::initialize() {
_isInit = true;
return _isInit;
}
void Batcher2d::update() {
fillBuffersAndMergeBatches();
resetRenderStates();
for (const auto& scene : Root::getInstance()->getScenes()) {
for (auto* batch : _batches) {
scene->addBatch(batch);
}
}
}
void Batcher2d::uploadBuffers() {
if (_batches.empty()) {
return;
}
for (auto& meshRenderData : _meshRenderDrawInfo) {
meshRenderData->uploadBuffers();
}
for (auto& map : _meshBuffersMap) {
for (auto& buffer : map.second) {
buffer->uploadBuffers();
buffer->reset();
}
}
updateDescriptorSet();
}
void Batcher2d::reset() {
for (auto& batch : _batches) {
batch->clear();
_drawBatchPool.free(batch);
}
_batches.clear();
for (auto& meshRenderData : _meshRenderDrawInfo) {
meshRenderData->resetMeshIA();
}
_meshRenderDrawInfo.clear();
// meshDataArray
for (auto& map : _meshBuffersMap) {
for (auto& buffer : map.second) {
if (buffer) {
buffer->resetIA();
}
}
}
//meshBuffer cannot clear because it is not transported at every frame.
_currMeshBuffer = nullptr;
_indexStart = 0;
_currHash = 0;
_currLayer = 0;
_currMaterial = nullptr;
_currTexture = nullptr;
_currSampler = nullptr;
// stencilManager
}
void Batcher2d::insertMaskBatch(RenderEntity* entity){
generateBatch(_currEntity, _currDrawInfo);
resetRenderStates();
createClearModel();
_maskClearModel->setNode(entity->getNode());
_maskClearModel->setTransform(entity->getNode());
_stencilManager->pushMask();
auto stage = _stencilManager->clear(entity);
gfx::DepthStencilState* depthStencil = nullptr;
ccstd::hash_t dssHash = 0;
if(_maskClearMtl != nullptr){
depthStencil = _stencilManager->getDepthStencilState(stage, _maskClearMtl);
dssHash = _stencilManager->getStencilHash(stage);
}
// Model
if (_maskClearModel == nullptr) return;
auto stamp = CC_CURRENT_ENGINE()->getTotalFrames();
_maskClearModel->updateTransform(stamp);
_maskClearModel->updateUBOs(stamp);
const auto& subModelList = _maskClearModel->getSubModels();
for (const auto& submodel : subModelList) {
auto* curdrawBatch = _drawBatchPool.alloc();
curdrawBatch->setVisFlags(entity->getNode()->getLayer());
curdrawBatch->setModel(_maskClearModel);
curdrawBatch->setInputAssembler(submodel->getInputAssembler());
curdrawBatch->setDescriptorSet(submodel->getDescriptorSet());
curdrawBatch->fillPass(_maskClearMtl, depthStencil, dssHash, &(submodel->getPatches()));
_batches.push_back(curdrawBatch);
}
_stencilManager->enterLevel(entity);
}
void Batcher2d::createClearModel() {
if (_maskClearModel == nullptr) {
_maskClearMtl = BuiltinResMgr::getInstance()->get<Material>(ccstd::string("default-clear-stencil"));
_maskClearModel = Root::getInstance()->createModel<scene::Model>();
uint32_t stride = 12;// vfmt
auto* vertexBuffer = _device->createBuffer({
gfx::BufferUsageBit::VERTEX | gfx::BufferUsageBit::TRANSFER_DST,
gfx::MemoryUsageBit::DEVICE,
4 * stride,
stride,
});
const float vertices[] = {-1, -1, 0, 1, -1, 0, -1, 1, 0, 1, 1, 0};
vertexBuffer->update(vertices);
auto* indexBuffer = _device->createBuffer({
gfx::BufferUsageBit::INDEX | gfx::BufferUsageBit::TRANSFER_DST,
gfx::MemoryUsageBit::DEVICE,
6 * sizeof(uint16_t),
sizeof(uint16_t),
});
const uint16_t indices[] = {0, 2, 1, 2, 1, 3};
indexBuffer->update(indices);
gfx::BufferList vbReference;
vbReference.emplace_back(vertexBuffer);
_maskModelMesh = ccnew RenderingSubMesh(vbReference, _maskAttributes, _primitiveMode, indexBuffer);
_maskModelMesh->setSubMeshIdx(0);
_maskClearModel->initSubModel(0, _maskModelMesh, _maskClearMtl);
}
}
// LCC_UI_SORTING_GROUP
void Batcher2d::flushRendererCache() {
if(rendererCache.size() > 0){
if(rendererOrder){
std::stable_sort(rendererCache.begin(), rendererCache.end(), [](RenderEntity* a, RenderEntity* b) { return a->getRenderPriority() < b->getRenderPriority(); });
}
// CC_LOG_INFO("flushRendererCache %d", rendererCache.size());
for(ccstd::vector<RenderEntity*>::iterator it = rendererCache.begin(); it != rendererCache.end(); it++)
{
RenderEntity* entity = *it;
// CC_LOG_INFO("%f", entity->getRenderPriority());
uint32_t size = entity->getRenderDrawInfosSize();
for (uint32_t i = 0; i < size; i++) {
auto* drawInfo = entity->getRenderDrawInfoAt(i);
handleDrawInfo(entity, drawInfo, entity->getNode());
}
entity->setVBColorDirty(false);
}
rendererCache.clear();
}
rendererOrder = false;
}
} // namespace cc

View File

@ -0,0 +1,208 @@
/****************************************************************************
Copyright (c) 2019-2021 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.
****************************************************************************/
#pragma once
#include "2d/renderer/RenderDrawInfo.h"
#include "2d/renderer/RenderEntity.h"
#include "2d/renderer/UIMeshBuffer.h"
#include "base/Macros.h"
#include "base/Ptr.h"
#include "base/TypeDef.h"
#include "core/assets/Material.h"
#include "core/memop/Pool.h"
#include "renderer/gfx-base/GFXTexture.h"
#include "renderer/gfx-base/states/GFXSampler.h"
#include "scene/DrawBatch2D.h"
namespace cc {
class Root;
using UIMeshBufferArray = ccstd::vector<UIMeshBuffer*>;
using UIMeshBufferMap = ccstd::unordered_map<uint16_t, UIMeshBufferArray>;
class Batcher2d final {
public:
Batcher2d();
explicit Batcher2d(Root* root);
~Batcher2d();
void syncMeshBuffersToNative(uint16_t accId, ccstd::vector<UIMeshBuffer*>&& buffers);
bool initialize();
void update();
void uploadBuffers();
void reset();
void syncRootNodesToNative(ccstd::vector<Node*>&& rootNodes);
void releaseDescriptorSetCache(gfx::Texture* texture, gfx::Sampler* sampler);
UIMeshBuffer* getMeshBuffer(uint16_t accId, uint16_t bufferId);
gfx::Device* getDevice();
inline ccstd::vector<gfx::Attribute>* getDefaultAttribute() { return &_attributes; }
void updateDescriptorSet();
void fillBuffersAndMergeBatches();
void walk(Node* node, float parentOpacity, bool cacheEnable, float sortingPriority);
void handlePostRender(RenderEntity* entity);
void handleDrawInfo(RenderEntity* entity, RenderDrawInfo* drawInfo, Node* node);
void handleComponentDraw(RenderEntity* entity, RenderDrawInfo* drawInfo, Node* node);
void handleModelDraw(RenderEntity* entity, RenderDrawInfo* drawInfo);
void handleMiddlewareDraw(RenderEntity* entity, RenderDrawInfo* drawInfo);
void handleSubNode(RenderEntity* entity, RenderDrawInfo* drawInfo);
void generateBatch(RenderEntity* entity, RenderDrawInfo* drawInfo);
void generateBatchForMiddleware(RenderEntity* entity, RenderDrawInfo* drawInfo);
void resetRenderStates();
private:
bool _isInit = false;
inline void fillIndexBuffers(RenderDrawInfo* drawInfo) { // NOLINT(readability-convert-member-functions-to-static)
uint16_t* ib = drawInfo->getIDataBuffer();
UIMeshBuffer* buffer = drawInfo->getMeshBuffer();
uint32_t indexOffset = buffer->getIndexOffset();
uint16_t* indexb = drawInfo->getIbBuffer();
uint32_t indexCount = drawInfo->getIbCount();
memcpy(&ib[indexOffset], indexb, indexCount * sizeof(uint16_t));
indexOffset += indexCount;
buffer->setIndexOffset(indexOffset);
}
inline void fillVertexBuffers(RenderEntity* entity, RenderDrawInfo* drawInfo) { // NOLINT(readability-convert-member-functions-to-static)
Node* node = entity->getNode();
const Mat4& matrix = node->getWorldMatrix();
uint8_t stride = drawInfo->getStride();
uint32_t size = drawInfo->getVbCount() * stride;
float* vbBuffer = drawInfo->getVbBuffer();
for (int i = 0; i < size; i += stride) {
Render2dLayout* curLayout = drawInfo->getRender2dLayout(i);
// make sure that the layout of Vec3 is three consecutive floats
static_assert(sizeof(Vec3) == 3 * sizeof(float));
// cast to reduce value copy instructions
reinterpret_cast<Vec3*>(vbBuffer + i)->transformMat4(curLayout->position, matrix);
}
}
inline void setIndexRange(RenderDrawInfo* drawInfo) { // NOLINT(readability-convert-member-functions-to-static)
UIMeshBuffer* buffer = drawInfo->getMeshBuffer();
uint32_t indexOffset = drawInfo->getIndexOffset();
uint32_t indexCount = drawInfo->getIbCount();
indexOffset += indexCount;
if (buffer->getIndexOffset() < indexOffset) {
buffer->setIndexOffset(indexOffset);
}
}
inline void fillColors(RenderEntity* entity, RenderDrawInfo* drawInfo) { // NOLINT(readability-convert-member-functions-to-static)
Color temp = entity->getColor();
uint8_t stride = drawInfo->getStride();
uint32_t size = drawInfo->getVbCount() * stride;
float* vbBuffer = drawInfo->getVbBuffer();
uint32_t offset = 0;
for (int i = 0; i < size; i += stride) {
offset = i + 5;
vbBuffer[offset++] = static_cast<float>(temp.r) / 255.0F;
vbBuffer[offset++] = static_cast<float>(temp.g) / 255.0F;
vbBuffer[offset++] = static_cast<float>(temp.b) / 255.0F;
vbBuffer[offset++] = entity->getOpacity();
}
}
void insertMaskBatch(RenderEntity* entity);
void createClearModel ();
// LCC_UI_SORTING_GROUP
ccstd::vector<RenderEntity*> rendererCache;
bool rendererOrder;
void flushRendererCache();
gfx::DescriptorSet* getDescriptorSet(gfx::Texture* texture, gfx::Sampler* sampler, gfx::DescriptorSetLayout* dsLayout);
StencilManager* _stencilManager{nullptr};
// weak reference
Root* _root{nullptr};
// weak reference
ccstd::vector<Node*> _rootNodeArr;
// manage memory manually
ccstd::vector<scene::DrawBatch2D*> _batches;
memop::Pool<scene::DrawBatch2D> _drawBatchPool;
// weak reference
gfx::Device* _device{nullptr}; // use getDevice()
// weak reference
RenderEntity* _currEntity{nullptr};
// weak reference
RenderDrawInfo* _currDrawInfo{nullptr};
// weak reference
UIMeshBuffer* _currMeshBuffer{nullptr};
uint32_t _indexStart{0};
ccstd::hash_t _currHash{0};
uint32_t _currLayer{0};
StencilStage _currStencilStage{StencilStage::DISABLED};
// weak reference
Material* _currMaterial{nullptr};
// weak reference
gfx::Texture* _currTexture{nullptr};
// weak reference
gfx::Sampler* _currSampler{nullptr};
ccstd::hash_t _currSamplerHash{0};
// weak reference
ccstd::vector<RenderDrawInfo*> _meshRenderDrawInfo;
// manage memory manually
ccstd::unordered_map<ccstd::hash_t, gfx::DescriptorSet*> _descriptorSetCache;
gfx::DescriptorSetInfo _dsInfo;
UIMeshBufferMap _meshBuffersMap;
// DefaultAttribute
ccstd::vector<gfx::Attribute> _attributes{
gfx::Attribute{gfx::ATTR_NAME_POSITION, gfx::Format::RGB32F},
gfx::Attribute{gfx::ATTR_NAME_TEX_COORD, gfx::Format::RG32F},
gfx::Attribute{gfx::ATTR_NAME_COLOR, gfx::Format::RGBA32F},
};
// Mask use
IntrusivePtr<scene::Model> _maskClearModel;
IntrusivePtr<Material> _maskClearMtl;
IntrusivePtr<RenderingSubMesh> _maskModelMesh;
ccstd::vector<gfx::Attribute> _maskAttributes{
gfx::Attribute{gfx::ATTR_NAME_POSITION, gfx::Format::RGB32F},
};
gfx::PrimitiveMode _primitiveMode{gfx::PrimitiveMode::TRIANGLE_LIST};
CC_DISALLOW_COPY_MOVE_ASSIGN(Batcher2d);
};
} // namespace cc

View File

@ -0,0 +1,116 @@
/****************************************************************************
Copyright (c) 2019-2021 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 "2d/renderer/RenderEntity.h"
#include "2d/renderer/Batcher2d.h"
#include "bindings/utils/BindingUtils.h"
namespace cc {
RenderEntity::RenderEntity(RenderEntityType type) : _renderEntityType(type) {
if (type == RenderEntityType::STATIC) {
ccnew_placement(&_staticDrawInfos) std::array<RenderDrawInfo, RenderEntity::STATIC_DRAW_INFO_CAPACITY>();
} else {
ccnew_placement(&_dynamicDrawInfos) ccstd::vector<RenderDrawInfo*>();
}
_entitySharedBufferActor.initialize(&_entityAttrLayout, sizeof(EntityAttrLayout));
}
RenderEntity::~RenderEntity() {
if (_renderEntityType == RenderEntityType::STATIC) {
_staticDrawInfos.~array();
} else {
_dynamicDrawInfos.~vector();
}
};
void RenderEntity::addDynamicRenderDrawInfo(RenderDrawInfo* drawInfo) {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
_dynamicDrawInfos.push_back(drawInfo);
}
void RenderEntity::setDynamicRenderDrawInfo(RenderDrawInfo* drawInfo, uint32_t index) {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
if (index < _dynamicDrawInfos.size()) {
_dynamicDrawInfos[index] = drawInfo;
}
}
void RenderEntity::removeDynamicRenderDrawInfo() {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
if (_dynamicDrawInfos.empty()) return;
_dynamicDrawInfos.pop_back(); // warning: memory leaking & crash
}
void RenderEntity::clearDynamicRenderDrawInfos() {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
_dynamicDrawInfos.clear();
}
void RenderEntity::clearStaticRenderDrawInfos() {
CC_ASSERT(_renderEntityType == RenderEntityType::STATIC);
for (uint32_t i = 0; i < _staticDrawInfoSize; i++) {
RenderDrawInfo& drawInfo = _staticDrawInfos[i];
drawInfo.resetDrawInfo();
}
_staticDrawInfoSize = 0;
}
void RenderEntity::setNode(Node* node) {
if (_node) {
_node->setUserData(nullptr);
}
_node = node;
if (_node) {
_node->setUserData(this);
}
}
void RenderEntity::setRenderTransform(Node* renderTransform) {
_renderTransform = renderTransform;
}
RenderDrawInfo* RenderEntity::getDynamicRenderDrawInfo(uint32_t index) {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
if (index >= _dynamicDrawInfos.size()) {
return nullptr;
}
return _dynamicDrawInfos[index];
}
ccstd::vector<RenderDrawInfo*>& RenderEntity::getDynamicRenderDrawInfos() {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
return _dynamicDrawInfos;
}
void RenderEntity::setStaticDrawInfoSize(uint32_t size) {
CC_ASSERT(_renderEntityType == RenderEntityType::STATIC && size <= RenderEntity::STATIC_DRAW_INFO_CAPACITY);
_staticDrawInfoSize = size;
}
RenderDrawInfo* RenderEntity::getStaticRenderDrawInfo(uint32_t index) {
CC_ASSERT(_renderEntityType == RenderEntityType::STATIC && index < _staticDrawInfoSize);
return &(_staticDrawInfos[index]);
}
std::array<RenderDrawInfo, RenderEntity::STATIC_DRAW_INFO_CAPACITY>& RenderEntity::getStaticRenderDrawInfos() {
CC_ASSERT(_renderEntityType == RenderEntityType::STATIC);
return _staticDrawInfos;
}
} // namespace cc

View File

@ -0,0 +1,164 @@
/****************************************************************************
Copyright (c) 2019-2021 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.
****************************************************************************/
#pragma once
#include <array>
#include "2d/renderer/RenderDrawInfo.h"
#include "2d/renderer/StencilManager.h"
#include "base/Macros.h"
#include "base/TypeDef.h"
#include "bindings/utils/BindingUtils.h"
#include "core/ArrayBuffer.h"
#include "core/scene-graph/Node.h"
namespace cc {
class Batcher2d;
enum class RenderEntityType : uint8_t {
STATIC,
DYNAMIC,
CROSSED,
};
enum class MaskMode : uint8_t {
NONE,
MASK,
MASK_INVERTED,
MASK_NODE,
MASK_NODE_INVERTED
};
struct EntityAttrLayout {
float localOpacity{1.0F};
uint8_t colorR{255};
uint8_t colorG{255};
uint8_t colorB{255};
uint8_t colorA{255};
uint8_t maskMode{0};
uint8_t colorDirtyBit{1};
uint8_t enabledIndex{0};
uint8_t useLocal{0};
};
class RenderEntity final : public Node::UserData {
public:
static constexpr uint32_t STATIC_DRAW_INFO_CAPACITY = 4;
explicit RenderEntity(RenderEntityType type);
~RenderEntity() override;
void addDynamicRenderDrawInfo(RenderDrawInfo* drawInfo);
void setDynamicRenderDrawInfo(RenderDrawInfo* drawInfo, uint32_t index);
void removeDynamicRenderDrawInfo();
void clearDynamicRenderDrawInfos();
void clearStaticRenderDrawInfos();
inline bool getIsMask() const {
return static_cast<MaskMode>(_entityAttrLayout.maskMode) == MaskMode::MASK || static_cast<MaskMode>(_entityAttrLayout.maskMode) == MaskMode::MASK_INVERTED;
}
inline bool getIsSubMask() const {
return static_cast<MaskMode>(_entityAttrLayout.maskMode) == MaskMode::MASK_NODE || static_cast<MaskMode>(_entityAttrLayout.maskMode) == MaskMode::MASK_NODE_INVERTED;
}
inline bool getIsMaskInverted() const {
return static_cast<MaskMode>(_entityAttrLayout.maskMode) == MaskMode::MASK_INVERTED || static_cast<MaskMode>(_entityAttrLayout.maskMode) == MaskMode::MASK_NODE_INVERTED;
}
inline bool getUseLocal() const { return _entityAttrLayout.useLocal; }
inline void setUseLocal(bool useLocal) {
_entityAttrLayout.useLocal = useLocal;
}
inline Node* getNode() const { return _node; }
void setNode(Node* node);
inline Node* getRenderTransform() const { return _renderTransform; }
void setRenderTransform(Node* renderTransform);
inline uint32_t getStencilStage() const { return static_cast<uint32_t>(_stencilStage); }
inline void setStencilStage(uint32_t stage) {
_stencilStage = static_cast<StencilStage>(stage);
}
inline StencilStage getEnumStencilStage() const { return _stencilStage; }
inline void setEnumStencilStage(StencilStage stage) {
_stencilStage = stage;
}
inline RenderEntityType getRenderEntityType() const { return _renderEntityType; };
inline uint32_t getStaticDrawInfoSize() const { return _staticDrawInfoSize; };
void setStaticDrawInfoSize(uint32_t size);
RenderDrawInfo* getStaticRenderDrawInfo(uint32_t index);
std::array<RenderDrawInfo, RenderEntity::STATIC_DRAW_INFO_CAPACITY>& getStaticRenderDrawInfos();
RenderDrawInfo* getDynamicRenderDrawInfo(uint32_t index);
ccstd::vector<RenderDrawInfo*>& getDynamicRenderDrawInfos();
inline se::Object* getEntitySharedBufferForJS() const { return _entitySharedBufferActor.getSharedArrayBufferObject(); }
inline bool getColorDirty() const { return _entityAttrLayout.colorDirtyBit != 0; }
inline void setColorDirty(bool dirty) { _entityAttrLayout.colorDirtyBit = dirty ? 1 : 0; }
inline bool getVBColorDirty() const { return _vbColorDirty; }
inline void setVBColorDirty(bool vbColorDirty) { _vbColorDirty = vbColorDirty; }
inline Color getColor() const { return Color(_entityAttrLayout.colorR, _entityAttrLayout.colorG, _entityAttrLayout.colorB, _entityAttrLayout.colorA); }
inline float getColorAlpha() const { return static_cast<float>(_entityAttrLayout.colorA) / 255.F; }
inline float getLocalOpacity() const { return _entityAttrLayout.localOpacity; }
inline float getOpacity() const { return _opacity; }
inline void setOpacity(float opacity) { _opacity = opacity; }
inline bool isEnabled() const { return _entityAttrLayout.enabledIndex != 0; }
inline uint32_t getRenderDrawInfosSize() const {
return _renderEntityType == RenderEntityType::STATIC ? _staticDrawInfoSize : static_cast<uint32_t>(_dynamicDrawInfos.size());
}
inline RenderDrawInfo* getRenderDrawInfoAt(uint32_t index) {
return _renderEntityType == RenderEntityType::STATIC ? &(_staticDrawInfos[index]) : _dynamicDrawInfos[index];
}
inline float getRenderPriority() const { return _renderPriority; }
inline void setRenderPriority(float value) { _renderPriority = value; }
private:
CC_DISALLOW_COPY_MOVE_ASSIGN(RenderEntity);
// weak reference
Node* _node{nullptr};
// weak reference
Node* _renderTransform{nullptr};
EntityAttrLayout _entityAttrLayout;
float _opacity{1.0F};
bindings::NativeMemorySharedToScriptActor _entitySharedBufferActor;
union {
std::array<RenderDrawInfo, RenderEntity::STATIC_DRAW_INFO_CAPACITY> _staticDrawInfos;
ccstd::vector<RenderDrawInfo*> _dynamicDrawInfos;
};
StencilStage _stencilStage{StencilStage::DISABLED};
RenderEntityType _renderEntityType{RenderEntityType::STATIC};
uint8_t _staticDrawInfoSize{0};
bool _vbColorDirty{true};
float _renderPriority{0.0F};
};
} // namespace cc

View File

@ -0,0 +1,984 @@
/****************************************************************************
Copyright (c) 2021 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 "core/scene-graph/Node.h"
#include "base/StringUtil.h"
#include "core/data/Object.h"
#include "core/memop/CachedArray.h"
#include "core/platform/Debug.h"
#include "core/scene-graph/NodeEnum.h"
#include "core/scene-graph/Scene.h"
#include "core/utils/IDGenerator.h"
#include "math/Utils.h"
namespace cc {
// static variables
uint32_t Node::clearFrame{0};
uint32_t Node::clearRound{1000};
const uint32_t Node::TRANSFORM_ON{1 << 0};
uint32_t Node::globalFlagChangeVersion{0};
namespace {
const ccstd::string EMPTY_NODE_NAME;
IDGenerator idGenerator("Node");
ccstd::vector<Node *> dirtyNodes;
CC_FORCE_INLINE void setDirtyNode(const index_t idx, Node *node) {
if (idx >= dirtyNodes.size()) {
if (idx >= dirtyNodes.capacity()) {
size_t minCapacity = std::max((idx + 1) * 2, 32);
if (minCapacity > dirtyNodes.capacity()) {
dirtyNodes.reserve(minCapacity); // Make a pre-allocated size for dirtyNode vector for better grow performance.
}
}
dirtyNodes.resize(idx + 1, nullptr);
}
dirtyNodes[idx] = node;
}
CC_FORCE_INLINE Node *getDirtyNode(const index_t idx) {
if (idx < 0 || idx >= dirtyNodes.size()) {
return nullptr;
}
return dirtyNodes[idx];
}
} // namespace
Node::Node() : Node(EMPTY_NODE_NAME) {
}
Node::Node(const ccstd::string &name) {
#define NODE_SHARED_MEMORY_BYTE_LENGTH (24)
static_assert(offsetof(Node, _uiSortingEnabled) + sizeof(_uiSortingEnabled) - offsetof(Node, _eventMask) == NODE_SHARED_MEMORY_BYTE_LENGTH, "Wrong shared memory size");
_sharedMemoryActor.initialize(&_eventMask, NODE_SHARED_MEMORY_BYTE_LENGTH);
#undef NODE_SHARED_MEMORY_BYTE_LENGTH
_id = idGenerator.getNewId();
if (name.empty()) {
_name.append("New Node");
} else {
_name = name;
}
_eventProcessor = ccnew NodeEventProcessor(this);
}
Node::~Node() {
CC_SAFE_DELETE(_eventProcessor);
if (!_children.empty()) {
// Reset children's _parent to nullptr to avoid dangerous pointer
for (const auto &child : _children) {
child->_parent = nullptr;
}
}
}
void Node::onBatchCreated(bool dontChildPrefab) {
// onBatchCreated was implemented in TS, so code should never go here.
CC_ASSERT(false);
emit(EventTypesToJS::NODE_ON_BATCH_CREATED, dontChildPrefab);
}
Node *Node::instantiate(Node *cloned, bool isSyncedNode) {
if (!cloned) {
CC_ASSERT(false);
// TODO(): cloned = legacyCC.instantiate._clone(this, this);
return nullptr;
}
// TODO():
// const newPrefabInfo = cloned._prefab;
// if (EDITOR && newPrefabInfo) {
// if (cloned == = newPrefabInfo.root) {
// // newPrefabInfo.fileId = '';
// } else {
// // var PrefabUtils = Editor.require('scene://utils/prefab');
// // PrefabUtils.unlinkPrefab(cloned);
// }
//}
// if (EDITOR && legacyCC.GAME_VIEW) {
// const syncing = newPrefabInfo&& cloned == = newPrefabInfo.root && newPrefabInfo.sync;
// if (!syncing) {
// cloned._name += ' (Clone)';
// }
//}
cloned->_parent = nullptr;
cloned->onBatchCreated(isSyncedNode);
return cloned;
}
void Node::onHierarchyChangedBase(Node *oldParent) { // NOLINT(misc-unused-parameters)
Node *newParent = _parent;
auto *scene = dynamic_cast<Scene *>(newParent);
if (isPersistNode() && scene == nullptr) {
emit(EventTypesToJS::NODE_REMOVE_PERSIST_ROOT_NODE);
#if CC_EDITOR
debug::warnID(1623);
#endif
}
#if CC_EDITOR
auto *curScene = getScene();
const bool inCurrentSceneBefore = oldParent && oldParent->isChildOf(curScene);
const bool inCurrentSceneNow = newParent && newParent->isChildOf(curScene);
if (!inCurrentSceneBefore && inCurrentSceneNow) {
// attached
this->notifyEditorAttached(true);
} else if (inCurrentSceneBefore && !inCurrentSceneNow) {
// detached
this->notifyEditorAttached(false);
}
// conflict detection
// _Scene.DetectConflict.afterAddChild(this);
#endif
bool shouldActiveNow = isActive() && !!(newParent && newParent->isActiveInHierarchy());
if (isActiveInHierarchy() != shouldActiveNow) {
// Director::getInstance()->getNodeActivator()->activateNode(this, shouldActiveNow); // TODO(xwx): use TS temporarily
emit(EventTypesToJS::NODE_ACTIVE_NODE, shouldActiveNow);
}
}
void Node::off(const CallbacksInvoker::KeyType &type, bool useCapture) {
_eventProcessor->offAll(type, useCapture);
bool hasListeners = _eventProcessor->hasEventListener(type);
if (!hasListeners) {
if (type == NodeEventType::TRANSFORM_CHANGED) {
_eventMask &= ~TRANSFORM_ON;
}
}
}
void Node::off(const CallbacksInvoker::KeyType &type, const CallbackID &cbID, bool useCapture) {
_eventProcessor->off(type, cbID, useCapture);
bool hasListeners = _eventProcessor->hasEventListener(type);
if (!hasListeners) {
if (type == NodeEventType::TRANSFORM_CHANGED) {
_eventMask &= ~TRANSFORM_ON;
}
}
}
void Node::off(const CallbacksInvoker::KeyType &type, void *target, bool useCapture) {
_eventProcessor->off(type, target, useCapture);
bool hasListeners = _eventProcessor->hasEventListener(type);
if (!hasListeners) {
if (type == NodeEventType::TRANSFORM_CHANGED) {
_eventMask &= ~TRANSFORM_ON;
}
}
}
//void Node::dispatchEvent(event::Event *eve) {
// _eventProcessor->dispatchEvent(eve);
//}
bool Node::hasEventListener(const CallbacksInvoker::KeyType &type) const {
return _eventProcessor->hasEventListener(type);
}
bool Node::hasEventListener(const CallbacksInvoker::KeyType &type, const CallbackID &cbID) const {
return _eventProcessor->hasEventListener(type, cbID);
}
bool Node::hasEventListener(const CallbacksInvoker::KeyType &type, void *target) const {
return _eventProcessor->hasEventListener(type, target);
}
bool Node::hasEventListener(const CallbacksInvoker::KeyType &type, void *target, const CallbackID &cbID) const {
return _eventProcessor->hasEventListener(type, target, cbID);
}
void Node::targetOff(const CallbacksInvoker::KeyType &type) {
_eventProcessor->targetOff(type);
if ((_eventMask & TRANSFORM_ON) && !_eventProcessor->hasEventListener(NodeEventType::TRANSFORM_CHANGED)) {
_eventMask &= ~TRANSFORM_ON;
}
}
void Node::setActive(bool isActive) {
uint8_t isActiveU8 = isActive ? 1 : 0;
if (_active != isActiveU8) {
_active = isActiveU8;
Node *parent = _parent;
if (parent) {
bool couldActiveInScene = parent->isActiveInHierarchy();
if (couldActiveInScene) {
// Director::getInstance()->getNodeActivator()->activateNode(this, isActive); // TODO(xwx): use TS temporarily
emit(EventTypesToJS::NODE_ACTIVE_NODE, isActive);
}
}
}
}
void Node::setParent(Node *parent, bool isKeepWorld /* = false */) {
if (isKeepWorld) {
updateWorldTransform();
}
if (_parent == parent) {
return;
}
Node *oldParent = _parent;
Node *newParent = parent;
#if CC_DEBUG > 0
if (oldParent && (oldParent->_objFlags & Flags::DEACTIVATING) == Flags::DEACTIVATING) {
debug::errorID(3821);
}
#endif
_parent = newParent;
_siblingIndex = 0;
onSetParent(oldParent, isKeepWorld);
emit(NodeEventType::PARENT_CHANGED, oldParent);
if (oldParent) {
if (!(oldParent->_objFlags & Flags::DESTROYING)) {
index_t removeAt = getIdxOfChild(oldParent->_children, this);
// TODO(): DEV
/*if (DEV && removeAt < 0) {
errorID(1633);
return;
}*/
if (removeAt < 0) {
return;
}
oldParent->_children.erase(oldParent->_children.begin() + removeAt);
oldParent->updateSiblingIndex();
oldParent->emit(NodeEventType::CHILD_REMOVED, this);
}
}
if (newParent) {
#if CC_DEBUG > 0
if ((newParent->_objFlags & Flags::DEACTIVATING) == Flags::DEACTIVATING) {
debug::errorID(3821);
}
#endif
newParent->_children.emplace_back(this);
_siblingIndex = static_cast<index_t>(newParent->_children.size() - 1);
newParent->emit(NodeEventType::CHILD_ADDED, this);
}
onHierarchyChanged(oldParent);
}
void Node::walk(const WalkCallback &preFunc) {
walk(preFunc, nullptr);
}
void Node::walk(const WalkCallback &preFunc, const WalkCallback &postFunc) { //NOLINT(misc-no-recursion)
if (preFunc) {
preFunc(this);
}
for (const auto &child : _children) {
if (child) {
child->walk(preFunc, postFunc);
}
}
if (postFunc) {
postFunc(this);
}
}
//Component *Node::addComponent(Component *comp) {
// comp->_node = this; // cjh TODO: shared_ptr
// _components.emplace_back(comp);
//
// if (isActiveInHierarchy()) {
// NodeActivator::activateComp(comp);
// }
//
// return comp;
//}
//
//void Node::removeComponent(Component *comp) {
// auto iteComp = std::find(_components.begin(), _components.end(), comp);
// if (iteComp != _components.end()) {
// _components.erase(iteComp);
// }
//}
bool Node::onPreDestroyBase() {
Flags destroyingFlag = Flags::DESTROYING;
_objFlags |= destroyingFlag;
bool destroyByParent = (!!_parent) && (!!(_parent->_objFlags & destroyingFlag));
#if CC_EDITOR
if (!destroyByParent) {
this->notifyEditorAttached(false);
}
#endif
if (isPersistNode()) {
emit(EventTypesToJS::NODE_REMOVE_PERSIST_ROOT_NODE);
}
if (!destroyByParent) {
if (_parent) {
emit(NodeEventType::PARENT_CHANGED, this);
index_t childIdx = getIdxOfChild(_parent->_children, this);
if (childIdx != -1) {
_parent->_children.erase(_parent->_children.begin() + childIdx);
}
_siblingIndex = 0;
_parent->updateSiblingIndex();
_parent->emit(NodeEventType::CHILD_REMOVED, this);
}
}
//NOTE: The following code is not needed now since we override Node._onPreDestroy in node.jsb.ts
// and the logic will be done in TS.
// emit(NodeEventType::NODE_DESTROYED, this);
// for (const auto &child : _children) {
// child->destroyImmediate();
// }
//
// emit(EventTypesToJS::NODE_DESTROY_COMPONENTS);
_eventProcessor->destroy();
return destroyByParent;
}
Node *Node::getChildByName(const ccstd::string &name) const {
if (name.empty()) {
CC_LOG_INFO("Invalid name");
return nullptr;
}
for (const auto &child : _children) {
if (child->_name == name) {
return child;
}
}
return nullptr;
}
void Node::setScene(Node *node) {
node->updateScene();
}
void Node::updateScene() {
if (_parent == nullptr) {
return;
}
_scene = _parent->_scene;
emit(EventTypesToJS::NODE_SCENE_UPDATED, _scene);
}
/* static */
index_t Node::getIdxOfChild(const ccstd::vector<IntrusivePtr<Node>> &child, Node *target) {
auto iteChild = std::find(child.begin(), child.end(), target);
if (iteChild != child.end()) {
return static_cast<index_t>(iteChild - child.begin());
}
return CC_INVALID_INDEX;
}
Node *Node::getChildByUuid(const ccstd::string &uuid) const {
if (uuid.empty()) {
CC_LOG_INFO("Invalid uuid");
return nullptr;
}
for (const auto &child : _children) {
if (child->_id == uuid) {
return child;
}
}
return nullptr;
}
bool Node::isChildOf(Node *parent) const {
const Node *child = this;
do {
if (child == parent) {
return true;
}
child = child->_parent;
} while (child);
return false;
}
void Node::removeAllChildren() {
for (auto i = static_cast<index_t>(_children.size() - 1); i >= 0; --i) {
if (_children[i]) {
_children[i]->setParent(nullptr);
}
}
_children.clear();
}
void Node::setSiblingIndex(index_t index) {
if (!_parent) {
return;
}
if (!!(_parent->_objFlags & Flags::DEACTIVATING)) {
debug::errorID(3821);
return;
}
ccstd::vector<IntrusivePtr<Node>> &siblings = _parent->_children;
index = index != -1 ? index : static_cast<index_t>(siblings.size()) - 1;
index_t oldIdx = getIdxOfChild(siblings, this);
if (index != oldIdx) {
if (oldIdx != CC_INVALID_INDEX) {
siblings.erase(siblings.begin() + oldIdx);
}
if (index < siblings.size()) {
siblings.insert(siblings.begin() + index, this);
} else {
siblings.emplace_back(this);
}
_parent->updateSiblingIndex();
if (onSiblingIndexChanged != nullptr) {
onSiblingIndexChanged(index);
}
}
}
Node *Node::getChildByPath(const ccstd::string &path) const {
size_t end = 0;
ccstd::vector<ccstd::string> segments = StringUtil::split(path, "/");
auto *lastNode = const_cast<Node *>(this);
for (const ccstd::string &segment : segments) {
if (segment.empty()) {
continue;
}
Node *next{nullptr};
if (lastNode) {
for (const auto &child : lastNode->_children) {
if (child->_name == segment) {
next = child;
break;
}
}
lastNode = next;
} else {
break;
}
}
return lastNode;
}
//
void Node::setPositionInternal(float x, float y, float z, bool calledFromJS) {
_localPosition.set(x, y, z);
invalidateChildren(TransformBit::POSITION);
if (_eventMask & TRANSFORM_ON) {
emit(NodeEventType::TRANSFORM_CHANGED, TransformBit::POSITION);
}
if (!calledFromJS) {
notifyLocalPositionUpdated();
}
}
void Node::setRotationInternal(float x, float y, float z, float w, bool calledFromJS) {
_localRotation.set(x, y, z, w);
_eulerDirty = true;
invalidateChildren(TransformBit::ROTATION);
if (_eventMask & TRANSFORM_ON) {
emit(NodeEventType::TRANSFORM_CHANGED, TransformBit::ROTATION);
}
if (!calledFromJS) {
notifyLocalRotationUpdated();
}
}
void Node::setRotationFromEuler(float x, float y, float z) {
_euler.set(x, y, z);
Quaternion::fromEuler(x, y, z, &_localRotation);
_eulerDirty = false;
invalidateChildren(TransformBit::ROTATION);
if (_eventMask & TRANSFORM_ON) {
emit(NodeEventType::TRANSFORM_CHANGED, TransformBit::ROTATION);
}
notifyLocalRotationUpdated();
}
void Node::setScaleInternal(float x, float y, float z, bool calledFromJS) {
_localScale.set(x, y, z);
invalidateChildren(TransformBit::SCALE);
if (_eventMask & TRANSFORM_ON) {
emit(NodeEventType::TRANSFORM_CHANGED, TransformBit::SCALE);
}
if (!calledFromJS) {
notifyLocalScaleUpdated();
}
}
void Node::updateWorldTransform() { //NOLINT(misc-no-recursion)
if (!getDirtyFlag()) {
return;
}
index_t i = 0;
Node *curr = this;
Mat3 mat3;
Mat3 m43;
Quaternion quat;
while (curr && curr->getDirtyFlag()) {
setDirtyNode(i++, curr);
curr = curr->getParent();
}
Node *child{nullptr};
uint32_t dirtyBits = 0;
while (i) {
child = getDirtyNode(--i);
if (!child) {
continue;
}
dirtyBits |= child->getDirtyFlag();
auto *currChild = child;
if (curr) {
if (dirtyBits & static_cast<uint32_t>(TransformBit::POSITION)) {
currChild->_worldPosition.transformMat4(currChild->_localPosition, curr->_worldMatrix);
currChild->_worldMatrix.m[12] = currChild->_worldPosition.x;
currChild->_worldMatrix.m[13] = currChild->_worldPosition.y;
currChild->_worldMatrix.m[14] = currChild->_worldPosition.z;
}
if (dirtyBits & static_cast<uint32_t>(TransformBit::RS)) {
Mat4::fromRTS(currChild->_localRotation, currChild->_localPosition, currChild->_localScale, &currChild->_worldMatrix);
Mat4::multiply(curr->_worldMatrix, currChild->_worldMatrix, &currChild->_worldMatrix);
if (dirtyBits & static_cast<uint32_t>(TransformBit::ROTATION)) {
Quaternion::multiply(curr->_worldRotation, currChild->_localRotation, &currChild->_worldRotation);
}
quat = currChild->_worldRotation;
quat.conjugate();
Mat3::fromQuat(quat, &mat3);
Mat3::fromMat4(currChild->_worldMatrix, &m43);
Mat3::multiply(mat3, m43, &mat3);
currChild->_worldScale.set(mat3.m[0], mat3.m[4], mat3.m[8]);
}
} else if (child) {
if (dirtyBits & static_cast<uint32_t>(TransformBit::POSITION)) {
currChild->_worldPosition.set(currChild->_localPosition);
currChild->_worldMatrix.m[12] = currChild->_worldPosition.x;
currChild->_worldMatrix.m[13] = currChild->_worldPosition.y;
currChild->_worldMatrix.m[14] = currChild->_worldPosition.z;
}
if (dirtyBits & static_cast<uint32_t>(TransformBit::RS)) {
if (dirtyBits & static_cast<uint32_t>(TransformBit::ROTATION)) {
currChild->_worldRotation.set(currChild->_localRotation);
}
if (dirtyBits & static_cast<uint32_t>(TransformBit::SCALE)) {
currChild->_worldScale.set(currChild->_localScale);
Mat4::fromRTS(currChild->_worldRotation, currChild->_worldPosition, currChild->_worldScale, &currChild->_worldMatrix);
}
}
}
child->setDirtyFlag(static_cast<uint32_t>(TransformBit::NONE));
curr = child;
}
}
const Mat4 &Node::getWorldMatrix() const { //NOLINT(misc-no-recursion)
const_cast<Node *>(this)->updateWorldTransform();
return _worldMatrix;
}
Mat4 Node::getWorldRS() {
updateWorldTransform();
Mat4 target{_worldMatrix};
target.m[12] = target.m[13] = target.m[14] = 0;
return target;
}
Mat4 Node::getWorldRT() {
updateWorldTransform();
Mat4 target;
Mat4::fromRT(_worldRotation, _worldPosition, &target);
return target;
}
void Node::invalidateChildren(TransformBit dirtyBit) {
auto curDirtyBit{static_cast<uint32_t>(dirtyBit)};
const uint32_t childDirtyBit{curDirtyBit | static_cast<uint32_t>(TransformBit::POSITION)};
setDirtyNode(0, this);
int i{0};
while (i >= 0) {
Node *cur = getDirtyNode(i--);
if (cur == nullptr) {
continue;
}
const uint32_t hasChangedFlags = cur->getChangedFlags();
if (cur->isValid() && (cur->getDirtyFlag() & hasChangedFlags & curDirtyBit) != curDirtyBit) {
cur->setDirtyFlag(cur->getDirtyFlag() | curDirtyBit);
cur->setChangedFlags(hasChangedFlags | curDirtyBit);
for (Node *curChild : cur->getChildren()) {
setDirtyNode(++i, curChild);
}
}
curDirtyBit = childDirtyBit;
}
}
void Node::setWorldPosition(float x, float y, float z) {
_worldPosition.set(x, y, z);
if (_parent) {
_parent->updateWorldTransform();
Mat4 invertWMat{_parent->_worldMatrix};
invertWMat.inverse();
_localPosition.transformMat4(_worldPosition, invertWMat);
} else {
_localPosition.set(_worldPosition);
}
notifyLocalPositionUpdated();
invalidateChildren(TransformBit::POSITION);
if (_eventMask & TRANSFORM_ON) {
emit(NodeEventType::TRANSFORM_CHANGED, TransformBit::POSITION);
}
}
const Vec3 &Node::getWorldPosition() const {
const_cast<Node *>(this)->updateWorldTransform();
return _worldPosition;
}
void Node::setWorldRotation(float x, float y, float z, float w) {
_worldRotation.set(x, y, z, w);
if (_parent) {
_parent->updateWorldTransform();
_localRotation.set(_parent->_worldRotation.getConjugated());
_localRotation.multiply(_worldRotation);
} else {
_localRotation.set(_worldRotation);
}
_eulerDirty = true;
invalidateChildren(TransformBit::ROTATION);
if (_eventMask & TRANSFORM_ON) {
emit(NodeEventType::TRANSFORM_CHANGED, TransformBit::ROTATION);
}
notifyLocalRotationUpdated();
}
const Quaternion &Node::getWorldRotation() const { //NOLINT(misc-no-recursion)
const_cast<Node *>(this)->updateWorldTransform();
return _worldRotation;
}
void Node::setWorldScale(float x, float y, float z) {
_worldScale.set(x, y, z);
if (_parent != nullptr) {
_parent->updateWorldTransform();
Mat3 mat3;
Mat3::fromQuat(_parent->_worldRotation.getConjugated(), &mat3);
Mat3 b;
Mat3::fromMat4(_parent->_worldMatrix, &b);
Mat3::multiply(mat3, b, &mat3);
Mat3 mat3Scaling;
mat3Scaling.m[0] = _worldScale.x;
mat3Scaling.m[4] = _worldScale.y;
mat3Scaling.m[8] = _worldScale.z;
mat3.inverse();
Mat3::multiply(mat3Scaling, mat3, &mat3);
_localScale.x = Vec3{mat3.m[0], mat3.m[1], mat3.m[2]}.length();
_localScale.y = Vec3{mat3.m[3], mat3.m[4], mat3.m[5]}.length();
_localScale.z = Vec3{mat3.m[6], mat3.m[7], mat3.m[8]}.length();
} else {
_localScale = _worldScale;
}
notifyLocalScaleUpdated();
invalidateChildren(TransformBit::SCALE);
if (_eventMask & TRANSFORM_ON) {
emit(NodeEventType::TRANSFORM_CHANGED, TransformBit::SCALE);
}
}
const Vec3 &Node::getWorldScale() const {
const_cast<Node *>(this)->updateWorldTransform();
return _worldScale;
}
void Node::setForward(const Vec3 &dir) {
const float len = dir.length();
Vec3 v3Temp = dir * (-1.F / len);
Quaternion qTemp{Quaternion::identity()};
Quaternion::fromViewUp(v3Temp, &qTemp);
setWorldRotation(qTemp);
}
void Node::setAngle(float val) {
_euler.set(0, 0, val);
Quaternion::createFromAngleZ(val, &_localRotation);
_eulerDirty = false;
invalidateChildren(TransformBit::ROTATION);
if (_eventMask & TRANSFORM_ON) {
emit(NodeEventType::TRANSFORM_CHANGED, TransformBit::ROTATION);
}
notifyLocalRotationUpdated();
}
void Node::onSetParent(Node *oldParent, bool keepWorldTransform) {
if (_parent) {
if ((oldParent == nullptr || oldParent->_scene != _parent->_scene) && _parent->_scene != nullptr) {
walk(setScene);
}
}
if (keepWorldTransform) {
if (_parent) {
_parent->updateWorldTransform();
if (mathutils::approx<float>(_parent->_worldMatrix.determinant(), 0.F, mathutils::EPSILON)) {
CC_LOG_WARNING("14300");
_dirtyFlag |= static_cast<uint32_t>(TransformBit::TRS);
updateWorldTransform();
} else {
Mat4 tmpMat4 = _parent->_worldMatrix.getInversed() * _worldMatrix;
Mat4::toRTS(tmpMat4, &_localRotation, &_localPosition, &_localScale);
}
} else {
_localPosition.set(_worldPosition);
_localRotation.set(_worldRotation);
_localScale.set(_worldScale);
}
notifyLocalPositionRotationScaleUpdated();
_eulerDirty = true;
}
invalidateChildren(TransformBit::TRS);
}
void Node::rotate(const Quaternion &rot, NodeSpace ns /* = NodeSpace::LOCAL*/, bool calledFromJS /* = false*/) {
Quaternion qTempA{rot};
qTempA.normalize();
if (ns == NodeSpace::LOCAL) {
_localRotation *= qTempA;
} else if (ns == NodeSpace::WORLD) {
Quaternion qTempB{Quaternion::identity()};
qTempB = qTempA * getWorldRotation();
qTempA = _worldRotation;
qTempA.inverse();
qTempB = qTempA * qTempB;
_localRotation = _localRotation * qTempB;
}
_eulerDirty = true;
invalidateChildren(TransformBit::ROTATION);
if (_eventMask & TRANSFORM_ON) {
emit(NodeEventType::TRANSFORM_CHANGED, TransformBit::ROTATION);
}
if (!calledFromJS) {
notifyLocalRotationUpdated();
}
}
void Node::lookAt(const Vec3 &pos, const Vec3 &up) {
Vec3 vTemp = getWorldPosition();
Quaternion qTemp{Quaternion::identity()};
vTemp -= pos;
vTemp.normalize();
Quaternion::fromViewUp(vTemp, up, &qTemp);
setWorldRotation(qTemp);
}
Vec3 Node::inverseTransformPoint(const Vec3 &p) {
Vec3 out;
out.set(p.x, p.y, p.z);
Node *cur{this};
index_t i{0};
while (cur != nullptr && cur->getParent()) {
setDirtyNode(i++, cur);
cur = cur->getParent();
}
while (i >= 0) {
Vec3::transformInverseRTS(out, cur->getRotation(), cur->getPosition(), cur->getScale(), &out);
--i;
cur = getDirtyNode(i);
}
return out;
}
void Node::setMatrix(const Mat4 &val) {
val.decompose(&_localScale, &_localRotation, &_localPosition);
notifyLocalPositionRotationScaleUpdated();
invalidateChildren(TransformBit::TRS);
_eulerDirty = true;
if (_eventMask & TRANSFORM_ON) {
emit(NodeEventType::TRANSFORM_CHANGED, TransformBit::TRS);
}
}
void Node::setWorldRotationFromEuler(float x, float y, float z) {
Quaternion::fromEuler(x, y, z, &_worldRotation);
if (_parent) {
_parent->updateWorldTransform();
_localRotation = _parent->_worldRotation.getConjugated() * _worldRotation;
} else {
_localRotation = _worldRotation;
}
_eulerDirty = true;
invalidateChildren(TransformBit::ROTATION);
if (_eventMask & TRANSFORM_ON) {
emit(NodeEventType::TRANSFORM_CHANGED, TransformBit::ROTATION);
}
notifyLocalRotationUpdated();
}
void Node::setRTSInternal(Quaternion *rot, Vec3 *pos, Vec3 *scale, bool calledFromJS) {
uint32_t dirtyBit = 0;
if (rot) {
dirtyBit |= static_cast<uint32_t>(TransformBit::ROTATION);
_localRotation = *rot;
_eulerDirty = true;
}
if (pos) {
_localPosition = *pos;
dirtyBit |= static_cast<uint32_t>(TransformBit::POSITION);
}
if (scale) {
_localScale = *scale;
dirtyBit |= static_cast<uint32_t>(TransformBit::SCALE);
}
if (!calledFromJS) {
notifyLocalPositionRotationScaleUpdated();
}
if (dirtyBit) {
invalidateChildren(static_cast<TransformBit>(dirtyBit));
if (_eventMask & TRANSFORM_ON) {
emit(NodeEventType::TRANSFORM_CHANGED, dirtyBit);
}
}
}
void Node::resetChangedFlags() {
globalFlagChangeVersion++;
}
void Node::clearNodeArray() {
if (clearFrame < clearRound) {
clearFrame++;
} else {
clearFrame = 0;
dirtyNodes.clear();
}
}
ccstd::string Node::getPathInHierarchy() const {
ccstd::string result = getName();
Node *curNode = getParent();
while (curNode && curNode->getParent()) {
result.insert(0, "/").insert(0, curNode->getName());
curNode = curNode->getParent();
}
return result;
}
void Node::translate(const Vec3 &trans, NodeSpace ns) {
Vec3 v3Temp{trans};
if (ns == NodeSpace::LOCAL) {
v3Temp.transformQuat(_localRotation);
_localPosition.x += v3Temp.x;
_localPosition.y += v3Temp.y;
_localPosition.z += v3Temp.z;
} else if (ns == NodeSpace::WORLD) {
if (_parent) {
Quaternion qTemp = _parent->getWorldRotation();
qTemp.inverse();
v3Temp.transformQuat(qTemp);
Vec3 scale{_worldScale};
_localPosition.x += v3Temp.x / scale.x;
_localPosition.y += v3Temp.y / scale.y;
_localPosition.z += v3Temp.z / scale.z;
} else {
_localPosition.x += trans.x;
_localPosition.y += trans.y;
_localPosition.z += trans.z;
}
}
notifyLocalPositionUpdated();
invalidateChildren(TransformBit::POSITION);
if (_eventMask & TRANSFORM_ON) {
emit(NodeEventType::TRANSFORM_CHANGED, TransformBit::POSITION);
}
}
bool Node::onPreDestroy() {
bool result = onPreDestroyBase();
// TODO(Lenovo): bookOfChange free
return result;
}
void Node::onHierarchyChanged(Node *oldParent) {
emit(EventTypesToJS::NODE_REATTACH);
_eventProcessor->reattach();
onHierarchyChangedBase(oldParent);
}
/* static */
//Node *Node::find(const ccstd::string &path, Node *referenceNode /* = nullptr*/) {
// return cc::find(path, referenceNode);
//}
// For deserialization
// void Node::_setChild(index_t i, Node *child) {
// if (i < _children.size()) {
// _children[i] = child;
// } else {
// CC_LOG_ERROR("Invalid index (%d) for Node children (size: %u)", i, static_cast<uint32_t>(_children.size()));
// }
//}
//
// Node *Node::_getChild(index_t i) {
// if (i < _children.size()) {
// return _children[i];
// }
// CC_LOG_ERROR("Invalid index (%d) for Node children (size: %u)", i, static_cast<uint32_t>(_children.size()));
// return nullptr;
//}
//
// void Node::_setChildrenSize(uint32_t size) {
// _children.resize(size);
//}
//
// uint32_t Node::_getChildrenSize() {
// return _children.size();
//}
//
void Node::_setChildren(ccstd::vector<IntrusivePtr<Node>> &&children) {
_children = std::move(children);
}
//
} // namespace cc

View File

@ -0,0 +1,861 @@
/****************************************************************************
Copyright (c) 2021 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.
****************************************************************************/
#pragma once
#include "base/Ptr.h"
#include "base/std/any.h"
#include "bindings/utils/BindingUtils.h"
//#include "core/components/Component.h"
//#include "core/event/Event.h"
#include "core/event/EventTypesToJS.h"
#include "core/scene-graph/BaseNode.h"
#include "core/scene-graph/Layers.h"
#include "core/scene-graph/NodeEnum.h"
#include "core/scene-graph/NodeEvent.h"
#include "core/scene-graph/NodeEventProcessor.h"
#include "math/Mat3.h"
#include "math/Mat4.h"
#include "math/Quaternion.h"
#include "math/Vec3.h"
#include "math/Vec4.h"
namespace cc {
class Scene;
class NodeEventProcessor;
/**
* Event types emitted by Node
*/
using EventType = NodeEventType;
/**
* Bit masks for Node transformation parts
*/
using TransformDirtyBit = TransformBit;
class Node : public BaseNode {
public:
class UserData : public RefCounted {
public:
~UserData() override = default;
protected:
UserData() = default;
};
using Super = BaseNode;
static const uint32_t TRANSFORM_ON;
static Node *instantiate(Node *cloned, bool isSyncedNode);
static void setScene(Node *);
/**
* @en Finds a node by hierarchy path, the path is case-sensitive.
* It will traverse the hierarchy by splitting the path using '/' character.
* This function will still returns the node even if it is inactive.
* It is recommended to not use this function every frame instead cache the result at startup.
* @zh `/`
* 使
* @param path The path of the target node
* @param referenceNode If given, the search will be limited in the sub node tree of the reference node
*/
// static Node *find(const ccstd::string &path, Node *referenceNode = nullptr);
/**
* @en Determine whether the given object is a normal Node. Will return false if [[Scene]] given.
* @zh [[Scene]] false
*/
template <typename T>
static bool isNode(T *obj);
static void resetChangedFlags();
static void clearNodeArray();
Node();
explicit Node(const ccstd::string &name);
~Node() override;
virtual void onPostActivated(bool active) {}
void setParent(Node *parent, bool isKeepWorld = false);
inline Scene *getScene() const { return _scene; };
using WalkCallback = std::function<void(Node *)>;
void walk(const WalkCallback &preFunc);
void walk(const WalkCallback &preFunc, const WalkCallback &postFunc);
template <typename Target, typename... Args>
void on(const CallbacksInvoker::KeyType &type, void (Target::*memberFn)(Args...), Target *target, bool useCapture = false);
template <typename... Args>
void on(const CallbacksInvoker::KeyType &type, std::function<void(Args...)> &&callback, CallbackID &cbID, bool useCapture = false);
template <typename Target, typename... Args>
void on(const CallbacksInvoker::KeyType &type, std::function<void(Args...)> &&callback, Target *target, CallbackID &cbID, bool useCapture = false);
template <typename Target, typename LambdaType>
std::enable_if_t<!std::is_member_function_pointer<LambdaType>::value, void>
on(const CallbacksInvoker::KeyType &type, LambdaType &&callback, Target *target, CallbackID &cbID, bool useCapture = false);
template <typename LambdaType>
std::enable_if_t<!std::is_member_function_pointer<LambdaType>::value, void>
on(const CallbacksInvoker::KeyType &type, LambdaType &&callback, CallbackID &cbID, bool useCapture = false);
template <typename... Args>
void on(const CallbacksInvoker::KeyType &type, std::function<void(Args...)> &&callback, bool useCapture = false);
template <typename Target, typename... Args>
void on(const CallbacksInvoker::KeyType &type, std::function<void(Args...)> &&callback, Target *target, bool useCapture = false);
template <typename Target, typename LambdaType>
std::enable_if_t<!std::is_member_function_pointer<LambdaType>::value, void>
on(const CallbacksInvoker::KeyType &type, LambdaType &&callback, Target *target, bool useCapture = false);
template <typename LambdaType>
std::enable_if_t<!std::is_member_function_pointer<LambdaType>::value, void>
on(const CallbacksInvoker::KeyType &type, LambdaType &&callback, bool useCapture = false);
template <typename Target, typename... Args>
void once(const CallbacksInvoker::KeyType &type, void (Target::*memberFn)(Args...), Target *target, bool useCapture = false);
template <typename... Args>
void once(const CallbacksInvoker::KeyType &type, std::function<void(Args...)> &&callback, CallbackID &cbID, bool useCapture = false);
template <typename Target, typename... Args>
void once(const CallbacksInvoker::KeyType &type, std::function<void(Args...)> &&callback, Target *target, CallbackID &cbID, bool useCapture = false);
template <typename LambdaType>
std::enable_if_t<!std::is_member_function_pointer<LambdaType>::value, void>
once(const CallbacksInvoker::KeyType &type, LambdaType &&callback, CallbackID &cbID, bool useCapture = false);
template <typename Target, typename LambdaType>
std::enable_if_t<!std::is_member_function_pointer<LambdaType>::value, void>
once(const CallbacksInvoker::KeyType &type, LambdaType &&callback, Target *target, CallbackID &cbID, bool useCapture = false);
template <typename... Args>
void once(const CallbacksInvoker::KeyType &type, std::function<void(Args...)> &&callback, bool useCapture = false);
template <typename Target, typename... Args>
void once(const CallbacksInvoker::KeyType &type, std::function<void(Args...)> &&callback, Target *target, bool useCapture = false);
template <typename LambdaType>
std::enable_if_t<!std::is_member_function_pointer<LambdaType>::value, void>
once(const CallbacksInvoker::KeyType &type, LambdaType &&callback, bool useCapture = false);
template <typename Target, typename LambdaType>
std::enable_if_t<!std::is_member_function_pointer<LambdaType>::value, void>
once(const CallbacksInvoker::KeyType &type, LambdaType &&callback, Target *target, bool useCapture = false);
void off(const CallbacksInvoker::KeyType &type, bool useCapture = false);
void off(const CallbacksInvoker::KeyType &type, const CallbackID &cbID, bool useCapture = false);
void off(const CallbacksInvoker::KeyType &type, void *target, bool useCapture = false);
template <typename Target, typename... Args>
void off(const CallbacksInvoker::KeyType &type, void (Target::*memberFn)(Args...), Target *target, bool useCapture = false);
template <typename... Args>
void emit(const CallbacksInvoker::KeyType &type, Args &&...args);
// void dispatchEvent(event::Event *event);
bool hasEventListener(const CallbacksInvoker::KeyType &type) const;
bool hasEventListener(const CallbacksInvoker::KeyType &type, const CallbackID &cbID) const;
bool hasEventListener(const CallbacksInvoker::KeyType &type, void *target) const;
bool hasEventListener(const CallbacksInvoker::KeyType &type, void *target, const CallbackID &cbID) const;
template <typename Target, typename... Args>
bool hasEventListener(const CallbacksInvoker::KeyType &type, void (Target::*memberFn)(Args...), Target *target) const;
void targetOff(const CallbacksInvoker::KeyType &type);
bool destroy() override {
if (CCObject::destroy()) {
setActive(false);
return true;
}
return false;
}
inline void destroyAllChildren() {
for (const auto &child : _children) {
child->destroy();
}
}
inline void updateSiblingIndex() {
index_t i = 0;
for (const auto &child : _children) {
child->_siblingIndex = i++;
}
emit(NodeEventType::SIBLING_ORDER_CHANGED);
}
inline void addChild(Node *node) { node->setParent(this); }
inline void removeChild(Node *node) const {
auto idx = getIdxOfChild(_children, node);
if (idx != -1) {
node->setParent(nullptr);
}
}
inline void removeFromParent() {
if (_parent) {
_parent->removeChild(this);
}
}
void removeAllChildren();
bool isChildOf(Node *parent) const;
void setActive(bool isActive);
void setSiblingIndex(index_t index);
inline bool isPersistNode() const {
return static_cast<FlagBits>(_objFlags & Flags::DONT_DESTROY) > 0;
}
inline void setPersistNode(bool val) {
val ? _objFlags |= Flags::DONT_DESTROY : _objFlags &= ~Flags::DONT_DESTROY;
}
inline const ccstd::string &getUuid() const {
return _id;
}
inline bool isActive() const { return _active != 0; }
inline bool isActiveInHierarchy() const { return _activeInHierarchy != 0; }
inline void setActiveInHierarchy(bool v) {
_activeInHierarchy = (v ? 1 : 0);
}
inline const ccstd::vector<IntrusivePtr<Node>> &getChildren() const { return _children; }
inline Node *getParent() const { return _parent; }
inline NodeEventProcessor *getEventProcessor() const { return _eventProcessor; }
Node *getChildByUuid(const ccstd::string &uuid) const;
Node *getChildByName(const ccstd::string &name) const;
Node *getChildByPath(const ccstd::string &path) const;
inline index_t getSiblingIndex() const { return _siblingIndex; }
inline UserData *getUserData() { return _userData.get(); }
inline void setUserData(UserData *data) { _userData = data; }
inline void insertChild(Node *child, index_t siblingIndex) {
child->setParent(this);
child->setSiblingIndex(siblingIndex);
}
void invalidateChildren(TransformBit dirtyBit);
void translate(const Vec3 &, NodeSpace ns = NodeSpace::LOCAL);
void rotate(const Quaternion &rot, NodeSpace ns = NodeSpace::LOCAL, bool calledFromJS = false);
inline void rotateForJS(float x, float y, float z, float w, NodeSpace ns = NodeSpace::LOCAL) {
rotate(Quaternion(x, y, z, w), ns, true);
}
void lookAt(const Vec3 &pos, const Vec3 &up = Vec3::UNIT_Y);
void pauseSystemEvents(bool recursive) {} // cjh TODO:
void resumeSystemEvents(bool recursive) {} // cjh TODO:
ccstd::string getPathInHierarchy() const;
// ===============================
// transform
// ===============================
/**
* @en Set position in local coordinate system
* @zh
* @param position Target position
*/
inline void setPosition(const Vec3 &pos) { setPosition(pos.x, pos.y, pos.z); }
inline void setPosition(float x, float y) { setPosition(x, y, _localPosition.z); }
inline void setPosition(float x, float y, float z) { setPositionInternal(x, y, z, false); }
inline void setPositionInternal(float x, float y, bool calledFromJS) { setPositionInternal(x, y, _localPosition.z, calledFromJS); }
void setPositionInternal(float x, float y, float z, bool calledFromJS);
// It is invoked after deserialization. It only sets position value, not triggers other logic.
inline void setPositionForJS(float x, float y, float z) { _localPosition.set(x, y, z); }
/**
* @en Get position in local coordinate system, please try to pass `out` vector and reuse it to avoid garbage.
* @zh [[Vec3]]
* @param out Set the result to out vector
* @return If `out` given, the return value equals to `out`, otherwise a new vector will be generated and return
*/
inline const Vec3 &getPosition() const { return _localPosition; }
/**
* @en Set rotation in local coordinate system with a quaternion representing the rotation
* @zh
* @param rotation Rotation in quaternion
*/
inline void setRotation(const Quaternion &rotation) { setRotation(rotation.x, rotation.y, rotation.z, rotation.w); }
inline void setRotation(float x, float y, float z, float w) { setRotationInternal(x, y, z, w, false); }
void setRotationInternal(float x, float y, float z, float w, bool calledFromJS);
inline void setRotationForJS(float x, float y, float z, float w) { _localRotation.set(x, y, z, w); }
inline void setEulerAngles(const Vec3 &val) { setRotationFromEuler(val.x, val.y, val.z); }
inline void setRotationFromEuler(const Vec3 &val) { setRotationFromEuler(val.x, val.y, val.z); }
inline void setRotationFromEuler(float x, float y) { setRotationFromEuler(x, y, _euler.z); }
void setRotationFromEuler(float x, float y, float z);
inline void setRotationFromEulerForJS(float x, float y, float z) { _euler.set(x, y, z); }
/**
* @en Get rotation as quaternion in local coordinate system, please try to pass `out` quaternion and reuse it to avoid garbage.
* @zh [[Quat]]
* @param out Set the result to out quaternion
* @return If `out` given, the return value equals to `out`, otherwise a new quaternion will be generated and return
*/
inline const Quaternion &getRotation() const { return _localRotation; }
/**
* @en Set scale in local coordinate system
* @zh
* @param scale Target scale
*/
inline void setScale(const Vec3 &scale) { setScale(scale.x, scale.y, scale.z); }
inline void setScale(float x, float y) { setScale(x, y, _localScale.z); }
inline void setScale(float x, float y, float z) { setScaleInternal(x, y, z, false); }
inline void setScaleInternal(float x, float y, bool calledFromJS) { setScaleInternal(x, y, _localScale.z, calledFromJS); }
void setScaleInternal(float x, float y, float z, bool calledFromJS);
inline void setScaleForJS(float x, float y, float z) { _localScale.set(x, y, z); }
/**
* @en Get scale in local coordinate system, please try to pass `out` vector and reuse it to avoid garbage.
* @zh [[Vec3]]
* @param out Set the result to out vector
* @return If `out` given, the return value equals to `out`, otherwise a new vector will be generated and return
*/
inline const Vec3 &getScale() const { return _localScale; }
/**
* @en Inversely transform a point from world coordinate system to local coordinate system.
* @zh
* @param p A position in world coordinate system
* @return The result point in local coordinate system will be stored in this vector
*/
Vec3 inverseTransformPoint(const Vec3 &p);
/**
* @en Set position in world coordinate system
* @zh
* @param position Target position
*/
inline void setWorldPosition(const Vec3 &pos) { setWorldPosition(pos.x, pos.y, pos.z); }
void setWorldPosition(float x, float y, float z);
/**
* @en Get position in world coordinate system, please try to pass `out` vector and reuse it to avoid garbage.
* @zh [[Vec3]]
* @param out Set the result to out vector
* @return If `out` given, the return value equals to `out`, otherwise a new vector will be generated and return
*/
const Vec3 &getWorldPosition() const;
/**
* @en Set rotation in world coordinate system with a quaternion representing the rotation
* @zh
* @param rotation Rotation in quaternion
*/
inline void setWorldRotation(const Quaternion &rotation) { setWorldRotation(rotation.x, rotation.y, rotation.z, rotation.w); }
void setWorldRotation(float x, float y, float z, float w);
/**
* @en Get rotation as quaternion in world coordinate system, please try to pass `out` quaternion and reuse it to avoid garbage.
* @zh [[Quat]]
* @param out Set the result to out quaternion
* @return If `out` given, the return value equals to `out`, otherwise a new quaternion will be generated and return
*/
const Quaternion &getWorldRotation() const;
/**
* @en Set rotation in world coordinate system with euler angles
* @zh
* @param x X axis rotation
* @param y Y axis rotation
* @param z Z axis rotation
*/
inline void setWorldScale(const Vec3 &scale) { setWorldScale(scale.x, scale.y, scale.z); }
void setWorldScale(float x, float y, float z);
/**
* @en Get scale in world coordinate system, please try to pass `out` vector and reuse it to avoid garbage.
* @zh [[Vec3]]
* @param out Set the result to out vector
* @return If `out` given, the return value equals to `out`, otherwise a new vector will be generated and return
*/
const Vec3 &getWorldScale() const;
void setWorldRotationFromEuler(float x, float y, float z);
/**
* @en Local transformation matrix
* @zh
*/
void setMatrix(const Mat4 &val);
/**
* @en Update the world transform information if outdated
* @zh
*/
void updateWorldTransform();
/**
* @en Get a world transform matrix
* @zh
* @param out Set the result to out matrix
* @return If `out` given, the return value equals to `out`, otherwise a new matrix will be generated and return
*/
const Mat4 &getWorldMatrix() const;
/**
* @en Get a world transform matrix with only rotation and scale
* @zh
* @param out Set the result to out matrix
* @return If `out` given, the return value equals to `out`, otherwise a new matrix will be generated and return
*/
Mat4 getWorldRS();
/**
* @en Get a world transform matrix with only rotation and translation
* @zh
* @param out Set the result to out matrix
* @return If `out` given, the return value equals to `out`, otherwise a new matrix will be generated and return
*/
Mat4 getWorldRT();
/**
* @en Set local transformation with rotation, position and scale separately.
* @zh
* @param rot The rotation
* @param pos The position
* @param scale The scale
*/
void setRTSInternal(Quaternion *rot, Vec3 *pos, Vec3 *scale, bool calledFromJS);
inline void setRTS(Quaternion *rot, Vec3 *pos, Vec3 *scale) { setRTSInternal(rot, pos, scale, false); }
void setForward(const Vec3 &dir);
void setAngle(float);
inline const Vec3 &getEulerAngles() {
if (_eulerDirty) {
Quaternion::toEuler(_localRotation, false, &_euler);
_eulerDirty = false;
}
return _euler;
}
inline float getAngle() const {
return _euler.z;
}
inline Vec3 getForward() const {
Vec3 forward{0, 0, -1};
forward.transformQuat(getWorldRotation());
return forward;
}
inline Vec3 getUp() const {
Vec3 up{0, 1, 0};
up.transformQuat(getWorldRotation());
return up;
}
inline Vec3 getRight() const {
Vec3 right{1, 0, 0};
right.transformQuat(getWorldRotation());
return right;
}
inline bool isStatic() const {
return _isStatic != 0;
}
inline void setStatic(bool v) {
_isStatic = v ? 1 : 0;
}
/**
* @en Whether the node's transformation have changed during the current frame.
* @zh
*/
inline uint32_t getChangedFlags() const {
return _hasChangedFlagsVersion == globalFlagChangeVersion ? _hasChangedFlags : 0;
}
inline void setChangedFlags(uint32_t value) {
_hasChangedFlagsVersion = globalFlagChangeVersion;
_hasChangedFlags = value;
}
inline void setDirtyFlag(uint32_t value) { _dirtyFlag = value; }
inline uint32_t getDirtyFlag() const { return _dirtyFlag; }
inline void setLayer(uint32_t layer) {
_layer = layer;
emit(NodeEventType::LAYER_CHANGED, layer);
}
inline uint32_t getLayer() const { return _layer; }
inline float getUISortingPriority() const { return _uiSortingPriority; }
inline bool isUISortingEnabled() const { return _uiSortingEnabled != 0; }
// inline NodeUiProperties *getUIProps() const { return _uiProps.get(); }
// // ------------------ Component code start -----------------------------
// // TODO(Lenovo):
//
// template <typename T, typename = std::enable_if_t<std::is_base_of<Component, T>::value>>
// static Component *findComponent(Node * /*node*/) {
// // cjh TODO:
// CC_ASSERT(false);
// return nullptr;
// }
//
// template <typename T, typename = std::enable_if_t<std::is_base_of<Component, T>::value>>
// static Component *findComponents(Node * /*node*/, const ccstd::vector<Component *> & /*components*/) {
// // cjh TODO:
// CC_ASSERT(false);
// return nullptr;
// }
//
// template <typename T, typename = std::enable_if_t<std::is_base_of<Component, T>::value>>
// static Component *findChildComponent(const ccstd::vector<Node *> & /*children*/) {
// // cjh TODO:
// CC_ASSERT(false);
// return nullptr;
// }
//
// template <typename T, typename = std::enable_if_t<std::is_base_of<Component, T>::value>>
// static void findChildComponents(const ccstd::vector<Node *> & /*children*/, ccstd::vector<Component *> & /*components*/) {
// // cjh TODO:
// CC_ASSERT(false);
// }
//
// template <typename T, typename = std::enable_if_t<std::is_base_of_v<Component, T>, T>>
// T *addComponent() {
// T *comp = new T();
// return static_cast<T *>(addComponent(comp));
// }
//
// template <typename T, typename std::enable_if_t<std::is_base_of<Component, T>::value>>
// void removeComponent() {
// for (auto iter = _components.begin(); iter != _components.end(); ++iter) {
// if (dynamic_cast<T *>(*iter) != nullptr) {
// _components.erase(iter);
// }
// }
// }
//
// Component *addComponent(Component *comp);
// void removeComponent(Component *comp);
//
// template <typename T, typename = std::enable_if_t<std::is_base_of<Component, T>::value>>
// Component *getComponent() const {
// for (auto *component : _components) {
// if (dynamic_cast<T *>(component) != nullptr) {
// return component;
// }
// }
// return nullptr;
// }
//
// // TODO(Lenovo):
// template <typename T, typename std::enable_if_t<std::is_base_of<Component, T>::value>>
// ccstd::vector<Component *> getComponents() const {
// // cjh TODO:
// CC_ASSERT(false);
// return {};
// };
//
// template <typename T, typename std::enable_if_t<std::is_base_of<Component, T>::value>>
// Component *getComponentInChildren(const T & /*comp*/) const {
// // cjh TODO:
// CC_ASSERT(false);
// return nullptr;
// }
//
// template <typename T, typename std::enable_if_t<std::is_base_of<Component, T>::value>>
// ccstd::vector<Component *> getComponentsInChildren() const {
// // cjh TODO:
// CC_ASSERT(false);
// return {};
// }
//
// inline ccstd::vector<Component *> getComponents() const { return _components; }
//
// void checkMultipleComp(Component *comp) {}
// ccstd::vector<Component *> _components;
//
// friend void componentCorrupted(Node *node, Component *comp, uint32_t index);
// ------------------ Component code end -----------------------------
// For deserialization
// void _setChild(index_t i, Node *child);
// Node * _getChild(index_t i);
// void _setChildrenSize(uint32_t size);
// uint32_t _getChildrenSize();
void _setChildren(ccstd::vector<IntrusivePtr<Node>> &&children); // NOLINT
inline se::Object *_getSharedArrayBufferObject() const { return _sharedMemoryActor.getSharedArrayBufferObject(); } // NOLINT
bool onPreDestroy() override;
bool onPreDestroyBase();
std::function<void(index_t)> onSiblingIndexChanged{nullptr};
// For deserialization
ccstd::string _id;
Node *_parent{nullptr};
private:
static index_t getIdxOfChild(const ccstd::vector<IntrusivePtr<Node>> &, Node *);
virtual void onBatchCreated(bool dontChildPrefab);
virtual void updateScene();
void onSetParent(Node *oldParent, bool keepWorldTransform);
void onHierarchyChanged(Node *);
void onHierarchyChangedBase(Node *oldParent);
inline void notifyLocalPositionUpdated() {
emit(EventTypesToJS::NODE_LOCAL_POSITION_UPDATED, _localPosition.x, _localPosition.y, _localPosition.z);
}
inline void notifyLocalRotationUpdated() {
emit(EventTypesToJS::NODE_LOCAL_ROTATION_UPDATED, _localRotation.x, _localRotation.y, _localRotation.z, _localRotation.w);
}
inline void notifyLocalScaleUpdated() {
emit(EventTypesToJS::NODE_LOCAL_SCALE_UPDATED, _localScale.x, _localScale.y, _localScale.z);
}
inline void notifyLocalPositionRotationScaleUpdated() {
emit(EventTypesToJS::NODE_LOCAL_POSITION_ROTATION_SCALE_UPDATED,
_localPosition.x, _localPosition.y, _localPosition.z,
_localRotation.x, _localRotation.y, _localRotation.z, _localRotation.w,
_localScale.x, _localScale.y, _localScale.z);
}
#if CC_EDITOR
inline void notifyEditorAttached(bool attached) {
emit(EventTypesToJS::NODE_EDITOR_ATTACHED, attached);
}
#endif
// increase on every frame, used to identify the frame
static uint32_t globalFlagChangeVersion;
static uint32_t clearFrame;
static uint32_t clearRound;
Scene *_scene{nullptr};
NodeEventProcessor *_eventProcessor{nullptr};
IntrusivePtr<UserData> _userData;
ccstd::vector<IntrusivePtr<Node>> _children;
bindings::NativeMemorySharedToScriptActor _sharedMemoryActor;
// local transform
Vec3 _localPosition{Vec3::ZERO};
Vec3 _localScale{Vec3::ONE};
Quaternion _localRotation{Quaternion::identity()};
// world transform
Vec3 _worldPosition{Vec3::ZERO};
Vec3 _worldScale{Vec3::ONE};
Vec3 _euler{0, 0, 0};
Quaternion _worldRotation{Quaternion::identity()};
Mat4 _worldMatrix{Mat4::IDENTITY};
// Shared memory with JS
// NOTE: TypeArray created in node.jsb.ts _ctor should have the same memory layout
uint32_t _eventMask{0}; // Uint32: 0
uint32_t _layer{static_cast<uint32_t>(Layers::LayerList::DEFAULT)}; // Uint32: 1
uint32_t _dirtyFlag{0}; // Uint32: 2
index_t _siblingIndex{0}; // Int32: 0
float _uiSortingPriority{0.0F}; // Float: 0
uint8_t _activeInHierarchy{0}; // Uint8: 0
uint8_t _active{1}; // Uint8: 1
uint8_t _isStatic{0}; // Uint8: 2
uint8_t _uiSortingEnabled{0}; // Uint8: 3
/* set _hasChangedFlagsVersion to globalFlagChangeVersion when `_hasChangedFlags` updated.
* `globalFlagChangeVersion == _hasChangedFlagsVersion` means that "_hasChangedFlags is dirty in current frametime".
*/
uint32_t _hasChangedFlagsVersion{0};
uint32_t _hasChangedFlags{0};
bool _eulerDirty{false};
friend class NodeActivator;
friend class Scene;
CC_DISALLOW_COPY_MOVE_ASSIGN(Node);
};
template <typename T>
bool Node::isNode(T *obj) {
return dynamic_cast<Node *>(obj) != nullptr && dynamic_cast<Scene *>(obj) == nullptr;
}
template <typename... Args>
void Node::emit(const CallbacksInvoker::KeyType &type, Args &&...args) {
_eventProcessor->emit(type, std::forward<Args>(args)...);
}
template <typename Target, typename... Args>
void Node::on(const CallbacksInvoker::KeyType &type, void (Target::*memberFn)(Args...), Target *target, bool useCapture) {
if (type == NodeEventType::TRANSFORM_CHANGED) {
_eventMask |= TRANSFORM_ON;
}
_eventProcessor->on(type, memberFn, target, useCapture);
}
template <typename... Args>
void Node::on(const CallbacksInvoker::KeyType &type, std::function<void(Args...)> &&callback, CallbackID &cbID, bool useCapture) {
if (type == NodeEventType::TRANSFORM_CHANGED) {
_eventMask |= TRANSFORM_ON;
}
_eventProcessor->on(type, std::forward<std::function<void(Args...)>>(callback), cbID, useCapture);
}
template <typename Target, typename... Args>
void Node::on(const CallbacksInvoker::KeyType &type, std::function<void(Args...)> &&callback, Target *target, CallbackID &cbID, bool useCapture) {
if (type == NodeEventType::TRANSFORM_CHANGED) {
_eventMask |= TRANSFORM_ON;
}
_eventProcessor->on(type, std::forward<std::function<void(Args...)>>(callback), target, cbID, useCapture);
}
template <typename Target, typename LambdaType>
std::enable_if_t<!std::is_member_function_pointer<LambdaType>::value, void>
Node::on(const CallbacksInvoker::KeyType &type, LambdaType &&callback, Target *target, CallbackID &cbID, bool useCapture) {
if (type == NodeEventType::TRANSFORM_CHANGED) {
_eventMask |= TRANSFORM_ON;
}
_eventProcessor->on(type, callback, target, cbID, useCapture);
}
template <typename LambdaType>
std::enable_if_t<!std::is_member_function_pointer<LambdaType>::value, void>
Node::on(const CallbacksInvoker::KeyType &type, LambdaType &&callback, CallbackID &cbID, bool useCapture) {
if (type == NodeEventType::TRANSFORM_CHANGED) {
_eventMask |= TRANSFORM_ON;
}
_eventProcessor->on(type, callback, cbID, useCapture);
}
template <typename... Args>
void Node::on(const CallbacksInvoker::KeyType &type, std::function<void(Args...)> &&callback, bool useCapture) {
CallbackID unusedID{0};
on(type, callback, unusedID, useCapture);
}
template <typename Target, typename... Args>
void Node::on(const CallbacksInvoker::KeyType &type, std::function<void(Args...)> &&callback, Target *target, bool useCapture) {
CallbackID unusedID{0};
on(type, callback, target, unusedID, useCapture);
}
template <typename Target, typename LambdaType>
std::enable_if_t<!std::is_member_function_pointer<LambdaType>::value, void>
Node::on(const CallbacksInvoker::KeyType &type, LambdaType &&callback, Target *target, bool useCapture) {
CallbackID unusedID{0};
on(type, callback, target, unusedID, useCapture);
}
template <typename LambdaType>
std::enable_if_t<!std::is_member_function_pointer<LambdaType>::value, void>
Node::on(const CallbacksInvoker::KeyType &type, LambdaType &&callback, bool useCapture) {
CallbackID unusedID{0};
on(type, callback, unusedID, useCapture);
}
template <typename Target, typename... Args>
void Node::once(const CallbacksInvoker::KeyType &type, void (Target::*memberFn)(Args...), Target *target, bool useCapture) {
_eventProcessor->once(type, memberFn, target, useCapture);
}
template <typename... Args>
void Node::once(const CallbacksInvoker::KeyType &type, std::function<void(Args...)> &&callback, CallbackID &cbID, bool useCapture) {
_eventProcessor->once(type, callback, cbID, useCapture);
}
template <typename Target, typename... Args>
void Node::once(const CallbacksInvoker::KeyType &type, std::function<void(Args...)> &&callback, Target *target, CallbackID &cbID, bool useCapture) {
_eventProcessor->once(type, std::forward<std::function<void(Args...)>>(callback), target, cbID, useCapture);
}
template <typename LambdaType>
std::enable_if_t<!std::is_member_function_pointer<LambdaType>::value, void>
Node::once(const CallbacksInvoker::KeyType &type, LambdaType &&callback, CallbackID &cbID, bool useCapture) {
_eventProcessor->once(type, callback, cbID, useCapture);
}
template <typename Target, typename LambdaType>
std::enable_if_t<!std::is_member_function_pointer<LambdaType>::value, void>
Node::once(const CallbacksInvoker::KeyType &type, LambdaType &&callback, Target *target, CallbackID &cbID, bool useCapture) {
_eventProcessor->once(type, callback, target, cbID, useCapture);
}
template <typename... Args>
void Node::once(const CallbacksInvoker::KeyType &type, std::function<void(Args...)> &&callback, bool useCapture) {
CallbackID unusedID{0};
once(type, callback, unusedID, useCapture);
}
template <typename Target, typename... Args>
void Node::once(const CallbacksInvoker::KeyType &type, std::function<void(Args...)> &&callback, Target *target, bool useCapture) {
CallbackID unusedID{0};
once(type, callback, target, unusedID, useCapture);
}
template <typename LambdaType>
std::enable_if_t<!std::is_member_function_pointer<LambdaType>::value, void>
Node::once(const CallbacksInvoker::KeyType &type, LambdaType &&callback, bool useCapture) {
CallbackID unusedID{0};
once(type, callback, unusedID, useCapture);
}
template <typename Target, typename LambdaType>
std::enable_if_t<!std::is_member_function_pointer<LambdaType>::value, void>
Node::once(const CallbacksInvoker::KeyType &type, LambdaType &&callback, Target *target, bool useCapture) {
CallbackID unusedID{0};
once(type, callback, target, unusedID, useCapture);
}
template <typename Target, typename... Args>
void Node::off(const CallbacksInvoker::KeyType &type, void (Target::*memberFn)(Args...), Target *target, bool useCapture) {
_eventProcessor->off(type, memberFn, target, useCapture);
bool hasListeners = _eventProcessor->hasEventListener(type);
if (!hasListeners) {
if (type == NodeEventType::TRANSFORM_CHANGED) {
_eventMask &= ~TRANSFORM_ON;
}
}
}
template <typename Target, typename... Args>
bool Node::hasEventListener(const CallbacksInvoker::KeyType &type, void (Target::*memberFn)(Args...), Target *target) const {
return _eventProcessor->hasEventListener(type, memberFn, target);
}
} // namespace cc

View File

@ -0,0 +1,7 @@
当前版本: cocos creator 3.6.3
涉及源文件:
cocos/2d/renderer/Batcher2d.h
cocos/2d/renderer/Batcher2d.cpp
cocos/2d/renderer/RenderEntity.h
cocos/2d/renderer/RenderEntity.cpp