diff --git a/assets/lcc-ui-sorting-group/engine-extend/render-entity.ts b/assets/lcc-ui-sorting-group/engine-extend/render-entity.ts
index aa4565f..c7010d6 100644
--- a/assets/lcc-ui-sorting-group/engine-extend/render-entity.ts
+++ b/assets/lcc-ui-sorting-group/engine-extend/render-entity.ts
@@ -66,7 +66,8 @@ export function UpdateRenderEntity(renderEntity:__private._cocos_2d_renderer_ren
return this._sortingPriority;
},
set: function(value) {
- this._sortingPriority = value;
+ this._sortingPriority = value;
+ // console.log(`JSB sortingPriority ${value}`);
if (JSB) {
this._floatSharedBuffer[RenderEntityFloatSharedBufferView.sortingPriority] = value;
}
diff --git a/assets/lcc-ui-sorting-group/engine-extend/ui-renderer.ts b/assets/lcc-ui-sorting-group/engine-extend/ui-renderer.ts
index 7f4e7b8..a6796aa 100644
--- a/assets/lcc-ui-sorting-group/engine-extend/ui-renderer.ts
+++ b/assets/lcc-ui-sorting-group/engine-extend/ui-renderer.ts
@@ -26,7 +26,8 @@ if(!('sortingPriority' in UIRenderer.prototype)){
return this._sortingPriority;
},
set: function(value) {
- this._sortingPriority = value;
+ this._sortingPriority = value;
+ this._renderEntity.sortingPriority = value;
},
enumerable: true
});
diff --git a/assets/lcc-ui-sorting-group/engine-extend/ui.ts b/assets/lcc-ui-sorting-group/engine-extend/ui.ts
index 1b7b77b..9eca69b 100644
--- a/assets/lcc-ui-sorting-group/engine-extend/ui.ts
+++ b/assets/lcc-ui-sorting-group/engine-extend/ui.ts
@@ -66,7 +66,9 @@ UI.prototype.flushRendererCache = function(){
if(this.rendererOrder){
rendererCache.sort((a, b)=>{ return a._sortingPriority - b._sortingPriority; });
}
+ // console.log(`flushRendererCache ${rendererCache.length}`);
for(let render of rendererCache){
+ // console.log(`${render.node.name} render hash ${render.renderData.dataHash}`);
render.fillBuffers(this);
if(render.sortingOpacity >= 0){
updateOpacity(render.renderData, render.sortingOpacity);
diff --git a/assets/test/scenes/test-scene.scene b/assets/test/scenes/test-scene.scene
index 84a0890..ca06c7e 100644
--- a/assets/test/scenes/test-scene.scene
+++ b/assets/test/scenes/test-scene.scene
@@ -945,7 +945,7 @@
"__expectedType__": "cc.SpriteFrame"
}
],
- "listItemMax": 200,
+ "listItemMax": 2,
"_id": "9fuu+PfOFHPqnvdYJwsexB"
},
{
diff --git a/native/engine/android/CMakeLists.txt b/native/engine/android/CMakeLists.txt
new file mode 100644
index 0000000..1a1bec4
--- /dev/null
+++ b/native/engine/android/CMakeLists.txt
@@ -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})
diff --git a/native/engine/android/Post-service.cmake b/native/engine/android/Post-service.cmake
new file mode 100644
index 0000000..16fd033
--- /dev/null
+++ b/native/engine/android/Post-service.cmake
@@ -0,0 +1 @@
+# Supported for Cocos Service!
\ No newline at end of file
diff --git a/native/engine/android/Pre-service.cmake b/native/engine/android/Pre-service.cmake
new file mode 100644
index 0000000..16fd033
--- /dev/null
+++ b/native/engine/android/Pre-service.cmake
@@ -0,0 +1 @@
+# Supported for Cocos Service!
\ No newline at end of file
diff --git a/native/engine/android/app/AndroidManifest.xml b/native/engine/android/app/AndroidManifest.xml
new file mode 100644
index 0000000..7e12819
--- /dev/null
+++ b/native/engine/android/app/AndroidManifest.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/native/engine/android/app/build.gradle b/native/engine/android/app/build.gradle
new file mode 100644
index 0000000..540d6b6
--- /dev/null
+++ b/native/engine/android/app/build.gradle
@@ -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')
+}
diff --git a/native/engine/android/app/proguard-rules.pro b/native/engine/android/app/proguard-rules.pro
new file mode 100644
index 0000000..dbb43fb
--- /dev/null
+++ b/native/engine/android/app/proguard-rules.pro
@@ -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
diff --git a/native/engine/android/app/src/com/cocos/game/AppActivity.java b/native/engine/android/app/src/com/cocos/game/AppActivity.java
new file mode 100644
index 0000000..5aaece8
--- /dev/null
+++ b/native/engine/android/app/src/com/cocos/game/AppActivity.java
@@ -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();
+ }
+}
diff --git a/native/engine/android/build-cfg.json b/native/engine/android/build-cfg.json
new file mode 100644
index 0000000..fb658e2
--- /dev/null
+++ b/native/engine/android/build-cfg.json
@@ -0,0 +1,8 @@
+{
+ "ndk_module_path" :[
+ "${COCOS_ROOT}",
+ "${COCOS_ROOT}/cocos",
+ "${COCOS_ROOT}/external"
+ ],
+ "copy_resources": []
+}
diff --git a/native/engine/android/build.gradle b/native/engine/android/build.gradle
new file mode 100644
index 0000000..2ae589d
--- /dev/null
+++ b/native/engine/android/build.gradle
@@ -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
+}
diff --git a/native/engine/android/instantapp/AndroidManifest.xml b/native/engine/android/instantapp/AndroidManifest.xml
new file mode 100644
index 0000000..2bf48de
--- /dev/null
+++ b/native/engine/android/instantapp/AndroidManifest.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/native/engine/android/instantapp/build.gradle b/native/engine/android/instantapp/build.gradle
new file mode 100644
index 0000000..cac6ddc
--- /dev/null
+++ b/native/engine/android/instantapp/build.gradle
@@ -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')
+}
diff --git a/native/engine/android/instantapp/proguard-rules.pro b/native/engine/android/instantapp/proguard-rules.pro
new file mode 100644
index 0000000..dbb43fb
--- /dev/null
+++ b/native/engine/android/instantapp/proguard-rules.pro
@@ -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
diff --git a/native/engine/android/instantapp/src/com/cocos/game/InstantActivity.java b/native/engine/android/instantapp/src/com/cocos/game/InstantActivity.java
new file mode 100644
index 0000000..318e839
--- /dev/null
+++ b/native/engine/android/instantapp/src/com/cocos/game/InstantActivity.java
@@ -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();
+ }
+}
diff --git a/native/engine/android/res/mipmap-hdpi/ic_launcher.png b/native/engine/android/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..888c0d5
Binary files /dev/null and b/native/engine/android/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/native/engine/android/res/mipmap-mdpi/ic_launcher.png b/native/engine/android/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..d5e3c77
Binary files /dev/null and b/native/engine/android/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/native/engine/android/res/mipmap-xhdpi/ic_launcher.png b/native/engine/android/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..2b6f32a
Binary files /dev/null and b/native/engine/android/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/native/engine/android/res/mipmap-xxhdpi/ic_launcher.png b/native/engine/android/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..2f1e5a6
Binary files /dev/null and b/native/engine/android/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/native/engine/android/res/mipmap-xxxhdpi/ic_launcher.png b/native/engine/android/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..a9ebc79
Binary files /dev/null and b/native/engine/android/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/native/engine/android/res/values/strings.xml b/native/engine/android/res/values/strings.xml
new file mode 100644
index 0000000..2e222d1
--- /dev/null
+++ b/native/engine/android/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ ui-sorting-group
+
diff --git a/native/engine/common/CMakeLists.txt b/native/engine/common/CMakeLists.txt
new file mode 100644
index 0000000..8ef0a93
--- /dev/null
+++ b/native/engine/common/CMakeLists.txt
@@ -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()
+
+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
+)
+
+# 引入lcc-ui-sorting-group native部分
+include(${CMAKE_CURRENT_LIST_DIR}/../lcc-ui-sorting-group-native/CMakeLists.txt)
diff --git a/native/engine/common/Classes/Game.cpp b/native/engine/common/Classes/Game.cpp
new file mode 100644
index 0000000..c15664c
--- /dev/null
+++ b/native/engine/common/Classes/Game.cpp
@@ -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);
diff --git a/native/engine/common/Classes/Game.h b/native/engine/common/Classes/Game.h
new file mode 100644
index 0000000..521615e
--- /dev/null
+++ b/native/engine/common/Classes/Game.h
@@ -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;
+};
diff --git a/native/engine/common/cocos-version.json b/native/engine/common/cocos-version.json
new file mode 100644
index 0000000..6519c54
--- /dev/null
+++ b/native/engine/common/cocos-version.json
@@ -0,0 +1 @@
+{"version":"3.6.3","skipCheck":false}
diff --git a/native/engine/common/localCfg.cmake b/native/engine/common/localCfg.cmake
new file mode 100644
index 0000000..f17333e
--- /dev/null
+++ b/native/engine/common/localCfg.cmake
@@ -0,0 +1,3 @@
+## Add or overwrite options from cfg.cmake.
+## This file is ignored from git.
+# set(NODE_EXECUTABLE /opt/...)
\ No newline at end of file
diff --git a/native/engine/lcc-ui-sorting-group-native/CMakeLists.txt b/native/engine/lcc-ui-sorting-group-native/CMakeLists.txt
new file mode 100644
index 0000000..30de0be
--- /dev/null
+++ b/native/engine/lcc-ui-sorting-group-native/CMakeLists.txt
@@ -0,0 +1,29 @@
+
+string(REPLACE "/" "\\" CMD_COCOS_X_PATH "${COCOS_X_PATH}")
+string(REPLACE "/" "\\" CMD_CMAKE_CURRENT_LIST_DIR "${CMAKE_CURRENT_LIST_DIR}")
+
+# 引擎编译添加源文件替换依赖目标
+add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_LIST_DIR}/ENGINE_REPLACE.txt
+ COMMAND copy /y "\"${CMD_CMAKE_CURRENT_LIST_DIR}\\replace\\Batcher2d.h\"" "\"${CMD_COCOS_X_PATH}\\cocos\\2d\\renderer\\Batcher2d.h\""
+ COMMAND copy /y "\"${CMD_CMAKE_CURRENT_LIST_DIR}\\replace\\Batcher2d.cpp\"" "\"${CMD_COCOS_X_PATH}\\cocos\\2d\\renderer\\Batcher2d.cpp\""
+ COMMAND copy /y "\"${CMD_CMAKE_CURRENT_LIST_DIR}\\replace\\RenderEntity.h\"" "\"${CMD_COCOS_X_PATH}\\cocos\\2d\\renderer\\RenderEntity.h\""
+ COMMAND copy /y "\"${CMD_CMAKE_CURRENT_LIST_DIR}\\replace\\RenderEntity.cpp\"" "\"${CMD_COCOS_X_PATH}\\cocos\\2d\\renderer\\RenderEntity.cpp\""
+ COMMAND echo "ENGINE_REPLACE" >> "${CMD_CMAKE_CURRENT_LIST_DIR}\\ENGINE_REPLACE.txt"
+ COMMAND echo "LCC_UI_SORTING_GROUP pre"
+ WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
+)
+add_custom_target(LCC_UI_SORTING_GROUP_ENGINE_REPLACE DEPENDS ${CMAKE_CURRENT_LIST_DIR}/ENGINE_REPLACE.txt)
+add_dependencies(${ENGINE_NAME} LCC_UI_SORTING_GROUP_ENGINE_REPLACE)
+
+# 引擎编译恢复源文件
+add_custom_command(TARGET ${ENGINE_NAME}
+ POST_BUILD
+ COMMAND copy /y "\"${CMD_CMAKE_CURRENT_LIST_DIR}\\backup\\Batcher2d.h\"" "\"${CMD_COCOS_X_PATH}\\cocos\\2d\\renderer\\Batcher2d.h\""
+ COMMAND copy /y "\"${CMD_CMAKE_CURRENT_LIST_DIR}\\backup\\Batcher2d.cpp\"" "\"${CMD_COCOS_X_PATH}\\cocos\\2d\\renderer\\Batcher2d.cpp\""
+ COMMAND copy /y "\"${CMD_CMAKE_CURRENT_LIST_DIR}\\backup\\RenderEntity.h\"" "\"${CMD_COCOS_X_PATH}\\cocos\\2d\\renderer\\RenderEntity.h\""
+ COMMAND copy /y "\"${CMD_CMAKE_CURRENT_LIST_DIR}\\backup\\RenderEntity.cpp\"" "\"${CMD_COCOS_X_PATH}\\cocos\\2d\\renderer\\RenderEntity.cpp\""
+ COMMAND del "${CMD_CMAKE_CURRENT_LIST_DIR}\\ENGINE_REPLACE.txt"
+ COMMAND echo "LCC_UI_SORTING_GROUP post"
+ WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
+)
diff --git a/native/engine/lcc-ui-sorting-group-native/backup/Batcher2d.cpp b/native/engine/lcc-ui-sorting-group-native/backup/Batcher2d.cpp
new file mode 100644
index 0000000..ba628b8
--- /dev/null
+++ b/native/engine/lcc-ui-sorting-group-native/backup/Batcher2d.cpp
@@ -0,0 +1,609 @@
+/****************************************************************************
+ 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"
+
+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();
+}
+
+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&& 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&& rootNodes) {
+ _rootNodeArr = std::move(rootNodes);
+}
+
+void Batcher2d::fillBuffersAndMergeBatches() {
+ for (auto* rootNode : _rootNodeArr) {
+ walk(rootNode, 1);
+ generateBatch(_currEntity, _currDrawInfo);
+ }
+}
+
+void Batcher2d::walk(Node* node, float parentOpacity) { // NOLINT(misc-no-recursion)
+ if (!node->isActiveInHierarchy()) {
+ return;
+ }
+ bool breakWalk = false;
+ auto* entity = static_cast(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);
+ }
+ if (entity->isEnabled()) {
+ 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);
+ }
+ 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);
+ }
+ }
+
+ // post assembler
+ if (_stencilManager->getMaskStackSize() > 0 && entity && entity->isEnabled()) {
+ handlePostRender(entity);
+ }
+}
+
+void Batcher2d::handlePostRender(RenderEntity* entity) {
+ bool isMask = entity->getIsMask();
+ if (isMask) {
+ 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(entity->getStencilStage());
+
+ if (_currHash != dataHash || dataHash == 0 || _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());
+ }
+}
+
+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(pipeline::ModelLocalBindings::SAMPLER_SPRITE), texture);
+ iter->second->bindSampler(static_cast(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(pipeline::ModelLocalBindings::SAMPLER_SPRITE), texture);
+ ds->bindSampler(static_cast(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(ccstd::string("default-clear-stencil"));
+
+ _maskClearModel = Root::getInstance()->createModel();
+ 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);
+ }
+}
+} // namespace cc
diff --git a/native/engine/lcc-ui-sorting-group-native/backup/Batcher2d.h b/native/engine/lcc-ui-sorting-group-native/backup/Batcher2d.h
new file mode 100644
index 0000000..ef22119
--- /dev/null
+++ b/native/engine/lcc-ui-sorting-group-native/backup/Batcher2d.h
@@ -0,0 +1,203 @@
+/****************************************************************************
+ 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;
+using UIMeshBufferMap = ccstd::unordered_map;
+
+class Batcher2d final {
+public:
+ Batcher2d();
+ explicit Batcher2d(Root* root);
+ ~Batcher2d();
+
+ void syncMeshBuffersToNative(uint16_t accId, ccstd::vector&& buffers);
+
+ bool initialize();
+ void update();
+ void uploadBuffers();
+ void reset();
+
+ void syncRootNodesToNative(ccstd::vector&& rootNodes);
+ void releaseDescriptorSetCache(gfx::Texture* texture, gfx::Sampler* sampler);
+
+ UIMeshBuffer* getMeshBuffer(uint16_t accId, uint16_t bufferId);
+ gfx::Device* getDevice();
+ inline ccstd::vector* getDefaultAttribute() { return &_attributes; }
+
+ void updateDescriptorSet();
+
+ void fillBuffersAndMergeBatches();
+ void walk(Node* node, float parentOpacity);
+ 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(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(temp.r) / 255.0F;
+ vbBuffer[offset++] = static_cast(temp.g) / 255.0F;
+ vbBuffer[offset++] = static_cast(temp.b) / 255.0F;
+ vbBuffer[offset++] = entity->getOpacity();
+ }
+ }
+
+ void insertMaskBatch(RenderEntity* entity);
+ void createClearModel ();
+
+ gfx::DescriptorSet* getDescriptorSet(gfx::Texture* texture, gfx::Sampler* sampler, gfx::DescriptorSetLayout* dsLayout);
+
+ StencilManager* _stencilManager{nullptr};
+
+ // weak reference
+ Root* _root{nullptr};
+ // weak reference
+ ccstd::vector _rootNodeArr;
+
+ // manage memory manually
+ ccstd::vector _batches;
+ memop::Pool _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 _meshRenderDrawInfo;
+
+ // manage memory manually
+ ccstd::unordered_map _descriptorSetCache;
+ gfx::DescriptorSetInfo _dsInfo;
+
+ UIMeshBufferMap _meshBuffersMap;
+
+ // DefaultAttribute
+ ccstd::vector _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 _maskClearModel;
+ IntrusivePtr _maskClearMtl;
+ IntrusivePtr _maskModelMesh;
+ ccstd::vector _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
diff --git a/native/engine/lcc-ui-sorting-group-native/backup/RenderEntity.cpp b/native/engine/lcc-ui-sorting-group-native/backup/RenderEntity.cpp
new file mode 100644
index 0000000..98a741b
--- /dev/null
+++ b/native/engine/lcc-ui-sorting-group-native/backup/RenderEntity.cpp
@@ -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();
+ } else {
+ ccnew_placement(&_dynamicDrawInfos) ccstd::vector();
+ }
+ _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& 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& RenderEntity::getStaticRenderDrawInfos() {
+ CC_ASSERT(_renderEntityType == RenderEntityType::STATIC);
+ return _staticDrawInfos;
+}
+} // namespace cc
diff --git a/native/engine/lcc-ui-sorting-group-native/backup/RenderEntity.h b/native/engine/lcc-ui-sorting-group-native/backup/RenderEntity.h
new file mode 100644
index 0000000..f61e1d1
--- /dev/null
+++ b/native/engine/lcc-ui-sorting-group-native/backup/RenderEntity.h
@@ -0,0 +1,159 @@
+/****************************************************************************
+ 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
+#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(_entityAttrLayout.maskMode) == MaskMode::MASK || static_cast(_entityAttrLayout.maskMode) == MaskMode::MASK_INVERTED;
+ }
+
+ inline bool getIsSubMask() const {
+ return static_cast(_entityAttrLayout.maskMode) == MaskMode::MASK_NODE || static_cast(_entityAttrLayout.maskMode) == MaskMode::MASK_NODE_INVERTED;
+ }
+
+ inline bool getIsMaskInverted() const {
+ return static_cast(_entityAttrLayout.maskMode) == MaskMode::MASK_INVERTED || static_cast(_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(_stencilStage); }
+ inline void setStencilStage(uint32_t stage) {
+ _stencilStage = static_cast(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& getStaticRenderDrawInfos();
+ RenderDrawInfo* getDynamicRenderDrawInfo(uint32_t index);
+ ccstd::vector& 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(_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(_dynamicDrawInfos.size());
+ }
+ inline RenderDrawInfo* getRenderDrawInfoAt(uint32_t index) {
+ return _renderEntityType == RenderEntityType::STATIC ? &(_staticDrawInfos[index]) : _dynamicDrawInfos[index];
+ }
+
+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 _staticDrawInfos;
+ ccstd::vector _dynamicDrawInfos;
+ };
+ StencilStage _stencilStage{StencilStage::DISABLED};
+ RenderEntityType _renderEntityType{RenderEntityType::STATIC};
+ uint8_t _staticDrawInfoSize{0};
+ bool _vbColorDirty{true};
+};
+} // namespace cc
diff --git a/native/engine/lcc-ui-sorting-group-native/readme.txt b/native/engine/lcc-ui-sorting-group-native/readme.txt
new file mode 100644
index 0000000..ac02aaf
--- /dev/null
+++ b/native/engine/lcc-ui-sorting-group-native/readme.txt
@@ -0,0 +1 @@
+cocos creator 3.6.3
\ No newline at end of file
diff --git a/native/engine/lcc-ui-sorting-group-native/replace/.vscode/settings.json b/native/engine/lcc-ui-sorting-group-native/replace/.vscode/settings.json
new file mode 100644
index 0000000..c77b39e
--- /dev/null
+++ b/native/engine/lcc-ui-sorting-group-native/replace/.vscode/settings.json
@@ -0,0 +1,8 @@
+{
+ "files.associations": {
+ "array": "cpp",
+ "initializer_list": "cpp",
+ "xutility": "cpp",
+ "algorithm": "cpp"
+ }
+}
\ No newline at end of file
diff --git a/native/engine/lcc-ui-sorting-group-native/replace/Batcher2d.cpp b/native/engine/lcc-ui-sorting-group-native/replace/Batcher2d.cpp
new file mode 100644
index 0000000..b9ef989
--- /dev/null
+++ b/native/engine/lcc-ui-sorting-group-native/replace/Batcher2d.cpp
@@ -0,0 +1,657 @@
+/****************************************************************************
+ 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
+
+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&& 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&& rootNodes) {
+ _rootNodeArr = std::move(rootNodes);
+}
+
+void Batcher2d::fillBuffersAndMergeBatches() {
+ for (auto* rootNode : _rootNodeArr) {
+ walk(rootNode, 1);
+ // CC_LOG_INFO("-------------- flushRendererCache 1 -------------- %d", _rootNodeArr.size());
+ flushRendererCache(); // LCC_UI_SORTING_GROUP
+ generateBatch(_currEntity, _currDrawInfo);
+ }
+}
+
+void Batcher2d::walk(Node* node, float parentOpacity) { // NOLINT(misc-no-recursion)
+ if (!node->isActiveInHierarchy()) {
+ return;
+ }
+ bool breakWalk = false;
+ auto* entity = static_cast(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()){
+ // 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);
+ if(entity->getSortingPriority() != 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);
+ }
+ }
+
+ // 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(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());
+ }
+}
+
+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(pipeline::ModelLocalBindings::SAMPLER_SPRITE), texture);
+ iter->second->bindSampler(static_cast(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(pipeline::ModelLocalBindings::SAMPLER_SPRITE), texture);
+ ds->bindSampler(static_cast(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(ccstd::string("default-clear-stencil"));
+
+ _maskClearModel = Root::getInstance()->createModel();
+ 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::sort(rendererCache.begin(), rendererCache.end(), [](RenderEntity* a, RenderEntity* b) { return a->getSortingPriority() < b->getSortingPriority(); });
+ }
+ // CC_LOG_INFO("flushRendererCache %d", rendererCache.size());
+ for(ccstd::vector::iterator it = rendererCache.begin(); it != rendererCache.end(); it++)
+ {
+ RenderEntity* entity = *it;
+ // CC_LOG_INFO("%f", entity->getSortingPriority());
+ 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
diff --git a/native/engine/lcc-ui-sorting-group-native/replace/Batcher2d.h b/native/engine/lcc-ui-sorting-group-native/replace/Batcher2d.h
new file mode 100644
index 0000000..25cf1cd
--- /dev/null
+++ b/native/engine/lcc-ui-sorting-group-native/replace/Batcher2d.h
@@ -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;
+using UIMeshBufferMap = ccstd::unordered_map;
+
+class Batcher2d final {
+public:
+ Batcher2d();
+ explicit Batcher2d(Root* root);
+ ~Batcher2d();
+
+ void syncMeshBuffersToNative(uint16_t accId, ccstd::vector&& buffers);
+
+ bool initialize();
+ void update();
+ void uploadBuffers();
+ void reset();
+
+ void syncRootNodesToNative(ccstd::vector&& rootNodes);
+ void releaseDescriptorSetCache(gfx::Texture* texture, gfx::Sampler* sampler);
+
+ UIMeshBuffer* getMeshBuffer(uint16_t accId, uint16_t bufferId);
+ gfx::Device* getDevice();
+ inline ccstd::vector* getDefaultAttribute() { return &_attributes; }
+
+ void updateDescriptorSet();
+
+ void fillBuffersAndMergeBatches();
+ void walk(Node* node, float parentOpacity);
+ 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(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(temp.r) / 255.0F;
+ vbBuffer[offset++] = static_cast(temp.g) / 255.0F;
+ vbBuffer[offset++] = static_cast(temp.b) / 255.0F;
+ vbBuffer[offset++] = entity->getOpacity();
+ }
+ }
+
+ void insertMaskBatch(RenderEntity* entity);
+ void createClearModel ();
+
+ // LCC_UI_SORTING_GROUP
+ ccstd::vector 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 _rootNodeArr;
+
+ // manage memory manually
+ ccstd::vector _batches;
+ memop::Pool _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 _meshRenderDrawInfo;
+
+ // manage memory manually
+ ccstd::unordered_map _descriptorSetCache;
+ gfx::DescriptorSetInfo _dsInfo;
+
+ UIMeshBufferMap _meshBuffersMap;
+
+ // DefaultAttribute
+ ccstd::vector _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 _maskClearModel;
+ IntrusivePtr _maskClearMtl;
+ IntrusivePtr _maskModelMesh;
+ ccstd::vector _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
diff --git a/native/engine/lcc-ui-sorting-group-native/replace/RenderEntity.cpp b/native/engine/lcc-ui-sorting-group-native/replace/RenderEntity.cpp
new file mode 100644
index 0000000..98a741b
--- /dev/null
+++ b/native/engine/lcc-ui-sorting-group-native/replace/RenderEntity.cpp
@@ -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();
+ } else {
+ ccnew_placement(&_dynamicDrawInfos) ccstd::vector();
+ }
+ _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& 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& RenderEntity::getStaticRenderDrawInfos() {
+ CC_ASSERT(_renderEntityType == RenderEntityType::STATIC);
+ return _staticDrawInfos;
+}
+} // namespace cc
diff --git a/native/engine/lcc-ui-sorting-group-native/replace/RenderEntity.h b/native/engine/lcc-ui-sorting-group-native/replace/RenderEntity.h
new file mode 100644
index 0000000..3df4982
--- /dev/null
+++ b/native/engine/lcc-ui-sorting-group-native/replace/RenderEntity.h
@@ -0,0 +1,161 @@
+/****************************************************************************
+ 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
+#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};
+ float sortingPriority{0.0F}; // LCC_UI_SORTING_GROUP
+ 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(_entityAttrLayout.maskMode) == MaskMode::MASK || static_cast(_entityAttrLayout.maskMode) == MaskMode::MASK_INVERTED;
+ }
+
+ inline bool getIsSubMask() const {
+ return static_cast(_entityAttrLayout.maskMode) == MaskMode::MASK_NODE || static_cast(_entityAttrLayout.maskMode) == MaskMode::MASK_NODE_INVERTED;
+ }
+
+ inline bool getIsMaskInverted() const {
+ return static_cast(_entityAttrLayout.maskMode) == MaskMode::MASK_INVERTED || static_cast(_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(_stencilStage); }
+ inline void setStencilStage(uint32_t stage) {
+ _stencilStage = static_cast(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& getStaticRenderDrawInfos();
+ RenderDrawInfo* getDynamicRenderDrawInfo(uint32_t index);
+ ccstd::vector& 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(_entityAttrLayout.colorA) / 255.F; }
+ inline float getLocalOpacity() const { return _entityAttrLayout.localOpacity; }
+ inline float getSortingPriority() const { return _entityAttrLayout.sortingPriority; } // LCC_UI_SORTING_GROUP
+ 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(_dynamicDrawInfos.size());
+ }
+ inline RenderDrawInfo* getRenderDrawInfoAt(uint32_t index) {
+ return _renderEntityType == RenderEntityType::STATIC ? &(_staticDrawInfos[index]) : _dynamicDrawInfos[index];
+ }
+
+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 _staticDrawInfos;
+ ccstd::vector _dynamicDrawInfos;
+ };
+ StencilStage _stencilStage{StencilStage::DISABLED};
+ RenderEntityType _renderEntityType{RenderEntityType::STATIC};
+ uint8_t _staticDrawInfoSize{0};
+ bool _vbColorDirty{true};
+};
+} // namespace cc