PageSourceSearch

https://mysteroid.ai/run/rbanks.js

js mysteroid.ai collected 2026-10-05 13:34:25 UTC 53,427 bytes, 1,702 lines download raw bytes

1/*@*****************************************************************************
2*                                                                              *
3*   █████╗  ██████╗ ███████╗    ███████╗████████╗██╗   ██╗██████╗ ██╗ ██████╗  *
4*  ██╔══██╗██╔═══██╗╚══███╔╝    ██╔════╝╚══██╔══╝██║   ██║██╔══██╗██║██╔═══██╗ *
5*  ███████║██║   ██║  ███╔╝     ███████╗   ██║   ██║   ██║██║  ██║██║██║   ██║ *
6*  ██╔══██║██║   ██║ ███╔╝      ╚════██║   ██║   ██║   ██║██║  ██║██║██║   ██║ *
7*  ██║  ██║╚██████╔╝███████╗    ███████║   ██║   ╚██████╔╝██████╔╝██║╚██████╔╝ *
8*  ╚═╝  ╚═╝ ╚═════╝ ╚══════╝    ╚══════╝   ╚═╝    ╚═════╝ ╚═════╝ ╚═╝ ╚═════╝  *
9*                                                                              *
10* This file is part of AOZ Studio.                                             *
11* Copyright (c) AOZ Studio. All rights reserved.                               *
12*                                                                              *
13* Licensed under the GNU General Public License v3.0.                          *
14* More info at: https://choosealicense.com/licenses/gpl-3.0/                   *
15* And in the file AOZ_StudioCodeLicense.pdf.                                   *
16*                                                                              *
17*****************************************************************************@*/
18/** @file
19 *
20 * AOZ Runtume
21 *
22 * Banks.
23 *
24 * @author FL (Francois Lionet)
25 * @date first pushed on 28/02/2018
26 */
27function Banks( aoz )
28{
29	this.aoz = aoz;
30	this.aoz.banks = this;
31	this.utilities = aoz.utilities;
32	this.manifest = aoz.manifest;
33	this.banks = [];
34	this.quickBanks = {};
35	this.numberOfReserves = 0;
36
37	this.banks[ 1 ] = {};
38	this.banks[ 2 ] = {};
39	this.banks[ 5 ] = {};
40	this.banks[ 6 ] = {};
41	this.banks[ 7 ] = {};
42	this.quickBanks[ "v1_0_sounds" ] = {};
43	this.quickBanks[ "application" ] = {};
44	this.banks[ 5 ][ 'v1_0_sounds' ] = new SampleBank( this.aoz, [{a:"1.bell.js",b:"1.bell.wav"},{a:"2.boom.js",b:"2.boom.wav"},{a:"3.shoot.js",b:"3.shoot.wav"}], ["audio/wav","audio/wav","audio/wav"], { domain: 'samples', type: 'samples', path: 'v1_0_sounds/5.samples' } );
45	this.banks[ 1 ][ 'application' ] = new ImageBank( this.aoz, ["fnt_default.js","logo.js","LW.js","S.js","S_old.js","user_man.js","user_woman.js"], ["image/png","image/png","image/png","image/png","image/png","image/png","image/png"], [ "#000000","#FFFFFF","#D1D1D1","#A2A2A2","#737373","#444444","#FF0000","#D10000","#A20000","#730000","#440000","#00FF00","#00D100","#00A200","#007300","#004400","#FFFF00","#D1D100","#A2A200","#737300","#444400","#FF7F00","#E27100","#C46200","#A65300","#884400","#0000FF","#0000D1","#0000A2","#000073","#000044","#00FFFF","#00D1D1","#00A2A2","#007373","#004444","#FF00FF","#D100D1","#A200A2","#730073","#440044","#FFA100","#FFB312","#FFC625","#FFD837","#FFEB4A","#FFFE5D","#002965","#123975","#244985","#365995","#4869A5","#5A79B5","#BF717F","#B26773","#A45D66","#975359","#89494C","#7B3F3F","#8252B4","#623E87","#41295A","#21152D","#000000" ], { hotSpots: [{ x: 0, y: 0 },{ x: 0, y: 0 },{ x: 0, y: 0 },{ x: 0, y: 0 },{ x: 0, y: 0 },{ x: 0, y: 0 },{ x: 0, y: 0 },], masks: '""', alpha: false, domain: 'images', type: 'images', path: '1.images' } );
46	this.banks[ 5 ][ 'application' ] = new SampleBank( this.aoz, [], [], { domain: 'samples', type: 'samples', path: '5.samples' } );
47	this.banks[ 2 ][ "application" ] = new TDBank( this.aoz, [], [], { domain: "3D", type: "3D" } );
48
49
50	// Poke the indexes and reservation numbers.
51	for ( var b = 0; b < this.banks.length; b++ )
52	{
53		if ( this.banks[ b ] )
54		{
55			for ( var c in this.banks[ b ] )
56			{
57				var bank = this.banks[ b ][ c ];
58				if ( bank )
59				{
60					bank.index = b;
61					bank.reserveNumber = this.numberOfReserves++;
62				}
63			}
64		}
65	}
66};
67
68Banks.ListBanks = function()
69{
70	var list = {}
71
72	if( application.aoz.banks && application.aoz.banks.banks.length > 0 )
73	{
74		for( var b = 0; b < application.aoz.banks.banks.length; b++ )
75		{
76			var bank = application.aoz.banks.banks[ b ];
77			if( bank && bank.application && bank.application.domain )
78			{
79				list[ bank.application.domain ] = [];
80				if( bank.application.context && bank.application.context.listNames )
81				{
82					var keys = Object.keys( bank.application.context.listNames );
83					for( var l = 0; l < keys.length; l++ )
84					{
85						list[ bank.application.domain ].push( { name: keys[ l ].strReplace( bank.application.domain + ':', '' ), item: bank.application.context.listNames[ keys[ l ] ] } );
86					}
87				}
88			}
89		}
90	}
91
92	return list;
93};
94
95Banks.prototype.loadAllBanks = function( type, contextName )
96{
97	for ( var number = 0; number < this.banks.length; number++ )
98	{
99		if ( this.banks[ number ] )
100		{
101			for ( var context in this.banks[ number ] )
102			{
103				var bank = this.banks[ number ][ context ];
104				if ( !bank )
105				 	continue;
106				if ( typeof type != 'undefined' && bank.type != type )
107					continue;
108				if ( typeof contextName != 'undefined' && contextName != context )
109					continue;
110				bank.loadList();
111			}
112		}
113	}
114	
115};
116Banks.prototype.reserve = function( number, type, length, contextName )
117{
118	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
119
120	if ( number < 0 )
121		throw { error: 'illegal_function_call', parameter: number };
122	if ( !this.manifest.unlimitedBanks && number > 16 )
123		throw { error: 'illegal_function_call', parameter: number };
124
125	var length = typeof length == 'undefined' ? 0 : length;
126	if ( length < 0 )
127		throw { error: 'illegal_function_call', parameter: length };
128	if ( !type || type == '' )
129		throw { error: 'illegal_function_call', parameter: type };
130
131	var bank = this.banks[ number ];
132	if ( !bank )
133		this.banks[ number ] = {};
134	type = type.toLowerCase();
135	var bank, copyBlock = false;
136	switch ( type )
137	{
138		case 'images':
139			bank = new ImageBank( this.aoz, [], [], this.aoz.manifest.default.screen.palette, { domain: type, type: type } );
140			break;
141		case 'icons':
142			bank = new ImageBank( this.aoz, [], [], this.aoz.manifest.default.screen.palette, { domain: type, type: type } );
143			break;
144		case '3D':
145			bank = new TDBank( this.aoz, [], [], { domain: type, type: type } );
146			break;
147		case 'musics':
148			bank = new SampleBank( this.aoz, [], [], { domain: type, type: type } );
149			break;
150		case 'samples':
151			bank = new SampleBank( this.aoz, [], [], { domain: type, type: type } );
152			break;
153		case 'picpac':
154		case 'amal':
155			bank = new DataBank( this.aoz, undefined, 0, { domain: type, type: type } );
156			break;
157		case 'work':
158		case 'tracker':
159		case 'data':
160		default:
161			bank = new DataBank( this.aoz, undefined, length, { domain: type, type: type } );
162			copyBlock = true;
163			break;
164	}
165	bank.reserveNumber = this.numberOfReserves++;
166	bank.index = number;
167	this.banks[ number ][ contextName ] = bank;
168	this.quickBanks[ contextName ] = {};
169	return bank;
170};
171Banks.prototype.erase = function( bankIndex, noError, contextName )
172{
173	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
174
175	if ( bankIndex < 1 || ( !this.aoz.unlimitedBanks && bankIndex > 16 ) )
176	{
177		if ( !noError )
178			throw { error: 'illegal_function_call', parameter: bankIndex };
179		return;
180	}
181
182	if ( !this.banks[ bankIndex ] || !this.banks[ bankIndex ][ contextName ] )
183	{
184		if ( !noError )
185			throw 'bank_not_reserved';
186		return;
187	}
188	this.getBank( bankIndex, contextName ).erase();
189	this.banks[ bankIndex ] = this.utilities.cleanObject( this.banks[ bankIndex ], contextName );
190	this.quickBanks[ contextName ] = {};
191};
192Banks.prototype.eraseTemp = function( bankIndex, contextName )
193{
194	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
195
196	for ( var b = 0; b < this.banks.length; b++ )
197	{
198		if ( this.banks[ b ] && this.banks[ b ][ contextName ] )
199		{
200			var bank = this.banks[ b ][ contextName ];
201			if ( bank.isType( 'work' ) )
202			{
203				this.erase( b, contextName );
204				this.updateBank( null, b, contextName );
205			}
206		}
207	}
208};
209Banks.prototype.eraseAll = function( bankIndex, contextName )
210{
211	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
212
213	for ( var b = 0; b < this.banks.length; b++ )
214	{
215		if ( this.banks[ b ] && this.banks[ b ][ contextName ] )
216		{
217			this.erase( b, contextName );
218			this.updateBank( null, b, contextName );
219		}
220	}
221};
222Banks.prototype.updateBank = function( bank, bankIndex, contextName )
223{
224	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
225
226	this.aoz.screensContext.parseAll( contextName, function( screen )
227	{
228		screen.updateBank( bank, bankIndex, contextName )
229	} );
230	if ( this.aoz.sprites )
231	{
232		this.aoz.sprites.updateBank( bank, bankIndex, contextName );
233	}
234};
235Banks.prototype.bankShrink = function( bankIndex, newLength, contextName )
236{
237	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
238
239	var bank = this.getBank( bankIndex, contextName );
240	bank.setLength( newLength );
241	this.updateBank( bank, bankIndex, contextName );
242};
243Banks.prototype.bankSwap = function( bankIndex1, bankIndex2, contextName )
244{
245	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
246
247	if ( bankIndex1 < 1 || bankIndex2 < 1 || typeof bankIndex1 == 'undefined' || typeof bankIndex2 == 'undefined' )
248		throw { error: 'illegal_function_call', parameters: [ bankIndex1, bankIndex2 ] };
249	if ( !this.manifest.unlimitedBanks && ( bankIndex1 > 16 || bankIndex2 > 16 ) )
250		throw { error: 'illegal_function_call', parameters: [ bankIndex1, bankIndex2 ] };
251
252	if ( !this.banks[ bankIndex1 ][ contextName ] || !this.banks[ bankIndex2 ][ contextName ] )
253		throw 'bank_not_reserved';
254
255	// Swap!
256	var bank1 = this.banks[ bankIndex1 ][ contextName ];
257	var bank2 = this.banks[ bankIndex2 ][ contextName ];
258	this.banks[ bankIndex1 ][ contextName ] = bank2;
259	this.banks[ bankIndex2 ][ contextName ] = bank1;
260	bank2.index = bankIndex1;
261	bank1.index = bankIndex2;
262
263	// Update banks
264	this.quickBanks[ contextName ] = {};
265	this.updateBank( bank1, bank1.index, contextName );
266	this.updateBank( bank2, bank2.index, contextName );
267};
268Banks.prototype.getBank = function( bankIndex, contextName, bankType, throwError = true )
269{
270	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
271	try 
272	{
273		if ( typeof bankIndex == 'undefined' )
274		{
275			if ( typeof bankType == 'undefined' )
276				throw { error: 'illegal_function_call', parameter: '' };
277			if ( bankType == 'images' || bankType == 'icons' || bankType == '3D' || bankType == 'musics' || bankType == 'samples' || bankType == 'amal' )
278			{
279				if ( this.quickBanks[ contextName ] && this.quickBanks[ contextName ][ bankType ] )
280					return this.quickBanks[ contextName ][ bankType ];
281				for ( var b = 0; b < this.banks.length; b++ )
282				{
283					if ( this.banks[ b ] )
284					{
285						var bank = this.banks[ b ][ contextName ];
286						if ( bank && bank.isType( bankType ) )
287						{
288							if ( !this.quickBanks[ contextName ] )
289								this.quickBanks[ contextName ] = {};
290							this.quickBanks[ contextName ][ bankType ] = bank;
291							return bank;
292						}
293					}
294				}
295			}
296			throw 'bank_not_reserved';
297		}
298		if ( bankIndex < 1 )
299			throw { error: 'illegal_function_call', parameter: bankIndex };
300		if ( !this.aoz.unlimitedBanks && bankIndex > 16 )
301			throw { error: 'illegal_function_call', parameter: bankIndex };
302	
303		if ( !this.banks[ bankIndex ] )
304			throw 'bank_not_reserved';
305		var bank = this.banks[ bankIndex ][ contextName ];
306		if ( !bank )
307			throw 'bank_not_reserved';
308		if ( bankType && !bank.isType( bankType ))
309			throw 'bank_type_mismatch';
310	}
311	catch( err )
312	{ 
313		if ( throwError )
314			throw err;
315		return undefined;
316	}
317	return bank;
318};
319Banks.prototype.getBankElement = function( bankIndex, elementNumber, 
319contextName )
320{
321	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
322	return this.getBank( bankIndex, contextName ).getElement( elementNumber );
323};
324Banks.prototype.getStart = function( bankIndex, contextName, elementNumber )
325{
326	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
327	elementNumber = typeof elementNumber == 'undefined' ? 1 : elementNumber;
328	var bank = this.getBank( bankIndex, contextName );
329	if ( bank.type == 'tracker' || bank.type == 'data' || bank.type == 'work' )
330		return bank.getElement( elementNumber ).memoryHash * this.aoz.memoryHashMultiplier;
331	throw 'bank_type_mismatch';
332};
333Banks.prototype.getLength = function( bankIndex, contextName )
334{
335	var bank = this.getBank( bankIndex, contextName, undefined, false );
336	if ( !bank )
337		return 0;
338	return bank.getLength();
339};
340Banks.prototype.listBank = function( contextName )
341{
342	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
343	for ( var b = 0; b < this.banks.length; b++ )
344	{
345		if ( this.banks[ b ] )
346		{
347			var bank = this.banks[ b ][ contextName ];
348			if ( bank && bank.getLength() )
349			{
350				this.aoz.currentScreen.currentTextWindow.printUsing( '###', [ b ], false );
351				this.aoz.currentScreen.currentTextWindow.print( ' - ', false );
352				this.aoz.currentScreen.currentTextWindow.printUsing( '~~~~~~~~~~~~~~~~~ L: ', [ bank.domain ], false );
353				this.aoz.currentScreen.currentTextWindow.print( '' + bank.getLength(), true );
354			}
355		}
356	}
357};
358Banks.prototype.loadFileToBank = function( pathOrDescriptor, bankIndex, bankType, options, callback, extra )
359{
360	options = typeof options == 'undefined' ? options : {};
361	var contextName = typeof options.contextName == 'undefined' ? this.aoz.currentContextName : options.contextName;
362
363	var descriptor;
364	if ( typeof pathOrDescriptor == 'string' )
365	{
366		descriptor = this.aoz.filesystem.getFile( pathOrDescriptor, { noErrors: true } );
367		if ( descriptor.error )
368			callback( false, descriptor.error, extra );
369	}
370	else
371	{
372		descriptor = pathOrDescriptor;
373	}
374
375	var self = this;
376	this.aoz.filesystem.loadFile( descriptor, { binary: true }, function( response, arrayBuffer, extra )
377	{
378		if ( response )
379		{
380			var block = self.aoz.allocMemoryBlock( arrayBuffer, 'big' );
381			var bank = self.aoz.banks.reserve( bankIndex, bankType, block.length, contextName );
382			var elementIndex = typeof options.elementIndex == 'undefined' ? 1 : options.elementIndex;
383			if ( elementIndex < 0 )
384			{
385				callback( false, 'illegal_function_call', extra );
386				return;
387			}
388			block.filename = descriptor.name;
389			bank.setElement( elementIndex, block );
390			callback( true, bank, extra );
391		}
392		else
393		{
394			callback( false, 'cannot_load_file', extra );
395		}
396	}, extra );
397};
398
399///////////////////////////////////////////////////////////////////////////
400// 3D BANK
401///////////////////////////////////////////////////////////////////////////
402Banks.prototype.get3DElement = function( bankName, index, contextName, bankIndex )
403{
404	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
405	return this.getBank( bankIndex, contextName, bankName ).getElement( index );
406}
407
408///////////////////////////////////////////////////////////////////////////
409// IMAGE / ICONS BANK
410///////////////////////////////////////////////////////////////////////////
411Banks.prototype.getImage = function( bankName, index, contextName, bankIndex )
412{
413	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
414	return this.getBank( bankIndex, contextName, bankName ).getElement( index );
415};
416Banks.prototype.setImageHotSpot = function( bankName, index, position, contextName, bankIndex )
417{
418	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
419	this.getBank( bankIndex, contextName, bankName ).setHotSpot( index, position );
420};
421Banks.prototype.getImageHotSpot = function( bankName, index, position, contextName, bankIndex )
422{
423	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
424	return this.getBank( bankIndex, contextName, bankName ).getHotSpot( index, position );
425};
426Banks.prototype.insertImage = function( bankName, index, name, tags, contextName, bankIndex, canvas, hotSpot )
427{
428	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
429	bank = this.getBank( bankIndex, contextName, bankName );
430	var imageObject = bank.add( index, name, tags );
431	if ( canvas )
432	{
433		bank.setElement( index, canvas, hotSpot );
434		this.aoz.renderer.newImage( imageObject );
435	}	
436};
437Banks.prototype.insertImageRange = function( bankName, first, last, tags, contextName, bankIndex )
438{
439	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
440	this.getBank( bankIndex, contextName, bankName ).addRange( first, last, tags );
441};
442Banks.prototype.insertImageFromArray = function( bankName, arrayIndex, arrayNames, tags, contextName, bankIndex )
443{
444	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
445	var bank = this.getBank( bankIndex, contextName, bankName );
446	arrayNames = typeof arrayNames == 'undefined' ? {} : arrayNames;
447	for ( var i in arrayIndex )
448		bank.add( arrayIndex[ i ], arrayNames[ i ], tags );
449};
450Banks.prototype.setImageCanvas = function( bankName, index, canvas, tags, contextName, bankIndex )
451{
452	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
453	this.getBank( bankIndex, contextName, bankName ).getElement( index ).setElement( canvas );
454};
455Banks.prototype.deleteImage = function( bankName, index, contextName, contextName, bankIndex )
456{
457	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
458	var bank = this.getBank( bankIndex, contextName, bankName );
459	if ( typeof index == 'undefined' )
460		bank.reset();
461	else
462		bank.delete( index );
463};
464Banks.prototype.deleteImageRange = function( bankName, first, last, contextName, bankIndex )
465{
466	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
467	var bank = this.getBank( bankIndex, contextName, bankName );
468	if ( typeof first == 'undefined' && typeof last == 'undefined' )
469		bank.reset();
470	else
471	{
472		last = typeof last != 'undefined' ? last : first + 1;
473		bank.deleteRange( first, last );
474	}
475};
476Banks.prototype.deleteImagesFromArray = function( bankName, _array, contextName, bankIndex )
477{
478	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
479	var bank = this.getBank( bankIndex, contextName, bankName );
480	for ( var i in _array )
481		bank.delete( _array[ i ] );
482};
483Banks.prototype.getImagePalette = function( bankName, contextName, bankIndex )
484{
485	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
486	return this.getBank( bankIndex, contextName, bankName ).getPalette();
487};
488Banks.prototype.processMask = function( bankName, index, onOff, contextName, bankIndex )
489{
490	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
491	var bank = this.getBank( bankIndex, contextName, bankName );
492	var from = onOff ? { r: 0, g: 0, b: 0, a: 255 } : { r: 0, g: 0, b: 0, a: 0 };
493	var to = onOff ? { r: 0, g: 0, b: 0, a: 0 } : { r: 0, g: 0, b: 0, a: 255 };
494	if ( typeof number != 'undefined' )
495	{
496		var element = bank.getElement( index );
497		var canvas = element.getCanvas();
498		var context = canvas.getContext( '2d', { willReadFrequently:undefined } );
499		this.utilities.remapBlock( context, [ from ], [ to ], { x: 0, y: 0, width: canvas.width, height: canvas.height } );
500	}
501	else
502	{
503		var self = this;
504		bank.context.parseAll( contextName, function( element )
505		{
506			var canvas = element.getCanvas();
507			var context = canvas.getContext( '2d', { willReadFrequently:undefined } );
508			self.utilities.remapBlock( context, [ from ], [ to ], { x: 0, y: 0, width: canvas.width, height: canvas.height } );
509		} );
510	}
511};
512
513
514function ImageBank( aoz, imageList, imageTypesList, palette, options )
515{
516	this.aoz = aoz;
517	this.utilities = aoz.utilities;
518	this.palette = palette;
519	options.masks = ( typeof options.masks == 'undefined' ? [] : options.masks );
520	options.masks = options.masks.length > 0 ? JSON.parse( options.masks ) : [];
521	this.options = options;
522	this.domain = options.domain;
523	this.type = options.type;
524	this.path = options.path;
525	this.context = new AOZContext( this.aoz, this.domain, {} );
526	if ( imageList )
527		this.loadList( imageList, imageTypesList, options );
528};
529ImageBank.prototype.isType = function( types )
530{
531	if ( typeof types == 'string' )
532		types = [ types ];
533	for ( var t = 0; t < types.length; t++ )
534	{
535		if ( types[ t ] == this.type )
536			return true;
537	}
538	return false;
539};
540ImageBank.prototype.loadList = function( imageList, imageTypesList, options )
541{
542	var self = this;
543	tags = typeof options.tags == 'undefined' ? '' : options.tags;
544	var indexMap = [];
545	for ( var i = 0; i < imageList.length; i++ )
546	{
547		this.aoz.loadingMax++;
548		var infos = this.context.getElementInfosFromFilename( this.domain, imageList[ i ], 'image', i + 1, indexMap );
549		infos.path = './resources/' + this.path + '/' + imageList[ i ];
550		infos.number = i;
551		if ( typeof infos.index == 'undefined' )
552			infos.index = 10000000 + i;
553		this.utilities.loadUnlockedImage( infos.path, { type: imageTypesList[ i ] }, function( response, imageLoaded, extra )
554		{
555			if ( response )
556			{
557				// Calculate transparency?
558				if ( !options.alpha )
559					imageLoaded = self.utilities.makeTransparentImage( imageLoaded );
560					
561				// Set color 0 transparent
562				
563				var image =
564				{
565					aoz: self.aoz,
566					bank: self,
567					name: extra.name,
568					path: extra.path,
569					canvas: imageLoaded,
570					width: imageLoaded.width,
571					height: imageLoaded.height,
572					hotSpotX: 0,
573					hotSpotY: 0,
574					collisionMaskMethod: self.aoz.manifest.collisions.method,
575					collisionMaskPrecision: self.aoz.manifest.collisions.precision,
576					collisionMaskAlphaThreshold: self.aoz.manifest.collisions.alphaThreshold,
577					getCanvas: self.getImageCanvas,
578					getHotSpot: self.getImageHotSpot,
579					getCollisionMask: self.getCollisionMask
580				};
581				self.context.setElement( this.domain, image, extra.index, true );
582				self.setHotSpot( extra.index, options.hotSpots[ extra.number ] );
583				self.setTags( extra.index, tags );
584
585				// Call renderer
586				self.aoz.renderer.imageLoaded( image, extra );
587			}
588			self.aoz.loadingCount++;
589		}, infos );
590	}
591};
592ImageBank.prototype.load = function( index, name, path, width, height, tags )
593{
594	var self = this;
595	var infos = this.utilities.getElementInfosFromFilename( this.domain, path, 'image' );
596	index = typeof index == 'undefined' ? infos.index : index;
597	name = typeof name == 'undefined' ? infos.name : name;
598	var image = new Image();
599	this.aoz.loadingMax++;
600	image.onload = function()
601	{
602		var canvas = document.createElement( 'canvas' );
603		canvas.width = typeof width != 'undefined' ? width : this.width;
604		canvas.height = typeof height != 'undefined' ? height : this.height;
605		var context = canvas.getContext( '2d' );
606		context.imageSmoothingEnabled = self.utilities.isTag( tags, [ 'smooth' ] )
607		context.drawImage( this, 0, 0 );
608		var newImage =
609		{
610			aoz: self.aoz,
611			bank: self,
612			name: name,
613			canvas: canvas,
614			width: canvas.width,
615			height: canvas.height,
616			hotSpotX: 0,
617			hotSpotY: 0,
618			collisionMaskMethod: self.aoz.manifest.collisions.method,
619			collisionMaskPrecision: self.aoz.manifest.collisions.precision,
620			collisionMaskAlphaThreshold: self.aoz.manifest.collisions.alphaThreshold,
621			getCanvas: self.getImageCanvas,
622			getHotSpot: self.getImageHotSpot,
623			getCollisionMask: self.getCollisionMask
624		}
625		self.context.setElement( this.domain, newImage, index, true );
626		self.setTags( index, tags );
627		self.aoz.loadingCount++;
628	};
629	image.src = path;
630};
631ImageBank.prototype.add = function( index, tags )
632{
633	var name;
634	if ( typeof index == 'string' )
635		name = index;
636	else
637		name = 'image#' + index;
638	var image =
639	{
640		aoz: this.aoz,
641		bank: this,
642		name: name,
643		canvas: null,
644		width: 0,
645		height: 0,
646		hotSpotX: 0,
647		hotSpotY: 0,
648		collisionMaskMethod: this.aoz.manifest.collisions.method,
649		collisionMaskPrecision: this.aoz.manifest.collisions.precision,
650		collisionMaskAlphaThreshold: this.aoz.manifest.collisions.alphaThreshold,
651		getCanvas: this.getImageCanvas,
652		getHotSpot: this.getImageHotSpot,
653		getCollisionMask: this.getCollisionMask,
654		collisions: null
655	}
656	this.context.setElement( this.domain, image, index, true );
657	this.setTags( image, tags );
658	return image;
659};
660ImageBank.prototype.addRange = function( first, last, tags )
661{
662	last = typeof last =='undefined' ? first + 1 : last;
663	if ( last < first )
664		throw { error: 'illegal_function_call', parameters: [ first, last ] };
665
666	var result = [];
667	for ( var count = first; count < last; count++ )
668	{
669		result.push( this.add( count, tags ) );
670	}
671	return result;
672};
673ImageBank.prototype.getScreen = function( update )
674{
675	var screen = undefined;
676	if ( this.name.indexOf( 'screen(' ) == 0 )
677	{
678		var end = this.name.indexOf( ')' );
679		var screenIndex = this.name.substring( 7, end );
680		screen = this.aoz.getScreen( screenIndex );
681		if ( update )
682		{
683			this.screen = screen;
684			this.canvas = screen.canvas;
685			this.width = screen.vars.width;
686			this.height = screen.vars.height;
687			this.hotSpotX = screen.vars.hotSpotX;
688			this.hotSpotY = screen.vars.hotSpotY;
689		}
690	}
691	return screen;
692};
693ImageBank.prototype.getImageCanvas =  function( hRev, vRev )
694{
695	if ( typeof vRev == 'undefined' )
696	{
697		vRev = ( hRev & 0x4000 ) != 0;
698		hRev = ( hRev & 0x8000 ) != 0;
699	}
700	//this.bank.getScreen( true );
701	var canvas = this.canvas;
702	if ( canvas )
703	{
704		if ( hRev || vRev )
705		{
706			if ( hRev && vRev )
707			{
708				if ( !this.canvasRev || canvas.sprite )
709					this.canvasRev = this.aoz.utilities.flipCanvas( this.canvas, true, true );
710				canvas = this.canvasRev;
711			}
712			else if ( hRev )
713			{
714				if ( !this.canvasHRev || canvas.sprite )
715					this.canvasHRev = this.aoz.utilities.flipCanvas( this.canvas, true, false );
716				canvas = this.canvasHRev;
717			}
718			else
719			{
720				if ( !this.canvasVRev || canvas.sprite )
721					this.canvasVRev = this.aoz.utilities.flipCanvas( this.canvas, false, true );
722				canvas = this.canvasVRev;
723			}
724		}
725	}
726	return canvas;
727};
728ImageBank.prototype.getImageHotSpot =  function( hRev, vRev )
729{
730	if ( typeof vRev == 'undefined' )
731	{
732		vRev = ( hRev & 0x4000 ) != 0;
733		hRev = ( hRev & 0x8000 ) != 0;
734	}
735	//this.bank.getScreen( true );
736	return { x: hRev ? this.canvas.width - this.hotSpotX : this.hotSpotX, y: vRev ? this.canvas.height - this.hotSpotY : this.hotSpotY };
737};
738ImageBank.prototype.getCollisionMask = function()
739{
740	if ( this.aoz.moduleCollisions )
741	{
742		let id = 0;
743		let collection;
744		if (this.actor) {
745			// FVL: 15/04/24. Actors store collection masks per image and per couple HREV/VREV
746			id = (this.actor.VRev ? 1 : 0) * 2 + (this.actor.HRev ? 1 : 0);		// FVL: 2x2 grid, cells numbered 0,1,2,3
747			this.collisionMaskCollection = this.collisionMaskCollection || {};
748			this.collisionMaskCollection[this.actor.Image] = this.collisionMaskCollection[this.actor.Image] || [];
749			collection = this.collisionMaskCollection[this.actor.Image];
750		} else {
751			// non-actors have a collection of only one item
752			this.collisionMaskCollection = this.collisionMaskCollection || [];
753			collection = this.collisionMaskCollection;
754		}
755		
756		this.collisionMask = collection[id];
757		
758		if ( !this.collisionMask )
759		{
760			for ( var m in this.bank.options.masks )
761			{
762				if ( m == this.path )
763				{
764					collection[id] = 				
765					{
766						imageObject: this,
767						hulls: this.aoz.utilities.copyArray( this.bank.options.masks[ m ] )
768					}
769					this.collisionMask = this.collection[id];
770					return this.collisionMask;
771				}
772			}
773			collection[id] = 
774			{
775				imageObject: this,
776				hulls: this.aoz.moduleCollisions.newImage( this )
777			}
778			this.collisionMask = collection[id];
779		}
780		
781		return this.collisionMask;
782	}
783	return;
784};
785ImageBank.prototype.getLength = function()
786{
787	return this.context.getNumberOfElements( this.domain );
788};
789ImageBank.prototype.setLength = function()
790{
791	throw 'illegal_function_call';
792};
793ImageBank.prototype.setElement = function( index, canvas, hotSpot, tags )
794{
795	var image = this.context.getElement( this.domain, index, 'image_not_defined' );
796	image.canvas = canvas;
797	if( window.application.aoz.manifest.platform == 'amiga' )
798	{
799		var ctx = image.canvas.getContext( '2d' );
800		ctx.mozImageSmoothingEnabled = false;
801		ctx.webkitImageSmoothingEnabled = false;
802		ctx.msImageSmoothingEnabled = false;
803		ctx.imageSmoothingEnabled = false;
804		image.canvas.imageSmoothEnabled = false;
805	}
806	image.width = canvas.width;
807	image.height = canvas.height;
808	image.canvasRev = null;
809	image.canvasHRev = null;
810	image.canvasVRev = null;
811	if ( hotSpot )
812	{
813		image.hotSpotX = hotSpot.x;
814		image.hotSpotY = hotSpot.y;
815	}
816};
817ImageBank.prototype.getElement = function( index )
818{
819	var image = this.context.getElement( this.domain, index, '' );
820	if ( image && image.canvas )
821		return image;
822	throw { error: 'image_not_defined', parameter: index };
823};
824ImageBank.prototype.getPalette = function()
825{
826	return this.palette;
827};
828ImageBank.prototype.setPalette = function( palette )
829{
830	this.palette = palette;
831};
832ImageBank.prototype.reset = function()
833{
834	this.context.reset( this.domain );
835};
836ImageBank.prototype.delete = function( index )
837{
838	this.context.deleteElement( this.domain, index );
839};
840ImageBank.prototype.deleteRange = function( first, last )
841{
842	this.context.deleteRange( this.domain, first, last );
843};
844ImageBank.prototype.setTags = function( index, tags )
845{
846	if ( tags )
847	{
848		var image;
849		if ( this.utilities.isObject( index ) )
850			image = index;
851		else
852			image = this.context.getElement( this.domain, index, 'image_not_defined' );
853		if ( this.utilities.isTag( tags, [ 'hotSpotX', 'hotSpotY' ] ) )
854		{
855			var x = this.utilities.getTagParameter( tags, 'hotSpotX' );
856			if ( typeof x == 'string' )
857			{
858				switch ( x )
859				{
860					case 'left':
861						image.hotSpotX = 0;
862						break;
863					case 'center':
864						image.hotSpotX = image.width / 2;
865						break;
866					case 'right':
867						image.hotSpotX = image.width;
868						break;
869				}
870			}
871			else if ( typeof x == 'number' )
872			{
873				image.hotSpotX = x;
874			}
875
876			var y = this.utilities.getTagParameter( tags, 'hotSpotY' );
877			if ( typeof y == 'string' )
878			{
879				switch ( y )
880				{
881					case 'top':
882						image.hotSpotY = 0;
883						break;
884					case 'middle':
885						image.hotSpotY = image.height / 2;
886						break;
887					case 'bottom':
888						image.hotSpotY = image.height;
889						break;
890				}
891			}
892			else if ( typeof y == 'number' )
893			{
894				image.hotSpotY = y;
895			}
896		}
897	}
898};
899ImageBank.prototype.getHotSpot = function( index, position )
900{
901	var image = this.context.getElement( this.domain, index, 'image_not_defined' );
902	if ( position.toLowerCase() == 'y' )
903		return image.hotSpotX;
904	return image.hotSpotY;
905};
906ImageBank.prototype.setHotSpot = function( index, position )
907{
908	var image = this.context.getElement( this.domain, index, 'image_not_defined' );
909	if ( position.x == 'mask' )
910	{
911		switch ( ( position.y & 0x70 ) >> 4 )
912		{
913			case 0:
914				image.hotSpotX = 0;
915				break;
916			case 1:
917				image.hotSpotX = image.width / 2;
918				break;
919			case 2:
920				image.hotSpotX = image.width;
921				break;
922		}
923		switch ( position.y & 0x07 )
924		{
925			case 0:
926				image.hotSpotY = 0;
927				break;
928			case 1:
929				image.hotSpotY = image.height / 2;
930				break;
931			case 2:
932				image.hotSpotY = image.height;
933				break;
934		}
935	}
936	else
937	{
938		if ( typeof position.x != 'undefined' )
939			image.hotSpotX = position.x;
940		if ( typeof position.y != 'undefined' )
941			image.hotSpotY = position.y;
942	}
943};
944ImageBank.prototype.erase = function( index )
945{
946};
947
948
949//////////////////////////////////////////////////////////////////////////
950//
951// SOUND BANK
952//
953//////////////////////////////////////////////////////////////////////////
954Banks.prototype.samBank = function( number )
955{
956	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
957	var bank = this.getBank( number, contextName, 'samples' );
958	this.samBankNumber = number;
959};
960Banks.prototype.getSound = function( index, contextName, bankIndex )
961{
962	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
963	bankIndex = ( contextName == 'application' ? ( typeof bankIndex == 'undefined' ? this.samBankNumber : bankIndex ) : bankIndex );
964	var bank = this.getBank( bankIndex, contextName, 'samples' );
965	return bank.getElement( index );
966};
967Banks.prototype.insertSample = function( index, name, tags, sample, contextName, bankIndex )
968{
969	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
970	var bank = this.getBank( bankIndex, contextName, 'samples' );
971	bank.add( index, name, tags );
972	if ( typeof sample != 'undefined' )
973		bank.setElement( index, sample, tags );
974};
975Banks.prototype.insertSampleRange = function( first, last, tags, contextName, bankIndex )
976{
977	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
978	this.getBank( bankIndex, contextName, 'samples' ).addRange( first, last, tags );
979};
980Banks.prototype.deleteSample = function( index, contextName, bankIndex )
981{
982	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
983	this.getBank( bankIndex, contextName, 'samples' ).delete( index );
984};
985Banks.prototype.deleteSampleRange = function( first, last, contextName, bankIndex )
986{
987	contextName = typeof contextName == 'undefined' ? this.aoz.currentContextName : contextName;
988	var bank = this.getBank( bankIndex, contextName, 'samples' );
989	if ( typeof first == 'undefined' && typeof last == 'undefined' )
990	{
991		bank.reset( this.domain );
992	}
993	else
994	{
995		last = typeof last != 'undefined' ? last : first + 1;
996		bank.deleteRange( first, last );
997	}
998};
999
1000function SampleBank( aoz, soundList, soundListTypes, options )
1001{
1002	this.aoz = aoz;
1003	this.banks = aoz.banks;
1004	this.utilities = aoz.utilities;
1005	this.options = options;
1006	this.domain = options.domain;
1007	this.type = options.type;
1008	this.path = options.path;
1009	this.context = new AOZContext( this.aoz, this.domain, {} );
1010	this.soundList = soundList;
1011	this.soundListTypes = soundListTypes;
1012	if ( soundList )
1013		this.loadList( soundList, soundListTypes, options );
1014};
1015SampleBank.prototype.isType = function( types )
1016{
1017	if ( typeof types == 'string' )
1018		types = [ types ];
1019	for ( var t = 0; t < types.length; t++ )
1020	{
1021		if ( types[ t ] == this.type )
1022			return true;
1023	}
1024	return false;
1025};
1026SampleBank.prototype.loadList = function( soundList, soundListTypes, callback, extra )
1027{
1028	var self = this;
1029	soundList = typeof soundList != 'undefined' ? soundList : this.soundList;
1030	soundListTypes = typeof soundListTypes != 'undefined' ? soundListTypes : this.soundListTypes;
1031	var count = soundList.length;
1032	var error;
1033	var indexMap = {};
1034	for ( var i = 0; i < soundList.length; i++ )
1035	{
1036		var element = soundList[ i ];
1037		var infos = this.context.getElementInfosFromFilename( this.domain, element.a, this.type, i + 1, indexMap );
1038		infos.path = './resources/' + this.path + '/' + element.a;
1039		infos.filename = element.b;
1040		this.aoz.loadingMax++;
1041
1042		this.utilities.loadUnlockedSound( infos.path, { }, function( response, data, extra )
1043		{
1044			if ( response )
1045			{
1046				self.aoz.sounds.loadSound( data, function( response, data, extra2 )
1047				{
1048					count--;
1049					self.aoz.loadingCount++;
1050					if ( response )
1051					{
1052						if ( extra2.name )
1053							data.name = extra2.name;
1054						self.context.setElement( self.domain, data, extra2.index, true );
1055					}
1056					else
1057					{
1058						console.log( '*** Cannot load sound: ' + extra2.name );
1059						error = 'cannot_load_sound';
1060					}
1061				}, extra );
1062			}
1063			else
1064			{
1065				console.log( '*** Cannot load sound: ' + extra.name );				
1066				error = 'cannot_load_sound';
1067				count--;
1068			}
1069			if ( count == 0 )
1070			{
1071				if ( callback )
1072				{
1073					if ( !error )
1074						callback( true, {}, extra );
1075					else
1076						callback( false, error, extra );
1077				}
1078			}
1079		}, infos );
1080	}
1081};
1082SampleBank.prototype.load = function( index, name, path, type, tags )
1083{
1084	// TODO
1085};
1086SampleBank.prototype.addSound = function( index, name, arrayBuffer, tags, callback, extra )
1087{
1088	this.aoz.sounds.loadSound( arrayBuffer, function( response, data, extra )
1089	{
1090		if ( !response )
1091		{
1092			console.log( '*** Cannot load sound: ' + extra.name );
1093			error = 'cannot_load_sound';
1094		}
1095		else
1096		{			
1097			this.context.setElement( self.domain, data, index, true );
1098		}
1099		callback( response, data, extra );
1100	}, {} );
1101};
1102SampleBank.prototype.add = function( index, name, pool )
1103{
1104	if ( typeof name == 'undefined' )
1105	{
1106		if ( typeof index == 'string' )
1107			name = index;
1108		else
1109			name = 'sound#' + index;
1110	}
1111	var sample =
1112	{
1113		name: name,
1114		filename: '',
1115		sounds: []
1116	}
1117	this.context.setElement( this.domain, sample, index, true );
1118	if ( typeof tags != 'undefined' )
1119		this.setTags( index, tags );
1120	return sample;
1121};
1122SampleBank.prototype.addRange = function( first, last, tags )
1123{
1124	last = typeof last == 'undefined' ? first + 1 : last;
1125	if ( last < first || first < 0 || last < 0 )
1126		throw { error: 'illegal_function_call', parameters: [ first, last ] };
1127	var result = [];
1128	for ( var index = first; index < last; index++ )
1129	{
1130		var sample =
1131		{
1132			name: 'sound#' + index,
1133			filename: '',
1134			sounds: []
1135		}
1136		result.push( sample );
1137		this.context.setElement( this.domain, sample, index, true );
1138		this.setTags( index, tags );
1139	}
1140	return result;
1141};
1142SampleBank.prototype.setElement = function( index, sound, tags )
1143{
1144	this.context.getElement( this.domain, index, 'sound_not_defined' ).sounds = [ sound ];
1145	this.setTags( index, tags );
1146};
1147SampleBank.prototype.getElement = function( index )
1148{
1149	return this.context.getElement( this.domain, index, 'sound_not_defined' );
1150};
1151SampleBank.prototype.getLength = function()
1152{
1153	return this.context.getNumberOfElements( this.domain );
1154};
1155SampleBank.prototype.setLength = function()
1156{
1157	throw 'illegal_function_call';
1158};
1159SampleBank.prototype.reset = function()
1160{
1161	return this.context.reset( this.domain );
1162};
1163SampleBank.prototype.delete = function( index )
1164{
1165	return this.context.deleteElement( this.domain, index );
1166};
1167SampleBank.prototype.deleteRange = function( first, last )
1168{
1169	return this.context.deleteRange( this.domain, first, last );
1170};
1171SampleBank.prototype.setTags = function( index, tags )
1172{
1173};
1174SampleBank.prototype.erase = function( index )
1175{
1176};
1177
1178// 3D bank
1179/////////////////////////////////////////////////////////////////////////////////
1180function TDBank( aoz, loadList, types, options )
1181{
1182	this.aoz = aoz;
1183	this.banks = aoz.banks;
1184	this.utilities = aoz.utilities;
1185	this.options = options;
1186	this.domain = options.domain;
1187	this.type = options.type;
1188	this.path = options.path;
1189	this.types = types;
1190	this.context = new AOZContext( this.aoz, this.domain, {} );
1191	if ( loadList )
1192		this.loadList( loadList, types );
1193};
1194TDBank.prototype.isType = function( types )
1195{
1196	if ( typeof types == 'string' )
1197		types = [ types ];
1198	for ( var t = 0; t < types.length; t++ )
1199	{
1200		if ( types[ t ] == this.type )
1201			return true;
1202	}
1203	return false;
1204};
1205TDBank.prototype.getElement = function( index, type, noError )
1206{
1207	var types = 
1208	{
1209		scene: [ 'gltf', 'glb', 'obj', 'fbx', 'dae', 'aoz3d' ],
1210		mesh: [ 'gltf', 'glb', 'obj', 'fbx', 'dae', 'aoz3d' ],
1211		material: [ ],
1212		texture: [ 'hdr', 'tga', 'exr' ]
1213	}
1214	var errorMessage = noError ? undefined : 'bank_element_not_defined';
1215
1216	var element;
1217	if ( !index )
1218		element = this.context.getElement( this.domain, 1 );
1219	else
1220		element = this.context.getElement( this.domain, index );
1221	if ( element && element.aoz )
1222	{
1223		if ( type )
1224		{
1225			var list = types[ type ];
1226			if ( list )
1227			{
1228				for ( var l = 0; l < list.length; l++ )
1229				{
1230					if ( element.type == list[ l ] )
1231						return element;
1232				}
1233			}
1234			if ( errorMessage )
1235				throw { error: errorMessage, parameter: index };
1236			return undefined;
1237		}
1238		return element;
1239	}
1240	if ( errorMessage )
1241		throw { error: errorMessage, parameter: index };
1242	return undefined;
1243};
1244TDBank.prototype.loadList = function( loadList, types )
1245{
1246	var indexMap = {};
1247	for ( var i = 0; i < loadList.length; i++ )
1248	{
1249		var infos = this.context.getElementInfosFromFilename( this.domain, loadList[ i ], types[ i ], i + 1, indexMap );		
1250		var element = new TDElement( this.aoz, this,
1251		{
1252			name: this.aoz.utilities.getFilename( loadList[ i ] ),
1253			path: './resources/' + this.path + '/' + loadList[ i ], 
1254			filename: loadList[ i ],
1255			type: types[ i ]
1256		} );
1257		this.context.setElement( this.domain, element, infos.index, true );
1258	}
1259};
1260TDBank.prototype.save = function( path, tags )
1261{
1262};
1263TDBank.prototype.add = function( index, name )
1264{
1265	if ( typeof name == 'undefined' )
1266	{
1267		name = typeof index == 'string' ? index : this.domain + '#' + index;
1268	}
1269	this.context.setElement( this.domain, { name: name }, index, true );
1270};
1271TDBank.prototype.addRange = function( first, last, tags )
1272{
1273	last = typeof last == 'undefined' ? first + 1 : last;
1274	if ( last < first || first < 0 || last < 0 )
1275		throw { error: 'illegal_function_call', parameters: [ first, last ] };
1276	for ( var index = first; index < last; index++ )
1277	{
1278		this.context.setElement( this.domain, { name: this.domain + '#' + index }, index, true );
1279	}
1280};
1281TDBank.prototype.setElement = function( index, block, tags )
1282{
1283	this.context.setElement( this.domain, block, index, true );
1284};
1285TDBank.prototype.erase = function()
1286{
1287};
1288TDBank.prototype.delete = function( index )
1289{
1290	return this.context.deleteElement( this.domain, index );
1291};
1292TDBank.prototype.deleteRange = function( first, last )
1293{
1294	return this.context.deleteRange( this.domain, first, last );
1295};
1296TDBank.prototype.getLength = function( index )
1297{
1298	return this.context.numberOfElements;
1299};
1300TDBank.prototype.setLength = function( newLength )
1301{
1302};
1303TDBank.prototype.setTags = function( index, tags )
1304{
1305};
1306
1307
1308function TDElement( aoz, bank, args )
1309{
1310	this.aoz = aoz;
1311	this.bank = bank;
1312	this.path = args.path;
1313	this.filename = args.filename;
1314	this.type = args.type;
1315	this.name = args.name;
1316	this.mesh = args.mesh;
1317	this.data = null;
1318}
1319TDElement.prototype.loadScene = function( options, callback, extra )
1320{
1321	if ( !this.data )
1322	{
1323		var loader;
1324		switch ( this.type )
1325		{
1326			case 'gltf':
1327			case 'glb':
1328				loader = new THREE.GLTFLoader();
1329				break;
1330			case 'obj':
1331				loader = new THREE.OBJLoader();
1332				break;
1333			case 'fbx':
1334				loader = new THREE.FBXLoader();
1335				break;
1336			case 'dae':
1337				loader = new THREE.ColladaLoader();
1338				break;
1339			case 'aoz3d':
1340				loader = new THREE.ObjectLoader();
1341				break;
1342			default:
1343				loader = new this.tdLoader();
1344				break;					
1345		}
1346
1347		var self = this;
1348		loader.load( this.path + '?update=' + Date.now(), function ( model )
1349		{
1350			switch ( self.type )
1351			{
1352				case 'aoz3d':
1353					self.data = model;
1354					var xhr = new XMLHttpRequest();
1355					xhr.onload = function( progressEvent )
1356					{
1357						var json = JSON.parse( xhr.responseText );
1358						self.aozData = json.object.aozEvents;							
1359						callback( true, self, extra );
1360					};
1361					xhr.open( "GET", self.path, true );
1362					xhr.send();
1363					break;
1364				
1365				case 'glb':
1366				case 'gltf':
1367				case 'dae':
1368					self.data = model.scene;
1369					callback( true, self, extra );
1370					break;
1371
1372				case 'obj':
1373				case 'fbx':
1374					if ( model.scene )
1375						self.data = model.scene;
1376					else
1377					{
1378						var group = new THREE.Group();
1379						if( model.children )
1380						{
1381							for( var c = 0; c < model.children.length; c++ )
1382								group.add( model.children[ c ] );
1383						}
1384						else
1385							group.add( model );
1386						self.data = group;
1387					}
1388					if( model.animations )
1389					{
1390						self.animations = model.animations;
1391						self.mixer = undefined;
1392					}
1393					callback( true, self, extra );
1394					break;
1395				default:
1396					this.data = model;
1397					callback( true, self, extra );
1398					break;
1399			}
1400		}, undefined, function ( error )
1401		{
1402			callback( false, 'cannot_load_asset', extra );
1403		} );
1404		return null;
1405	}
1406	return this.data;
1407}
1408
1409TDElement.prototype.loadTexture = function( options, callback, extra )
1410{
1411	if ( !this.data )
1412	{
1413		var loader;
1414		switch ( this.type )
1415		{
1416			default:
1417			case 'hdr':
1418				loader = new THREE.RGBELoader();
1419				break;
1420			case 'tga':
1421				loader = new THREE.TGALoader();
1422				break;
1423			case 'exr':
1424				loader = new THREE.EXRLoader();
1425				break;
1426		}
1427
1428		var self = this;
1429		loader.setPath( this.aoz.utilities.getDirectoryFromPath( this.path ) + '/' )
1430		loader.load( this.filename, function ( texture )
1431		{
1432			self.data = texture;
1433			callback( true, texture, extra );
1434		}, undefined, function ( error )
1435		{
1436			callback( false, 'cannot_load_asset', extra );
1437		} );
1438		return null;
1439	}
1440	return this.data;
1441}
1442
1443TDElement.prototype.loadObject = function( options, callback, extra )
1444{
1445	if ( !this.data )
1446	{
1447		if ( this.type == 'mesh' )
1448			this.data = this.mesh;
1449		else
1450		{
1451			var loader;
1452			switch ( this.type )
1453			{
1454				case 'gltf':
1455				case 'glb':
1456					loader = new THREE.GLTFLoader();
1457					break;
1458				case 'obj':
1459					loader = new THREE.OBJLoader();
1460					break;
1461				case 'fbx':
1462					loader = new THREE.FBXLoader();
1463					break;
1464				case 'dae':
1465					loader = new THREE.ColladaLoader();
1466					break;
1467				case 'aoz3d':
1468					loader = new THREE.ObjectLoader();
1469					break;
1470				default:
1471					loader = new this.tdLoader();
1472					break;					
1473			}
1474
1475			var self = this;
1476			loader.load( this.path + '?update=' + Date.now(), function ( model )
1477			{
1478				switch ( self.type )
1479				{
1480					//case 'aoz3d':
1481					case 'gltf':
1482					case 'dae':
1483						if ( model.scene.children.length > 0 )
1484						{
1485							self.data = model.scene.children[ 0 ].clone();
1486							callback( true, self, extra );
1487							return;
1488						}
1489						break;
1490
1491					case 'glb':
1492						var group = new THREE.Group();
1493						model = model.scene;
1494						if( model.children )
1495						{
1496							for( var c = 0; c < model.children.length; c++ )
1497								group.add( model.children[ c ] );
1498						}
1499						else
1500							group.add( model );
1501						self.data = group;
1502						callback( true, self, extra );
1503						return;
1504
1505					case 'obj':
1506					case 'fbx':
1507						if ( model.scene )
1508							self.data = model.scene;
1509						else
1510						{
1511							var group = new THREE.Group();
1512							if( model.children )
1513							{
1514								for( var c = 0; c < model.children.length; c++ )
1515									group.add( model.children[ c ] );
1516							}
1517							else
1518								group.add( model );
1519							self.data = group;
1520						}
1521						if( model.animations )
1522						{
1523							self.animations = model.animations;
1524							self.mixer = undefined;
1525						}
1526						callback( true, self, extra );
1527						return;
1528
1529					default:
1530						this.data = model;
1531						callback( true, self, extra );
1532						return;
1533				}
1534				callback( false, self, extra );
1535			}, undefined, function ( error )
1536			{
1537				callback( false, 'cannot_load_asset', extra );
1538			} );
1539			return null;
1540		}
1541	}
1542	return this;
1543}
1544
1545// Little loader for unknown types.
1546function tdLoader()
1547{
1548}
1549tdLoader.prototype.load = function( path, callback )
1550{
1551	var xhr = new XMLHttpRequest();
1552	xhr.onload = function( progressEvent )
1553	{
1554		callback( xhr.responseText );
1555	};
1556	xhr.open( "GET", path, true );
1557	xhr.send();
1558}
1559
1560// DATA Bank
1561////////////////////////////////////////////////////////////////////
1562function DataBank( aoz, loadList, length, options )
1563{
1564	this.aoz = aoz;
1565	this.banks = aoz.banks;
1566	this.utilities = aoz.utilities;
1567	this.options = options;
1568	this.domain = options.domain;
1569	this.type = options.type;
1570	this.path = options.path;
1571	this.context = new AOZContext( this.aoz, this.domain, {} );
1572	if ( loadList )
1573		this.loadList( loadList, options.tags );
1574	else if ( length > 0 )
1575		this.context.setElement( this.domain, this.aoz.allocMemoryBlock( length, this.aoz.endian ), 1, true );
1576};
1577DataBank.prototype.isType = function( types )
1578{
1579	if ( typeof types == 'string' )
1580		types = [ types ];
1581	for ( var t = 0; t < types.length; t++ )
1582	{
1583		if ( types[ t ] == this.type )
1584			return true;
1585	}
1586	return false;
1587};
1588DataBank.prototype.getElement = function( index, noError )
1589{
1590	var errorMessage = noError ? undefined : 'bank_element_not_defined';
1591
1592	var element;
1593	if ( !index )
1594		element = this.context.getElement( this.domain, 1, errorMessage );
1595	else
1596		element = this.context.getElement( this.domain, index, errorMessage );
1597	if ( element && element.aoz )
1598		return element;
1599	if ( errorMessage )
1600		throw { error: errorMessage, parameter: index };
1601	return undefined;
1602};
1603DataBank.prototype.loadList = function( loadList, tags )
1604{
1605	var self = this;
1606	tags = typeof tags == 'undefined' ? '' : tags;
1607	var indexMap = [];
1608	for ( var i = 0; i < loadList.length; i++ )
1609	{
1610		var element = loadList[ i ];
1611		var infos = this.context.getElementInfosFromFilename( this.domain, element.a, this.type, i + 1, indexMap );
1612		infos.path = './resources/' + this.path + '/' + element.a;
1613		infos.filename = element.b;
1614		this.utilities.loadUnlockedBankElement( infos.path, infos, function( response, data, extra )
1615		{
1616			if ( response )
1617			{
1618				var block = self.aoz.allocMemoryBlock( data, self.aoz.endian );
1619				block.path = extra.path;
1620				block.name = extra.name;
1621				block.filename = extra.filename;
1622				self.context.setElement( self.domain, block, extra.index, true );
1623			}
1624		}, infos );
1625	}
1626};
1627DataBank.prototype.save = function( path, tags )
1628{
1629	var start = this.getElement();
1630	this.aoz.filesystem.saveBinary( path, {}, function( response, data, extra )
1631	{
1632		self.load_done = true;
1633		if ( !response )
1634			throw data;
1635	} );
1636};
1637DataBank.prototype.add = function( index, name )
1638{
1639	if ( typeof name == 'undefined' )
1640	{
1641		name = typeof index == 'string' ? index : this.domain + '#' + index;
1642	}
1643	this.context.setElement( this.domain, { name: name }, index, true );
1644};
1645DataBank.prototype.addRange = function( first, last, tags )
1646{
1647	last = typeof last == 'undefined' ? first + 1 : last;
1648	if ( last < first || first < 0 || last < 0 )
1649		throw { error: 'illegal_function_call', parameters: [ first, last ] };
1650	for ( var index = first; index < last; index++ )
1651	{
1652		this.context.setElement( this.domain, { name: this.domain + '#' + index }, index, true );
1653	}
1654};
1655DataBank.prototype.setElement = function( index, block, tags )
1656{
1657	this.context.setElement( this.domain, block, index, true );
1658};
1659DataBank.prototype.erase = function()
1660{
1661	for ( var block = this.context.getFirstElement( this.domain ); block !=null; block = this.context.getNextElement( this.domain ) )
1662		this.aoz.freeMemoryBlock( block );
1663};
1664DataBank.prototype.delete = function( index )
1665{
1666	return this.context.deleteElement( this.domain, index );
1667};
1668DataBank.prototype.deleteRange = function( first, last )
1669{
1670	return this.context.deleteRange( this.domain, first, last );
1671};
1672DataBank.prototype.getLength = function( index )
1673{
1674	if ( this.type == 'tracker' )
1675	{
1676		if ( typeof index == 'undefined' )
1677			return this.context.numberOfElements;
1678		else
1679			return this.getElement( index ).length;
1680	}
1681	var element = this.context.getElement( this.domain, 1 );
1682	if ( element && element.aoz )
1683		return element.length;
1684	return this.context.numberOfElements;
1685};
1686DataBank.prototype.setLength = function( newLength )
1687{
1688	if ( this.type == 'tracker' )
1689		throw 'illegal_function_call';
1690	var element = this.context.getElement( this.domain, 1 );
1691
1692	// If MemoryBlock
1693	if ( element && element.aoz )
1694	{
1695		element.setLength( newLength );
1696		return;
1697	}
1698	throw 'illegal_function_call';
1699};
1700DataBank.prototype.setTags = function( index, tags )
1701{
1702};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.