1 /*
2  * Copyright (c) 2009-2010 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 
33 package com.jme3.scene;
34 
35 import com.jme3.asset.AssetInfo;
36 import com.jme3.asset.AssetManager;
37 import com.jme3.asset.ModelKey;
38 import com.jme3.export.InputCapsule;
39 import com.jme3.export.JmeExporter;
40 import com.jme3.export.JmeImporter;
41 import com.jme3.export.OutputCapsule;
42 import com.jme3.export.binary.BinaryImporter;
43 import com.jme3.util.SafeArrayList;
44 import java.io.IOException;
45 import java.util.Map.Entry;
46 import java.util.*;
47 import java.util.logging.Level;
48 import java.util.logging.Logger;
49 
50 /**
51  * The AssetLinkNode does not store its children when exported to file.
52  * Instead, you can add a list of AssetKeys that will be loaded and attached
53  * when the AssetLinkNode is restored.
54  *
55  * @author normenhansen
56  */
57 public class AssetLinkNode extends Node {
58 
59     protected ArrayList<ModelKey> assetLoaderKeys = new ArrayList<ModelKey>();
60     protected Map<ModelKey, Spatial> assetChildren = new HashMap<ModelKey, Spatial>();
61 
AssetLinkNode()62     public AssetLinkNode() {
63     }
64 
AssetLinkNode(ModelKey key)65     public AssetLinkNode(ModelKey key) {
66         this(key.getName(), key);
67     }
68 
AssetLinkNode(String name, ModelKey key)69     public AssetLinkNode(String name, ModelKey key) {
70         super(name);
71         assetLoaderKeys.add(key);
72     }
73 
74     /**
75      * Add a "linked" child. These are loaded from the assetManager when the
76      * AssetLinkNode is loaded from a binary file.
77      * @param key
78      */
addLinkedChild(ModelKey key)79     public void addLinkedChild(ModelKey key) {
80         if (assetLoaderKeys.contains(key)) {
81             return;
82         }
83         assetLoaderKeys.add(key);
84     }
85 
removeLinkedChild(ModelKey key)86     public void removeLinkedChild(ModelKey key) {
87         assetLoaderKeys.remove(key);
88     }
89 
getAssetLoaderKeys()90     public ArrayList<ModelKey> getAssetLoaderKeys() {
91         return assetLoaderKeys;
92     }
93 
attachLinkedChild(AssetManager manager, ModelKey key)94     public void attachLinkedChild(AssetManager manager, ModelKey key) {
95         addLinkedChild(key);
96         Spatial child = manager.loadAsset(key);
97         assetChildren.put(key, child);
98         attachChild(child);
99     }
100 
attachLinkedChild(Spatial spat, ModelKey key)101     public void attachLinkedChild(Spatial spat, ModelKey key) {
102         addLinkedChild(key);
103         assetChildren.put(key, spat);
104         attachChild(spat);
105     }
106 
detachLinkedChild(ModelKey key)107     public void detachLinkedChild(ModelKey key) {
108         Spatial spatial = assetChildren.get(key);
109         if (spatial != null) {
110             detachChild(spatial);
111         }
112         removeLinkedChild(key);
113         assetChildren.remove(key);
114     }
115 
detachLinkedChild(Spatial child, ModelKey key)116     public void detachLinkedChild(Spatial child, ModelKey key) {
117         removeLinkedChild(key);
118         assetChildren.remove(key);
119         detachChild(child);
120     }
121 
122     /**
123      * Loads the linked children AssetKeys from the AssetManager and attaches them to the Node<br>
124      * If they are already attached, they will be reloaded.
125      * @param manager
126      */
attachLinkedChildren(AssetManager manager)127     public void attachLinkedChildren(AssetManager manager) {
128         detachLinkedChildren();
129         for (Iterator<ModelKey> it = assetLoaderKeys.iterator(); it.hasNext();) {
130             ModelKey assetKey = it.next();
131             Spatial curChild = assetChildren.get(assetKey);
132             if (curChild != null) {
133                 curChild.removeFromParent();
134             }
135             Spatial child = manager.loadAsset(assetKey);
136             attachChild(child);
137             assetChildren.put(assetKey, child);
138         }
139     }
140 
detachLinkedChildren()141     public void detachLinkedChildren() {
142         Set<Entry<ModelKey, Spatial>> set = assetChildren.entrySet();
143         for (Iterator<Entry<ModelKey, Spatial>> it = set.iterator(); it.hasNext();) {
144             Entry<ModelKey, Spatial> entry = it.next();
145             entry.getValue().removeFromParent();
146             it.remove();
147         }
148     }
149 
150     @Override
read(JmeImporter e)151     public void read(JmeImporter e) throws IOException {
152         super.read(e);
153         InputCapsule capsule = e.getCapsule(this);
154         BinaryImporter importer = BinaryImporter.getInstance();
155         AssetManager loaderManager = e.getAssetManager();
156 
157         assetLoaderKeys = (ArrayList<ModelKey>) capsule.readSavableArrayList("assetLoaderKeyList", new ArrayList<ModelKey>());
158         for (Iterator<ModelKey> it = assetLoaderKeys.iterator(); it.hasNext();) {
159             ModelKey modelKey = it.next();
160             AssetInfo info = loaderManager.locateAsset(modelKey);
161             Spatial child = null;
162             if (info != null) {
163                 child = (Spatial) importer.load(info);
164             }
165             if (child != null) {
166                 child.parent = this;
167                 children.add(child);
168                 assetChildren.put(modelKey, child);
169             } else {
170                 Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Cannot locate {0} for asset link node {1}",
171                                                                     new Object[]{ modelKey, key });
172             }
173         }
174     }
175 
176     @Override
write(JmeExporter e)177     public void write(JmeExporter e) throws IOException {
178         SafeArrayList<Spatial> childs = children;
179         children = new SafeArrayList<Spatial>(Spatial.class);
180         super.write(e);
181         OutputCapsule capsule = e.getCapsule(this);
182         capsule.writeSavableArrayList(assetLoaderKeys, "assetLoaderKeyList", null);
183         children = childs;
184     }
185 }
186