1/* 2 * Copyright (c) 2009-2012 jMonkeyEngine 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32package com.jme3.asset; 33 34import com.jme3.bounding.BoundingVolume; 35import com.jme3.collision.Collidable; 36import com.jme3.collision.CollisionResults; 37import com.jme3.collision.UnsupportedCollisionException; 38import com.jme3.export.InputCapsule; 39import com.jme3.export.JmeExporter; 40import com.jme3.export.JmeImporter; 41import com.jme3.export.OutputCapsule; 42import com.jme3.light.AmbientLight; 43import com.jme3.light.Light; 44import com.jme3.material.Material; 45import com.jme3.material.RenderState.FaceCullMode; 46import com.jme3.renderer.Camera; 47import com.jme3.scene.Node; 48import com.jme3.scene.SceneGraphVisitor; 49import com.jme3.scene.Spatial; 50import com.jme3.scene.plugins.ogre.AnimData; 51import com.jme3.texture.Texture; 52import java.io.IOException; 53import java.util.ArrayList; 54import java.util.List; 55import java.util.Queue; 56 57/** 58 * Blender key. Contains path of the blender file and its loading properties. 59 * @author Marcin Roguski (Kaelthas) 60 */ 61public class BlenderKey extends ModelKey { 62 63 protected static final int DEFAULT_FPS = 25; 64 /** 65 * FramesPerSecond parameter describe how many frames there are in each second. It allows to calculate the time 66 * between the frames. 67 */ 68 protected int fps = DEFAULT_FPS; 69 /** Width of generated textures (in pixels). */ 70 protected int generatedTextureWidth = 60; 71 /** Height of generated textures (in pixels). */ 72 protected int generatedTextureHeight = 60; 73 /** Depth of generated textures (in pixels). */ 74 protected int generatedTextureDepth = 60; 75 /** 76 * This variable is a bitwise flag of FeatureToLoad interface values; By default everything is being loaded. 77 */ 78 protected int featuresToLoad = FeaturesToLoad.ALL; 79 /** This variable determines if assets that are not linked to the objects should be loaded. */ 80 protected boolean loadUnlinkedAssets; 81 /** The root path for all the assets. */ 82 protected String assetRootPath; 83 /** This variable indicate if Y axis is UP axis. If not then Z is up. By default set to true. */ 84 protected boolean fixUpAxis = true; 85 /** 86 * The name of world settings that the importer will use. If not set or specified name does not occur in the file 87 * then the first world settings in the file will be used. 88 */ 89 protected String usedWorld; 90 /** 91 * User's default material that is set fo objects that have no material definition in blender. The default value is 92 * null. If the value is null the importer will use its own default material (gray color - like in blender). 93 */ 94 protected Material defaultMaterial; 95 /** Face cull mode. By default it is disabled. */ 96 protected FaceCullMode faceCullMode = FaceCullMode.Off; 97 /** 98 * Variable describes which layers will be loaded. N-th bit set means N-th layer will be loaded. 99 * If set to -1 then the current layer will be loaded. 100 */ 101 protected int layersToLoad = -1; 102 103 /** 104 * Constructor used by serialization mechanisms. 105 */ 106 public BlenderKey() {} 107 108 /** 109 * Constructor. Creates a key for the given file name. 110 * @param name 111 * the name (path) of a file 112 */ 113 public BlenderKey(String name) { 114 super(name); 115 } 116 117 /** 118 * This method returns frames per second amount. The default value is BlenderKey.DEFAULT_FPS = 25. 119 * @return the frames per second amount 120 */ 121 public int getFps() { 122 return fps; 123 } 124 125 /** 126 * This method sets frames per second amount. 127 * @param fps 128 * the frames per second amount 129 */ 130 public void setFps(int fps) { 131 this.fps = fps; 132 } 133 134 /** 135 * This method sets the width of generated texture (in pixels). By default the value is 140 px. 136 * @param generatedTextureWidth 137 * the width of generated texture 138 */ 139 public void setGeneratedTextureWidth(int generatedTextureWidth) { 140 this.generatedTextureWidth = generatedTextureWidth; 141 } 142 143 /** 144 * This method returns the width of generated texture (in pixels). By default the value is 140 px. 145 * @return the width of generated texture 146 */ 147 public int getGeneratedTextureWidth() { 148 return generatedTextureWidth; 149 } 150 151 /** 152 * This method sets the height of generated texture (in pixels). By default the value is 20 px. 153 * @param generatedTextureHeight 154 * the height of generated texture 155 */ 156 public void setGeneratedTextureHeight(int generatedTextureHeight) { 157 this.generatedTextureHeight = generatedTextureHeight; 158 } 159 160 /** 161 * This method returns the height of generated texture (in pixels). By default the value is 20 px. 162 * @return the height of generated texture 163 */ 164 public int getGeneratedTextureHeight() { 165 return generatedTextureHeight; 166 } 167 168 /** 169 * This method sets the depth of generated texture (in pixels). By default the value is 20 px. 170 * @param generatedTextureDepth 171 * the depth of generated texture 172 */ 173 public void setGeneratedTextureDepth(int generatedTextureDepth) { 174 this.generatedTextureDepth = generatedTextureDepth; 175 } 176 177 /** 178 * This method returns the depth of generated texture (in pixels). By default the value is 20 px. 179 * @return the depth of generated texture 180 */ 181 public int getGeneratedTextureDepth() { 182 return generatedTextureDepth; 183 } 184 185 /** 186 * This method returns the face cull mode. 187 * @return the face cull mode 188 */ 189 public FaceCullMode getFaceCullMode() { 190 return faceCullMode; 191 } 192 193 /** 194 * This method sets the face cull mode. 195 * @param faceCullMode 196 * the face cull mode 197 */ 198 public void setFaceCullMode(FaceCullMode faceCullMode) { 199 this.faceCullMode = faceCullMode; 200 } 201 202 /** 203 * This method sets layers to be loaded. 204 * @param layersToLoad 205 * layers to be loaded 206 */ 207 public void setLayersToLoad(int layersToLoad) { 208 this.layersToLoad = layersToLoad; 209 } 210 211 /** 212 * This method returns layers to be loaded. 213 * @return layers to be loaded 214 */ 215 public int getLayersToLoad() { 216 return layersToLoad; 217 } 218 219 /** 220 * This method sets the asset root path. 221 * @param assetRootPath 222 * the assets root path 223 */ 224 public void setAssetRootPath(String assetRootPath) { 225 this.assetRootPath = assetRootPath; 226 } 227 228 /** 229 * This method returns the asset root path. 230 * @return the asset root path 231 */ 232 public String getAssetRootPath() { 233 return assetRootPath; 234 } 235 236 /** 237 * This method adds features to be loaded. 238 * @param featuresToLoad 239 * bitwise flag of FeaturesToLoad interface values 240 */ 241 public void includeInLoading(int featuresToLoad) { 242 this.featuresToLoad |= featuresToLoad; 243 } 244 245 /** 246 * This method removes features from being loaded. 247 * @param featuresNotToLoad 248 * bitwise flag of FeaturesToLoad interface values 249 */ 250 public void excludeFromLoading(int featuresNotToLoad) { 251 this.featuresToLoad &= ~featuresNotToLoad; 252 } 253 254 /** 255 * This method returns bitwise value of FeaturesToLoad interface value. It describes features that will be loaded by 256 * the blender file loader. 257 * @return features that will be loaded by the blender file loader 258 */ 259 public int getFeaturesToLoad() { 260 return featuresToLoad; 261 } 262 263 /** 264 * This method determines if unlinked assets should be loaded. 265 * If not then only objects on selected layers will be loaded and their assets if required. 266 * If yes then all assets will be loaded even if they are on inactive layers or are not linked 267 * to anything. 268 * @return <b>true</b> if unlinked assets should be loaded and <b>false</b> otherwise 269 */ 270 public boolean isLoadUnlinkedAssets() { 271 return loadUnlinkedAssets; 272 } 273 274 /** 275 * This method sets if unlinked assets should be loaded. 276 * If not then only objects on selected layers will be loaded and their assets if required. 277 * If yes then all assets will be loaded even if they are on inactive layers or are not linked 278 * to anything. 279 * @param loadUnlinkedAssets 280 * <b>true</b> if unlinked assets should be loaded and <b>false</b> otherwise 281 */ 282 public void setLoadUnlinkedAssets(boolean loadUnlinkedAssets) { 283 this.loadUnlinkedAssets = loadUnlinkedAssets; 284 } 285 286 /** 287 * This method creates an object where loading results will be stores. Only those features will be allowed to store 288 * that were specified by features-to-load flag. 289 * @return an object to store loading results 290 */ 291 public LoadingResults prepareLoadingResults() { 292 return new LoadingResults(featuresToLoad); 293 } 294 295 /** 296 * This method sets the fix up axis state. If set to true then Y is up axis. Otherwise the up i Z axis. By default Y 297 * is up axis. 298 * @param fixUpAxis 299 * the up axis state variable 300 */ 301 public void setFixUpAxis(boolean fixUpAxis) { 302 this.fixUpAxis = fixUpAxis; 303 } 304 305 /** 306 * This method returns the fix up axis state. If set to true then Y is up axis. Otherwise the up i Z axis. By 307 * default Y is up axis. 308 * @return the up axis state variable 309 */ 310 public boolean isFixUpAxis() { 311 return fixUpAxis; 312 } 313 314 /** 315 * This mehtod sets the name of the WORLD data block taht should be used during file loading. By default the name is 316 * not set. If no name is set or the given name does not occur in the file - the first WORLD data block will be used 317 * during loading (assumin any exists in the file). 318 * @param usedWorld 319 * the name of the WORLD block used during loading 320 */ 321 public void setUsedWorld(String usedWorld) { 322 this.usedWorld = usedWorld; 323 } 324 325 /** 326 * This mehtod returns the name of the WORLD data block taht should be used during file loading. 327 * @return the name of the WORLD block used during loading 328 */ 329 public String getUsedWorld() { 330 return usedWorld; 331 } 332 333 /** 334 * This method sets the default material for objects. 335 * @param defaultMaterial 336 * the default material 337 */ 338 public void setDefaultMaterial(Material defaultMaterial) { 339 this.defaultMaterial = defaultMaterial; 340 } 341 342 /** 343 * This method returns the default material. 344 * @return the default material 345 */ 346 public Material getDefaultMaterial() { 347 return defaultMaterial; 348 } 349 350 @Override 351 public void write(JmeExporter e) throws IOException { 352 super.write(e); 353 OutputCapsule oc = e.getCapsule(this); 354 oc.write(fps, "fps", DEFAULT_FPS); 355 oc.write(generatedTextureWidth, "generated-texture-width", 20); 356 oc.write(generatedTextureHeight, "generated-texture-height", 20); 357 oc.write(generatedTextureDepth, "generated-texture-depth", 20); 358 oc.write(featuresToLoad, "features-to-load", FeaturesToLoad.ALL); 359 oc.write(loadUnlinkedAssets, "load-unlinked-assets", false); 360 oc.write(assetRootPath, "asset-root-path", null); 361 oc.write(fixUpAxis, "fix-up-axis", true); 362 oc.write(usedWorld, "used-world", null); 363 oc.write(defaultMaterial, "default-material", null); 364 oc.write(faceCullMode, "face-cull-mode", FaceCullMode.Off); 365 oc.write(layersToLoad, "layers-to-load", -1); 366 } 367 368 @Override 369 public void read(JmeImporter e) throws IOException { 370 super.read(e); 371 InputCapsule ic = e.getCapsule(this); 372 fps = ic.readInt("fps", DEFAULT_FPS); 373 generatedTextureWidth = ic.readInt("generated-texture-width", 20); 374 generatedTextureHeight = ic.readInt("generated-texture-height", 20); 375 generatedTextureDepth = ic.readInt("generated-texture-depth", 20); 376 featuresToLoad = ic.readInt("features-to-load", FeaturesToLoad.ALL); 377 loadUnlinkedAssets = ic.readBoolean("load-unlinked-assets", false); 378 assetRootPath = ic.readString("asset-root-path", null); 379 fixUpAxis = ic.readBoolean("fix-up-axis", true); 380 usedWorld = ic.readString("used-world", null); 381 defaultMaterial = (Material) ic.readSavable("default-material", null); 382 faceCullMode = ic.readEnum("face-cull-mode", FaceCullMode.class, FaceCullMode.Off); 383 layersToLoad = ic.readInt("layers-to=load", -1); 384 } 385 386 @Override 387 public int hashCode() { 388 final int prime = 31; 389 int result = super.hashCode(); 390 result = prime * result + (assetRootPath == null ? 0 : assetRootPath.hashCode()); 391 result = prime * result + (defaultMaterial == null ? 0 : defaultMaterial.hashCode()); 392 result = prime * result + (faceCullMode == null ? 0 : faceCullMode.hashCode()); 393 result = prime * result + featuresToLoad; 394 result = prime * result + (fixUpAxis ? 1231 : 1237); 395 result = prime * result + fps; 396 result = prime * result + generatedTextureDepth; 397 result = prime * result + generatedTextureHeight; 398 result = prime * result + generatedTextureWidth; 399 result = prime * result + layersToLoad; 400 result = prime * result + (loadUnlinkedAssets ? 1231 : 1237); 401 result = prime * result + (usedWorld == null ? 0 : usedWorld.hashCode()); 402 return result; 403 } 404 405 @Override 406 public boolean equals(Object obj) { 407 if (this == obj) { 408 return true; 409 } 410 if (!super.equals(obj)) { 411 return false; 412 } 413 if (this.getClass() != obj.getClass()) { 414 return false; 415 } 416 BlenderKey other = (BlenderKey) obj; 417 if (assetRootPath == null) { 418 if (other.assetRootPath != null) { 419 return false; 420 } 421 } else if (!assetRootPath.equals(other.assetRootPath)) { 422 return false; 423 } 424 if (defaultMaterial == null) { 425 if (other.defaultMaterial != null) { 426 return false; 427 } 428 } else if (!defaultMaterial.equals(other.defaultMaterial)) { 429 return false; 430 } 431 if (faceCullMode != other.faceCullMode) { 432 return false; 433 } 434 if (featuresToLoad != other.featuresToLoad) { 435 return false; 436 } 437 if (fixUpAxis != other.fixUpAxis) { 438 return false; 439 } 440 if (fps != other.fps) { 441 return false; 442 } 443 if (generatedTextureDepth != other.generatedTextureDepth) { 444 return false; 445 } 446 if (generatedTextureHeight != other.generatedTextureHeight) { 447 return false; 448 } 449 if (generatedTextureWidth != other.generatedTextureWidth) { 450 return false; 451 } 452 if (layersToLoad != other.layersToLoad) { 453 return false; 454 } 455 if (loadUnlinkedAssets != other.loadUnlinkedAssets) { 456 return false; 457 } 458 if (usedWorld == null) { 459 if (other.usedWorld != null) { 460 return false; 461 } 462 } else if (!usedWorld.equals(other.usedWorld)) { 463 return false; 464 } 465 return true; 466 } 467 468 /** 469 * This interface describes the features of the scene that are to be loaded. 470 * @author Marcin Roguski (Kaelthas) 471 */ 472 public static interface FeaturesToLoad { 473 474 int SCENES = 0x0000FFFF; 475 int OBJECTS = 0x0000000B; 476 int ANIMATIONS = 0x00000004; 477 int MATERIALS = 0x00000003; 478 int TEXTURES = 0x00000001; 479 int CAMERAS = 0x00000020; 480 int LIGHTS = 0x00000010; 481 int ALL = 0xFFFFFFFF; 482 } 483 484 /** 485 * This class holds the loading results according to the given loading flag. 486 * @author Marcin Roguski (Kaelthas) 487 */ 488 public static class LoadingResults extends Spatial { 489 490 /** Bitwise mask of features that are to be loaded. */ 491 private final int featuresToLoad; 492 /** The scenes from the file. */ 493 private List<Node> scenes; 494 /** Objects from all scenes. */ 495 private List<Node> objects; 496 /** Materials from all objects. */ 497 private List<Material> materials; 498 /** Textures from all objects. */ 499 private List<Texture> textures; 500 /** Animations of all objects. */ 501 private List<AnimData> animations; 502 /** All cameras from the file. */ 503 private List<Camera> cameras; 504 /** All lights from the file. */ 505 private List<Light> lights; 506 507 /** 508 * Private constructor prevents users to create an instance of this class from outside the 509 * @param featuresToLoad 510 * bitwise mask of features that are to be loaded 511 * @see FeaturesToLoad FeaturesToLoad 512 */ 513 private LoadingResults(int featuresToLoad) { 514 this.featuresToLoad = featuresToLoad; 515 if ((featuresToLoad & FeaturesToLoad.SCENES) != 0) { 516 scenes = new ArrayList<Node>(); 517 } 518 if ((featuresToLoad & FeaturesToLoad.OBJECTS) != 0) { 519 objects = new ArrayList<Node>(); 520 if ((featuresToLoad & FeaturesToLoad.MATERIALS) != 0) { 521 materials = new ArrayList<Material>(); 522 if ((featuresToLoad & FeaturesToLoad.TEXTURES) != 0) { 523 textures = new ArrayList<Texture>(); 524 } 525 } 526 if ((featuresToLoad & FeaturesToLoad.ANIMATIONS) != 0) { 527 animations = new ArrayList<AnimData>(); 528 } 529 } 530 if ((featuresToLoad & FeaturesToLoad.CAMERAS) != 0) { 531 cameras = new ArrayList<Camera>(); 532 } 533 if ((featuresToLoad & FeaturesToLoad.LIGHTS) != 0) { 534 lights = new ArrayList<Light>(); 535 } 536 } 537 538 /** 539 * This method returns a bitwise flag describing what features of the blend file will be included in the result. 540 * @return bitwise mask of features that are to be loaded 541 * @see FeaturesToLoad FeaturesToLoad 542 */ 543 public int getLoadedFeatures() { 544 return featuresToLoad; 545 } 546 547 /** 548 * This method adds a scene to the result set. 549 * @param scene 550 * scene to be added to the result set 551 */ 552 public void addScene(Node scene) { 553 if (scenes != null) { 554 scenes.add(scene); 555 } 556 } 557 558 /** 559 * This method adds an object to the result set. 560 * @param object 561 * object to be added to the result set 562 */ 563 public void addObject(Node object) { 564 if (objects != null) { 565 objects.add(object); 566 } 567 } 568 569 /** 570 * This method adds a material to the result set. 571 * @param material 572 * material to be added to the result set 573 */ 574 public void addMaterial(Material material) { 575 if (materials != null) { 576 materials.add(material); 577 } 578 } 579 580 /** 581 * This method adds a texture to the result set. 582 * @param texture 583 * texture to be added to the result set 584 */ 585 public void addTexture(Texture texture) { 586 if (textures != null) { 587 textures.add(texture); 588 } 589 } 590 591 /** 592 * This method adds a camera to the result set. 593 * @param camera 594 * camera to be added to the result set 595 */ 596 public void addCamera(Camera camera) { 597 if (cameras != null) { 598 cameras.add(camera); 599 } 600 } 601 602 /** 603 * This method adds a light to the result set. 604 * @param light 605 * light to be added to the result set 606 */ 607 @Override 608 public void addLight(Light light) { 609 if (lights != null) { 610 lights.add(light); 611 } 612 } 613 614 /** 615 * This method returns all loaded scenes. 616 * @return all loaded scenes 617 */ 618 public List<Node> getScenes() { 619 return scenes; 620 } 621 622 /** 623 * This method returns all loaded objects. 624 * @return all loaded objects 625 */ 626 public List<Node> getObjects() { 627 return objects; 628 } 629 630 /** 631 * This method returns all loaded materials. 632 * @return all loaded materials 633 */ 634 public List<Material> getMaterials() { 635 return materials; 636 } 637 638 /** 639 * This method returns all loaded textures. 640 * @return all loaded textures 641 */ 642 public List<Texture> getTextures() { 643 return textures; 644 } 645 646 /** 647 * This method returns all loaded animations. 648 * @return all loaded animations 649 */ 650 public List<AnimData> getAnimations() { 651 return animations; 652 } 653 654 /** 655 * This method returns all loaded cameras. 656 * @return all loaded cameras 657 */ 658 public List<Camera> getCameras() { 659 return cameras; 660 } 661 662 /** 663 * This method returns all loaded lights. 664 * @return all loaded lights 665 */ 666 public List<Light> getLights() { 667 return lights; 668 } 669 670 @Override 671 public int collideWith(Collidable other, CollisionResults results) throws UnsupportedCollisionException { 672 return 0; 673 } 674 675 @Override 676 public void updateModelBound() {} 677 678 @Override 679 public void setModelBound(BoundingVolume modelBound) {} 680 681 @Override 682 public int getVertexCount() { 683 return 0; 684 } 685 686 @Override 687 public int getTriangleCount() { 688 return 0; 689 } 690 691 @Override 692 public Spatial deepClone() { 693 return null; 694 } 695 696 @Override 697 public void depthFirstTraversal(SceneGraphVisitor visitor) {} 698 699 @Override 700 protected void breadthFirstTraversal(SceneGraphVisitor visitor, Queue<Spatial> queue) {} 701 } 702 703 /** 704 * The WORLD file block contains various data that could be added to the scene. The contained data includes: ambient 705 * light. 706 * @author Marcin Roguski (Kaelthas) 707 */ 708 public static class WorldData { 709 710 /** The ambient light. */ 711 private AmbientLight ambientLight; 712 713 /** 714 * This method returns the world's ambient light. 715 * @return the world's ambient light 716 */ 717 public AmbientLight getAmbientLight() { 718 return ambientLight; 719 } 720 721 /** 722 * This method sets the world's ambient light. 723 * @param ambientLight 724 * the world's ambient light 725 */ 726 public void setAmbientLight(AmbientLight ambientLight) { 727 this.ambientLight = ambientLight; 728 } 729 } 730} 731