1 /*
2  * Copyright (c) 2009-2012 jMonkeyEngine
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17  *   may be used to endorse or promote products derived from this software
18  *   without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 package com.jme3.scene.plugins.blender;
33 
34 import java.io.IOException;
35 import java.util.ArrayList;
36 import java.util.EmptyStackException;
37 import java.util.HashMap;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.Stack;
41 import java.util.logging.Level;
42 import java.util.logging.Logger;
43 
44 import com.jme3.animation.Skeleton;
45 import com.jme3.asset.AssetManager;
46 import com.jme3.asset.BlenderKey;
47 import com.jme3.material.Material;
48 import com.jme3.math.ColorRGBA;
49 import com.jme3.scene.plugins.blender.animations.BoneContext;
50 import com.jme3.scene.plugins.blender.animations.Ipo;
51 import com.jme3.scene.plugins.blender.constraints.Constraint;
52 import com.jme3.scene.plugins.blender.file.BlenderInputStream;
53 import com.jme3.scene.plugins.blender.file.DnaBlockData;
54 import com.jme3.scene.plugins.blender.file.FileBlockHeader;
55 import com.jme3.scene.plugins.blender.file.Structure;
56 import com.jme3.scene.plugins.blender.materials.MaterialContext;
57 import com.jme3.scene.plugins.blender.meshes.MeshContext;
58 import com.jme3.scene.plugins.blender.modifiers.Modifier;
59 import com.jme3.scene.plugins.ogre.AnimData;
60 
61 /**
62  * The class that stores temporary data and manages it during loading the belnd
63  * file. This class is intended to be used in a single loading thread. It holds
64  * the state of loading operations.
65  *
66  * @author Marcin Roguski (Kaelthas)
67  */
68 public class BlenderContext {
69 	private static final Logger					LOGGER					= Logger.getLogger(BlenderContext.class.getName());
70 
71 	/** The blender file version. */
72 	private int									blenderVersion;
73 	/** The blender key. */
74 	private BlenderKey							blenderKey;
75 	/** The header of the file block. */
76 	private DnaBlockData						dnaBlockData;
77 	/** The input stream of the blend file. */
78 	private BlenderInputStream					inputStream;
79 	/** The asset manager. */
80 	private AssetManager						assetManager;
81 	/**
82 	 * A map containing the file block headers. The key is the old pointer
83 	 * address.
84 	 */
85 	private Map<Long, FileBlockHeader>			fileBlockHeadersByOma	= new HashMap<Long, FileBlockHeader>();
86 	/** A map containing the file block headers. The key is the block code. */
87 	private Map<Integer, List<FileBlockHeader>>	fileBlockHeadersByCode	= new HashMap<Integer, List<FileBlockHeader>>();
88 	/**
89 	 * This map stores the loaded features by their old memory address. The
90 	 * first object in the value table is the loaded structure and the second -
91 	 * the structure already converted into proper data.
92 	 */
93 	private Map<Long, Object[]>					loadedFeatures			= new HashMap<Long, Object[]>();
94 	/**
95 	 * This map stores the loaded features by their name. Only features with ID
96 	 * structure can be stored here. The first object in the value table is the
97 	 * loaded structure and the second - the structure already converted into
98 	 * proper data.
99 	 */
100 	private Map<String, Object[]>				loadedFeaturesByName	= new HashMap<String, Object[]>();
101 	/** A stack that hold the parent structure of currently loaded feature. */
102 	private Stack<Structure>					parentStack				= new Stack<Structure>();
103 	/**
104 	 * A map storing loaded ipos. The key is the ipo's owner old memory address
105 	 * and the value is the ipo.
106 	 */
107 	private Map<Long, Ipo>						loadedIpos				= new HashMap<Long, Ipo>();
108 	/** A list of modifiers for the specified object. */
109 	protected Map<Long, List<Modifier>>			modifiers				= new HashMap<Long, List<Modifier>>();
110 	/** A list of constraints for the specified object. */
111 	protected Map<Long, List<Constraint>>		constraints				= new HashMap<Long, List<Constraint>>();
112 	/** Anim data loaded for features. */
113 	private Map<Long, AnimData>					animData				= new HashMap<Long, AnimData>();
114 	/** Loaded skeletons. */
115 	private Map<Long, Skeleton>					skeletons				= new HashMap<Long, Skeleton>();
116 	/** A map of mesh contexts. */
117 	protected Map<Long, MeshContext>			meshContexts			= new HashMap<Long, MeshContext>();
118 	/** A map of bone contexts. */
119 	protected Map<Long, BoneContext>			boneContexts			= new HashMap<Long, BoneContext>();
120 	/** A map of material contexts. */
121 	protected Map<Material, MaterialContext>	materialContexts		= new HashMap<Material, MaterialContext>();
122 	/** A map og helpers that perform loading. */
123 	private Map<String, AbstractBlenderHelper>	helpers					= new HashMap<String, AbstractBlenderHelper>();
124 
125 	/**
126 	 * This method sets the blender file version.
127 	 *
128 	 * @param blenderVersion
129 	 *            the blender file version
130 	 */
setBlenderVersion(String blenderVersion)131 	public void setBlenderVersion(String blenderVersion) {
132 		this.blenderVersion = Integer.parseInt(blenderVersion);
133 	}
134 
135 	/**
136 	 * @return the blender file version
137 	 */
getBlenderVersion()138 	public int getBlenderVersion() {
139 		return blenderVersion;
140 	}
141 
142 	/**
143 	 * This method sets the blender key.
144 	 *
145 	 * @param blenderKey
146 	 *            the blender key
147 	 */
setBlenderKey(BlenderKey blenderKey)148 	public void setBlenderKey(BlenderKey blenderKey) {
149 		this.blenderKey = blenderKey;
150 	}
151 
152 	/**
153 	 * This method returns the blender key.
154 	 *
155 	 * @return the blender key
156 	 */
getBlenderKey()157 	public BlenderKey getBlenderKey() {
158 		return blenderKey;
159 	}
160 
161 	/**
162 	 * This method sets the dna block data.
163 	 *
164 	 * @param dnaBlockData
165 	 *            the dna block data
166 	 */
setBlockData(DnaBlockData dnaBlockData)167 	public void setBlockData(DnaBlockData dnaBlockData) {
168 		this.dnaBlockData = dnaBlockData;
169 	}
170 
171 	/**
172 	 * This method returns the dna block data.
173 	 *
174 	 * @return the dna block data
175 	 */
getDnaBlockData()176 	public DnaBlockData getDnaBlockData() {
177 		return dnaBlockData;
178 	}
179 
180 	/**
181 	 * This method returns the asset manager.
182 	 *
183 	 * @return the asset manager
184 	 */
getAssetManager()185 	public AssetManager getAssetManager() {
186 		return assetManager;
187 	}
188 
189 	/**
190 	 * This method sets the asset manager.
191 	 *
192 	 * @param assetManager
193 	 *            the asset manager
194 	 */
setAssetManager(AssetManager assetManager)195 	public void setAssetManager(AssetManager assetManager) {
196 		this.assetManager = assetManager;
197 	}
198 
199 	/**
200 	 * This method returns the input stream of the blend file.
201 	 *
202 	 * @return the input stream of the blend file
203 	 */
getInputStream()204 	public BlenderInputStream getInputStream() {
205 		return inputStream;
206 	}
207 
208 	/**
209 	 * This method sets the input stream of the blend file.
210 	 *
211 	 * @param inputStream
212 	 *            the input stream of the blend file
213 	 */
setInputStream(BlenderInputStream inputStream)214 	public void setInputStream(BlenderInputStream inputStream) {
215 		this.inputStream = inputStream;
216 	}
217 
218 	/**
219 	 * This method adds a file block header to the map. Its old memory address
220 	 * is the key.
221 	 *
222 	 * @param oldMemoryAddress
223 	 *            the address of the block header
224 	 * @param fileBlockHeader
225 	 *            the block header to store
226 	 */
addFileBlockHeader(Long oldMemoryAddress, FileBlockHeader fileBlockHeader)227 	public void addFileBlockHeader(Long oldMemoryAddress, FileBlockHeader fileBlockHeader) {
228 		fileBlockHeadersByOma.put(oldMemoryAddress, fileBlockHeader);
229 		List<FileBlockHeader> headers = fileBlockHeadersByCode.get(Integer.valueOf(fileBlockHeader.getCode()));
230 		if (headers == null) {
231 			headers = new ArrayList<FileBlockHeader>();
232 			fileBlockHeadersByCode.put(Integer.valueOf(fileBlockHeader.getCode()), headers);
233 		}
234 		headers.add(fileBlockHeader);
235 	}
236 
237 	/**
238 	 * This method returns the block header of a given memory address. If the
239 	 * header is not present then null is returned.
240 	 *
241 	 * @param oldMemoryAddress
242 	 *            the address of the block header
243 	 * @return loaded header or null if it was not yet loaded
244 	 */
getFileBlock(Long oldMemoryAddress)245 	public FileBlockHeader getFileBlock(Long oldMemoryAddress) {
246 		return fileBlockHeadersByOma.get(oldMemoryAddress);
247 	}
248 
249 	/**
250 	 * This method returns a list of file blocks' headers of a specified code.
251 	 *
252 	 * @param code
253 	 *            the code of file blocks
254 	 * @return a list of file blocks' headers of a specified code
255 	 */
getFileBlocks(Integer code)256 	public List<FileBlockHeader> getFileBlocks(Integer code) {
257 		return fileBlockHeadersByCode.get(code);
258 	}
259 
260 	/**
261 	 * This method clears the saved block headers stored in the features map.
262 	 */
clearFileBlocks()263 	public void clearFileBlocks() {
264 		fileBlockHeadersByOma.clear();
265 		fileBlockHeadersByCode.clear();
266 	}
267 
268 	/**
269 	 * This method adds a helper instance to the helpers' map.
270 	 *
271 	 * @param <T>
272 	 *            the type of the helper
273 	 * @param clazz
274 	 *            helper's class definition
275 	 * @param helper
276 	 *            the helper instance
277 	 */
putHelper(Class<T> clazz, AbstractBlenderHelper helper)278 	public <T> void putHelper(Class<T> clazz, AbstractBlenderHelper helper) {
279 		helpers.put(clazz.getSimpleName(), helper);
280 	}
281 
282 	@SuppressWarnings("unchecked")
getHelper(Class<?> clazz)283 	public <T> T getHelper(Class<?> clazz) {
284 		return (T) helpers.get(clazz.getSimpleName());
285 	}
286 
287 	/**
288 	 * This method adds a loaded feature to the map. The key is its unique old
289 	 * memory address.
290 	 *
291 	 * @param oldMemoryAddress
292 	 *            the address of the feature
293 	 * @param featureName
294 	 *            the name of the feature
295 	 * @param structure
296 	 *            the filled structure of the feature
297 	 * @param feature
298 	 *            the feature we want to store
299 	 */
addLoadedFeatures(Long oldMemoryAddress, String featureName, Structure structure, Object feature)300 	public void addLoadedFeatures(Long oldMemoryAddress, String featureName, Structure structure, Object feature) {
301 		if (oldMemoryAddress == null || structure == null || feature == null) {
302 			throw new IllegalArgumentException("One of the given arguments is null!");
303 		}
304 		Object[] storedData = new Object[] { structure, feature };
305 		loadedFeatures.put(oldMemoryAddress, storedData);
306 		if (featureName != null) {
307 			loadedFeaturesByName.put(featureName, storedData);
308 		}
309 	}
310 
311 	/**
312 	 * This method returns the feature of a given memory address. If the feature
313 	 * is not yet loaded then null is returned.
314 	 *
315 	 * @param oldMemoryAddress
316 	 *            the address of the feature
317 	 * @param loadedFeatureDataType
318 	 *            the type of data we want to retreive it can be either filled
319 	 *            structure or already converted feature
320 	 * @return loaded feature or null if it was not yet loaded
321 	 */
getLoadedFeature(Long oldMemoryAddress, LoadedFeatureDataType loadedFeatureDataType)322 	public Object getLoadedFeature(Long oldMemoryAddress, LoadedFeatureDataType loadedFeatureDataType) {
323 		Object[] result = loadedFeatures.get(oldMemoryAddress);
324 		if (result != null) {
325 			return result[loadedFeatureDataType.getIndex()];
326 		}
327 		return null;
328 	}
329 
330 	/**
331 	 * This method returns the feature of a given name. If the feature is not
332 	 * yet loaded then null is returned.
333 	 *
334 	 * @param featureName
335 	 *            the name of the feature
336 	 * @param loadedFeatureDataType
337 	 *            the type of data we want to retreive it can be either filled
338 	 *            structure or already converted feature
339 	 * @return loaded feature or null if it was not yet loaded
340 	 */
getLoadedFeature(String featureName, LoadedFeatureDataType loadedFeatureDataType)341 	public Object getLoadedFeature(String featureName, LoadedFeatureDataType loadedFeatureDataType) {
342 		Object[] result = loadedFeaturesByName.get(featureName);
343 		if (result != null) {
344 			return result[loadedFeatureDataType.getIndex()];
345 		}
346 		return null;
347 	}
348 
349 	/**
350 	 * This method clears the saved features stored in the features map.
351 	 */
clearLoadedFeatures()352 	public void clearLoadedFeatures() {
353 		loadedFeatures.clear();
354 	}
355 
356 	/**
357 	 * This method adds the structure to the parent stack.
358 	 *
359 	 * @param parent
360 	 *            the structure to be added to the stack
361 	 */
pushParent(Structure parent)362 	public void pushParent(Structure parent) {
363 		parentStack.push(parent);
364 	}
365 
366 	/**
367 	 * This method removes the structure from the top of the parent's stack.
368 	 *
369 	 * @return the structure that was removed from the stack
370 	 */
popParent()371 	public Structure popParent() {
372 		try {
373 			return parentStack.pop();
374 		} catch (EmptyStackException e) {
375 			return null;
376 		}
377 	}
378 
379 	/**
380 	 * This method retreives the structure at the top of the parent's stack but
381 	 * does not remove it.
382 	 *
383 	 * @return the structure from the top of the stack
384 	 */
peekParent()385 	public Structure peekParent() {
386 		try {
387 			return parentStack.peek();
388 		} catch (EmptyStackException e) {
389 			return null;
390 		}
391 	}
392 
393 	/**
394 	 * This method adds new ipo curve for the feature.
395 	 *
396 	 * @param ownerOMA
397 	 *            the OMA of blender feature that owns the ipo
398 	 * @param ipo
399 	 *            the ipo to be added
400 	 */
addIpo(Long ownerOMA, Ipo ipo)401 	public void addIpo(Long ownerOMA, Ipo ipo) {
402 		loadedIpos.put(ownerOMA, ipo);
403 	}
404 
405 	/**
406 	 * This method removes the ipo curve from the feature.
407 	 *
408 	 * @param ownerOma
409 	 *            the OMA of blender feature that owns the ipo
410 	 */
removeIpo(Long ownerOma)411 	public Ipo removeIpo(Long ownerOma) {
412 		return loadedIpos.remove(ownerOma);
413 	}
414 
415 	/**
416 	 * This method returns the ipo curve of the feature.
417 	 *
418 	 * @param ownerOMA
419 	 *            the OMA of blender feature that owns the ipo
420 	 */
getIpo(Long ownerOMA)421 	public Ipo getIpo(Long ownerOMA) {
422 		return loadedIpos.get(ownerOMA);
423 	}
424 
425 	/**
426 	 * This method adds a new modifier to the list.
427 	 *
428 	 * @param ownerOMA
429 	 *            the owner's old memory address
430 	 * @param modifier
431 	 *            the object's modifier
432 	 */
addModifier(Long ownerOMA, Modifier modifier)433 	public void addModifier(Long ownerOMA, Modifier modifier) {
434 		List<Modifier> objectModifiers = this.modifiers.get(ownerOMA);
435 		if (objectModifiers == null) {
436 			objectModifiers = new ArrayList<Modifier>();
437 			this.modifiers.put(ownerOMA, objectModifiers);
438 		}
439 		objectModifiers.add(modifier);
440 	}
441 
442 	/**
443 	 * This method returns modifiers for the object specified by its old memory
444 	 * address and the modifier type. If no modifiers are found - empty list is
445 	 * returned. If the type is null - all modifiers for the object are
446 	 * returned.
447 	 *
448 	 * @param objectOMA
449 	 *            object's old memory address
450 	 * @param type
451 	 *            the type of the modifier
452 	 * @return the list of object's modifiers
453 	 */
getModifiers(Long objectOMA, String type)454 	public List<Modifier> getModifiers(Long objectOMA, String type) {
455 		List<Modifier> result = new ArrayList<Modifier>();
456 		List<Modifier> readModifiers = modifiers.get(objectOMA);
457 		if (readModifiers != null && readModifiers.size() > 0) {
458 			for (Modifier modifier : readModifiers) {
459 				if (type == null || type.isEmpty() || modifier.getType().equals(type)) {
460 					result.add(modifier);
461 				}
462 			}
463 		}
464 		return result;
465 	}
466 
467 	/**
468 	 * This method adds a new modifier to the list.
469 	 *
470 	 * @param ownerOMA
471 	 *            the owner's old memory address
472 	 * @param constraints
473 	 *            the object's constraints
474 	 */
addConstraints(Long ownerOMA, List<Constraint> constraints)475 	public void addConstraints(Long ownerOMA, List<Constraint> constraints) {
476 		List<Constraint> objectConstraints = this.constraints.get(ownerOMA);
477 		if (objectConstraints == null) {
478 			objectConstraints = new ArrayList<Constraint>();
479 			this.constraints.put(ownerOMA, objectConstraints);
480 		}
481 		objectConstraints.addAll(constraints);
482 	}
483 
484 	/**
485 	 * This method returns constraints for the object specified by its old
486 	 * memory address. If no modifiers are found - <b>null</b> is returned.
487 	 *
488 	 * @param objectOMA
489 	 *            object's old memory address
490 	 * @return the list of object's modifiers or null
491 	 */
getConstraints(Long objectOMA)492 	public List<Constraint> getConstraints(Long objectOMA) {
493 		return objectOMA == null ? null : constraints.get(objectOMA);
494 	}
495 
496 	/**
497 	 * This method sets the anim data for the specified OMA of its owner.
498 	 *
499 	 * @param ownerOMA
500 	 *            the owner's old memory address
501 	 * @param animData
502 	 *            the animation data for the feature specified by ownerOMA
503 	 */
setAnimData(Long ownerOMA, AnimData animData)504 	public void setAnimData(Long ownerOMA, AnimData animData) {
505 		this.animData.put(ownerOMA, animData);
506 	}
507 
508 	/**
509 	 * This method returns the animation data for the specified owner.
510 	 *
511 	 * @param ownerOMA
512 	 *            the old memory address of the animation data owner
513 	 * @return the animation data or null if none exists
514 	 */
getAnimData(Long ownerOMA)515 	public AnimData getAnimData(Long ownerOMA) {
516 		return this.animData.get(ownerOMA);
517 	}
518 
519 	/**
520 	 * This method sets the skeleton for the specified OMA of its owner.
521 	 *
522 	 * @param skeletonOMA
523 	 *            the skeleton's old memory address
524 	 * @param skeleton
525 	 *            the skeleton specified by the given OMA
526 	 */
setSkeleton(Long skeletonOMA, Skeleton skeleton)527 	public void setSkeleton(Long skeletonOMA, Skeleton skeleton) {
528 		this.skeletons.put(skeletonOMA, skeleton);
529 	}
530 
531 	/**
532 	 * This method returns the skeleton for the specified OMA of its owner.
533 	 *
534 	 * @param skeletonOMA
535 	 *            the skeleton's old memory address
536 	 * @return the skeleton specified by the given OMA
537 	 */
getSkeleton(Long skeletonOMA)538 	public Skeleton getSkeleton(Long skeletonOMA) {
539 		return this.skeletons.get(skeletonOMA);
540 	}
541 
542 	/**
543 	 * This method sets the mesh context for the given mesh old memory address.
544 	 * If the context is already set it will be replaced.
545 	 *
546 	 * @param meshOMA
547 	 *            the mesh's old memory address
548 	 * @param meshContext
549 	 *            the mesh's context
550 	 */
setMeshContext(Long meshOMA, MeshContext meshContext)551 	public void setMeshContext(Long meshOMA, MeshContext meshContext) {
552 		this.meshContexts.put(meshOMA, meshContext);
553 	}
554 
555 	/**
556 	 * This method returns the mesh context for the given mesh old memory
557 	 * address. If no context exists then <b>null</b> is returned.
558 	 *
559 	 * @param meshOMA
560 	 *            the mesh's old memory address
561 	 * @return mesh's context
562 	 */
getMeshContext(Long meshOMA)563 	public MeshContext getMeshContext(Long meshOMA) {
564 		return this.meshContexts.get(meshOMA);
565 	}
566 
567 	/**
568 	 * This method sets the bone context for the given bone old memory address.
569 	 * If the context is already set it will be replaced.
570 	 *
571 	 * @param boneOMA
572 	 *            the bone's old memory address
573 	 * @param boneContext
574 	 *            the bones's context
575 	 */
setBoneContext(Long boneOMA, BoneContext boneContext)576 	public void setBoneContext(Long boneOMA, BoneContext boneContext) {
577 		this.boneContexts.put(boneOMA, boneContext);
578 	}
579 
580 	/**
581 	 * This method returns the bone context for the given bone old memory
582 	 * address. If no context exists then <b>null</b> is returned.
583 	 *
584 	 * @param boneOMA
585 	 *            the bone's old memory address
586 	 * @return bone's context
587 	 */
getBoneContext(Long boneOMA)588 	public BoneContext getBoneContext(Long boneOMA) {
589 		return boneContexts.get(boneOMA);
590 	}
591 
592 	/**
593 	 * This method sets the material context for the given material. If the
594 	 * context is already set it will be replaced.
595 	 *
596 	 * @param material
597 	 *            the material
598 	 * @param materialContext
599 	 *            the material's context
600 	 */
setMaterialContext(Material material, MaterialContext materialContext)601 	public void setMaterialContext(Material material, MaterialContext materialContext) {
602 		this.materialContexts.put(material, materialContext);
603 	}
604 
605 	/**
606 	 * This method returns the material context for the given material. If no
607 	 * context exists then <b>null</b> is returned.
608 	 *
609 	 * @param material
610 	 *            the material
611 	 * @return material's context
612 	 */
getMaterialContext(Material material)613 	public MaterialContext getMaterialContext(Material material) {
614 		return materialContexts.get(material);
615 	}
616 
617 	/**
618 	 * This metod returns the default material.
619 	 *
620 	 * @return the default material
621 	 */
getDefaultMaterial()622 	public synchronized Material getDefaultMaterial() {
623 		if (blenderKey.getDefaultMaterial() == null) {
624 			Material defaultMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
625 			defaultMaterial.setColor("Color", ColorRGBA.DarkGray);
626 			blenderKey.setDefaultMaterial(defaultMaterial);
627 		}
628 		return blenderKey.getDefaultMaterial();
629 	}
630 
dispose()631 	public void dispose() {
632 		try {
633 			inputStream.close();
634 		} catch (IOException e) {
635 			LOGGER.log(Level.SEVERE, e.getLocalizedMessage(), e);
636 		}
637 		loadedFeatures.clear();
638 		loadedFeaturesByName.clear();
639 	}
640 
641 	/**
642 	 * This enum defines what loaded data type user wants to retreive. It can be
643 	 * either filled structure or already converted data.
644 	 *
645 	 * @author Marcin Roguski
646 	 */
647 	public static enum LoadedFeatureDataType {
648 
649 		LOADED_STRUCTURE(0), LOADED_FEATURE(1);
650 		private int	index;
651 
LoadedFeatureDataType(int index)652 		private LoadedFeatureDataType(int index) {
653 			this.index = index;
654 		}
655 
getIndex()656 		public int getIndex() {
657 			return index;
658 		}
659 	}
660 }
661