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