@@ -151,50 +151,48 @@ export class TextureAtlas implements ITextureAtlas {
151151 // microtask to ensure it does not interrupt textures that will be rendered in the current
152152 // animation frame which would result in blank rendered areas. This is actually not that
153153 // expensive relative to drawing the glyphs, so there is no need to wait for an idle callback.
154- if ( TextureAtlas . maxAtlasPages && this . _pages . length >= Math . max ( 4 , TextureAtlas . maxAtlasPages / 2 ) ) {
155- queueMicrotask ( ( ) => {
156- // Find the set of the largest 4 images, below the maximum size, with the highest
157- // percentages used
158- const pagesBySize = this . _pages . filter ( e => {
159- return e . canvas . width * 2 <= ( TextureAtlas . maxTextureSize || Constants . FORCED_MAX_TEXTURE_SIZE ) ;
160- } ) . sort ( ( a , b ) => {
161- if ( b . canvas . width !== a . canvas . width ) {
162- return b . canvas . width - a . canvas . width ;
163- }
164- return b . percentageUsed - a . percentageUsed ;
165- } ) ;
166- let sameSizeI = - 1 ;
167- let size = 0 ;
168- for ( let i = 0 ; i < pagesBySize . length ; i ++ ) {
169- if ( pagesBySize [ i ] . canvas . width !== size ) {
170- sameSizeI = i ;
171- size = pagesBySize [ i ] . canvas . width ;
172- } else if ( i - sameSizeI === 3 ) {
173- break ;
174- }
154+ if ( TextureAtlas . maxAtlasPages && this . _pages . length >= Math . max ( 4 , TextureAtlas . maxAtlasPages ) ) {
155+ // Find the set of the largest 4 images, below the maximum size, with the highest
156+ // percentages used
157+ const pagesBySize = this . _pages . filter ( e => {
158+ return e . canvas . width * 2 <= ( TextureAtlas . maxTextureSize || Constants . FORCED_MAX_TEXTURE_SIZE ) ;
159+ } ) . sort ( ( a , b ) => {
160+ if ( b . canvas . width !== a . canvas . width ) {
161+ return b . canvas . width - a . canvas . width ;
162+ }
163+ return b . percentageUsed - a . percentageUsed ;
164+ } ) ;
165+ let sameSizeI = - 1 ;
166+ let size = 0 ;
167+ for ( let i = 0 ; i < pagesBySize . length ; i ++ ) {
168+ if ( pagesBySize [ i ] . canvas . width !== size ) {
169+ sameSizeI = i ;
170+ size = pagesBySize [ i ] . canvas . width ;
171+ } else if ( i - sameSizeI === 3 ) {
172+ break ;
175173 }
174+ }
176175
177- // Gather details of the merge
178- const mergingPages = pagesBySize . slice ( sameSizeI , sameSizeI + 4 ) ;
179- const sortedMergingPagesIndexes = mergingPages . map ( e => e . glyphs [ 0 ] . texturePage ) . sort ( ( a , b ) => a > b ? 1 : - 1 ) ;
180- const mergedPageIndex = sortedMergingPagesIndexes [ 0 ] ;
176+ // Gather details of the merge
177+ const mergingPages = pagesBySize . slice ( sameSizeI , sameSizeI + 4 ) ;
178+ const sortedMergingPagesIndexes = mergingPages . map ( e => e . glyphs [ 0 ] . texturePage ) . sort ( ( a , b ) => a > b ? 1 : - 1 ) ;
179+ const mergedPageIndex = this . pages . length - mergingPages . length ;
181180
182- // Merge into the new page
183- const mergedPage = this . _mergePages ( mergingPages , mergedPageIndex ) ;
184- mergedPage . version ++ ;
181+ // Merge into the new page
182+ const mergedPage = this . _mergePages ( mergingPages , mergedPageIndex ) ;
183+ mergedPage . version ++ ;
185184
186- // Replace the first _merging_ page with the _merged_ page
187- this . _pages [ mergedPageIndex ] = mergedPage ;
185+ // Delete the pages, shifting glyph texture pages as needed
186+ for ( let i = sortedMergingPagesIndexes . length - 1 ; i >= 0 ; i -- ) {
187+ this . _deletePage ( sortedMergingPagesIndexes [ i ] ) ;
188+ }
188189
189- // Delete the other 3 pages, shifting glyph texture pages as needed
190- for ( let i = sortedMergingPagesIndexes . length - 1 ; i >= 1 ; i -- ) {
191- this . _deletePage ( sortedMergingPagesIndexes [ i ] ) ;
192- }
190+ // Add the new merged page to the end
191+ this . pages . push ( mergedPage ) ;
193192
194- // Request the model to be cleared to refresh all texture pages.
195- this . _requestClearModel = true ;
196- this . _onAddTextureAtlasCanvas . fire ( mergedPage . canvas ) ;
197- } ) ;
193+ // Request the model to be cleared to refresh all texture pages.
194+ this . _requestClearModel = true ;
195+ this . _onAddTextureAtlasCanvas . fire ( mergedPage . canvas ) ;
198196 }
199197
200198 // All new atlas pages are created small as they are highly dynamic
@@ -756,13 +754,13 @@ export class TextureAtlas implements ITextureAtlas {
756754 }
757755 }
758756
759- // Create a new one if too much vertical space would be wasted or there is not enough room
757+ // Create a new page if too much vertical space would be wasted or there is not enough room
760758 // left in the page. The previous active row will become fixed in the process as it now has a
761759 // fixed height
762760 if ( activeRow . y + rasterizedGlyph . size . y >= activePage . canvas . height || activeRow . height > rasterizedGlyph . size . y + Constants . ROW_PIXEL_THRESHOLD ) {
763761 // Create the new fixed height row, creating a new page if there isn't enough room on the
764762 // current page
765- let wasNewPageCreated = false ;
763+ let wasPageAndRowFound = false ;
766764 if ( activePage . currentRow . y + activePage . currentRow . height + rasterizedGlyph . size . y >= activePage . canvas . height ) {
767765 // Find the first page with room to create the new row on
768766 let candidatePage : AtlasPage | undefined ;
@@ -775,15 +773,30 @@ export class TextureAtlas implements ITextureAtlas {
775773 if ( candidatePage ) {
776774 activePage = candidatePage ;
777775 } else {
778- // Create a new page if there is no room
779- const newPage = this . _createNewPage ( ) ;
780- activePage = newPage ;
781- activeRow = newPage . currentRow ;
782- activeRow . height = rasterizedGlyph . size . y ;
783- wasNewPageCreated = true ;
776+ // Before creating a new atlas page that would trigger a page merge, check if the
777+ // current active row is sufficient when ignoring the ROW_PIXEL_THRESHOLD. This will
778+ // improve texture utilization by using the available space before the page is merged
779+ // and becomes static.
780+ if (
781+ TextureAtlas . maxAtlasPages &&
782+ this . _pages . length >= TextureAtlas . maxAtlasPages &&
783+ activeRow . y + rasterizedGlyph . size . y <= activePage . canvas . height &&
784+ activeRow . height >= rasterizedGlyph . size . y &&
785+ activeRow . x + rasterizedGlyph . size . x <= activePage . canvas . width
786+ ) {
787+ // activePage and activeRow is already valid
788+ wasPageAndRowFound = true ;
789+ } else {
790+ // Create a new page if there is no room
791+ const newPage = this . _createNewPage ( ) ;
792+ activePage = newPage ;
793+ activeRow = newPage . currentRow ;
794+ activeRow . height = rasterizedGlyph . size . y ;
795+ wasPageAndRowFound = true ;
796+ }
784797 }
785798 }
786- if ( ! wasNewPageCreated ) {
799+ if ( ! wasPageAndRowFound ) {
787800 // Fix the current row as the new row is being added below
788801 if ( activePage . currentRow . height > 0 ) {
789802 activePage . fixedRows . push ( activePage . currentRow ) ;
0 commit comments