Home | History | Annotate | Download | only in blender
      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
     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 	 */
    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 	 */
    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