mirror of
https://gitee.com/nomat/lcc-ui-sorting-group-demo.git
synced 2024-12-25 19:28:26 +00:00
3.6.3 native目录
This commit is contained in:
parent
fa7a606f33
commit
4d9a0f87e8
15
3.6.3/native/engine/android/CMakeLists.txt
Normal file
15
3.6.3/native/engine/android/CMakeLists.txt
Normal 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})
|
1
3.6.3/native/engine/android/Post-service.cmake
Normal file
1
3.6.3/native/engine/android/Post-service.cmake
Normal file
@ -0,0 +1 @@
|
||||
# Supported for Cocos Service!
|
1
3.6.3/native/engine/android/Pre-service.cmake
Normal file
1
3.6.3/native/engine/android/Pre-service.cmake
Normal file
@ -0,0 +1 @@
|
||||
# Supported for Cocos Service!
|
43
3.6.3/native/engine/android/app/AndroidManifest.xml
Normal file
43
3.6.3/native/engine/android/app/AndroidManifest.xml
Normal 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>
|
104
3.6.3/native/engine/android/app/build.gradle
Normal file
104
3.6.3/native/engine/android/app/build.gradle
Normal 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')
|
||||
}
|
42
3.6.3/native/engine/android/app/proguard-rules.pro
vendored
Normal file
42
3.6.3/native/engine/android/app/proguard-rules.pro
vendored
Normal 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
|
@ -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();
|
||||
}
|
||||
}
|
8
3.6.3/native/engine/android/build-cfg.json
Normal file
8
3.6.3/native/engine/android/build-cfg.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"ndk_module_path" :[
|
||||
"${COCOS_ROOT}",
|
||||
"${COCOS_ROOT}/cocos",
|
||||
"${COCOS_ROOT}/external"
|
||||
],
|
||||
"copy_resources": []
|
||||
}
|
31
3.6.3/native/engine/android/build.gradle
Normal file
31
3.6.3/native/engine/android/build.gradle
Normal 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
|
||||
}
|
53
3.6.3/native/engine/android/instantapp/AndroidManifest.xml
Normal file
53
3.6.3/native/engine/android/instantapp/AndroidManifest.xml
Normal 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>
|
101
3.6.3/native/engine/android/instantapp/build.gradle
Normal file
101
3.6.3/native/engine/android/instantapp/build.gradle
Normal 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')
|
||||
}
|
42
3.6.3/native/engine/android/instantapp/proguard-rules.pro
vendored
Normal file
42
3.6.3/native/engine/android/instantapp/proguard-rules.pro
vendored
Normal 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
|
@ -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();
|
||||
}
|
||||
}
|
BIN
3.6.3/native/engine/android/res/mipmap-hdpi/ic_launcher.png
Normal file
BIN
3.6.3/native/engine/android/res/mipmap-hdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.6 KiB |
BIN
3.6.3/native/engine/android/res/mipmap-mdpi/ic_launcher.png
Normal file
BIN
3.6.3/native/engine/android/res/mipmap-mdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.9 KiB |
BIN
3.6.3/native/engine/android/res/mipmap-xhdpi/ic_launcher.png
Normal file
BIN
3.6.3/native/engine/android/res/mipmap-xhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.7 KiB |
BIN
3.6.3/native/engine/android/res/mipmap-xxhdpi/ic_launcher.png
Normal file
BIN
3.6.3/native/engine/android/res/mipmap-xxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
BIN
3.6.3/native/engine/android/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
BIN
3.6.3/native/engine/android/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
3
3.6.3/native/engine/android/res/values/strings.xml
Normal file
3
3.6.3/native/engine/android/res/values/strings.xml
Normal file
@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name" translatable="false">ui-sorting-group</string>
|
||||
</resources>
|
54
3.6.3/native/engine/common/CMakeLists.txt
Normal file
54
3.6.3/native/engine/common/CMakeLists.txt
Normal 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
|
||||
)
|
65
3.6.3/native/engine/common/Classes/Game.cpp
Normal file
65
3.6.3/native/engine/common/Classes/Game.cpp
Normal 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);
|
44
3.6.3/native/engine/common/Classes/Game.h
Normal file
44
3.6.3/native/engine/common/Classes/Game.h
Normal 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;
|
||||
};
|
1
3.6.3/native/engine/common/cocos-version.json
Normal file
1
3.6.3/native/engine/common/cocos-version.json
Normal file
@ -0,0 +1 @@
|
||||
{"version":"3.6.3","skipCheck":false}
|
3
3.6.3/native/engine/common/localCfg.cmake
Normal file
3
3.6.3/native/engine/common/localCfg.cmake
Normal file
@ -0,0 +1,3 @@
|
||||
## Add or overwrite options from cfg.cmake.
|
||||
## This file is ignored from git.
|
||||
# set(NODE_EXECUTABLE /opt/...)
|
@ -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
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
Loading…
Reference in New Issue
Block a user