├── LICENSE
├── build.xml
├── dist
├── JUMI.jar
└── README.TXT
├── manifest.mf
├── nbproject
├── build-impl.xml
├── genfiles.properties
├── project.properties
└── project.xml
└── src
└── com
└── jumi
├── JUMILoader.java
├── data
├── Color.java
├── Vector2.java
├── Vector3.java
└── Vector4.java
├── fbx
├── FBXLoader.java
├── node
│ ├── FBXConnectionsNode.java
│ ├── FBXNode.java
│ └── FBXObjectNode.java
└── objects
│ ├── FBXConnection.java
│ ├── FBXProperty.java
│ └── definitions
│ ├── FBXAnimCurveDefinition.java
│ ├── FBXAnimCurveNodeDefinition.java
│ ├── FBXAnimLayerDefinition.java
│ ├── FBXAnimStackDefinition.java
│ ├── FBXCameraDefinition.java
│ ├── FBXClusterDefinition.java
│ ├── FBXLimbNodeDefinition.java
│ ├── FBXMaterialDefinition.java
│ ├── FBXMediaDefinition.java
│ ├── FBXModelDefinition.java
│ ├── FBXObjectDefinition.java
│ ├── FBXShapeDefinition.java
│ ├── FBXSkinDeformerDefinition.java
│ └── FBXTextureDefinition.java
├── obj
├── OBJLoader.java
└── objects
│ └── definitions
│ ├── OBJMatLibDefinition.java
│ ├── OBJMaterialDefinition.java
│ └── OBJModelDefinition.java
└── scene
├── JUMIScene.java
└── objects
├── JUMIBone.java
├── JUMIMaterial.java
├── JUMIMesh.java
├── JUMISkinDeformer.java
├── JUMISubDeformer.java
└── JUMITexture.java
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 RGreenlees
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Builds, tests, and runs the project JUMI.
12 |
13 |
73 |
74 |
--------------------------------------------------------------------------------
/dist/JUMI.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RGreenlees/JUMI-Java-Model-Importer/701ea41eeec9f7465fa1965f0c6c7a985a68948f/dist/JUMI.jar
--------------------------------------------------------------------------------
/dist/README.TXT:
--------------------------------------------------------------------------------
1 | ========================
2 | BUILD OUTPUT DESCRIPTION
3 | ========================
4 |
5 | When you build an Java application project that has a main class, the IDE
6 | automatically copies all of the JAR
7 | files on the projects classpath to your projects dist/lib folder. The IDE
8 | also adds each of the JAR files to the Class-Path element in the application
9 | JAR files manifest file (MANIFEST.MF).
10 |
11 | To run the project from the command line, go to the dist folder and
12 | type the following:
13 |
14 | java -jar "JUMI.jar"
15 |
16 | To distribute this project, zip up the dist folder (including the lib folder)
17 | and distribute the ZIP file.
18 |
19 | Notes:
20 |
21 | * If two JAR files on the project classpath have the same name, only the first
22 | JAR file is copied to the lib folder.
23 | * Only JAR files are copied to the lib folder.
24 | If the classpath contains other types of files or folders, these files (folders)
25 | are not copied.
26 | * If a library on the projects classpath also has a Class-Path element
27 | specified in the manifest,the content of the Class-Path element has to be on
28 | the projects runtime path.
29 | * To set a main class in a standard Java project, right-click the project node
30 | in the Projects window and choose Properties. Then click Run and enter the
31 | class name in the Main Class field. Alternatively, you can manually type the
32 | class name in the manifest Main-Class element.
33 |
--------------------------------------------------------------------------------
/manifest.mf:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 | X-COMMENT: Main-Class will be added automatically by build
3 |
4 |
--------------------------------------------------------------------------------
/nbproject/genfiles.properties:
--------------------------------------------------------------------------------
1 | build.xml.data.CRC32=7e62c94b
2 | build.xml.script.CRC32=90a764a5
3 | build.xml.stylesheet.CRC32=8064a381@1.75.2.48
4 | # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
5 | # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
6 | nbproject/build-impl.xml.data.CRC32=7e62c94b
7 | nbproject/build-impl.xml.script.CRC32=dae1e692
8 | nbproject/build-impl.xml.stylesheet.CRC32=876e7a8f@1.75.2.48
9 |
--------------------------------------------------------------------------------
/nbproject/project.properties:
--------------------------------------------------------------------------------
1 | annotation.processing.enabled=true
2 | annotation.processing.enabled.in.editor=false
3 | annotation.processing.processors.list=
4 | annotation.processing.run.all.processors=true
5 | annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
6 | application.title=JUMI
7 | application.vendor=RGreenlees
8 | build.classes.dir=${build.dir}/classes
9 | build.classes.excludes=**/*.java,**/*.form
10 | # This directory is removed when the project is cleaned:
11 | build.dir=build
12 | build.generated.dir=${build.dir}/generated
13 | build.generated.sources.dir=${build.dir}/generated-sources
14 | # Only compile against the classpath explicitly listed here:
15 | build.sysclasspath=ignore
16 | build.test.classes.dir=${build.dir}/test/classes
17 | build.test.results.dir=${build.dir}/test/results
18 | # Uncomment to specify the preferred debugger connection transport:
19 | #debug.transport=dt_socket
20 | debug.classpath=\
21 | ${run.classpath}
22 | debug.test.classpath=\
23 | ${run.test.classpath}
24 | # Files in build.classes.dir which should be excluded from distribution jar
25 | dist.archive.excludes=
26 | # This directory is removed when the project is cleaned:
27 | dist.dir=dist
28 | dist.jar=${dist.dir}/JUMI.jar
29 | dist.javadoc.dir=${dist.dir}/javadoc
30 | endorsed.classpath=
31 | excludes=
32 | includes=**
33 | jar.compress=false
34 | javac.classpath=
35 | # Space-separated list of extra javac options
36 | javac.compilerargs=
37 | javac.deprecation=false
38 | javac.processorpath=\
39 | ${javac.classpath}
40 | javac.source=1.7
41 | javac.target=1.7
42 | javac.test.classpath=\
43 | ${javac.classpath}:\
44 | ${build.classes.dir}
45 | javac.test.processorpath=\
46 | ${javac.test.classpath}
47 | javadoc.additionalparam=
48 | javadoc.author=false
49 | javadoc.encoding=${source.encoding}
50 | javadoc.noindex=false
51 | javadoc.nonavbar=false
52 | javadoc.notree=false
53 | javadoc.private=false
54 | javadoc.splitindex=true
55 | javadoc.use=true
56 | javadoc.version=false
57 | javadoc.windowtitle=
58 | main.class=FBXTest
59 | manifest.file=manifest.mf
60 | meta.inf.dir=${src.dir}/META-INF
61 | mkdist.disabled=false
62 | platform.active=default_platform
63 | run.classpath=\
64 | ${javac.classpath}:\
65 | ${build.classes.dir}
66 | run.test.classpath=\
67 | ${javac.test.classpath}:\
68 | ${build.test.classes.dir}
69 | source.encoding=UTF-8
70 | src.dir=src
71 | test.src.dir=test
72 |
--------------------------------------------------------------------------------
/nbproject/project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | org.netbeans.modules.java.j2seproject
4 |
5 |
6 | JUMI
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/com/jumi/JUMILoader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi;
20 |
21 | import com.jumi.fbx.FBXLoader;
22 | import com.jumi.obj.OBJLoader;
23 | import com.jumi.scene.JUMIScene;
24 | import java.io.FileNotFoundException;
25 | import java.io.IOException;
26 |
27 | /**
28 | * JUMILoader
29 | *
30 | * This is the main loading class. Determines the file type being loaded and calls the appropriate loader.
31 | * Catches any exceptions thrown during the loading process.
32 | *
33 | * @author Richard Greenlees
34 | */
35 | public class JUMILoader {
36 |
37 | /** Load the supplied file and return a standardised JUMIScene data structure
38 | *
39 | * @param filename The file to load
40 | * @return JUMIScene - A simplified data structure containing key elements
41 | */
42 | public static JUMIScene loadModel(String filename) {
43 | try {
44 | String fileExtension = filename.substring(filename.indexOf('.') + 1, filename.length()).toUpperCase();
45 | switch (fileExtension) {
46 | case "FBX":
47 | return FBXLoader.importModel(filename);
48 | case "OBJ":
49 | return OBJLoader.importModel(filename);
50 | default:
51 | return null;
52 | }
53 | } catch (FileNotFoundException e) {
54 | System.err.println("ERROR: JUMILoader failed to find specified file at " + filename);
55 | } catch (IOException e) {
56 | System.err.println("ERROR: JUMILoader encountered an issue while parsing file " + filename);
57 | }
58 |
59 | return null;
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/com/jumi/data/Color.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.data;
20 |
21 | /**
22 | * Color
23 | *
24 | * A simple container for holding RGBA colour data
25 | *
26 | * @author Richard Greenlees
27 | */
28 | public class Color {
29 | public float r;
30 | public float g;
31 | public float b;
32 | public float a;
33 |
34 | public Color() {
35 | r = 0.0f;
36 | g = 0.0f;
37 | b = 0.0f;
38 | a = 1.0f;
39 | }
40 |
41 | public Color(float newR, float newG, float newB, float newA) {
42 | r = newR;
43 | g = newG;
44 | b = newB;
45 | a = newA;
46 | }
47 |
48 | public Color(float newR, float newG, float newB) {
49 | r = newR;
50 | g = newG;
51 | b = newB;
52 | a = 1.0f;
53 | }
54 |
55 | public String toString() {
56 | return "{ R=" + r + ", G=" + g + ", B=" + b + ", A=" + a + "}";
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/com/jumi/data/Vector2.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.data;
20 |
21 | /**
22 | * Vector2
23 | *
24 | * A simple container for holding 2-dimensional float data (such as UVs)
25 | *
26 | * @author Richard Greenlees
27 | */
28 | public class Vector2 {
29 |
30 | public float x;
31 | public float y;
32 |
33 | public Vector2(float newX, float newY) {
34 | x = newX;
35 | y = newY;
36 | }
37 |
38 | public void set(float newX, float newY) {
39 | x = newX;
40 | y = newY;
41 | }
42 |
43 | public Vector2() {
44 | super();
45 | }
46 |
47 | public String toString() {
48 | return "(" + x + ", " + y + ")";
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/com/jumi/data/Vector3.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.data;
20 |
21 | /**
22 | * Vector3
23 | *
24 | * A simple container for holding 3-dimensional data (such as vertices)
25 | *
26 | * @author Richard Greenlees
27 | */
28 | public class Vector3 {
29 | public float x;
30 | public float y;
31 | public float z;
32 |
33 | public Vector3(float newX, float newY, float newZ) {
34 | x = newX;
35 | y = newY;
36 | z = newZ;
37 | }
38 |
39 | public void set(float newX, float newY, float newZ) {
40 | x = newX;
41 | y = newY;
42 | z = newZ;
43 | }
44 |
45 | public Vector3() {
46 | super();
47 | }
48 |
49 | public String toString() {
50 | return "(" + x + ", " + y + ", " + z + ")";
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/com/jumi/data/Vector4.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.data;
20 |
21 | /**
22 | * Vector4
23 | *
24 | * A simple container for holding 4-dimensional data (such as Quaternions)
25 | *
26 | * @author RGreenlees
27 | */
28 | public class Vector4 {
29 | public float x;
30 | public float y;
31 | public float z;
32 | public float w;
33 |
34 | public Vector4() {
35 | super();
36 | }
37 |
38 | public Vector4(float newX, float newY, float newZ, float newW) {
39 | x = newX;
40 | y = newY;
41 | z = newZ;
42 | w = newW;
43 | }
44 |
45 | public void set(float newX, float newY, float newZ, float newW) {
46 | x = newX;
47 | y = newY;
48 | z = newZ;
49 | w = newW;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/com/jumi/fbx/FBXLoader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.fbx;
20 |
21 | import com.jumi.JUMILoader;
22 | import com.jumi.fbx.node.FBXConnectionsNode;
23 | import static com.jumi.fbx.node.FBXNode.retrieveBytesFrom;
24 | import com.jumi.fbx.node.FBXObjectNode;
25 | import com.jumi.fbx.objects.FBXConnection;
26 | import com.jumi.fbx.objects.definitions.FBXModelDefinition;
27 | import com.jumi.fbx.objects.definitions.FBXObjectDefinition;
28 | import com.jumi.fbx.objects.definitions.FBXTextureDefinition;
29 | import com.jumi.scene.JUMIScene;
30 | import com.jumi.scene.objects.JUMIMesh;
31 | import com.jumi.scene.objects.JUMITexture;
32 | import java.io.BufferedInputStream;
33 | import java.io.File;
34 | import java.io.FileInputStream;
35 | import java.io.IOException;
36 | import java.io.InputStream;
37 | import java.nio.ByteBuffer;
38 | import java.nio.ByteOrder;
39 | import java.util.ArrayList;
40 |
41 | /**
42 | * FBXLoader
43 | *
44 | * The main FBX loading class. Can be invoked directly if the user wishes, but is normally invoked by JUMILoader.
45 | * Parses the supplied FBX binary file and returns a JUMIScene object.
46 | *
47 | * @author Richard Greenlees
48 | */
49 | public class FBXLoader extends JUMILoader {
50 |
51 | /** Import a FBX binary file, parse it and return a JUMIScene object containing the scene data
52 | *
53 | * @param fileName Location of the FBX file to load
54 | * @return JUMIScene containing scene data
55 | * @throws IOException
56 | */
57 | public static JUMIScene importModel(String fileName) throws IOException {
58 | FBXObjectNode objectsNode = null;
59 | FBXConnectionsNode connectionsNode = null;
60 |
61 | ArrayList allMeshes = new ArrayList();
62 | ArrayList allTextures = new ArrayList();
63 |
64 | byte[] mybytes = readBytes(fileName);
65 |
66 | // Read bytes 23 - 26 to retrieve version number
67 | byte[] versionData = retrieveBytesFrom(mybytes, 4, 23);
68 | int version = ByteBuffer.wrap(versionData).order(ByteOrder.LITTLE_ENDIAN).getInt();
69 |
70 | float versionID = (float) version / 1000.0f;
71 |
72 | if (version < 7100) {
73 | String file = fileName.substring(fileName.lastIndexOf("/") + 1, fileName.length());
74 | System.out.println("WARNING: Asset " + file + " uses an older version of the FBX SDK (" + versionID + "), animation data will not be imported.");
75 | System.out.println("\tFor best results, please use 7.1 (SDK 2010) or later.");
76 | } else if (version > 7300) {
77 | String file = fileName.substring(fileName.lastIndexOf("/") + 1, fileName.length());
78 | System.out.println("WARNING: Asset " + file + " uses a newer version of the FBX SDK (" + versionID + ") than the max supported version (7.3), this may produce unexpected results.");
79 | System.out.println("\tFor best results, please use 7.3 (SDK 2011).");
80 | }
81 |
82 | // Start reading the binary data at byte 27, the first byte after the header
83 | int offset = 27;
84 |
85 | while (true) {
86 | int endOffset;
87 |
88 | // Retrieve the end point of the next FBX node
89 | byte[] offsetData = retrieveBytesFrom(mybytes, 4, offset);
90 | endOffset = ByteBuffer.wrap(offsetData).order(ByteOrder.LITTLE_ENDIAN).getInt();
91 |
92 | // This shouldn't happen but you never know...
93 | if (endOffset <= 0) {
94 | break;
95 | }
96 |
97 | // Retrieve the data for the next node, using the calculated endoffset
98 | // TODO: Handle this better so we're not storing the data twice in memory (once in mybytes and once here)
99 | byte[] nextNodeData = retrieveBytesFrom(mybytes, endOffset - offset, offset);
100 |
101 | // Retrieve the length in bytes of the next node's name
102 | int nextNodeNameLength = nextNodeData[12];
103 | // Retrieve the name data
104 | byte[] nextNodeNameData = retrieveBytesFrom(nextNodeData, nextNodeNameLength, 13);
105 |
106 | String nextNodeName = new String(nextNodeNameData);
107 |
108 | // The Objects node holds all the definitions
109 | if (nextNodeName.equals("Objects")) {
110 | objectsNode = new FBXObjectNode(nextNodeData, (nextNodeNameLength + 13));
111 | objectsNode.parseData(nextNodeData, (nextNodeNameLength + 13));
112 | // The Connections node hooks the objects together to create useful data structures
113 | } else if (nextNodeName.equals("Connections")) {
114 | connectionsNode = new FBXConnectionsNode(nextNodeData, (nextNodeNameLength + 13));
115 | connectionsNode.parseData(nextNodeData, (nextNodeNameLength + 13));
116 | // This is the deprecated animation system, but is still present. Once we reach this point we've parsed all useful data
117 | // TODO: Handle this better so we're not reliant on the Takes node to determine when we've finished parsing the file
118 | } else if (nextNodeName.equals("Takes")) {
119 | break;
120 | }
121 |
122 | offset = endOffset;
123 | }
124 |
125 | // For each connection defined in the Connections node, hook them up
126 | for (FBXConnection connection : connectionsNode.connections) {
127 | FBXObjectDefinition a = objectsNode.getConnectable(connection.getLeftUID());
128 | FBXObjectDefinition b = objectsNode.getConnectable(connection.getRightUID());
129 |
130 | if (a != null && b != null) {
131 | a.connect(b);
132 | }
133 | }
134 |
135 | // Retrieve all the model definitions and turn them into JUMIMeshes
136 | for (FBXModelDefinition a : objectsNode.getMeshDefinitions()) {
137 | allMeshes.add(a.createMesh());
138 | }
139 |
140 | // Retrieve all texture definitions that don't have a parent mesh and turn them into JUMITextures
141 | for (FBXTextureDefinition a : objectsNode.getTextureDefinitions()) {
142 | allTextures.add(a.createTexture());
143 | }
144 |
145 | // Build the scene
146 | JUMIScene result = new JUMIScene();
147 | result.addMeshes(allMeshes);
148 | result.addTextures(allTextures);
149 | return result;
150 | }
151 |
152 | /** Read the supplied file and extract the binary data from it */
153 | protected static byte[] readBytes(String aInputFileName) throws IOException {
154 | File file = new File(aInputFileName);
155 | byte[] result = new byte[(int) file.length()];
156 |
157 | int totalBytesRead = 0;
158 | try (InputStream input = new BufferedInputStream(new FileInputStream(file))) {
159 | while (totalBytesRead < result.length) {
160 | int bytesRemaining = result.length - totalBytesRead;
161 | int bytesRead = input.read(result, totalBytesRead, bytesRemaining);
162 | if (bytesRead > 0) {
163 | totalBytesRead = totalBytesRead + bytesRead;
164 | }
165 | }
166 | }
167 |
168 | return result;
169 | }
170 |
171 | }
172 |
--------------------------------------------------------------------------------
/src/com/jumi/fbx/node/FBXConnectionsNode.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.fbx.node;
20 |
21 | import com.jumi.fbx.objects.FBXConnection;
22 | import com.jumi.fbx.objects.FBXProperty;
23 | import java.util.ArrayList;
24 |
25 | /**
26 | * FBXConnectionsNode
27 | *
28 | * Parses the FBX Connections node data to produce a set of object connections
29 | *
30 | * @author RGreenlees
31 | */
32 | public class FBXConnectionsNode extends FBXNode {
33 |
34 | public ArrayList connections = new ArrayList();
35 |
36 | public FBXConnectionsNode(byte[] inputData, int propertyOffset) {
37 | super(inputData, propertyOffset);
38 | }
39 |
40 | /** Method to parse the binary data for the Connections node
41 | * @param inputData The binary data being parsed
42 | * @param propertyOffset Where to start parsing from */
43 | @Override
44 | public void parseData(byte[] inputData, int propertyOffset) {
45 |
46 | // Allow for 13 null bytes at the end of the node (standard in FBX files)
47 | while (sizeInBytes - cursorPosition > 13) {
48 |
49 | // Determine the name of the nested node. It should never be anything except "C" or "Connect" but you never know
50 | int nestedNameLength = inputData[cursorPosition + 12];
51 | byte[] nestedNameData = FBXNode.retrieveBytesFrom(inputData, nestedNameLength, cursorPosition + 13);
52 | String nestedName = new String(nestedNameData);
53 |
54 |
55 | // Find out how many properties we have. Should always be 3 but again, you never know
56 | int nestedProperties = getNumProperties(inputData, cursorPosition);
57 |
58 |
59 | FBXProperty[] connectionProperties = new FBXProperty[nestedProperties];
60 | cursorPosition += nestedNameLength + 13;
61 |
62 | /* Parse all of the properties of this nested item. The first property indicates if it's
63 | connecting two objects ("OO") or an object to a property ("OP"). The next two properties
64 | are the UIDs of the two objects or object and property to hook up */
65 | for (int i = 0; i < nestedProperties; i++) {
66 | FBXProperty newProp = new FBXProperty(inputData, cursorPosition);
67 | cursorPosition += newProp.dataLength;
68 | connectionProperties[i] = newProp;
69 | }
70 |
71 | // Determine the two objects to connect and create a connection object for them to be handled later
72 | if (nestedName.equals("C") || nestedName.equals("Connect")) {
73 | switch (connectionProperties[0].asString()) {
74 | case "OO":
75 | if (connectionProperties[1].dataType.equals("Long")) {
76 | connections.add(new FBXConnection(FBXConnection.FBXConnectionType.OBJECT_OBJECT, connectionProperties[1].asLong(), connectionProperties[2].asLong()));
77 | } else {
78 | String leftID = connectionProperties[1].asString().substring(0, connectionProperties[1].asString().indexOf('\0'));
79 | String rightID = connectionProperties[2].asString().substring(0, connectionProperties[2].asString().indexOf('\0'));
80 | connections.add(new FBXConnection(FBXConnection.FBXConnectionType.OBJECT_OBJECT, leftID, rightID));
81 | } break;
82 | case "OP":
83 | if (connectionProperties[1].dataType.equals("Long")) {
84 | connections.add(new FBXConnection(FBXConnection.FBXConnectionType.OBJECT_PROPERTY, connectionProperties[1].asLong(), connectionProperties[2].asLong()));
85 | } else {
86 | String leftID = connectionProperties[1].asString().substring(0, connectionProperties[1].asString().indexOf('\0'));
87 | String rightID = connectionProperties[2].asString().substring(0, connectionProperties[2].asString().indexOf('\0'));
88 | connections.add(new FBXConnection(FBXConnection.FBXConnectionType.OBJECT_PROPERTY, leftID, rightID));
89 | } break;
90 | }
91 | }
92 | }
93 | }
94 |
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/src/com/jumi/fbx/node/FBXNode.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.fbx.node;
20 |
21 |
22 | import com.jumi.fbx.objects.FBXProperty;
23 | import java.nio.ByteBuffer;
24 | import java.nio.ByteOrder;
25 | import java.util.ArrayList;
26 |
27 | /**
28 | * FBXNode
29 | *
30 | * Base class for Object and Connection nodes
31 | *
32 | * @author Richard Greenlees
33 | */
34 | public abstract class FBXNode {
35 |
36 | public int endOffset;
37 | public int numProperties;
38 | public int propertyListLength;
39 | public int cursorPosition;
40 | public int nameLength;
41 | public String name;
42 | public int sizeInBytes;
43 |
44 | public ArrayList properties = new ArrayList();
45 |
46 | // Constructor. Sets up some useful info about the node
47 | public FBXNode(byte[] inputData, int propertyOffset) {
48 | sizeInBytes = inputData.length;
49 |
50 | numProperties = getNumProperties(inputData);
51 |
52 | int propertyStartOffset = propertyOffset;
53 |
54 | for (int i = 0; i < numProperties; i++) {
55 | FBXProperty newProp = new FBXProperty(inputData, propertyStartOffset);
56 | propertyStartOffset += newProp.dataLength;
57 | properties.add(newProp);
58 | }
59 |
60 | cursorPosition = propertyStartOffset;
61 | }
62 |
63 | public abstract void parseData(byte[] inputData, int propertyOffset);
64 |
65 | // Helper method to extract the data specific to this node
66 | public final byte[] extractRawData(byte[] inputData, int startPosition, int endOffset) {
67 | byte[] rawData = new byte[endOffset - startPosition];
68 |
69 | for (int i = 0; i < rawData.length; i++) {
70 | rawData[i] = inputData[startPosition + i];
71 | }
72 |
73 | return rawData;
74 | }
75 |
76 | public final int getNumProperties(byte[] inputData) {
77 | byte[] bytes = retrieveBytesFrom(inputData, 4, 4);
78 | return ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getInt();
79 | }
80 |
81 | public final int getNumProperties(byte[] inputData, int startPosition) {
82 | byte[] bytes = retrieveBytesFrom(inputData, 4, 4+startPosition);
83 | return ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getInt();
84 | }
85 |
86 | public final String getName(byte[] inputData) {
87 | nameLength = getNameLength(inputData);
88 | return new String(retrieveBytesFrom(inputData, nameLength, 13));
89 | }
90 |
91 | public final int getNameLength(byte[] inputData) {
92 | return inputData[12];
93 | }
94 |
95 | public final int getPropertyListLength(byte[] inputData) {
96 | byte[] bytes = retrieveBytesFrom(inputData, 4, 8);
97 | return ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getInt();
98 | }
99 |
100 | public final int getEndOffset(byte[] inputData, int startPosition) {
101 | byte[] result = retrieveBytesFrom(inputData, 4, startPosition);
102 | return ByteBuffer.wrap(result).order(ByteOrder.LITTLE_ENDIAN).getInt();
103 | }
104 |
105 | public final static byte[] retrieveBytesFrom(byte[] inputData, int numBytes, int offSet) {
106 | byte[] result = new byte[numBytes];
107 |
108 | for (int i = offSet; i < numBytes + offSet; i++) {
109 | result[i - offSet] = inputData[i];
110 | }
111 |
112 | return result;
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/src/com/jumi/fbx/node/FBXObjectNode.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.fbx.node;
20 |
21 | import com.jumi.fbx.objects.definitions.FBXAnimCurveDefinition;
22 | import com.jumi.fbx.objects.definitions.FBXAnimCurveNodeDefinition;
23 | import com.jumi.fbx.objects.definitions.FBXAnimLayerDefinition;
24 | import com.jumi.fbx.objects.definitions.FBXAnimStackDefinition;
25 | import com.jumi.fbx.objects.definitions.FBXCameraDefinition;
26 | import com.jumi.fbx.objects.definitions.FBXClusterDefinition;
27 | import com.jumi.fbx.objects.definitions.FBXLimbNodeDefinition;
28 | import com.jumi.fbx.objects.definitions.FBXMaterialDefinition;
29 | import com.jumi.fbx.objects.definitions.FBXMediaDefinition;
30 | import com.jumi.fbx.objects.definitions.FBXModelDefinition;
31 | import com.jumi.fbx.objects.definitions.FBXObjectDefinition;
32 | import com.jumi.fbx.objects.FBXProperty;
33 | import com.jumi.fbx.objects.definitions.FBXShapeDefinition;
34 | import com.jumi.fbx.objects.definitions.FBXSkinDeformerDefinition;
35 | import com.jumi.fbx.objects.definitions.FBXTextureDefinition;
36 | import java.nio.ByteBuffer;
37 | import java.nio.ByteOrder;
38 | import java.util.ArrayList;
39 | import java.util.HashMap;
40 | import java.util.Map.Entry;
41 |
42 | /**
43 | * FBXObjectNode
44 | *
45 | * Parses data stored in the Objects node.
46 | *
47 | * @author Richard Greenlees
48 | */
49 | public class FBXObjectNode extends FBXNode {
50 |
51 | public HashMap connectableObjects = new HashMap();
52 |
53 | public FBXObjectNode(byte[] inputData, int propertyOffset) {
54 | super(inputData, propertyOffset);
55 | }
56 |
57 | @Override
58 | public void parseData(byte[] inputData, int propertyOffset) {
59 |
60 | long objectUID;
61 | FBXObjectDefinition newObject;
62 |
63 | while (sizeInBytes - cursorPosition > 13) {
64 |
65 | objectUID = 0;
66 | newObject = null;
67 |
68 | int nestedNameLength = inputData[cursorPosition + 12];
69 |
70 | byte[] nestedNameData = FBXNode.retrieveBytesFrom(inputData, nestedNameLength, cursorPosition + 13);
71 | String nestedName = new String(nestedNameData);
72 |
73 | byte[] numPropertiesData = FBXNode.retrieveBytesFrom(inputData, 4, cursorPosition + 4);
74 | int numNestedProperties = ByteBuffer.wrap(numPropertiesData).order(ByteOrder.LITTLE_ENDIAN).getInt();
75 |
76 | FBXProperty[] nestedProperties = new FBXProperty[numNestedProperties];
77 |
78 | cursorPosition += nestedNameLength + 13;
79 |
80 | for (int i = 0; i < nestedProperties.length; i++) {
81 | FBXProperty newProp = new FBXProperty(inputData, cursorPosition);
82 | cursorPosition += newProp.dataLength;
83 | nestedProperties[i] = newProp;
84 | }
85 |
86 | if (nestedProperties.length > 0 && nestedProperties[0].dataType.equals("Long")) {
87 | objectUID = nestedProperties[0].asLong();
88 | }
89 |
90 | // What kind of nested item is this?
91 | switch (nestedName) {
92 | case "Model":
93 | case "Geometry":
94 | String modelType = nestedProperties[nestedProperties.length - 1].asString();
95 |
96 | switch (modelType) {
97 | // Bone definition. Name and local translation
98 | case "LimbNode":
99 | newObject = new FBXLimbNodeDefinition(objectUID);
100 | break;
101 | // Morph target
102 | case "Shape":
103 | newObject = new FBXShapeDefinition(objectUID);
104 | break;
105 | // Mesh geometry or model attributes (local translation etc...)
106 | case "Mesh":
107 | newObject = new FBXModelDefinition(objectUID);
108 | break;
109 | // TODO: Look at adding support for cameras
110 | default: break;
111 | }
112 | break;
113 | // Material definition. Doesn't contain texture info
114 | case "Material":
115 | newObject = new FBXMaterialDefinition(objectUID);
116 | break;
117 | // A texture definition, filename, format etc.
118 | case "Texture":
119 | newObject = new FBXTextureDefinition(objectUID);
120 | break;
121 | // Seems to do the same job as a texture object, not sure why it's needed but it's used so keep it
122 | case "Video":
123 | newObject = new FBXMediaDefinition(objectUID);
124 | break;
125 | // Bone definition. Affected vertices and weights
126 | case "Deformer":
127 | String deformerType = nestedProperties[nestedProperties.length - 1].asString();
128 | if (deformerType.equals("Skin")) {
129 | newObject = new FBXSkinDeformerDefinition(objectUID);
130 | } else if (deformerType.equals("Cluster")) {
131 | newObject = new FBXClusterDefinition(objectUID);
132 | } break;
133 | // A container for animations, allowing for blending
134 | case "AnimationStack":
135 | newObject = new FBXAnimStackDefinition(objectUID);
136 | break;
137 | // A single animation
138 | case "AnimationLayer":
139 | newObject = new FBXAnimLayerDefinition(objectUID);
140 | break;
141 | // Contains the actual animation data
142 | case "AnimationCurveNode":
143 | newObject = new FBXAnimCurveNodeDefinition(objectUID);
144 | break;
145 | // Data for a single keyframe
146 | case "AnimationCurve":
147 | newObject = new FBXAnimCurveDefinition(objectUID);
148 | break;
149 | }
150 |
151 | // If our new object is one of the above then add it to our connectable objects ready to hook up
152 | if (newObject != null) {
153 |
154 | String newObjectName = nestedProperties[nestedProperties.length - 2].asString();
155 | newObjectName = newObjectName.substring(0, newObjectName.indexOf('\0'));
156 |
157 | newObject.setName(newObjectName);
158 | newObject.parseData(inputData, cursorPosition);
159 | // Some older FBX files use String names as IDs instead of longs. Performance isn't affected too badly so let's allow it
160 | connectableObjects.put((objectUID > 0) ? String.valueOf(objectUID) : newObjectName, newObject);
161 | cursorPosition = newObject.endOffset;
162 | }
163 |
164 | }
165 | }
166 |
167 | /** Returns a specific connectable object using the supplied key */
168 | public FBXObjectDefinition getConnectable(String key) {
169 | return connectableObjects.get(key);
170 | }
171 |
172 | /** Retrieves all the individual mesh objects in the scene. Only returns parent models that have geometry assigned */
173 | public ArrayList getMeshDefinitions() {
174 | ArrayList result = new ArrayList();
175 | for (Entry entry : connectableObjects.entrySet()) {
176 | if (entry.getValue() instanceof FBXModelDefinition) {
177 | FBXModelDefinition test = (FBXModelDefinition) entry.getValue();
178 | if (test.isRoot() && test.containsGeometryDefinition()) {
179 | result.add(test);
180 | }
181 | }
182 | }
183 | return result;
184 | }
185 |
186 | /** Retrieves all "orphan" textures which aren't assigned to a mesh for some reason */
187 | public ArrayList getTextureDefinitions() {
188 | ArrayList result = new ArrayList();
189 | for (Entry entry : connectableObjects.entrySet()) {
190 | if (entry.getValue() instanceof FBXTextureDefinition) {
191 | FBXTextureDefinition test = (FBXTextureDefinition) entry.getValue();
192 | if (test.parent == null) {
193 | result.add(test);
194 | }
195 | }
196 | }
197 | return result;
198 | }
199 |
200 | /** Get the root node for the mesh */
201 | public FBXLimbNodeDefinition getRootNode() {
202 | for (Entry entry : connectableObjects.entrySet()) {
203 | if (entry.getValue() instanceof FBXLimbNodeDefinition) {
204 | FBXLimbNodeDefinition test = (FBXLimbNodeDefinition) entry.getValue();
205 | if (test.isRoot) {
206 | return test;
207 | }
208 | }
209 | }
210 | return null;
211 | }
212 | }
213 |
--------------------------------------------------------------------------------
/src/com/jumi/fbx/objects/FBXConnection.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.fbx.objects;
20 |
21 |
22 | /**
23 | * FBXConnection
24 | *
25 | * A container for an FBX connection definition.
26 | *
27 | * @author Richard Greenlees
28 | */
29 | public class FBXConnection {
30 | public long leftObjectUID;
31 | public long rightObjectUID;
32 |
33 | public String leftObjectName;
34 | public String rightObjectName;
35 |
36 | public static enum FBXConnectionType {OBJECT_OBJECT, OBJECT_PROPERTY };
37 |
38 | public FBXConnectionType connectionType;
39 |
40 | public FBXConnection(FBXConnectionType newConnectionType, long leftUID, long rightUID) {
41 | connectionType = newConnectionType;
42 | leftObjectUID = leftUID;
43 | rightObjectUID = rightUID;
44 | }
45 |
46 | public FBXConnection(FBXConnectionType newConnectionType, String leftUID, String rightUID) {
47 | connectionType = newConnectionType;
48 | leftObjectName = leftUID;
49 | rightObjectName = rightUID;
50 | }
51 |
52 | /** Does this connection reference the given long ID? */
53 | public boolean containsReferenceTo(long ref) {
54 | return leftObjectUID == ref || rightObjectUID == ref;
55 | }
56 |
57 | /** Does this connection reference the given String ID? */
58 | public boolean containsReferenceTo(String ref) {
59 | return leftObjectName.equals(ref) || rightObjectName.equals(ref);
60 | }
61 |
62 | public String toString() {
63 | String result = "Connection: ";
64 |
65 | if (leftObjectUID > 0) {
66 | result = result + leftObjectUID + " to ";
67 | } else {
68 | result = result + leftObjectName + " to ";
69 | }
70 |
71 | if (rightObjectUID > 0) {
72 | result = result + rightObjectUID;
73 | } else {
74 | result = result + rightObjectName;
75 | }
76 |
77 | return result;
78 | }
79 |
80 | public boolean hasLeftUID() {
81 | return leftObjectUID > 0;
82 | }
83 |
84 | public boolean hasRightUID() {
85 | return rightObjectUID > 0;
86 | }
87 |
88 | public String getLeftUID() {
89 | if (leftObjectUID > 0) {
90 | return String.valueOf(leftObjectUID);
91 | } else {
92 | return leftObjectName;
93 | }
94 | }
95 |
96 | public String getRightUID() {
97 | if (rightObjectUID > 0) {
98 | return String.valueOf(rightObjectUID);
99 | } else {
100 | return rightObjectName;
101 | }
102 | }
103 |
104 | }
105 |
--------------------------------------------------------------------------------
/src/com/jumi/fbx/objects/FBXProperty.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.fbx.objects;
20 |
21 | import com.jumi.fbx.node.FBXNode;
22 | import java.io.ByteArrayOutputStream;
23 | import java.io.IOException;
24 | import java.nio.ByteBuffer;
25 | import java.nio.ByteOrder;
26 | import java.nio.DoubleBuffer;
27 | import java.nio.IntBuffer;
28 | import java.nio.LongBuffer;
29 | import java.util.zip.DataFormatException;
30 | import java.util.zip.Inflater;
31 |
32 | /**
33 | * FBXProperty
34 | *
35 | * A single property definition, belonging to a nested item or node
36 | *
37 | * @author Richard Greenlees
38 | */
39 | public class FBXProperty {
40 |
41 | public char typeCode;
42 | public String dataType;
43 | public int dataLength;
44 | private byte[] binaryData;
45 | private int dataSizeInBytes;
46 | private int startPosition;
47 |
48 | public FBXProperty(byte[] inputData, int cursorPosition) {
49 | startPosition = cursorPosition;
50 | typeCode = (char) (inputData[startPosition] & 0xFF);
51 |
52 | // Every FBX Property starts with a char indicating what data type it is. Self-explanatory hopefully.
53 | switch (typeCode) {
54 | case 'Y':
55 | dataType = "Short";
56 | dataSizeInBytes = 2;
57 | parseValue(inputData);
58 | break;
59 | case 'C':
60 | dataType = "Boolean";
61 | dataSizeInBytes = 1;
62 | parseValue(inputData);
63 | break;
64 | case 'F':
65 | dataType = "Float";
66 | dataSizeInBytes = 4;
67 | parseValue(inputData);
68 | break;
69 | case 'I':
70 | dataType = "Integer";
71 | dataSizeInBytes = 4;
72 | parseValue(inputData);
73 | break;
74 | case 'D':
75 | dataType = "Double";
76 | dataSizeInBytes = 8;
77 | parseValue(inputData);
78 | break;
79 | case 'L':
80 | dataType = "Long";
81 | dataSizeInBytes = 8;
82 | parseValue(inputData);
83 | break;
84 | case 'f':
85 | case 'i':
86 | dataType = "Integer Array";
87 | dataSizeInBytes = 4;
88 | parseArray(inputData);
89 | break;
90 | case 'd':
91 | dataType = "Double Array";
92 | dataSizeInBytes = 8;
93 | parseArray(inputData);
94 | break;
95 | case 'l':
96 | dataType = "Long Array";
97 | dataSizeInBytes = 8;
98 | parseArray(inputData);
99 | break;
100 | case 'b':
101 | dataType = "Boolean Array";
102 | dataSizeInBytes = 1;
103 | parseArray(inputData);
104 | break;
105 | case 'S':
106 | dataType = "String";
107 | parseBinary(inputData);
108 | break;
109 | case 'R':
110 | dataType = "Raw Binary Data";
111 | parseBinary(inputData);
112 | break;
113 | default:
114 | System.err.println("Unknown property type! " + typeCode);
115 | System.exit(-1);
116 | break;
117 | }
118 | }
119 |
120 | /* Simply extract the binary data based on the data size */
121 | private void parseValue(byte[] inputData) {
122 | binaryData = FBXNode.retrieveBytesFrom(inputData, dataSizeInBytes, startPosition + 1);
123 | dataLength = dataSizeInBytes + 1;
124 | }
125 |
126 | /* Slightly different, we need to determine the length of the binary data before we store it */
127 | private void parseBinary(byte[] inputData) {
128 | byte[] binaryLength = FBXNode.retrieveBytesFrom(inputData, 4, startPosition + 1);
129 | int binarySize = ByteBuffer.wrap(binaryLength).order(ByteOrder.LITTLE_ENDIAN).getInt();
130 |
131 | binaryData = FBXNode.retrieveBytesFrom(inputData, binarySize, startPosition + 5);
132 |
133 | dataLength = 5 + binarySize;
134 | }
135 |
136 | /* Slightly tricker. We need to determine the length of the data and whether it is compressed or not. Decompress if necessary */
137 | private void parseArray(byte[] inputData) {
138 | byte[] arrayData = null;
139 |
140 | byte[] arrayLengthData = FBXNode.retrieveBytesFrom(inputData, 4, startPosition + 1);
141 | int arrayLength = ByteBuffer.wrap(arrayLengthData).order(ByteOrder.LITTLE_ENDIAN).getInt();
142 |
143 | byte[] encodingBytes = FBXNode.retrieveBytesFrom(inputData, 4, startPosition + 5);
144 | int encoding = ByteBuffer.wrap(encodingBytes).order(ByteOrder.LITTLE_ENDIAN).getInt();
145 |
146 | byte[] compressionSizeBytes = FBXNode.retrieveBytesFrom(inputData, 4, startPosition + 9);
147 | int compressedSize = ByteBuffer.wrap(compressionSizeBytes).order(ByteOrder.LITTLE_ENDIAN).getInt();
148 |
149 | if (encoding == 1) {
150 | byte[] compressedData = FBXNode.retrieveBytesFrom(inputData, compressedSize, startPosition + 13);
151 | arrayData = decompressData(compressedData);
152 |
153 | } else {
154 | arrayData = FBXNode.retrieveBytesFrom(inputData, arrayLength * dataSizeInBytes, startPosition + 13);
155 | }
156 |
157 | binaryData = arrayData;
158 |
159 | if (encoding == 1) {
160 | dataLength = compressedSize + 13;
161 | } else {
162 | dataLength = (arrayLength * dataSizeInBytes) + 13;
163 | }
164 | }
165 |
166 | /* Inflates compressed binary data to give you the final binary data in an array */
167 | private byte[] decompressData(byte[] compressedData) {
168 |
169 | Inflater decompressor = new Inflater();
170 | decompressor.setInput(compressedData);
171 |
172 | ByteArrayOutputStream outputStream = new ByteArrayOutputStream(compressedData.length);
173 | byte[] buffer = new byte[1024];
174 | while (!decompressor.finished()) {
175 | try {
176 | int count = decompressor.inflate(buffer);
177 | outputStream.write(buffer, 0, count);
178 | } catch (DataFormatException e) {
179 | e.printStackTrace();
180 | }
181 | }
182 | try {
183 | outputStream.close();
184 | } catch (IOException e) {
185 | e.printStackTrace();
186 | }
187 | decompressor.end();
188 | return outputStream.toByteArray();
189 |
190 | }
191 |
192 | /** Express this property as an array of integers */
193 | public int[] asIntArray() {
194 | IntBuffer intBuffer = ByteBuffer.wrap(binaryData).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer();
195 | int[] result = new int[intBuffer.remaining()];
196 | intBuffer.get(result);
197 |
198 | return result;
199 | }
200 |
201 | /** Express this property as an array of longs */
202 | public long[] asLongArray() {
203 | LongBuffer longBuffer = ByteBuffer.wrap(binaryData).order(ByteOrder.LITTLE_ENDIAN).asLongBuffer();
204 | long[] result = new long[longBuffer.remaining()];
205 | longBuffer.get(result);
206 |
207 | return result;
208 | }
209 |
210 | /** Express this property as an array of doubles */
211 | public double[] asDoubleArray() {
212 | DoubleBuffer doubleBuffer = ByteBuffer.wrap(binaryData).order(ByteOrder.LITTLE_ENDIAN).asDoubleBuffer();
213 | double[] result = new double[doubleBuffer.remaining()];
214 | doubleBuffer.get(result);
215 |
216 | return result;
217 | }
218 |
219 | /** Express this property as an array of floats */
220 | public float[] asFloatArray() {
221 | float[] result;
222 | DoubleBuffer doubleBuffer = ByteBuffer.wrap(binaryData).order(ByteOrder.LITTLE_ENDIAN).asDoubleBuffer();
223 | double[] interim = new double[doubleBuffer.remaining()];
224 | doubleBuffer.get(interim);
225 |
226 | result = new float[interim.length];
227 |
228 | for (int i = 0; i < interim.length; i++) {
229 | result[i] = (float) interim[i];
230 | }
231 |
232 | return result;
233 | }
234 |
235 | /** Express this property as a String */
236 | public String asString() {
237 | return new String(binaryData);
238 | }
239 |
240 | /** Express this property as a short */
241 | public short asShort() {
242 | return ByteBuffer.wrap(binaryData).order(ByteOrder.LITTLE_ENDIAN).getShort();
243 | }
244 |
245 | /** Express this property as a long */
246 | public long asLong() {
247 | return ByteBuffer.wrap(binaryData).order(ByteOrder.LITTLE_ENDIAN).getLong();
248 | }
249 |
250 | /** Express this property as a double */
251 | public double asDouble() {
252 | return ByteBuffer.wrap(binaryData).order(ByteOrder.LITTLE_ENDIAN).getDouble();
253 | }
254 |
255 | /** Express this property as a float */
256 | public float asFloat() {
257 | if (dataType.equals("Float")) {
258 | return ByteBuffer.wrap(binaryData).order(ByteOrder.LITTLE_ENDIAN).getFloat();
259 | } else {
260 | return (float) ByteBuffer.wrap(binaryData).order(ByteOrder.LITTLE_ENDIAN).getDouble();
261 | }
262 | }
263 |
264 | /** Express this property as a boolean */
265 | public boolean asBoolean() {
266 | return (binaryData[0] != 0);
267 | }
268 |
269 | /** Express this property as an array of booleans */
270 | public boolean[] asBooleanArray() {
271 | boolean[] result = new boolean[binaryData.length];
272 | for (int i = 0; i < binaryData.length; i++) {
273 | result[i] = (binaryData[i] != 0);
274 | }
275 | return result;
276 | }
277 |
278 | /** Express this property as raw binary */
279 | public byte[] asByteArray() {
280 | return binaryData;
281 | }
282 |
283 | /** Express this property as an integer */
284 | public int asInteger() {
285 | return ByteBuffer.wrap(binaryData).order(ByteOrder.LITTLE_ENDIAN).getInt();
286 | }
287 |
288 | public String toString() {
289 | String result = dataType + ": ";
290 |
291 | switch (typeCode) {
292 | case 'Y':
293 | result = result + asShort();
294 | break;
295 | case 'C':
296 | result = result + asBoolean();
297 | break;
298 | case 'I':
299 | result = result + asInteger();
300 | break;
301 | case 'F':
302 | result = result + asFloat();
303 | break;
304 | case 'D':
305 | result = result + asDouble();
306 | break;
307 | case 'L':
308 | result = result + asLong();
309 | break;
310 | case 'f':
311 | case 'i':
312 | result = result + "{ " + asIntArray()[0] + "...}";
313 | break;
314 | case 'd':
315 | result = result + "{ " + asDoubleArray()[0] + "...}";
316 | break;
317 | case 'l':
318 | result = result + "{ " + asLongArray()[0] + " ...}";
319 | break;
320 | case 'b':
321 | result = result + "{ " + asBooleanArray()[0] + " ...}";
322 | break;
323 | case 'S':
324 | result = result + asString();
325 | break;
326 | case 'R':
327 | result = result + "{ BINARY ... (" + binaryData.length + " bytes) }";
328 | break;
329 | default:
330 | result = result + "ERROR! Unknown type";
331 | break;
332 | }
333 | return result;
334 | }
335 |
336 | }
337 |
--------------------------------------------------------------------------------
/src/com/jumi/fbx/objects/definitions/FBXAnimCurveDefinition.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.fbx.objects.definitions;
20 |
21 | import com.jumi.fbx.objects.FBXProperty;
22 |
23 | /**
24 | * FBXAnimCurveDefinition
25 | *
26 | * Container for FBX data related to an Animation Curve. Not currently used for anything.
27 | *
28 | * @author Richard Greenlees
29 | */
30 | public class FBXAnimCurveDefinition extends FBXObjectDefinition {
31 |
32 | public static final long FBX_TC_MILLIS = 46186158L;
33 |
34 | long[] keyTime = new long[0];
35 | int[] keyValueFloat = new int[0];
36 | int[] keyAttrFlags = new int[0];
37 | int[] keyAttrDataFloat = new int[0];
38 | int[] keyAttrRefCount = new int[0];
39 |
40 | public FBXAnimCurveDefinition(long UID, String inName) {
41 | super(UID, inName);
42 | }
43 |
44 | public FBXAnimCurveDefinition(long inUID) {
45 | super(inUID);
46 | }
47 |
48 | @Override
49 | public void readNestedObject(String nestedName, FBXProperty[] properties) {
50 | if (nestedName.equals("KeyTime")) {
51 | keyTime = properties[0].asLongArray();
52 | } else if (nestedName.equals("KeyValueFloat")) {
53 | keyValueFloat = properties[0].asIntArray();
54 | } else if (nestedName.equals("KeyAttrFlags")) {
55 | keyAttrFlags = properties[0].asIntArray();
56 | } else if (nestedName.equals("KeyAttrDataFloat")) {
57 | keyAttrDataFloat = properties[0].asIntArray();
58 | } else if (nestedName.equals("KeyAttrRefCount")) {
59 | keyAttrRefCount = properties[0].asIntArray();
60 | }
61 | }
62 |
63 | @Override
64 | public void readEmbeddedProperty(FBXProperty[] properties) {
65 |
66 | }
67 |
68 |
69 | @Override
70 | public void connect(FBXAnimCurveNodeDefinition inAnimCurveNode) {
71 | inAnimCurveNode.animationCurve = this;
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/src/com/jumi/fbx/objects/definitions/FBXAnimCurveNodeDefinition.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.fbx.objects.definitions;
20 |
21 | import com.jumi.fbx.objects.FBXProperty;
22 |
23 | /**
24 | * FBXAnimCurveNodeDefinition
25 | *
26 | * A container for storing key frame data. Not currently used for anything.
27 | *
28 | * @author Richard Greenlees
29 | */
30 | public class FBXAnimCurveNodeDefinition extends FBXObjectDefinition {
31 |
32 | public float dX = 0.0f;
33 | public float dY = 0.0f;
34 | public float dZ = 0.0f;
35 |
36 | public FBXAnimCurveDefinition animationCurve;
37 |
38 | public FBXAnimCurveNodeDefinition(long UID, String inName) {
39 | super(UID, inName);
40 | }
41 |
42 | public FBXAnimCurveNodeDefinition(long inUID) {
43 | super(inUID);
44 | }
45 |
46 | @Override
47 | public void readNestedObject(String nestedName, FBXProperty[] properties) {
48 |
49 | }
50 |
51 | @Override
52 | public void readEmbeddedProperty(FBXProperty[] properties) {
53 | String propertyName = properties[0].asString();
54 | if (propertyName.equals("d|X")) {
55 | dX = properties[properties.length-1].asFloat();
56 | } else if (propertyName.equals("d|Y")) {
57 | dY = properties[properties.length-1].asFloat();
58 | } else if (propertyName.equals("d|Z")) {
59 | dZ = properties[properties.length-1].asFloat();
60 | }
61 | }
62 |
63 | @Override
64 | public void connect(FBXAnimCurveDefinition inAnimCurve) {
65 | //.out.println("Joining this Animation Curve Node " + UID + " to Animation Curve " + inAnimCurve.name);
66 | animationCurve = inAnimCurve;
67 | }
68 |
69 | @Override
70 | public void connect(FBXAnimLayerDefinition inAnimLayer) {
71 | //System.out.println("Joining this Animation Curve Node " + UID + " to Animation Layer " + inAnimLayer.name);
72 | inAnimLayer.curveNodes.add(this);
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/src/com/jumi/fbx/objects/definitions/FBXAnimLayerDefinition.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.fbx.objects.definitions;
20 |
21 | import com.jumi.fbx.objects.FBXProperty;
22 | import java.util.ArrayList;
23 |
24 | /**
25 | * FBXAnimLayerDefinition
26 | *
27 | * Container for holding information for a single animation. Not currently in use.
28 | *
29 | * @author Richard Greenlees
30 | */
31 | public class FBXAnimLayerDefinition extends FBXObjectDefinition {
32 |
33 | public ArrayList curveNodes = new ArrayList();
34 |
35 | public FBXAnimLayerDefinition(long UID, String inName) {
36 | super(UID, inName);
37 | }
38 |
39 | public FBXAnimLayerDefinition(long inUID) {
40 | super(inUID);
41 | }
42 |
43 | @Override
44 | public void readNestedObject(String nestedName, FBXProperty[] properties) {
45 |
46 | }
47 |
48 | @Override
49 | public void readEmbeddedProperty(FBXProperty[] properties) {
50 |
51 | }
52 |
53 | @Override
54 | public void connect(FBXAnimCurveNodeDefinition inAnimCurveNode) {
55 | curveNodes.add(inAnimCurveNode);
56 | }
57 |
58 | @Override
59 | public void connect(FBXAnimStackDefinition inAnimStack) {
60 | inAnimStack.animationLayers.add(this);
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/src/com/jumi/fbx/objects/definitions/FBXAnimStackDefinition.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.fbx.objects.definitions;
20 |
21 | import com.jumi.fbx.objects.FBXProperty;
22 | import java.util.ArrayList;
23 |
24 | /**
25 | * FBXAnimStackDefinition
26 | *
27 | * Container for holding information on an animation set. Not currently used for anything.
28 | *
29 | * @author Richard Greenlees
30 | */
31 | public class FBXAnimStackDefinition extends FBXObjectDefinition {
32 |
33 | public ArrayList animationLayers = new ArrayList();
34 |
35 | public FBXAnimStackDefinition(long UID, String inName) {
36 | super(UID, inName);
37 | }
38 |
39 | public FBXAnimStackDefinition(long inUID) {
40 | super(inUID);
41 | }
42 |
43 | @Override
44 | public void readNestedObject(String nestedName, FBXProperty[] properties) {
45 |
46 | }
47 |
48 | @Override
49 | public void readEmbeddedProperty(FBXProperty[] properties) {
50 |
51 | }
52 |
53 | @Override
54 | public void connect(FBXAnimLayerDefinition inAnimLayer) {
55 | animationLayers.add(inAnimLayer);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/com/jumi/fbx/objects/definitions/FBXCameraDefinition.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.fbx.objects.definitions;
20 |
21 | import com.jumi.fbx.objects.FBXProperty;
22 |
23 | /**
24 | * FBXCameraDefinition
25 | *
26 | * Container for holding camera information. Not currently used for anything.
27 | *
28 | * @author RGreenlees
29 | */
30 | public class FBXCameraDefinition extends FBXObjectDefinition {
31 |
32 | public FBXCameraDefinition(long inUID, String inName) {
33 | super(inUID, inName);
34 | }
35 |
36 | public FBXCameraDefinition(long inUID) {
37 | super(inUID);
38 | }
39 |
40 | @Override
41 | public void readNestedObject(String nestedName, FBXProperty[] properties) {
42 |
43 | }
44 |
45 | @Override
46 | public void readEmbeddedProperty(FBXProperty[] properties) {
47 |
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/com/jumi/fbx/objects/definitions/FBXClusterDefinition.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.fbx.objects.definitions;
20 |
21 | import com.jumi.scene.objects.JUMISubDeformer;
22 | import com.jumi.fbx.objects.FBXProperty;
23 |
24 | /**
25 | * FBXClusterDefinition
26 | *
27 | * A container for holding information on the weights and indices for a bone.
28 | *
29 | * @author Richard Greenlees
30 | */
31 | public class FBXClusterDefinition extends FBXObjectDefinition {
32 |
33 | public int[] indexes = new int[0];
34 | public float[] weights = new float[0];
35 | public float[] transforms = new float[0];
36 | public float[] transformLinks = new float[0];
37 |
38 | public FBXLimbNodeDefinition limbNode;
39 |
40 | public FBXClusterDefinition(long UID, String name) {
41 | super(UID, name);
42 | }
43 |
44 | public FBXClusterDefinition(long inUID) {
45 | super(inUID);
46 | }
47 |
48 | @Override
49 | public void readNestedObject(String nestedName, FBXProperty[] properties) {
50 | if (nestedName.equals("Indexes") && properties.length > 0) {
51 | if (properties[0].typeCode == 'i' || properties[0].typeCode == 'f') {
52 | indexes = properties[0].asIntArray();
53 | } else if (properties[0].typeCode == 'I' || properties[0].typeCode == 'F') {
54 | indexes = new int[properties.length];
55 | for (int i = 0; i < properties.length; i++) {
56 | indexes[i] = properties[i].asInteger();
57 | }
58 | } else {
59 | System.err.println("Invalid indices data type! Expected: integer or array of integers, actual: " + properties[0].dataType);
60 | }
61 | } else if (nestedName.equals("Weights") && properties.length > 0) {
62 | if (properties[0].typeCode == 'd') {
63 | weights = properties[0].asFloatArray();
64 | } else if (properties[0].typeCode == 'D') {
65 | weights = new float[properties.length];
66 | for (int i = 0; i < properties.length; i++) {
67 | weights[i] = (float) properties[i].asDouble();
68 | }
69 | } else {
70 | System.err.println("Invalid UV data type! Expected: double or array of doubles, actual: " + properties[0].dataType);
71 | }
72 | } else if (nestedName.equals("Transform") && properties.length > 0) {
73 | if (properties[0].typeCode == 'd') {
74 | transforms = properties[0].asFloatArray();
75 | } else if (properties[0].typeCode == 'D') {
76 | transforms = new float[properties.length];
77 | for (int i = 0; i < properties.length; i++) {
78 | transforms[i] = (float) properties[i].asDouble();
79 | }
80 | } else {
81 | System.err.println("Invalid UV data type! Expected: double or array of doubles, actual: " + properties[0].dataType);
82 | }
83 | } else if (nestedName.equals("TransformLink") && properties.length > 0) {
84 | if (properties[0].typeCode == 'd') {
85 | transformLinks = properties[0].asFloatArray();
86 | } else if (properties[0].typeCode == 'D') {
87 | transformLinks = new float[properties.length];
88 | for (int i = 0; i < properties.length; i++) {
89 | transformLinks[i] = (float) properties[i].asDouble();
90 | }
91 | } else {
92 | System.err.println("Invalid UV data type! Expected: double or array of doubles, actual: " + properties[0].dataType);
93 | }
94 | }
95 | }
96 |
97 | public JUMISubDeformer createSubDeformer() {
98 | JUMISubDeformer result = new JUMISubDeformer(name);
99 |
100 | result.indexes = indexes;
101 | result.weights = weights;
102 | result.transforms = transforms;
103 | result.transformLinks = transformLinks;
104 |
105 | return result;
106 | }
107 |
108 | @Override
109 | public void readEmbeddedProperty(FBXProperty[] properties) {
110 |
111 | }
112 |
113 | @Override
114 | public void connect(FBXLimbNodeDefinition inLimbNode) {
115 | limbNode = inLimbNode;
116 | limbNode.cluster = this;
117 | }
118 |
119 | @Override
120 | public void connect(FBXSkinDeformerDefinition inSkinDeformer) {
121 | inSkinDeformer.clusters.add(this);
122 | }
123 |
124 | }
125 |
--------------------------------------------------------------------------------
/src/com/jumi/fbx/objects/definitions/FBXLimbNodeDefinition.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.fbx.objects.definitions;
20 |
21 | import com.jumi.data.Vector3;
22 | import com.jumi.fbx.objects.FBXProperty;
23 | import com.jumi.scene.objects.JUMIBone;
24 | import java.util.ArrayList;
25 |
26 | /**
27 | * FBXLimbNodeDefinition
28 | *
29 | * Container for holding information on the translation and rotation of a bone
30 | *
31 | * @author Richard Greenlees
32 | */
33 | public class FBXLimbNodeDefinition extends FBXObjectDefinition {
34 |
35 | public Vector3 localTranslation = new Vector3(0, 0, 0);
36 | public Vector3 localRotation = new Vector3(0, 0, 0);
37 | public Vector3 localScaling = new Vector3(0, 0, 0);
38 |
39 | public ArrayList children = new ArrayList();
40 | public FBXLimbNodeDefinition parent = null;
41 |
42 | public FBXClusterDefinition cluster = null;
43 |
44 | public boolean isRoot = true;
45 |
46 | public FBXLimbNodeDefinition(long inUID, String inName) {
47 | super(inUID, inName);
48 | }
49 |
50 | public FBXLimbNodeDefinition(long inUID) {
51 | super(inUID);
52 | }
53 |
54 | public JUMIBone createSkeleton() {
55 | JUMIBone result = getRoot().createBone();
56 | createBoneHierarchy(result);
57 | return result;
58 | }
59 |
60 | public void createBoneHierarchy(JUMIBone parent) {
61 | for (FBXLimbNodeDefinition child : children) {
62 | JUMIBone newBone = child.createBone();
63 | newBone.setParent(parent);
64 | parent.addChild(newBone);
65 | child.createBoneHierarchy(newBone);
66 | }
67 | }
68 |
69 | public void createChildBones(JUMIBone parent) {
70 | for (FBXLimbNodeDefinition a : children) {
71 | parent.addChild(a.createBone());
72 | }
73 | }
74 |
75 | public void createDescendantBones(JUMIBone parent) {
76 |
77 | }
78 |
79 | public void readNestedObject(String nestedName, FBXProperty[] properties) {
80 |
81 | }
82 |
83 | public void setName(String newName) {
84 | super.setName(newName);
85 | }
86 |
87 | public void readEmbeddedProperty(FBXProperty[] properties) {
88 | String propertyName = properties[0].asString();
89 |
90 | if (propertyName.equals("Lcl Translation")) {
91 | float x = properties[properties.length - 3].asFloat();
92 | float y = properties[properties.length - 2].asFloat();
93 | float z = properties[properties.length - 1].asFloat();
94 |
95 | localTranslation.set(x, y, z);
96 | } else if (propertyName.equals("Lcl Rotation")) {
97 | float x = properties[properties.length - 3].asFloat();
98 | float y = properties[properties.length - 2].asFloat();
99 | float z = properties[properties.length - 1].asFloat();
100 |
101 | localRotation.set(x, y, z);
102 | } else if (propertyName.equals("Lcl Scaling")) {
103 | float x = properties[properties.length - 3].asFloat();
104 | float y = properties[properties.length - 2].asFloat();
105 | float z = properties[properties.length - 1].asFloat();
106 |
107 | localScaling.set(x, y, z);
108 | }
109 | }
110 |
111 | public JUMIBone createBone() {
112 | if (cluster != null) {
113 | return new JUMIBone(name, cluster.indexes, cluster.weights, cluster.transforms, cluster.transformLinks, localTranslation, localRotation, localScaling);
114 | } else {
115 | return new JUMIBone(name, localTranslation, localRotation, localScaling);
116 | }
117 | }
118 |
119 | @Override
120 | public void connect(FBXModelDefinition inModel) {
121 | //System.out.println("Joining this Limb Node " + name + " to Model " + inModel.name);
122 | inModel.rootNode = this;
123 | }
124 |
125 | public void connect(FBXLimbNodeDefinition inLimbNode) {
126 | //System.out.println("Joining this Limb Node " + name + " to Limb Node " + inLimbNode.name);
127 | inLimbNode.children.add(this);
128 | parent = inLimbNode;
129 | isRoot = false;
130 | }
131 |
132 | @Override
133 | public void connect(FBXTextureDefinition inTexture) {
134 | //System.out.println("Joining this Limb Node " + name + " to Texture " + inTexture.name);
135 | }
136 |
137 | @Override
138 | public void connect(FBXMaterialDefinition inMaterial) {
139 | //System.out.println("Joining this Limb Node " + name + " to Material " + inMaterial.name);
140 | }
141 |
142 | @Override
143 | public void connect(FBXMediaDefinition inMedia) {
144 | //System.out.println("Joining this Limb Node " + name + " to Model " + inMedia.name);
145 | }
146 |
147 | @Override
148 | public void connect(FBXSkinDeformerDefinition inSkinDeformer) {
149 | //System.out.println("Connecting this Limb Node " + name + " to Skin Deformer " + inSkinDeformer.name);
150 | }
151 |
152 | @Override
153 | public void connect(FBXCameraDefinition inCamera) {
154 | //System.out.println("Connecting this Limb Node " + name + " to Camera " + inCamera.name);
155 | }
156 |
157 | @Override
158 | public void connect(FBXShapeDefinition inShape) {
159 | //System.out.println("Connecting this Limb Node " + name + " to Shape Key " + inShape.name);
160 | }
161 |
162 | @Override
163 | public void connect(FBXClusterDefinition inCluster) {
164 | //System.out.println("Connecting this Limb Node " + name + " to Cluster " + inCluster.name);
165 | inCluster.limbNode = this;
166 | cluster = inCluster;
167 | }
168 |
169 | @Override
170 | public void connect(FBXAnimCurveDefinition inAnimCurve) {
171 | //System.out.println("Joining this Limb Node " + name + " to Animation Curve " + inAnimCurve.name);
172 | }
173 |
174 | @Override
175 | public void connect(FBXAnimCurveNodeDefinition inAnimCurveNode) {
176 | //System.out.println("Joining this Limb Node " + name + " to Animation Curve Node " + inAnimCurveNode.name);
177 | }
178 |
179 | @Override
180 | public void connect(FBXAnimLayerDefinition inAnimLayer) {
181 | //System.out.println("Joining this Limb Node " + name + " to Animation Layer " + inAnimLayer.name);
182 | }
183 |
184 | @Override
185 | public void connect(FBXAnimStackDefinition inAnimStack) {
186 | //System.out.println("Joining this Limb Node " + name + " to Animation Stack " + inAnimStack.name);
187 | }
188 |
189 | public String toString() {
190 | return "Limb Node: " + name + "\n\tTranslation: " + localTranslation + "\n\tRotation: " + localRotation + "\n\tScaling: " + localScaling;
191 | }
192 |
193 | public FBXLimbNodeDefinition getRoot() {
194 | if (isRoot || parent == null) {
195 | return this;
196 | } else {
197 | return parent.getRoot();
198 | }
199 | }
200 |
201 | public void printSkeleton() {
202 | if (isRoot || parent == null) {
203 | printNodeRecursive(0);
204 | } else {
205 | getRoot().printNodeRecursive(0);
206 | }
207 | }
208 |
209 | public void printNodeRecursive(int level) {
210 | for (int i = 0; i < level; i++) {
211 | System.out.print(" ");
212 | }
213 |
214 | System.out.println("- " + name);
215 |
216 | for (FBXLimbNodeDefinition child : children) {
217 | child.printNodeRecursive(level + 1);
218 | }
219 |
220 | }
221 |
222 | }
223 |
--------------------------------------------------------------------------------
/src/com/jumi/fbx/objects/definitions/FBXMaterialDefinition.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.fbx.objects.definitions;
20 |
21 | import com.jumi.data.Color;
22 | import com.jumi.scene.objects.JUMIMaterial;
23 | import com.jumi.scene.objects.JUMITexture;
24 | import com.jumi.fbx.objects.FBXProperty;
25 | import java.util.ArrayList;
26 |
27 | /**
28 | * FBXMaterialDefinition
29 | *
30 | * Container for holding information on a material.
31 | *
32 | * @author Richard Greenlees
33 | */
34 | public class FBXMaterialDefinition extends FBXObjectDefinition {
35 |
36 | public Color ambientColor = new Color(1.f, 1.f, 1.f);
37 | public Color diffuseColor = new Color(1.f, 1.f, 1.f);
38 | public Color specularColor = new Color(1.f, 1.f, 1.f);
39 | public Color emissiveColor = new Color(1.f, 1.f, 1.f);
40 |
41 | public float specularFactor = 1.0f;
42 | public float shininessExponent = 1.0f;
43 | public float transparencyFactor = 1.0f;
44 | public float emissiveFactor = 1.0f;
45 | public float reflectionFactor = 1.0f;
46 | public float shininess = 1.0f;
47 | public float reflectivity = 1.0f;
48 | public float opacity = 1.0f;
49 |
50 | public ArrayList textures = new ArrayList();
51 |
52 | public FBXMaterialDefinition(long inUID, String inName) {
53 | super(inUID, inName);
54 | }
55 |
56 | public FBXMaterialDefinition(long inUID) {
57 | super(inUID);
58 | }
59 |
60 | @Override
61 | public void readEmbeddedProperty(FBXProperty[] properties) {
62 | String propertyName = properties[0].asString();
63 | String propertyType = properties[1].asString();
64 |
65 | switch (propertyType) {
66 | case "Color":
67 | case "ColorRGB":
68 | float r = properties[properties.length - 3].asFloat();
69 | float g = properties[properties.length - 2].asFloat();
70 | float b = properties[properties.length - 1].asFloat();
71 |
72 | Color newColor = new Color(r, g, b);
73 |
74 | switch(propertyName) {
75 | case "Ambient":
76 | case "AmbientColor":
77 | ambientColor = newColor; break;
78 | case "Specular":
79 | case "SpecularColor":
80 | specularColor = newColor; break;
81 | case "Diffuse":
82 | case "DiffuseColor":
83 | diffuseColor = newColor; break;
84 | case "Emissive":
85 | case "EmissiveColor":
86 | emissiveColor = newColor; break;
87 | default: break;
88 | }
89 | break;
90 | case "TransparencyFactor":
91 | transparencyFactor = properties[properties.length - 1].asFloat(); break;
92 | case "SpecularFactor":
93 | specularFactor = properties[properties.length - 1].asFloat(); break;
94 | case "ReflectionFactor":
95 | reflectionFactor = properties[properties.length - 1].asFloat(); break;
96 | case "Shininess":
97 | shininess = properties[properties.length - 1].asFloat(); break;
98 | case "Opacity":
99 | opacity = properties[properties.length - 1].asFloat(); break;
100 | case "Reflectivity":
101 | reflectivity = properties[properties.length - 1].asFloat(); break;
102 | default: break;
103 | }
104 | }
105 |
106 | @Override
107 | public void readNestedObject(String nestedName, FBXProperty[] properties) {
108 |
109 | }
110 |
111 | public JUMIMaterial createMaterial() {
112 | JUMIMaterial result = new JUMIMaterial();
113 |
114 | result.name = name;
115 | result.ambientColor = ambientColor;
116 | result.diffuseColor = diffuseColor;
117 | result.emissiveColor = emissiveColor;
118 | result.emissiveFactor = emissiveFactor;
119 | result.opacity = opacity;
120 | result.reflectionFactor = reflectionFactor;
121 | result.reflectivity = reflectivity;
122 | result.shininess = shininess;
123 | result.shininessExponent = shininessExponent;
124 | result.specularColor = specularColor;
125 | result.specularFactor = specularFactor;
126 | result.transparencyFactor = transparencyFactor;
127 |
128 | result.textures = new JUMITexture[textures.size()];
129 |
130 | for (int i = 0; i < textures.size(); i++) {
131 | result.textures[i] = textures.get(i).createTexture();
132 | }
133 | return result;
134 | }
135 |
136 | @Override
137 | public void connect(FBXModelDefinition inModel) {
138 | inModel.addMaterialDefinition(this);
139 | }
140 |
141 | @Override
142 | public void connect(FBXTextureDefinition inTexture) {
143 | textures.add(inTexture);
144 | }
145 |
146 | }
147 |
--------------------------------------------------------------------------------
/src/com/jumi/fbx/objects/definitions/FBXMediaDefinition.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.fbx.objects.definitions;
20 |
21 | import com.jumi.fbx.objects.FBXProperty;
22 |
23 | /**
24 | * FBXMediaDefinition
25 | *
26 | * Container for holding information on a texture file. Currently just used for embedded data.
27 | *
28 | * @author Richard Greenlees
29 | */
30 | public class FBXMediaDefinition extends FBXObjectDefinition {
31 |
32 | byte[] content = new byte[0];
33 |
34 | public FBXMediaDefinition(long inUID, String inName) {
35 | super(inUID, inName);
36 | }
37 |
38 | public FBXMediaDefinition(long inUID) {
39 | super(inUID);
40 | }
41 |
42 | public void readNestedObject(String nestedName, FBXProperty[] properties) {
43 | if (nestedName.equals("Content")) {
44 | if (properties.length > 0) {
45 | content = properties[0].asByteArray();
46 | }
47 | }
48 | }
49 |
50 | public void readEmbeddedProperty(FBXProperty[] properties) {
51 |
52 | }
53 |
54 | @Override
55 | public void connect(FBXTextureDefinition inTexture) {
56 | if (content != null && content.length > 0) {
57 | inTexture.textureData = content;
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/com/jumi/fbx/objects/definitions/FBXModelDefinition.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.fbx.objects.definitions;
20 |
21 | import com.jumi.scene.objects.JUMIMaterial;
22 | import com.jumi.scene.objects.JUMIMesh;
23 | import com.jumi.scene.objects.JUMIMesh.FaceType;
24 | import com.jumi.scene.objects.JUMITexture;
25 | import com.jumi.fbx.objects.FBXProperty;
26 | import java.util.ArrayList;
27 |
28 | /**
29 | * FBXModelDefinition
30 | *
31 | * Container for model information. A model can either be a geometry definition, or contain other data like
32 | * local translation/rotation etc. Models can be joined in hierarchies, but the final JUMIMesh will flatten
33 | * it into a single JUMIMesh object, merging the various models together.
34 | *
35 | * @author Richard Greenlees
36 | */
37 | public class FBXModelDefinition extends FBXObjectDefinition {
38 |
39 | public FaceType faceType = FaceType.NONE;
40 |
41 | public float[] vertices = new float[0];
42 | public float[] normals = new float[0];
43 | public float[] uvs = new float[0];
44 | public int[] UVIndices = new int[0];
45 | public int[] indices = new int[0];
46 | public int[] edges = new int[0];
47 | public float[] binormals = new float[0];
48 |
49 | public boolean bDiscard;
50 |
51 | public ArrayList textures = new ArrayList();
52 | public ArrayList materials = new ArrayList();
53 | public ArrayList models = new ArrayList();
54 | public FBXSkinDeformerDefinition deformer = null;
55 |
56 | public FBXLimbNodeDefinition rootNode = null;
57 |
58 | public FBXModelDefinition parent = null;
59 |
60 | public FBXModelDefinition(long inUID, String inName) {
61 | super(inUID, inName);
62 | }
63 |
64 | public FBXModelDefinition(long inUID) {
65 | super(inUID);
66 | }
67 |
68 | public boolean isRoot() {
69 | return (parent == null);
70 | }
71 |
72 | public void readNestedObject(String nestedName, FBXProperty[] properties) {
73 | switch (nestedName) {
74 | // Vertex information
75 | case "Vertices":
76 | // Just to make life difficult, some models express vertices as a single array of doubles (correct),
77 | // and some express them as a load of individual double primitives (BAD!). Should provide support for both I guess
78 | if (properties[0].typeCode == 'd') {
79 | vertices = properties[0].asFloatArray();
80 | } else if (properties[0].typeCode == 'D') {
81 | vertices = new float[properties.length];
82 | for (int i = 0; i < properties.length; i++) {
83 | vertices[i] = (float) properties[i].asDouble();
84 | }
85 | } else {
86 | // Vertices should be either a tonne of individual double values or an array of doubles. Anything else just ain't right
87 | System.err.println("Invalid vertex data type! Expected: double or array of doubles, actual: " + properties[0].dataType);
88 | } break;
89 | case "Normals":
90 | // Same as vertices, normals can either be an array or lots of single doubles
91 | if (properties[0].typeCode == 'd') {
92 | normals = properties[0].asFloatArray();
93 | } else if (properties[0].typeCode == 'D') {
94 | normals = new float[properties.length];
95 | for (int i = 0; i < properties.length; i++) {
96 | normals[i] = (float) properties[i].asDouble();
97 | }
98 | } else {
99 | System.err.println("Invalid normal data type! Expected: double or array of doubles, actual: " + properties[0].dataType);
100 | } break;
101 | // Indices
102 | case "PolygonVertexIndex":
103 | // Same as vertices, indices can either be an array or lots of single integers
104 | if (properties[0].typeCode == 'i' || properties[0].typeCode == 'f') {
105 | indices = properties[0].asIntArray();
106 | } else if (properties[0].typeCode == 'I' || properties[0].typeCode == 'F') {
107 | indices = new int[properties.length];
108 | for (int i = 0; i < properties.length; i++) {
109 | indices[i] = properties[i].asInteger();
110 | }
111 | } else {
112 | System.err.println("Invalid indices data type! Expected: integer or array of integers, actual: " + properties[0].dataType);
113 | } int faceSize = 0;
114 | for (int i = 0; i < indices.length; i++) {
115 | if (indices[i] < 0) {
116 | // FBX denotes the end of a single face with a negated index, so we need to restore it
117 | indices[i] = ~indices[i];
118 | // If we don't know whether we're working with QUADS or TRIANGLES yet, we do now!
119 | if (faceSize == 0) {
120 | faceSize = i + 1;
121 | }
122 | }
123 | } if (faceSize == 3) {
124 | faceType = JUMIMesh.FaceType.TRIANGLES;
125 | } else if (faceSize == 4) {
126 | faceType = JUMIMesh.FaceType.QUADS;
127 | } break;
128 | // TODO: Add something in case we're dealing with polygons or some other rubbish
129 | case "UV":
130 | // See my comments for vertices/normals
131 | if (properties[0].typeCode == 'd') {
132 | uvs = properties[0].asFloatArray();
133 | } else if (properties[0].typeCode == 'D') {
134 | uvs = new float[properties.length];
135 | for (int i = 0; i < properties.length; i++) {
136 | uvs[i] = (float) properties[i].asDouble();
137 | }
138 | } else {
139 | System.err.println("Invalid UV data type! Expected: double or array of doubles, actual: " + properties[0].dataType);
140 | } break;
141 | case "UVIndex":
142 | // See my comments for vertices/normals
143 | if (properties[0].typeCode == 'i' || properties[0].typeCode == 'f') {
144 | UVIndices = properties[0].asIntArray();
145 | } else if (properties[0].typeCode == 'I' || properties[0].typeCode == 'F') {
146 | UVIndices = new int[properties.length];
147 | for (int i = 0; i < properties.length; i++) {
148 | UVIndices[i] = properties[i].asInteger();
149 | }
150 | } else {
151 | System.err.println("Invalid UV indices data type! Expected: integer or array of integers, actual: " + properties[0].dataType);
152 | } break;
153 | }
154 | }
155 |
156 | public void addChildModel(FBXModelDefinition newChild) {
157 | models.add(newChild);
158 | }
159 |
160 | @Override
161 | public void readEmbeddedProperty(FBXProperty[] properties) {
162 |
163 | }
164 |
165 | public boolean containsGeometryDefinition() {
166 | return findMeshData() != null;
167 | }
168 |
169 | public boolean hasGeometry() {
170 | return (vertices != null && vertices.length > 0);
171 | }
172 |
173 | public void addMaterialDefinition(FBXMaterialDefinition newMat) {
174 | materials.add(newMat);
175 | }
176 |
177 | public void connect(FBXModelDefinition inModel) {
178 | inModel.addChildModel(this);
179 | parent = inModel;
180 | }
181 |
182 | public void connect(FBXTextureDefinition inTexture) {
183 | textures.add(inTexture);
184 | }
185 |
186 | @Override
187 | public void connect(FBXMaterialDefinition inMaterial) {
188 | materials.add(inMaterial);
189 | }
190 |
191 | public void connect(FBXLimbNodeDefinition inLimbNode) {
192 | rootNode = inLimbNode;
193 | }
194 |
195 | @Override
196 | public void connect(FBXSkinDeformerDefinition inSkinDeformer) {
197 | deformer = inSkinDeformer;
198 | }
199 |
200 | /* UVs are expressed as indices referencing the doubles we extracted. Why make things simple when they can be needlessly complex? */
201 | private float[] generateUVs() {
202 | if (UVIndices == null || UVIndices.length == 0) {
203 | return uvs;
204 | } else {
205 | float[] uvResult = new float[UVIndices.length * 2];
206 |
207 | for (int i = 0; i < indices.length; i++) {
208 | uvResult[indices[i] * 2] = uvs[UVIndices[i] * 2];
209 | uvResult[indices[i] * 2 + 1] = uvs[UVIndices[i] * 2 + 1];
210 | }
211 |
212 | return uvResult;
213 | }
214 | }
215 |
216 | /** Check this model and its children to find where we're keeping our geometry data */
217 | public FBXModelDefinition findMeshData() {
218 | FBXModelDefinition result = null;
219 | if (this.hasGeometry()) {
220 | result = this;
221 | } else {
222 | for (FBXModelDefinition a : models) {
223 | result = a.findMeshData();
224 | if (result != null) {
225 | break;
226 | }
227 | }
228 | }
229 | return result;
230 | }
231 |
232 | /** Do we have a root bone and if so, what is it? */
233 | public FBXLimbNodeDefinition findRootNode() {
234 | FBXLimbNodeDefinition result = null;
235 | if (rootNode != null) {
236 | return rootNode;
237 | } else {
238 | for (FBXModelDefinition a : models) {
239 | if (a.deformer != null) {
240 | return a.deformer.getRootNode();
241 | }
242 | }
243 | }
244 | return result;
245 | }
246 |
247 | public void buildMaterialList(ArrayList list) {
248 | for (FBXMaterialDefinition a : materials) {
249 | list.add(a);
250 | }
251 |
252 | for (FBXModelDefinition a : models) {
253 | a.buildMaterialList(list);
254 | }
255 | }
256 |
257 | public void buildTextureList(ArrayList list) {
258 | for (FBXTextureDefinition a : textures) {
259 | list.add(a);
260 | }
261 |
262 | for (FBXModelDefinition a : models) {
263 | a.buildTextureList(list);
264 | }
265 | }
266 |
267 | /** Generate a JUMIMesh using this model definition */
268 | public JUMIMesh createMesh() {
269 | JUMIMesh result = new JUMIMesh(name);
270 |
271 | FBXModelDefinition meshData = findMeshData();
272 | FBXLimbNodeDefinition rootNode = findRootNode();
273 |
274 | result.vertices = meshData.vertices;
275 | result.normals = meshData.normals;
276 | result.binormals = meshData.binormals;
277 | result.indices = meshData.indices;
278 | result.uvs = meshData.generateUVs();
279 | result.edges = meshData.edges;
280 | result.faceType = meshData.faceType;
281 |
282 | ArrayList textureList = new ArrayList();
283 | buildTextureList(textureList);
284 | result.textures = new JUMITexture[textureList.size()];
285 |
286 | for (int i = 0; i < textures.size(); i++) {
287 | result.textures[i] = textureList.get(i).createTexture();
288 | }
289 |
290 | ArrayList materialList = new ArrayList();
291 | buildMaterialList(materialList);
292 |
293 | result.materials = new JUMIMaterial[materialList.size()];
294 |
295 | for (int i = 0; i < materialList.size(); i++) {
296 |
297 | result.materials[i] = materialList.get(i).createMaterial();
298 | }
299 |
300 | if (rootNode != null) {
301 | result.rootBone = rootNode.createSkeleton();
302 | }
303 |
304 |
305 | return result;
306 | }
307 |
308 | }
309 |
--------------------------------------------------------------------------------
/src/com/jumi/fbx/objects/definitions/FBXObjectDefinition.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.fbx.objects.definitions;
20 |
21 | import com.jumi.fbx.objects.FBXProperty;
22 | import com.jumi.fbx.node.FBXNode;
23 | import java.nio.ByteBuffer;
24 | import java.nio.ByteOrder;
25 |
26 | /**
27 | * FBXObjectDefinition
28 | *
29 | * Base class for all object definitions. Contains hooks for connecting them to each other and for parsing data.
30 | * Please note this is still in a rough shape, but it seems to work which is always useful.
31 | *
32 | * @author Richard Greenlees
33 | */
34 | public abstract class FBXObjectDefinition {
35 | public long UID;
36 | public String name;
37 | public int endOffset;
38 |
39 | public FBXObjectDefinition(long inUID, String inName) {
40 | UID = inUID;
41 | if (inName.equals("")) {
42 | name = "NULL";
43 | } else {
44 | name = inName;
45 | }
46 | }
47 |
48 | public FBXObjectDefinition(long inUID) {
49 | UID = inUID;
50 | name = "NULL";
51 | }
52 |
53 | public void setName(String newName) {
54 | name = newName;
55 | }
56 |
57 | public final void parseData(byte[] inputData, int startPosition) {
58 | endOffset = startPosition;
59 |
60 | byte scope = 1;
61 |
62 | while (scope > 0) {
63 | int nestedNameLength = inputData[endOffset + 12];
64 | byte[] nestedNameData = FBXNode.retrieveBytesFrom(inputData, nestedNameLength, endOffset + 13);
65 | String nestedName = new String(nestedNameData);
66 |
67 | byte[] numPropertiesData = FBXNode.retrieveBytesFrom(inputData, 4, endOffset + 4);
68 |
69 | int numProperties = ByteBuffer.wrap(numPropertiesData).order(ByteOrder.LITTLE_ENDIAN).getInt();
70 |
71 | endOffset += nestedNameLength + 13;
72 |
73 | if (nestedName.equals("")) {
74 | scope--;
75 | if (scope <= 0) {
76 | break;
77 | }
78 | } else {
79 |
80 | // TODO: Figure out a better way of deciding which nested nodes contain MORE nested nodes.
81 | // Tracking the size of each nested element vs. its properties doesn't seem to be reliable
82 | if (nestedName.equals("Properties60")
83 | || nestedName.equals("Properties70")
84 | || nestedName.equals("LayerElementUV")
85 | || nestedName.equals("LayerElementMaterial")
86 | || nestedName.equals("LayerElementTexture")
87 | || nestedName.equals("Layer")
88 | || nestedName.equals("LayerElement")
89 | || nestedName.equals("LayerElementBinormal")
90 | || nestedName.equals("LayerElementNormal")
91 | || nestedName.equals("LayerElementTangent")
92 | || nestedName.equals("LayerElementSmoothing")
93 | || nestedName.equals("LayerElementColor")
94 | || nestedName.equals("LayerElementVisibility")) {
95 | scope++;
96 | }
97 |
98 | }
99 |
100 | FBXProperty[] properties = new FBXProperty[numProperties];
101 |
102 | // Get all the properties this nested item contains
103 | for (int i = 0; i < properties.length; i++) {
104 | FBXProperty newProp = new FBXProperty(inputData, endOffset);
105 | endOffset += newProp.dataLength;
106 | properties[i] = newProp;
107 | }
108 |
109 | // "P" or "Property" means we're inside a Properties60 or Properties70 node, so it's an embedded property
110 | if (nestedName.equals("P") || nestedName.equals("Property")) {
111 | readEmbeddedProperty(properties);
112 | } else {
113 | readNestedObject(nestedName, properties);
114 | }
115 |
116 | }
117 | }
118 |
119 | /** Called every time a new nested node is parsed */
120 | protected abstract void readNestedObject(String nestedName, FBXProperty[] properties);
121 |
122 | /** Called whenever an embedded property (via Properties60 or Properties70) is encountered */
123 | protected abstract void readEmbeddedProperty(FBXProperty[] properties);
124 |
125 | public void connect(FBXModelDefinition inModel) {
126 |
127 | }
128 |
129 | public void connect(FBXTextureDefinition inTexture) {
130 |
131 | }
132 |
133 | public void connect(FBXMaterialDefinition inMaterial) {
134 |
135 | }
136 |
137 | public void connect(FBXMediaDefinition inMedia) {
138 |
139 | }
140 |
141 | public void connect(FBXLimbNodeDefinition inLimbNode) {
142 |
143 | }
144 |
145 | public void connect(FBXSkinDeformerDefinition inSkinDeformer) {
146 |
147 | }
148 |
149 | public void connect(FBXCameraDefinition inCamera) {
150 |
151 | }
152 |
153 | public void connect(FBXShapeDefinition inShape) {
154 |
155 | }
156 |
157 | public void connect(FBXClusterDefinition inCluster) {
158 |
159 | }
160 |
161 | public void connect(FBXAnimCurveDefinition inAnimCurve) {
162 |
163 | }
164 |
165 | public void connect(FBXAnimCurveNodeDefinition inAnimCurveNode) {
166 |
167 | }
168 |
169 | public void connect(FBXAnimLayerDefinition inAnimLayer) {
170 |
171 | }
172 |
173 | public void connect(FBXAnimStackDefinition inAnimStack) {
174 |
175 | }
176 |
177 | // TODO: Sort this mess out. Quick hack until I'm happy with how everything connects up and put a proper process together
178 | public void connect(FBXObjectDefinition inObject) {
179 | if (inObject instanceof FBXModelDefinition) {
180 | connect((FBXModelDefinition) inObject);
181 | } else if (inObject instanceof FBXTextureDefinition) {
182 | connect((FBXTextureDefinition) inObject);
183 | } else if (inObject instanceof FBXMediaDefinition) {
184 | connect((FBXMediaDefinition) inObject);
185 | } else if (inObject instanceof FBXMaterialDefinition) {
186 | connect((FBXMaterialDefinition) inObject);
187 | } else if (inObject instanceof FBXLimbNodeDefinition) {
188 | connect((FBXLimbNodeDefinition) inObject);
189 | } else if (inObject instanceof FBXSkinDeformerDefinition) {
190 | connect((FBXSkinDeformerDefinition) inObject);
191 | } else if (inObject instanceof FBXCameraDefinition) {
192 | connect((FBXCameraDefinition) inObject);
193 | } else if (inObject instanceof FBXShapeDefinition) {
194 | connect((FBXShapeDefinition) inObject);
195 | } else if (inObject instanceof FBXClusterDefinition) {
196 | connect((FBXClusterDefinition) inObject);
197 | } else if (inObject instanceof FBXAnimCurveDefinition) {
198 | connect((FBXAnimCurveDefinition) inObject);
199 | } else if (inObject instanceof FBXAnimCurveNodeDefinition) {
200 | connect((FBXAnimCurveNodeDefinition) inObject);
201 | } else if (inObject instanceof FBXAnimLayerDefinition) {
202 | connect((FBXAnimLayerDefinition) inObject);
203 | } else if (inObject instanceof FBXAnimStackDefinition) {
204 | connect((FBXAnimStackDefinition) inObject);
205 | }
206 | }
207 |
208 | public final boolean hasUID() {
209 | return UID > 0;
210 | }
211 | }
212 |
--------------------------------------------------------------------------------
/src/com/jumi/fbx/objects/definitions/FBXShapeDefinition.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.fbx.objects.definitions;
20 |
21 | import com.jumi.fbx.objects.FBXProperty;
22 |
23 | /**
24 | * FBXShapeDefinition
25 | *
26 | * Container for holding information on a morph target. Not currently in use.
27 | *
28 | * @author RGreenlees
29 | */
30 | public class FBXShapeDefinition extends FBXObjectDefinition {
31 |
32 | public FBXShapeDefinition(long inUID, String inName) {
33 | super(inUID, inName);
34 | }
35 |
36 | public FBXShapeDefinition(long inUID) {
37 | super(inUID);
38 | }
39 |
40 | @Override
41 | public void readNestedObject(String nestedName, FBXProperty[] properties) {
42 |
43 | }
44 |
45 | @Override
46 | public void readEmbeddedProperty(FBXProperty[] properties) {
47 |
48 | }
49 |
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/com/jumi/fbx/objects/definitions/FBXSkinDeformerDefinition.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.fbx.objects.definitions;
20 |
21 | import com.jumi.scene.objects.JUMISkinDeformer;
22 | import com.jumi.scene.objects.JUMISubDeformer;
23 | import com.jumi.fbx.objects.FBXProperty;
24 | import java.util.ArrayList;
25 |
26 | /**
27 | * FBXSkinDeformerDefinition
28 | *
29 | * Container for holding information on a model's skin.
30 | *
31 | * @author Richard Greenlees
32 | */
33 | public class FBXSkinDeformerDefinition extends FBXObjectDefinition {
34 |
35 | public float linkDeformAccuracy = 0.f;
36 |
37 | public ArrayList clusters = new ArrayList();
38 |
39 | public FBXSkinDeformerDefinition(long inUID, String inName) {
40 | super(inUID, inName);
41 | }
42 |
43 | public FBXSkinDeformerDefinition(long inUID) {
44 | super(inUID);
45 | }
46 |
47 | @Override
48 | public void readNestedObject(String nestedName, FBXProperty[] properties) {
49 | if (nestedName.equals("Link_DeformAcuracy")) {
50 | linkDeformAccuracy = properties[0].asLong();
51 | }
52 | }
53 |
54 | @Override
55 | public void readEmbeddedProperty(FBXProperty[] properties) {
56 |
57 | }
58 |
59 | public FBXLimbNodeDefinition getRootNode() {
60 | for (FBXClusterDefinition a : clusters) {
61 | if (a.limbNode != null) {
62 | return a.limbNode.getRoot();
63 | }
64 | }
65 | return null;
66 | }
67 |
68 | public JUMISkinDeformer createSkinDeformer() {
69 | JUMISkinDeformer result = new JUMISkinDeformer(name);
70 |
71 | result.deformers = new JUMISubDeformer[clusters.size()];
72 |
73 | for (int i = 0; i < clusters.size(); i++) {
74 | result.deformers[i] = clusters.get(i).createSubDeformer();
75 | }
76 |
77 | return result;
78 | }
79 |
80 | @Override
81 | public void connect(FBXModelDefinition inModel) {
82 | inModel.deformer = this;
83 | }
84 |
85 | @Override
86 | public void connect(FBXClusterDefinition inCluster) {
87 | clusters.add(inCluster);
88 | }
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/src/com/jumi/fbx/objects/definitions/FBXTextureDefinition.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.fbx.objects.definitions;
20 |
21 | import com.jumi.scene.objects.JUMITexture;
22 | import com.jumi.fbx.objects.FBXProperty;
23 |
24 | /**
25 | * FBXTextureDefinition
26 | *
27 | * Container for holding information on a texture definition.
28 | *
29 | * @author Richard Greenlees
30 | */
31 | public class FBXTextureDefinition extends FBXObjectDefinition {
32 |
33 | public String textureName = "";
34 | public String fileLocation = "";
35 |
36 | public String mediaType = "";
37 | public String fileName = "";
38 | public String relativeFilename = "";
39 |
40 | public byte[] textureData = new byte[0];
41 |
42 | public FBXObjectDefinition parent = null;
43 |
44 | public FBXTextureDefinition(long inUID, String inName) {
45 | super(inUID, inName);
46 | }
47 |
48 | public FBXTextureDefinition(long inUID) {
49 | super(inUID);
50 | }
51 |
52 | public void readNestedObject(String nestedName, FBXProperty[] properties) {
53 | if (nestedName.equals("Type")) {
54 | mediaType = properties[0].asString();
55 | } else if (nestedName.equals("TextureName")) {
56 | textureName = properties[0].asString().substring(0, properties[0].asString().indexOf('\0'));
57 | } else if (nestedName.equals("FileName")) {
58 | fileName = properties[0].asString();
59 | } else if (nestedName.equals("RelativeFilename")) {
60 | relativeFilename = properties[0].asString();
61 | }
62 | }
63 |
64 | public void readEmbeddedProperty(FBXProperty[] properties) {
65 |
66 | }
67 |
68 | public JUMITexture createTexture() {
69 | JUMITexture result = new JUMITexture();
70 | result.name = name;
71 | result.fullFilePath = fileName;
72 | result.relativeFilename = relativeFilename;
73 | result.fileName = fileName.substring(fileName.lastIndexOf("\\") + 1, fileName.length());
74 | result.setTextureData(textureData);
75 | return result;
76 | }
77 |
78 | @Override
79 | public void connect(FBXModelDefinition inModel) {
80 | inModel.textures.add(this);
81 | parent = inModel;
82 | }
83 |
84 | @Override
85 | public void connect(FBXTextureDefinition inTexture) {
86 | parent = inTexture;
87 | }
88 |
89 | public void connect(FBXLimbNodeDefinition inLimbNode) {
90 | parent = inLimbNode;
91 | }
92 |
93 | @Override
94 | public void connect(FBXMaterialDefinition inMaterial) {
95 | inMaterial.textures.add(this);
96 | parent = inMaterial;
97 | }
98 |
99 | @Override
100 | public void connect(FBXMediaDefinition inMedia) {
101 | if (inMedia.content != null && inMedia.content.length > 0) {
102 | textureData = inMedia.content;
103 | }
104 | parent = inMedia;
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/com/jumi/obj/OBJLoader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.obj;
20 |
21 | import com.jumi.JUMILoader;
22 | import com.jumi.data.Vector2;
23 | import com.jumi.data.Vector3;
24 | import com.jumi.obj.objects.definitions.OBJMatLibDefinition;
25 | import com.jumi.obj.objects.definitions.OBJModelDefinition;
26 | import com.jumi.scene.JUMIScene;
27 | import com.jumi.scene.objects.JUMIMesh;
28 | import java.io.BufferedReader;
29 | import java.io.FileNotFoundException;
30 | import java.io.FileReader;
31 | import java.io.IOException;
32 | import java.util.ArrayList;
33 |
34 | /**
35 | *
36 | * @author RGreenlees
37 | */
38 | public class OBJLoader extends JUMILoader {
39 |
40 | public static JUMIScene importModel(String fileName) throws IOException {
41 | ArrayList vertices = new ArrayList();
42 | ArrayList normals = new ArrayList();
43 | ArrayList uvs = new ArrayList();
44 | ArrayList modelContexts = new ArrayList();
45 |
46 | OBJMatLibDefinition materialLibrary = null;
47 |
48 | BufferedReader reader = null;
49 |
50 | OBJModelDefinition defaultModel = new OBJModelDefinition("default");
51 | modelContexts.add(defaultModel);
52 | OBJModelDefinition currentModelContext = defaultModel;
53 |
54 | try {
55 | reader = new BufferedReader(new FileReader(fileName));
56 | String line;
57 |
58 | while ((line = reader.readLine()) != null) {
59 | // Split up the string by space or tab
60 | String[] lineTokens = line.split("\\s+");
61 |
62 | // Obviously ignore blank lines
63 | if (lineTokens.length == 0) {
64 | continue;
65 | }
66 |
67 | // Make sure we remove leading/trailing white space!
68 | switch (lineTokens[0].trim()) {
69 | case "mtllib": // Define our material library
70 | // Some OBJ files like to include hard-coded paths, let's get rid of that and get just the name of the file
71 | String libName = line.substring(line.indexOf(" ") + 1, line.length()).replace("\\", "/");
72 |
73 | if (libName.contains("/")) {
74 | libName = libName.substring(libName.lastIndexOf("/") + 1, libName.length());
75 | }
76 |
77 | // Look for our MTL file in the same folder as the OBJ file
78 | String libLocation = fileName.substring(0, fileName.lastIndexOf("/") + 1) + libName;
79 | try {
80 | // Create the material library and parse the MTL file separately
81 | materialLibrary = new OBJMatLibDefinition();
82 | materialLibrary.parseMTL(libLocation);
83 | } catch (FileNotFoundException e) {
84 | System.err.println("WARNING: Could not find requested material file " + libLocation);
85 | } catch (IOException e) {
86 | System.out.println("WARNING: Error while parsing requested material file " + libLocation);
87 | }
88 | break;
89 | case "V":
90 | case "v":
91 | // OBJ indices refer to the vertices/UVs/normals as groups of 3, so let's do the same
92 | vertices.add(new Vector3(Float.valueOf(lineTokens[1]), Float.valueOf(lineTokens[2]), Float.valueOf(lineTokens[3])));
93 | break;
94 | case "VN":
95 | case "vn":
96 | // OBJ indices refer to the vertices/UVs/normals as groups of 3, so let's do the same
97 | normals.add(new Vector3(Float.valueOf(lineTokens[1]), Float.valueOf(lineTokens[2]), Float.valueOf(lineTokens[3])));
98 | break;
99 | case "VT":
100 | case "vt":
101 | // OBJ indices refer to the vertices/UVs/normals as groups of 3, so let's do the same
102 | uvs.add(new Vector2(Float.valueOf(lineTokens[1]), Float.valueOf(lineTokens[2])));
103 | break;
104 | case "F":
105 | case "f":
106 | // Only allow support for Triangles or Quads for now
107 | if (lineTokens.length > 5 || lineTokens.length < 4) {
108 | System.err.println("Invalid face definition! Expected 3 (Triangles) or 4 (Quads), actual = " + (lineTokens.length - 1));
109 | } else {
110 | // Some OBJ models use relative positions (negative indices). The aim here is to convert them to regular face definitions
111 | // First check if we have a negative index
112 | if (lineTokens[1].charAt(0) == '-') {
113 | for (int i = 1; i < lineTokens.length; i++) {
114 | // Split the face definition, we're going to redefine each index
115 | String[] lineToken = lineTokens[i].split("/");
116 |
117 | // Check that model has UVs and normals defined before converting them
118 | int vIndex = Integer.valueOf(lineToken[0]);
119 | int vtIndex = (lineToken.length > 1 && !lineToken[1].equals("")) ? Integer.valueOf(lineToken[1]) : 0;
120 | int nIndex = (lineToken.length > 2 && !lineToken[2].equals("")) ? Integer.valueOf(lineToken[2]) : 0;
121 |
122 | // Convert each index as the current number of definitions - index. We use + as the index is negative
123 | // Also add +1 as OBJ definitions go from 1...n while ArrayLists go 0...n
124 | vIndex = vertices.size() + vIndex + 1;
125 | vtIndex = (vtIndex < 0) ? (uvs.size() + vtIndex + 1) : 0;
126 | nIndex = (nIndex < 0) ? (normals.size() + nIndex + 1) : 0;
127 |
128 | // Reconstruct the face definition so it can be processed as normal when constructing the mesh
129 | lineTokens[i] = vIndex + "/" + ((vtIndex > 0) ? vtIndex : "") + "/" + ((nIndex > 0) ? nIndex : "");
130 | }
131 | }
132 |
133 | // If we're dealing with a quad, triangulate it. Some models use a mix of triangles and quads, and it's easier
134 | // to just triangulate everything rather than try and switch back and forth
135 | if (lineTokens.length == 5) {
136 |
137 | currentModelContext.uniqueIndexDefinitions.add(lineTokens[1]);
138 | currentModelContext.uniqueIndexDefinitions.add(lineTokens[2]);
139 | currentModelContext.uniqueIndexDefinitions.add(lineTokens[3]);
140 | currentModelContext.uniqueIndexDefinitions.add(lineTokens[4]);
141 |
142 | currentModelContext.allIndexDefinitions.add(lineTokens[1]);
143 | currentModelContext.allIndexDefinitions.add(lineTokens[2]);
144 | currentModelContext.allIndexDefinitions.add(lineTokens[3]);
145 | currentModelContext.allIndexDefinitions.add(lineTokens[3]);
146 | currentModelContext.allIndexDefinitions.add(lineTokens[4]);
147 | currentModelContext.allIndexDefinitions.add(lineTokens[1]);
148 | } else {
149 | // Keep a separate list of unique index definitions and the actual defined indices. These will be used later
150 | // to create a final indices array
151 | for (int i = 1; i < lineTokens.length; i++) {
152 | currentModelContext.uniqueIndexDefinitions.add(lineTokens[i]);
153 | currentModelContext.allIndexDefinitions.add(lineTokens[i]);
154 | }
155 | }
156 | }
157 |
158 | break;
159 | case "usemtl": // Use a material from the defined library
160 | // Only do stuff if we've already had a material library defined (via mtllib)
161 | if (materialLibrary != null && lineTokens.length > 1) {
162 | currentModelContext.materialDefinitions.add(materialLibrary.getMaterialDefinition(lineTokens[1]));
163 | }
164 | break;
165 | case "O":
166 | case "o":
167 | case "G":
168 | case "g":
169 | // If the group or object has no name defined, give it a default one
170 | String modelContextName = "default";
171 | if (lineTokens.length > 1) {
172 | modelContextName = lineTokens[1];
173 | }
174 |
175 | // First check if we already have a model with that name defined, and use that instead
176 | OBJModelDefinition newContext = null;
177 |
178 | for (OBJModelDefinition a : modelContexts) {
179 | if (a.name.equals(modelContextName)) {
180 | newContext = a;
181 | break;
182 | }
183 | }
184 |
185 | // Otherwise, create a new model and use it
186 | if (newContext == null) {
187 | newContext = new OBJModelDefinition(modelContextName);
188 | modelContexts.add(newContext);
189 | }
190 |
191 | currentModelContext = newContext;
192 |
193 | break;
194 |
195 | }
196 | }
197 | } catch (IOException e) {
198 | e.printStackTrace();
199 | return null;
200 | } finally {
201 | if (reader != null) {
202 | // Don't forget to close the reader!
203 | reader.close();
204 | }
205 | }
206 |
207 | ArrayList allMeshes = new ArrayList();
208 |
209 | JUMIScene result = new JUMIScene();
210 |
211 | // Gather all the models we have defined and turn them into JUMI Meshes for inclusion in the scene
212 | for (OBJModelDefinition a : modelContexts) {
213 | if (a.allIndexDefinitions.size() > 0) {
214 | allMeshes.add(a.createMesh(vertices, normals, uvs));
215 | }
216 | }
217 |
218 |
219 | result.addMeshes(allMeshes);
220 |
221 | return result;
222 |
223 | }
224 |
225 | }
226 |
--------------------------------------------------------------------------------
/src/com/jumi/obj/objects/definitions/OBJMatLibDefinition.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.obj.objects.definitions;
20 |
21 | import com.jumi.data.Color;
22 | import java.io.BufferedReader;
23 | import java.io.FileReader;
24 | import java.io.IOException;
25 | import java.util.ArrayList;
26 |
27 | /**
28 | *
29 | * @author RGreenlees
30 | */
31 | public class OBJMatLibDefinition {
32 |
33 | public ArrayList materials = new ArrayList();
34 | private OBJMaterialDefinition currentMaterial = null;
35 |
36 | public OBJMatLibDefinition() {
37 | super();
38 | }
39 |
40 | // Parses the supplied MTL
41 | public void parseMTL(String mtlLocation) throws IOException {
42 | BufferedReader reader = new BufferedReader(new FileReader(mtlLocation));
43 |
44 | String line;
45 |
46 | while ((line = reader.readLine()) != null) {
47 | String[] lineTokens = line.split(" ");
48 |
49 | if (lineTokens.length == 0) {
50 | continue;
51 | }
52 |
53 | // Get rid of those whitespaces!
54 | switch (lineTokens[0].trim()) {
55 | // New material definition, add it to the list and set it to be the current material
56 | case "newmtl":
57 | if (lineTokens.length > 1) {
58 | OBJMaterialDefinition newMat = new OBJMaterialDefinition(lineTokens[1]);
59 | materials.add(newMat);
60 | currentMaterial = newMat;
61 | }
62 | break;
63 | // Various attributes to be applied to whichever material is current
64 | case "Ka": currentMaterial.ambientColour = new Color(Float.valueOf(lineTokens[1]), Float.valueOf(lineTokens[2]), Float.valueOf(lineTokens[3])); break;
65 | case "Kd": currentMaterial.diffuseColour = new Color(Float.valueOf(lineTokens[1]), Float.valueOf(lineTokens[2]), Float.valueOf(lineTokens[3])); break;
66 | case "Ks": currentMaterial.specularColour = new Color(Float.valueOf(lineTokens[1]), Float.valueOf(lineTokens[2]), Float.valueOf(lineTokens[3])); break;
67 | case "Ns": currentMaterial.specularWeight = Float.valueOf(lineTokens[1]); break;
68 | case "d":
69 | case "Tr": currentMaterial.alpha = Float.valueOf(lineTokens[1]); break;
70 | case "illum": currentMaterial.illum = Integer.valueOf(lineTokens[1]); break;
71 | // Various specific textures like diffuse, specular etc. Take the whole line incase the filename contains spaces
72 | case "map_Ka":
73 | currentMaterial.alphaMap = line.substring(line.indexOf(" ") + 1, line.length());
74 | case "map_Kd":
75 | currentMaterial.diffuseMap = line.substring(line.indexOf(" ") + 1, line.length());
76 | break;
77 | case "map_Ks":
78 | currentMaterial.specularMap = line.substring(line.indexOf(" ") + 1, line.length());
79 | break;
80 | case "map_Ns":
81 | currentMaterial.specularHighlightMap = line.substring(line.indexOf(" ") + 1, line.length());
82 | break;
83 | case "bump":
84 | case "map_bump":
85 | currentMaterial.bumpMap = line.substring(line.indexOf(" ") + 1, line.length());
86 | break;
87 | case "disp":
88 | case "map_disp":
89 | currentMaterial.displaceMap = line.substring(line.indexOf(" ") + 1, line.length());
90 | break;
91 | case "decal":
92 | case "map_decal":
93 | currentMaterial.decalMap = line.substring(line.indexOf(" ") + 1, line.length());
94 | break;
95 | default: break;
96 | }
97 | }
98 | }
99 |
100 | public OBJMaterialDefinition getMaterialDefinition(String matName) {
101 | for (OBJMaterialDefinition a : materials) {
102 | if (a.name.equals(matName)) {
103 | return a;
104 | }
105 | }
106 |
107 | return null;
108 | }
109 |
110 | }
111 |
--------------------------------------------------------------------------------
/src/com/jumi/obj/objects/definitions/OBJMaterialDefinition.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.obj.objects.definitions;
20 |
21 | import com.jumi.data.Color;
22 |
23 | /**
24 | *
25 | * @author RGreenlees
26 | */
27 | public class OBJMaterialDefinition {
28 |
29 | public Color ambientColour = new Color();
30 | public Color diffuseColour = new Color();
31 | public Color specularColour = new Color();
32 |
33 | public float specularWeight = 0.0f;
34 | public float alpha = 1.0f;
35 |
36 | public int illum = 0;
37 |
38 | public String name;
39 | public String ambientMap = "";
40 | public String diffuseMap = "";
41 | public String alphaMap = "";
42 | public String bumpMap = "";
43 | public String displaceMap = "";
44 | public String decalMap = "";
45 | public String specularMap = "";
46 | public String specularHighlightMap = "";
47 |
48 | public OBJMaterialDefinition(String inName) {
49 | super();
50 | name = inName;
51 | }
52 |
53 | public OBJMaterialDefinition() {
54 | super();
55 | name = "NULL";
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/com/jumi/obj/objects/definitions/OBJModelDefinition.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.obj.objects.definitions;
20 |
21 | import com.jumi.data.Vector2;
22 | import com.jumi.data.Vector3;
23 | import com.jumi.scene.objects.JUMIMaterial;
24 | import com.jumi.scene.objects.JUMIMesh;
25 | import com.jumi.scene.objects.JUMIMesh.FaceType;
26 | import com.jumi.scene.objects.JUMITexture;
27 | import java.util.ArrayList;
28 | import java.util.HashMap;
29 | import java.util.HashSet;
30 |
31 | /**
32 | *
33 | * @author RGreenlees
34 | */
35 | public class OBJModelDefinition {
36 |
37 | public String name = "";
38 | public ArrayList materialDefinitions = new ArrayList();
39 |
40 | float[] vertices = new float[0];
41 | float[] normals = new float[0];
42 | float[] uvs = new float[0];
43 | int[] indices = new int[0];
44 |
45 | public HashSet uniqueIndexDefinitions = new HashSet();
46 | public ArrayList allIndexDefinitions = new ArrayList();
47 |
48 | public OBJModelDefinition(String inName) {
49 | super();
50 | name = inName;
51 | }
52 |
53 | /** Generates a JUMIMesh from this OBJModelDefinition
54 | *
55 | * @param vertexPool All the defined vertices for this OBJ
56 | * @param normalPool All the defined normals for this OBJ
57 | * @param uvPool All the defined UVs for this OBJ
58 | * @return
59 | */
60 | public JUMIMesh createMesh(ArrayList vertexPool, ArrayList normalPool, ArrayList uvPool) {
61 | JUMIMesh result = new JUMIMesh(name);
62 |
63 | // We're going to take the total vertices/normals/UVs and divide them up among each JUMIMesh in the scene
64 | ArrayList modelVertices = new ArrayList();
65 | ArrayList modelNormals = new ArrayList();
66 | ArrayList modelUVs = new ArrayList();
67 |
68 | // First create the set of vertices, UVs and normals relevant to this model. Do this using the unique indices associated with it
69 | for (String a : uniqueIndexDefinitions) {
70 | String[] indexDef = a.split("/");
71 | int vindex = Integer.valueOf(indexDef[0]);
72 |
73 | // Retrieve from the wider vertex pool, the vertices for this model. -1 as OBJ goes from 1...n
74 | modelVertices.add(vertexPool.get(vindex - 1));
75 |
76 | // If UVs are defined, retrieve from the wider UV pool the UVs for this model. -1 as OBJ goes from 1...n
77 | if (indexDef.length > 1 && !indexDef[1].equals("")) {
78 | int uvIndex = Integer.valueOf(indexDef[1]);
79 | modelUVs.add(uvPool.get(uvIndex - 1));
80 | }
81 |
82 | // If normals are defined, retrieve from the wider normal pool the normals for this model. -1 as OBJ goes from 1...n
83 | if (indexDef.length > 2 && !indexDef[2].equals("")) {
84 | int nIndex = Integer.valueOf(indexDef[2]);
85 | modelNormals.add(normalPool.get(nIndex - 1));
86 | }
87 | }
88 |
89 | // Create the arrays ready to hold the raw float data
90 | result.vertices = new float[modelVertices.size() * 3];
91 | result.normals = new float[modelNormals.size() * 3];
92 | result.uvs = new float[modelUVs.size() * 2];
93 | result.indices = new int[allIndexDefinitions.size()];
94 |
95 | int arrayCounter = 0;
96 |
97 | // Create a hashmap with each unique face mapped against the order in which it appears. Lookup is MUCH faster than ArrayList for large models
98 | HashMap uniqueIndices = new HashMap();
99 |
100 | for (String a : uniqueIndexDefinitions) {
101 | uniqueIndices.put(a, arrayCounter++);
102 | }
103 |
104 | arrayCounter = 0;
105 |
106 | // For every index defined, retrieve the index within the hashmap to get our final index!
107 | for (String a : allIndexDefinitions) {
108 | result.indices[arrayCounter++] = uniqueIndices.get(a);
109 | }
110 |
111 | arrayCounter = 0;
112 |
113 | // Now populate the raw float data for vertices, UVs and normals (if applicable)
114 | for (Vector3 a : modelVertices) {
115 | result.vertices[arrayCounter++] = a.x;
116 | result.vertices[arrayCounter++] = a.y;
117 | result.vertices[arrayCounter++] = a.z;
118 | }
119 |
120 | arrayCounter = 0;
121 |
122 | for (Vector3 a : modelNormals) {
123 | result.normals[arrayCounter++] = a.x;
124 | result.normals[arrayCounter++] = a.y;
125 | result.normals[arrayCounter++] = a.z;
126 | }
127 |
128 | arrayCounter = 0;
129 |
130 | for (Vector2 a : modelUVs) {
131 | result.uvs[arrayCounter++] = a.x;
132 | result.uvs[arrayCounter++] = a.y;
133 | }
134 |
135 | // Now create all the materials for the mesh
136 | result.materials = new JUMIMaterial[materialDefinitions.size()];
137 |
138 | int materialCounter = 0;
139 |
140 | // TODO: What happens if a .obj references a material by its diffuse map rather than name? (see Ax.obj)
141 | for (OBJMaterialDefinition a : materialDefinitions) {
142 | if (a == null) {
143 | continue;
144 | }
145 | JUMIMaterial newMat = new JUMIMaterial();
146 | newMat.name = a.name;
147 | newMat.ambientColor = a.ambientColour;
148 | newMat.diffuseColor = a.diffuseColour;
149 | newMat.specularColor = a.specularColour;
150 | newMat.specularFactor = a.specularWeight;
151 | newMat.opacity = a.alpha;
152 |
153 | // If a diffuse/specular/normal map is defined, make sure it's included in the JUMIMaterial!
154 | if (!a.diffuseMap.equals("")) {
155 | JUMITexture newTexture = new JUMITexture();
156 | newTexture.fileName = a.diffuseMap;
157 | newTexture.name = a.diffuseMap;
158 | newMat.diffuseTexture = newTexture;
159 | }
160 |
161 | if (!a.specularMap.equals("")) {
162 | JUMITexture newTexture = new JUMITexture();
163 | newTexture.fileName = a.specularMap;
164 | newTexture.name = a.specularMap;
165 | newMat.specularTexture = newTexture;
166 | }
167 |
168 | if (!a.bumpMap.equals("")) {
169 | JUMITexture newTexture = new JUMITexture();
170 | newTexture.fileName = a.bumpMap;
171 | newTexture.name = a.bumpMap;
172 | newMat.normalTexture = newTexture;
173 | }
174 |
175 | result.materials[materialCounter++] = newMat;
176 |
177 | }
178 |
179 | result.faceType = FaceType.TRIANGLES;
180 |
181 | return result;
182 | }
183 |
184 | }
185 |
--------------------------------------------------------------------------------
/src/com/jumi/scene/JUMIScene.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.scene;
20 |
21 |
22 | import com.jumi.scene.objects.JUMIMesh;
23 | import com.jumi.scene.objects.JUMITexture;
24 | import java.util.ArrayList;
25 | import java.util.EnumSet;
26 |
27 | /*
28 | * To change this license header, choose License Headers in Project Properties.
29 | * To change this template file, choose Tools | Templates
30 | * and open the template in the editor.
31 | */
32 | /**
33 | *
34 | * @author RGreenlees
35 | */
36 | public class JUMIScene {
37 |
38 | JUMIMesh[] meshes = new JUMIMesh[0];
39 | JUMITexture[] textures = new JUMITexture[0];
40 |
41 | public static enum MeshAttributes {
42 | VERTICES, NORMALS, TEXTURECOORDINATES, TANGENTS;
43 | EnumSet ALLATTRIBUTES = EnumSet.allOf(MeshAttributes.class);
44 | }
45 |
46 | public void addMeshes(ArrayList newMeshes) {
47 | meshes = new JUMIMesh[newMeshes.size()];
48 | for (int i = 0; i < meshes.length; i++) {
49 | meshes[i] = newMeshes.get(i);
50 | }
51 | }
52 |
53 | public void addTextures(ArrayList newTextures) {
54 | textures = new JUMITexture[newTextures.size()];
55 | for (int i = 0; i < textures.length; i++) {
56 | textures[i] = newTextures.get(i);
57 | }
58 | }
59 |
60 | public JUMIMesh getMeshByName(String name) {
61 | for (JUMIMesh i : meshes) {
62 | if (i.name.equals(name)) {
63 | return i;
64 | }
65 | }
66 | return null;
67 | }
68 |
69 | public JUMIMesh getMeshByIndex(int index) {
70 | if (index >= meshes.length) {
71 | return null;
72 | }
73 | return meshes[index];
74 | }
75 |
76 | public JUMITexture getTextureByIndex(int index) {
77 | if (index >= textures.length) {
78 | return null;
79 | }
80 | return textures[index];
81 | }
82 |
83 | public JUMIMesh[] getAllMeshes() {
84 | return meshes;
85 | }
86 |
87 | public String toString() {
88 | String result = "JUMIScene: " + "\n\tMeshes: ";
89 | for (int i = 0; i < meshes.length; i++) {
90 | result = result + "\n\t\t" + meshes[i].name;
91 | }
92 |
93 | result = result + "\n\tTextures:";
94 |
95 | for (int i = 0; i < textures.length; i++) {
96 | result = result + "\n\t\t" + textures[i].name;
97 | }
98 |
99 | return result;
100 | }
101 |
102 | public int numMeshes() {
103 | return meshes.length;
104 | }
105 |
106 | }
107 |
--------------------------------------------------------------------------------
/src/com/jumi/scene/objects/JUMIBone.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.scene.objects;
20 |
21 | import com.jumi.data.Vector3;
22 | import java.util.ArrayList;
23 |
24 | /**
25 | *
26 | * @author RGreenlees
27 | */
28 | public class JUMIBone {
29 |
30 | private int[] indices = new int[0];
31 | private float[] weights = new float[0];
32 | private float[] transforms = new float[0];
33 | private float[] transformLinks = new float[0];
34 |
35 | private JUMIBone parent;
36 | private final ArrayList children = new ArrayList();
37 |
38 | private Vector3 localTranslation = new Vector3();
39 | private Vector3 localRotation = new Vector3();
40 | private Vector3 localScaling = new Vector3();
41 |
42 | private String name;
43 |
44 | public JUMIBone() {
45 | super();
46 | }
47 |
48 | public JUMIBone(String inName) {
49 | name = inName;
50 | }
51 |
52 | public JUMIBone(String inName, int[] inIndices, float[] inWeights, float[] inTransforms, float[] inTransformLinks, Vector3 inTranslation, Vector3 inRotation, Vector3 inScaling) {
53 | name = inName;
54 | indices = inIndices;
55 | weights = inWeights;
56 | transforms = inTransforms;
57 | transformLinks = inTransformLinks;
58 | localTranslation = inTranslation;
59 | localRotation = inRotation;
60 | localScaling = inScaling;
61 | }
62 |
63 | public Vector3 getLocalScaling() {
64 | return localScaling;
65 | }
66 |
67 | public JUMIBone(String inName, Vector3 inTranslation, Vector3 inRotation, Vector3 inScaling) {
68 | name = inName;
69 | localTranslation = inTranslation;
70 | localRotation = inRotation;
71 | localScaling = inScaling;
72 | }
73 |
74 | public Vector3 getLocalTranslation() {
75 | return localTranslation;
76 | }
77 |
78 | public Vector3 getLocalRotation() {
79 | return localRotation;
80 | }
81 |
82 | public float[] getTransforms() {
83 | return transforms;
84 | }
85 |
86 | public float[] getTransformLinks() {
87 | return transformLinks;
88 | }
89 |
90 | public void setParent(JUMIBone newParent) {
91 | parent = newParent;
92 | }
93 |
94 | public void addChild(JUMIBone newChild) {
95 | children.add(newChild);
96 | newChild.setParent(this);
97 | }
98 |
99 | public void removeChild(JUMIBone childToRemove) {
100 | children.remove(childToRemove);
101 | childToRemove.setParent(null);
102 | }
103 |
104 | public void removeChild(String childName) {
105 | int index = -1;
106 | for (JUMIBone a : children) {
107 | if (a.name.equals(childName)) {
108 | index = children.indexOf(a);
109 | break;
110 | }
111 | }
112 |
113 | if (index > -1) {
114 | children.remove(index);
115 | }
116 | }
117 |
118 | public String getName() {
119 | return name;
120 | }
121 |
122 | public void setName(String newName) {
123 | name = newName;
124 | }
125 |
126 | public int[] getVertexIndices() {
127 | return indices;
128 | }
129 |
130 | public float[] getWeights() {
131 | return weights;
132 | }
133 |
134 | public JUMIBone getParent() {
135 | return parent;
136 | }
137 |
138 | public JUMIBone[] getChildren() {
139 | return children.toArray(new JUMIBone[children.size()]);
140 | }
141 |
142 | public JUMIBone[] getDescendants() {
143 | ArrayList allBones = new ArrayList();
144 |
145 | addDescendantsToList(allBones);
146 |
147 | JUMIBone[] result = new JUMIBone[allBones.size()];
148 | allBones.toArray(result);
149 | return result;
150 | }
151 |
152 | public JUMIBone[] getFullSkeleton() {
153 | ArrayList allBones = new ArrayList();
154 | JUMIBone root = getRoot();
155 | allBones.add(root);
156 | root.addDescendantsToList(allBones);
157 |
158 | JUMIBone[] result = new JUMIBone[allBones.size()];
159 | allBones.toArray(result);
160 | return result;
161 | }
162 |
163 | public JUMIBone getRoot() {
164 | if (parent == null) {
165 | return this;
166 | } else {
167 | return parent.getRoot();
168 | }
169 | }
170 |
171 | private void addDescendantsToList(ArrayList boneList) {
172 | for (JUMIBone a : children) {
173 | boneList.add(a);
174 | a.addDescendantsToList(boneList);
175 | }
176 | }
177 |
178 | public JUMIBone findDescendantByName(String inName) {
179 | for (JUMIBone a : children) {
180 | if (a.getName().equals(inName)) {
181 | return a;
182 | }
183 | a.findDescendantByName(inName);
184 | }
185 | return null;
186 | }
187 |
188 | public String toString() {
189 | return "JUMIBone:\n\tName: " + name + "\n\tParent: " + ((parent != null) ? parent.name : "None") + "\n\tChildren: " + children.size() + "\n\tDescendants: " + getDescendants().length;
190 | }
191 |
192 | }
193 |
--------------------------------------------------------------------------------
/src/com/jumi/scene/objects/JUMIMaterial.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.scene.objects;
20 |
21 | import com.jumi.data.Color;
22 |
23 | /**
24 | *
25 | * @author RGreenlees
26 | */
27 | public class JUMIMaterial {
28 |
29 | public String name;
30 |
31 | public Color ambientColor = new Color();
32 | public Color diffuseColor = new Color();
33 | public Color specularColor = new Color();
34 | public Color emissiveColor = new Color();
35 |
36 | public float specularFactor;
37 | public float shininessExponent;
38 | public float transparencyFactor;
39 | public float emissiveFactor;
40 | public float reflectionFactor;
41 | public float shininess;
42 | public float reflectivity;
43 | public float opacity;
44 |
45 | public JUMITexture diffuseTexture = null;
46 | public JUMITexture normalTexture = null;
47 | public JUMITexture specularTexture = null;
48 |
49 | public JUMITexture[] textures = new JUMITexture[0];
50 |
51 | public String toString() {
52 | String result = "JUMIMaterial:\n\tName: " + name
53 | + "\n\tAmbient Color: " + ambientColor
54 | + "\n\tDiffuse Color: " + diffuseColor
55 | + "\n\tSpecular Color: " + specularColor + ", Factor = " + specularFactor
56 | + "\n\tEmissive Color: " + emissiveColor
57 | + "\n\tDiffuse Texture: " + ((diffuseTexture != null) ? diffuseTexture.name : "None")
58 | + "\n\tNormal Texture: " + ((normalTexture != null) ? normalTexture.name : "None")
59 | + "\n\tSpecular Texture: " + ((specularTexture != null) ? specularTexture.name : "None")
60 | + "\n\tUnassociated Textures: " + textures.length;
61 |
62 | for (JUMITexture a : textures) {
63 | result = result + "\n\t\t" + a.name;
64 | }
65 |
66 | return result;
67 | }
68 |
69 | /** Returns the texture at the supplied index for the unsorted textures only */
70 | public JUMITexture getTextureByIndex(int index) {
71 | if (index >= textures.length) {
72 | return null;
73 | }
74 | return textures[index];
75 | }
76 |
77 | /** Returns the diffuse texture for this material, or null if none exists */
78 | public JUMITexture getDiffuseTexture() {
79 | return diffuseTexture;
80 | }
81 |
82 | /** Returns the specular texture for this material, or null if none exists */
83 | public JUMITexture getSpecularTexture() {
84 | return specularTexture;
85 | }
86 |
87 | /** Returns the normal texture for this material, or null if none exists */
88 | public JUMITexture getNormalTexture() {
89 | return normalTexture;
90 | }
91 |
92 | /** Searches all textures, including unsorted, for the given name */
93 | public JUMITexture getTextureByName(String name) {
94 |
95 | if (diffuseTexture.name.equals(name)) {
96 | return diffuseTexture;
97 | }
98 |
99 | if (specularTexture.name.equals(name)) {
100 | return specularTexture;
101 | }
102 |
103 | if (normalTexture.name.equals(name)) {
104 | return normalTexture;
105 | }
106 |
107 | for (JUMITexture a : textures) {
108 | if (a.name.equals(name)) {
109 | return a;
110 | }
111 | }
112 | return null;
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/src/com/jumi/scene/objects/JUMIMesh.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.scene.objects;
20 |
21 | import static java.lang.Math.abs;
22 |
23 | /*
24 | * To change this license header, choose License Headers in Project Properties.
25 | * To change this template file, choose Tools | Templates
26 | * and open the template in the editor.
27 | */
28 | /**
29 | *
30 | * @author RGreenlees
31 | */
32 | public class JUMIMesh {
33 |
34 | public static enum FaceType {
35 |
36 | NONE, TRIANGLES, QUADS
37 | };
38 | public FaceType faceType = FaceType.NONE;
39 |
40 | public String name;
41 |
42 | public float[] vertices = new float[0];
43 | public float[] normals = new float[0];
44 | public float[] binormals = new float[0];
45 | public float[] tangents = new float[0];
46 | public float[] uvs = new float[0];
47 |
48 | public int[] indices = new int[0];
49 | public int[] edges = new int[0];
50 |
51 | public JUMITexture[] textures = new JUMITexture[0];
52 | public JUMIMaterial[] materials = new JUMIMaterial[0];
53 |
54 | public JUMIBone rootBone;
55 |
56 | public JUMIMesh(String inputName) {
57 | name = inputName;
58 | }
59 |
60 | public int numTextures() {
61 | return textures.length;
62 | }
63 |
64 | /** Does this mesh have skeletal information? */
65 | public boolean hasSkeleton() {
66 | return rootBone != null;
67 | }
68 |
69 | /** Searches for the supplied bone name within the hierarchy, returning null if not found */
70 | public JUMIBone getBoneByName(String boneName) {
71 | return findBoneInHierarchy(rootBone, boneName);
72 | }
73 |
74 | private JUMIBone findBoneInHierarchy(JUMIBone root, String boneName) {
75 | JUMIBone result = null;
76 | if (root.getName().equals(boneName)) {
77 | return root;
78 | } else {
79 | for (JUMIBone child : root.getChildren()) {
80 | result = findBoneInHierarchy(child, boneName) ;
81 | if (result != null) {
82 | return result;
83 | }
84 | }
85 | return result;
86 | }
87 | }
88 |
89 | /** Returns the texture at the supplied index, or null if it does not exist. Only for textures without a parent material */
90 | public JUMITexture getTextureByIndex(int index) {
91 | if (index >= textures.length) {
92 | return null;
93 | }
94 | return textures[index];
95 | }
96 |
97 | /** Searches for the supplied texture name and returns any matches, or null if none found */
98 | public JUMITexture getTextureByName(String inName) {
99 | for (JUMITexture a : textures) {
100 | if (a.name.equals(inName)) {
101 | return a;
102 | }
103 | }
104 | return null;
105 | }
106 |
107 | /** Returns the material at the supplied index, or null if it does not exist */
108 | public JUMIMaterial getMaterialByIndex(int index) {
109 | if (index >= materials.length) {
110 | return null;
111 | }
112 | return materials[index];
113 | }
114 |
115 | /** Searches for the supplied material name and returns any matches, or null if none found */
116 | public JUMIMaterial getMaterialByName(String inName) {
117 | for (JUMIMaterial a : materials) {
118 | if (a.name.equals(inName)) {
119 | return a;
120 | }
121 | }
122 | return null;
123 | }
124 |
125 | /** Return an array of all bones for this mesh */
126 | public JUMIBone[] getAllBones() {
127 | return rootBone.getFullSkeleton();
128 | }
129 |
130 | /** Returns the distance of the furthest point from the model's origin */
131 | public float getMaxExtent() {
132 | float result = 0.0f;
133 | for (int i = 0; i < vertices.length; i++) {
134 | if (abs(vertices[i]) > result) {
135 | result = abs(vertices[i]);
136 | }
137 | }
138 | return result;
139 | }
140 |
141 | /** Scales the model so that the furthest vertex from the model's origin matches the supplied extent */
142 | public void setMaxExtent(float newExtent) {
143 | float scale = newExtent / getMaxExtent();
144 |
145 | setScale(scale);
146 |
147 | }
148 |
149 | /** Scales the mesh by the supplied scalar */
150 | public void setScale(float newScale) {
151 | for (int i = 0; i < vertices.length; i++) {
152 | vertices[i] *= newScale;
153 | }
154 | }
155 |
156 | /** Triangulates the mesh (Currently only works for QUADS) */
157 | public void triangulate() {
158 | if (faceType == FaceType.QUADS) {
159 | int[] newIndices = new int[(int) (indices.length * 1.5f)];
160 | int newIndexCounter = 0;
161 |
162 | for (int i = 0; i < indices.length - 4; i += 4) {
163 | newIndices[newIndexCounter++] = indices[i];
164 | newIndices[newIndexCounter++] = indices[i + 1];
165 | newIndices[newIndexCounter++] = indices[i + 2];
166 | newIndices[newIndexCounter++] = indices[i + 2];
167 | newIndices[newIndexCounter++] = indices[i + 3];
168 | newIndices[newIndexCounter++] = indices[i];
169 | }
170 |
171 | indices = newIndices;
172 | faceType = FaceType.TRIANGLES;
173 | }
174 | }
175 |
176 | public String toString() {
177 | String result = "JUMIMesh: " + name + "\n\tVertices: " + ((vertices != null) ? (vertices.length / 3) : 0)
178 | + "\n\tNormals: " + ((normals != null) ? (normals.length / 3) : 0)
179 | + "\n\tUVs: " + ((uvs != null) ? (uvs.length / 2) : 0)
180 | + "\n\tTextures: " + ((textures != null) ? textures.length : 0);
181 | for (int i = 0; i < textures.length; i++) {
182 | result = result + "\n\t\t" + textures[i].name;
183 | }
184 | result = result + "\n\tMaterials: " + ((materials != null) ? materials.length : 0);
185 | for (int i = 0; i < materials.length; i++) {
186 | result = result + "\n\t\t" + materials[i].name;
187 | }
188 |
189 | result = result + "\n\tFace Type: " + faceType.toString()
190 | + "\n\tMax Extent: " + this.getMaxExtent();
191 | result = result + "\n\tRoot Bone: " + ((rootBone != null) ? rootBone.getName() : "None");
192 | return result;
193 | }
194 |
195 | /** Returns the vertices for this mesh in float[] form */
196 | public float[] getVertices() {
197 | return vertices;
198 | }
199 |
200 | /** Returns the normals for this mesh in float[] form */
201 | public float[] getNormals() {
202 | return normals;
203 | }
204 |
205 | /** Returns the UVs for this mesh in float[] form */
206 | public float[] getUVs() {
207 | return uvs;
208 | }
209 |
210 | /** Returns the indices for this mesh in int[] form */
211 | public int[] getVertexIndices() {
212 | return indices;
213 | }
214 |
215 | /** Returns the edges for this mesh in int[] form (NOT IMPLEMENTED YET!) */
216 | public int[] getEdges() {
217 | return edges;
218 | }
219 |
220 | /** Horizontally flips the UV coordinates */
221 | public void flipUVX() {
222 | for (int i = 0; i < uvs.length; i += 2) {
223 | uvs[i] = 1.0f - uvs[i];
224 | }
225 | }
226 |
227 | /** Vertically flips the UV coordinates */
228 | public void flipUVY() {
229 | for (int i = 1; i < uvs.length; i += 2) {
230 | uvs[i] = 1.0f - uvs[i];
231 | }
232 | }
233 | }
234 |
--------------------------------------------------------------------------------
/src/com/jumi/scene/objects/JUMISkinDeformer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.scene.objects;
20 |
21 | /**
22 | *
23 | * @author RGreenlees
24 | */
25 | public class JUMISkinDeformer {
26 |
27 | String name;
28 |
29 | public JUMISubDeformer[] deformers = new JUMISubDeformer[0];
30 |
31 | public JUMISkinDeformer(String inName) {
32 | name = inName;
33 | }
34 |
35 | public String toString() {
36 | String result = "Skin Deformer " + name + ":";
37 | for (int i = 0; i < deformers.length; i++) {
38 | result = result + "\n\t" + deformers[i].name;
39 | }
40 | return result;
41 | }
42 |
43 | public JUMISubDeformer getSubDeformerByIndex(int index) {
44 | if (index >= deformers.length) {
45 | return null;
46 | }
47 | return deformers[index];
48 | }
49 |
50 | public JUMISubDeformer getSubDeformerByName(String inName) {
51 | for (JUMISubDeformer a : deformers) {
52 | if (a.name.equals(inName)) {
53 | return a;
54 | }
55 | }
56 | return null;
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/src/com/jumi/scene/objects/JUMISubDeformer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.scene.objects;
20 |
21 | /**
22 | *
23 | * @author RGreenlees
24 | */
25 | public class JUMISubDeformer {
26 |
27 | public String name;
28 |
29 | public int[] indexes = new int[0];
30 | public float[] weights = new float[0];
31 | public float[] transforms = new float[0];
32 | public float[] transformLinks = new float[0];
33 |
34 | public JUMISubDeformer(String inName) {
35 | name = inName;
36 | }
37 |
38 | public String toString() {
39 | return "Sub-Deformer " + name + ":\n\tIndexes: " + indexes.length + "\n\tWeights: " + weights.length;
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/com/jumi/scene/objects/JUMITexture.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) Copyright 2015 Richard Greenlees
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | * subject to the following conditions:
9 | *
10 | * 1) The above copyright notice and this permission notice shall be included
11 | * in all copies or substantial portions of the Software.
12 | *
13 | * This library is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * Lesser General Public License for more details.
17 | *
18 | */
19 | package com.jumi.scene.objects;
20 |
21 | import java.nio.ByteBuffer;
22 |
23 | /**
24 | *
25 | * @author RGreenlees
26 | */
27 | public class JUMITexture {
28 | public String fileName;
29 | public String relativeFilename;
30 | public String fullFilePath;
31 | public String type;
32 | public String name;
33 |
34 | private byte[] textureData = new byte[0];
35 |
36 | public int textureDataSize() {
37 | return textureData.length;
38 | }
39 |
40 | public void setTextureData(byte[] data) {
41 | textureData = data;
42 | }
43 |
44 | /** Return the raw binary data for embedded textures (currently FBX only) */
45 | public byte[] getEmbeddedData() {
46 | if (textureData.length > 0) {
47 | return textureData;
48 | } else {
49 | return null;
50 | }
51 | }
52 |
53 | /** Buffer the raw binary data for embedded textures into the supplied ByteBuffer (Currently FBX only) */
54 | public void bufferData(ByteBuffer buf) {
55 | for (int i = 0; i < textureData.length; i++) {
56 | buf.put(textureData[i]);
57 | }
58 | }
59 |
60 | public String toString() {
61 | boolean embeddedData = (textureData != null && textureData.length > 0);
62 | return "Texture:" + "\n\tName: " + name
63 | + "\n\tFile Name: " + fileName
64 | + "\n\tRelative File Location: " + relativeFilename
65 | + "\n\tFull Path: " + fullFilePath
66 | + "\n\tEmbedded Data: " + embeddedData + " " + ((embeddedData) ? "(" + textureData.length + " bytes)" : "");
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------