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 package com.jme3.scene.plugins.blender; 33 34 import com.jme3.asset.AssetInfo; 35 import com.jme3.asset.BlenderKey; 36 import com.jme3.asset.BlenderKey.FeaturesToLoad; 37 import com.jme3.asset.BlenderKey.LoadingResults; 38 import com.jme3.asset.BlenderKey.WorldData; 39 import com.jme3.asset.ModelKey; 40 import com.jme3.light.Light; 41 import com.jme3.renderer.Camera; 42 import com.jme3.scene.Node; 43 import com.jme3.scene.Spatial; 44 import com.jme3.scene.plugins.blender.animations.ArmatureHelper; 45 import com.jme3.scene.plugins.blender.animations.IpoHelper; 46 import com.jme3.scene.plugins.blender.cameras.CameraHelper; 47 import com.jme3.scene.plugins.blender.constraints.ConstraintHelper; 48 import com.jme3.scene.plugins.blender.curves.CurvesHelper; 49 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; 50 import com.jme3.scene.plugins.blender.file.BlenderInputStream; 51 import com.jme3.scene.plugins.blender.file.FileBlockHeader; 52 import com.jme3.scene.plugins.blender.file.Structure; 53 import com.jme3.scene.plugins.blender.lights.LightHelper; 54 import com.jme3.scene.plugins.blender.materials.MaterialHelper; 55 import com.jme3.scene.plugins.blender.meshes.MeshHelper; 56 import com.jme3.scene.plugins.blender.modifiers.ModifierHelper; 57 import com.jme3.scene.plugins.blender.objects.ObjectHelper; 58 import com.jme3.scene.plugins.blender.particles.ParticlesHelper; 59 import com.jme3.scene.plugins.blender.textures.TextureHelper; 60 import java.io.IOException; 61 import java.util.ArrayList; 62 import java.util.List; 63 import java.util.logging.Level; 64 import java.util.logging.Logger; 65 66 /** 67 * This is the main loading class. Have in notice that asset manager needs to have loaders for resources like textures. 68 * @author Marcin Roguski (Kaelthas) 69 */ 70 public class BlenderLoader extends AbstractBlenderLoader { 71 72 private static final Logger LOGGER = Logger.getLogger(BlenderLoader.class.getName()); 73 74 /** The blocks read from the file. */ 75 protected List<FileBlockHeader> blocks; 76 77 @Override load(AssetInfo assetInfo)78 public Spatial load(AssetInfo assetInfo) throws IOException { 79 try { 80 this.setup(assetInfo); 81 82 BlenderKey blenderKey = blenderContext.getBlenderKey(); 83 LoadingResults loadingResults = blenderKey.prepareLoadingResults(); 84 WorldData worldData = null;// a set of data used in different scene aspects 85 for (FileBlockHeader block : blocks) { 86 switch (block.getCode()) { 87 case FileBlockHeader.BLOCK_OB00:// Object 88 Object object = this.toObject(block.getStructure(blenderContext)); 89 if (object instanceof Node) { 90 if ((blenderKey.getFeaturesToLoad() & FeaturesToLoad.OBJECTS) != 0) { 91 LOGGER.log(Level.INFO, "{0}: {1}--> {2}", new Object[] { ((Node) object).getName(), ((Node) object).getLocalTranslation().toString(), ((Node) object).getParent() == null ? "null" : ((Node) object).getParent().getName() }); 92 if (this.isRootObject(loadingResults, (Node)object)) { 93 loadingResults.addObject((Node) object); 94 } 95 } 96 } else if (object instanceof Camera) { 97 if ((blenderKey.getFeaturesToLoad() & FeaturesToLoad.CAMERAS) != 0) { 98 loadingResults.addCamera((Camera) object); 99 } 100 } else if (object instanceof Light) { 101 if ((blenderKey.getFeaturesToLoad() & FeaturesToLoad.LIGHTS) != 0) { 102 loadingResults.addLight((Light) object); 103 } 104 } 105 break; 106 case FileBlockHeader.BLOCK_MA00:// Material 107 if (blenderKey.isLoadUnlinkedAssets() && (blenderKey.getFeaturesToLoad() & FeaturesToLoad.MATERIALS) != 0) { 108 loadingResults.addMaterial(this.toMaterial(block.getStructure(blenderContext))); 109 } 110 break; 111 case FileBlockHeader.BLOCK_SC00:// Scene 112 if ((blenderKey.getFeaturesToLoad() & FeaturesToLoad.SCENES) != 0) { 113 loadingResults.addScene(this.toScene(block.getStructure(blenderContext))); 114 } 115 break; 116 case FileBlockHeader.BLOCK_WO00:// World 117 if (blenderKey.isLoadUnlinkedAssets() && worldData == null) {// onlu one world data is used 118 Structure worldStructure = block.getStructure(blenderContext); 119 String worldName = worldStructure.getName(); 120 if (blenderKey.getUsedWorld() == null || blenderKey.getUsedWorld().equals(worldName)) { 121 worldData = this.toWorldData(worldStructure); 122 if ((blenderKey.getFeaturesToLoad() & FeaturesToLoad.LIGHTS) != 0) { 123 loadingResults.addLight(worldData.getAmbientLight()); 124 } 125 } 126 } 127 break; 128 } 129 } 130 blenderContext.dispose(); 131 return loadingResults; 132 } catch (BlenderFileException e) { 133 LOGGER.log(Level.SEVERE, e.getMessage(), e); 134 } 135 return null; 136 } 137 138 /** 139 * This method indicates if the given spatial is a root object. It means it 140 * has no parent or is directly attached to one of the already loaded scene 141 * nodes. 142 * 143 * @param loadingResults 144 * loading results containing the scene nodes 145 * @param spatial 146 * spatial object 147 * @return <b>true</b> if the given spatial is a root object and 148 * <b>false</b> otherwise 149 */ isRootObject(LoadingResults loadingResults, Spatial spatial)150 protected boolean isRootObject(LoadingResults loadingResults, Spatial spatial) { 151 if(spatial.getParent() == null) { 152 return true; 153 } 154 for(Node scene : loadingResults.getScenes()) { 155 if(spatial.getParent().equals(scene)) { 156 return true; 157 } 158 } 159 return false; 160 } 161 162 /** 163 * This method sets up the loader. 164 * @param assetInfo 165 * the asset info 166 * @throws BlenderFileException 167 * an exception is throw when something wrong happens with blender file 168 */ setup(AssetInfo assetInfo)169 protected void setup(AssetInfo assetInfo) throws BlenderFileException { 170 // registering loaders 171 ModelKey modelKey = (ModelKey) assetInfo.getKey(); 172 BlenderKey blenderKey; 173 if (modelKey instanceof BlenderKey) { 174 blenderKey = (BlenderKey) modelKey; 175 } else { 176 blenderKey = new BlenderKey(modelKey.getName()); 177 blenderKey.setAssetRootPath(modelKey.getFolder()); 178 } 179 180 // opening stream 181 BlenderInputStream inputStream = new BlenderInputStream(assetInfo.openStream(), assetInfo.getManager()); 182 183 // reading blocks 184 blocks = new ArrayList<FileBlockHeader>(); 185 FileBlockHeader fileBlock; 186 blenderContext = new BlenderContext(); 187 blenderContext.setBlenderVersion(inputStream.getVersionNumber()); 188 blenderContext.setAssetManager(assetInfo.getManager()); 189 blenderContext.setInputStream(inputStream); 190 blenderContext.setBlenderKey(blenderKey); 191 192 // creating helpers 193 blenderContext.putHelper(ArmatureHelper.class, new ArmatureHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis())); 194 blenderContext.putHelper(TextureHelper.class, new TextureHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis())); 195 blenderContext.putHelper(MeshHelper.class, new MeshHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis())); 196 blenderContext.putHelper(ObjectHelper.class, new ObjectHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis())); 197 blenderContext.putHelper(CurvesHelper.class, new CurvesHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis())); 198 blenderContext.putHelper(LightHelper.class, new LightHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis())); 199 blenderContext.putHelper(CameraHelper.class, new CameraHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis())); 200 blenderContext.putHelper(ModifierHelper.class, new ModifierHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis())); 201 blenderContext.putHelper(MaterialHelper.class, new MaterialHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis())); 202 blenderContext.putHelper(ConstraintHelper.class, new ConstraintHelper(inputStream.getVersionNumber(), blenderContext, blenderKey.isFixUpAxis())); 203 blenderContext.putHelper(IpoHelper.class, new IpoHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis())); 204 blenderContext.putHelper(ParticlesHelper.class, new ParticlesHelper(inputStream.getVersionNumber(), blenderKey.isFixUpAxis())); 205 206 // setting additional data to helpers 207 MaterialHelper materialHelper = blenderContext.getHelper(MaterialHelper.class); 208 materialHelper.setFaceCullMode(blenderKey.getFaceCullMode()); 209 210 // reading the blocks (dna block is automatically saved in the blender context when found)//TODO: zmienić to 211 FileBlockHeader sceneFileBlock = null; 212 do { 213 fileBlock = new FileBlockHeader(inputStream, blenderContext); 214 if (!fileBlock.isDnaBlock()) { 215 blocks.add(fileBlock); 216 // save the scene's file block 217 if (fileBlock.getCode() == FileBlockHeader.BLOCK_SC00 && blenderKey.getLayersToLoad() < 0) { 218 sceneFileBlock = fileBlock; 219 } 220 } 221 } while (!fileBlock.isLastBlock()); 222 // VERIFY LAYERS TO BE LOADED BEFORE LOADING FEATURES 223 if (sceneFileBlock != null) { 224 int lay = ((Number) sceneFileBlock.getStructure(blenderContext).getFieldValue("lay")).intValue(); 225 blenderContext.getBlenderKey().setLayersToLoad(lay);// load only current layer 226 } 227 } 228 } 229