Main repository of MikuMikuStudio
Revision | 330dbd18622934376d803455320607727de98fa6 (tree) |
---|---|
Time | 2003-09-05 06:17:51 |
Author | mojomonkey <mojomonkey@75d0...> |
Commiter | mojomonkey |
New Milkshape loader changes.
git-svn-id: http://jmonkeyengine.googlecode.com/svn/trunk@78 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
@@ -29,26 +29,90 @@ | ||
29 | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | 30 | * |
31 | 31 | */ |
32 | + | |
32 | 33 | package jme.geometry.model; |
33 | 34 | |
34 | 35 | import jme.math.Matrix; |
35 | 36 | |
37 | + | |
38 | + | |
36 | 39 | /** |
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 | |
40 | 45 | */ |
41 | 46 | public class Joint { |
47 | + | |
48 | + /** | |
49 | + * The name of the joint in MS3D. | |
50 | + */ | |
42 | 51 | public String name; |
52 | + | |
53 | + /** | |
54 | + * The name of the parent joint in MS3D. | |
55 | + */ | |
43 | 56 | 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 |
@@ -29,15 +29,44 @@ | ||
29 | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | 30 | * |
31 | 31 | */ |
32 | + | |
32 | 33 | package jme.geometry.model; |
33 | 34 | |
34 | 35 | /** |
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 | |
38 | 42 | */ |
39 | 43 | 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 | + */ | |
41 | 49 | 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 |
@@ -29,45 +29,66 @@ | ||
29 | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | 30 | * |
31 | 31 | */ |
32 | + | |
32 | 33 | package jme.geometry.model; |
33 | 34 | |
34 | 35 | /** |
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 | |
38 | 41 | */ |
39 | - | |
40 | 42 | public class Material { |
43 | + | |
44 | + /** | |
45 | + * The filename of the bitmap. Must be relative to the loaded model file. | |
46 | + */ | |
41 | 47 | 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 | + */ | |
42 | 92 | 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 |
@@ -29,29 +29,61 @@ | ||
29 | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | 30 | * |
31 | 31 | */ |
32 | + | |
32 | 33 | package jme.geometry.model; |
33 | 34 | |
34 | 35 | /** |
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. | |
39 | 37 | * |
40 | - *Special thanks to Chman's <a href="http://chman-area.tuxfamily.org">site</a> for help. | |
38 | + * @author naj | |
39 | + * @version 0.1 | |
41 | 40 | */ |
42 | 41 | public class Mesh { |
43 | - public byte flags; | |
42 | + | |
43 | + /** | |
44 | + * The name of the mesh in MS3D. | |
45 | + */ | |
44 | 46 | 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 |
@@ -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 |
@@ -29,34 +29,79 @@ | ||
29 | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | 30 | * |
31 | 31 | */ |
32 | + | |
32 | 33 | package jme.geometry.model; |
33 | 34 | |
34 | 35 | /** |
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. | |
38 | 38 | * |
39 | - * @author Mark Powell | |
39 | + * @author naj | |
40 | + * @version 0.1 | |
40 | 41 | */ |
41 | 42 | public class Triangle { |
43 | + | |
44 | + /** | |
45 | + * The flags in MS3D. | |
46 | + */ | |
42 | 47 | 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 |
@@ -29,51 +29,74 @@ | ||
29 | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | 30 | * |
31 | 31 | */ |
32 | -package jme.geometry.model; | |
33 | - | |
34 | -import jme.math.Vector; | |
35 | 32 | |
33 | +package jme.geometry.model; | |
36 | 34 | |
37 | 35 | /** |
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 | |
42 | 41 | */ |
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; | |
45 | 78 | |
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 |
@@ -29,644 +29,594 @@ | ||
29 | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | 30 | * |
31 | 31 | */ |
32 | + | |
32 | 33 | package jme.geometry.model.ms; |
33 | 34 | |
35 | +import java.io.BufferedReader; | |
34 | 36 | import java.io.File; |
35 | -import java.io.FileInputStream; | |
36 | -import java.io.FileNotFoundException; | |
37 | -import java.io.IOException; | |
37 | +import java.io.FileReader; | |
38 | 38 | import java.nio.ByteBuffer; |
39 | 39 | 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; | |
45 | 40 | |
46 | -import jme.exception.MonkeyGLException; | |
47 | -import jme.geometry.*; | |
48 | -import jme.geometry.bounding.BoundingBox; | |
49 | -import jme.geometry.bounding.BoundingSphere; | |
50 | 41 | import jme.geometry.model.Joint; |
51 | 42 | import jme.geometry.model.Keyframe; |
52 | 43 | import jme.geometry.model.Material; |
53 | 44 | import jme.geometry.model.Mesh; |
45 | +import jme.geometry.model.Model; | |
54 | 46 | import jme.geometry.model.Triangle; |
55 | 47 | import jme.geometry.model.Vertex; |
56 | 48 | import jme.math.Matrix; |
49 | +import jme.math.Quaternion; | |
57 | 50 | import jme.math.Vector; |
51 | +import jme.system.DisplaySystem; | |
58 | 52 | import jme.texture.TextureManager; |
59 | -import jme.utility.Conversion; | |
60 | -import jme.utility.LoggingSystem; | |
53 | + | |
54 | +import org.lwjgl.opengl.GL; | |
61 | 55 | |
62 | 56 | /** |
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 | |
70 | 76 | */ |
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 { | |
87 | 78 | |
88 | 79 | /** |
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. | |
99 | 81 | */ |
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 | + | |
109 | 84 | /** |
110 | - * the number of vertices that makes up the model. | |
85 | + * The total number of frames in the animation. | |
111 | 86 | */ |
112 | - private int numVertices = 0; | |
87 | + private int totalFrames; | |
88 | + | |
113 | 89 | /** |
114 | - * the number of joints that make up the model. | |
90 | + * The current frame of the animation. | |
115 | 91 | */ |
116 | - private int numJoints = 0; | |
92 | + private float currentFrame; | |
93 | + | |
117 | 94 | /** |
118 | - * the total animation time. | |
95 | + * The number of meshes in the model. | |
119 | 96 | */ |
120 | - private float totalTime = 0; | |
97 | + private int numberMeshes; | |
98 | + | |
121 | 99 | /** |
122 | - * the array of meshes that build the model. | |
100 | + * The number of materials or textures in the model. | |
123 | 101 | */ |
124 | - private Mesh meshes[] = null; | |
102 | + private int numberMaterials; | |
103 | + | |
125 | 104 | /** |
126 | - * the array of materials that build the model. | |
105 | + * The number of joints or bones in the model. | |
127 | 106 | */ |
128 | - private Material materials[] = null; | |
107 | + private int numberJoints; | |
108 | + | |
129 | 109 | /** |
130 | - * the array of triangles that build the model. | |
110 | + * The meshes in the model. | |
131 | 111 | */ |
132 | - private Triangle triangles[] = null; | |
112 | + private Mesh[] meshes; | |
113 | + | |
133 | 114 | /** |
134 | - * the array of vertices that build the model. | |
115 | + * The materials in the model. | |
135 | 116 | */ |
136 | - private Vertex vertices[] = null; | |
117 | + private Material[] materials; | |
118 | + | |
137 | 119 | /** |
138 | - * the array of Joints that build the model. | |
120 | + * The joints in the model. | |
139 | 121 | */ |
140 | - private Joint joints[] = null; | |
122 | + private Joint[] joints; | |
141 | 123 | |
142 | 124 | /** |
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. | |
146 | 127 | */ |
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; | |
152 | 129 | |
153 | - this.modelFile = modelFile; | |
130 | + | |
154 | 131 | |
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 | + } | |
160 | 135 | |
161 | - initialize(); | |
162 | - setBoundingVolumes(); | |
136 | + public MilkshapeModel(boolean animated) { | |
137 | + this.animated = animated; | |
163 | 138 | } |
164 | 139 | |
165 | 140 | /** |
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. | |
168 | 143 | */ |
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(); | |
194 | 148 | } |
149 | + boolean isTextureEnabled = GL.glIsEnabled(GL.GL_TEXTURE_2D); | |
195 | 150 | |
196 | - buffer = ByteBuffer.wrap(data).order(ByteOrder.nativeOrder()); | |
151 | + for (int meshIndex = 0; meshIndex < numberMeshes; meshIndex++) { | |
152 | + int materialIndex = meshes[meshIndex].materialIndex; | |
197 | 153 | |
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()); | |
220 | 156 | |
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); | |
233 | 162 | |
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); | |
242 | 171 | } |
243 | 172 | |
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; | |
249 | 175 | |
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 | + } | |
253 | 195 | |
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 | + } | |
256 | 227 | } |
228 | + GL.glEnd(); | |
229 | + } | |
257 | 230 | |
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); | |
260 | 235 | } |
236 | + | |
237 | + } | |
261 | 238 | |
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 | + } | |
278 | 272 | } |
279 | - meshes[i].materialIndex = buffer.get(); | |
280 | - | |
273 | + } catch (Exception e) { | |
274 | + e.printStackTrace(); | |
281 | 275 | } |
282 | 276 | |
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 | + } | |
288 | 279 | |
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])); | |
293 | 298 | } |
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])}; | |
324 | 309 | } |
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])); | |
329 | 319 | } |
330 | - materials[i].alphaFilename = Conversion.byte2String(texBuffer); | |
320 | + mesh.triangles = triangles; | |
321 | + meshes[i] = mesh; | |
331 | 322 | } |
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 | + } | |
350 | 360 | |
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])); | |
356 | 387 | } |
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; | |
358 | 399 | |
359 | 400 | int parentIndex = -1; |
360 | 401 | 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)) { | |
365 | 404 | parentIndex = j; |
366 | 405 | break; |
367 | 406 | } |
368 | 407 | } |
369 | 408 | 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); | |
374 | 411 | } |
375 | 412 | } |
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(); | |
413 | 417 | } |
414 | - | |
415 | - //setupJoints(); | |
416 | - //restart(); | |
417 | 418 | } |
418 | 419 | |
419 | 420 | /** |
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. | |
422 | 422 | */ |
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); | |
472 | 437 | } else { |
473 | - GL.glDisable(GL.GL_TEXTURE_2D); | |
438 | + joints[jointIndex].absoluteMatrix.copy(joints[jointIndex].relativeMatrix); | |
439 | + joints[jointIndex].finalMatrix.copy(joints[jointIndex].relativeMatrix); | |
474 | 440 | } |
441 | + } | |
475 | 442 | |
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; | |
496 | 456 | } |
497 | 457 | } |
498 | - GL.glEnd(); | |
499 | 458 | } |
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; | |
527 | 459 | } |
528 | 460 | |
529 | 461 | /** |
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. | |
534 | 465 | */ |
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 | + } | |
538 | 476 | |
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 | + } | |
547 | 554 | |
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; | |
555 | 555 | } |
556 | 556 | |
557 | 557 | /** |
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. | |
561 | 560 | */ |
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; | |
572 | 567 | } |
568 | + break; | |
573 | 569 | } |
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; | |
582 | 571 | } |
583 | 572 | |
584 | 573 | /** |
585 | - * <code>setupJoints</code> initializes the joint information for | |
586 | - * animation. | |
574 | + * Reloads the textures. | |
587 | 575 | */ |
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; | |
622 | 583 | } |
584 | + } else { | |
585 | + materials[i].glTextureAddress = 0; | |
623 | 586 | } |
624 | 587 | } |
625 | 588 | } |
626 | 589 | |
627 | 590 | /** |
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 | |
631 | 594 | */ |
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 | + | |
638 | 600 | } |
639 | 601 | |
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 | + | |
640 | 607 | /** |
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. | |
644 | 610 | */ |
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; | |
658 | 613 | } |
659 | 614 | |
660 | 615 | /** |
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. | |
664 | 618 | */ |
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; | |
670 | 621 | } |
671 | - | |
672 | -} | |
622 | +} | |
\ No newline at end of file |
@@ -39,11 +39,11 @@ import jme.exception.MonkeyRuntimeException; | ||
39 | 39 | * convinience methods for creating the matrix from a multitude of sources. |
40 | 40 | * |
41 | 41 | * @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 $ | |
43 | 43 | */ |
44 | 44 | public class Matrix { |
45 | - private float matrix[]; | |
46 | - | |
45 | + public float matrix[][]; | |
46 | + | |
47 | 47 | /** |
48 | 48 | * Constructor instantiates a new <code>Matrix</code> that is set to the |
49 | 49 | * identity matrix. |
@@ -64,9 +64,11 @@ public class Matrix { | ||
64 | 64 | if(null == mat) { |
65 | 65 | loadIdentity(); |
66 | 66 | } 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 | + } | |
70 | 72 | } |
71 | 73 | } |
72 | 74 |
@@ -76,8 +78,8 @@ public class Matrix { | ||
76 | 78 | * |
77 | 79 | */ |
78 | 80 | 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; | |
81 | 83 | } |
82 | 84 | |
83 | 85 | /** |
@@ -86,19 +88,62 @@ public class Matrix { | ||
86 | 88 | * @param matrix the matrix to set the value to. |
87 | 89 | * @throws MonkeyRuntimeException if the array is not of size 16. |
88 | 90 | */ |
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) { | |
91 | 93 | throw new MonkeyRuntimeException("Array must be of size 16."); |
92 | 94 | } |
93 | 95 | |
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 | + } | |
96 | 135 | } |
97 | 136 | } |
98 | 137 | |
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 | + */ | |
99 | 142 | 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 | + } | |
102 | 147 | } |
103 | 148 | } |
104 | 149 |
@@ -107,81 +152,53 @@ public class Matrix { | ||
107 | 152 | * @param scalar the scalar to multiply this matrix by. |
108 | 153 | */ |
109 | 154 | 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 | + } | |
112 | 159 | } |
113 | 160 | } |
114 | 161 | |
115 | 162 | /** |
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. | |
117 | 165 | * This matrix will be on the left hand side, while the parameter matrix |
118 | 166 | * 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 | |
120 | 169 | * @throws MonkeyRuntimeException if matrix is null. |
121 | 170 | */ |
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; | |
185 | 202 | } |
186 | 203 | |
187 | 204 | /** |
@@ -193,9 +210,9 @@ public class Matrix { | ||
193 | 210 | if (translation.length != 3) { |
194 | 211 | throw new MonkeyRuntimeException("Translation size must be 3."); |
195 | 212 | } |
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]; | |
199 | 216 | } |
200 | 217 | |
201 | 218 | /** |
@@ -208,59 +225,63 @@ public class Matrix { | ||
208 | 225 | if (translation.length != 3) { |
209 | 226 | throw new MonkeyRuntimeException("Translation size must be 3."); |
210 | 227 | } |
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]; | |
214 | 231 | } |
215 | 232 | |
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; | |
232 | 235 | |
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); | |
236 | 242 | |
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; | |
247 | 256 | } |
257 | + | |
258 | + public void angleRotationDegrees(Vector angles) { | |
259 | + float angle; | |
260 | + float sr, sp, sy, cr, cp, cy; | |
248 | 261 | |
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; | |
264 | 285 | } |
265 | 286 | |
266 | 287 | /** |
@@ -273,19 +294,19 @@ public class Matrix { | ||
273 | 294 | if(null == quat) { |
274 | 295 | throw new MonkeyRuntimeException("Quat may not be null."); |
275 | 296 | } |
276 | - matrix[0] = | |
297 | + matrix[0][0] = | |
277 | 298 | (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); | |
280 | 301 | |
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] = | |
283 | 304 | (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); | |
285 | 306 | |
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] = | |
289 | 310 | (float) (1.0 - 2.0 * quat.x * quat.x - 2.0 * quat.y * quat.y); |
290 | 311 | } |
291 | 312 |
@@ -306,20 +327,20 @@ public class Matrix { | ||
306 | 327 | double cy = Math.cos(angles[2]); |
307 | 328 | double sy = Math.sin(angles[2]); |
308 | 329 | |
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); | |
312 | 333 | |
313 | 334 | double srsp = sr * sp; |
314 | 335 | double crsp = cr * sp; |
315 | 336 | |
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); | |
319 | 340 | |
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); | |
323 | 344 | } |
324 | 345 | |
325 | 346 | /** |
@@ -344,7 +365,7 @@ public class Matrix { | ||
344 | 365 | * floats. Size 16. |
345 | 366 | * @return the array of floats that represent this matrix. |
346 | 367 | */ |
347 | - public float[] getMatrix() { | |
368 | + public float[][] getMatrix() { | |
348 | 369 | return matrix; |
349 | 370 | } |
350 | 371 |
@@ -360,9 +381,9 @@ public class Matrix { | ||
360 | 381 | throw new MonkeyRuntimeException("Vector must be of size 3."); |
361 | 382 | } |
362 | 383 | |
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]; | |
366 | 387 | } |
367 | 388 | |
368 | 389 | /** |
@@ -378,28 +399,28 @@ public class Matrix { | ||
378 | 399 | } |
379 | 400 | |
380 | 401 | 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]; | |
384 | 405 | 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]; | |
388 | 409 | 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]; | |
392 | 413 | } |
393 | 414 | |
394 | 415 | 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; | |
404 | 425 | } |
405 | 426 | } |
@@ -36,7 +36,7 @@ import jme.exception.MonkeyRuntimeException; | ||
36 | 36 | /** |
37 | 37 | * <code>Vector</code> defines a three dimensional vector of (x,y,z). |
38 | 38 | * @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 $ | |
40 | 40 | */ |
41 | 41 | public class Vector { |
42 | 42 | public float x; |
@@ -181,6 +181,28 @@ public class Vector { | ||
181 | 181 | ((z * v.x) - (x * v.z)), |
182 | 182 | ((x * v.y) - (y * v.x))); |
183 | 183 | } |
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 | + } | |
184 | 206 | |
185 | 207 | /** |
186 | 208 | * <code>negate</code> sets this vector to the negative (-x, -y, -z). |
@@ -423,7 +423,7 @@ public class DisplaySystem { | ||
423 | 423 | |
424 | 424 | if (fullscreen) { |
425 | 425 | Display.setDisplayMode(mode); |
426 | - Window.create(title, bpp, 0, 16, 0); | |
426 | + Window.create(title, bpp, 0, 8, 0); | |
427 | 427 | } else { |
428 | 428 | int x, y; |
429 | 429 | x = |
@@ -433,7 +433,7 @@ public class DisplaySystem { | ||
433 | 433 | (Toolkit.getDefaultToolkit().getScreenSize().height |
434 | 434 | - height) |
435 | 435 | / 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); | |
437 | 437 | } |
438 | 438 | |
439 | 439 | GLCaps.determineAvailableExtensions(); |
@@ -130,14 +130,24 @@ public class TextureManager { | ||
130 | 130 | keyList = new ArrayList(); |
131 | 131 | previousKeys = new ArrayList(); |
132 | 132 | } |
133 | - | |
133 | + | |
134 | 134 | /** |
135 | 135 | * <code>reload</code> reloads all loaded textures after making a call |
136 | 136 | * to <code>saveKeys</code>. This is useful for |
137 | 137 | * reloading textures if the GL object has been recreated. |
138 | - * | |
139 | 138 | */ |
140 | 139 | 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) { | |
141 | 151 | saveKeys(); |
142 | 152 | deleteAll(); |
143 | 153 |
@@ -158,17 +168,31 @@ public class TextureManager { | ||
158 | 168 | tempData.image, |
159 | 169 | tempData.minFilter, |
160 | 170 | tempData.magFilter, |
161 | - tempData.mipmapped); | |
171 | + tempData.mipmapped, flipped); | |
162 | 172 | } |
163 | 173 | } |
164 | - | |
174 | + | |
165 | 175 | /** |
166 | 176 | * <code>batchLoad</code> loads a collection of textures defined by an |
167 | 177 | * <code>ArrayList</code>. |
168 | 178 | * |
169 | 179 | * @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. | |
170 | 182 | */ |
171 | 183 | 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) { | |
172 | 196 | |
173 | 197 | TextureData tempData; |
174 | 198 | for (int i = 0; i < keys.size(); i++) { |
@@ -178,7 +202,7 @@ public class TextureManager { | ||
178 | 202 | tempData.image, |
179 | 203 | tempData.minFilter, |
180 | 204 | tempData.magFilter, |
181 | - tempData.mipmapped); | |
205 | + tempData.mipmapped, flipped); | |
182 | 206 | } |
183 | 207 | } |
184 | 208 |
@@ -192,6 +216,27 @@ public class TextureManager { | ||
192 | 216 | previousKeys = (ArrayList) keyList.clone(); |
193 | 217 | return previousKeys; |
194 | 218 | } |
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 | + } | |
195 | 240 | |
196 | 241 | /** |
197 | 242 | * <code>loadTexture</code> loads a new texture defined by a loaded |
@@ -206,6 +251,8 @@ public class TextureManager { | ||
206 | 251 | * @param magFilter the filter for the far values. |
207 | 252 | * @param isMipmapped determines if we will load the texture mipmapped |
208 | 253 | * 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. | |
209 | 256 | * |
210 | 257 | * @return an integer for the loaded texture id. If there is a problem |
211 | 258 | * loading the texture -1 is returned. |
@@ -214,7 +261,8 @@ public class TextureManager { | ||
214 | 261 | ImageIcon image, |
215 | 262 | int minFilter, |
216 | 263 | int magFilter, |
217 | - boolean isMipmapped) { | |
264 | + boolean isMipmapped, | |
265 | + boolean flipped) { | |
218 | 266 | |
219 | 267 | //check if the texture is already loaded. |
220 | 268 | Object obj = textureList.get(image.getDescription()); |
@@ -228,9 +276,32 @@ public class TextureManager { | ||
228 | 276 | image.getImage(), |
229 | 277 | minFilter, |
230 | 278 | magFilter, |
231 | - isMipmapped); | |
279 | + isMipmapped, true); | |
232 | 280 | |
233 | 281 | } |
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 | + } | |
234 | 305 | |
235 | 306 | /** |
236 | 307 | * <code>loadTexture</code> loads a new texture defined by the parameter |
@@ -253,7 +324,8 @@ public class TextureManager { | ||
253 | 324 | String file, |
254 | 325 | int minFilter, |
255 | 326 | int magFilter, |
256 | - boolean isMipmapped) { | |
327 | + boolean isMipmapped, | |
328 | + boolean flipped) { | |
257 | 329 | |
258 | 330 | //check if the texture is already loaded. |
259 | 331 | Object obj = textureList.get(file); |
@@ -282,7 +354,7 @@ public class TextureManager { | ||
282 | 354 | return -1; |
283 | 355 | } |
284 | 356 | |
285 | - return loadImage(file, image, minFilter, magFilter, isMipmapped); | |
357 | + return loadImage(file, image, minFilter, magFilter, isMipmapped, flipped); | |
286 | 358 | |
287 | 359 | } |
288 | 360 |
@@ -468,7 +540,8 @@ public class TextureManager { | ||
468 | 540 | Image image, |
469 | 541 | int minFilter, |
470 | 542 | int magFilter, |
471 | - boolean isMipmapped) { | |
543 | + boolean isMipmapped, | |
544 | + boolean flipImage) { | |
472 | 545 | // Obtain the image data. |
473 | 546 | BufferedImage tex = null; |
474 | 547 | try { |
@@ -487,12 +560,14 @@ public class TextureManager { | ||
487 | 560 | g.drawImage(image, null, null); |
488 | 561 | g.dispose(); |
489 | 562 | |
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 | + } | |
496 | 571 | |
497 | 572 | //Get a pointer to the image memory |
498 | 573 | ByteBuffer scratch = |
@@ -235,23 +235,20 @@ public class TestMain extends AbstractGame { | ||
235 | 235 | } |
236 | 236 | |
237 | 237 | private void initGL() { |
238 | - GL.glShadeModel(GL.GL_SMOOTH); | |
238 | + | |
239 | 239 | GL.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); |
240 | 240 | GL.glClearDepth(1.0); |
241 | 241 | GL.glEnable(GL.GL_DEPTH_TEST); |
242 | - GL.glDepthFunc(GL.GL_LESS); | |
242 | + GL.glDepthFunc(GL.GL_LEQUAL); | |
243 | + | |
243 | 244 | GL.glMatrixMode(GL.GL_PROJECTION); |
244 | 245 | 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); | |
255 | 252 | |
256 | 253 | } |
257 | 254 | protected void reinit() { |
@@ -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 |
@@ -29,41 +29,44 @@ | ||
29 | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | 30 | * |
31 | 31 | */ |
32 | - | |
33 | -package test.model; | |
32 | +package test.model.ms3dAscii; | |
34 | 33 | |
35 | -import org.lwjgl.Display; | |
36 | -import org.lwjgl.opengl.GL; | |
34 | + | |
35 | +import org.lwjgl.Display; | |
36 | +import org.lwjgl.opengl.GL; | |
37 | 37 | import org.lwjgl.opengl.GLU; |
38 | 38 | import org.lwjgl.opengl.Window; |
39 | 39 | |
40 | -import jme.AbstractGame; | |
40 | +import jme.AbstractGame; | |
41 | 41 | import jme.controller.BaseFPSController; |
42 | 42 | import jme.entity.camera.Camera; |
43 | +import jme.geometry.model.Model; | |
43 | 44 | import jme.geometry.model.ms.MilkshapeModel; |
44 | 45 | import jme.system.DisplaySystem; |
45 | 46 | import jme.utility.Timer; |
46 | 47 | |
47 | 48 | /** |
48 | - * | |
49 | 49 | * @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 | |
50 | 53 | */ |
51 | - | |
52 | 54 | public class TestMilkshape extends AbstractGame { |
53 | - //our model object | |
54 | - private MilkshapeModel model; | |
55 | 55 | |
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 | + | |
59 | 62 | /** |
60 | 63 | * This is where we'll do any updating |
61 | 64 | */ |
62 | 65 | protected void update() { |
63 | - timer.update(); | |
64 | - if(!controller.update(timer.getFrameRate())) { | |
66 | + if(!cc.update(timer.getFrameRate())) { | |
65 | 67 | finish(); |
66 | 68 | } |
69 | + timer.update(); | |
67 | 70 | } |
68 | 71 | |
69 | 72 | /** |
@@ -72,7 +75,7 @@ public class TestMilkshape extends AbstractGame { | ||
72 | 75 | protected void render() { |
73 | 76 | GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); |
74 | 77 | GL.glLoadIdentity(); |
75 | - controller.render(); | |
78 | + cc.render(); | |
76 | 79 | model.render(); |
77 | 80 | } |
78 | 81 |
@@ -95,20 +98,17 @@ public class TestMilkshape extends AbstractGame { | ||
95 | 98 | //Define the clear color to be black |
96 | 99 | |
97 | 100 | 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); | |
98 | 104 | |
99 | 105 | GL.glMatrixMode(GL.GL_PROJECTION); |
100 | 106 | 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); | |
110 | 109 | 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); | |
112 | 112 | } |
113 | 113 | |
114 | 114 | /** |
@@ -117,15 +117,16 @@ public class TestMilkshape extends AbstractGame { | ||
117 | 117 | protected void initSystem() { |
118 | 118 | initDisplay(); |
119 | 119 | initGL(); |
120 | + camera = new Camera(1,50, 0, 300, 0, 0, 0, 0, 1, 0); | |
121 | + cc = new BaseFPSController(camera); | |
122 | + timer = Timer.getTimer(); | |
120 | 123 | } |
121 | 124 | /** |
122 | 125 | * Nothing here yet. |
123 | 126 | */ |
124 | 127 | 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"); | |
129 | 130 | } |
130 | 131 | |
131 | 132 | /** |
@@ -150,4 +151,4 @@ public class TestMilkshape extends AbstractGame { | ||
150 | 151 | testApp.start(); |
151 | 152 | } |
152 | 153 | } |
153 | - | |
\ No newline at end of file | ||
154 | + |