@@ -99,27 +99,26 @@ function createImageActor(imageData) {
99
99
return actor ;
100
100
}
101
101
102
- async function createActors ( numberOfActors ) {
102
+ async function readImageData ( ) {
103
103
const reader = vtkHttpDataSetReader . newInstance ( { fetchGzip : true } ) ;
104
104
await reader . setUrl ( `${ __BASE_PATH__ } /data/volume/LIDC2.vti` ) ;
105
105
await reader . loadData ( ) ;
106
106
const imageData = reader . getOutputData ( ) ;
107
107
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 ;
118
109
}
119
110
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 ( ) ;
123
122
124
123
const rootContainer = document . createElement ( 'div' ) ;
125
124
rootContainer . style . display = 'flex' ;
@@ -128,6 +127,10 @@ rootContainer.style['justify-content'] = 'space-between';
128
127
rootContainer . style [ 'flex-wrap' ] = 'wrap' ;
129
128
document . body . appendChild ( rootContainer ) ;
130
129
130
+ const addRenderWindowButton = document . createElement ( 'button' ) ;
131
+ addRenderWindowButton . innerText = 'Create a new render window' ;
132
+ rootContainer . appendChild ( addRenderWindowButton ) ;
133
+
131
134
function applyStyle ( element ) {
132
135
const width = Math . floor ( 200 + Math . random ( ) * 200 ) ;
133
136
const height = Math . floor ( 200 + Math . random ( ) * 200 ) ;
@@ -146,7 +149,11 @@ function createRemoveButton() {
146
149
return buttonEl ;
147
150
}
148
151
149
- function addRenderWindow ( ) {
152
+ const childRenderWindows = [ ] ;
153
+ function addRenderWindow ( actor ) {
154
+ if ( mainRenderWindow . isDeleted ( ) ) {
155
+ resetMainRenderWindowAndView ( ) ;
156
+ }
150
157
// Create a child renderwindow
151
158
const renderWindow = vtkRenderWindow . newInstance ( ) ;
152
159
mainRenderWindow . addRenderWindow ( renderWindow ) ;
@@ -189,47 +196,66 @@ function addRenderWindow() {
189
196
mainRenderWindow . removeRenderWindow ( renderWindow ) ;
190
197
mainRenderWindowView . removeNode ( renderWindowView ) ;
191
198
interactor . delete ( ) ;
192
- renderWindow . delete ( ) ;
193
199
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
+ }
194
211
} ) ;
195
212
container . appendChild ( button ) ;
196
213
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
+
197
233
return renderWindow ;
198
234
}
199
235
236
+ function createRandomActor ( imageData ) {
237
+ if ( Math . random ( ) > 0.5 ) {
238
+ return createVolumeActor ( imageData ) ;
239
+ }
240
+ return createImageActor ( imageData ) ;
241
+ }
242
+
200
243
// ----------------------------------------------------------------------------
201
244
// Fill up page
202
245
// ----------------------------------------------------------------------------
203
246
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 ( ) ;
231
253
} ) ;
232
254
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
+ }
233
259
mainRenderWindowView . resizeFromChildRenderWindows ( ) ;
234
260
mainRenderWindow . render ( ) ;
235
261
} ) ;
0 commit comments