This commit is contained in:
lujun 2023-02-06 22:06:27 +08:00
parent f9c85e9b81
commit 934207d732
39 changed files with 3135 additions and 3 deletions

View File

@ -67,6 +67,7 @@ export function UpdateRenderEntity(renderEntity:__private._cocos_2d_renderer_ren
}, },
set: function(value) { set: function(value) {
this._sortingPriority = value; this._sortingPriority = value;
// console.log(`JSB sortingPriority ${value}`);
if (JSB) { if (JSB) {
this._floatSharedBuffer[RenderEntityFloatSharedBufferView.sortingPriority] = value; this._floatSharedBuffer[RenderEntityFloatSharedBufferView.sortingPriority] = value;
} }

View File

@ -27,6 +27,7 @@ if(!('sortingPriority' in UIRenderer.prototype)){
}, },
set: function(value) { set: function(value) {
this._sortingPriority = value; this._sortingPriority = value;
this._renderEntity.sortingPriority = value;
}, },
enumerable: true enumerable: true
}); });

View File

@ -66,7 +66,9 @@ UI.prototype.flushRendererCache = function(){
if(this.rendererOrder){ if(this.rendererOrder){
rendererCache.sort((a, b)=>{ return a._sortingPriority - b._sortingPriority; }); rendererCache.sort((a, b)=>{ return a._sortingPriority - b._sortingPriority; });
} }
// console.log(`flushRendererCache ${rendererCache.length}`);
for(let render of rendererCache){ for(let render of rendererCache){
// console.log(`${render.node.name} render hash ${render.renderData.dataHash}`);
render.fillBuffers(this); render.fillBuffers(this);
if(render.sortingOpacity >= 0){ if(render.sortingOpacity >= 0){
updateOpacity(render.renderData, render.sortingOpacity); updateOpacity(render.renderData, render.sortingOpacity);

View File

@ -945,7 +945,7 @@
"__expectedType__": "cc.SpriteFrame" "__expectedType__": "cc.SpriteFrame"
} }
], ],
"listItemMax": 200, "listItemMax": 2,
"_id": "9fuu+PfOFHPqnvdYJwsexB" "_id": "9fuu+PfOFHPqnvdYJwsexB"
}, },
{ {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,125 @@
/****************************************************************************
Copyright (c) 2015-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
package com.cocos.game;
import android.os.Bundle;
import android.content.Intent;
import android.content.res.Configuration;
import com.cocos.service.SDKWrapper;
import com.cocos.lib.CocosActivity;
public class AppActivity extends CocosActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// DO OTHER INITIALIZATION BELOW
SDKWrapper.shared().init(this);
}
@Override
protected void onResume() {
super.onResume();
SDKWrapper.shared().onResume();
}
@Override
protected void onPause() {
super.onPause();
SDKWrapper.shared().onPause();
}
@Override
protected void onDestroy() {
super.onDestroy();
// Workaround in https://stackoverflow.com/questions/16283079/re-launch-of-activity-on-home-button-but-only-the-first-time/16447508
if (!isTaskRoot()) {
return;
}
SDKWrapper.shared().onDestroy();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
SDKWrapper.shared().onActivityResult(requestCode, resultCode, data);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
SDKWrapper.shared().onNewIntent(intent);
}
@Override
protected void onRestart() {
super.onRestart();
SDKWrapper.shared().onRestart();
}
@Override
protected void onStop() {
super.onStop();
SDKWrapper.shared().onStop();
}
@Override
public void onBackPressed() {
SDKWrapper.shared().onBackPressed();
super.onBackPressed();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
SDKWrapper.shared().onConfigurationChanged(newConfig);
super.onConfigurationChanged(newConfig);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
SDKWrapper.shared().onRestoreInstanceState(savedInstanceState);
super.onRestoreInstanceState(savedInstanceState);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
SDKWrapper.shared().onSaveInstanceState(outState);
super.onSaveInstanceState(outState);
}
@Override
protected void onStart() {
SDKWrapper.shared().onStart();
super.onStart();
}
@Override
public void onLowMemory() {
SDKWrapper.shared().onLowMemory();
super.onLowMemory();
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,125 @@
/****************************************************************************
Copyright (c) 2015-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
package com.cocos.game;
import android.os.Bundle;
import android.content.Intent;
import android.content.res.Configuration;
import com.cocos.service.SDKWrapper;
import com.cocos.lib.CocosActivity;
public class InstantActivity extends CocosActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// DO OTHER INITIALIZATION BELOW
SDKWrapper.shared().init(this);
}
@Override
protected void onResume() {
super.onResume();
SDKWrapper.shared().onResume();
}
@Override
protected void onPause() {
super.onPause();
SDKWrapper.shared().onPause();
}
@Override
protected void onDestroy() {
super.onDestroy();
// Workaround in https://stackoverflow.com/questions/16283079/re-launch-of-activity-on-home-button-but-only-the-first-time/16447508
if (!isTaskRoot()) {
return;
}
SDKWrapper.shared().onDestroy();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
SDKWrapper.shared().onActivityResult(requestCode, resultCode, data);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
SDKWrapper.shared().onNewIntent(intent);
}
@Override
protected void onRestart() {
super.onRestart();
SDKWrapper.shared().onRestart();
}
@Override
protected void onStop() {
super.onStop();
SDKWrapper.shared().onStop();
}
@Override
public void onBackPressed() {
SDKWrapper.shared().onBackPressed();
super.onBackPressed();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
SDKWrapper.shared().onConfigurationChanged(newConfig);
super.onConfigurationChanged(newConfig);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
SDKWrapper.shared().onRestoreInstanceState(savedInstanceState);
super.onRestoreInstanceState(savedInstanceState);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
SDKWrapper.shared().onSaveInstanceState(outState);
super.onSaveInstanceState(outState);
}
@Override
protected void onStart() {
SDKWrapper.shared().onStart();
super.onStart();
}
@Override
public void onLowMemory() {
SDKWrapper.shared().onLowMemory();
super.onLowMemory();
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

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

View File

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

View File

@ -0,0 +1,65 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You
shall not use Cocos Creator software for developing other software or tools
that's used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to
you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "Game.h"
#ifndef GAME_NAME
#define GAME_NAME "CocosGame";
#endif
#ifndef SCRIPT_XXTEAKEY
#define SCRIPT_XXTEAKEY "";
#endif
Game::Game() = default;
int Game::init() {
_windowInfo.title = GAME_NAME;
// configurate window size
// _windowInfo.height = 600;
// _windowInfo.width = 800;
#if CC_DEBUG
_debuggerInfo.enabled = true;
#else
_debuggerInfo.enabled = false;
#endif
_debuggerInfo.port = 6086;
_debuggerInfo.address = "0.0.0.0";
_debuggerInfo.pauseOnStart = false;
_xxteaKey = SCRIPT_XXTEAKEY;
BaseGame::init();
return 0;
}
void Game::onPause() { BaseGame::onPause(); }
void Game::onResume() { BaseGame::onResume(); }
void Game::onClose() { BaseGame::onClose(); }
CC_REGISTER_APPLICATION(Game);

View File

@ -0,0 +1,44 @@
/****************************************************************************
Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You
shall not use Cocos Creator software for developing other software or tools
that's used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to
you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "cocos/cocos.h"
/**
@brief The cocos2d Application.
The reason for implement as private inheritance is to hide some interface call
by Director.
*/
class Game : public cc::BaseGame {
public:
Game();
int init() override;
// bool init() override;
void onPause() override;
void onResume() override;
void onClose() override;
};

View File

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

View File

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

View File

@ -0,0 +1,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}
)

