1/*
2 * Copyright (c) 2009-2010 jMonkeyEngine
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 *   notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 *   notice, this list of conditions and the following disclaimer in the
14 *   documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17 *   may be used to endorse or promote products derived from this software
18 *   without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33package com.jme3.scene.shape;
34
35import com.jme3.export.InputCapsule;
36import com.jme3.export.JmeExporter;
37import com.jme3.export.JmeImporter;
38import com.jme3.export.OutputCapsule;
39import com.jme3.math.Vector3f;
40import com.jme3.scene.Mesh;
41import java.io.IOException;
42
43/**
44 * An eight sided box.
45 * <p>
46 * A {@code Box} is defined by a minimal point and a maximal point. The eight
47 * vertices that make the box are then computed, they are computed in such
48 * a way as to generate an axis-aligned box.
49 * <p>
50 * This class does not control how the geometry data is generated, see {@link Box}
51 * for that.
52 *
53 * @author <a href="mailto:ianp@ianp.org">Ian Phillips</a>
54 * @version $Revision: 4131 $, $Date: 2009-03-19 16:15:28 -0400 (Thu, 19 Mar 2009) $
55 */
56public abstract class AbstractBox extends Mesh {
57
58    public final Vector3f center = new Vector3f(0f, 0f, 0f);
59
60    public float xExtent, yExtent, zExtent;
61
62    public AbstractBox() {
63        super();
64    }
65
66    /**
67     * Gets the array or vectors representing the 8 vertices of the box.
68     *
69     * @return a newly created array of vertex vectors.
70     */
71    protected final Vector3f[] computeVertices() {
72        Vector3f[] axes = {
73                Vector3f.UNIT_X.mult(xExtent),
74                Vector3f.UNIT_Y.mult(yExtent),
75                Vector3f.UNIT_Z.mult(zExtent)
76        };
77        return new Vector3f[] {
78                center.subtract(axes[0]).subtractLocal(axes[1]).subtractLocal(axes[2]),
79                center.add(axes[0]).subtractLocal(axes[1]).subtractLocal(axes[2]),
80                center.add(axes[0]).addLocal(axes[1]).subtractLocal(axes[2]),
81                center.subtract(axes[0]).addLocal(axes[1]).subtractLocal(axes[2]),
82                center.add(axes[0]).subtractLocal(axes[1]).addLocal(axes[2]),
83                center.subtract(axes[0]).subtractLocal(axes[1]).addLocal(axes[2]),
84                center.add(axes[0]).addLocal(axes[1]).addLocal(axes[2]),
85                center.subtract(axes[0]).addLocal(axes[1]).addLocal(axes[2])
86        };
87    }
88
89    /**
90     * Convert the indices into the list of vertices that define the box's geometry.
91     */
92    protected abstract void duUpdateGeometryIndices();
93
94    /**
95     * Update the normals of each of the box's planes.
96     */
97    protected abstract void duUpdateGeometryNormals();
98
99    /**
100     * Update the points that define the texture of the box.
101     * <p>
102     * It's a one-to-one ratio, where each plane of the box has it's own copy
103     * of the texture. That is, the texture is repeated one time for each face.
104     */
105    protected abstract void duUpdateGeometryTextures();
106
107    /**
108     * Update the position of the vertices that define the box.
109     * <p>
110     * These eight points are determined from the minimum and maximum point.
111     */
112    protected abstract void duUpdateGeometryVertices();
113
114    /**
115     * Get the center point of this box.
116     */
117    public final Vector3f getCenter() {
118        return center;
119    }
120
121    /**
122     * Get the x-axis size (extent) of this box.
123     */
124    public final float getXExtent() {
125        return xExtent;
126    }
127
128    /**
129     * Get the y-axis size (extent) of this box.
130     */
131    public final float getYExtent() {
132        return yExtent;
133    }
134
135    /**
136     * Get the z-axis size (extent) of this box.
137     */
138    public final float getZExtent() {
139        return zExtent;
140    }
141
142    /**
143     * Rebuilds the box after a property has been directly altered.
144     * <p>
145     * For example, if you call {@code getXExtent().x = 5.0f} then you will
146     * need to call this method afterwards in order to update the box.
147     */
148    public final void updateGeometry() {
149        duUpdateGeometryVertices();
150        duUpdateGeometryNormals();
151        duUpdateGeometryTextures();
152        duUpdateGeometryIndices();
153    }
154
155    /**
156     * Rebuilds this box based on a new set of parameters.
157     * <p>
158     * Note that the actual sides will be twice the given extent values because
159     * the box extends in both directions from the center for each extent.
160     *
161     * @param center the center of the box.
162     * @param x the x extent of the box, in each directions.
163     * @param y the y extent of the box, in each directions.
164     * @param z the z extent of the box, in each directions.
165     */
166    public final void updateGeometry(Vector3f center, float x, float y, float z) {
167        if (center != null) {this.center.set(center); }
168        this.xExtent = x;
169        this.yExtent = y;
170        this.zExtent = z;
171        updateGeometry();
172    }
173
174    /**
175     * Rebuilds this box based on a new set of parameters.
176     * <p>
177     * The box is updated so that the two opposite corners are {@code minPoint}
178     * and {@code maxPoint}, the other corners are created from those two positions.
179     *
180     * @param minPoint the new minimum point of the box.
181     * @param maxPoint the new maximum point of the box.
182     */
183    public final void updateGeometry(Vector3f minPoint, Vector3f maxPoint) {
184        center.set(maxPoint).addLocal(minPoint).multLocal(0.5f);
185        float x = maxPoint.x - center.x;
186        float y = maxPoint.y - center.y;
187        float z = maxPoint.z - center.z;
188        updateGeometry(center, x, y, z);
189    }
190
191    @Override
192    public void read(JmeImporter e) throws IOException {
193        super.read(e);
194        InputCapsule capsule = e.getCapsule(this);
195        xExtent = capsule.readFloat("xExtent", 0);
196        yExtent = capsule.readFloat("yExtent", 0);
197        zExtent = capsule.readFloat("zExtent", 0);
198        center.set((Vector3f) capsule.readSavable("center", Vector3f.ZERO.clone()));
199    }
200
201    @Override
202    public void write(JmeExporter e) throws IOException {
203        super.write(e);
204        OutputCapsule capsule = e.getCapsule(this);
205        capsule.write(xExtent, "xExtent", 0);
206        capsule.write(yExtent, "yExtent", 0);
207        capsule.write(zExtent, "zExtent", 0);
208        capsule.write(center, "center", Vector3f.ZERO);
209    }
210
211}
212