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