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.math.FastMath; 35 import com.jme3.math.Quaternion; 36 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; 37 import com.jme3.scene.plugins.blender.file.Pointer; 38 import com.jme3.scene.plugins.blender.file.Structure; 39 import com.jme3.scene.plugins.blender.objects.Properties; 40 import com.jme3.util.BufferUtils; 41 import java.nio.ByteBuffer; 42 import java.nio.FloatBuffer; 43 import java.util.List; 44 45 /** 46 * A purpose of the helper class is to split calculation code into several classes. Each helper after use should be cleared because it can 47 * hold the state of the calculations. 48 * @author Marcin Roguski 49 */ 50 public abstract class AbstractBlenderHelper { 51 52 /** The version of the blend file. */ 53 protected final int blenderVersion; 54 /** This variable indicates if the Y asxis is the UP axis or not. */ 55 protected boolean fixUpAxis; 56 /** Quaternion used to rotate data when Y is up axis. */ 57 protected Quaternion upAxisRotationQuaternion; 58 59 /** 60 * This constructor parses the given blender version and stores the result. Some functionalities may differ in different blender 61 * versions. 62 * @param blenderVersion 63 * the version read from the blend file 64 * @param fixUpAxis 65 * a variable that indicates if the Y asxis is the UP axis or not 66 */ 67 public AbstractBlenderHelper(String blenderVersion, boolean fixUpAxis) { 68 this.blenderVersion = Integer.parseInt(blenderVersion); 69 this.fixUpAxis = fixUpAxis; 70 if(fixUpAxis) { 71 upAxisRotationQuaternion = new Quaternion().fromAngles(-FastMath.HALF_PI, 0, 0); 72 } 73 } 74 75 /** 76 * This method clears the state of the helper so that it can be used for different calculations of another feature. 77 */ 78 public void clearState() {} 79 80 /** 81 * This method should be used to check if the text is blank. Avoid using text.trim().length()==0. This causes that more strings are 82 * being created and stored in the memory. It can be unwise especially inside loops. 83 * @param text 84 * the text to be checked 85 * @return <b>true</b> if the text is blank and <b>false</b> otherwise 86 */ 87 protected boolean isBlank(String text) { 88 if (text != null) { 89 for (int i = 0; i < text.length(); ++i) { 90 if (!Character.isWhitespace(text.charAt(i))) { 91 return false; 92 } 93 } 94 } 95 return true; 96 } 97 98 /** 99 * Generate a new ByteBuffer using the given array of byte[4] objects. The ByteBuffer will be 4 * data.length 100 * long and contain the vector data as data[0][0], data[0][1], data[0][2], data[0][3], data[1][0]... etc. 101 * @param data 102 * list of byte[4] objects to place into a new ByteBuffer 103 */ 104 protected ByteBuffer createByteBuffer(List<byte[]> data) { 105 if (data == null) { 106 return null; 107 } 108 ByteBuffer buff = BufferUtils.createByteBuffer(4 * data.size()); 109 for (byte[] v : data) { 110 if (v != null) { 111 buff.put(v[0]).put(v[1]).put(v[2]).put(v[3]); 112 } else { 113 buff.put((byte)0).put((byte)0).put((byte)0).put((byte)0); 114 } 115 } 116 buff.flip(); 117 return buff; 118 } 119 120 /** 121 * Generate a new FloatBuffer using the given array of float[4] objects. The FloatBuffer will be 4 * data.length 122 * long and contain the vector data as data[0][0], data[0][1], data[0][2], data[0][3], data[1][0]... etc. 123 * @param data 124 * list of float[4] objects to place into a new FloatBuffer 125 */ 126 protected FloatBuffer createFloatBuffer(List<float[]> data) { 127 if (data == null) { 128 return null; 129 } 130 FloatBuffer buff = BufferUtils.createFloatBuffer(4 * data.size()); 131 for (float[] v : data) { 132 if (v != null) { 133 buff.put(v[0]).put(v[1]).put(v[2]).put(v[3]); 134 } else { 135 buff.put(0).put(0).put(0).put(0); 136 } 137 } 138 buff.flip(); 139 return buff; 140 } 141 142 /** 143 * This method loads the properties if they are available and defined for the structure. 144 * @param structure 145 * the structure we read the properties from 146 * @param blenderContext 147 * the blender context 148 * @return loaded properties or null if they are not available 149 * @throws BlenderFileException 150 * an exception is thrown when the blend file is somehow corrupted 151 */ 152 protected Properties loadProperties(Structure structure, BlenderContext blenderContext) throws BlenderFileException { 153 Properties properties = null; 154 Structure id = (Structure) structure.getFieldValue("ID"); 155 if (id != null) { 156 Pointer pProperties = (Pointer) id.getFieldValue("properties"); 157 if (pProperties.isNotNull()) { 158 Structure propertiesStructure = pProperties.fetchData(blenderContext.getInputStream()).get(0); 159 properties = new Properties(); 160 properties.load(propertiesStructure, blenderContext); 161 } 162 } 163 return properties; 164 } 165 166 /** 167 * This method analyzes the given structure and the data contained within 168 * blender context and decides if the feature should be loaded. 169 * @param structure 170 * structure to be analyzed 171 * @param blenderContext 172 * the blender context 173 * @return <b>true</b> if the feature should be loaded and false otherwise 174 */ 175 public abstract boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext); 176 } 177