* Fixed Blender loader crash when "Image" texture mode is specified but actual image is not selected
* Replaced oracle proprietary exception with UnsupportedOperationException * Shared Geometry Patch - Still need detection mechanism for old versions! * Binary/J3O format will now write signature and version * Binary/J3O format now has version numbers for exported class hierarchies * Fix crash in TestHoveringTank * ListMap now uses backing array and a map - increased lookup performance for uniforms/matparams and faster iteration too. Only insertion became slower git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7726 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
		
							parent
							
								
									090e57b224
								
							
						
					
					
						commit
						348b1d638a
					
				| @ -177,8 +177,10 @@ public class TextureHelper extends AbstractBlenderHelper { | ||||
| 				break; | ||||
| 			case TEX_IMAGE:// (it is first because probably this will be most commonly used) | ||||
| 				Pointer pImage = (Pointer) tex.getFieldValue("ima"); | ||||
| 				Structure image = pImage.fetchData(dataRepository.getInputStream()).get(0); | ||||
| 				result = this.getTextureFromImage(image, dataRepository); | ||||
|                                 if (pImage.isNotNull()){ | ||||
|                                     Structure image = pImage.fetchData(dataRepository.getInputStream()).get(0); | ||||
|                                     result = this.getTextureFromImage(image, dataRepository); | ||||
|                                 } | ||||
| 				break; | ||||
| 			case TEX_CLOUDS: | ||||
| 				result = this.clouds(tex, width, height, dataRepository); | ||||
| @ -212,7 +214,7 @@ public class TextureHelper extends AbstractBlenderHelper { | ||||
| 				break; | ||||
| 			case TEX_PLUGIN: | ||||
| 			case TEX_ENVMAP:// TODO: implement envmap texture | ||||
| 				LOGGER.log(Level.WARNING, "Unsupported texture type: " + type + " for texture: " + tex.getName()); | ||||
| 				LOGGER.log(Level.WARNING, "Unsupported texture type: {0} for texture: {1}", new Object[]{type, tex.getName()}); | ||||
| 				break; | ||||
| 			default: | ||||
| 				throw new BlenderFileException("Unknown texture type: " + type + " for texture: " + tex.getName()); | ||||
|  | ||||
| @ -6,9 +6,6 @@ import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.logging.Logger; | ||||
| 
 | ||||
| import sun.reflect.generics.reflectiveObjects.NotImplementedException; | ||||
| 
 | ||||
| import com.jme3.export.InputCapsule; | ||||
| import com.jme3.export.JmeExporter; | ||||
| import com.jme3.export.JmeImporter; | ||||
| @ -158,7 +155,7 @@ public class Properties implements Cloneable, Savable { | ||||
| 				break; | ||||
| 			} | ||||
| 			case IDP_NUMTYPES: | ||||
| 				throw new NotImplementedException(); | ||||
| 				throw new UnsupportedOperationException(); | ||||
| 				// case IDP_ID://not yet implemented in blender | ||||
| 				// return null; | ||||
| 			default: | ||||
|  | ||||
| @ -42,5 +42,5 @@ class BinaryClassObject { | ||||
|      | ||||
|     byte[] alias; | ||||
|     String className; | ||||
|      | ||||
|     int[] classHierarchyVersions; | ||||
| } | ||||
|  | ||||
| @ -34,6 +34,8 @@ package com.jme3.export.binary; | ||||
| 
 | ||||
| import com.jme3.export.JmeExporter; | ||||
| import com.jme3.export.Savable; | ||||
| import com.jme3.export.FormatVersion; | ||||
| import com.jme3.export.SavableClassUtil; | ||||
| import com.jme3.math.FastMath; | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import java.io.File; | ||||
| @ -43,6 +45,7 @@ import java.io.OutputStream; | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashMap; | ||||
| import java.util.IdentityHashMap; | ||||
| import java.util.logging.Level; | ||||
| import java.util.logging.Logger; | ||||
| 
 | ||||
| /** | ||||
| @ -162,7 +165,7 @@ public class BinaryExporter implements JmeExporter { | ||||
| 
 | ||||
|     public static boolean debug = false; | ||||
|     public static boolean useFastBufs = true; | ||||
| 
 | ||||
|        | ||||
|     public BinaryExporter() { | ||||
|     } | ||||
| 
 | ||||
| @ -179,32 +182,44 @@ public class BinaryExporter implements JmeExporter { | ||||
|         locationTable.clear(); | ||||
|         contentKeys.clear(); | ||||
|          | ||||
|         // write signature and version | ||||
|         os.write(ByteUtils.convertToBytes(FormatVersion.SIGNATURE)); | ||||
|         os.write(ByteUtils.convertToBytes(FormatVersion.VERSION)); | ||||
|          | ||||
|         int id = processBinarySavable(object); | ||||
| 
 | ||||
|         // write out tag table | ||||
|         int ttbytes = 0; | ||||
|         int classTableSize = 0; | ||||
|         int classNum = classes.keySet().size(); | ||||
|         int aliasWidth = ((int) FastMath.log(classNum, 256) + 1); // make all | ||||
|                                                                 // aliases a | ||||
|                                                                 // fixed width | ||||
|         int aliasSize = ((int) FastMath.log(classNum, 256) + 1); // make all | ||||
|                                                                   // aliases a | ||||
|                                                                   // fixed width | ||||
|          | ||||
|         os.write(ByteUtils.convertToBytes(classNum)); | ||||
|         for (String key : classes.keySet()) { | ||||
|             BinaryClassObject bco = classes.get(key); | ||||
| 
 | ||||
|             // write alias | ||||
|             byte[] aliasBytes = fixClassAlias(bco.alias, | ||||
|                     aliasWidth); | ||||
|                     aliasSize); | ||||
|             os.write(aliasBytes); | ||||
|             ttbytes += aliasWidth; | ||||
| 
 | ||||
|             classTableSize += aliasSize; | ||||
|              | ||||
|             // jME3 NEW: Write class hierarchy version numbers | ||||
|             os.write( bco.classHierarchyVersions.length ); | ||||
|             for (int version : bco.classHierarchyVersions){ | ||||
|                 os.write(ByteUtils.convertToBytes(version)); | ||||
|             } | ||||
|             classTableSize += 1 + bco.classHierarchyVersions.length * 4; | ||||
|              | ||||
|             // write classname size & classname | ||||
|             byte[] classBytes = key.getBytes(); | ||||
|             os.write(ByteUtils.convertToBytes(classBytes.length)); | ||||
|             os.write(classBytes); | ||||
|             ttbytes += 4 + classBytes.length; | ||||
| 
 | ||||
|             classTableSize += 4 + classBytes.length; | ||||
|              | ||||
|             // for each field, write alias, type, and name | ||||
|             os.write(ByteUtils.convertToBytes(bco.nameFields.size())); | ||||
| 
 | ||||
|             for (String fieldName : bco.nameFields.keySet()) { | ||||
|                 BinaryClassField bcf = bco.nameFields.get(fieldName); | ||||
|                 os.write(bcf.alias); | ||||
| @ -214,7 +229,7 @@ public class BinaryExporter implements JmeExporter { | ||||
|                 byte[] fNameBytes = fieldName.getBytes(); | ||||
|                 os.write(ByteUtils.convertToBytes(fNameBytes.length)); | ||||
|                 os.write(fNameBytes); | ||||
|                 ttbytes += 2 + 4 + fNameBytes.length; | ||||
|                 classTableSize += 2 + 4 + fNameBytes.length; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| @ -242,9 +257,9 @@ public class BinaryExporter implements JmeExporter { | ||||
|                 alreadySaved.put(savableName + getChunk(pair), bucket); | ||||
|             } | ||||
|             bucket.add(pair); | ||||
|             byte[] aliasBytes = fixClassAlias(classes.get(savableName).alias, aliasWidth); | ||||
|             byte[] aliasBytes = fixClassAlias(classes.get(savableName).alias, aliasSize); | ||||
|             out.write(aliasBytes); | ||||
|             location += aliasWidth; | ||||
|             location += aliasSize; | ||||
|             BinaryOutputCapsule cap = contentTable.get(savable).getContent(); | ||||
|             out.write(ByteUtils.convertToBytes(cap.bytes.length)); | ||||
|             location += 4; // length of bytes | ||||
| @ -254,13 +269,13 @@ public class BinaryExporter implements JmeExporter { | ||||
| 
 | ||||
|         // write out location table | ||||
|         // tag/location | ||||
|         int locNum = locationTable.keySet().size(); | ||||
|         os.write(ByteUtils.convertToBytes(locNum)); | ||||
|         int locbytes = 0; | ||||
|         int numLocations = locationTable.keySet().size(); | ||||
|         os.write(ByteUtils.convertToBytes(numLocations)); | ||||
|         int locationTableSize = 0; | ||||
|         for (Integer key : locationTable.keySet()) { | ||||
|             os.write(ByteUtils.convertToBytes(key)); | ||||
|             os.write(ByteUtils.convertToBytes(locationTable.get(key))); | ||||
|             locbytes += 8; | ||||
|             locationTableSize += 8; | ||||
|         } | ||||
| 
 | ||||
|         // write out number of root ids - hardcoded 1 for now | ||||
| @ -278,11 +293,11 @@ public class BinaryExporter implements JmeExporter { | ||||
| 
 | ||||
|         if (debug ) { | ||||
|             logger.info("Stats:"); | ||||
|             logger.info("classes: " + classNum); | ||||
|             logger.info("class table: " + ttbytes + " bytes"); | ||||
|             logger.info("objects: " + locNum); | ||||
|             logger.info("location table: " + locbytes + " bytes"); | ||||
|             logger.info("data: " + location + " bytes"); | ||||
|             logger.log(Level.INFO, "classes: {0}", classNum); | ||||
|             logger.log(Level.INFO, "class table: {0} bytes", classTableSize); | ||||
|             logger.log(Level.INFO, "objects: {0}", numLocations); | ||||
|             logger.log(Level.INFO, "location table: {0} bytes", locationTableSize); | ||||
|             logger.log(Level.INFO, "data: {0} bytes", location); | ||||
|         } | ||||
| 
 | ||||
|         return true; | ||||
| @ -331,17 +346,38 @@ public class BinaryExporter implements JmeExporter { | ||||
|         return contentTable.get(object).getContent(); | ||||
|     } | ||||
| 
 | ||||
|     private BinaryClassObject createClassObject(Class clazz) throws IOException{ | ||||
|         BinaryClassObject bco = new BinaryClassObject(); | ||||
|         bco.alias = generateTag(); | ||||
|         bco.nameFields = new HashMap<String, BinaryClassField>(); | ||||
|          | ||||
|         ArrayList<Integer> versionList = new ArrayList<Integer>(); | ||||
|         Class superclass = clazz; | ||||
|         do { | ||||
|             versionList.add(SavableClassUtil.getSavableVersion(superclass)); | ||||
|             superclass = superclass.getSuperclass(); | ||||
|         } while (superclass != null && SavableClassUtil.isImplementingSavable(superclass)); | ||||
|          | ||||
|         int[] versions = new int[versionList.size()]; | ||||
|         for (int i = 0; i < versionList.size(); i++){ | ||||
|             versions[i] = versionList.get(i); | ||||
|         } | ||||
|         bco.classHierarchyVersions = versions; | ||||
|          | ||||
|         classes.put(clazz.getName(), bco); | ||||
|              | ||||
|         return bco; | ||||
|     } | ||||
|      | ||||
|     public int processBinarySavable(Savable object) throws IOException { | ||||
|         if (object == null) { | ||||
|             return -1; | ||||
|         } | ||||
|         Class<? extends Savable> clazz = object.getClass(); | ||||
|         BinaryClassObject bco = classes.get(object.getClass().getName()); | ||||
|         // is this class been looked at before? in tagTable? | ||||
|         if (bco == null) { | ||||
|             bco = new BinaryClassObject(); | ||||
|             bco.alias = generateTag(); | ||||
|             bco.nameFields = new HashMap<String, BinaryClassField>(); | ||||
|             classes.put(object.getClass().getName(), bco); | ||||
|             bco = createClassObject(object.getClass()); | ||||
|         } | ||||
| 
 | ||||
|         // is object in contentTable? | ||||
|  | ||||
| @ -32,9 +32,11 @@ | ||||
| 
 | ||||
| package com.jme3.export.binary; | ||||
| 
 | ||||
| import com.jme3.export.SavableClassFinder; | ||||
| import com.jme3.export.SavableClassUtil; | ||||
| import com.jme3.asset.AssetInfo; | ||||
| import com.jme3.asset.AssetManager; | ||||
| import com.jme3.export.FormatVersion; | ||||
| import com.jme3.export.InputCapsule; | ||||
| import com.jme3.export.JmeImporter; | ||||
| import com.jme3.export.ReadListener; | ||||
| import com.jme3.export.Savable; | ||||
| @ -57,6 +59,7 @@ import java.util.logging.Logger; | ||||
| 
 | ||||
| /** | ||||
|  * @author Joshua Slack | ||||
|  * @author Kirill Vainer - Version number, Fast buffer reading | ||||
|  */ | ||||
| public final class BinaryImporter implements JmeImporter { | ||||
|     private static final Logger logger = Logger.getLogger(BinaryImporter.class | ||||
| @ -81,6 +84,7 @@ public final class BinaryImporter implements JmeImporter { | ||||
| 
 | ||||
|     private byte[] dataArray; | ||||
|     private int aliasWidth; | ||||
|     private int formatVersion; | ||||
| 
 | ||||
|     private static final boolean fastRead = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN; | ||||
|      | ||||
| @ -89,6 +93,10 @@ public final class BinaryImporter implements JmeImporter { | ||||
|     public BinaryImporter() { | ||||
|     } | ||||
|      | ||||
|     public int getFormatVersion(){ | ||||
|         return formatVersion; | ||||
|     } | ||||
|      | ||||
|     public static boolean canUseFastBuffers(){ | ||||
|         return fastRead; | ||||
|     } | ||||
| @ -139,20 +147,59 @@ public final class BinaryImporter implements JmeImporter { | ||||
|     public Savable load(InputStream is, ReadListener listener, ByteArrayOutputStream baos) throws IOException { | ||||
|         contentTable.clear(); | ||||
|         BufferedInputStream bis = new BufferedInputStream(is); | ||||
|         int numClasses = ByteUtils.readInt(bis); | ||||
|          | ||||
|         int numClasses; | ||||
|          | ||||
|         // Try to read signature | ||||
|         int maybeSignature = ByteUtils.readInt(bis); | ||||
|         if (maybeSignature == FormatVersion.SIGNATURE){ | ||||
|             // this is a new version J3O file | ||||
|             formatVersion = ByteUtils.readInt(bis); | ||||
|             numClasses = ByteUtils.readInt(bis); | ||||
|              | ||||
|             // check if this binary is from the future | ||||
|             if (formatVersion > FormatVersion.VERSION){ | ||||
|                 throw new IOException("The binary file is of newer version than expected! " +  | ||||
|                                       formatVersion + " > " + FormatVersion.VERSION); | ||||
|             } | ||||
|         }else{ | ||||
|             // this is an old version J3O file | ||||
|             // the signature was actually the class count | ||||
|             numClasses = maybeSignature; | ||||
|              | ||||
|             // 0 indicates version before we started adding | ||||
|             // version numbers | ||||
|             formatVersion = 0;  | ||||
|         } | ||||
|          | ||||
|         int bytes = 4; | ||||
|         aliasWidth = ((int)FastMath.log(numClasses, 256) + 1); | ||||
| 
 | ||||
|         classes.clear(); | ||||
|         for(int i = 0; i < numClasses; i++) { | ||||
|             String alias = readString(bis, aliasWidth); | ||||
| 
 | ||||
|              | ||||
|             // jME3 NEW: Read class version number | ||||
|             int[] classHierarchyVersions; | ||||
|             if (formatVersion >= 1){ | ||||
|                 int classHierarchySize = bis.read(); | ||||
|                 classHierarchyVersions = new int[classHierarchySize]; | ||||
|                 for (int j = 0; j < classHierarchySize; j++){ | ||||
|                     classHierarchyVersions[j] = ByteUtils.readInt(bis); | ||||
|                 } | ||||
|             }else{ | ||||
|                 classHierarchyVersions = new int[]{ 0 }; | ||||
|             } | ||||
|              | ||||
|             // read classname and classname size | ||||
|             int classLength = ByteUtils.readInt(bis); | ||||
|             String className = readString(bis, classLength); | ||||
|              | ||||
|             BinaryClassObject bco = new BinaryClassObject(); | ||||
|             bco.alias = alias.getBytes(); | ||||
|             bco.className = className; | ||||
| 
 | ||||
|             bco.classHierarchyVersions = classHierarchyVersions; | ||||
|              | ||||
|             int fields = ByteUtils.readInt(bis); | ||||
|             bytes += (8 + aliasWidth + classLength); | ||||
| 
 | ||||
| @ -210,9 +257,9 @@ public final class BinaryImporter implements JmeImporter { | ||||
|         Savable rVal = readObject(id); | ||||
|         if (debug) { | ||||
|             logger.info("Importer Stats: "); | ||||
|             logger.info("Tags: "+numClasses); | ||||
|             logger.info("Objects: "+numLocs); | ||||
|             logger.info("Data Size: "+dataArray.length); | ||||
|             logger.log(Level.INFO, "Tags: {0}", numClasses); | ||||
|             logger.log(Level.INFO, "Objects: {0}", numLocs); | ||||
|             logger.log(Level.INFO, "Data Size: {0}", dataArray.length); | ||||
|         } | ||||
|         dataArray = null; | ||||
|         return rVal; | ||||
| @ -247,7 +294,8 @@ public final class BinaryImporter implements JmeImporter { | ||||
|         return rVal; | ||||
|     } | ||||
| 
 | ||||
|     public BinaryInputCapsule getCapsule(Savable id) { | ||||
|     @Override | ||||
|     public InputCapsule getCapsule(Savable id) { | ||||
|         return capsuleTable.get(id); | ||||
|     } | ||||
| 
 | ||||
| @ -291,11 +339,11 @@ public final class BinaryImporter implements JmeImporter { | ||||
|             int dataLength = ByteUtils.convertIntFromBytes(dataArray, loc); | ||||
|             loc+=4; | ||||
| 
 | ||||
|             BinaryInputCapsule cap = new BinaryInputCapsule(this, bco); | ||||
|             Savable out = SavableClassUtil.fromName(bco.className, loaders); | ||||
|              | ||||
|             BinaryInputCapsule cap = new BinaryInputCapsule(this, out, bco); | ||||
|             cap.setContent(dataArray, loc, loc+dataLength); | ||||
| 
 | ||||
|             Savable out = SavableClassFinder.fromName(bco.className, cap, loaders); | ||||
| 
 | ||||
|             capsuleTable.put(out, cap); | ||||
|             contentTable.put(id, out); | ||||
| 
 | ||||
|  | ||||
| @ -39,7 +39,6 @@ import com.jme3.util.IntMap; | ||||
| import java.io.IOException; | ||||
| import java.io.UnsupportedEncodingException; | ||||
| import java.nio.ByteBuffer; | ||||
| import java.nio.ByteOrder; | ||||
| import java.nio.FloatBuffer; | ||||
| import java.nio.IntBuffer; | ||||
| import java.nio.ShortBuffer; | ||||
| @ -60,13 +59,15 @@ final class BinaryInputCapsule implements InputCapsule { | ||||
| 
 | ||||
|     protected BinaryImporter importer; | ||||
|     protected BinaryClassObject cObj; | ||||
|     protected Savable savable; | ||||
|     protected HashMap<Byte, Object> fieldData; | ||||
| 
 | ||||
|     protected int index = 0; | ||||
| 
 | ||||
|     public BinaryInputCapsule(BinaryImporter importer, BinaryClassObject bco) { | ||||
|     public BinaryInputCapsule(BinaryImporter importer, Savable savable, BinaryClassObject bco) { | ||||
|         this.importer = importer; | ||||
|         this.cObj = bco; | ||||
|         this.savable = savable; | ||||
|     } | ||||
| 
 | ||||
|     public void setContent(byte[] content, int start, int limit) { | ||||
| @ -255,6 +256,26 @@ final class BinaryInputCapsule implements InputCapsule { | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     public int getSavableVersion(Class<? extends Savable> desiredClass){ | ||||
|         Class thisClass = savable.getClass(); | ||||
|         int count = 0; | ||||
|         while (thisClass != null && thisClass != desiredClass){ | ||||
|             thisClass = thisClass.getSuperclass(); | ||||
|             count ++; | ||||
|         } | ||||
|         if (thisClass == null){ | ||||
|             throw new IllegalArgumentException(savable.getClass().getName() +  | ||||
|                                                " does not extend " +  | ||||
|                                                desiredClass.getName() + "!"); | ||||
|         }else if (count > cObj.classHierarchyVersions.length){ | ||||
|             throw new IllegalArgumentException(savable.getClass().getName() +  | ||||
|                                                " cannot access version of " + | ||||
|                                                desiredClass.getName() +  | ||||
|                                                " because it doesn't implement Savable"); | ||||
|         } | ||||
|         return cObj.classHierarchyVersions[count]; | ||||
|     } | ||||
| 
 | ||||
|     public BitSet readBitSet(String name, BitSet defVal) throws IOException { | ||||
|         BinaryClassField field = cObj.nameFields.get(name); | ||||
|  | ||||
| @ -1,62 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (c) 2009-2010 jMonkeyEngine | ||||
|  * All rights reserved. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are | ||||
|  * met: | ||||
|  * | ||||
|  * * Redistributions of source code must retain the above copyright | ||||
|  *   notice, this list of conditions and the following disclaimer. | ||||
|  * | ||||
|  * * Redistributions in binary form must reproduce the above copyright | ||||
|  *   notice, this list of conditions and the following disclaimer in the | ||||
|  *   documentation and/or other materials provided with the distribution. | ||||
|  * | ||||
|  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors | ||||
|  *   may be used to endorse or promote products derived from this software | ||||
|  *   without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||
|  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | ||||
|  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||||
|  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | ||||
|  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | ||||
|  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||||
|  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||||
|  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||||
|  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||||
|  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| package com.jme3.export.binary; | ||||
| 
 | ||||
| import com.jme3.export.InputCapsule; | ||||
| import com.jme3.export.Savable; | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| /** | ||||
|  * BinaryLoaderModule defines two methods, the first provides a key value to | ||||
|  * look for to issue the load command. This key is typically (and should be) | ||||
|  * the class name the loader is responsible for. While load handles creating | ||||
|  * a new instance of the class. | ||||
|  * @author mpowell | ||||
|  * | ||||
|  */ | ||||
| interface BinaryLoaderModule { | ||||
|      | ||||
|     String getKey(); | ||||
| 
 | ||||
|     /** | ||||
|      * The inputCapsule parameter is not used at all. | ||||
|      * | ||||
|      * The DOMOutputStream class calls this method with a null parameter, so | ||||
|      * if you make use of the parameter, either handle null 'inputCapsule' | ||||
|      * or rearrange the class hierarchy to satisfy DOMOuptutStream. | ||||
|      * | ||||
|      * @param inputCapsule  A value which is currently ignored by all | ||||
|      *                      implementation classes. | ||||
|      */ | ||||
|     Savable load(InputCapsule inputCapsule) throws IOException; | ||||
| } | ||||
| @ -39,7 +39,6 @@ import com.jme3.export.Savable; | ||||
| import com.jme3.renderer.RenderManager; | ||||
| import com.jme3.renderer.ViewPort; | ||||
| import com.jme3.scene.Mesh; | ||||
| import com.jme3.scene.Node; | ||||
| import com.jme3.scene.Spatial; | ||||
| import com.jme3.scene.control.AbstractControl; | ||||
| import com.jme3.scene.control.Control; | ||||
| @ -68,7 +67,7 @@ import java.util.HashMap; | ||||
|  * | ||||
|  * @author Kirill Vainer | ||||
|  */ | ||||
| public final class AnimControl extends AbstractControl implements Savable, Cloneable { | ||||
| public final class AnimControl extends AbstractControl implements Cloneable { | ||||
| 
 | ||||
|     /** | ||||
|      * Skeleton object must contain corresponding data for the targets' weight buffers. | ||||
| @ -351,16 +350,17 @@ public final class AnimControl extends AbstractControl implements Savable, Clone | ||||
|         skeleton = (Skeleton) in.readSavable("skeleton", null); | ||||
|         animationMap = (HashMap<String, BoneAnimation>) in.readStringSavableMap("animations", null); | ||||
| 
 | ||||
|         //changed for backward compatibility with j3o files generated before the AnimControl/SkeletonControl split | ||||
|         //if we find a target mesh array the AnimControl creates the SkeletonControl for old files and add it to the spatial.         | ||||
|         //When backward compatibility won't be needed anymore this can deleted         | ||||
|         Savable[] sav = in.readSavableArray("targets", null); | ||||
|         if (sav != null) { | ||||
|             Mesh[] tg = null; | ||||
|             tg = new Mesh[sav.length]; | ||||
|             System.arraycopy(sav, 0, tg, 0, sav.length); | ||||
|             skeletonControl = new SkeletonControl(tg, skeleton); | ||||
|             spatial.addControl(skeletonControl); | ||||
|         if (im.getFormatVersion() == 0){ | ||||
|             //changed for backward compatibility with j3o files generated before the AnimControl/SkeletonControl split | ||||
|             //if we find a target mesh array the AnimControl creates the SkeletonControl for old files and add it to the spatial.         | ||||
|             //When backward compatibility won't be needed anymore this can deleted         | ||||
|             Savable[] sav = in.readSavableArray("targets", null); | ||||
|             if (sav != null) { | ||||
|                 Mesh[] targets = new Mesh[sav.length]; | ||||
|                 System.arraycopy(sav, 0, targets, 0, sav.length); | ||||
|                 skeletonControl = new SkeletonControl(targets, skeleton); | ||||
|                 spatial.addControl(skeletonControl); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -268,27 +268,27 @@ public final class BoneTrack implements Savable { | ||||
| 
 | ||||
| 
 | ||||
|         //Backward compatibility for old j3o files generated before revision 6807 | ||||
|         if (translations == null) { | ||||
|             Savable[] sav = ic.readSavableArray("translations", null); | ||||
|             if (sav != null) { | ||||
|                 translations = new CompactVector3Array(); | ||||
|                 Vector3f[] transCopy = new Vector3f[sav.length]; | ||||
|                 System.arraycopy(sav, 0, transCopy, 0, sav.length); | ||||
|                 translations.add(transCopy); | ||||
|                 translations.freeze(); | ||||
|         if (im.getFormatVersion() == 0){ | ||||
|             if (translations == null) { | ||||
|                 Savable[] sav = ic.readSavableArray("translations", null); | ||||
|                 if (sav != null) { | ||||
|                     translations = new CompactVector3Array(); | ||||
|                     Vector3f[] transCopy = new Vector3f[sav.length]; | ||||
|                     System.arraycopy(sav, 0, transCopy, 0, sav.length); | ||||
|                     translations.add(transCopy); | ||||
|                     translations.freeze(); | ||||
|                 } | ||||
|             } | ||||
|             if (rotations == null) { | ||||
|                 Savable[] sav = ic.readSavableArray("rotations", null); | ||||
|                 if (sav != null) { | ||||
|                     rotations = new CompactQuaternionArray(); | ||||
|                     Quaternion[] rotCopy = new Quaternion[sav.length]; | ||||
|                     System.arraycopy(sav, 0, rotCopy, 0, sav.length); | ||||
|                     rotations.add(rotCopy); | ||||
|                     rotations.freeze(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         if (rotations == null) { | ||||
|             Savable[] sav = ic.readSavableArray("rotations", null); | ||||
|             if (sav != null) { | ||||
|                 rotations = new CompactQuaternionArray(); | ||||
|                 Quaternion[] rotCopy = new Quaternion[sav.length]; | ||||
|                 System.arraycopy(sav, 0, rotCopy, 0, sav.length); | ||||
|                 rotations.add(rotCopy); | ||||
|                 rotations.freeze(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -17,6 +17,7 @@ import com.jme3.scene.Geometry; | ||||
| import com.jme3.scene.Mesh; | ||||
| import com.jme3.scene.Node; | ||||
| import com.jme3.scene.Spatial; | ||||
| import com.jme3.scene.UserData; | ||||
| import com.jme3.scene.VertexBuffer; | ||||
| import com.jme3.scene.VertexBuffer.Type; | ||||
| import com.jme3.scene.control.AbstractControl; | ||||
| @ -25,14 +26,16 @@ import com.jme3.util.TempVars; | ||||
| import java.io.IOException; | ||||
| import java.nio.ByteBuffer; | ||||
| import java.nio.FloatBuffer; | ||||
| import java.util.ArrayList; | ||||
| 
 | ||||
| /** | ||||
|  * The Skeleton control deforms a model according to a skeleton,  | ||||
|  * It handles the computation of the deformtation matrices and performs the transformations on the mesh | ||||
|  * It handles the computation of the deformation matrices and performs  | ||||
|  * the transformations on the mesh | ||||
|  *  | ||||
|  * @author Rémy Bouquet Based on AnimControl by Kirill Vainer | ||||
|  */ | ||||
| public class SkeletonControl extends AbstractControl implements Savable, Cloneable { | ||||
| public class SkeletonControl extends AbstractControl implements Cloneable { | ||||
| 
 | ||||
|     /** | ||||
|      * The skeleton of the model | ||||
| @ -49,21 +52,90 @@ public class SkeletonControl extends AbstractControl implements Savable, Cloneab | ||||
|     private boolean wasMeshUpdated = false; | ||||
| 
 | ||||
|     /** | ||||
|      * for serialization only | ||||
|      * Serialization only. Do not use. | ||||
|      */ | ||||
|     public SkeletonControl() { | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Creates a skeleton control  | ||||
|      * @param targets the meshes controled by the skeleton | ||||
|      * Creates a skeleton control. | ||||
|      * The list of targets will be acquired automatically when | ||||
|      * the control is attached to a node. | ||||
|      *  | ||||
|      * @param skeleton the skeleton | ||||
|      */ | ||||
|     public SkeletonControl(Mesh[] targets, Skeleton skeleton) { | ||||
|     public SkeletonControl(Skeleton skeleton) { | ||||
|         this.skeleton = skeleton; | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|      * Creates a skeleton control. | ||||
|      *  | ||||
|      * @param targets the meshes controlled by the skeleton | ||||
|      * @param skeleton the skeleton | ||||
|      */ | ||||
|     @Deprecated | ||||
|     public SkeletonControl(Mesh[] targets, Skeleton skeleton){ | ||||
|         this.skeleton = skeleton; | ||||
|         this.targets = targets; | ||||
|     } | ||||
|      | ||||
|     private boolean isMeshAnimated(Mesh mesh){ | ||||
|         return mesh.getBuffer(Type.BindPosePosition) != null; | ||||
|     } | ||||
| 
 | ||||
|     private Mesh[] findTargets(Node node){ | ||||
|         Mesh sharedMesh = null; | ||||
|         ArrayList<Mesh> animatedMeshes = new ArrayList<Mesh>(); | ||||
|          | ||||
|         for (Spatial child : node.getChildren()){ | ||||
|             if (!(child instanceof Geometry)){ | ||||
|                 continue; // could be an attachment node, ignore. | ||||
|             } | ||||
|              | ||||
|             Geometry geom = (Geometry) child; | ||||
|              | ||||
|             // is this geometry using a shared mesh? | ||||
|             Mesh childSharedMesh = geom.getUserData(UserData.JME_SHAREDMESH); | ||||
|              | ||||
|             if (childSharedMesh != null){ | ||||
|                  | ||||
|                 // Don't bother with non-animated shared meshes | ||||
|                 if (isMeshAnimated(childSharedMesh)){ | ||||
|                      | ||||
|                     // child is using shared mesh, | ||||
|                     // so animate the shared mesh but ignore child | ||||
|                     if (sharedMesh == null){ | ||||
|                         sharedMesh = childSharedMesh; | ||||
|                     }else if (sharedMesh != childSharedMesh){ | ||||
|                         throw new IllegalStateException("Two conflicting shared meshes for " + node); | ||||
|                     } | ||||
|                 } | ||||
|             }else{ | ||||
|                 Mesh mesh = geom.getMesh(); | ||||
|                 if (isMeshAnimated(mesh)){ | ||||
|                     animatedMeshes.add(mesh); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         if (sharedMesh != null){ | ||||
|             animatedMeshes.add(sharedMesh); | ||||
|         } | ||||
|          | ||||
|         return animatedMeshes.toArray(new Mesh[animatedMeshes.size()]); | ||||
|     } | ||||
|      | ||||
|     @Override | ||||
|     public void setSpatial(Spatial spatial){ | ||||
|         if (spatial != null){ | ||||
|             Node node = (Node) spatial; | ||||
|             targets = findTargets(node); | ||||
|         }else{ | ||||
|             targets = null; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     @Override | ||||
|     protected void controlRender(RenderManager rm, ViewPort vp) { | ||||
|         if (!wasMeshUpdated) { | ||||
| @ -87,13 +159,11 @@ public class SkeletonControl extends AbstractControl implements Savable, Cloneab | ||||
|     @Override | ||||
|     protected void controlUpdate(float tpf) { | ||||
|         wasMeshUpdated = false; | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     void resetToBind() { | ||||
|         for (int i = 0; i < targets.length; i++) { | ||||
|             Mesh mesh = targets[i]; | ||||
|             if (targets[i].getBuffer(Type.BindPosePosition) != null) { | ||||
|         for (Mesh mesh : targets){ | ||||
|             if (isMeshAnimated(mesh)) { | ||||
|                 VertexBuffer bi = mesh.getBuffer(Type.BoneIndex); | ||||
|                 ByteBuffer bib = (ByteBuffer) bi.getData(); | ||||
|                 if (!bib.hasArray()) { | ||||
| @ -177,12 +247,12 @@ public class SkeletonControl extends AbstractControl implements Savable, Cloneab | ||||
|      * sets the skeleton for this control | ||||
|      * @param skeleton  | ||||
|      */ | ||||
|     public void setSkeleton(Skeleton skeleton) { | ||||
|         this.skeleton = skeleton; | ||||
|     } | ||||
| //    public void setSkeleton(Skeleton skeleton) { | ||||
| //        this.skeleton = skeleton; | ||||
| //    } | ||||
| 
 | ||||
|     /** | ||||
|      * retuns the targets meshes of this ocntrol | ||||
|      * returns the targets meshes of this control | ||||
|      * @return  | ||||
|      */ | ||||
|     public Mesh[] getTargets() { | ||||
| @ -193,9 +263,9 @@ public class SkeletonControl extends AbstractControl implements Savable, Cloneab | ||||
|      * sets the target  meshes of this control | ||||
|      * @param targets  | ||||
|      */ | ||||
|     public void setTargets(Mesh[] targets) { | ||||
|         this.targets = targets; | ||||
|     } | ||||
| //    public void setTargets(Mesh[] targets) { | ||||
| //        this.targets = targets; | ||||
| //    } | ||||
| 
 | ||||
|     private void softwareSkinUpdate(Mesh mesh, Matrix4f[] offsetMatrices) { | ||||
|         int maxWeightsPerVert = mesh.getMaxNumWeights(); | ||||
|  | ||||
| @ -61,7 +61,7 @@ import java.util.logging.Logger; | ||||
|  * | ||||
|  * @author Nehon | ||||
|  */ | ||||
| public class Cinematic extends AbstractCinematicEvent implements Savable, AppState { | ||||
| public class Cinematic extends AbstractCinematicEvent implements AppState { | ||||
| 
 | ||||
|     private static final Logger logger = Logger.getLogger(Application.class.getName()); | ||||
|     private String niftyXmlPath = null; | ||||
|  | ||||
| @ -48,7 +48,7 @@ import java.util.List; | ||||
|  * | ||||
|  * @author Nehon | ||||
|  */ | ||||
| public abstract class AbstractCinematicEvent implements CinematicEvent, Savable { | ||||
| public abstract class AbstractCinematicEvent implements CinematicEvent { | ||||
| 
 | ||||
|     protected PlayState playState = PlayState.Stopped; | ||||
|     protected float speed = 1; | ||||
|  | ||||
| @ -35,12 +35,13 @@ import com.jme3.animation.LoopMode; | ||||
| import com.jme3.app.Application; | ||||
| import com.jme3.cinematic.Cinematic; | ||||
| import com.jme3.cinematic.PlayState; | ||||
| import com.jme3.export.Savable; | ||||
| 
 | ||||
| /** | ||||
|  * | ||||
|  * @author Nehon | ||||
|  */ | ||||
| public interface CinematicEvent { | ||||
| public interface CinematicEvent extends Savable { | ||||
| 
 | ||||
|     /** | ||||
|      * Starts the animation | ||||
|  | ||||
| @ -1118,23 +1118,25 @@ public class ParticleEmitter extends Geometry { | ||||
| 
 | ||||
|         particleInfluencer = (ParticleInfluencer) ic.readSavable("influencer", DEFAULT_INFLUENCER); | ||||
| 
 | ||||
|         // compatibility before the control inside particle emitter | ||||
|         // was changed: | ||||
|         // find it in the controls and take it out, then add the proper one in | ||||
|         for (int i = 0; i < controls.size(); i++) { | ||||
|             Object obj = controls.get(i); | ||||
|             if (obj instanceof ParticleEmitter) { | ||||
|                 controls.remove(i); | ||||
|                 // now add the proper one in | ||||
|                 controls.add(control); | ||||
|                 break; | ||||
|         if (im.getFormatVersion() == 0){ | ||||
|             // compatibility before the control inside particle emitter | ||||
|             // was changed: | ||||
|             // find it in the controls and take it out, then add the proper one in | ||||
|             for (int i = 0; i < controls.size(); i++){ | ||||
|                 Object obj = controls.get(i); | ||||
|                 if (obj instanceof ParticleEmitter){ | ||||
|                     controls.remove(i); | ||||
|                     // now add the proper one in | ||||
|                     controls.add(control); | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // compatability before gravity was not a vector but a float | ||||
|         if (gravity == null) { | ||||
|             gravity = new Vector3f(); | ||||
|             gravity.y = ic.readFloat("gravity", 0); | ||||
|             // compatability before gravity was not a vector but a float | ||||
|             if (gravity == null){ | ||||
|                 gravity = new Vector3f(); | ||||
|                 gravity.y = ic.readFloat("gravity", 0); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -56,7 +56,7 @@ public class DefaultParticleInfluencer implements ParticleInfluencer { | ||||
|     @Override | ||||
|     public void read(JmeImporter im) throws IOException { | ||||
|         InputCapsule ic = im.getCapsule(this); | ||||
|         startVelocity = (Vector3f) ic.readSavable("startVelocity", Vector3f.ZERO); | ||||
|         startVelocity = (Vector3f) ic.readSavable("startVelocity", Vector3f.ZERO.clone()); | ||||
|         velocityVariation = ic.readFloat("variation", 0.2f); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| package com.jme3.effect.shapes; | ||||
| 
 | ||||
| import com.jme3.export.InputCapsule; | ||||
| import java.io.IOException; | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashMap; | ||||
| @ -141,11 +142,18 @@ public class EmitterMeshVertexShape implements EmitterShape { | ||||
|     public void write(JmeExporter ex) throws IOException { | ||||
|         OutputCapsule oc = ex.getCapsule(this); | ||||
|         oc.writeSavableArrayList((ArrayList<List<Vector3f>>) vertices, "vertices", null); | ||||
|         oc.writeSavableArrayList((ArrayList<List<Vector3f>>) normals, "normals", null); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     @SuppressWarnings("unchecked") | ||||
|     public void read(JmeImporter im) throws IOException { | ||||
|         this.vertices = im.getCapsule(this).readSavableArrayList("vertices", null); | ||||
|         InputCapsule ic = im.getCapsule(this); | ||||
|         this.vertices = ic.readSavableArrayList("vertices", null); | ||||
|          | ||||
|         List<List<Vector3f>> tmpNormals = ic.readSavableArrayList("normals", null); | ||||
|         if (tmpNormals != null){ | ||||
|             this.normals = tmpNormals; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -47,6 +47,8 @@ import java.util.Map; | ||||
|  */ | ||||
| public interface InputCapsule { | ||||
| 
 | ||||
|     public int getSavableVersion(Class<? extends Savable> clazz); | ||||
|      | ||||
|     // byte primitive | ||||
| 
 | ||||
|     public byte readByte(String name, byte defVal) throws IOException; | ||||
|  | ||||
| @ -38,4 +38,12 @@ import com.jme3.asset.AssetManager; | ||||
| public interface JmeImporter extends AssetLoader { | ||||
|     public InputCapsule getCapsule(Savable id); | ||||
|     public AssetManager getAssetManager(); | ||||
|      | ||||
|     /** | ||||
|      * Returns the version number written in the header of the J3O/XML | ||||
|      * file. | ||||
|      *  | ||||
|      * @return Global version number for the file | ||||
|      */ | ||||
|     public int getFormatVersion(); | ||||
| } | ||||
|  | ||||
| @ -37,7 +37,8 @@ import java.io.IOException; | ||||
| /** | ||||
|  * <code>Savable</code> is an interface for objects that can be serialized | ||||
|  * using jME's serialization system.  | ||||
|  * @author Dany | ||||
|  *  | ||||
|  * @author Kirill Vainer | ||||
|  */ | ||||
| public interface Savable { | ||||
|     void write(JmeExporter ex) throws IOException; | ||||
|  | ||||
| @ -41,26 +41,27 @@ import java.io.IOException; | ||||
| import java.util.logging.Level; | ||||
| import java.util.logging.Logger; | ||||
| 
 | ||||
| import com.jme3.export.InputCapsule; | ||||
| import com.jme3.export.Savable; | ||||
| import com.jme3.material.MatParamTexture; | ||||
| import com.jme3.scene.Spatial; | ||||
| import java.lang.reflect.Field; | ||||
| import java.lang.reflect.Type; | ||||
| import java.util.HashMap; | ||||
| import java.util.Iterator; | ||||
| import java.util.List; | ||||
| 
 | ||||
| /** | ||||
|  * <code>SavableClassFinder</code> is used to find classes referenced | ||||
|  * by savables. | ||||
|  * <code>SavableClassUtil</code> contains various utilities to handle | ||||
|  * Savable classes. The methods are general enough to not be specific to any | ||||
|  * particular implementation. | ||||
|  * Currently it will remap any classes from old paths to new paths | ||||
|  * so that old J3O models can still be loaded. | ||||
|  * | ||||
|  * @author mpowell | ||||
|  * @author Kirill Vainer | ||||
|  */ | ||||
| public class SavableClassFinder { | ||||
| public class SavableClassUtil { | ||||
| 
 | ||||
|     private final static HashMap<String, String> classRemappings = new HashMap<String, String>(); | ||||
| 
 | ||||
|      | ||||
|     private static void addRemapping(String oldClass, Class<? extends Savable> newClass){ | ||||
|         classRemappings.put(oldClass, newClass.getName()); | ||||
|     } | ||||
| @ -83,7 +84,32 @@ public class SavableClassFinder { | ||||
|             return result; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     public static boolean isImplementingSavable(Class clazz){ | ||||
|         Class[] interfaces = clazz.getInterfaces(); | ||||
|         for (Class interfaceClass : interfaces){ | ||||
|             if (interfaceClass == Savable.class){ | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     public static int getSavableVersion(Class<? extends Savable> clazz) throws IOException{ | ||||
|         try { | ||||
|             Field field = clazz.getField("SAVABLE_VERSION"); | ||||
|             return field.getInt(null); | ||||
|         } catch (IllegalAccessException ex) { | ||||
|             IOException ioEx = new IOException(); | ||||
|             ioEx.initCause(ex); | ||||
|             throw ioEx; | ||||
|         } catch (IllegalArgumentException ex) { | ||||
|             throw ex; // can happen if SAVABLE_VERSION is not static | ||||
|         } catch (NoSuchFieldException ex) { | ||||
|             return 0; // not using versions | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|      * fromName creates a new Savable from the provided class name. First registered modules | ||||
|      * are checked to handle special cases, if the modules do not handle the class name, the | ||||
| @ -96,29 +122,29 @@ public class SavableClassFinder { | ||||
|      * @throws ClassNotFoundException thrown if the class name is not in the classpath. | ||||
|      * @throws IOException when loading ctor parameters fails | ||||
|      */ | ||||
|     public static Savable fromName(String className, InputCapsule inputCapsule) throws InstantiationException, | ||||
|     public static Savable fromName(String className) throws InstantiationException, | ||||
|             IllegalAccessException, ClassNotFoundException, IOException { | ||||
| 
 | ||||
|         className = remapClass(className); | ||||
|         try { | ||||
|             return (Savable) Class.forName(className).newInstance(); | ||||
|         } catch (InstantiationException e) { | ||||
|             Logger.getLogger(SavableClassFinder.class.getName()).log( | ||||
|             Logger.getLogger(SavableClassUtil.class.getName()).log( | ||||
|                     Level.SEVERE, "Could not access constructor of class ''{0}" + "''! \n" | ||||
|                     + "Some types need to have the BinaryImporter set up in a special way. Please doublecheck the setup.", className); | ||||
|             throw e; | ||||
|         } catch (IllegalAccessException e) { | ||||
|             Logger.getLogger(SavableClassFinder.class.getName()).log( | ||||
|             Logger.getLogger(SavableClassUtil.class.getName()).log( | ||||
|                     Level.SEVERE, "{0} \n" | ||||
|                     + "Some types need to have the BinaryImporter set up in a special way. Please doublecheck the setup.", e.getMessage()); | ||||
|             throw e; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public static Savable fromName(String className, InputCapsule inputCapsule, List<ClassLoader> loaders) throws InstantiationException, | ||||
|     public static Savable fromName(String className, List<ClassLoader> loaders) throws InstantiationException, | ||||
|             IllegalAccessException, ClassNotFoundException, IOException { | ||||
|         if (loaders == null) { | ||||
|             return fromName(className, inputCapsule); | ||||
|             return fromName(className); | ||||
|         } | ||||
|          | ||||
|         String newClassName = remapClass(className); | ||||
| @ -131,6 +157,6 @@ public class SavableClassFinder { | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         return fromName(className, inputCapsule); | ||||
|         return fromName(className); | ||||
|     } | ||||
| } | ||||
| @ -53,6 +53,12 @@ public final class UserData implements Savable { | ||||
|      */ | ||||
|     public static final String JME_PHYSICSIGNORE = "JmePhysicsIgnore"; | ||||
|      | ||||
|     /** | ||||
|      * For geometries using shared mesh, this will specify the shared | ||||
|      * mesh reference. | ||||
|      */ | ||||
|     public static final String JME_SHAREDMESH = "JmeSharedMesh"; | ||||
|      | ||||
|     protected byte type; | ||||
|     protected Object value; | ||||
| 
 | ||||
|  | ||||
| @ -63,7 +63,7 @@ import java.nio.ShortBuffer; | ||||
|  * </ul> | ||||
|  */ | ||||
| public class VertexBuffer extends GLObject implements Savable, Cloneable { | ||||
| 
 | ||||
|    | ||||
|     /** | ||||
|      * Type of buffer. Specifies the actual attribute it defines. | ||||
|      */ | ||||
|  | ||||
| @ -44,7 +44,7 @@ import java.nio.IntBuffer; | ||||
| 
 | ||||
| /** | ||||
|  * implements all writeXXXXArray methods to reduce boilerplate code | ||||
|  * Geomap implementations are encourged to extend this class | ||||
|  * Geomap implementations are encouraged to extend this class | ||||
|  */ | ||||
| public abstract class AbstractGeomap implements Geomap { | ||||
| 
 | ||||
| @ -60,7 +60,7 @@ public abstract class AbstractGeomap implements Geomap { | ||||
| 
 | ||||
|     /* | ||||
|      * (non-Javadoc) | ||||
|      * Subclasses are encourged to provide a better implementation | ||||
|      * Subclasses are encouraged to provide a better implementation | ||||
|      * which directly accesses the data rather than using getHeight | ||||
|      */ | ||||
|     public FloatBuffer writeVertexArray(FloatBuffer store, Vector3f scale, boolean center){ | ||||
|  | ||||
| @ -33,9 +33,8 @@ | ||||
| package com.jme3.util; | ||||
| 
 | ||||
| import java.io.Serializable; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collection; | ||||
| import java.util.HashSet; | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
| import java.util.Map.Entry; | ||||
| import java.util.Set; | ||||
| @ -92,35 +91,48 @@ public final class ListMap<K, V> implements Map<K, V>, Cloneable, Serializable { | ||||
| 
 | ||||
|     } | ||||
|      | ||||
|     private final ArrayList<ListMapEntry<K,V>> entries; | ||||
|     private final HashMap<K, V> backingMap; | ||||
|     private ListMapEntry<K, V>[] entries; | ||||
|      | ||||
| //    private final ArrayList<ListMapEntry<K,V>> entries; | ||||
| 
 | ||||
|     public ListMap(){ | ||||
|        entries = new ArrayList<ListMapEntry<K,V>>(); | ||||
|         entries = new ListMapEntry[4]; | ||||
|         backingMap = new HashMap<K, V>(4); | ||||
| //       entries = new ArrayList<ListMapEntry<K,V>>(); | ||||
|     } | ||||
| 
 | ||||
|     public ListMap(int initialCapacity){ | ||||
|         entries = new ArrayList<ListMapEntry<K, V>>(initialCapacity); | ||||
|         entries = new ListMapEntry[initialCapacity]; | ||||
|         backingMap = new HashMap<K, V>(initialCapacity); | ||||
| //        entries = new ArrayList<ListMapEntry<K, V>>(initialCapacity); | ||||
|     } | ||||
| 
 | ||||
|     public ListMap(Map<? extends K, ? extends V> map){ | ||||
|         entries = new ArrayList<ListMapEntry<K, V>>(map.size()); | ||||
|         entries = new ListMapEntry[map.size()]; | ||||
|         backingMap = new HashMap<K, V>(map.size()); | ||||
| //        entries = new ArrayList<ListMapEntry<K, V>>(map.size()); | ||||
|         putAll(map); | ||||
|     } | ||||
| 
 | ||||
|     public int size() { | ||||
|         return entries.size(); | ||||
| //        return entries.size(); | ||||
|         return backingMap.size(); | ||||
|     } | ||||
| 
 | ||||
|     public Entry<K, V> getEntry(int index){ | ||||
|         return entries.get(index); | ||||
| //        return entries.get(index); | ||||
|         return entries[index]; | ||||
|     } | ||||
| 
 | ||||
|     public V getValue(int index){ | ||||
|         return entries.get(index).value; | ||||
| //        return entries.get(index).value; | ||||
|         return entries[index].value; | ||||
|     } | ||||
| 
 | ||||
|     public K getKey(int index){ | ||||
|         return entries.get(index).key; | ||||
| //        return entries.get(index).key; | ||||
|         return entries[index].key; | ||||
|     } | ||||
| 
 | ||||
|     public boolean isEmpty() { | ||||
| @ -130,93 +142,142 @@ public final class ListMap<K, V> implements Map<K, V>, Cloneable, Serializable { | ||||
|     private static boolean keyEq(Object keyA, Object keyB){ | ||||
|         return keyA.hashCode() == keyB.hashCode() ? (keyA == keyB) || keyA.equals(keyB) : false; | ||||
|     } | ||||
| 
 | ||||
|     private static boolean valEq(Object a, Object b){ | ||||
|         return a == null ? (b == null) : a.equals(b); | ||||
|     } | ||||
| // | ||||
| //    private static boolean valEq(Object a, Object b){ | ||||
| //        return a == null ? (b == null) : a.equals(b); | ||||
| //    } | ||||
| 
 | ||||
|     public boolean containsKey(Object key) { | ||||
|         if (key == null) | ||||
|             throw new IllegalArgumentException(); | ||||
| 
 | ||||
|         for (int i = 0; i < entries.size(); i++){ | ||||
|             ListMapEntry<K,V> entry = entries.get(i); | ||||
|             if (keyEq(entry.key, key)) | ||||
|                 return true; | ||||
|         } | ||||
|         return false; | ||||
|         return backingMap.containsKey( (K) key);  | ||||
| //        if (key == null) | ||||
| //            throw new IllegalArgumentException(); | ||||
| // | ||||
| //        for (int i = 0; i < entries.size(); i++){ | ||||
| //            ListMapEntry<K,V> entry = entries.get(i); | ||||
| //            if (keyEq(entry.key, key)) | ||||
| //                return true; | ||||
| //        } | ||||
| //        return false; | ||||
|     } | ||||
| 
 | ||||
|     public boolean containsValue(Object value) { | ||||
|         for (int i = 0; i < entries.size(); i++){ | ||||
|             if (valEq(entries.get(i).value, value)) | ||||
|                 return true; | ||||
|         } | ||||
|         return false; | ||||
|         return backingMap.containsValue( (V) value);  | ||||
| //        for (int i = 0; i < entries.size(); i++){ | ||||
| //            if (valEq(entries.get(i).value, value)) | ||||
| //                return true; | ||||
| //        } | ||||
| //        return false; | ||||
|     } | ||||
| 
 | ||||
|     public V get(Object key) { | ||||
|         if (key == null) | ||||
|             throw new IllegalArgumentException(); | ||||
| 
 | ||||
|         for (int i = 0; i < entries.size(); i++){ | ||||
|             ListMapEntry<K,V> entry = entries.get(i); | ||||
|             if (keyEq(entry.key, key)) | ||||
|                 return entry.value; | ||||
|         } | ||||
|         return null; | ||||
|         return backingMap.get( (K) key);  | ||||
| //        if (key == null) | ||||
| //            throw new IllegalArgumentException(); | ||||
| // | ||||
| //        for (int i = 0; i < entries.size(); i++){ | ||||
| //            ListMapEntry<K,V> entry = entries.get(i); | ||||
| //            if (keyEq(entry.key, key)) | ||||
| //                return entry.value; | ||||
| //        } | ||||
| //        return null; | ||||
|     } | ||||
| 
 | ||||
|     public V put(K key, V value) { | ||||
|         if (key == null) | ||||
|             throw new IllegalArgumentException(); | ||||
| 
 | ||||
|         // check if entry exists, if yes, overwrite it with new value | ||||
|         for (int i = 0; i < entries.size(); i++){ | ||||
|             ListMapEntry<K,V> entry = entries.get(i); | ||||
|             if (keyEq(entry.key, key)){ | ||||
|                 V prevValue = entry.value; | ||||
|                 entry.value = value; | ||||
|                 return prevValue; | ||||
|         if (backingMap.containsKey(key)){ | ||||
|             // set the value on the entry | ||||
|             int size = size(); | ||||
|             for (int i = 0; i < size; i++){ | ||||
|                 ListMapEntry<K, V> entry = entries[i]; | ||||
|                 if (keyEq(entry.key, key)){ | ||||
|                     entry.value = value; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|         }else{ | ||||
|             int size = size(); | ||||
|             // expand list as necessary | ||||
|             if (size == entries.length){ | ||||
|                 ListMapEntry<K, V>[] tmpEntries = entries; | ||||
|                 entries = new ListMapEntry[size * 2]; | ||||
|                 System.arraycopy(tmpEntries, 0, entries, 0, size); | ||||
|             } | ||||
|             entries[size] = new ListMapEntry<K, V>(key, value); | ||||
|         } | ||||
|          | ||||
|         // add a new entry | ||||
|         entries.add(new ListMapEntry<K, V>(key, value)); | ||||
|         return null; | ||||
|         return backingMap.put(key, value); | ||||
| //        if (key == null) | ||||
| //            throw new IllegalArgumentException(); | ||||
| // | ||||
| //        // check if entry exists, if yes, overwrite it with new value | ||||
| //        for (int i = 0; i < entries.size(); i++){ | ||||
| //            ListMapEntry<K,V> entry = entries.get(i); | ||||
| //            if (keyEq(entry.key, key)){ | ||||
| //                V prevValue = entry.value; | ||||
| //                entry.value = value; | ||||
| //                return prevValue; | ||||
| //            } | ||||
| //        } | ||||
| //         | ||||
| //        // add a new entry | ||||
| //        entries.add(new ListMapEntry<K, V>(key, value)); | ||||
| //        return null; | ||||
|     } | ||||
| 
 | ||||
|     public V remove(Object key) { | ||||
|         if (key == null) | ||||
|             throw new IllegalArgumentException(); | ||||
| 
 | ||||
|         for (int i = 0; i < entries.size(); i++){ | ||||
|             ListMapEntry<K,V> entry = entries.get(i); | ||||
|             if (keyEq(entry.key, key)){ | ||||
|                 return entries.remove(i).value; | ||||
|         V element = backingMap.remove( (K) key); | ||||
|         if (element != null){ | ||||
|             // find removed element | ||||
|             int size = size() + 1; // includes removed element | ||||
|             int removedIndex = -1; | ||||
|             for (int i = 0; i < size; i++){ | ||||
|                 ListMapEntry<K, V> entry = entries[i]; | ||||
|                 if (keyEq(entry.key, key)){ | ||||
|                     removedIndex = i; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|             assert removedIndex >= 0; | ||||
|              | ||||
|             size --; | ||||
|             for (int i = removedIndex; i < size; i++){ | ||||
|                 entries[i] = entries[i+1]; | ||||
|             } | ||||
|         } | ||||
|         return null; | ||||
|         return element; | ||||
| //        if (key == null) | ||||
| //            throw new IllegalArgumentException(); | ||||
| // | ||||
| //        for (int i = 0; i < entries.size(); i++){ | ||||
| //            ListMapEntry<K,V> entry = entries.get(i); | ||||
| //            if (keyEq(entry.key, key)){ | ||||
| //                return entries.remove(i).value; | ||||
| //            } | ||||
| //        } | ||||
| //        return null; | ||||
|     } | ||||
| 
 | ||||
|     public void putAll(Map<? extends K, ? extends V> map) { | ||||
|         if (map instanceof ListMap){ | ||||
|             ListMap<K, V> listMap = (ListMap<K, V>) map; | ||||
|             ArrayList<ListMapEntry<K, V>> otherEntries = listMap.entries; | ||||
|             for (int i = 0; i < otherEntries.size(); i++){ | ||||
|                 ListMapEntry<K, V> entry = otherEntries.get(i); | ||||
|                 put(entry.key, entry.value); | ||||
|             } | ||||
|         }else{ | ||||
|             for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()){ | ||||
|                 put(entry.getKey(), entry.getValue()); | ||||
|             } | ||||
|         for (Entry<? extends K, ? extends V> entry : map.entrySet()){ | ||||
|             put(entry.getKey(), entry.getValue()); | ||||
|         } | ||||
|          | ||||
|          | ||||
| //        if (map instanceof ListMap){ | ||||
| //            ListMap<K, V> listMap = (ListMap<K, V>) map; | ||||
| //            ArrayList<ListMapEntry<K, V>> otherEntries = listMap.entries; | ||||
| //            for (int i = 0; i < otherEntries.size(); i++){ | ||||
| //                ListMapEntry<K, V> entry = otherEntries.get(i); | ||||
| //                put(entry.key, entry.value); | ||||
| //            } | ||||
| //        }else{ | ||||
| //            for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()){ | ||||
| //                put(entry.getKey(), entry.getValue()); | ||||
| //            } | ||||
| //        } | ||||
|     } | ||||
| 
 | ||||
|     public void clear() { | ||||
|         entries.clear(); | ||||
|         backingMap.clear(); | ||||
| //        entries.clear(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
| @ -227,27 +288,30 @@ public final class ListMap<K, V> implements Map<K, V>, Cloneable, Serializable { | ||||
|     } | ||||
| 
 | ||||
|     public Set<K> keySet() { | ||||
|         HashSet<K> keys = new HashSet<K>(); | ||||
|         for (int i = 0; i < entries.size(); i++){ | ||||
|             ListMapEntry<K,V> entry = entries.get(i); | ||||
|             keys.add(entry.key); | ||||
|         } | ||||
|         return keys; | ||||
|         return backingMap.keySet(); | ||||
| //        HashSet<K> keys = new HashSet<K>(); | ||||
| //        for (int i = 0; i < entries.size(); i++){ | ||||
| //            ListMapEntry<K,V> entry = entries.get(i); | ||||
| //            keys.add(entry.key); | ||||
| //        } | ||||
| //        return keys; | ||||
|     } | ||||
| 
 | ||||
|     public Collection<V> values() { | ||||
|         ArrayList<V> values = new ArrayList<V>(); | ||||
|         for (int i = 0; i < entries.size(); i++){ | ||||
|             ListMapEntry<K,V> entry = entries.get(i); | ||||
|             values.add(entry.value); | ||||
|         } | ||||
|         return values; | ||||
|         return backingMap.values(); | ||||
| //        ArrayList<V> values = new ArrayList<V>(); | ||||
| //        for (int i = 0; i < entries.size(); i++){ | ||||
| //            ListMapEntry<K,V> entry = entries.get(i); | ||||
| //            values.add(entry.value); | ||||
| //        } | ||||
| //        return values; | ||||
|     } | ||||
| 
 | ||||
|     public Set<Entry<K, V>> entrySet() { | ||||
|         HashSet<Entry<K, V>> entryset = new HashSet<Entry<K, V>>(); | ||||
|         entryset.addAll(entries); | ||||
|         return entryset; | ||||
|         return backingMap.entrySet(); | ||||
| //        HashSet<Entry<K, V>> entryset = new HashSet<Entry<K, V>>(); | ||||
| //        entryset.addAll(entries); | ||||
| //        return entryset; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -47,6 +47,7 @@ import com.jme3.scene.Geometry; | ||||
| import com.jme3.scene.Mesh; | ||||
| import com.jme3.scene.Node; | ||||
| import com.jme3.scene.Spatial.CullHint; | ||||
| import com.jme3.scene.UserData; | ||||
| import com.jme3.scene.VertexBuffer; | ||||
| import com.jme3.scene.VertexBuffer.Format; | ||||
| import com.jme3.scene.VertexBuffer.Type; | ||||
| @ -101,28 +102,30 @@ public class MeshLoader extends DefaultHandler implements AssetLoader { | ||||
|     private String folderName; | ||||
|     private AssetManager assetManager; | ||||
|     private MaterialList materialList; | ||||
|      | ||||
|     // Data per submesh/sharedgeom | ||||
|     private ShortBuffer sb; | ||||
|     private IntBuffer ib; | ||||
|     private FloatBuffer fb; | ||||
|     private VertexBuffer vb; | ||||
|     private Mesh mesh; | ||||
|     private Geometry geom; | ||||
|     private Mesh sharedmesh; | ||||
|     private Geometry sharedgeom; | ||||
|     private int geomIdx = 0; | ||||
|     private int texCoordIdx = 0; | ||||
|     private static volatile int nodeIdx = 0; | ||||
|     private String ignoreUntilEnd = null; | ||||
|     private boolean bigindices = false; | ||||
|     private int vertCount; | ||||
|     private int triCount; | ||||
|     private List<Geometry> geoms = new ArrayList<Geometry>(); | ||||
|     private List<Boolean> usesSharedGeom = new ArrayList<Boolean>(); | ||||
|     private IntMap<List<VertexBuffer>> lodLevels = new IntMap<List<VertexBuffer>>(); | ||||
|     private AnimData animData; | ||||
|     private ByteBuffer indicesData; | ||||
|     private FloatBuffer weightsFloatData; | ||||
| 
 | ||||
|     private int vertCount; | ||||
|     private boolean usesSharedVerts; | ||||
|     private boolean usesBigIndices; | ||||
|      | ||||
|     // Global data | ||||
|     private Mesh sharedMesh; | ||||
|     private int meshIndex = 0; | ||||
|     private int texCoordIndex = 0; | ||||
|     private String ignoreUntilEnd = null; | ||||
|      | ||||
|     private List<Geometry> geoms = new ArrayList<Geometry>(); | ||||
|     private IntMap<List<VertexBuffer>> lodLevels = new IntMap<List<VertexBuffer>>(); | ||||
|     private AnimData animData; | ||||
|      | ||||
|     public MeshLoader() { | ||||
|         super(); | ||||
|     } | ||||
| @ -130,7 +133,6 @@ public class MeshLoader extends DefaultHandler implements AssetLoader { | ||||
|     @Override | ||||
|     public void startDocument() { | ||||
|         geoms.clear(); | ||||
|         usesSharedGeom.clear(); | ||||
|         lodLevels.clear(); | ||||
| 
 | ||||
|         sb = null; | ||||
| @ -139,14 +141,12 @@ public class MeshLoader extends DefaultHandler implements AssetLoader { | ||||
|         vb = null; | ||||
|         mesh = null; | ||||
|         geom = null; | ||||
|         sharedgeom = null; | ||||
|         sharedmesh = null; | ||||
|         sharedMesh = null; | ||||
| 
 | ||||
|         usesSharedVerts = false; | ||||
|         vertCount = 0; | ||||
|         triCount = 0; | ||||
|         geomIdx = 0; | ||||
|         texCoordIdx = 0; | ||||
|         nodeIdx = 0; | ||||
|         meshIndex = 0; | ||||
|         texCoordIndex = 0; | ||||
|         ignoreUntilEnd = null; | ||||
| 
 | ||||
|         animData = null; | ||||
| @ -171,28 +171,23 @@ public class MeshLoader extends DefaultHandler implements AssetLoader { | ||||
|             sb.put((short) i1).put((short) i2).put((short) i3); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     private boolean isUsingSharedVerts(Geometry geom){ | ||||
|         return geom.getUserData(UserData.JME_SHAREDMESH) != null; | ||||
|     } | ||||
| 
 | ||||
|     private void startFaces(String count) throws SAXException { | ||||
|         int numFaces = parseInt(count); | ||||
|         int numIndices; | ||||
| 
 | ||||
|         if (mesh.getMode() == Mesh.Mode.Triangles) { | ||||
|             //mesh.setTriangleCount(numFaces); | ||||
|             numIndices = numFaces * 3; | ||||
|         } else { | ||||
|             throw new SAXException("Triangle strip or fan not supported!"); | ||||
|         } | ||||
| 
 | ||||
|         int numVerts; | ||||
|         if (usesSharedGeom.size() > 0 && usesSharedGeom.get(geoms.size() - 1)) { | ||||
| //            sharedgeom.getMesh().updateCounts(); | ||||
|             numVerts = sharedmesh.getVertexCount(); | ||||
|         } else { | ||||
| //            mesh.updateCounts(); | ||||
|             numVerts = mesh.getVertexCount(); | ||||
|         } | ||||
|         vb = new VertexBuffer(VertexBuffer.Type.Index); | ||||
|         if (!bigindices) { | ||||
|         if (!usesBigIndices) { | ||||
|             sb = BufferUtils.createShortBuffer(numIndices); | ||||
|             ib = null; | ||||
|             vb.setupData(Usage.Static, 3, Format.UnsignedShort, sb); | ||||
| @ -226,16 +221,11 @@ public class MeshLoader extends DefaultHandler implements AssetLoader { | ||||
|         if (mat.isTransparent()) { | ||||
|             geom.setQueueBucket(Bucket.Transparent); | ||||
|         } | ||||
| //        else | ||||
| //            geom.setShadowMode(ShadowMode.CastAndReceive); | ||||
| 
 | ||||
| //        if (mat.isReceivesShadows()) | ||||
| 
 | ||||
| 
 | ||||
|          | ||||
|         geom.setMaterial(mat); | ||||
|     } | ||||
| 
 | ||||
|     private void startMesh(String matName, String usesharedvertices, String use32bitIndices, String opType) throws SAXException { | ||||
|     private void startSubMesh(String matName, String usesharedvertices, String use32bitIndices, String opType) throws SAXException { | ||||
|         mesh = new Mesh(); | ||||
|         if (opType == null || opType.equals("triangle_list")) { | ||||
|             mesh.setMode(Mesh.Mode.Triangles); | ||||
| @ -245,24 +235,25 @@ public class MeshLoader extends DefaultHandler implements AssetLoader { | ||||
|             mesh.setMode(Mesh.Mode.TriangleFan); | ||||
|         } | ||||
| 
 | ||||
|         bigindices = parseBool(use32bitIndices, false); | ||||
|         boolean sharedverts = parseBool(usesharedvertices, false); | ||||
|         if (sharedverts) { | ||||
|             usesSharedGeom.add(true); | ||||
|         usesBigIndices = parseBool(use32bitIndices, false); | ||||
|         usesSharedVerts = parseBool(usesharedvertices, false); | ||||
|         if (usesSharedVerts) { | ||||
|             // import vertexbuffers from shared geom | ||||
|             IntMap<VertexBuffer> sharedBufs = sharedmesh.getBuffers(); | ||||
|             IntMap<VertexBuffer> sharedBufs = sharedMesh.getBuffers(); | ||||
|             for (Entry<VertexBuffer> entry : sharedBufs) { | ||||
|                 mesh.setBuffer(entry.getValue()); | ||||
|             } | ||||
|             // this mesh is shared! | ||||
|         } else { | ||||
|             usesSharedGeom.add(false); | ||||
|         } | ||||
| 
 | ||||
|         if (meshName == null) { | ||||
|             geom = new Geometry("OgreSubmesh-" + (++geomIdx), mesh); | ||||
|             geom = new Geometry("OgreSubmesh-" + (++meshIndex), mesh); | ||||
|         } else { | ||||
|             geom = new Geometry(meshName + "-geom-" + (++geomIdx), mesh); | ||||
|             geom = new Geometry(meshName + "-geom-" + (++meshIndex), mesh); | ||||
|         } | ||||
|          | ||||
|         if (usesSharedVerts){ | ||||
|             // this mesh is shared! | ||||
|             geom.setUserData(UserData.JME_SHAREDMESH, sharedMesh); | ||||
|         } | ||||
| 
 | ||||
|         applyMaterial(geom, matName); | ||||
| @ -270,27 +261,16 @@ public class MeshLoader extends DefaultHandler implements AssetLoader { | ||||
|     } | ||||
| 
 | ||||
|     private void startSharedGeom(String vertexcount) throws SAXException { | ||||
|         sharedmesh = new Mesh(); | ||||
|         sharedMesh = new Mesh(); | ||||
|         vertCount = parseInt(vertexcount); | ||||
| //        sharedmesh.setVertexCount(vertCount); | ||||
|         usesSharedVerts = false; | ||||
| 
 | ||||
|         if (meshName == null) { | ||||
|             sharedgeom = new Geometry("Ogre-SharedGeom", sharedmesh); | ||||
|         } else { | ||||
|             sharedgeom = new Geometry(meshName + "-sharedgeom", sharedmesh); | ||||
|         } | ||||
| 
 | ||||
|         sharedgeom.setCullHint(CullHint.Always); | ||||
|         geoms.add(sharedgeom); | ||||
|         usesSharedGeom.add(false); // shared geometry doesnt use shared geometry (?) | ||||
| 
 | ||||
|         geom = sharedgeom; | ||||
|         mesh = sharedmesh; | ||||
|         geom = null; | ||||
|         mesh = sharedMesh; | ||||
|     } | ||||
| 
 | ||||
|     private void startGeometry(String vertexcount) throws SAXException { | ||||
|         vertCount = parseInt(vertexcount); | ||||
| //        mesh.setVertexCount(vertCount); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -298,7 +278,7 @@ public class MeshLoader extends DefaultHandler implements AssetLoader { | ||||
|      * for all vertices in the buffer. | ||||
|      */ | ||||
|     private void endBoneAssigns() { | ||||
|         if (mesh != sharedmesh && usesSharedGeom.get(geoms.size() - 1)) { | ||||
|         if (mesh != sharedMesh && isUsingSharedVerts(geom)) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
| @ -341,7 +321,7 @@ public class MeshLoader extends DefaultHandler implements AssetLoader { | ||||
|     } | ||||
| 
 | ||||
|     private void startBoneAssigns() { | ||||
|         if (mesh != sharedmesh && usesSharedGeom.get(geoms.size() - 1)) { | ||||
|         if (mesh != sharedMesh && usesSharedVerts) { | ||||
|             // will use bone assignments from shared mesh (?) | ||||
|             return; | ||||
|         } | ||||
| @ -424,7 +404,7 @@ public class MeshLoader extends DefaultHandler implements AssetLoader { | ||||
|     } | ||||
| 
 | ||||
|     private void startVertex() { | ||||
|         texCoordIdx = 0; | ||||
|         texCoordIndex = 0; | ||||
|     } | ||||
| 
 | ||||
|     private void pushAttrib(Type type, Attributes attribs) throws SAXException { | ||||
| @ -450,10 +430,10 @@ public class MeshLoader extends DefaultHandler implements AssetLoader { | ||||
|     } | ||||
| 
 | ||||
|     private void pushTexCoord(Attributes attribs) throws SAXException { | ||||
|         if (texCoordIdx >= 8) { | ||||
|         if (texCoordIndex >= 8) { | ||||
|             return; // More than 8 not supported by ogre. | ||||
|         } | ||||
|         Type type = TEXCOORD_TYPES[texCoordIdx]; | ||||
|         Type type = TEXCOORD_TYPES[texCoordIndex]; | ||||
| 
 | ||||
|         VertexBuffer tcvb = mesh.getBuffer(type); | ||||
|         FloatBuffer buf = (FloatBuffer) tcvb.getData(); | ||||
| @ -469,7 +449,7 @@ public class MeshLoader extends DefaultHandler implements AssetLoader { | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         texCoordIdx++; | ||||
|         texCoordIndex++; | ||||
|     } | ||||
| 
 | ||||
|     private void pushColor(Attributes attribs) throws SAXException { | ||||
| @ -529,7 +509,6 @@ public class MeshLoader extends DefaultHandler implements AssetLoader { | ||||
|     } | ||||
| 
 | ||||
|     private void startLodGenerated(String depthsqr) { | ||||
| //        dist = Float.parseFloat(depthsqr); | ||||
|     } | ||||
| 
 | ||||
|     private void pushBoneAssign(String vertIndex, String boneIndex, String weight) throws SAXException { | ||||
| @ -560,10 +539,6 @@ public class MeshLoader extends DefaultHandler implements AssetLoader { | ||||
| 
 | ||||
|     private void startSkeleton(String name) { | ||||
|         animData = (AnimData) assetManager.loadAsset(folderName + name + ".xml"); | ||||
|         //TODO:workaround for meshxml / mesh.xml | ||||
|         if (animData == null) { | ||||
|             animData = (AnimData) assetManager.loadAsset(folderName + name + "xml"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private void startSubmeshName(String indexStr, String nameStr) { | ||||
| @ -620,7 +595,7 @@ public class MeshLoader extends DefaultHandler implements AssetLoader { | ||||
|         } else if (qName.equals("boneassignments")) { | ||||
|             startBoneAssigns(); | ||||
|         } else if (qName.equals("submesh")) { | ||||
|             startMesh(attribs.getValue("material"), | ||||
|             startSubMesh(attribs.getValue("material"), | ||||
|                     attribs.getValue("usesharedvertices"), | ||||
|                     attribs.getValue("use32bitindexes"), | ||||
|                     attribs.getValue("operationtype")); | ||||
| @ -653,18 +628,18 @@ public class MeshLoader extends DefaultHandler implements AssetLoader { | ||||
|             if (ignoreUntilEnd.equals(qName)) { | ||||
|                 ignoreUntilEnd = null; | ||||
|             } | ||||
| 
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         if (qName.equals("submesh")) { | ||||
|             bigindices = false; | ||||
|             usesBigIndices = false; | ||||
|             geom = null; | ||||
|             mesh = null; | ||||
|         } else if (qName.equals("submeshes")) { | ||||
|             // IMPORTANT: restore sharedgeoemtry, for use with shared boneweights | ||||
|             geom = sharedgeom; | ||||
|             mesh = sharedmesh; | ||||
|             // IMPORTANT: restore sharedmesh, for use with shared boneweights | ||||
|             geom = null; | ||||
|             mesh = sharedMesh; | ||||
|             usesSharedVerts = false; | ||||
|         } else if (qName.equals("faces")) { | ||||
|             if (ib != null) { | ||||
|                 ib.flip(); | ||||
| @ -711,80 +686,82 @@ public class MeshLoader extends DefaultHandler implements AssetLoader { | ||||
|     } | ||||
| 
 | ||||
|     private Node compileModel() { | ||||
|         String nodeName; | ||||
|         if (meshName == null) { | ||||
|             nodeName = "OgreMesh" + (++nodeIdx); | ||||
|         } else { | ||||
|             nodeName = meshName + "-ogremesh"; | ||||
|         Node model = new Node(meshName + "-ogremesh"); | ||||
|          | ||||
|         for (int i = 0; i < geoms.size(); i++) { | ||||
|             Geometry g = geoms.get(i); | ||||
|             Mesh m = g.getMesh(); | ||||
|             if (sharedMesh != null && isUsingSharedVerts(geom)) { | ||||
|                 m.setBound(sharedMesh.getBound().clone()); | ||||
|             } | ||||
|             model.attachChild(geoms.get(i)); | ||||
|         } | ||||
| 
 | ||||
|         Node model = new Node(nodeName); | ||||
|          | ||||
|         // Do not attach shared geometry to the node! | ||||
|          | ||||
|         if (animData != null) { | ||||
|             ArrayList<Mesh> newMeshes = new ArrayList<Mesh>(geoms.size()); | ||||
| 
 | ||||
|             // generate bind pose for mesh and add to skin-list | ||||
|             // This model uses animation | ||||
|              | ||||
|             // generate bind pose for mesh | ||||
|             // ONLY if not using shared geometry | ||||
|             // This includes the shared geoemtry itself actually | ||||
|             if (sharedMesh != null){ | ||||
|                 sharedMesh.generateBindPose(!HARDWARE_SKINNING); | ||||
|             } | ||||
|              | ||||
|             for (int i = 0; i < geoms.size(); i++) { | ||||
|                 Geometry g = geoms.get(i); | ||||
|                 Mesh m = geoms.get(i).getMesh(); | ||||
|                 boolean useShared = usesSharedGeom.get(i); | ||||
|                 // create bind pose | ||||
|                 boolean useShared = isUsingSharedVerts(g);  | ||||
|                  | ||||
|                  | ||||
|                 if (!useShared) { | ||||
|                     // create bind pose | ||||
|                     m.generateBindPose(!HARDWARE_SKINNING); | ||||
|                     newMeshes.add(m); | ||||
|                 } else { | ||||
|                     VertexBuffer bindPos = sharedmesh.getBuffer(Type.BindPosePosition); | ||||
|                     VertexBuffer bindNorm = sharedmesh.getBuffer(Type.BindPoseNormal); | ||||
|                     VertexBuffer boneIndex = sharedmesh.getBuffer(Type.BoneIndex); | ||||
|                     VertexBuffer boneWeight = sharedmesh.getBuffer(Type.BoneWeight); | ||||
| 
 | ||||
|                     if (bindPos != null) { | ||||
|                         m.setBuffer(bindPos); | ||||
|                     } | ||||
| 
 | ||||
|                     if (bindNorm != null) { | ||||
|                         m.setBuffer(bindNorm); | ||||
|                     } | ||||
| 
 | ||||
|                     if (boneIndex != null) { | ||||
|                         m.setBuffer(boneIndex); | ||||
|                     } | ||||
| 
 | ||||
|                     if (boneWeight != null) { | ||||
|                         m.setBuffer(boneWeight); | ||||
|                     } | ||||
| //                } else { | ||||
|                     // Inherit animation data from shared mesh | ||||
| //                    VertexBuffer bindPos = sharedMesh.getBuffer(Type.BindPosePosition); | ||||
| //                    VertexBuffer bindNorm = sharedMesh.getBuffer(Type.BindPoseNormal); | ||||
| //                    VertexBuffer boneIndex = sharedMesh.getBuffer(Type.BoneIndex); | ||||
| //                    VertexBuffer boneWeight = sharedMesh.getBuffer(Type.BoneWeight); | ||||
| // | ||||
| //                    if (bindPos != null) { | ||||
| //                        m.setBuffer(bindPos); | ||||
| //                    } | ||||
| // | ||||
| //                    if (bindNorm != null) { | ||||
| //                        m.setBuffer(bindNorm); | ||||
| //                    } | ||||
| // | ||||
| //                    if (boneIndex != null) { | ||||
| //                        m.setBuffer(boneIndex); | ||||
| //                    } | ||||
| // | ||||
| //                    if (boneWeight != null) { | ||||
| //                        m.setBuffer(boneWeight); | ||||
| //                    } | ||||
|                 } | ||||
|             } | ||||
|             Mesh[] meshes = new Mesh[newMeshes.size()]; | ||||
|             for (int i = 0; i < meshes.length; i++) { | ||||
|                 meshes[i] = newMeshes.get(i); | ||||
|             } | ||||
| 
 | ||||
|              | ||||
|             // Put the animations in the AnimControl | ||||
|             HashMap<String, BoneAnimation> anims = new HashMap<String, BoneAnimation>(); | ||||
|             ArrayList<BoneAnimation> animList = animData.anims; | ||||
|             for (int i = 0; i < animList.size(); i++) { | ||||
|                 BoneAnimation anim = animList.get(i); | ||||
|                 anims.put(anim.getName(), anim); | ||||
|             } | ||||
| 
 | ||||
|             //AnimControl ctrl = new AnimControl(model, meshes, animData.skeleton);             | ||||
|             | ||||
|             AnimControl ctrl = new AnimControl(animData.skeleton); | ||||
|             ctrl.setAnimations(anims); | ||||
|             model.addControl(ctrl); | ||||
|             SkeletonControl skeletonControl = new SkeletonControl(meshes, animData.skeleton); | ||||
|              | ||||
|             // Put the skeleton in the skeleton control | ||||
|             SkeletonControl skeletonControl = new SkeletonControl(animData.skeleton); | ||||
|              | ||||
|             // This will acquire the targets from the node | ||||
|             model.addControl(skeletonControl); | ||||
|         } | ||||
| 
 | ||||
|         for (int i = 0; i < geoms.size(); i++) { | ||||
|             Geometry g = geoms.get(i); | ||||
|             Mesh m = g.getMesh(); | ||||
|             if (sharedmesh != null && usesSharedGeom.get(i)) { | ||||
|                 m.setBound(sharedmesh.getBound().clone()); | ||||
|             } | ||||
|             model.attachChild(geoms.get(i)); | ||||
|         } | ||||
| 
 | ||||
|         return model; | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -270,7 +270,7 @@ public class TestHoveringTank extends SimpleApplication implements AnalogListene | ||||
|         rock.setWrap(WrapMode.Repeat); | ||||
|         matRock.setTexture("DiffuseMap_2", rock); | ||||
|         matRock.setFloat("DiffuseMap_2_scale", 128); | ||||
|         Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.png"); | ||||
|         Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg"); | ||||
|         normalMap0.setWrap(WrapMode.Repeat); | ||||
|         Texture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png"); | ||||
|         normalMap1.setWrap(WrapMode.Repeat); | ||||
|  | ||||
| @ -34,7 +34,7 @@ package com.jme3.export.xml; | ||||
| 
 | ||||
| import com.jme3.export.InputCapsule; | ||||
| import com.jme3.export.Savable; | ||||
| import com.jme3.export.SavableClassFinder; | ||||
| import com.jme3.export.SavableClassUtil; | ||||
| import com.jme3.util.BufferUtils; | ||||
| import com.jme3.util.IntMap; | ||||
| import java.io.IOException; | ||||
| @ -78,6 +78,10 @@ public class DOMInputCapsule implements InputCapsule { | ||||
|         currentElem = doc.getDocumentElement(); | ||||
|     } | ||||
| 
 | ||||
|     public int getSavableVersion(Class<? extends Savable> clazz) { | ||||
|         return 0; // TODO: figure this out ... | ||||
|     } | ||||
|      | ||||
|     private static String decodeString(String s) { | ||||
|         if (s == null) { | ||||
|             return null; | ||||
| @ -973,7 +977,7 @@ public class DOMInputCapsule implements InputCapsule { | ||||
|             } else if (currentElem.hasAttribute("class")) { | ||||
|                 className = currentElem.getAttribute("class"); | ||||
|             } | ||||
|             tmp = SavableClassFinder.fromName(className, null); | ||||
|             tmp = SavableClassUtil.fromName(className, null); | ||||
|             String refID = currentElem.getAttribute("reference_ID"); | ||||
|             if (refID.length() < 1) refID = currentElem.getAttribute("id"); | ||||
|             if (refID.length() > 0) referencedSavables.put(refID, tmp); | ||||
|  | ||||
| @ -52,11 +52,15 @@ public class XMLImporter implements JmeImporter { | ||||
| 
 | ||||
|     private AssetManager assetManager; | ||||
|     private DOMInputCapsule domIn; | ||||
|     // A single-load-state base URI for texture-loading. | ||||
|      | ||||
|     public XMLImporter() { | ||||
|     } | ||||
| 
 | ||||
| // TODO: ....... | ||||
|     public int getFormatVersion() { | ||||
|         return 0; | ||||
|     } | ||||
|      | ||||
|     public AssetManager getAssetManager(){ | ||||
|         return assetManager; | ||||
|     } | ||||
| @ -73,10 +77,7 @@ public class XMLImporter implements JmeImporter { | ||||
|         return obj; | ||||
|     } | ||||
| 
 | ||||
|     synchronized public Savable load(InputStream f) throws IOException { | ||||
|         /* Leave this method synchronized.  Calling this method from more than | ||||
|          * one thread at a time for the same XMLImporter instance will clobber | ||||
|          * the XML Document instantiated here. */ | ||||
|     public Savable load(InputStream f) throws IOException { | ||||
|         try { | ||||
|             domIn = new DOMInputCapsule(DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(f), this); | ||||
|             return domIn.readSavable(null, null); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user