@@ -783,6 +783,21 @@ export class CoreNode extends EventEmitter {
783783 if ( this . textureOptions . preload ) {
784784 texture . ctxTexture . load ( ) ;
785785 }
786+
787+ texture . on ( 'loaded' , this . onTextureLoaded ) ;
788+ texture . on ( 'failed' , this . onTextureFailed ) ;
789+ texture . on ( 'freed' , this . onTextureFreed ) ;
790+
791+ // If the parent is a render texture, the initial texture status
792+ // will be set to freed until the texture is processed by the
793+ // Render RTT nodes. So we only need to listen fo changes and
794+ // no need to check the texture.state until we restructure how
795+ // textures are being processed.
796+ if ( this . parentHasRenderTexture ) {
797+ this . notifyParentRTTOfUpdate ( ) ;
798+ return ;
799+ }
800+
786801 if ( texture . state === 'loaded' ) {
787802 assertTruthy ( texture . dimensions ) ;
788803 this . onTextureLoaded ( texture , texture . dimensions ) ;
@@ -792,9 +807,6 @@ export class CoreNode extends EventEmitter {
792807 } else if ( texture . state === 'freed' ) {
793808 this . onTextureFreed ( texture ) ;
794809 }
795- texture . on ( 'loaded' , this . onTextureLoaded ) ;
796- texture . on ( 'failed' , this . onTextureFailed ) ;
797- texture . on ( 'freed' , this . onTextureFreed ) ;
798810 } ) ;
799811 }
800812
@@ -822,9 +834,8 @@ export class CoreNode extends EventEmitter {
822834 this . stage . requestRender ( ) ;
823835
824836 // If parent has a render texture, flag that we need to update
825- // @todo : Reserve type for RTT updates
826837 if ( this . parentHasRenderTexture ) {
827- this . setRTTUpdates ( 1 ) ;
838+ this . notifyParentRTTOfUpdate ( ) ;
828839 }
829840
830841 this . emit ( 'loaded' , {
@@ -839,13 +850,23 @@ export class CoreNode extends EventEmitter {
839850 } ;
840851
841852 private onTextureFailed : TextureFailedEventHandler = ( _ , error ) => {
853+ // If parent has a render texture, flag that we need to update
854+ if ( this . parentHasRenderTexture ) {
855+ this . notifyParentRTTOfUpdate ( ) ;
856+ }
857+
842858 this . emit ( 'failed' , {
843859 type : 'texture' ,
844860 error,
845861 } satisfies NodeTextureFailedPayload ) ;
846862 } ;
847863
848864 private onTextureFreed : TextureFreedEventHandler = ( ) => {
865+ // If parent has a render texture, flag that we need to update
866+ if ( this . parentHasRenderTexture ) {
867+ this . notifyParentRTTOfUpdate ( ) ;
868+ }
869+
849870 this . emit ( 'freed' , {
850871 type : 'texture' ,
851872 } satisfies NodeTextureFreedPayload ) ;
@@ -866,24 +887,10 @@ export class CoreNode extends EventEmitter {
866887 const parent = this . props . parent ;
867888 if ( ! parent ) return ;
868889
869- // Inform the parent if it doesn’t already have a child update
870890 if ( ( parent . updateType & UpdateType . Children ) === 0 ) {
891+ // Inform the parent if it doesn’t already have a child update
871892 parent . setUpdateType ( UpdateType . Children ) ;
872893 }
873-
874- if ( this . parentHasRenderTexture === false ) return ;
875-
876- if ( this . rtt === false ) {
877- if ( ( parent . updateType & UpdateType . RenderTexture ) === 0 ) {
878- this . setRTTUpdates ( type ) ;
879- parent . setUpdateType ( UpdateType . RenderTexture ) ;
880- }
881- }
882-
883- // If this node has outstanding RTT updates, propagate them
884- if ( this . hasRTTupdates ) {
885- this . setRTTUpdates ( type ) ;
886- }
887894 }
888895
889896 sortChildren ( ) {
@@ -988,24 +995,11 @@ export class CoreNode extends EventEmitter {
988995 const parent = this . props . parent ;
989996 let renderState = null ;
990997
991- if ( this . updateType & UpdateType . ParentRenderTexture ) {
992- let p = this . parent ;
993- while ( p ) {
994- if ( p . rtt ) {
995- this . parentHasRenderTexture = true ;
996- }
997- p = p . parent ;
998- }
999- }
1000-
1001- // If we have render texture updates and not already running a full update
1002- if (
1003- this . updateType ^ UpdateType . All &&
1004- this . updateType & UpdateType . RenderTexture
1005- ) {
1006- for ( let i = 0 , length = this . children . length ; i < length ; i ++ ) {
1007- this . children [ i ] ?. setUpdateType ( UpdateType . All ) ;
1008- }
998+ // Handle specific RTT updates at this node level
999+ if ( this . updateType & UpdateType . RenderTexture && this . rtt ) {
1000+ // Only the RTT node itself triggers `renderToTexture`
1001+ this . hasRTTupdates = true ;
1002+ this . stage . renderer ?. renderToTexture ( this ) ;
10091003 }
10101004
10111005 if ( this . updateType & UpdateType . Global ) {
@@ -1130,11 +1124,7 @@ export class CoreNode extends EventEmitter {
11301124 return ;
11311125 }
11321126
1133- if (
1134- this . updateType & UpdateType . Children &&
1135- this . children . length > 0 &&
1136- this . rtt === false
1137- ) {
1127+ if ( this . updateType & UpdateType . Children && this . children . length > 0 ) {
11381128 for ( let i = 0 , length = this . children . length ; i < length ; i ++ ) {
11391129 const child = this . children [ i ] as CoreNode ;
11401130
@@ -1148,6 +1138,13 @@ export class CoreNode extends EventEmitter {
11481138 }
11491139 }
11501140
1141+ // If the node has an RTT parent and requires a texture re-render, inform the RTT parent
1142+ // if (this.parentHasRenderTexture && this.updateType & UpdateType.RenderTexture) {
1143+ // @TODO have a more scoped down updateType for RTT updates
1144+ if ( this . parentHasRenderTexture && this . updateType > 0 ) {
1145+ this . notifyParentRTTOfUpdate ( ) ;
1146+ }
1147+
11511148 // Sorting children MUST happen after children have been updated so
11521149 // that they have the oppotunity to update their calculated zIndex.
11531150 if ( this . updateType & UpdateType . ZIndexSortedChildren ) {
@@ -1168,6 +1165,31 @@ export class CoreNode extends EventEmitter {
11681165 this . childUpdateType = 0 ;
11691166 }
11701167
1168+ private notifyParentRTTOfUpdate ( ) {
1169+ if ( this . parent === null ) {
1170+ return ;
1171+ }
1172+
1173+ let rttNode : CoreNode | null = this . parent ;
1174+ // Traverse up to find the RTT root node
1175+ while ( rttNode && ! rttNode . rtt ) {
1176+ rttNode = rttNode . parent ;
1177+ }
1178+
1179+ if ( ! rttNode ) {
1180+ return ;
1181+ }
1182+
1183+ // If an RTT node is found, mark it for re-rendering
1184+ rttNode . hasRTTupdates = true ;
1185+ rttNode . setUpdateType ( UpdateType . RenderTexture ) ;
1186+
1187+ // if rttNode is nested, also make it update its RTT parent
1188+ if ( rttNode . parentHasRenderTexture === true ) {
1189+ rttNode . notifyParentRTTOfUpdate ( ) ;
1190+ }
1191+ }
1192+
11711193 //check if CoreNode is renderable based on props
11721194 hasRenderableProperties ( ) : boolean {
11731195 if ( this . props . texture ) {
@@ -1940,8 +1962,9 @@ export class CoreNode extends EventEmitter {
19401962 UpdateType . Children | UpdateType . ZIndexSortedChildren ,
19411963 ) ;
19421964
1965+ // If the new parent has an RTT enabled, apply RTT inheritance
19431966 if ( newParent . rtt || newParent . parentHasRenderTexture ) {
1944- this . setRTTUpdates ( UpdateType . All ) ;
1967+ this . applyRTTInheritance ( newParent ) ;
19451968 }
19461969 }
19471970 this . updateScaleRotateTransform ( ) ;
@@ -1963,43 +1986,77 @@ export class CoreNode extends EventEmitter {
19631986 }
19641987
19651988 set rtt ( value : boolean ) {
1966- if ( this . props . rtt === true ) {
1967- this . props . rtt = value ;
1968-
1969- // unload texture if we used to have a render texture
1970- if ( value === false && this . texture !== null ) {
1971- this . unloadTexture ( ) ;
1972- this . setUpdateType ( UpdateType . All ) ;
1973- for ( let i = 0 , length = this . children . length ; i < length ; i ++ ) {
1974- this . children [ i ] ! . parentHasRenderTexture = false ;
1975- }
1976- this . stage . renderer ?. removeRTTNode ( this ) ;
1977- return ;
1978- }
1989+ if ( this . props . rtt === value ) {
1990+ return ;
19791991 }
1992+ this . props . rtt = value ;
19801993
1981- // if the new value is false and we didnt have rtt previously, we don't need to do anything
1982- if ( value === false ) {
1983- return ;
1994+ if ( value ) {
1995+ this . initRenderTexture ( ) ;
1996+ this . markChildrenWithRTT ( ) ;
1997+ } else {
1998+ this . cleanupRenderTexture ( ) ;
19841999 }
19852000
1986- // load texture
2001+ this . setUpdateType ( UpdateType . RenderTexture ) ;
2002+
2003+ if ( this . parentHasRenderTexture ) {
2004+ this . notifyParentRTTOfUpdate ( ) ;
2005+ }
2006+ }
2007+ private initRenderTexture ( ) {
19872008 this . texture = this . stage . txManager . loadTexture ( 'RenderTexture' , {
19882009 width : this . width ,
19892010 height : this . height ,
19902011 } ) ;
19912012 this . textureOptions . preload = true ;
2013+ this . stage . renderer ?. renderToTexture ( this ) ; // Only this RTT node
2014+ }
19922015
1993- this . props . rtt = true ;
1994- this . hasRTTupdates = true ;
1995- this . setUpdateType ( UpdateType . All ) ;
2016+ private cleanupRenderTexture ( ) {
2017+ this . unloadTexture ( ) ;
2018+ this . clearRTTInheritance ( ) ;
19962019
1997- for ( let i = 0 , length = this . children . length ; i < length ; i ++ ) {
1998- this . children [ i ] ! . setUpdateType ( UpdateType . All ) ;
2020+ this . stage . renderer ?. removeRTTNode ( this ) ;
2021+ this . hasRTTupdates = false ;
2022+ this . texture = null ;
2023+ }
2024+
2025+ private markChildrenWithRTT ( node : CoreNode | null = null ) {
2026+ const parent = node || this ;
2027+
2028+ for ( const child of parent . children ) {
2029+ child . setUpdateType ( UpdateType . All ) ;
2030+ child . parentHasRenderTexture = true ;
2031+ child . markChildrenWithRTT ( ) ;
2032+ }
2033+ }
2034+
2035+ // Apply RTT inheritance when a node has an RTT-enabled parent
2036+ private applyRTTInheritance ( parent : CoreNode ) {
2037+ if ( parent . rtt ) {
2038+ // Only the RTT node should be added to `renderToTexture`
2039+ parent . setUpdateType ( UpdateType . RenderTexture ) ;
19992040 }
20002041
2001- // Store RTT nodes in a separate list
2002- this . stage . renderer ?. renderToTexture ( this ) ;
2042+ // Propagate `parentHasRenderTexture` downwards
2043+ this . markChildrenWithRTT ( parent ) ;
2044+ }
2045+
2046+ // Clear RTT inheritance when detaching from an RTT chain
2047+ private clearRTTInheritance ( ) {
2048+ // if this node is RTT itself stop the propagation important for nested RTT nodes
2049+ // for the initial RTT node this is already handled in `set rtt`
2050+ if ( this . rtt ) {
2051+ return ;
2052+ }
2053+
2054+ for ( const child of this . children ) {
2055+ // force child to update everything as the RTT inheritance has changed
2056+ child . parentHasRenderTexture = false ;
2057+ child . setUpdateType ( UpdateType . All ) ;
2058+ child . clearRTTInheritance ( ) ;
2059+ }
20032060 }
20042061
20052062 get shader ( ) : BaseShaderController {
@@ -2158,11 +2215,6 @@ export class CoreNode extends EventEmitter {
21582215 this . childUpdateType |= UpdateType . RenderBounds | UpdateType . Children ;
21592216 }
21602217
2161- setRTTUpdates ( type : number ) {
2162- this . hasRTTupdates = true ;
2163- this . parent ?. setRTTUpdates ( type ) ;
2164- }
2165-
21662218 animate (
21672219 props : Partial < CoreNodeAnimateProps > ,
21682220 settings : Partial < AnimationSettings > ,
0 commit comments