View File

@ -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<UIMeshBuffer*>&& buffers) {
_meshBuffersMap[accId] = std::move(buffers);
}
UIMeshBuffer* Batcher2d::getMeshBuffer(uint16_t accId, uint16_t bufferId) { // NOLINT(bugprone-easily-swappable-parameters)
const auto& map = _meshBuffersMap[accId];
return map[bufferId];
}
gfx::Device* Batcher2d::getDevice() {
if (_device == nullptr) {
_device = Root::getInstance()->getDevice();
}
return _device;
}
void Batcher2d::updateDescriptorSet() {
}
void Batcher2d::syncRootNodesToNative(ccstd::vector<Node*>&& rootNodes) {
_rootNodeArr = std::move(rootNodes);
}
void Batcher2d::fillBuffersAndMergeBatches() {
for (auto* rootNode : _rootNodeArr) {
walk(rootNode, 1);
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<RenderEntity*>(node->getUserData());
if (entity) {
if (entity->getColorDirty()) {
float localOpacity = entity->getLocalOpacity();
float localColorAlpha = entity->getColorAlpha();
entity->setOpacity(parentOpacity * localOpacity * localColorAlpha);
entity->setColorDirty(false);
entity->setVBColorDirty(true);
}
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<StencilStage>(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<uint32_t>(pipeline::ModelLocalBindings::SAMPLER_SPRITE), texture);
iter->second->bindSampler(static_cast<uint32_t>(pipeline::ModelLocalBindings::SAMPLER_SPRITE), sampler);
}
iter->second->forceUpdate();
return iter->second;
}
_dsInfo.layout = dsLayout;
auto* ds = getDevice()->createDescriptorSet(_dsInfo);
if (texture != nullptr && sampler != nullptr) {
ds->bindTexture(static_cast<uint32_t>(pipeline::ModelLocalBindings::SAMPLER_SPRITE), texture);
ds->bindSampler(static_cast<uint32_t>(pipeline::ModelLocalBindings::SAMPLER_SPRITE), sampler);
}
ds->update();
_descriptorSetCache.emplace(hash, ds);
return ds;
}
void Batcher2d::releaseDescriptorSetCache(gfx::Texture* texture, gfx::Sampler* sampler) {
ccstd::hash_t hash = 2;
size_t textureHash;
if (texture != nullptr) {
textureHash = boost::hash_value(texture);
ccstd::hash_combine(hash, textureHash);
}
if (sampler != nullptr) {
ccstd::hash_combine(hash, sampler->getHash());
}
auto iter = _descriptorSetCache.find(hash);
if (iter != _descriptorSetCache.end()) {
delete iter->second;
_descriptorSetCache.erase(hash);
}
}
bool Batcher2d::initialize() {
_isInit = true;
return _isInit;
}
void Batcher2d::update() {
fillBuffersAndMergeBatches();
resetRenderStates();
for (const auto& scene : Root::getInstance()->getScenes()) {
for (auto* batch : _batches) {
scene->addBatch(batch);
}
}
}
void Batcher2d::uploadBuffers() {
if (_batches.empty()) {
return;
}
for (auto& meshRenderData : _meshRenderDrawInfo) {
meshRenderData->uploadBuffers();
}
for (auto& map : _meshBuffersMap) {
for (auto& buffer : map.second) {
buffer->uploadBuffers();
buffer->reset();
}
}
updateDescriptorSet();
}
void Batcher2d::reset() {
for (auto& batch : _batches) {
batch->clear();
_drawBatchPool.free(batch);
}
_batches.clear();
for (auto& meshRenderData : _meshRenderDrawInfo) {
meshRenderData->resetMeshIA();
}
_meshRenderDrawInfo.clear();
// meshDataArray
for (auto& map : _meshBuffersMap) {
for (auto& buffer : map.second) {
if (buffer) {
buffer->resetIA();
}
}
}
//meshBuffer cannot clear because it is not transported at every frame.
_currMeshBuffer = nullptr;
_indexStart = 0;
_currHash = 0;
_currLayer = 0;
_currMaterial = nullptr;
_currTexture = nullptr;
_currSampler = nullptr;
// stencilManager
}
void Batcher2d::insertMaskBatch(RenderEntity* entity){
generateBatch(_currEntity, _currDrawInfo);
resetRenderStates();
createClearModel();
_maskClearModel->setNode(entity->getNode());
_maskClearModel->setTransform(entity->getNode());
_stencilManager->pushMask();
auto stage = _stencilManager->clear(entity);
gfx::DepthStencilState* depthStencil = nullptr;
ccstd::hash_t dssHash = 0;
if(_maskClearMtl != nullptr){
depthStencil = _stencilManager->getDepthStencilState(stage, _maskClearMtl);
dssHash = _stencilManager->getStencilHash(stage);
}
// Model
if (_maskClearModel == nullptr) return;
auto stamp = CC_CURRENT_ENGINE()->getTotalFrames();
_maskClearModel->updateTransform(stamp);
_maskClearModel->updateUBOs(stamp);
const auto& subModelList = _maskClearModel->getSubModels();
for (const auto& submodel : subModelList) {
auto* curdrawBatch = _drawBatchPool.alloc();
curdrawBatch->setVisFlags(entity->getNode()->getLayer());
curdrawBatch->setModel(_maskClearModel);
curdrawBatch->setInputAssembler(submodel->getInputAssembler());
curdrawBatch->setDescriptorSet(submodel->getDescriptorSet());
curdrawBatch->fillPass(_maskClearMtl, depthStencil, dssHash, &(submodel->getPatches()));
_batches.push_back(curdrawBatch);
}
_stencilManager->enterLevel(entity);
}
void Batcher2d::createClearModel() {
if (_maskClearModel == nullptr) {
_maskClearMtl = BuiltinResMgr::getInstance()->get<Material>(ccstd::string("default-clear-stencil"));
_maskClearModel = Root::getInstance()->createModel<scene::Model>();
uint32_t stride = 12;// vfmt
auto* vertexBuffer = _device->createBuffer({
gfx::BufferUsageBit::VERTEX | gfx::BufferUsageBit::TRANSFER_DST,
gfx::MemoryUsageBit::DEVICE,
4 * stride,
stride,
});
const float vertices[] = {-1, -1, 0, 1, -1, 0, -1, 1, 0, 1, 1, 0};
vertexBuffer->update(vertices);
auto* indexBuffer = _device->createBuffer({
gfx::BufferUsageBit::INDEX | gfx::BufferUsageBit::TRANSFER_DST,
gfx::MemoryUsageBit::DEVICE,
6 * sizeof(uint16_t),
sizeof(uint16_t),
});
const uint16_t indices[] = {0, 2, 1, 2, 1, 3};
indexBuffer->update(indices);
gfx::BufferList vbReference;
vbReference.emplace_back(vertexBuffer);
_maskModelMesh = ccnew RenderingSubMesh(vbReference, _maskAttributes, _primitiveMode, indexBuffer);
_maskModelMesh->setSubMeshIdx(0);
_maskClearModel->initSubModel(0, _maskModelMesh, _maskClearMtl);
}
}
} // namespace cc

