001/***************************************************************************** 002 * J3D.org Copyright (c) 2000 003 * Java Source 004 * 005 * This source is licensed under the GNU LGPL v2.1 006 * Please read http://www.gnu.org/copyleft/lgpl.html for more information 007 * 008 ****************************************************************************/ 009 010package jahuwaldt.j3d.geom; 011 012// Standard imports 013import org.jogamp.vecmath.Vector3f; 014 015// Application specific imports 016// none 017 018/** 019 * Abstract base representation of geometry generator of box raw coordinate 020 * and geometry normals. 021 * <p> 022 * 023 * Curved surfaces would like to generate a smooth object most of the time. 024 * To do this, the normal values at each vertex are made to smooth the values 025 * for each set of faces that use that value (ie the effect is averaged between 026 * all the sharing faces). The typical approach to do this is to work with a 027 * value called creaseAngle. If the angle between two surfaces is less that 028 * the creaseAngle, a smoothed normal is generated. If greater, the normal is 029 * perpendicular to the face. If we are playing with different numbers of 030 * facets in an object, this gets rather annoying at times as some pieces may 031 * or may not be faceted. At the same time there is a performance hit for 032 * generating the normals as you have to check every face and build a lot of 033 * extra data before you start doing normal calculations. 034 * <p> 035 * 036 * This library takes a much simplified approach - let the geometry generator 037 * implementation decide. Our aim is for speed here and if we have to decide 038 * in a general fashion for every normal calculation, that could be a huge 039 * impact. 040 * <P> 041 * 042 * Obvious limitations to this are shapes like the cube or a near-degenerate 043 * cone that ends up as a pyramid. The smoothing of normals may be there, but 044 * no matter how hard you try, the differences between the face angles will 045 * just be too great. 046 * 047 * @author Justin Couch 048 * @version $Revision: 1.6-JAH1 $ 049 */ 050public abstract class GeometryGenerator 051{ 052 /** Working values for the normal generation */ 053 private final Vector3f normal; 054 private final Vector3f v0; 055 private final Vector3f v1; 056 057 protected GeometryGenerator() 058 { 059 v0 = new Vector3f(); 060 v1 = new Vector3f(); 061 normal = new Vector3f(); 062 } 063 064 /** 065 * Get the number of vertices that this generator will create for the 066 * shape given in the definition. 067 * 068 * @param data The data to base the calculations on 069 * @return The vertex count for the object 070 * @throws UnsupportedTypeException The generator cannot handle the type 071 * of geometry you have requested. 072 */ 073 public abstract int getVertexCount(GeometryData data) 074 throws UnsupportedTypeException; 075 076 /** 077 * Generate a new set of geometry items based on the passed data. If the 078 * data does not contain the right minimum array lengths an exception will 079 * be generated. If the array reference is null, this will create arrays 080 * of the correct length and assign them to the return value. 081 * 082 * @param data The data to base the calculations on 083 * @throws InvalidArraySizeException The array is not big enough to contain 084 * the requested geometry 085 * @throws UnsupportedTypeException The generator cannot handle the type 086 * of geometry you have requested 087 */ 088 public abstract void generate(GeometryData data) 089 throws UnsupportedTypeException, InvalidArraySizeException; 090 091 /** 092 * Convenience method to create a normal for the given vertex coordinates 093 * and normal array. This performs a cross product of the two vectors 094 * described by the middle and two end points. 095 * 096 * @param coords The coordinate array to read values from 097 * @param p The index of the middle point 098 * @param p1 The index of the first point 099 * @param p2 The index of the second point 100 * @return A temporary value containing the normal value 101 */ 102 protected Vector3f createFaceNormal(float[] coords, int p, int p1, int p2) 103 { 104 v0.x = coords[p1] - coords[p]; 105 v0.y = coords[p1 + 1] - coords[p + 1]; 106 v0.z = coords[p1 + 2] - coords[p + 2]; 107 108 v1.x = coords[p] - coords[p2]; 109 v1.y = coords[p + 1] - coords[p2 + 1]; 110 v1.z = coords[p + 2] - coords[p2 + 2]; 111 112 normal.cross(v0, v1); 113 normal.normalize(); 114 115 return normal; 116 } 117 118 119 /** 120 * Convenience method to create a normal for the given vertex coordinates 121 * and normal array and using a 2D array of coordinate values. This 122 * performs a cross product of the two vectors described by the middle 123 * and two end points. 124 * 125 * @param coords The coordinate array to read values from 126 * @param w The reference into the first array dimension for p 127 * @param p The index of the middle point 128 * @param w1 The reference into the first array dimension for p1 129 * @param p1 The index of the first point 130 * @param w2 The reference into the first array dimension for p2 131 * @param p2 The index of the second point 132 * @return A temporary value containing the normal value 133 */ 134 protected Vector3f createFaceNormal(float[][] coords, 135 int w, int p, 136 int w1, int p1, 137 int w2, int p2) 138 { 139 v0.x = coords[w1][p1] - coords[w][p]; 140 v0.y = coords[w1][p1 + 1] - coords[w][p + 1]; 141 v0.z = coords[w1][p1 + 2] - coords[w][p + 2]; 142 143 v1.x = coords[w][p] - coords[w2][p2]; 144 v1.y = coords[w][p + 1] - coords[w2][p2 + 1]; 145 v1.z = coords[w][p + 2] - coords[w2][p2 + 2]; 146 147 normal.cross(v0, v1); 148 normal.normalize(); 149 150 return normal; 151 } 152 153 /** 154 * Create a normal based on the given vertex position, assuming that it is 155 * a point in space, relative to the origin. This will create a normal that 156 * points directly along the vector from the origin to the point. 157 * 158 * @param coords The coordinate array to read values from 159 * @param p The index of the point to calculate 160 * @return A temporary value containing the normal value 161 */ 162 protected Vector3f createRadialNormal(float[] coords, int p) 163 { 164 float x = coords[p]; 165 float y = coords[p + 1]; 166 float z = coords[p + 2]; 167 168 float mag = x * x + y * y + z * z; 169 170 if(mag != 0.0) 171 { 172 mag = 1.0f / ((float) Math.sqrt(mag)); 173 normal.x = x * mag; 174 normal.y = y * mag; 175 normal.z = z * mag; 176 } 177 else 178 { 179 normal.x = 0; 180 normal.y = 0; 181 normal.z = 0; 182 } 183 184 return normal; 185 } 186 187 /** 188 * Create a normal based on the given vertex position, assuming that it is 189 * a point in space, relative to the given point. This will create a normal 190 * that points directly along the vector from the given point to the 191 * coordinate. 192 * 193 * @param coords The coordinate array to read values from 194 * @param p The index of the point to calculate 195 * @param origin The origin to calculate relative to 196 * @param originOffset The offset into the origin array to use 197 * @return A temporary value containing the normal value 198 */ 199 protected Vector3f createRadialNormal(float[] coords, 200 int p, 201 float[] origin, 202 int originOffset) 203 { 204 float x = coords[p] - origin[originOffset]; 205 float y = coords[p + 1] - origin[originOffset + 1]; 206 float z = coords[p + 2] - origin[originOffset + 2]; 207 208 float mag = x * x + y * y + z * z; 209 210 if(mag != 0.0) 211 { 212 mag = 1.0f / ((float) Math.sqrt(mag)); 213 normal.x = x * mag; 214 normal.y = y * mag; 215 normal.z = z * mag; 216 } 217 else 218 { 219 normal.x = 0; 220 normal.y = 0; 221 normal.z = 0; 222 } 223 224 return normal; 225 } 226}