@@ -99,27 +99,26 @@ function createImageActor(imageData) {
9999 return actor ;
100100}
101101
102- async function createActors ( numberOfActors ) {
102+ async function readImageData ( ) {
103103 const reader = vtkHttpDataSetReader . newInstance ( { fetchGzip : true } ) ;
104104 await reader . setUrl ( `${ __BASE_PATH__ } /data/volume/LIDC2.vti` ) ;
105105 await reader . loadData ( ) ;
106106 const imageData = reader . getOutputData ( ) ;
107107
108- const actors = [ ] ;
109- for ( let i = 0 ; i < numberOfActors ; ++ i ) {
110- if ( Math . random ( ) > 0.5 ) {
111- actors . push ( createVolumeActor ( imageData ) ) ;
112- } else {
113- actors . push ( createImageActor ( imageData ) ) ;
114- }
115- }
116-
117- return actors ;
108+ return imageData ;
118109}
119110
120- const mainRenderWindow = vtkRenderWindow . newInstance ( ) ;
121- const mainRenderWindowView = mainRenderWindow . newAPISpecificView ( ) ;
122- mainRenderWindow . addView ( mainRenderWindowView ) ;
111+ let mainRenderWindow ;
112+ let mainRenderWindowView ;
113+ function resetMainRenderWindowAndView ( ) {
114+ mainRenderWindow = vtkRenderWindow . newInstance ( ) ;
115+ mainRenderWindowView = mainRenderWindow . newAPISpecificView ( ) ;
116+ mainRenderWindow . addView ( mainRenderWindowView ) ;
117+ // Main view has to be initialized before the first "render" from a child render window
118+ // We initialize before creating the child render windows because the interactor initialization calls "render" on them
119+ mainRenderWindowView . initialize ( ) ;
120+ }
121+ resetMainRenderWindowAndView ( ) ;
123122
124123const rootContainer = document . createElement ( 'div' ) ;
125124rootContainer . style . display = 'flex' ;
@@ -128,6 +127,10 @@ rootContainer.style['justify-content'] = 'space-between';
128127rootContainer . style [ 'flex-wrap' ] = 'wrap' ;
129128document . body . appendChild ( rootContainer ) ;
130129
130+ const addRenderWindowButton = document . createElement ( 'button' ) ;
131+ addRenderWindowButton . innerText = 'Create a new render window' ;
132+ rootContainer . appendChild ( addRenderWindowButton ) ;
133+
131134function applyStyle ( element ) {
132135 const width = Math . floor ( 200 + Math . random ( ) * 200 ) ;
133136 const height = Math . floor ( 200 + Math . random ( ) * 200 ) ;
@@ -146,7 +149,11 @@ function createRemoveButton() {
146149 return buttonEl ;
147150}
148151
149- function addRenderWindow ( ) {
152+ const childRenderWindows = [ ] ;
153+ function addRenderWindow ( actor ) {
154+ if ( mainRenderWindow . isDeleted ( ) ) {
155+ resetMainRenderWindowAndView ( ) ;
156+ }
150157 // Create a child renderwindow
151158 const renderWindow = vtkRenderWindow . newInstance ( ) ;
152159 mainRenderWindow . addRenderWindow ( renderWindow ) ;
@@ -189,47 +196,66 @@ function addRenderWindow() {
189196 mainRenderWindow . removeRenderWindow ( renderWindow ) ;
190197 mainRenderWindowView . removeNode ( renderWindowView ) ;
191198 interactor . delete ( ) ;
192- renderWindow . delete ( ) ;
193199 renderWindowView . delete ( ) ;
200+ renderWindow . delete ( ) ;
201+ if ( mainRenderWindow . getChildRenderWindowsByReference ( ) . length === 0 ) {
202+ // When there is no child render window anymore, delete the main render window
203+ // We also release the graphics resources, which is not very import as when the context is destroyed, the resources should be freed
204+ // The release of shared graphics resources is not automatic and can be done by hand when the resource is not needed anymore
205+ const imageData = actor . getMapper ( ) . getInputData ( ) ;
206+ const scalars = imageData . getPointData ( ) . getScalars ( ) ;
207+ mainRenderWindowView . releaseGraphicsResourcesForObject ( scalars ) ;
208+ mainRenderWindowView . delete ( ) ;
209+ mainRenderWindow . delete ( ) ;
210+ }
194211 } ) ;
195212 container . appendChild ( button ) ;
196213
214+ // Create the corresponding renderer
215+ const background = [
216+ 0.5 * Math . random ( ) + 0.25 ,
217+ 0.5 * Math . random ( ) + 0.25 ,
218+ 0.5 * Math . random ( ) + 0.25 ,
219+ ] ;
220+ const renderer = vtkRenderer . newInstance ( { background } ) ;
221+ renderWindow . addRenderer ( renderer ) ;
222+
223+ // Add the actor and reset camera
224+ renderer . addActor ( actor ) ;
225+ const camera = renderer . getActiveCamera ( ) ;
226+ camera . yaw ( 90 ) ;
227+ camera . roll ( 90 ) ;
228+ camera . azimuth ( Math . random ( ) * 360 ) ;
229+ renderer . resetCamera ( ) ;
230+
231+ childRenderWindows . push ( renderWindow ) ;
232+
197233 return renderWindow ;
198234}
199235
236+ function createRandomActor ( imageData ) {
237+ if ( Math . random ( ) > 0.5 ) {
238+ return createVolumeActor ( imageData ) ;
239+ }
240+ return createImageActor ( imageData ) ;
241+ }
242+
200243// ----------------------------------------------------------------------------
201244// Fill up page
202245// ----------------------------------------------------------------------------
203246
204- const childRenderWindows = [ ] ;
205- createActors ( 64 ) . then ( ( actors ) => {
206- // Main view has to be initialized before the first "render" from a child render window
207- // We initialize before creating the child render windows because the interactor initialization calls "render" on them
208- mainRenderWindowView . initialize ( ) ;
209-
210- actors . forEach ( ( actor ) => {
211- const childRenderWindow = addRenderWindow ( ) ;
212-
213- // Create the corresponding renderer
214- const background = [
215- 0.5 * Math . random ( ) + 0.25 ,
216- 0.5 * Math . random ( ) + 0.25 ,
217- 0.5 * Math . random ( ) + 0.25 ,
218- ] ;
219- const renderer = vtkRenderer . newInstance ( { background } ) ;
220- childRenderWindow . addRenderer ( renderer ) ;
221-
222- // Add the actor and reset camera
223- renderer . addActor ( actor ) ;
224- const camera = renderer . getActiveCamera ( ) ;
225- camera . yaw ( 90 ) ;
226- camera . roll ( 90 ) ;
227- camera . azimuth ( Math . random ( ) * 360 ) ;
228- renderer . resetCamera ( ) ;
229-
230- childRenderWindows . push ( childRenderWindow ) ;
247+ readImageData ( ) . then ( ( imageData ) => {
248+ // The button to add render windows
249+ addRenderWindowButton . addEventListener ( 'click' , ( ) => {
250+ addRenderWindow ( createRandomActor ( imageData ) ) ;
251+ mainRenderWindowView . resizeFromChildRenderWindows ( ) ;
252+ mainRenderWindow . render ( ) ;
231253 } ) ;
232254
255+ // Create several render windows and do the first resize and render
256+ for ( let i = 0 ; i < 64 ; i ++ ) {
257+ addRenderWindow ( createRandomActor ( imageData ) ) ;
258+ }
233259 mainRenderWindowView . resizeFromChildRenderWindows ( ) ;
234260 mainRenderWindow . render ( ) ;
235261} ) ;
0 commit comments