• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Main repository of MikuMikuStudio


Commit MetaInfo

Revision330dbd18622934376d803455320607727de98fa6 (tree)
Time2003-09-05 06:17:51
Authormojomonkey <mojomonkey@75d0...>
Commitermojomonkey

Log Message

New Milkshape loader changes.

git-svn-id: http://jmonkeyengine.googlecode.com/svn/trunk@78 75d07b2b-3a1a-0410-a2c5-0572b91ccdca

Change Summary

Incremental Difference

--- a/src/jme/geometry/model/Joint.java
+++ b/src/jme/geometry/model/Joint.java
@@ -29,26 +29,90 @@
2929 * POSSIBILITY OF SUCH DAMAGE.
3030 *
3131 */
32+
3233 package jme.geometry.model;
3334
3435 import jme.math.Matrix;
3536
37+
38+
3639 /**
37- * <code>Joint</code> defines a joint for a model.
38- *
39- * @author Mark Powell
40+ * A Joint stores everything about an animated bone (a joint that knows
41+ * about its parent joint - the two endpoints make up a bone).
42+ *
43+ * @author naj
44+ * @version 0.1
4045 */
4146 public class Joint {
47+
48+ /**
49+ * The name of the joint in MS3D.
50+ */
4251 public String name;
52+
53+ /**
54+ * The name of the parent joint in MS3D.
55+ */
4356 public String parentName;
44- public float[] rotation = new float[3];
45- public float[] translation = new float[3];
46- public byte flags;
47- public Matrix absolute, relative;
48- public int numRotationKeyframes, numTranslationKeyframes;
49- public Keyframe[] translationKeyframes;
50- public Keyframe[] rotationKeyframes;
51- public int currentTranslationKeyframe, currentRotationKeyframe;
52- public Matrix finalMatrix;
53- public int parent;
54-}
57+
58+ /**
59+ * The flags in MS3D.
60+ */
61+ public int flags;
62+
63+ /**
64+ * The local translation of the joint in 3D space.
65+ */
66+ public float posx, posy, posz;
67+
68+ /**
69+ * The local rotation of the joint in 3D space.
70+ */
71+ public float rotx, roty, rotz;
72+
73+ /**
74+ * The number of position keyframes for the joint.
75+ */
76+ public int numberPosistionKeyframes;
77+
78+ /**
79+ * The number of position keyframes for the joint.
80+ */
81+ public int numberRotationKeyframes;
82+
83+ /**
84+ * The tranlation keyframes of the animation.
85+ */
86+ public Keyframe[] positionKeys;
87+
88+ /**
89+ * The rotation keyframes of the animation.
90+ */
91+ public Keyframe[] rotationKeys;
92+
93+ /**
94+ * The transformation of a joint from its parent.
95+ */
96+ public Matrix relativeMatrix = new Matrix();
97+
98+ /**
99+ * The original transformation of the joint.
100+ */
101+ public Matrix absoluteMatrix = new Matrix();
102+
103+ /**
104+ * The helper matrix for calculating the final matrix.
105+ */
106+ public Matrix relativeFinalMatrix = new Matrix();
107+
108+ /**
109+ * The final result of all transformations in the skeleton.
110+ */
111+ public Matrix finalMatrix = new Matrix();
112+
113+ /**
114+ * The parent joint index.
115+ */
116+ public int parentIndex;
117+
118+}
\ No newline at end of file
--- a/src/jme/geometry/model/Keyframe.java
+++ b/src/jme/geometry/model/Keyframe.java
@@ -29,15 +29,44 @@
2929 * POSSIBILITY OF SUCH DAMAGE.
3030 *
3131 */
32+
3233 package jme.geometry.model;
3334
3435 /**
35- * <code>Keyframe</code> represents a frame of animation for a model.
36- *
37- * @author Mark Powell
36+ * A Keyframe is a point in time which defines when a joint will reach a
37+ * certain rotation or translation. To perform animation, you interpolate
38+ * the translation or rotation over the time frame.
39+ *
40+ * @author naj
41+ * @version 0.1
3842 */
3943 public class Keyframe {
40- public int jointIndex;
44+
45+ /**
46+ * The time in milliseconds after the start of the animation for which
47+ * that keyframe occurs.
48+ */
4149 public float time;
42- public float parameter[] = new float[3];
43-}
50+
51+ /**
52+ * For a position keyframe (x,y,z) are the coordinates to translate.
53+ * For a rotation keyframe (x,y,z) are angles, in radians, to rotate.
54+ */
55+ public float x, y, z;
56+
57+ /**
58+ * Create a keyframe at a given time and vector.
59+ * @param time the time in milliseconds after the start of the animation
60+ * for which that keyframe occurs.
61+ * @param x the x value of the translation or rotation for the keyframe.
62+ * @param y the y value of the translation or rotation for the keyframe.
63+ * @param z the z value of the translation or rotation for the keyframe.
64+ */
65+ public Keyframe(float time, float x, float y, float z) {
66+ this.time = time;
67+ this.x = x;
68+ this.y = y;
69+ this.z = z;
70+ }
71+
72+}
\ No newline at end of file
--- a/src/jme/geometry/model/Material.java
+++ b/src/jme/geometry/model/Material.java
@@ -29,45 +29,66 @@
2929 * POSSIBILITY OF SUCH DAMAGE.
3030 *
3131 */
32+
3233 package jme.geometry.model;
3334
3435 /**
35- * <code>Material</code> maintains all standard lighting coeffecients
36- * for OpenGL based lighting as well as texture information.
37- * @author Mark Powell
36+ * A Material is a texture map in MS3D. Currently, as of version 0.1 of
37+ * najgl, only bitmap (*.bmp) textures are supported.
38+ *
39+ * @author naj
40+ * @version 0.1
3841 */
39-
4042 public class Material {
43+
44+ /**
45+ * The filename of the bitmap. Must be relative to the loaded model file.
46+ */
4147 public String name;
48+
49+ /**
50+ * The filename of the color map. Must be relative to the loaded model file.
51+ */
52+ public String colorMap;
53+
54+ /**
55+ * The filename of the alpah map. Must be relative to the loaded model file.
56+ */
57+ public String alphaMap;
58+
59+ /**
60+ * A pointer to the memory address of the texture in opengl memory.
61+ */
62+ public int glTextureAddress;
63+
64+ /**
65+ * An array of (r,g,b,a) color values for natural light.
66+ */
67+ public float[] ambient;
68+
69+ /**
70+ * An array of (r,g,b,a) color values for indirect light.
71+ */
72+ public float[] diffuse;
73+
74+ /**
75+ * An array of (r,g,b,a) color values for direct light.
76+ */
77+ public float[] specular;
78+
79+ /**
80+ * An array of (r,g,b,a) color values for projected light.
81+ */
82+ public float[] emissive;
83+
84+ /**
85+ * The ammount of light to be reflected off of the texture.
86+ */
87+ public float shininess;
88+
89+ /**
90+ * The ammount of light to pass through the texture.
91+ */
4292 public float transparency;
43- public byte mode;
44- public String alphaFilename;
45- /**
46- * defines the color and intensity of the ambient or natural light.
47- */
48- public float[] ambient = new float[4];
49- /**
50- * defines the color and intensity of the diffuse or indirect light.
51- */
52- public float[] diffuse = new float[4];
53- /**
54- * defines the color and intensity of the specular or direct light.
55- */
56- public float[] specular = new float[4];
57- /**
58- * defines the color and intensity of the emissive or projected light.
59- */
60- public float[] emissive = new float[4];
61- /**
62- * defines the amount of light is reflected by the material.
63- */
64- public float shininess;
65- /**
66- * defines the id of the texture as assigned by OpenGL.
67- */
68- public int texture;
69- /**
70- * defines the name of the image file used to generate the texture.
71- */
72- public String textureFilename;
73-}
93+
94+}
\ No newline at end of file
--- a/src/jme/geometry/model/Mesh.java
+++ b/src/jme/geometry/model/Mesh.java
@@ -29,29 +29,61 @@
2929 * POSSIBILITY OF SUCH DAMAGE.
3030 *
3131 */
32+
3233 package jme.geometry.model;
3334
3435 /**
35- * <code>Mesh</code> defines a group of triangles that are all related in some way.
36- * Typically a mesh will share a <code>Material</code> and a collection of meshes
37- * will define a model.
38- * @author Mark Powell
36+ * A Mesh is a group of related triangles in MS3D.
3937 *
40- *Special thanks to Chman's <a href="http://chman-area.tuxfamily.org">site</a> for help.
38+ * @author naj
39+ * @version 0.1
4140 */
4241 public class Mesh {
43- public byte flags;
42+
43+ /**
44+ * The name of the mesh in MS3D.
45+ */
4446 public String name;
45- /**
46- * the index into an array of materials.
47- */
48- public int materialIndex;
49- /**
50- * the number of triangles that make up the mesh.
51- */
52- public int numTriangles;
53- /**
54- * indices into the array of triangles.
55- */
56- public int[] triangleIndices;
57-}
47+
48+ /**
49+ * The flags in MS3D.
50+ */
51+ public int flags;
52+
53+ /**
54+ * The index into the array of materials in the model. -1 indicates that
55+ * the mesh does not have a material assigned to it.
56+ */
57+ public int materialIndex;
58+
59+ /**
60+ * The number of vertices in the mesh.
61+ */
62+ public int numberVertices;
63+
64+ /**
65+ * The number of normal vectors in the mesh.
66+ */
67+ public int numberNormals;
68+
69+ /**
70+ * The number of triangles in the mesh.
71+ */
72+ public int numberTriangles;
73+
74+ /**
75+ * The vertices in the mesh.
76+ */
77+ public Vertex[] vertices;
78+
79+ /**
80+ * The normals in the mesh. Stores as an array of (x,y,z) arrays.
81+ */
82+ public float[][] normals;
83+
84+ /**
85+ * The traingles in the mesh.
86+ */
87+ public Triangle[] triangles;
88+
89+}
\ No newline at end of file
--- /dev/null
+++ b/src/jme/geometry/model/Model.java
@@ -0,0 +1,55 @@
1+/*
2+ * Copyright (c) 2003, jMonkeyEngine - Mojo Monkey Coding
3+ * All rights reserved.
4+ *
5+ * Redistribution and use in source and binary forms, with or without
6+ * modification, are permitted provided that the following conditions are met:
7+ *
8+ * Redistributions of source code must retain the above copyright notice, this
9+ * list of conditions and the following disclaimer.
10+ *
11+ * Redistributions in binary form must reproduce the above copyright notice,
12+ * this list of conditions and the following disclaimer in the documentation
13+ * and/or other materials provided with the distribution.
14+ *
15+ * Neither the name of the Mojo Monkey Coding, jME, jMonkey Engine, nor the
16+ * names of its contributors may be used to endorse or promote products derived
17+ * from this software without specific prior written permission.
18+ *
19+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29+ * POSSIBILITY OF SUCH DAMAGE.
30+ *
31+ */
32+
33+package jme.geometry.model;
34+
35+/**
36+ * An interface for models. Models should be able to load from a file and
37+ * draw itself (animated if possible).
38+ *
39+ * @author naj
40+ * @version 0.1
41+ */
42+public interface Model {
43+
44+ /**
45+ * Loads a model from a file that contains the model information.
46+ * @param filename file that contains the model information.
47+ */
48+ public void load(String filename);
49+
50+ /**
51+ * Draw the model (to opengl).
52+ */
53+ public void render();
54+
55+}
\ No newline at end of file
--- a/src/jme/geometry/model/Triangle.java
+++ b/src/jme/geometry/model/Triangle.java
@@ -29,34 +29,79 @@
2929 * POSSIBILITY OF SUCH DAMAGE.
3030 *
3131 */
32+
3233 package jme.geometry.model;
3334
3435 /**
35- * <code>Triangle</code> defines all attributes of a triangle. This includes
36- * the three points that define it's position, the normal of each point, and
37- * the texture coordinates.
36+ * A Triangle is a polygon in MD3D. It holds indexes to the three vertices
37+ * in the model, as well as indexes to its normals.
3838 *
39- * @author Mark Powell
39+ * @author naj
40+ * @version 0.1
4041 */
4142 public class Triangle {
43+
44+ /**
45+ * The flags in MS3D.
46+ */
4247 public int flags;
43- public byte smoothingGroup;
44- public byte groupIndex;
45-
46- /**
47- * the indices into the array of vertices/
48- */
49- public int[] vertexIndices = new int[3];
50- /**
51- * the normal for each point.
52- */
53- public float[][] vertexNormals = new float[3][3];
54- /**
55- * the s texture coordinate for each point.
56- */
57- public float[] s = new float[3];
58- /**
59- * the t texture coordinate for each point.
60- */
61- public float[] t = new float[3];
62-}
48+
49+ /**
50+ * Vertex 1.
51+ */
52+ public int vertexIndex1;
53+
54+ /**
55+ * Vertex 2.
56+ */
57+ public int vertexIndex2;
58+
59+ /**
60+ * Vertex 3.
61+ */
62+ public int vertexIndex3;
63+
64+ /**
65+ * Normal 1.
66+ */
67+ public int normalIndex1;
68+
69+ /**
70+ * Normal 2.
71+ */
72+ public int normalIndex2;
73+
74+ /**
75+ * Normal 3.
76+ */
77+ public int normalIndex3;
78+
79+ /**
80+ * The MS3D smoothing group.
81+ */
82+ public int smoothingGroup;
83+
84+ /**
85+ * Creates a triangle with the vertices and normals given.
86+ *
87+ * @param flags the MS3D flags.
88+ * @param vertexIndex1 vertex 1.
89+ * @param vertexIndex2 vertex 2.
90+ * @param vertexIndex3 vertex 3.
91+ * @param normalIndex1 normal 1.
92+ * @param normalIndex2 normal 2.
93+ * @param normalIndex3 normal 3.
94+ * @param smoothingGroup the MS3D smoothing group.
95+ */
96+ public Triangle(int flags, int vertexIndex1, int vertexIndex2, int vertexIndex3, int normalIndex1, int normalIndex2, int normalIndex3, int smoothingGroup) {
97+ this.flags = flags;
98+ this.vertexIndex1 = vertexIndex1;
99+ this.vertexIndex2 = vertexIndex2;
100+ this.vertexIndex3 = vertexIndex3;
101+ this.normalIndex1 = normalIndex1;
102+ this.normalIndex2 = normalIndex2;
103+ this.normalIndex3 = normalIndex3;
104+ this.smoothingGroup = smoothingGroup;
105+ }
106+
107+}
\ No newline at end of file
--- a/src/jme/geometry/model/Vertex.java
+++ b/src/jme/geometry/model/Vertex.java
@@ -29,51 +29,74 @@
2929 * POSSIBILITY OF SUCH DAMAGE.
3030 *
3131 */
32-package jme.geometry.model;
33-
34-import jme.math.Vector;
3532
33+package jme.geometry.model;
3634
3735 /**
38- * <code>Vertex</code> provides an extension to <code>Vector</code> to handle
39- * texture coordinates as well as positions.
40- *
41- * @author Mark Powell
36+ * A Vertex is a 3D point (x,y,z) along with a 2D texture map point (u,v).
37+ * It also knows which bone (Joint) it is associated with for animations.
38+ *
39+ * @author naj
40+ * @version 0.1
4241 */
43-public class Vertex extends Vector {
44- public byte refCount;
42+public class Vertex {
43+
44+ /**
45+ * The flags in MS3D.
46+ */
47+ public int flags;
48+
49+ /**
50+ * The x value of the 3D point.
51+ */
52+ public float x;
53+
54+ /**
55+ * The y value of the 3D point.
56+ */
57+ public float y;
58+
59+ /**
60+ * The z value of the 3D point.
61+ */
62+ public float z;
63+
64+ /**
65+ * The x value of the 2D texture point.
66+ */
67+ public float u;
68+
69+ /**
70+ * The y value of the 2D texture point.
71+ */
72+ public float v;
73+
74+ /**
75+ * The index into the array of bones (Joint) in the model.
76+ */
77+ public int boneIndex;
4578
46- public byte flags;
47- /**
48- * the u coordinate of the texture.
49- */
50- public float u;
51- /**
52- * the v coordinate of the texture.
53- */
54- public float v;
55- /**
56- * the red component of the color.
57- */
58- public float r;
59- /**
60- * the green component of the color.
61- */
62- public float g;
63- /**
64- * the blue component of the color.
65- */
66- public float b;
67- /**
68- * the alpha value of the point.
69- */
70- public float a;
71- /**
72- * the bone this point is connected to.
73- */
74- public byte boneId;
75- /**
76- * the position of the point.
77- */
78- public float[] point = new float[3];
79-}
79+ public Vertex() {}
80+
81+ /**
82+ * Creates a Vertex with the given 3D point and texture coordinates, as
83+ * well as a bone reference if used in animations.
84+ * @param flags the flags in MS3D.
85+ * @param x the x value of the 3D point.
86+ * @param y the y value of the 3D point.
87+ * @param z the z value of the 3D point.
88+ * @param u the x value of the 2D texture point.
89+ * @param v the y value of the 2D texture point.
90+ * @param boneIndex the index into the array of bones (Joint) in the model.
91+ */
92+ public Vertex(int flags, float x, float y, float z, float u, float v, int boneIndex) {
93+ this.flags = flags;
94+ this.x = x;
95+ this.y = y;
96+ this.z = z;
97+ this.u = u;
98+ this.v = v;
99+ this.boneIndex = boneIndex;
100+ }
101+
102+}
\ No newline at end of file
--- a/src/jme/geometry/model/ms/MilkshapeModel.java
+++ b/src/jme/geometry/model/ms/MilkshapeModel.java
@@ -29,644 +29,594 @@
2929 * POSSIBILITY OF SUCH DAMAGE.
3030 *
3131 */
32+
3233 package jme.geometry.model.ms;
3334
35+import java.io.BufferedReader;
3436 import java.io.File;
35-import java.io.FileInputStream;
36-import java.io.FileNotFoundException;
37-import java.io.IOException;
37+import java.io.FileReader;
3838 import java.nio.ByteBuffer;
3939 import java.nio.ByteOrder;
40-import java.nio.FloatBuffer;
41-import java.util.logging.Level;
42-
43-import org.lwjgl.opengl.GL;
44-import org.lwjgl.opengl.Window;
4540
46-import jme.exception.MonkeyGLException;
47-import jme.geometry.*;
48-import jme.geometry.bounding.BoundingBox;
49-import jme.geometry.bounding.BoundingSphere;
5041 import jme.geometry.model.Joint;
5142 import jme.geometry.model.Keyframe;
5243 import jme.geometry.model.Material;
5344 import jme.geometry.model.Mesh;
45+import jme.geometry.model.Model;
5446 import jme.geometry.model.Triangle;
5547 import jme.geometry.model.Vertex;
5648 import jme.math.Matrix;
49+import jme.math.Quaternion;
5750 import jme.math.Vector;
51+import jme.system.DisplaySystem;
5852 import jme.texture.TextureManager;
59-import jme.utility.Conversion;
60-import jme.utility.LoggingSystem;
53+
54+import org.lwjgl.opengl.GL;
6155
6256 /**
63- *
64- * <code>MilkshapeModel</code> defines a model created by the Milkshape 3D
65- * modeling package. The loader handles all aspects of the Milkshape model up
66- * to version 3. Animation is not currently supported, but planned.
67- *
68- * @author Mark Powell
69- * @version $Id: MilkshapeModel.java,v 1.5 2003-09-03 16:20:52 mojomonkey Exp $
57+ * A MilkshapeModel represents a Milkshape 3D model. Currently, it can only
58+ * load the exported ascii text version of an MD3D model. In the future, the
59+ * binary version may be supported, but there really is no need for it because
60+ * it does not matter how long it takes to load the animation. Loading should
61+ * take place at game startup. If speed becomes extremely important in the
62+ * future, the binary loader may be an option, or serialized models is another
63+ * option. Unless someone contributes a binary loader or add the nehe lwjgl
64+ * port of the binary loader that actually loads multiple texture correctly :)
65+ *
66+ * The model can also draw itself, fully textured, to OpenGL through lwjgl.
67+ *
68+ * Bone animation is also supported.
69+ *
70+ * SPECIAL THANKS:
71+ * Animation method was ported by naj from a MSVC++ Model Viewer tutorial
72+ * written by Mete Ciragan (creator of Milkshape).
73+ *
74+ * @author naj
75+ * @version 0.1
7076 */
71-public class MilkshapeModel implements Geometry {
72- //defines the bounding volumes of the model.
73- private BoundingSphere boundingSphere;
74- private BoundingBox boundingBox;
75-
76- //animation attributes
77- private float animationFPS;
78- private float currentTime;
79- private int totalFrames;
80-
81- //model data information
82- private String modelFile;
83- private ByteBuffer buffer;
84- private String id;
85- private String path;
86- private int version;
77+public class MilkshapeModel implements Model {
8778
8879 /**
89- * the color of the model. This color will be applied as a whole to the
90- * model and may be trumped by the material level.
91- */
92- private float red, blue, green, alpha;
93- /**
94- * the scale of the model, where 1.0 is the standard size of the model.
95- */
96- private Vector scale;
97- /**
98- * the number of meshes that makes up the model.
80+ * Debugging variable to toggle animations.
9981 */
100- private int numMeshes = 0;
101- /**
102- * the number of materials that makes up the model.
103- */
104- private int numMaterials = 0;
105- /**
106- * the number of triangles that makes up the model.
107- */
108- private int numTriangles = 0;
82+ private boolean animated;
83+
10984 /**
110- * the number of vertices that makes up the model.
85+ * The total number of frames in the animation.
11186 */
112- private int numVertices = 0;
87+ private int totalFrames;
88+
11389 /**
114- * the number of joints that make up the model.
90+ * The current frame of the animation.
11591 */
116- private int numJoints = 0;
92+ private float currentFrame;
93+
11794 /**
118- * the total animation time.
95+ * The number of meshes in the model.
11996 */
120- private float totalTime = 0;
97+ private int numberMeshes;
98+
12199 /**
122- * the array of meshes that build the model.
100+ * The number of materials or textures in the model.
123101 */
124- private Mesh meshes[] = null;
102+ private int numberMaterials;
103+
125104 /**
126- * the array of materials that build the model.
105+ * The number of joints or bones in the model.
127106 */
128- private Material materials[] = null;
107+ private int numberJoints;
108+
129109 /**
130- * the array of triangles that build the model.
110+ * The meshes in the model.
131111 */
132- private Triangle triangles[] = null;
112+ private Mesh[] meshes;
113+
133114 /**
134- * the array of vertices that build the model.
115+ * The materials in the model.
135116 */
136- private Vertex vertices[] = null;
117+ private Material[] materials;
118+
137119 /**
138- * the array of Joints that build the model.
120+ * The joints in the model.
139121 */
140- private Joint joints[] = null;
122+ private Joint[] joints;
141123
142124 /**
143- * Constructor instantiates a new <code>MilkshapeModel</code> object.
144- * @param modelFile the Milkshape file.
145- * @throws MonkeyGLException if the OpenGL context has not been created.
125+ * The absolute path to the directory containing the model file. Used
126+ * to load the texture files.
146127 */
147- public MilkshapeModel(String modelFile) {
148- if (!Window.isCreated()) {
149- throw new MonkeyGLException(
150- "OpenGL context must be " + "created before MilkshapeModel.");
151- }
128+ private String absoluteFilePath;
152129
153- this.modelFile = modelFile;
130+
154131
155- red = 1.0f;
156- blue = 1.0f;
157- green = 1.0f;
158- alpha = 1.0f;
159- scale = new Vector(1.0f, 1.0f, 1.0f);
132+ public MilkshapeModel() {
133+ this.animated = false;
134+ }
160135
161- initialize();
162- setBoundingVolumes();
136+ public MilkshapeModel(boolean animated) {
137+ this.animated = animated;
163138 }
164139
165140 /**
166- * <code>initialize</code> reads the Milkshape model and sets the
167- * structure for rendering.
141+ * Draws the model to OpenGL via lwjgl. Also advances the animation
142+ * frames along if there are animations for the model.
168143 */
169- public void initialize() {
170- //read the byte data
171- byte data[] = null;
172- File file = new File(modelFile);
173- path =
174- file.getAbsolutePath().substring(
175- 0,
176- file.getAbsolutePath().length() - file.getName().length());
177- int length = (int) file.length();
178- data = new byte[length];
179- FileInputStream fis;
180- try {
181- fis = new FileInputStream(file);
182- fis.read(data);
183- fis.close();
184- } catch (FileNotFoundException e) {
185- LoggingSystem.getLoggingSystem().getLogger().log(
186- Level.WARNING,
187- "Could not find model file " + modelFile);
188- return;
189- } catch (IOException e) {
190- LoggingSystem.getLoggingSystem().getLogger().log(
191- Level.WARNING,
192- "Could not read model file " + modelFile);
193- return;
144+ public void render() {
145+
146+ if (animated) {
147+ advanceFrame();
194148 }
149+ boolean isTextureEnabled = GL.glIsEnabled(GL.GL_TEXTURE_2D);
195150
196- buffer = ByteBuffer.wrap(data).order(ByteOrder.nativeOrder());
151+ for (int meshIndex = 0; meshIndex < numberMeshes; meshIndex++) {
152+ int materialIndex = meshes[meshIndex].materialIndex;
197153
198- //read header information
199- //the ID is 10 bytes
200- byte idBuffer[] = new byte[10];
201- for (int i = 0; i < 10; i++) {
202- idBuffer[i] = buffer.get();
203- }
204- id = Conversion.byte2String(idBuffer);
205- version = buffer.getInt();
206-
207- if (!id.equals("MS3D000000")) {
208- LoggingSystem.getLoggingSystem().getLogger().log(
209- Level.WARNING,
210- modelFile + " is not a valid Milkshape3D model file.");
211- return;
212- }
213-
214- if (version < 3) {
215- LoggingSystem.getLoggingSystem().getLogger().log(
216- Level.WARNING,
217- "Bad " + modelFile + " version.");
218- return;
219- }
154+ if (materialIndex >= 0) {
155+ ByteBuffer buffer = ByteBuffer.allocateDirect(16).order(ByteOrder.nativeOrder());
220156
221- //Read the vertices
222- numVertices = buffer.getShort();
223- vertices = new Vertex[numVertices];
224- for (int i = 0; i < numVertices; i++) {
225- vertices[i] = new Vertex();
226- vertices[i].flags = buffer.get();
227- vertices[i].point[0] = buffer.getFloat();
228- vertices[i].point[1] = buffer.getFloat();
229- vertices[i].point[2] = buffer.getFloat();
230- vertices[i].boneId = buffer.get();
231- vertices[i].refCount = buffer.get();
232- }
157+ GL.glMaterial(GL.GL_FRONT, GL.GL_AMBIENT, buffer.asFloatBuffer().put(materials[materialIndex].ambient));
158+ GL.glMaterial(GL.GL_FRONT, GL.GL_DIFFUSE, buffer.asFloatBuffer().put(materials[materialIndex].diffuse));
159+ GL.glMaterial(GL.GL_FRONT, GL.GL_SPECULAR, buffer.asFloatBuffer().put(materials[materialIndex].specular));
160+ GL.glMaterial(GL.GL_FRONT, GL.GL_EMISSION, buffer.asFloatBuffer().put(materials[materialIndex].emissive));
161+ GL.glMaterialf(GL.GL_FRONT, GL.GL_SHININESS, materials[materialIndex].shininess);
233162
234- //Read the Triangles
235- numTriangles = buffer.getShort();
236- triangles = new Triangle[numTriangles];
237- for (int i = 0; i < numTriangles; i++) {
238- triangles[i] = new Triangle();
239- triangles[i].flags = buffer.getShort();
240- for (int j = 0; j < 3; j++) {
241- triangles[i].vertexIndices[j] = buffer.getShort();
163+ if (materials[materialIndex].glTextureAddress > 0) {
164+ GL.glBindTexture(GL.GL_TEXTURE_2D, materials[materialIndex].glTextureAddress);
165+ GL.glEnable(GL.GL_TEXTURE_2D);
166+ } else {
167+ GL.glDisable(GL.GL_TEXTURE_2D);
168+ }
169+ } else {
170+ GL.glDisable(GL.GL_TEXTURE_2D);
242171 }
243172
244- for (int j = 0; j < 3; j++) {
245- triangles[i].vertexNormals[j][0] = buffer.getFloat();
246- triangles[i].vertexNormals[j][1] = buffer.getFloat();
247- triangles[i].vertexNormals[j][2] = buffer.getFloat();
248- }
173+ int triangleCount = meshes[meshIndex].numberTriangles;
174+ Vertex[] vertices = meshes[meshIndex].vertices;
249175
250- for (int j = 0; j < 3; j++) {
251- triangles[i].s[j] = buffer.getFloat();
252- }
176+ GL.glBegin(GL.GL_TRIANGLES);
177+ for (int triangleIndex = 0; triangleIndex < triangleCount; triangleIndex++) {
178+ Triangle triangle = (meshes[meshIndex].triangles)[triangleIndex];
179+
180+ Vertex vertex = vertices[triangle.vertexIndex1];
181+ float[] normals = (meshes[meshIndex].normals)[triangle.normalIndex1];
182+ if (!animated || vertex.boneIndex == -1) {
183+ GL.glNormal3f(normals[0], normals[1], normals[2]);
184+ GL.glTexCoord2f(vertex.u, vertex.v);
185+ GL.glVertex3f(vertex.x, vertex.y, vertex.z);
186+ } else {
187+ Vector animationVector = new Vector(vertex.x, vertex.y, vertex.z).rotate(joints[vertex.boneIndex].finalMatrix);
188+ animationVector.x += joints[vertex.boneIndex].finalMatrix.matrix[0][3];
189+ animationVector.y += joints[vertex.boneIndex].finalMatrix.matrix[1][3];
190+ animationVector.z += joints[vertex.boneIndex].finalMatrix.matrix[2][3];
191+ GL.glNormal3f(normals[0], normals[1], normals[2]);
192+ GL.glTexCoord2f(vertex.u, vertex.v);
193+ GL.glVertex3f(animationVector.x, animationVector.y, animationVector.z);
194+ }
253195
254- for (int j = 0; j < 3; j++) {
255- triangles[i].t[j] = 1.0f - buffer.getFloat();
196+ vertex = vertices[triangle.vertexIndex2];
197+ normals = (meshes[meshIndex].normals)[triangle.normalIndex2];
198+ if (!animated || vertex.boneIndex == -1) {
199+ GL.glNormal3f(normals[0], normals[1], normals[2]);
200+ GL.glTexCoord2f(vertex.u, vertex.v);
201+ GL.glVertex3f(vertex.x, vertex.y, vertex.z);
202+ } else {
203+ Vector animationVector = new Vector(vertex.x, vertex.y, vertex.z).rotate(joints[vertex.boneIndex].finalMatrix);
204+ animationVector.x += joints[vertex.boneIndex].finalMatrix.matrix[0][3];
205+ animationVector.y += joints[vertex.boneIndex].finalMatrix.matrix[1][3];
206+ animationVector.z += joints[vertex.boneIndex].finalMatrix.matrix[2][3];
207+ GL.glNormal3f(normals[0], normals[1], normals[2]);
208+ GL.glTexCoord2f(vertex.u, vertex.v);
209+ GL.glVertex3f(animationVector.x, animationVector.y, animationVector.z);
210+ }
211+
212+ vertex = vertices[triangle.vertexIndex3];
213+ normals = (meshes[meshIndex].normals)[triangle.normalIndex3];
214+ if (!animated || vertex.boneIndex == -1) {
215+ GL.glNormal3f(normals[0], normals[1], normals[2]);
216+ GL.glTexCoord2f(vertex.u, vertex.v);
217+ GL.glVertex3f(vertex.x, vertex.y, vertex.z);
218+ } else {
219+ Vector animationVector = new Vector(vertex.x, vertex.y, vertex.z).rotate(joints[vertex.boneIndex].finalMatrix);
220+ animationVector.x += joints[vertex.boneIndex].finalMatrix.matrix[0][3];
221+ animationVector.y += joints[vertex.boneIndex].finalMatrix.matrix[1][3];
222+ animationVector.z += joints[vertex.boneIndex].finalMatrix.matrix[2][3];
223+ GL.glNormal3f(normals[0], normals[1], normals[2]);
224+ GL.glTexCoord2f(vertex.u, vertex.v);
225+ GL.glVertex3f(animationVector.x, animationVector.y, animationVector.z);
226+ }
256227 }
228+ GL.glEnd();
229+ }
257230
258- triangles[i].smoothingGroup = buffer.get();
259- triangles[i].groupIndex = buffer.get();
231+ if (isTextureEnabled) {
232+ GL.glEnable(GL.GL_TEXTURE_2D);
233+ } else {
234+ GL.glDisable(GL.GL_TEXTURE_2D);
260235 }
236+
237+ }
261238
262- //Read the meshes
263- numMeshes = buffer.getShort();
264- meshes = new Mesh[numMeshes];
265- for (int i = 0; i < numMeshes; i++) {
266- meshes[i] = new Mesh();
267- meshes[i].flags = buffer.get();
268- //get the name 32 bytes
269- byte nameBuffer[] = new byte[32];
270- for (int j = 0; j < 32; j++) {
271- nameBuffer[j] = buffer.get();
272- }
273- meshes[i].name = Conversion.byte2String(nameBuffer);
274- meshes[i].numTriangles = buffer.getShort();
275- meshes[i].triangleIndices = new int[meshes[i].numTriangles];
276- for (int j = 0; j < meshes[i].numTriangles; j++) {
277- meshes[i].triangleIndices[j] = buffer.getShort();
239+ /**
240+ * Loads an ascii text model exported from MS3D.
241+ * @param filename the file to load.
242+ */
243+ public void load(String filename) {
244+ try {
245+ File file = new File(filename);
246+ absoluteFilePath = file.getAbsolutePath();
247+ absoluteFilePath = absoluteFilePath.substring(0, absoluteFilePath.lastIndexOf(File.separator) + 1);
248+ BufferedReader reader = new BufferedReader(new FileReader(file));
249+ String line;
250+ while ( (line = getNextLine(reader)) != null) {
251+ if (line.startsWith("Frames: ")) {
252+ totalFrames = Integer.parseInt(line.substring(8));
253+ }
254+ if (line.startsWith("Frame: ")) {
255+ currentFrame = Integer.parseInt(line.substring(7));
256+ }
257+ if (line.startsWith("Meshes: ")) {
258+ numberMeshes = Integer.parseInt(line.substring(8));
259+ meshes = new Mesh[numberMeshes];
260+ parseMeshes(reader);
261+ }
262+ if (line.startsWith("Materials: ")) {
263+ numberMaterials = Integer.parseInt(line.substring(11));
264+ materials = new Material[numberMaterials];
265+ parseMaterials(reader);
266+ }
267+ if (line.startsWith("Bones: ")) {
268+ numberJoints = Integer.parseInt(line.substring(7));
269+ joints = new Joint[numberJoints];
270+ parseJoints(reader);
271+ }
278272 }
279- meshes[i].materialIndex = buffer.get();
280-
273+ } catch (Exception e) {
274+ e.printStackTrace();
281275 }
282276
283- //read materials
284- numMaterials = buffer.getShort();
285- materials = new Material[numMaterials];
286- for (int i = 0; i < numMaterials; i++) {
287- materials[i] = new Material();
277+ reloadTextures();
278+ }
288279
289- //read the material name 32 bytes
290- byte nameBuffer[] = new byte[32];
291- for (int j = 0; j < 32; j++) {
292- nameBuffer[j] = buffer.get();
280+ /**
281+ * Simple parser to extract the mesh information from the text file.
282+ */
283+ private void parseMeshes(BufferedReader reader) throws Exception {
284+ for (int i = 0; i < numberMeshes; i++) {
285+ Mesh mesh = new Mesh();
286+ String line = getNextLine(reader);
287+ mesh.name = line.substring(1, line.lastIndexOf("\""));
288+ mesh.flags = Integer.parseInt(line.substring(line.lastIndexOf("\"") + 2, line.lastIndexOf(" ")));
289+ mesh.materialIndex = Integer.parseInt(line.substring(line.lastIndexOf(" ") + 1));
290+
291+ line = getNextLine(reader);
292+ mesh.numberVertices = Integer.parseInt(line);
293+ Vertex[] vertices = new Vertex[mesh.numberVertices];
294+ for (int j = 0; j < mesh.numberVertices; j++) {
295+ line = getNextLine(reader);
296+ String[] values = line.split(" ");
297+ vertices[j] = new Vertex(Integer.parseInt(values[0]), Float.parseFloat(values[1]), Float.parseFloat(values[2]), Float.parseFloat(values[3]), Float.parseFloat(values[4]), Float.parseFloat(values[5]), Integer.parseInt(values[6]));
293298 }
294- materials[i].name = Conversion.byte2String(nameBuffer);
295-
296- materials[i].ambient[0] = buffer.getFloat();
297- materials[i].ambient[1] = buffer.getFloat();
298- materials[i].ambient[2] = buffer.getFloat();
299- materials[i].ambient[3] = buffer.getFloat();
300-
301- materials[i].diffuse[0] = buffer.getFloat();
302- materials[i].diffuse[1] = buffer.getFloat();
303- materials[i].diffuse[2] = buffer.getFloat();
304- materials[i].diffuse[3] = buffer.getFloat();
305-
306- materials[i].specular[0] = buffer.getFloat();
307- materials[i].specular[1] = buffer.getFloat();
308- materials[i].specular[2] = buffer.getFloat();
309- materials[i].specular[3] = buffer.getFloat();
310-
311- materials[i].emissive[0] = buffer.getFloat();
312- materials[i].emissive[1] = buffer.getFloat();
313- materials[i].emissive[2] = buffer.getFloat();
314- materials[i].emissive[3] = buffer.getFloat();
315-
316- materials[i].shininess = buffer.getFloat();
317- materials[i].transparency = buffer.getFloat();
318- materials[i].mode = buffer.get();
319-
320- //get texture
321- byte texBuffer[] = new byte[128];
322- for (int j = 0; j < 128; j++) {
323- texBuffer[j] = buffer.get();
299+ mesh.vertices = vertices;
300+
301+ line = getNextLine(reader);
302+ mesh.numberNormals = Integer.parseInt(line);
303+ float[][] normals = new float[mesh.numberNormals][3];
304+ for (int j = 0; j < mesh.numberNormals; j++) {
305+ line = getNextLine(reader);
306+ String[] values = line.split(" ");
307+ normals[j] = new float[] {
308+ Float.parseFloat(values[0]), Float.parseFloat(values[1]), Float.parseFloat(values[2])};
324309 }
325- materials[i].textureFilename = Conversion.byte2String(texBuffer);
326- byte alphaBuffer[] = new byte[128];
327- for (int j = 0; j < 128; j++) {
328- alphaBuffer[j] = buffer.get();
310+ mesh.normals = normals;
311+
312+ line = getNextLine(reader);
313+ mesh.numberTriangles = Integer.parseInt(line);
314+ Triangle[] triangles = new Triangle[mesh.numberTriangles];
315+ for (int j = 0; j < mesh.numberTriangles; j++) {
316+ line = getNextLine(reader);
317+ String[] values = line.split(" ");
318+ triangles[j] = new Triangle(Integer.parseInt(values[0]), Integer.parseInt(values[1]), Integer.parseInt(values[2]), Integer.parseInt(values[3]), Integer.parseInt(values[4]), Integer.parseInt(values[5]), Integer.parseInt(values[6]), Integer.parseInt(values[7]));
329319 }
330- materials[i].alphaFilename = Conversion.byte2String(texBuffer);
320+ mesh.triangles = triangles;
321+ meshes[i] = mesh;
331322 }
332- loadTextures();
333-
334- //Read key frames
335- animationFPS = buffer.getFloat();
336- currentTime = (buffer.getFloat() * 1000);
337- totalFrames = buffer.getInt();
338-
339- numJoints = buffer.getShort();
340- joints = new Joint[numJoints];
341-
342- for (int i = 0; i < numJoints; i++) {
343- joints[i] = new Joint();
344- joints[i].flags = buffer.get();
345- //get name 32 bytes
346- byte[] nameBuffer = new byte[32];
347- for (int j = 0; j < 32; j++) {
348- nameBuffer[j] = buffer.get();
349- }
323+ }
324+
325+ /**
326+ * Simple parser to extract the material information from the text file.
327+ */
328+ private void parseMaterials(BufferedReader reader) throws Exception {
329+ for (int i = 0; i < numberMaterials; i++) {
330+ String line = getNextLine(reader);
331+ Material material = new Material();
332+ material.name = line.substring(1, line.length() - 1);
333+ line = getNextLine(reader);
334+ String[] values = line.split(" ");
335+ material.ambient = new float[] {
336+ Float.parseFloat(values[0]), Float.parseFloat(values[1]), Float.parseFloat(values[2]), Float.parseFloat(values[3])};
337+ line = getNextLine(reader);
338+ values = line.split(" ");
339+ material.diffuse = new float[] {
340+ Float.parseFloat(values[0]), Float.parseFloat(values[1]), Float.parseFloat(values[2]), Float.parseFloat(values[3])};
341+ line = getNextLine(reader);
342+ values = line.split(" ");
343+ material.specular = new float[] {
344+ Float.parseFloat(values[0]), Float.parseFloat(values[1]), Float.parseFloat(values[2]), Float.parseFloat(values[3])};
345+ line = getNextLine(reader);
346+ values = line.split(" ");
347+ material.emissive = new float[] {
348+ Float.parseFloat(values[0]), Float.parseFloat(values[1]), Float.parseFloat(values[2]), Float.parseFloat(values[3])};
349+ line = getNextLine(reader);
350+ material.shininess = Float.parseFloat(line);
351+ line = getNextLine(reader);
352+ material.transparency = Float.parseFloat(line);
353+ line = getNextLine(reader);
354+ material.colorMap = line.substring(1, line.length() - 1);
355+ line = getNextLine(reader);
356+ material.alphaMap = line.substring(1, line.length() - 1);
357+ materials[i] = material;
358+ }
359+ }
350360
351- joints[i].name = Conversion.byte2String(nameBuffer);
352- //get parent name 32 bytes
353- byte[] parentBuffer = new byte[32];
354- for (int j = 0; j < 32; j++) {
355- parentBuffer[j] = buffer.get();
361+ /**
362+ * Simple parser to extract the joint information from the text file.
363+ */
364+ private void parseJoints(BufferedReader reader) throws Exception {
365+ for (int i = 0; i < numberJoints; i++) {
366+ String line = getNextLine(reader);
367+ Joint joint = new Joint();
368+ joint.name = line.substring(1, line.length() - 1);
369+ line = getNextLine(reader);
370+ joint.parentName = line.substring(1, line.length() - 1);
371+ line = getNextLine(reader);
372+ String[] values = line.split(" ");
373+ joint.flags = Integer.parseInt(values[0]);
374+ joint.posx = Float.parseFloat(values[1]);
375+ joint.posy = Float.parseFloat(values[2]);
376+ joint.posz = Float.parseFloat(values[3]);
377+ joint.rotx = Float.parseFloat(values[4]);
378+ joint.roty = Float.parseFloat(values[5]);
379+ joint.rotz = Float.parseFloat(values[6]);
380+ line = getNextLine(reader);
381+ joint.numberPosistionKeyframes = Integer.parseInt(line);
382+ Keyframe[] positionKeyframes = new Keyframe[joint.numberPosistionKeyframes];
383+ for (int j = 0; j < joint.numberPosistionKeyframes; j++) {
384+ line = getNextLine(reader);
385+ values = line.split(" ");
386+ positionKeyframes[j] = new Keyframe(Float.parseFloat(values[0]), Float.parseFloat(values[1]), Float.parseFloat(values[2]), Float.parseFloat(values[3]));
356387 }
357- joints[i].parentName = Conversion.byte2String(parentBuffer);
388+ joint.positionKeys = positionKeyframes;
389+ line = getNextLine(reader);
390+ joint.numberRotationKeyframes = Integer.parseInt(line);
391+ Keyframe[] rotationKeyframes = new Keyframe[joint.numberRotationKeyframes];
392+ for (int j = 0; j < joint.numberRotationKeyframes; j++) {
393+ line = getNextLine(reader);
394+ values = line.split(" ");
395+ rotationKeyframes[j] = new Keyframe(Float.parseFloat(values[0]), Float.parseFloat(values[1]), Float.parseFloat(values[2]), Float.parseFloat(values[3]));
396+ }
397+ joint.rotationKeys = rotationKeyframes;
398+ joints[i] = joint;
358399
359400 int parentIndex = -1;
360401 if (joints[i].parentName.length() > 0) {
361- for (int j = 0; j < numJoints; j++) {
362- if (joints[j]
363- .name
364- .equalsIgnoreCase(joints[i].parentName)) {
402+ for (int j = 0; j < numberJoints; j++) {
403+ if (joints[j].name.equalsIgnoreCase(joints[i].parentName)) {
365404 parentIndex = j;
366405 break;
367406 }
368407 }
369408 if (parentIndex == -1) {
370- LoggingSystem.getLoggingSystem().getLogger().log(
371- Level.WARNING,
372- "Milkshape does not have a parent joint.");
373- return;
409+ System.out.println("CRAP!");
410+ System.exit(1);
374411 }
375412 }
376- joints[i].parent = parentIndex;
377- joints[i].rotation[0] = buffer.getFloat();
378- joints[i].rotation[1] = buffer.getFloat();
379- joints[i].rotation[2] = buffer.getFloat();
380-
381- joints[i].translation[0] = buffer.getFloat();
382- joints[i].translation[1] = buffer.getFloat();
383- joints[i].translation[2] = buffer.getFloat();
384-
385- joints[i].numRotationKeyframes = buffer.getShort();
386- joints[i].rotationKeyframes =
387- new Keyframe[joints[i].numRotationKeyframes];
388-
389- joints[i].numTranslationKeyframes = buffer.getShort();
390- joints[i].translationKeyframes =
391- new Keyframe[joints[i].numTranslationKeyframes];
392-
393- for (int j = 0; j < joints[i].numRotationKeyframes; j++) {
394- joints[i].rotationKeyframes[j] = new Keyframe();
395- joints[i].rotationKeyframes[j].time =
396- (buffer.getFloat() * 1000);
397- joints[i].rotationKeyframes[j].parameter[0] = buffer.getFloat();
398- joints[i].rotationKeyframes[j].parameter[1] = buffer.getFloat();
399- joints[i].rotationKeyframes[j].parameter[2] = buffer.getFloat();
400- }
401-
402- for (int j = 0; j < joints[i].numTranslationKeyframes; j++) {
403- joints[i].translationKeyframes[j] = new Keyframe();
404- joints[i].translationKeyframes[j].time =
405- (buffer.getFloat() * 1000);
406- joints[i].translationKeyframes[j].parameter[0] =
407- buffer.getFloat();
408- joints[i].translationKeyframes[j].parameter[1] =
409- buffer.getFloat();
410- joints[i].translationKeyframes[j].parameter[2] =
411- buffer.getFloat();
412- }
413+ joints[i].parentIndex = parentIndex;
414+ }
415+ if (animated) {
416+ setupJointAnimations();
413417 }
414-
415- //setupJoints();
416- //restart();
417418 }
418419
419420 /**
420- * <code>render</code> using the current mesh and material information to
421- * display the model to the screen.
421+ * Calculate the initial absolute and relative matrices for the joints.
422422 */
423- public void render() {
424- Triangle currentTri;
425- int triangleIndex;
426- int index;
427- FloatBuffer temp =
428- ByteBuffer
429- .allocateDirect(16)
430- .order(ByteOrder.nativeOrder())
431- .asFloatBuffer();
432- GL.glColor4f(red, green, blue, alpha);
433- GL.glPushMatrix();
434- GL.glScalef(scale.x, scale.y, scale.z);
435-
436- //go through each mesh and render them.
437- for (int i = 0; i < numMeshes; i++) {
438- int materialIndex = meshes[i].materialIndex;
439- //if the material is set, use it to set the texture and lighting.
440- if (materialIndex >= 0) {
441- temp.clear();
442- temp.put(materials[materialIndex].ambient);
443- temp.flip();
444- GL.glMaterial(GL.GL_FRONT, GL.GL_AMBIENT, temp);
445-
446- temp.clear();
447- temp.put(materials[materialIndex].diffuse);
448- temp.flip();
449- GL.glMaterial(GL.GL_FRONT, GL.GL_DIFFUSE, temp);
450-
451- temp.clear();
452- temp.put(materials[materialIndex].specular);
453- temp.flip();
454- GL.glMaterial(GL.GL_FRONT, GL.GL_SPECULAR, temp);
455-
456- temp.clear();
457- temp.put(materials[materialIndex].emissive);
458- temp.flip();
459- GL.glMaterial(GL.GL_FRONT, GL.GL_EMISSION, temp);
460-
461- GL.glMaterialf(
462- GL.GL_FRONT,
463- GL.GL_SHININESS,
464- materials[materialIndex].shininess);
465-
466- if (materials[materialIndex].texture > 0) {
467- TextureManager.getTextureManager().bind(
468- materials[materialIndex].texture);
469- GL.glEnable(GL.GL_TEXTURE_2D);
470- } else
471- GL.glDisable(GL.GL_TEXTURE_2D);
423+ private void setupJointAnimations() {
424+ for (int jointIndex = 0; jointIndex < numberJoints; jointIndex++) {
425+ Joint joint = joints[jointIndex];
426+ Vector rotationVector = new Vector();
427+ rotationVector.x = joint.rotx * 180 / (float) Math.PI;
428+ rotationVector.y = joint.roty * 180 / (float) Math.PI;
429+ rotationVector.z = joint.rotz * 180 / (float) Math.PI;
430+ joints[jointIndex].relativeMatrix.angleRotationDegrees(rotationVector);
431+ joints[jointIndex].relativeMatrix.matrix[0][3] = joint.posx;
432+ joints[jointIndex].relativeMatrix.matrix[1][3] = joint.posy;
433+ joints[jointIndex].relativeMatrix.matrix[2][3] = joint.posz;
434+ if (joint.parentIndex != -1) {
435+ joints[jointIndex].absoluteMatrix = joints[joint.parentIndex].absoluteMatrix.multiply(joints[jointIndex].relativeMatrix);
436+ joints[jointIndex].finalMatrix.copy(joints[jointIndex].absoluteMatrix);
472437 } else {
473- GL.glDisable(GL.GL_TEXTURE_2D);
438+ joints[jointIndex].absoluteMatrix.copy(joints[jointIndex].relativeMatrix);
439+ joints[jointIndex].finalMatrix.copy(joints[jointIndex].relativeMatrix);
474440 }
441+ }
475442
476- GL.glBegin(GL.GL_TRIANGLES);
477- int m = meshes[i].numTriangles;
478-
479- //render all triangles defined for the current mesh.
480- for (int j = 0; j < m; j++) {
481- triangleIndex = meshes[i].triangleIndices[j];
482- currentTri = triangles[triangleIndex];
483-
484- for (int k = 0; k < 3; k++) {
485- index = currentTri.vertexIndices[k];
486-
487- GL.glNormal3f(
488- currentTri.vertexNormals[k][0],
489- currentTri.vertexNormals[k][1],
490- currentTri.vertexNormals[k][2]);
491- GL.glTexCoord2f(currentTri.s[k], currentTri.t[k]);
492- GL.glVertex3f(
493- vertices[index].point[0],
494- vertices[index].point[1],
495- vertices[index].point[2]);
443+ for (int meshIndex = 0; meshIndex < numberMeshes; meshIndex++) {
444+ Mesh pMesh = meshes[meshIndex];
445+ for (int j = 0; j < pMesh.numberVertices; j++) {
446+ Vertex vertex = pMesh.vertices[j];
447+ if (vertex.boneIndex != -1) {
448+ vertex.x -= joints[vertex.boneIndex].absoluteMatrix.matrix[0][3];
449+ vertex.y -= joints[vertex.boneIndex].absoluteMatrix.matrix[1][3];
450+ vertex.z -= joints[vertex.boneIndex].absoluteMatrix.matrix[2][3];
451+ Vector inverseRotationVector = new Vector();
452+ inverseRotationVector = new Vector(vertex.x, vertex.y, vertex.z).inverseRotate(joints[vertex.boneIndex].absoluteMatrix);
453+ vertex.x = inverseRotationVector.x;
454+ vertex.y = inverseRotationVector.y;
455+ vertex.z = inverseRotationVector.z;
496456 }
497457 }
498- GL.glEnd();
499458 }
500- GL.glPopMatrix();
501- GL.glDisable(GL.GL_TEXTURE_2D);
502- }
503-
504- /**
505- * <code>setTexture</code> is not used for the model. Instead, the
506- * material set up is responsible for defining the texture.
507- * @param filename not used.
508- */
509- public void setTexture(String filename) {
510- //do nothing as textures are defined within the Milkshape MilkshapeModel.
511- }
512-
513- /**
514- * <code>setColor</code> will define the color of the model. This overall
515- * color may be overridden by the defined material information of the
516- * model.
517- * @param red the red component of the color.
518- * @param green the green component of the color.
519- * @param blue the blue component of the color.
520- * @param alpha the transparency of the color.
521- */
522- public void setColor(float red, float green, float blue, float alpha) {
523- this.red = red;
524- this.green = green;
525- this.blue = blue;
526- this.alpha = alpha;
527459 }
528460
529461 /**
530- * <code>setScale</code> sets the overall size of the model. The scale is
531- * used to decrease or increase the size of the model, where 1.0 is the
532- * normal size of the model.
533- * @param scale the multiplier of the model's size.
462+ * Set the final matrix of all of the joints to be part way between the
463+ * previous keyframe and the next keyframe, depending on how much time
464+ * has passed since the last keyframe.
534465 */
535- public void setScale(Vector scale) {
536- this.scale = scale;
537- }
466+ private void advanceFrame() {
467+ /* FIXME: The current frame needs to be determined by what milkshape
468+ model defined, not a constant value as below... otherwise,
469+ animations are going to be out of synch on different fps
470+ systems and animations with different numbers of frames */
471+ //currentFrame += ExampleModelLoader.dt;
472+ currentFrame += 0.1f;
473+ if (currentFrame > totalFrames) {
474+ currentFrame = 0.0f;
475+ }
538476
539- /**
540- * <code>getBoundingSphere</code> returns the bounding sphere that
541- * contains the model.
542- * @return the bounding sphere of the model.
543- */
544- public BoundingSphere getBoundingSphere() {
545- return boundingSphere;
546- }
477+ for (int meshIndex = 0; meshIndex < numberJoints; meshIndex++) {
478+ Joint joint = joints[meshIndex];
479+ int positionKeyframeCount = joint.numberPosistionKeyframes;
480+ int rotationKeyframeCount = joint.numberRotationKeyframes;
481+ if (positionKeyframeCount == 0 && rotationKeyframeCount == 0) {
482+ joints[meshIndex].finalMatrix.copy(joints[meshIndex].absoluteMatrix);
483+ } else {
484+ Vector positionVector = new Vector();
485+ Quaternion rotationVector = new Quaternion();
486+ Keyframe lastPositionKeyframe = null;
487+ Keyframe currentPositionKeyframe = null;
488+ for (int keyframeIndex = 0; keyframeIndex < positionKeyframeCount; keyframeIndex++) {
489+ Keyframe positionKeyframe = joint.positionKeys[keyframeIndex];
490+ if (positionKeyframe.time >= currentFrame) {
491+ currentPositionKeyframe = positionKeyframe;
492+ break;
493+ }
494+ lastPositionKeyframe = positionKeyframe;
495+ }
496+ if (lastPositionKeyframe != null && currentPositionKeyframe != null) {
497+ float d = currentPositionKeyframe.time - lastPositionKeyframe.time;
498+ float s = (currentFrame - lastPositionKeyframe.time) / d;
499+ positionVector.x = lastPositionKeyframe.x + (currentPositionKeyframe.x - lastPositionKeyframe.x) * s;
500+ positionVector.y = lastPositionKeyframe.y + (currentPositionKeyframe.y - lastPositionKeyframe.y) * s;
501+ positionVector.z = lastPositionKeyframe.z + (currentPositionKeyframe.z - lastPositionKeyframe.z) * s;
502+ } else if (lastPositionKeyframe == null) {
503+ currentPositionKeyframe.x = positionVector.x;
504+ currentPositionKeyframe.y = positionVector.y;
505+ currentPositionKeyframe.z = positionVector.z;
506+ } else if (currentPositionKeyframe == null) {
507+ lastPositionKeyframe.x = positionVector.x;
508+ lastPositionKeyframe.y = positionVector.y;
509+ lastPositionKeyframe.z = positionVector.z;
510+ }
511+ Matrix slerpedMatrix = new Matrix();
512+ Keyframe lastRotationKeyframe = null;
513+ Keyframe currentRotationKeyframe = null;
514+ for (int keyframeIndex = 0; keyframeIndex < rotationKeyframeCount; keyframeIndex++) {
515+ Keyframe rotationKeyframe = joint.rotationKeys[keyframeIndex];
516+ if (rotationKeyframe.time >= currentFrame) {
517+ currentRotationKeyframe = rotationKeyframe;
518+ break;
519+ }
520+ lastRotationKeyframe = rotationKeyframe;
521+ }
522+ if (lastRotationKeyframe != null && currentRotationKeyframe != null) {
523+ float d = currentRotationKeyframe.time - lastRotationKeyframe.time;
524+ float s = (currentFrame - lastRotationKeyframe.time) / d;
525+ Quaternion slerpedQuaternion = new Quaternion();
526+ Quaternion lastRotationQuaternion = new Quaternion();
527+ Quaternion currentRotationQuaternion = new Quaternion();
528+ lastRotationQuaternion.fromAngles(new float[]{lastRotationKeyframe.x, lastRotationKeyframe.y, lastRotationKeyframe.z});
529+ currentRotationQuaternion.fromAngles(new float[] {currentRotationKeyframe.x, currentRotationKeyframe.y, currentRotationKeyframe.z});
530+ slerpedQuaternion = slerpedQuaternion.slerp(lastRotationQuaternion, currentRotationQuaternion, s);
531+ slerpedMatrix.set(slerpedQuaternion);
532+ } else if (lastRotationKeyframe == null) {
533+ rotationVector.x = currentRotationKeyframe.x * 180 / (float) Math.PI;
534+ rotationVector.y = currentRotationKeyframe.y * 180 / (float) Math.PI;
535+ rotationVector.z = currentRotationKeyframe.z * 180 / (float) Math.PI;
536+ slerpedMatrix.angleRotationDegrees(new Vector(rotationVector.x, rotationVector.y, rotationVector.z));
537+ } else if (currentRotationKeyframe == null) {
538+ rotationVector.x = lastRotationKeyframe.x * 180 / (float) Math.PI;
539+ rotationVector.y = lastRotationKeyframe.y * 180 / (float) Math.PI;
540+ rotationVector.z = lastRotationKeyframe.z * 180 / (float) Math.PI;
541+ slerpedMatrix.angleRotationDegrees(new Vector(rotationVector.x, rotationVector.y, rotationVector.z));
542+ }
543+ slerpedMatrix.matrix[0][3] = positionVector.x;
544+ slerpedMatrix.matrix[1][3] = positionVector.y;
545+ slerpedMatrix.matrix[2][3] = positionVector.z;
546+ joints[meshIndex].relativeFinalMatrix = joints[meshIndex].relativeMatrix.multiply(slerpedMatrix);
547+ if (joint.parentIndex == -1) {
548+ joints[meshIndex].finalMatrix.copy(joints[meshIndex].relativeFinalMatrix);
549+ } else {
550+ joints[meshIndex].finalMatrix = joints[joint.parentIndex].finalMatrix.multiply(joints[meshIndex].relativeFinalMatrix);
551+ }
552+ }
553+ }
547554
548- /**
549- * <code>getBoundingBox</code> returns the bounding box that contains the
550- * model.
551- * @return the bounding box of the model.
552- */
553- public BoundingBox getBoundingBox() {
554- return boundingBox;
555555 }
556556
557557 /**
558- * <code>setBoundingVolumes</code> intializes the bounding sphere and box
559- * of the model.
560- *
558+ * Returns the next line from the text file being parsed. Removes
559+ * comments and trims the line of whitespace.
561560 */
562- private void setBoundingVolumes() {
563- float distanceSqr = 0;
564- float tempValue;
565- for (int i = 0; i < numVertices; i++) {
566- tempValue =
567- vertices[i].point[0] * vertices[i].point[0]
568- + vertices[i].point[1] * vertices[i].point[1]
569- + vertices[i].point[2] * vertices[i].point[2];
570- if (tempValue > distanceSqr) {
571- distanceSqr = tempValue;
561+ private String getNextLine(BufferedReader reader) throws Exception {
562+ String line = null;
563+ while ( (line = reader.readLine()) != null) {
564+ line = line.trim();
565+ if (line.startsWith("//") || "".equals(line)) {
566+ continue;
572567 }
568+ break;
573569 }
574- distanceSqr *= scale.x;
575- float distance = (float) Math.sqrt(distanceSqr);
576- boundingSphere = new BoundingSphere(distance, null);
577- boundingBox =
578- new BoundingBox(
579- new Vector(),
580- new Vector(-distance, -distance, -distance),
581- new Vector(distance, distance, distance));
570+ return line;
582571 }
583572
584573 /**
585- * <code>setupJoints</code> initializes the joint information for
586- * animation.
574+ * Reloads the textures.
587575 */
588- private void setupJoints() {
589- for (int i = 0; i < numJoints; i++) {
590- joints[i].relative = new Matrix();
591- joints[i].absolute = new Matrix();
592- joints[i].finalMatrix = new Matrix();
593-
594- joints[i].relative.setRotationRadians(joints[i].rotation);
595- joints[i].relative.setTranslation(joints[i].translation);
596-
597- if (joints[i].parent != -1) {
598- joints[i].absolute.set(
599- joints[joints[i].parent].absolute.getMatrix());
600- joints[i].absolute.multiply(joints[i].relative);
601- } else {
602- joints[i].absolute.set(joints[i].relative.getMatrix());
603- }
604- }
605-
606- for (int i = 0; i < numVertices; i++) {
607- if (vertices[i].boneId != -1) {
608- joints[vertices[i].boneId].absolute.inverseTranslateVect(
609- vertices[i].point);
610- joints[vertices[i].boneId].absolute.inverseRotateVect(
611- vertices[i].point);
612- }
613- }
614-
615- for (int i = 0; i < numTriangles; i++) {
616- Triangle tri = triangles[i];
617- for (int j = 0; j < 3; j++) {
618- Vertex vert = vertices[tri.vertexIndices[j]];
619- if (vert.boneId != -1) {
620- joints[vert.boneId].absolute.inverseRotateVect(
621- tri.vertexNormals[j]);
576+ private final void reloadTextures() {
577+ for (int i = 0; i < numberMaterials; i++) {
578+ if (materials[i].name.length() > 0) {
579+ try {
580+ materials[i].glTextureAddress = loadTexture(absoluteFilePath + materials[i].name);
581+ } catch (Exception e) {
582+ materials[i].glTextureAddress = 0;
622583 }
584+ } else {
585+ materials[i].glTextureAddress = 0;
623586 }
624587 }
625588 }
626589
627590 /**
628- *
629- * <code>restart</code> sets the animation to the initial key frame.
630- *
591+ * Loads a bitmap (*.bmp image file) texture in opengl memory
592+ * @param the relative filename to the bmp
593+ * @return the image address in memory
631594 */
632- private void restart() {
633- for (int i = 0; i < numJoints; i++) {
634- joints[i].currentRotationKeyframe =
635- joints[i].currentTranslationKeyframe = 0;
636- joints[i].finalMatrix.set(joints[i].absolute.getMatrix());
637- }
595+ private final int loadTexture(String file) throws Exception {
596+ return TextureManager.getTextureManager().loadTexture(file, GL.GL_LINEAR_MIPMAP_LINEAR,
597+ GL.GL_LINEAR,
598+ true, false);
599+
638600 }
639601
602+
603+ /* FIXME: these methods do not change the state of opengl so they can not
604+ be used on the fly to change between modes since the opengl
605+ state is currently created in the init method */
606+
640607 /**
641- * <code>loadTextures</code> makes the appropriate call to have
642- * OpenGL load all needed textures for the given model.
643- *
608+ * Determine is the model is going to run animations, if it has them.
609+ * @return the animation mode.
644610 */
645- private void loadTextures() {
646- for (int i = 0; i < numMaterials; i++) {
647- if (materials[i].textureFilename.length() > 0) {
648- String fullFilename = getPath(materials[i].textureFilename);
649- materials[i].texture =
650- TextureManager.getTextureManager().loadTexture(
651- fullFilename,
652- GL.GL_LINEAR_MIPMAP_LINEAR,
653- GL.GL_LINEAR,
654- true);
655- } else
656- materials[i].texture = 0;
657- }
611+ public boolean isAnimated() {
612+ return animated;
658613 }
659614
660615 /**
661- * <code>getPath</code> returns the path of the file.
662- * @param name the file name.
663- * @return the full resolved file path.
616+ * Set the new animation mode.
617+ * @param animated the new animation mode.
664618 */
665- private String getPath(String name) {
666- if (name.indexOf(".\\") != -1) {
667- name = name.substring(1);
668- }
669- return path + name;
619+ public void setAnimated(boolean animated) {
620+ this.animated = animated;
670621 }
671-
672-}
622+}
\ No newline at end of file
--- a/src/jme/math/Matrix.java
+++ b/src/jme/math/Matrix.java
@@ -39,11 +39,11 @@ import jme.exception.MonkeyRuntimeException;
3939 * convinience methods for creating the matrix from a multitude of sources.
4040 *
4141 * @author Mark Powell
42- * @version $Id: Matrix.java,v 1.5 2003-08-28 18:48:21 mojomonkey Exp $
42+ * @version $Id: Matrix.java,v 1.6 2003-09-04 21:17:51 mojomonkey Exp $
4343 */
4444 public class Matrix {
45- private float matrix[];
46-
45+ public float matrix[][];
46+
4747 /**
4848 * Constructor instantiates a new <code>Matrix</code> that is set to the
4949 * identity matrix.
@@ -64,9 +64,11 @@ public class Matrix {
6464 if(null == mat) {
6565 loadIdentity();
6666 } else {
67- for(int i = 0; i < 16; i++) {
68- matrix[i] = mat.getMatrix()[i];
69- }
67+ for(int i = 0; i < 4; i++) {
68+ for(int j = 0; j < 4; j++) {
69+ matrix[i][j] = mat.getMatrix()[i][j];
70+ }
71+ }
7072 }
7173 }
7274
@@ -76,8 +78,8 @@ public class Matrix {
7678 *
7779 */
7880 public void loadIdentity() {
79- matrix = new float[16];
80- matrix[0] = matrix[5] = matrix[10] = matrix[15] = 1;
81+ matrix = new float[4][4];
82+ matrix[0][0] = matrix[1][1] = matrix[2][2] = matrix[3][3] = 1;
8183 }
8284
8385 /**
@@ -86,19 +88,62 @@ public class Matrix {
8688 * @param matrix the matrix to set the value to.
8789 * @throws MonkeyRuntimeException if the array is not of size 16.
8890 */
89- public void set(float[] matrix) {
90- if (matrix.length != 16) {
91+ public void set(float[][] matrix) {
92+ if (matrix.length != 4 || matrix[0].length != 4) {
9193 throw new MonkeyRuntimeException("Array must be of size 16.");
9294 }
9395
94- for (int i = 0; i < 16; i++) {
95- this.matrix[i] = matrix[i];
96+ for (int i = 0; i < 4; i++) {
97+ for(int j = 0; j < 4; j++ ) {
98+ this.matrix[i][j] = matrix[i][j];
99+ }
100+ }
101+ }
102+
103+ public void set(float[] matrix) {
104+ for(int i = 0; i < 4; i++) {
105+ for(int j = 0; j < 4; j++) {
106+ this.matrix[i][j] = matrix[j*4 + i];
107+ }
108+ }
109+ }
110+
111+ public void set(Quaternion quaternion) {
112+ matrix[0][0] = (float) (1.0 - 2.0 * quaternion.y * quaternion.y - 2.0 * quaternion.z * quaternion.z);
113+ matrix[1][0] = (float) (2.0 * quaternion.x * quaternion.y + 2.0 * quaternion.w * quaternion.z);
114+ matrix[2][0] = (float) (2.0 * quaternion.x * quaternion.z - 2.0 * quaternion.w * quaternion.y);
115+
116+ matrix[0][1] = (float) (2.0 * quaternion.x * quaternion.y - 2.0 * quaternion.w * quaternion.z);
117+ matrix[1][1] = (float) (1.0 - 2.0 * quaternion.x * quaternion.x - 2.0 * quaternion.z * quaternion.z);
118+ matrix[2][1] = (float) (2.0 * quaternion.y * quaternion.z + 2.0 * quaternion.w * quaternion.x);
119+
120+ matrix[0][2] = (float) (2.0 * quaternion.x * quaternion.z + 2.0 * quaternion.w * quaternion.y);
121+ matrix[1][2] = (float) (2.0 * quaternion.y * quaternion.z - 2.0 * quaternion.w * quaternion.x);
122+ matrix[2][2] = (float) (1.0 - 2.0 * quaternion.x * quaternion.x - 2.0 * quaternion.y * quaternion.y);
123+
124+ }
125+
126+ public void copy(Matrix matrix) {
127+ if(null == matrix) {
128+ loadIdentity();
129+ } else {
130+ for(int i = 0; i < 4; i++) {
131+ for(int j = 0; j < 4; j++) {
132+ this.matrix[i][j] = matrix.matrix[i][j];
133+ }
134+ }
96135 }
97136 }
98137
138+ /**
139+ * <code>add</code> adds the values of a parameter matrix to this matrix.
140+ * @param matrix the matrix to add to this.
141+ */
99142 public void add(Matrix matrix) {
100- for(int i = 0; i < 16; i++) {
101- this.matrix[i] += matrix.getMatrix()[i];
143+ for(int i = 0; i < 4; i++) {
144+ for(int j = 0; j < 4; j++) {
145+ this.matrix[i][j] += matrix.getMatrix()[i][j];
146+ }
102147 }
103148 }
104149
@@ -107,81 +152,53 @@ public class Matrix {
107152 * @param scalar the scalar to multiply this matrix by.
108153 */
109154 public void multiply(float scalar) {
110- for(int i = 0; i < 16; i++) {
111- matrix[i] *= scalar;
155+ for(int i = 0; i < 4; i++) {
156+ for(int j = 0; j < 4; j++) {
157+ matrix[i][j] *= scalar;
158+ }
112159 }
113160 }
114161
115162 /**
116- * <code>multiply</code> multiplies this matrix with another matrix.
163+ * <code>multiply</code> multiplies this matrix with another matrix. The
164+ * result matrix will then be returned.
117165 * This matrix will be on the left hand side, while the parameter matrix
118166 * will be on the right.
119- * @param matrix the matrix to multiply this matrix by.
167+ * @param in2 the matrix to multiply this matrix by.
168+ * @return the resultant matrix
120169 * @throws MonkeyRuntimeException if matrix is null.
121170 */
122- public void multiply(Matrix matrix) {
123- if(null == matrix) {
124- throw new MonkeyRuntimeException("Matrix may not be null.");
125- }
126- this.matrix[0] =
127- this.matrix[0] * matrix.getMatrix()[0]
128- + this.matrix[4] * matrix.getMatrix()[1]
129- + this.matrix[8] * matrix.getMatrix()[2];
130- this.matrix[1] =
131- this.matrix[1] * matrix.getMatrix()[0]
132- + this.matrix[5] * matrix.getMatrix()[1]
133- + this.matrix[9] * matrix.getMatrix()[2];
134- this.matrix[2] =
135- this.matrix[2] * matrix.getMatrix()[0]
136- + this.matrix[6] * matrix.getMatrix()[1]
137- + this.matrix[10] * matrix.getMatrix()[2];
138- this.matrix[3] = 0;
139-
140- this.matrix[4] =
141- this.matrix[0] * matrix.getMatrix()[4]
142- + this.matrix[4] * matrix.getMatrix()[5]
143- + this.matrix[8] * matrix.getMatrix()[6];
144- this.matrix[5] =
145- this.matrix[1] * matrix.getMatrix()[4]
146- + this.matrix[5] * matrix.getMatrix()[5]
147- + this.matrix[9] * matrix.getMatrix()[6];
148- this.matrix[6] =
149- this.matrix[2] * matrix.getMatrix()[4]
150- + this.matrix[6] * matrix.getMatrix()[5]
151- + this.matrix[10] * matrix.getMatrix()[6];
152- this.matrix[7] = 0;
153-
154- this.matrix[8] =
155- this.matrix[0] * matrix.getMatrix()[8]
156- + this.matrix[4] * matrix.getMatrix()[9]
157- + this.matrix[8] * matrix.getMatrix()[10];
158- this.matrix[9] =
159- this.matrix[1] * matrix.getMatrix()[8]
160- + this.matrix[5] * matrix.getMatrix()[9]
161- + this.matrix[9] * matrix.getMatrix()[10];
162- this.matrix[10] =
163- this.matrix[2] * matrix.getMatrix()[8]
164- + this.matrix[6] * matrix.getMatrix()[9]
165- + this.matrix[10] * matrix.getMatrix()[10];
166- this.matrix[11] = 0;
167-
168- this.matrix[12] =
169- this.matrix[0] * matrix.getMatrix()[12]
170- + this.matrix[4] * matrix.getMatrix()[13]
171- + this.matrix[8] * matrix.getMatrix()[14]
172- + this.matrix[12];
173- this.matrix[13] =
174- this.matrix[1] * matrix.getMatrix()[12]
175- + this.matrix[5] * matrix.getMatrix()[13]
176- + this.matrix[9] * matrix.getMatrix()[14]
177- + this.matrix[13];
178- this.matrix[14] =
179- this.matrix[2] * matrix.getMatrix()[12]
180- + this.matrix[6] * matrix.getMatrix()[13]
181- + this.matrix[10] * matrix.getMatrix()[14]
182- + this.matrix[14];
183- this.matrix[15] = 1;
184-
171+ public Matrix multiply(Matrix in2) {
172+ Matrix out = new Matrix();
173+ out.matrix[0][0] = matrix[0][0] * in2.matrix[0][0] + matrix[0][1] * in2.matrix[1][0] + matrix[0][2] * in2.matrix[2][0];
174+ out.matrix[0][1] = matrix[0][0] * in2.matrix[0][1] + matrix[0][1] * in2.matrix[1][1] + matrix[0][2] * in2.matrix[2][1];
175+ out.matrix[0][2] = matrix[0][0] * in2.matrix[0][2] + matrix[0][1] * in2.matrix[1][2] + matrix[0][2] * in2.matrix[2][2];
176+ out.matrix[0][3] = matrix[0][0] * in2.matrix[0][3] + matrix[0][1] * in2.matrix[1][3] + matrix[0][2] * in2.matrix[2][3] + matrix[0][3];
177+ out.matrix[1][0] = matrix[1][0] * in2.matrix[0][0] + matrix[1][1] * in2.matrix[1][0] + matrix[1][2] * in2.matrix[2][0];
178+ out.matrix[1][1] = matrix[1][0] * in2.matrix[0][1] + matrix[1][1] * in2.matrix[1][1] + matrix[1][2] * in2.matrix[2][1];
179+ out.matrix[1][2] = matrix[1][0] * in2.matrix[0][2] + matrix[1][1] * in2.matrix[1][2] + matrix[1][2] * in2.matrix[2][2];
180+ out.matrix[1][3] = matrix[1][0] * in2.matrix[0][3] + matrix[1][1] * in2.matrix[1][3] + matrix[1][2] * in2.matrix[2][3] + matrix[1][3];
181+ out.matrix[2][0] = matrix[2][0] * in2.matrix[0][0] + matrix[2][1] * in2.matrix[1][0] + matrix[2][2] * in2.matrix[2][0];
182+ out.matrix[2][1] = matrix[2][0] * in2.matrix[0][1] + matrix[2][1] * in2.matrix[1][1] + matrix[2][2] * in2.matrix[2][1];
183+ out.matrix[2][2] = matrix[2][0] * in2.matrix[0][2] + matrix[2][1] * in2.matrix[1][2] + matrix[2][2] * in2.matrix[2][2];
184+ out.matrix[2][3] = matrix[2][0] * in2.matrix[0][3] + matrix[2][1] * in2.matrix[1][3] + matrix[2][2] * in2.matrix[2][3] + matrix[2][3];
185+ out.matrix[3][0] =
186+ this.matrix[0][0] * in2.getMatrix()[3][0]
187+ + this.matrix[1][0] * in2.getMatrix()[3][1]
188+ + this.matrix[2][0] * in2.getMatrix()[3][2]
189+ + this.matrix[3][0];
190+ out.matrix[3][1] =
191+ this.matrix[0][1] * in2.getMatrix()[3][0]
192+ + this.matrix[1][1] * in2.getMatrix()[3][1]
193+ + this.matrix[2][1] * in2.getMatrix()[3][2]
194+ + this.matrix[3][1];
195+ out.matrix[3][2] =
196+ this.matrix[0][2] * in2.getMatrix()[3][0]
197+ + this.matrix[1][2] * in2.getMatrix()[3][1]
198+ + this.matrix[2][2] * in2.getMatrix()[3][2]
199+ + this.matrix[3][2];
200+ out.matrix[3][3] = 1;
201+ return out;
185202 }
186203
187204 /**
@@ -193,9 +210,9 @@ public class Matrix {
193210 if (translation.length != 3) {
194211 throw new MonkeyRuntimeException("Translation size must be 3.");
195212 }
196- matrix[12] = translation[0];
197- matrix[13] = translation[1];
198- matrix[14] = translation[2];
213+ matrix[3][0] = translation[0];
214+ matrix[3][1] = translation[1];
215+ matrix[3][2] = translation[2];
199216 }
200217
201218 /**
@@ -208,59 +225,63 @@ public class Matrix {
208225 if (translation.length != 3) {
209226 throw new MonkeyRuntimeException("Translation size must be 3.");
210227 }
211- matrix[12] = -translation[0];
212- matrix[13] = -translation[1];
213- matrix[14] = -translation[2];
228+ matrix[3][0] = -translation[0];
229+ matrix[3][1] = -translation[1];
230+ matrix[3][2] = -translation[2];
214231 }
215232
216- /**
217- * <code>setRotationRadians</code> builds a rotation from Euler angles that
218- * are in radians.
219- * @param angles the Euler angles in radians.
220- * @throws MonkeyRuntimeException if angles is not size 3.
221- */
222- public void setRotationRadians(float[] angles) {
223- if (angles.length != 3) {
224- throw new MonkeyRuntimeException("Angles must be of size 3.");
225- }
226- double cr = Math.cos(angles[0]);
227- double sr = Math.sin(angles[0]);
228- double cp = Math.cos(angles[1]);
229- double sp = Math.sin(angles[1]);
230- double cy = Math.cos(angles[2]);
231- double sy = Math.sin(angles[2]);
233+ public void angleRotationRadians(Vector angles) {
234+ float sr, sp, sy, cr, cp, cy;
232235
233- matrix[0] = (float) (cp * cy);
234- matrix[1] = (float) (cp * sy);
235- matrix[2] = (float) (-sp);
236+ sy = (float) java.lang.Math.sin(angles.z);
237+ cy = (float) java.lang.Math.cos(angles.z);
238+ sp = (float) java.lang.Math.sin(angles.y);
239+ cp = (float) java.lang.Math.cos(angles.y);
240+ sr = (float) java.lang.Math.sin(angles.x);
241+ cr = (float) java.lang.Math.cos(angles.x);
236242
237- double srsp = sr * sp;
238- double crsp = cr * sp;
239-
240- matrix[4] = (float) (srsp * cy - cr * sy);
241- matrix[5] = (float) (srsp * sy + cr * cy);
242- matrix[6] = (float) (sr * cp);
243-
244- matrix[8] = (float) (crsp * cy + sr * sy);
245- matrix[9] = (float) (crsp * sy - sr * cy);
246- matrix[10] = (float) (cr * cp);
243+ // matrix = (Z * Y) * X
244+ matrix[0][0] = cp * cy;
245+ matrix[1][0] = cp * sy;
246+ matrix[2][0] = -sp;
247+ matrix[0][1] = sr * sp * cy + cr * -sy;
248+ matrix[1][1] = sr * sp * sy + cr * cy;
249+ matrix[2][1] = sr * cp;
250+ matrix[0][2] = (cr * sp * cy + -sr * -sy);
251+ matrix[1][2] = (cr * sp * sy + -sr * cy);
252+ matrix[2][2] = cr * cp;
253+ matrix[0][3] = 0.0f;
254+ matrix[1][3] = 0.0f;
255+ matrix[2][3] = 0.0f;
247256 }
257+
258+ public void angleRotationDegrees(Vector angles) {
259+ float angle;
260+ float sr, sp, sy, cr, cp, cy;
248261
249- /**
250- * <code>setRotationDegrees</code> builds a rotation from Euler angles that
251- * are in degrees.
252- * @param angles the Euler angles in degrees.
253- * @throws MonkeyRuntimeException if angles is not size 3.
254- */
255- public void setRotationDegrees(float[] angles) {
256- if (angles.length != 3) {
257- throw new MonkeyRuntimeException("Angles must be of size 3.");
258- }
259- float vec[] = new float[3];
260- vec[0] = (float) (angles[0] * 180.0 / Math.PI);
261- vec[1] = (float) (angles[1] * 180.0 / Math.PI);
262- vec[2] = (float) (angles[2] * 180.0 / Math.PI);
263- setRotationRadians(vec);
262+ angle = (float) (angles.z * (Math.PI * 2 / 360));
263+ sy = (float) java.lang.Math.sin(angle);
264+ cy = (float) java.lang.Math.cos(angle);
265+ angle = (float) (angles.y * (Math.PI * 2 / 360));
266+ sp = (float) java.lang.Math.sin(angle);
267+ cp = (float) java.lang.Math.cos(angle);
268+ angle = (float) (angles.x * (Math.PI * 2 / 360));
269+ sr = (float) java.lang.Math.sin(angle);
270+ cr = (float) java.lang.Math.cos(angle);
271+
272+ // matrix = (Z * Y) * X
273+ matrix[0][0] = cp * cy;
274+ matrix[1][0] = cp * sy;
275+ matrix[2][0] = -sp;
276+ matrix[0][1] = sr * sp * cy + cr * -sy;
277+ matrix[1][1] = sr * sp * sy + cr * cy;
278+ matrix[2][1] = sr * cp;
279+ matrix[0][2] = (cr * sp * cy + -sr * -sy);
280+ matrix[1][2] = (cr * sp * sy + -sr * cy);
281+ matrix[2][2] = cr * cp;
282+ matrix[0][3] = 0.0f;
283+ matrix[1][3] = 0.0f;
284+ matrix[2][3] = 0.0f;
264285 }
265286
266287 /**
@@ -273,19 +294,19 @@ public class Matrix {
273294 if(null == quat) {
274295 throw new MonkeyRuntimeException("Quat may not be null.");
275296 }
276- matrix[0] =
297+ matrix[0][0] =
277298 (float) (1.0 - 2.0 * quat.y * quat.y - 2.0 * quat.z * quat.z);
278- matrix[1] = (float) (2.0 * quat.x * quat.y + 2.0 * quat.w * quat.z);
279- matrix[2] = (float) (2.0 * quat.x * quat.z - 2.0 * quat.w * quat.y);
299+ matrix[0][1] = (float) (2.0 * quat.x * quat.y + 2.0 * quat.w * quat.z);
300+ matrix[0][2] = (float) (2.0 * quat.x * quat.z - 2.0 * quat.w * quat.y);
280301
281- matrix[4] = (float) (2.0 * quat.x * quat.y - 2.0 * quat.w * quat.z);
282- matrix[5] =
302+ matrix[1][0] = (float) (2.0 * quat.x * quat.y - 2.0 * quat.w * quat.z);
303+ matrix[1][1] =
283304 (float) (1.0 - 2.0 * quat.x * quat.x - 2.0 * quat.z * quat.z);
284- matrix[6] = (float) (2.0 * quat.y * quat.z + 2.0 * quat.w * quat.x);
305+ matrix[1][2] = (float) (2.0 * quat.y * quat.z + 2.0 * quat.w * quat.x);
285306
286- matrix[8] = (float) (2.0 * quat.x * quat.z + 2.0 * quat.w * quat.y);
287- matrix[9] = (float) (2.0 * quat.y * quat.z - 2.0 * quat.w * quat.x);
288- matrix[10] =
307+ matrix[2][0] = (float) (2.0 * quat.x * quat.z + 2.0 * quat.w * quat.y);
308+ matrix[2][1] = (float) (2.0 * quat.y * quat.z - 2.0 * quat.w * quat.x);
309+ matrix[2][2] =
289310 (float) (1.0 - 2.0 * quat.x * quat.x - 2.0 * quat.y * quat.y);
290311 }
291312
@@ -306,20 +327,20 @@ public class Matrix {
306327 double cy = Math.cos(angles[2]);
307328 double sy = Math.sin(angles[2]);
308329
309- matrix[0] = (float) (cp * cy);
310- matrix[4] = (float) (cp * sy);
311- matrix[8] = (float) (-sp);
330+ matrix[0][0] = (float) (cp * cy);
331+ matrix[1][0] = (float) (cp * sy);
332+ matrix[2][0] = (float) (-sp);
312333
313334 double srsp = sr * sp;
314335 double crsp = cr * sp;
315336
316- matrix[1] = (float) (srsp * cy - cr * sy);
317- matrix[5] = (float) (srsp * sy + cr * cy);
318- matrix[9] = (float) (sr * cp);
337+ matrix[0][1] = (float) (srsp * cy - cr * sy);
338+ matrix[1][1] = (float) (srsp * sy + cr * cy);
339+ matrix[2][1] = (float) (sr * cp);
319340
320- matrix[2] = (float) (crsp * cy + sr * sy);
321- matrix[6] = (float) (crsp * sy - sr * cy);
322- matrix[10] = (float) (cr * cp);
341+ matrix[0][2] = (float) (crsp * cy + sr * sy);
342+ matrix[1][2] = (float) (crsp * sy - sr * cy);
343+ matrix[2][2] = (float) (cr * cp);
323344 }
324345
325346 /**
@@ -344,7 +365,7 @@ public class Matrix {
344365 * floats. Size 16.
345366 * @return the array of floats that represent this matrix.
346367 */
347- public float[] getMatrix() {
368+ public float[][] getMatrix() {
348369 return matrix;
349370 }
350371
@@ -360,9 +381,9 @@ public class Matrix {
360381 throw new MonkeyRuntimeException("Vector must be of size 3.");
361382 }
362383
363- vector[0] = vector[0] - matrix[12];
364- vector[1] = vector[1] - matrix[13];
365- vector[2] = vector[2] - matrix[14];
384+ vector[0] = vector[0] - matrix[3][0];
385+ vector[1] = vector[1] - matrix[3][1];
386+ vector[2] = vector[2] - matrix[3][2];
366387 }
367388
368389 /**
@@ -378,28 +399,28 @@ public class Matrix {
378399 }
379400
380401 vector[0] =
381- vector[0] * matrix[0]
382- + vector[1] * matrix[1]
383- + vector[2] * matrix[2];
402+ vector[0] * matrix[0][0]
403+ + vector[1] * matrix[0][1]
404+ + vector[2] * matrix[0][2];
384405 vector[1] =
385- vector[0] * matrix[4]
386- + vector[1] * matrix[5]
387- + vector[2] * matrix[6];
406+ vector[0] * matrix[1][0]
407+ + vector[1] * matrix[1][1]
408+ + vector[2] * matrix[1][2];
388409 vector[2] =
389- vector[0] * matrix[8]
390- + vector[1] * matrix[9]
391- + vector[2] * matrix[10];
410+ vector[0] * matrix[2][0]
411+ + vector[1] * matrix[2][1]
412+ + vector[2] * matrix[2][2];
392413 }
393414
394415 public void tensorProduct (Vector u, Vector v) {
395- matrix[0] = u.x * v.x;
396- matrix[1] = u.x * v.y;
397- matrix[2] = u.x * v.z;
398- matrix[4] = u.y * v.x;
399- matrix[5] = u.y * v.y;
400- matrix[6] = u.y * v.z;
401- matrix[8] = u.z * v.x;
402- matrix[9] = u.z * v.y;
403- matrix[10] = u.z * v.z;
416+ matrix[0][0] = u.x * v.x;
417+ matrix[0][1] = u.x * v.y;
418+ matrix[0][2] = u.x * v.z;
419+ matrix[1][0] = u.y * v.x;
420+ matrix[1][1] = u.y * v.y;
421+ matrix[1][2] = u.y * v.z;
422+ matrix[2][0] = u.z * v.x;
423+ matrix[2][1] = u.z * v.y;
424+ matrix[2][2] = u.z * v.z;
404425 }
405426 }
--- a/src/jme/math/Vector.java
+++ b/src/jme/math/Vector.java
@@ -36,7 +36,7 @@ import jme.exception.MonkeyRuntimeException;
3636 /**
3737 * <code>Vector</code> defines a three dimensional vector of (x,y,z).
3838 * @author Mark Powell
39- * @version $Id: Vector.java,v 1.7 2003-08-22 02:26:48 mojomonkey Exp $
39+ * @version $Id: Vector.java,v 1.8 2003-09-04 21:17:51 mojomonkey Exp $
4040 */
4141 public class Vector {
4242 public float x;
@@ -181,6 +181,28 @@ public class Vector {
181181 ((z * v.x) - (x * v.z)),
182182 ((x * v.y) - (y * v.x)));
183183 }
184+
185+ /**
186+ * <code>rotate</code> rotates a vector about a rotation matrix. The
187+ * resulting vector is returned.
188+ * @param m the rotation matrix.
189+ * @return the rotated vector.
190+ */
191+ public Vector rotate(Matrix m) {
192+ Vector out = new Vector();
193+ out.x = dot(new Vector(m.matrix[0][0], m.matrix[0][1], m.matrix[0][2]));
194+ out.y = dot(new Vector(m.matrix[1][0], m.matrix[1][1], m.matrix[1][2]));
195+ out.z = dot(new Vector(m.matrix[2][0], m.matrix[2][1], m.matrix[2][2]));
196+ return out;
197+ }
198+
199+ public Vector inverseRotate(Matrix m) {
200+ Vector out = new Vector();
201+ out.x = x * m.matrix[0][0] + y * m.matrix[1][0] + z * m.matrix[2][0];
202+ out.y = x * m.matrix[0][1] + y * m.matrix[1][1] + z * m.matrix[2][1];
203+ out.z = x * m.matrix[0][2] + y * m.matrix[1][2] + z * m.matrix[2][2];
204+ return out;
205+ }
184206
185207 /**
186208 * <code>negate</code> sets this vector to the negative (-x, -y, -z).
--- a/src/jme/system/DisplaySystem.java
+++ b/src/jme/system/DisplaySystem.java
@@ -423,7 +423,7 @@ public class DisplaySystem {
423423
424424 if (fullscreen) {
425425 Display.setDisplayMode(mode);
426- Window.create(title, bpp, 0, 16, 0);
426+ Window.create(title, bpp, 0, 8, 0);
427427 } else {
428428 int x, y;
429429 x =
@@ -433,7 +433,7 @@ public class DisplaySystem {
433433 (Toolkit.getDefaultToolkit().getScreenSize().height
434434 - height)
435435 / 2;
436- Window.create(title, x, y, width, height, bpp, 0, 16, 0);
436+ Window.create(title, x, y, width, height, bpp, 0, 8, 0);
437437 }
438438
439439 GLCaps.determineAvailableExtensions();
--- a/src/jme/texture/TextureManager.java
+++ b/src/jme/texture/TextureManager.java
@@ -130,14 +130,24 @@ public class TextureManager {
130130 keyList = new ArrayList();
131131 previousKeys = new ArrayList();
132132 }
133-
133+
134134 /**
135135 * <code>reload</code> reloads all loaded textures after making a call
136136 * to <code>saveKeys</code>. This is useful for
137137 * reloading textures if the GL object has been recreated.
138- *
139138 */
140139 public void reload() {
140+ reload(true);
141+ }
142+
143+ /**
144+ * <code>reload</code> reloads all loaded textures after making a call
145+ * to <code>saveKeys</code>. This is useful for
146+ * reloading textures if the GL object has been recreated.
147+ * @param flipped true flips the bits of the image, false does not. True
148+ * by default.
149+ */
150+ public void reload(boolean flipped) {
141151 saveKeys();
142152 deleteAll();
143153
@@ -158,17 +168,31 @@ public class TextureManager {
158168 tempData.image,
159169 tempData.minFilter,
160170 tempData.magFilter,
161- tempData.mipmapped);
171+ tempData.mipmapped, flipped);
162172 }
163173 }
164-
174+
165175 /**
166176 * <code>batchLoad</code> loads a collection of textures defined by an
167177 * <code>ArrayList</code>.
168178 *
169179 * @param keys the list of files to open.
180+ * @param flipped true flips the bits of the image, false does not. True
181+ * by default.
170182 */
171183 public void batchLoad(ArrayList keys) {
184+ batchLoad(keys, true);
185+ }
186+
187+ /**
188+ * <code>batchLoad</code> loads a collection of textures defined by an
189+ * <code>ArrayList</code>.
190+ *
191+ * @param keys the list of files to open.
192+ * @param flipped true flips the bits of the image, false does not. True
193+ * by default.
194+ */
195+ public void batchLoad(ArrayList keys, boolean flipped) {
172196
173197 TextureData tempData;
174198 for (int i = 0; i < keys.size(); i++) {
@@ -178,7 +202,7 @@ public class TextureManager {
178202 tempData.image,
179203 tempData.minFilter,
180204 tempData.magFilter,
181- tempData.mipmapped);
205+ tempData.mipmapped, flipped);
182206 }
183207 }
184208
@@ -192,6 +216,27 @@ public class TextureManager {
192216 previousKeys = (ArrayList) keyList.clone();
193217 return previousKeys;
194218 }
219+
220+ /**
221+ * <code>loadTexture</code> loads a new texture defined by a loaded
222+ * ImageIcon. If a texture with the same filename has previously been loaded,
223+ * that id is returned rather than reloading. Filter parameters are used
224+ * to define the filtering of the texture. Whether the texture is to be
225+ * mipmapped or not is denoted by the isMipmapped boolean flag. If there
226+ * is an error loading the file, -1 is returned.
227+ *
228+ * @param image the ImageIcon of the texture image.
229+ * @param minFilter the filter for the near values.
230+ * @param magFilter the filter for the far values.
231+ * @param isMipmapped determines if we will load the texture mipmapped
232+ * or not. True load the texture mipmapped, false do not.
233+ *
234+ * @return an integer for the loaded texture id. If there is a problem
235+ * loading the texture -1 is returned.
236+ */
237+ public int loadTexture(ImageIcon image, int minFilter, int magFilter, boolean isMipMapped) {
238+ return loadTexture(image, minFilter, magFilter, isMipMapped, true);
239+ }
195240
196241 /**
197242 * <code>loadTexture</code> loads a new texture defined by a loaded
@@ -206,6 +251,8 @@ public class TextureManager {
206251 * @param magFilter the filter for the far values.
207252 * @param isMipmapped determines if we will load the texture mipmapped
208253 * or not. True load the texture mipmapped, false do not.
254+ * @param flipped true flips the bits of the image, false does not. True
255+ * by default.
209256 *
210257 * @return an integer for the loaded texture id. If there is a problem
211258 * loading the texture -1 is returned.
@@ -214,7 +261,8 @@ public class TextureManager {
214261 ImageIcon image,
215262 int minFilter,
216263 int magFilter,
217- boolean isMipmapped) {
264+ boolean isMipmapped,
265+ boolean flipped) {
218266
219267 //check if the texture is already loaded.
220268 Object obj = textureList.get(image.getDescription());
@@ -228,9 +276,32 @@ public class TextureManager {
228276 image.getImage(),
229277 minFilter,
230278 magFilter,
231- isMipmapped);
279+ isMipmapped, true);
232280
233281 }
282+
283+ /**
284+ * <code>loadTexture</code> loads a new texture defined by the parameter
285+ * string. If a texture with the same filename has previously been loaded,
286+ * that id is returned rather than reloading. Filter parameters are used
287+ * to define the filtering of the texture. Whether the texture is to be
288+ * mipmapped or not is denoted by the isMipmapped boolean flag. If there
289+ * is an error loading the file, -1 is returned.
290+ *
291+ * @param file the filename of the texture image.
292+ * @param minFilter the filter for the near values.
293+ * @param magFilter the filter for the far values.
294+ * @param isMipmapped determines if we will load the texture mipmapped
295+ * or not. True load the texture mipmapped, false do not.
296+ * @param flipped true flips the bits of the image, false does not. True
297+ * by default.
298+ *
299+ * @return an integer for the loaded texture id. If there is a problem
300+ * loading the texture -1 is returned.
301+ */
302+ public int loadTexture(String file, int minFilter, int magFilter, boolean isMipMapped) {
303+ return loadTexture(file, minFilter, magFilter, isMipMapped, true);
304+ }
234305
235306 /**
236307 * <code>loadTexture</code> loads a new texture defined by the parameter
@@ -253,7 +324,8 @@ public class TextureManager {
253324 String file,
254325 int minFilter,
255326 int magFilter,
256- boolean isMipmapped) {
327+ boolean isMipmapped,
328+ boolean flipped) {
257329
258330 //check if the texture is already loaded.
259331 Object obj = textureList.get(file);
@@ -282,7 +354,7 @@ public class TextureManager {
282354 return -1;
283355 }
284356
285- return loadImage(file, image, minFilter, magFilter, isMipmapped);
357+ return loadImage(file, image, minFilter, magFilter, isMipmapped, flipped);
286358
287359 }
288360
@@ -468,7 +540,8 @@ public class TextureManager {
468540 Image image,
469541 int minFilter,
470542 int magFilter,
471- boolean isMipmapped) {
543+ boolean isMipmapped,
544+ boolean flipImage) {
472545 // Obtain the image data.
473546 BufferedImage tex = null;
474547 try {
@@ -487,12 +560,14 @@ public class TextureManager {
487560 g.drawImage(image, null, null);
488561 g.dispose();
489562
490- //Flip the image
491- AffineTransform tx = AffineTransform.getScaleInstance(1, -1);
492- tx.translate(0, -image.getHeight(null));
493- AffineTransformOp op =
494- new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
495- tex = op.filter(tex, null);
563+ if(flipImage) {
564+ //Flip the image
565+ AffineTransform tx = AffineTransform.getScaleInstance(1, -1);
566+ tx.translate(0, -image.getHeight(null));
567+ AffineTransformOp op =
568+ new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
569+ tex = op.filter(tex, null);
570+ }
496571
497572 //Get a pointer to the image memory
498573 ByteBuffer scratch =
--- a/src/test/general/TestMain.java
+++ b/src/test/general/TestMain.java
@@ -235,23 +235,20 @@ public class TestMain extends AbstractGame {
235235 }
236236
237237 private void initGL() {
238- GL.glShadeModel(GL.GL_SMOOTH);
238+
239239 GL.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
240240 GL.glClearDepth(1.0);
241241 GL.glEnable(GL.GL_DEPTH_TEST);
242- GL.glDepthFunc(GL.GL_LESS);
242+ GL.glDepthFunc(GL.GL_LEQUAL);
243+
243244 GL.glMatrixMode(GL.GL_PROJECTION);
244245 GL.glLoadIdentity();
245- // Calculate The Aspect Ratio Of The Window
246- GLU.gluPerspective(
247- 45.0f,
248- (float) Display.getWidth() / (float) Display.getHeight(),
249- 0.1f,
250- 500.0f);
251- GL.glMatrixMode(GL.GL_MODELVIEW);
252- GL.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);
253- GL.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE);
254- DisplaySystem.getDisplaySystem().cullMode(GL.GL_BACK, true);
246+
247+ GLU.gluPerspective(45.0f, (float) Display.getWidth() / (float) Display.getHeight(), 1.0f, 750.0f);
248+ GL.glMatrixMode(GL.GL_MODELVIEW);
249+
250+ GL.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);
251+ DisplaySystem.getDisplaySystem().cullMode(GL.GL_BACK, true);
255252
256253 }
257254 protected void reinit() {
--- /dev/null
+++ b/src/test/model/ms3dAscii/TestAsciiMilkshape.java
@@ -0,0 +1,195 @@
1+/*
2+ * Copyright (c) 2003 najgl Project
3+ * All rights reserved.
4+ *
5+ * Redistribution and use in source and binary forms, with or without
6+ * modification, are permitted provided that the following conditions are met:
7+ *
8+ * 1) Redistributions of source code must retain the above copyright
9+ * notice, this list of conditions and the following disclaimer.
10+ *
11+ * 2) Redistributions in binary form must reproduce the above copyright
12+ * notice, this list of conditions and the following disclaimer in the
13+ * documentation and/or other materials provided with the distribution.
14+ *
15+ * 3) Neither the name of 'najgl' nor the names of its contributors
16+ * may be used to endorse or promote products derived from this software
17+ * without specific prior written permission.
18+ *
19+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30+ */
31+
32+package test.model.ms3dAscii;
33+
34+import jme.geometry.model.Model;
35+import jme.geometry.model.ms.MilkshapeModel;
36+
37+import org.lwjgl.Display;
38+import org.lwjgl.input.Keyboard;
39+import org.lwjgl.opengl.GL;
40+import org.lwjgl.opengl.GLCaps;
41+import org.lwjgl.opengl.GLU;
42+import org.lwjgl.opengl.Window;
43+
44+/**
45+ * A basic lwjgl game skeleton. Starts up opengl. The game loop executes
46+ * forever, or until the escape key is pressed or the window is closed. Can
47+ * be run in windowed or fullscreen mode.
48+ *
49+ * The demo will load a Milkshape 3D model, rotate it around the y-axis, and
50+ * play its animation.
51+ *
52+ * @author naj
53+ * @version 0.1
54+ */
55+public class TestAsciiMilkshape {
56+
57+ private static final boolean WIREFRAME = false;
58+ private static final boolean ANIMATED = true;
59+
60+ private static boolean fullscreen = false;
61+ private static String modelFilename = "data/run.txt";
62+// private static String modelFilename = "data/diablo.txt";
63+
64+ private static boolean finished;
65+ private static float yrot;
66+ private static int count;
67+ private static Model model;
68+
69+ public static float dt = 0.2f;
70+
71+ public static void main(String[] args) {
72+ if (args.length == 1) {
73+ modelFilename = args[0];
74+ } else if (args.length == 2) {
75+ modelFilename = args[0];
76+ fullscreen = (args[1] != null && args[1].equalsIgnoreCase("fullscreen")) ? true : false;
77+ } else {
78+ System.out.println("Usage: java -jar example1.jar <filename> [fullscreen]");
79+ System.out.println(" - filename must be a ms3d ascii text file");
80+ System.out.println(" - add the optional word 'fullscreen' for fullscreen mode");
81+ System.exit(1);
82+ }
83+ model = new MilkshapeModel(ANIMATED);
84+ try {
85+ init();
86+ while (!finished) {
87+ Keyboard.poll();
88+ mainLoop();
89+ render();
90+ Window.update();
91+ Window.paint();
92+ }
93+ } catch (Throwable t) {
94+ t.printStackTrace();
95+ } finally {
96+ cleanup();
97+ }
98+ }
99+
100+ /**
101+ * Start up and initialize OpenGL.
102+ */
103+ private final static void init() throws Exception {
104+ if (fullscreen) {
105+ Window.create("Milkshape Model Animation (Fullscreen)", 16, 0, 8, 0);
106+ } else {
107+ Window.create("Milkshape Model Animation", 50, 50, 640, 480, 16, 0, 8, 0);
108+ }
109+ Keyboard.create();
110+
111+ model.load(modelFilename);
112+
113+ if (WIREFRAME) {
114+ GL.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_LINE);
115+ } else {
116+ GL.glEnable(GL.GL_TEXTURE_2D);
117+ GL.glShadeModel(GL.GL_SMOOTH);
118+ }
119+ GL.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
120+ GL.glClearDepth(1.0);
121+ GL.glEnable(GL.GL_DEPTH_TEST);
122+ GL.glDepthFunc(GL.GL_LEQUAL);
123+
124+ GL.glMatrixMode(GL.GL_PROJECTION);
125+ GL.glLoadIdentity();
126+
127+ GLU.gluPerspective(45.0f, (float) Display.getWidth() / (float) Display.getHeight(), 100.0f, 2000.0f);
128+ GL.glMatrixMode(GL.GL_MODELVIEW);
129+
130+ GL.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);
131+
132+ GLCaps.determineAvailableExtensions();
133+ if (GLCaps.WGL_EXT_swap_control) {
134+ GL.wglSwapIntervalEXT(1);
135+ }
136+ }
137+
138+ /**
139+ * Rendering method.
140+ */
141+ private final static void render() {
142+ if (!fullscreen && count++ > 20) {
143+ Window.setTitle("Milkshape Model Animation");
144+ count = 0;
145+ }
146+
147+ GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
148+ GL.glLoadIdentity();
149+ GLU.gluLookAt(50, 0, 300, 0, 0, 0, 0, 1, 0);
150+ GL.glRotatef(yrot, 0.0f, 1.0f, 0.0f);
151+ yrot += 0.3f;
152+ model.render();
153+ }
154+
155+ /**
156+ * Main loop.
157+ */
158+ private final static void mainLoop() {
159+ processKeyboard();
160+ processWindow();
161+ }
162+
163+ /**
164+ * Process keyboard events.
165+ */
166+ private final static void processKeyboard() {
167+ if (Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) {
168+ finished = true;
169+ }
170+ if (Keyboard.isKeyDown(Keyboard.KEY_UP)) {
171+ dt += 0.01;
172+ }
173+ if (Keyboard.isKeyDown(Keyboard.KEY_DOWN)) {
174+ dt -= 0.01; dt = Math.max(0.05f, dt);
175+ }
176+ }
177+
178+ /**
179+ * Process window events.
180+ */
181+ private final static void processWindow() {
182+ if (Window.isCloseRequested()) {
183+ finished = true;
184+ }
185+ }
186+
187+ /**
188+ * Cleanup.
189+ */
190+ private final static void cleanup() {
191+ Keyboard.destroy();
192+ Window.destroy();
193+ }
194+
195+}
\ No newline at end of file
--- a/src/test/model/TestMilkshape.java
+++ b/src/test/model/ms3dAscii/TestMilkshape.java
@@ -29,41 +29,44 @@
2929 * POSSIBILITY OF SUCH DAMAGE.
3030 *
3131 */
32-
33-package test.model;
32+package test.model.ms3dAscii;
3433
35-import org.lwjgl.Display;
36-import org.lwjgl.opengl.GL;
34+
35+import org.lwjgl.Display;
36+import org.lwjgl.opengl.GL;
3737 import org.lwjgl.opengl.GLU;
3838 import org.lwjgl.opengl.Window;
3939
40-import jme.AbstractGame;
40+import jme.AbstractGame;
4141 import jme.controller.BaseFPSController;
4242 import jme.entity.camera.Camera;
43+import jme.geometry.model.Model;
4344 import jme.geometry.model.ms.MilkshapeModel;
4445 import jme.system.DisplaySystem;
4546 import jme.utility.Timer;
4647
4748 /**
48- *
4949 * @author Mark Powell
50+ *
51+ * To change the template for this generated type comment go to
52+ * Window - Preferences - Java - Code Generation - Code and Comments
5053 */
51-
5254 public class TestMilkshape extends AbstractGame {
53- //our model object
54- private MilkshapeModel model;
5555
56- BaseFPSController controller;
57- Timer timer;
58- Camera camera;
56+ private Model model;
57+ private float yrot;
58+ private BaseFPSController cc;
59+ private Timer timer;
60+ private Camera camera;
61+
5962 /**
6063 * This is where we'll do any updating
6164 */
6265 protected void update() {
63- timer.update();
64- if(!controller.update(timer.getFrameRate())) {
66+ if(!cc.update(timer.getFrameRate())) {
6567 finish();
6668 }
69+ timer.update();
6770 }
6871
6972 /**
@@ -72,7 +75,7 @@ public class TestMilkshape extends AbstractGame {
7275 protected void render() {
7376 GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
7477 GL.glLoadIdentity();
75- controller.render();
78+ cc.render();
7679 model.render();
7780 }
7881
@@ -95,20 +98,17 @@ public class TestMilkshape extends AbstractGame {
9598 //Define the clear color to be black
9699
97100 GL.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
101+ GL.glClearDepth(1.0);
102+ GL.glEnable(GL.GL_DEPTH_TEST);
103+ GL.glDepthFunc(GL.GL_LEQUAL);
98104
99105 GL.glMatrixMode(GL.GL_PROJECTION);
100106 GL.glLoadIdentity();
101-
102-
103- // Calculate the aspect ratio
104- GLU.gluPerspective(
105- 45.0f,
106- (float)Display.getWidth() / (float)Display.getHeight(),
107- 0.01f,
108- 750.0f);
109-
107+
108+ GLU.gluPerspective(45.0f, (float) Display.getWidth() / (float) Display.getHeight(), 100.0f, 2000.0f);
110109 GL.glMatrixMode(GL.GL_MODELVIEW);
111- GL.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);
110+
111+ GL.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);
112112 }
113113
114114 /**
@@ -117,15 +117,16 @@ public class TestMilkshape extends AbstractGame {
117117 protected void initSystem() {
118118 initDisplay();
119119 initGL();
120+ camera = new Camera(1,50, 0, 300, 0, 0, 0, 0, 1, 0);
121+ cc = new BaseFPSController(camera);
122+ timer = Timer.getTimer();
120123 }
121124 /**
122125 * Nothing here yet.
123126 */
124127 protected void initGame() {
125- model = new MilkshapeModel("./data/model/arab/ak47.ms3d");
126- camera = new Camera(1,0,0,100,0,10,0,0,1,0);
127- controller = new BaseFPSController(camera);
128- timer = Timer.getTimer();
128+ model = new MilkshapeModel(true);
129+ model.load("data/model/msascii/run.txt");
129130 }
130131
131132 /**
@@ -150,4 +151,4 @@ public class TestMilkshape extends AbstractGame {
150151 testApp.start();
151152 }
152153 }
153-
\ No newline at end of file
154+