View File

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

View File

@ -0,0 +1,116 @@
/****************************************************************************
Copyright (c) 2019-2021 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "2d/renderer/RenderEntity.h"
#include "2d/renderer/Batcher2d.h"
#include "bindings/utils/BindingUtils.h"
namespace cc {
RenderEntity::RenderEntity(RenderEntityType type) : _renderEntityType(type) {
if (type == RenderEntityType::STATIC) {
ccnew_placement(&_staticDrawInfos) std::array<RenderDrawInfo, RenderEntity::STATIC_DRAW_INFO_CAPACITY>();
} else {
ccnew_placement(&_dynamicDrawInfos) ccstd::vector<RenderDrawInfo*>();
}
_entitySharedBufferActor.initialize(&_entityAttrLayout, sizeof(EntityAttrLayout));
}
RenderEntity::~RenderEntity() {
if (_renderEntityType == RenderEntityType::STATIC) {
_staticDrawInfos.~array();
} else {
_dynamicDrawInfos.~vector();
}
};
void RenderEntity::addDynamicRenderDrawInfo(RenderDrawInfo* drawInfo) {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
_dynamicDrawInfos.push_back(drawInfo);
}
void RenderEntity::setDynamicRenderDrawInfo(RenderDrawInfo* drawInfo, uint32_t index) {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
if (index < _dynamicDrawInfos.size()) {
_dynamicDrawInfos[index] = drawInfo;
}
}
void RenderEntity::removeDynamicRenderDrawInfo() {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
if (_dynamicDrawInfos.empty()) return;
_dynamicDrawInfos.pop_back(); // warning: memory leaking & crash
}
void RenderEntity::clearDynamicRenderDrawInfos() {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
_dynamicDrawInfos.clear();
}
void RenderEntity::clearStaticRenderDrawInfos() {
CC_ASSERT(_renderEntityType == RenderEntityType::STATIC);
for (uint32_t i = 0; i < _staticDrawInfoSize; i++) {
RenderDrawInfo& drawInfo = _staticDrawInfos[i];
drawInfo.resetDrawInfo();
}
_staticDrawInfoSize = 0;
}
void RenderEntity::setNode(Node* node) {
if (_node) {
_node->setUserData(nullptr);
}
_node = node;
if (_node) {
_node->setUserData(this);
}
}
void RenderEntity::setRenderTransform(Node* renderTransform) {
_renderTransform = renderTransform;
}
RenderDrawInfo* RenderEntity::getDynamicRenderDrawInfo(uint32_t index) {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
if (index >= _dynamicDrawInfos.size()) {
return nullptr;
}
return _dynamicDrawInfos[index];
}
ccstd::vector<RenderDrawInfo*>& RenderEntity::getDynamicRenderDrawInfos() {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
return _dynamicDrawInfos;
}
void RenderEntity::setStaticDrawInfoSize(uint32_t size) {
CC_ASSERT(_renderEntityType == RenderEntityType::STATIC && size <= RenderEntity::STATIC_DRAW_INFO_CAPACITY);
_staticDrawInfoSize = size;
}
RenderDrawInfo* RenderEntity::getStaticRenderDrawInfo(uint32_t index) {
CC_ASSERT(_renderEntityType == RenderEntityType::STATIC && index < _staticDrawInfoSize);
return &(_staticDrawInfos[index]);
}
std::array<RenderDrawInfo, RenderEntity::STATIC_DRAW_INFO_CAPACITY>& RenderEntity::getStaticRenderDrawInfos() {
CC_ASSERT(_renderEntityType == RenderEntityType::STATIC);
return _staticDrawInfos;
}
} // namespace cc

View File

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

View File

@ -0,0 +1 @@
cocos creator 3.6.3

View File

@ -0,0 +1,8 @@
{
"files.associations": {
"array": "cpp",
"initializer_list": "cpp",
"xutility": "cpp",
"algorithm": "cpp"
}
}

View File

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

View File

@ -0,0 +1,208 @@
/****************************************************************************
Copyright (c) 2019-2021 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "2d/renderer/RenderDrawInfo.h"
#include "2d/renderer/RenderEntity.h"
#include "2d/renderer/UIMeshBuffer.h"
#include "base/Macros.h"
#include "base/Ptr.h"
#include "base/TypeDef.h"
#include "core/assets/Material.h"
#include "core/memop/Pool.h"
#include "renderer/gfx-base/GFXTexture.h"
#include "renderer/gfx-base/states/GFXSampler.h"
#include "scene/DrawBatch2D.h"
namespace cc {
class Root;
using UIMeshBufferArray = ccstd::vector<UIMeshBuffer*>;
using UIMeshBufferMap = ccstd::unordered_map<uint16_t, UIMeshBufferArray>;
class Batcher2d final {
public:
Batcher2d();
explicit Batcher2d(Root* root);
~Batcher2d();
void syncMeshBuffersToNative(uint16_t accId, ccstd::vector<UIMeshBuffer*>&& buffers);
bool initialize();
void update();
void uploadBuffers();
void reset();
void syncRootNodesToNative(ccstd::vector<Node*>&& rootNodes);
void releaseDescriptorSetCache(gfx::Texture* texture, gfx::Sampler* sampler);
UIMeshBuffer* getMeshBuffer(uint16_t accId, uint16_t bufferId);
gfx::Device* getDevice();
inline ccstd::vector<gfx::Attribute>* getDefaultAttribute() { return &_attributes; }
void updateDescriptorSet();
void fillBuffersAndMergeBatches();
void walk(Node* node, float parentOpacity);
void handlePostRender(RenderEntity* entity);
void handleDrawInfo(RenderEntity* entity, RenderDrawInfo* drawInfo, Node* node);
void handleComponentDraw(RenderEntity* entity, RenderDrawInfo* drawInfo, Node* node);
void handleModelDraw(RenderEntity* entity, RenderDrawInfo* drawInfo);
void handleMiddlewareDraw(RenderEntity* entity, RenderDrawInfo* drawInfo);
void handleSubNode(RenderEntity* entity, RenderDrawInfo* drawInfo);
void generateBatch(RenderEntity* entity, RenderDrawInfo* drawInfo);
void generateBatchForMiddleware(RenderEntity* entity, RenderDrawInfo* drawInfo);
void resetRenderStates();
private:
bool _isInit = false;
inline void fillIndexBuffers(RenderDrawInfo* drawInfo) { // NOLINT(readability-convert-member-functions-to-static)
uint16_t* ib = drawInfo->getIDataBuffer();
UIMeshBuffer* buffer = drawInfo->getMeshBuffer();
uint32_t indexOffset = buffer->getIndexOffset();
uint16_t* indexb = drawInfo->getIbBuffer();
uint32_t indexCount = drawInfo->getIbCount();
memcpy(&ib[indexOffset], indexb, indexCount * sizeof(uint16_t));
indexOffset += indexCount;
buffer->setIndexOffset(indexOffset);
}
inline void fillVertexBuffers(RenderEntity* entity, RenderDrawInfo* drawInfo) { // NOLINT(readability-convert-member-functions-to-static)
Node* node = entity->getNode();
const Mat4& matrix = node->getWorldMatrix();
uint8_t stride = drawInfo->getStride();
uint32_t size = drawInfo->getVbCount() * stride;
float* vbBuffer = drawInfo->getVbBuffer();
for (int i = 0; i < size; i += stride) {
Render2dLayout* curLayout = drawInfo->getRender2dLayout(i);
// make sure that the layout of Vec3 is three consecutive floats
static_assert(sizeof(Vec3) == 3 * sizeof(float));
// cast to reduce value copy instructions
reinterpret_cast<Vec3*>(vbBuffer + i)->transformMat4(curLayout->position, matrix);
}
}
inline void setIndexRange(RenderDrawInfo* drawInfo) { // NOLINT(readability-convert-member-functions-to-static)
UIMeshBuffer* buffer = drawInfo->getMeshBuffer();
uint32_t indexOffset = drawInfo->getIndexOffset();
uint32_t indexCount = drawInfo->getIbCount();
indexOffset += indexCount;
if (buffer->getIndexOffset() < indexOffset) {
buffer->setIndexOffset(indexOffset);
}
}
inline void fillColors(RenderEntity* entity, RenderDrawInfo* drawInfo) { // NOLINT(readability-convert-member-functions-to-static)
Color temp = entity->getColor();
uint8_t stride = drawInfo->getStride();
uint32_t size = drawInfo->getVbCount() * stride;
float* vbBuffer = drawInfo->getVbBuffer();
uint32_t offset = 0;
for (int i = 0; i < size; i += stride) {
offset = i + 5;
vbBuffer[offset++] = static_cast<float>(temp.r) / 255.0F;
vbBuffer[offset++] = static_cast<float>(temp.g) / 255.0F;
vbBuffer[offset++] = static_cast<float>(temp.b) / 255.0F;
vbBuffer[offset++] = entity->getOpacity();
}
}
void insertMaskBatch(RenderEntity* entity);
void createClearModel ();
// LCC_UI_SORTING_GROUP
ccstd::vector<RenderEntity*> rendererCache;
bool rendererOrder;
void flushRendererCache();
gfx::DescriptorSet* getDescriptorSet(gfx::Texture* texture, gfx::Sampler* sampler, gfx::DescriptorSetLayout* dsLayout);
StencilManager* _stencilManager{nullptr};
// weak reference
Root* _root{nullptr};
// weak reference
ccstd::vector<Node*> _rootNodeArr;
// manage memory manually
ccstd::vector<scene::DrawBatch2D*> _batches;
memop::Pool<scene::DrawBatch2D> _drawBatchPool;
// weak reference
gfx::Device* _device{nullptr}; // use getDevice()
// weak reference
RenderEntity* _currEntity{nullptr};
// weak reference
RenderDrawInfo* _currDrawInfo{nullptr};
// weak reference
UIMeshBuffer* _currMeshBuffer{nullptr};
uint32_t _indexStart{0};
ccstd::hash_t _currHash{0};
uint32_t _currLayer{0};
StencilStage _currStencilStage{StencilStage::DISABLED};
// weak reference
Material* _currMaterial{nullptr};
// weak reference
gfx::Texture* _currTexture{nullptr};
// weak reference
gfx::Sampler* _currSampler{nullptr};
ccstd::hash_t _currSamplerHash{0};
// weak reference
ccstd::vector<RenderDrawInfo*> _meshRenderDrawInfo;
// manage memory manually
ccstd::unordered_map<ccstd::hash_t, gfx::DescriptorSet*> _descriptorSetCache;
gfx::DescriptorSetInfo _dsInfo;
UIMeshBufferMap _meshBuffersMap;
// DefaultAttribute
ccstd::vector<gfx::Attribute> _attributes{
gfx::Attribute{gfx::ATTR_NAME_POSITION, gfx::Format::RGB32F},
gfx::Attribute{gfx::ATTR_NAME_TEX_COORD, gfx::Format::RG32F},
gfx::Attribute{gfx::ATTR_NAME_COLOR, gfx::Format::RGBA32F},
};
// Mask use
IntrusivePtr<scene::Model> _maskClearModel;
IntrusivePtr<Material> _maskClearMtl;
IntrusivePtr<RenderingSubMesh> _maskModelMesh;
ccstd::vector<gfx::Attribute> _maskAttributes{
gfx::Attribute{gfx::ATTR_NAME_POSITION, gfx::Format::RGB32F},
};
gfx::PrimitiveMode _primitiveMode{gfx::PrimitiveMode::TRIANGLE_LIST};
CC_DISALLOW_COPY_MOVE_ASSIGN(Batcher2d);
};
} // namespace cc

View File

@ -0,0 +1,116 @@
/****************************************************************************
Copyright (c) 2019-2021 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "2d/renderer/RenderEntity.h"
#include "2d/renderer/Batcher2d.h"
#include "bindings/utils/BindingUtils.h"
namespace cc {
RenderEntity::RenderEntity(RenderEntityType type) : _renderEntityType(type) {
if (type == RenderEntityType::STATIC) {
ccnew_placement(&_staticDrawInfos) std::array<RenderDrawInfo, RenderEntity::STATIC_DRAW_INFO_CAPACITY>();
} else {
ccnew_placement(&_dynamicDrawInfos) ccstd::vector<RenderDrawInfo*>();
}
_entitySharedBufferActor.initialize(&_entityAttrLayout, sizeof(EntityAttrLayout));
}
RenderEntity::~RenderEntity() {
if (_renderEntityType == RenderEntityType::STATIC) {
_staticDrawInfos.~array();
} else {
_dynamicDrawInfos.~vector();
}
};
void RenderEntity::addDynamicRenderDrawInfo(RenderDrawInfo* drawInfo) {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
_dynamicDrawInfos.push_back(drawInfo);
}
void RenderEntity::setDynamicRenderDrawInfo(RenderDrawInfo* drawInfo, uint32_t index) {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
if (index < _dynamicDrawInfos.size()) {
_dynamicDrawInfos[index] = drawInfo;
}
}
void RenderEntity::removeDynamicRenderDrawInfo() {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
if (_dynamicDrawInfos.empty()) return;
_dynamicDrawInfos.pop_back(); // warning: memory leaking & crash
}
void RenderEntity::clearDynamicRenderDrawInfos() {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
_dynamicDrawInfos.clear();
}
void RenderEntity::clearStaticRenderDrawInfos() {
CC_ASSERT(_renderEntityType == RenderEntityType::STATIC);
for (uint32_t i = 0; i < _staticDrawInfoSize; i++) {
RenderDrawInfo& drawInfo = _staticDrawInfos[i];
drawInfo.resetDrawInfo();
}
_staticDrawInfoSize = 0;
}
void RenderEntity::setNode(Node* node) {
if (_node) {
_node->setUserData(nullptr);
}
_node = node;
if (_node) {
_node->setUserData(this);
}
}
void RenderEntity::setRenderTransform(Node* renderTransform) {
_renderTransform = renderTransform;
}
RenderDrawInfo* RenderEntity::getDynamicRenderDrawInfo(uint32_t index) {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
if (index >= _dynamicDrawInfos.size()) {
return nullptr;
}
return _dynamicDrawInfos[index];
}
ccstd::vector<RenderDrawInfo*>& RenderEntity::getDynamicRenderDrawInfos() {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
return _dynamicDrawInfos;
}
void RenderEntity::setStaticDrawInfoSize(uint32_t size) {
CC_ASSERT(_renderEntityType == RenderEntityType::STATIC && size <= RenderEntity::STATIC_DRAW_INFO_CAPACITY);
_staticDrawInfoSize = size;
}
RenderDrawInfo* RenderEntity::getStaticRenderDrawInfo(uint32_t index) {
CC_ASSERT(_renderEntityType == RenderEntityType::STATIC && index < _staticDrawInfoSize);
return &(_staticDrawInfos[index]);
}
std::array<RenderDrawInfo, RenderEntity::STATIC_DRAW_INFO_CAPACITY>& RenderEntity::getStaticRenderDrawInfos() {
CC_ASSERT(_renderEntityType == RenderEntityType::STATIC);
return _staticDrawInfos;
}
} // namespace cc

View File

@ -0,0 +1,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 <array>
#include "2d/renderer/RenderDrawInfo.h"
#include "2d/renderer/StencilManager.h"
#include "base/Macros.h"
#include "base/TypeDef.h"
#include "bindings/utils/BindingUtils.h"
#include "core/ArrayBuffer.h"
#include "core/scene-graph/Node.h"
namespace cc {
class Batcher2d;
enum class RenderEntityType : uint8_t {
STATIC,
DYNAMIC,
CROSSED,
};
enum class MaskMode : uint8_t {
NONE,
MASK,
MASK_INVERTED,
MASK_NODE,
MASK_NODE_INVERTED
};
struct EntityAttrLayout {
float localOpacity{1.0F};
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<MaskMode>(_entityAttrLayout.maskMode) == MaskMode::MASK || static_cast<MaskMode>(_entityAttrLayout.maskMode) == MaskMode::MASK_INVERTED;
}
inline bool getIsSubMask() const {
return static_cast<MaskMode>(_entityAttrLayout.maskMode) == MaskMode::MASK_NODE || static_cast<MaskMode>(_entityAttrLayout.maskMode) == MaskMode::MASK_NODE_INVERTED;
}
inline bool getIsMaskInverted() const {
return static_cast<MaskMode>(_entityAttrLayout.maskMode) == MaskMode::MASK_INVERTED || static_cast<MaskMode>(_entityAttrLayout.maskMode) == MaskMode::MASK_NODE_INVERTED;
}
inline bool getUseLocal() const { return _entityAttrLayout.useLocal; }
inline void setUseLocal(bool useLocal) {
_entityAttrLayout.useLocal = useLocal;
}
inline Node* getNode() const { return _node; }
void setNode(Node* node);
inline Node* getRenderTransform() const { return _renderTransform; }
void setRenderTransform(Node* renderTransform);
inline uint32_t getStencilStage() const { return static_cast<uint32_t>(_stencilStage); }
inline void setStencilStage(uint32_t stage) {
_stencilStage = static_cast<StencilStage>(stage);
}
inline StencilStage getEnumStencilStage() const { return _stencilStage; }
inline void setEnumStencilStage(StencilStage stage) {
_stencilStage = stage;
}
inline RenderEntityType getRenderEntityType() const { return _renderEntityType; };
inline uint32_t getStaticDrawInfoSize() const { return _staticDrawInfoSize; };
void setStaticDrawInfoSize(uint32_t size);
RenderDrawInfo* getStaticRenderDrawInfo(uint32_t index);
std::array<RenderDrawInfo, RenderEntity::STATIC_DRAW_INFO_CAPACITY>& getStaticRenderDrawInfos();
RenderDrawInfo* getDynamicRenderDrawInfo(uint32_t index);
ccstd::vector<RenderDrawInfo*>& getDynamicRenderDrawInfos();
inline se::Object* getEntitySharedBufferForJS() const { return _entitySharedBufferActor.getSharedArrayBufferObject(); }
inline bool getColorDirty() const { return _entityAttrLayout.colorDirtyBit != 0; }
inline void setColorDirty(bool dirty) { _entityAttrLayout.colorDirtyBit = dirty ? 1 : 0; }
inline bool getVBColorDirty() const { return _vbColorDirty; }
inline void setVBColorDirty(bool vbColorDirty) { _vbColorDirty = vbColorDirty; }
inline Color getColor() const { return Color(_entityAttrLayout.colorR, _entityAttrLayout.colorG, _entityAttrLayout.colorB, _entityAttrLayout.colorA); }
inline float getColorAlpha() const { return static_cast<float>(_entityAttrLayout.colorA) / 255.F; }
inline float getLocalOpacity() const { return _entityAttrLayout.localOpacity; }
inline float 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<uint32_t>(_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<RenderDrawInfo, RenderEntity::STATIC_DRAW_INFO_CAPACITY> _staticDrawInfos;
ccstd::vector<RenderDrawInfo*> _dynamicDrawInfos;
};
StencilStage _stencilStage{StencilStage::DISABLED};
RenderEntityType _renderEntityType{RenderEntityType::STATIC};
uint8_t _staticDrawInfoSize{0};
bool _vbColorDirty{true};
};
} // namespace cc