To put the question shortly, how can I dispose current View3D instance and replace it with the new one, (arbitrary number of times) so that all old one’s Context3D and Scene3D content is disposed and new one’s is clear and free?
I tried and failed to find solution, and now I want to find out is this a bug or I misuse Away3D somehow.
Obviously there’s a limit on number of any kind of resource, that is created through Context3D methods. For instance, I need a lot of CubeMap textures in my 3D simulation, so I decided to determine the exact limit number, and the plan was to recreate View3D instance and add all existing objects as I reach limit. That is, you can create any number (well, at least, a lot) of Away3D CubeMap instances, and dispose them with CubeMap’s dispose method, but it is all right as long as you don’t render them. Once the cubemap gets rendered, it’s stuck somewhere inside Context3D, and dispose call doesn’t affect this. I made a test application which creates new cubemap (it’s bitmapDatas are cloned from embedded ones), makes skybox out of it, adds it to the view’s scene and renders view. Then, it disposes old skybox and creates new one with fresh cubemap. So I discovered the limits, and that they are resolution-dependent: for 512x512x6 cubemap the limit is 28, for 1024x1024x6 it is 7. After the limit is reached you get exception from Context3D.createCubeTexture method when Away3D tries to render new skybox :
‘Error: Error #3691: Resource limit for this resource type exceeded.’
By the way, apart from disposable skybox my test scene contains 1 point light, 1 plane primitive and 1 cube primitive, no textures. I keep references to all objects within my application class’ variables, to be able to add them to freshly created view’s scene.
So far, so good, but when it came to exchanging views, things got really nasty. At first I tried straightforward approach, like:
protected function recreateView():void
{
removeChild(_view);
_view = new View3D();
addChildAt(_view, 0);
_view.stage.addEventListener(Event.RESIZE, onStageResize, false, 0, true);
addObjects();
}
It seemed to work, but only 3 times, because Away’s Stage3DManager has it’s own limitation on total Stage3D instances (4), and as you try to add fifth view, its method ‘getFreeStage3DProxy()’ throws an Exception: ‘Error: Too many Stage3D instances used!’
Anyway, we are able to create and render 28 cubemaps instead of 7.
Well, after this failure, I figured that actual Stage3D instance is not disposed along with old View3D, so I have to delete it manually somehow. So I found Stage3DProxy’s method dispose(), and as view keeps reference to its Stage3D, I call it like that:
protected function recreateView():void
{
removeChild(_view);
var oldView:View3D = _view; // remember old view
_view = new View3D();
addChildAt(_view, 0);
_view.stage.addEventListener(Event.RESIZE, onStageResize, false, 0, true);
addObjects();
oldView.stage3DProxy.dispose(); // dispose old view's Stage3D
}
Well, I guess (hope), it helped in some way. But now it generates exception after 2nd view exchange (and 14 cubemaps rendered sucessfully), this time trying to draw triangles of the plane primitive:
‘Error: Error #3600: No valid program set.’
And here I’m out of ideas, and have to beg of an advice from people who understand Broomstick and Molehill guts better than me. If anyone is interested, I can attach my test project (it is in FlashDevelop format).