Home | History | Annotate | Download | only in modifiers
      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.modifiers;
     33 
     34 import java.util.ArrayList;
     35 import java.util.Collection;
     36 import java.util.List;
     37 import java.util.logging.Level;
     38 import java.util.logging.Logger;
     39 
     40 import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
     41 import com.jme3.scene.plugins.blender.BlenderContext;
     42 import com.jme3.scene.plugins.blender.animations.Ipo;
     43 import com.jme3.scene.plugins.blender.animations.IpoHelper;
     44 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
     45 import com.jme3.scene.plugins.blender.file.Pointer;
     46 import com.jme3.scene.plugins.blender.file.Structure;
     47 
     48 /**
     49  * A class that is used in modifiers calculations.
     50  *
     51  * @author Marcin Roguski
     52  */
     53 public class ModifierHelper extends AbstractBlenderHelper {
     54 
     55 	private static final Logger	LOGGER	= Logger.getLogger(ModifierHelper.class.getName());
     56 
     57 	/**
     58 	 * This constructor parses the given blender version and stores the result.
     59 	 * Some functionalities may differ in different blender versions.
     60 	 *
     61 	 * @param blenderVersion
     62 	 *            the version read from the blend file
     63 	 * @param fixUpAxis
     64 	 *            a variable that indicates if the Y asxis is the UP axis or not
     65 	 */
     66 	public ModifierHelper(String blenderVersion, boolean fixUpAxis) {
     67 		super(blenderVersion, fixUpAxis);
     68 	}
     69 
     70 	/**
     71 	 * This method reads the given object's modifiers.
     72 	 *
     73 	 * @param objectStructure
     74 	 *            the object structure
     75 	 * @param blenderContext
     76 	 *            the blender context
     77 	 * @throws BlenderFileException
     78 	 *             this exception is thrown when the blender file is somehow
     79 	 *             corrupted
     80 	 */
     81 	public Collection<Modifier> readModifiers(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException {
     82 		Collection<Modifier> result = new ArrayList<Modifier>();
     83 		Structure modifiersListBase = (Structure) objectStructure.getFieldValue("modifiers");
     84 		List<Structure> modifiers = modifiersListBase.evaluateListBase(blenderContext);
     85 		for (Structure modifierStructure : modifiers) {
     86 			Modifier modifier = null;
     87 			if (Modifier.ARRAY_MODIFIER_DATA.equals(modifierStructure.getType())) {
     88 				modifier = new ArrayModifier(modifierStructure, blenderContext);
     89 			} else if (Modifier.MIRROR_MODIFIER_DATA.equals(modifierStructure.getType())) {
     90 				modifier = new MirrorModifier(modifierStructure, blenderContext);
     91 			} else if (Modifier.ARMATURE_MODIFIER_DATA.equals(modifierStructure.getType())) {
     92 				modifier = new ArmatureModifier(objectStructure, modifierStructure, blenderContext);
     93 			} else if (Modifier.PARTICLE_MODIFIER_DATA.equals(modifierStructure.getType())) {
     94 				modifier = new ParticlesModifier(modifierStructure, blenderContext);
     95 			}
     96 
     97 			if (modifier != null) {
     98 				result.add(modifier);
     99 				blenderContext.addModifier(objectStructure.getOldMemoryAddress(), modifier);
    100 			} else {
    101 				LOGGER.log(Level.WARNING, "Unsupported modifier type: {0}", modifierStructure.getType());
    102 			}
    103 		}
    104 
    105 		// at the end read object's animation modifier (object animation is
    106 		// either described by action or by ipo of the object)
    107 		Modifier modifier;
    108 		if (blenderVersion <= 249) {
    109 			modifier = this.readAnimationModifier249(objectStructure, blenderContext);
    110 		} else {
    111 			modifier = this.readAnimationModifier250(objectStructure, blenderContext);
    112 		}
    113 		if (modifier != null) {
    114 			result.add(modifier);
    115 		}
    116 		return result;
    117 	}
    118 
    119 	@Override
    120 	public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) {
    121 		return true;
    122 	}
    123 
    124 	/**
    125 	 * This method reads the object's animation modifier for blender version
    126 	 * 2.49 and lower.
    127 	 *
    128 	 * @param objectStructure
    129 	 *            the object's structure
    130 	 * @param blenderContext
    131 	 *            the blender context
    132 	 * @return loaded modifier
    133 	 * @throws BlenderFileException
    134 	 *             this exception is thrown when the blender file is somehow
    135 	 *             corrupted
    136 	 */
    137 	private Modifier readAnimationModifier249(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException {
    138 		Modifier result = null;
    139 		Pointer pAction = (Pointer) objectStructure.getFieldValue("action");
    140 		IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class);
    141 		if (pAction.isNotNull()) {
    142 			Structure action = pAction.fetchData(blenderContext.getInputStream()).get(0);
    143 			List<Structure> actionChannels = ((Structure) action.getFieldValue("chanbase")).evaluateListBase(blenderContext);
    144 			if (actionChannels.size() == 1) {// object's animtion action has
    145 												// only one channel
    146 				Pointer pChannelIpo = (Pointer) actionChannels.get(0).getFieldValue("ipo");
    147 				Structure ipoStructure = pChannelIpo.fetchData(blenderContext.getInputStream()).get(0);
    148 				Ipo ipo = ipoHelper.fromIpoStructure(ipoStructure, blenderContext);
    149 				result = new ObjectAnimationModifier(ipo, action.getName(), objectStructure.getOldMemoryAddress(), blenderContext);
    150 				blenderContext.addModifier(objectStructure.getOldMemoryAddress(), result);
    151 			} else {
    152 				throw new IllegalStateException("Object's action cannot have more than one channel!");
    153 			}
    154 		} else {
    155 			Pointer pIpo = (Pointer) objectStructure.getFieldValue("ipo");
    156 			if (pIpo.isNotNull()) {
    157 				Structure ipoStructure = pIpo.fetchData(blenderContext.getInputStream()).get(0);
    158 				Ipo ipo = ipoHelper.fromIpoStructure(ipoStructure, blenderContext);
    159 				result = new ObjectAnimationModifier(ipo, objectStructure.getName(), objectStructure.getOldMemoryAddress(), blenderContext);
    160 				blenderContext.addModifier(objectStructure.getOldMemoryAddress(), result);
    161 			}
    162 		}
    163 		return result;
    164 	}
    165 
    166 	/**
    167 	 * This method reads the object's animation modifier for blender version
    168 	 * 2.50 and higher.
    169 	 *
    170 	 * @param objectStructure
    171 	 *            the object's structure
    172 	 * @param blenderContext
    173 	 *            the blender context
    174 	 * @return loaded modifier
    175 	 * @throws BlenderFileException
    176 	 *             this exception is thrown when the blender file is somehow
    177 	 *             corrupted
    178 	 */
    179 	private Modifier readAnimationModifier250(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException {
    180 		Modifier result = null;
    181 		Pointer pAnimData = (Pointer) objectStructure.getFieldValue("adt");
    182 		if (pAnimData.isNotNull()) {
    183 			Structure animData = pAnimData.fetchData(blenderContext.getInputStream()).get(0);
    184 			Pointer pAction = (Pointer) animData.getFieldValue("action");
    185 			if (pAction.isNotNull()) {
    186 				Structure actionStructure = pAction.fetchData(blenderContext.getInputStream()).get(0);
    187 				IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class);
    188 				Ipo ipo = ipoHelper.fromAction(actionStructure, blenderContext);
    189 				result = new ObjectAnimationModifier(ipo, actionStructure.getName(), objectStructure.getOldMemoryAddress(), blenderContext);
    190 				blenderContext.addModifier(objectStructure.getOldMemoryAddress(), result);
    191 			}
    192 		}
    193 		return result;
    194 	}
    195 }
    196