OSDN Git Service

Set optimal mime types and executable settings.
[mikumikustudio/MikuMikuStudio.git] / src / com / jmex / effects / water / ProjectedGrid.java
1 /*
2  * Copyright (c) 2003-2009 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
33 package com.jmex.effects.water;
34
35 import java.nio.FloatBuffer;
36 import java.nio.IntBuffer;
37
38 import com.jme.math.FastMath;
39 import com.jme.math.Matrix4f;
40 import com.jme.math.Quaternion;
41 import com.jme.math.Vector2f;
42 import com.jme.math.Vector3f;
43 import com.jme.renderer.AbstractCamera;
44 import com.jme.renderer.Camera;
45 import com.jme.renderer.Renderer;
46 import com.jme.scene.TexCoords;
47 import com.jme.scene.TriMesh;
48 import com.jme.util.Timer;
49 import com.jme.util.geom.BufferUtils;
50 import com.jmex.effects.ProjectedTextureUtil;
51
52 /**
53  * <code>ProjectedGrid</code>
54  * Projected grid mesh
55  *
56  * @author Rikard Herlitz (MrCoder)
57  */
58 public class ProjectedGrid extends TriMesh {
59     private static final long serialVersionUID = 1L;
60     
61         private int sizeX;
62         private int sizeY;
63
64         //x/z step
65         private static Vector3f calcVec1 = new Vector3f();
66         private static Vector3f calcVec2 = new Vector3f();
67         private static Vector3f calcVec3 = new Vector3f();
68
69         private FloatBuffer vertBuf;
70         private FloatBuffer normBuf;
71         private FloatBuffer texs;
72         private IntBuffer indexBuffer;
73
74         private float viewPortWidth = 0;
75         private float viewPortHeight = 0;
76         private float viewPortLeft = 0;
77         private float viewPortBottom = 0;
78
79         private Quaternion origin = new Quaternion();
80         private Quaternion direction = new Quaternion();
81         private Vector2f source = new Vector2f();
82
83         private Matrix4f modelViewMatrix = new Matrix4f();
84         private Matrix4f projectionMatrix = new Matrix4f();
85         private Matrix4f modelViewProjectionInverse = new Matrix4f();
86         private Quaternion intersectBottomLeft = new Quaternion();
87         private Quaternion intersectTopLeft = new Quaternion();
88         private Quaternion intersectTopRight = new Quaternion();
89         private Quaternion intersectBottomRight = new Quaternion();
90
91         private Matrix4f modelViewMatrix1 = new Matrix4f();
92         private Matrix4f projectionMatrix1 = new Matrix4f();
93         private Matrix4f modelViewProjection1 = new Matrix4f();
94         private Matrix4f modelViewProjectionInverse1 = new Matrix4f();
95         private Quaternion intersectBottomLeft1 = new Quaternion();
96         private Quaternion intersectTopLeft1 = new Quaternion();
97         private Quaternion intersectTopRight1 = new Quaternion();
98         private Quaternion intersectBottomRight1 = new Quaternion();
99
100         private Vector3f camloc = new Vector3f();
101         private Vector3f camdir = new Vector3f();
102         private Quaternion pointFinal = new Quaternion();
103         private Quaternion pointTop = new Quaternion();
104         private Quaternion pointBottom = new Quaternion();
105         private Vector3f realPoint = new Vector3f();
106
107         public boolean freezeProjector = false;
108         public boolean useReal = false;
109         private Vector3f projectorLoc = new Vector3f();
110         private Timer timer;
111         private Camera cam;
112         private float fovY = 45.0f;
113
114         private HeightGenerator heightGenerator;
115         private float textureScale;
116
117         private float[] vertBufArray;
118         private float[] normBufArray;
119         private float[] texBufArray;
120         
121         public ProjectedGrid( String name, Camera cam, int sizeX, int sizeY, float texureScale, HeightGenerator heightGenerator ) {
122                 super( name );
123                 this.sizeX = sizeX;
124                 this.sizeY = sizeY;
125                 this.textureScale = texureScale;
126                 this.heightGenerator = heightGenerator;
127                 this.cam = cam;
128                 
129                 if (cam.getFrustumNear() > 0.0f) {
130                         fovY = FastMath.atan(cam.getFrustumTop() / cam.getFrustumNear())
131                                         * 2.0f / FastMath.DEG_TO_RAD;
132                 }
133
134                 timer = Timer.getTimer();
135
136                 setVertexCount( sizeX * sizeY );
137
138                 vertBufArray = new float[getVertexCount()*3];
139                 normBufArray = new float[getVertexCount()*3];
140                 texBufArray = new float[getVertexCount()*2];
141
142                 buildVertices();
143                 buildTextureCoordinates();
144                 buildNormals();
145         }
146
147         public void switchFreeze() {
148                 freezeProjector = !freezeProjector;
149         }
150
151         public void draw( Renderer r ) {
152                 update();
153                 super.draw( r );
154         }
155
156         public void update() {
157                 if( freezeProjector ) return;
158
159                 float time = timer.getTimeInSeconds();
160
161                 camloc.set( cam.getLocation() );
162                 camdir.set( cam.getDirection() );
163
164                 AbstractCamera camera = (AbstractCamera) cam;
165
166                 viewPortWidth = camera.getWidth();
167                 viewPortHeight = camera.getHeight();
168                 viewPortLeft = camera.getViewPortLeft();
169                 viewPortBottom = camera.getViewPortBottom();
170                 modelViewMatrix.set( camera.getModelViewMatrix() );
171                 projectionMatrix.set( camera.getProjectionMatrix() );
172                 modelViewProjectionInverse.set( modelViewMatrix ).multLocal( projectionMatrix );
173                 modelViewProjectionInverse.invertLocal();
174
175                 source.set( 0.5f, 0.5f );
176                 getWorldIntersection( source, modelViewProjectionInverse, pointFinal );
177                 pointFinal.multLocal( 1.0f / pointFinal.w );
178                 realPoint.set( pointFinal.x, pointFinal.y, pointFinal.z );
179                 projectorLoc.set( cam.getLocation() );
180                 realPoint.set( projectorLoc ).addLocal( cam.getDirection() );
181
182                 Matrix4f rangeMatrix = null;
183                 if( useReal ) {
184                         Vector3f fakeLoc = new Vector3f( projectorLoc );
185                         Vector3f fakePoint = new Vector3f( realPoint );
186                         fakeLoc.addLocal( 0, 1000, 0 );
187
188                         rangeMatrix = getMinMax( fakeLoc, fakePoint, cam );
189                 }
190
191                 ProjectedTextureUtil.matrixLookAt( projectorLoc, realPoint, Vector3f.UNIT_Y, modelViewMatrix );
192                 ProjectedTextureUtil.matrixProjection( fovY + 10.0f, viewPortWidth / viewPortHeight, cam.getFrustumNear(), cam.getFrustumFar(), projectionMatrix );
193                 modelViewProjectionInverse.set( modelViewMatrix ).multLocal( projectionMatrix );
194                 modelViewProjectionInverse.invertLocal();
195
196                 if( useReal && rangeMatrix != null ) {
197                         rangeMatrix.multLocal( modelViewProjectionInverse );
198                         modelViewProjectionInverse.set( rangeMatrix );
199                 }
200
201                 source.set( 0, 0 );
202                 getWorldIntersection( source, modelViewProjectionInverse, intersectBottomLeft );
203                 source.set( 0, 1 );
204                 getWorldIntersection( source, modelViewProjectionInverse, intersectTopLeft );
205                 source.set( 1, 1 );
206                 getWorldIntersection( source, modelViewProjectionInverse, intersectTopRight );
207                 source.set( 1, 0 );
208                 getWorldIntersection( source, modelViewProjectionInverse, intersectBottomRight );
209
210                 vertBuf.rewind();
211                 float du = 1.0f / (float) (sizeX - 1);
212                 float dv = 1.0f / (float) (sizeY - 1);
213                 float u = 0, v = 0;
214                 int index = 0;
215                 for( int y = 0; y < sizeY; y++ ) {
216                         for( int x = 0; x < sizeX; x++ ) {
217                                 interpolate( intersectTopLeft, intersectTopRight, u, pointTop );
218                                 interpolate( intersectBottomLeft, intersectBottomRight, u, pointBottom );
219                                 interpolate( pointTop, pointBottom, v, pointFinal );
220                                 pointFinal.x /= pointFinal.w;
221                                 pointFinal.z /= pointFinal.w;
222                                 realPoint.set( pointFinal.x,
223                                                            heightGenerator.getHeight( pointFinal.x, pointFinal.z, time ),
224                                                            pointFinal.z );
225
226                                 vertBufArray[index++] = realPoint.x;
227                                 vertBufArray[index++] = realPoint.y;
228                                 vertBufArray[index++] = realPoint.z;
229
230                                 u += du;
231                         }
232                         v += dv;
233                         u = 0;
234                 }
235                 vertBuf.put( vertBufArray );
236
237                 texs.rewind();
238                 for( int i = 0; i < getVertexCount(); i++ ) {
239                         texBufArray[i*2] = vertBufArray[i*3] * textureScale;
240                         texBufArray[i*2+1] = vertBufArray[i*3+2] * textureScale;
241                 }
242                 texs.put( texBufArray );
243
244                 normBuf.rewind();
245                 oppositePoint.set( 0, 0, 0 );
246                 adjacentPoint.set( 0, 0, 0 );
247                 rootPoint.set( 0, 0, 0 );
248                 tempNorm.set( 0, 0, 0 );
249                 int adj = 0, opp = 0, normalIndex = 0;
250                 for( int row = 0; row < sizeY; row++ ) {
251                         for( int col = 0; col < sizeX; col++ ) {
252                                 if( row == sizeY - 1 ) {
253                                         if( col == sizeX - 1 ) { // last row, last col
254                                                 // up cross left
255                                                 adj = normalIndex - sizeX;
256                                                 opp = normalIndex - 1;
257                                         }
258                                         else { // last row, except for last col
259                                                 // right cross up
260                                                 adj = normalIndex + 1;
261                                                 opp = normalIndex - sizeX;
262                                         }
263                                 }
264                                 else {
265                                         if( col == sizeX - 1 ) { // last column except for last row
266                                                 // left cross down
267                                                 adj = normalIndex - 1;
268                                                 opp = normalIndex + sizeX;
269                                         }
270                                         else { // most cases
271                                                 // down cross right
272                                                 adj = normalIndex + sizeX;
273                                                 opp = normalIndex + 1;
274                                         }
275                                 }
276                                 rootPoint.set(vertBufArray[normalIndex*3],vertBufArray[normalIndex*3+1],vertBufArray[normalIndex*3+2]);
277                                 adjacentPoint.set(vertBufArray[adj*3],vertBufArray[adj*3+1],vertBufArray[adj*3+2]);
278                                 oppositePoint.set(vertBufArray[opp*3],vertBufArray[opp*3+1],vertBufArray[opp*3+2]);
279                                 tempNorm.set( adjacentPoint ).subtractLocal( rootPoint )
280                                                 .crossLocal( oppositePoint.subtractLocal( rootPoint ) )
281                                                 .normalizeLocal();
282
283                                 normBufArray[normalIndex*3] = tempNorm.x;
284                                 normBufArray[normalIndex*3+1] = tempNorm.y;
285                                 normBufArray[normalIndex*3+2] = tempNorm.z;
286
287                                 normalIndex++;
288                         }
289                 }
290                 normBuf.put( normBufArray );
291         }
292
293         private Matrix4f getMinMax( Vector3f fakeLoc, Vector3f fakePoint, Camera cam ) {
294                 Matrix4f rangeMatrix;
295                 ProjectedTextureUtil.matrixLookAt( fakeLoc, fakePoint, Vector3f.UNIT_Y, modelViewMatrix1 );
296                 ProjectedTextureUtil.matrixProjection( fovY, viewPortWidth / viewPortHeight, cam.getFrustumNear(), cam.getFrustumFar(), projectionMatrix1 );
297                 modelViewProjection1.set( modelViewMatrix1 ).multLocal( projectionMatrix1 );
298                 modelViewProjectionInverse1.set( modelViewProjection1 ).invertLocal();
299
300                 source.set( 0, 0 );
301                 getWorldIntersection( source, modelViewProjectionInverse, intersectBottomLeft1 );
302                 source.set( 0, 1 );
303                 getWorldIntersection( source, modelViewProjectionInverse, intersectTopLeft1 );
304                 source.set( 1, 1 );
305                 getWorldIntersection( source, modelViewProjectionInverse, intersectTopRight1 );
306                 source.set( 1, 0 );
307                 getWorldIntersection( source, modelViewProjectionInverse, intersectBottomRight1 );
308
309                 Vector3f tmp = new Vector3f();
310                 tmp.set( intersectBottomLeft.x, intersectBottomLeft.y, intersectBottomLeft.z );
311                 modelViewProjection1.mult( tmp, tmp );
312                 intersectBottomLeft.x = tmp.x;
313                 intersectBottomLeft.y = tmp.y;
314                 intersectBottomLeft.z = tmp.z;
315
316                 tmp.set( intersectTopLeft1.x, intersectTopLeft1.y, intersectTopLeft1.z );
317                 modelViewProjection1.mult( tmp, tmp );
318                 intersectTopLeft1.x = tmp.x;
319                 intersectTopLeft1.y = tmp.y;
320                 intersectTopLeft1.z = tmp.z;
321
322                 tmp.set( intersectTopRight1.x, intersectTopRight1.y, intersectTopRight1.z );
323                 modelViewProjection1.mult( tmp, tmp );
324                 intersectTopRight1.x = tmp.x;
325                 intersectTopRight1.y = tmp.y;
326                 intersectTopRight1.z = tmp.z;
327
328                 tmp.set( intersectBottomRight1.x, intersectBottomRight1.y, intersectBottomRight1.z );
329                 modelViewProjection1.mult( tmp, tmp );
330                 intersectBottomRight1.x = tmp.x;
331                 intersectBottomRight1.y = tmp.y;
332                 intersectBottomRight1.z = tmp.z;
333
334 //                      modelViewProjection1.mult( intersectBottomLeft1, intersectBottomLeft1 );
335 //                      modelViewProjection1.mult( intersectTopLeft1, intersectTopLeft1 );
336 //                      modelViewProjection1.mult( intersectTopRight1, intersectTopRight1 );
337 //                      modelViewProjection1.mult( intersectBottomRight1, intersectBottomRight1 );
338
339                 float minX = Float.MAX_VALUE, minY = Float.MAX_VALUE, maxX = Float.MIN_VALUE, maxY = Float.MIN_VALUE;
340                 if( intersectBottomLeft1.x < minX ) minX = intersectBottomLeft1.x;
341                 if( intersectTopLeft1.x < minX ) minX = intersectTopLeft1.x;
342                 if( intersectTopRight1.x < minX ) minX = intersectTopRight1.x;
343                 if( intersectBottomRight1.x < minX ) minX = intersectBottomRight1.x;
344                 if( intersectBottomLeft1.x > maxX ) maxX = intersectBottomLeft1.x;
345                 if( intersectTopLeft1.x > maxX ) maxX = intersectTopLeft1.x;
346                 if( intersectTopRight1.x > maxX ) maxX = intersectTopRight1.x;
347                 if( intersectBottomRight1.x > maxX ) maxX = intersectBottomRight1.x;
348
349                 if( intersectBottomLeft1.y < minY ) minY = intersectBottomLeft1.y;
350                 if( intersectTopLeft1.y < minY ) minY = intersectTopLeft1.y;
351                 if( intersectTopRight1.y < minY ) minY = intersectTopRight1.y;
352                 if( intersectBottomRight1.y < minY ) minY = intersectBottomRight1.y;
353                 if( intersectBottomLeft1.y > maxY ) maxY = intersectBottomLeft1.y;
354                 if( intersectTopLeft1.y > maxY ) maxY = intersectTopLeft1.y;
355                 if( intersectTopRight1.y > maxY ) maxY = intersectTopRight1.y;
356                 if( intersectBottomRight1.y > maxY ) maxY = intersectBottomRight1.y;
357                 rangeMatrix = new Matrix4f(
358                                 maxX - minX, 0, 0, minX,
359                                 0, maxY - minY, 0, minY,
360                                 0, 0, 1, 0,
361                                 0, 0, 0, 1
362                 );
363                 rangeMatrix.transpose();
364                 return rangeMatrix;
365         }
366
367         private void interpolate( Quaternion beginVec, Quaternion finalVec, float changeAmnt, Quaternion resultVec ) {
368                 resultVec.x = (1 - changeAmnt) * beginVec.x + changeAmnt * finalVec.x;
369 //              resultVec.y = (1 - changeAmnt) * beginVec.y + changeAmnt * finalVec.y;
370                 resultVec.z = (1 - changeAmnt) * beginVec.z + changeAmnt * finalVec.z;
371                 resultVec.w = (1 - changeAmnt) * beginVec.w + changeAmnt * finalVec.w;
372         }
373
374         private void interpolate( Vector3f beginVec, Vector3f finalVec, float changeAmnt, Vector3f resultVec ) {
375                 resultVec.x = (1 - changeAmnt) * beginVec.x + changeAmnt * finalVec.x;
376                 resultVec.y = (1 - changeAmnt) * beginVec.y + changeAmnt * finalVec.y;
377                 resultVec.z = (1 - changeAmnt) * beginVec.z + changeAmnt * finalVec.z;
378         }
379
380         private void getWorldIntersection( Vector2f screenPosition, Matrix4f viewProjectionMatrix, Quaternion store ) {
381                 origin.set( screenPosition.x * 2 - 1, screenPosition.y * 2 - 1, -1, 1 );
382                 direction.set( screenPosition.x * 2 - 1, screenPosition.y * 2 - 1, 1, 1 );
383
384                 viewProjectionMatrix.mult( origin, origin );
385                 viewProjectionMatrix.mult( direction, direction );
386
387                 if( cam.getLocation().y > 0 ) {
388                         if( direction.y > 0 ) {
389                                 direction.y = 0;
390                         }
391                 }
392                 else {
393                         if( direction.y < 0 ) {
394                                 direction.y = 0;
395                         }
396                 }
397
398                 direction.subtractLocal( origin );
399
400                 float t = -origin.y / direction.y;
401
402                 direction.multLocal( t );
403                 store.set( origin );
404                 store.addLocal( direction );
405         }
406
407     private float homogenousIntersect(Quaternion a, Quaternion xa, Quaternion xb) {
408 //        float tx = -xb.w*(dotXYZ(a.xyz,xa.xyz)+xa.w*a.w);
409 //        float tw = dotXYZ(a,xa.w*xb.xyz-xb.w*xa.xyz);
410 //        return tx/tw;
411         return 0;
412     }
413
414     private float dotXYZ(Quaternion a, Quaternion b) {
415         return a.x * b.x + a.y * b.y + a.z * b.z;
416     }
417
418     private void mulXYZ(Quaternion a, Quaternion b) {
419     }
420
421         /**
422      * <code>setDetailTexture</code> copies the texture coordinates from the
423      * first texture channel to another channel specified by unit, mulitplying
424      * by the factor specified by repeat so that the texture in that channel
425      * will be repeated that many times across the block.
426      * 
427      * @param unit
428      *            channel to copy coords to
429      * @param repeat
430      *            number of times to repeat the texture across and down the
431      *            block
432      */
433         public void setDetailTexture( int unit, float repeat) {
434                 copyTextureCoordinates(0, unit, repeat);
435         }
436
437
438         /**
439          * <code>getSurfaceNormal</code> returns the normal of an arbitrary point
440          * on the terrain. The normal is linearly interpreted from the normals of
441          * the 4 nearest defined points. If the point provided is not within the
442          * bounds of the height map, null is returned.
443          *
444          * @param position the vector representing the location to find a normal at.
445          * @param store the Vector3f object to store the result in. If null, a new one
446          *                 is created.
447          * @return the normal vector at the provided location.
448          */
449         public Vector3f getSurfaceNormal( Vector2f position, Vector3f store ) {
450                 return getSurfaceNormal( position.x, position.y, store );
451         }
452
453         /**
454          * <code>getSurfaceNormal</code> returns the normal of an arbitrary point
455          * on the terrain. The normal is linearly interpreted from the normals of
456          * the 4 nearest defined points. If the point provided is not within the
457          * bounds of the height map, null is returned.
458          *
459          * @param position the vector representing the location to find a normal at. Only
460          *                 the x and z values are used.
461          * @param store the Vector3f object to store the result in. If null, a new one
462          *                 is created.
463          * @return the normal vector at the provided location.
464          */
465         public Vector3f getSurfaceNormal( Vector3f position, Vector3f store ) {
466                 return getSurfaceNormal( position.x, position.z, store );
467         }
468
469         /**
470          * <code>getSurfaceNormal</code> returns the normal of an arbitrary point
471          * on the terrain. The normal is linearly interpreted from the normals of
472          * the 4 nearest defined points. If the point provided is not within the
473          * bounds of the height map, null is returned.
474          *
475          * @param x      the x coordinate to check.
476          * @param z      the z coordinate to check.
477          * @param store the Vector3f object to store the result in. If null, a new one
478          *              is created.
479          * @return the normal unit vector at the provided location.
480          */
481         public Vector3f getSurfaceNormal( float x, float z, Vector3f store ) {
482 //        x /= stepScale.x;
483 //        z /= stepScale.z;
484                 float col = FastMath.floor( x );
485                 float row = FastMath.floor( z );
486
487                 if( col < 0 || row < 0 || col >= sizeX - 1 || row >= sizeY - 1 ) {
488                         return null;
489                 }
490                 float intOnX = x - col, intOnZ = z - row;
491
492                 if( store == null ) store = new Vector3f();
493
494                 Vector3f topLeft = store, topRight = calcVec1, bottomLeft = calcVec2, bottomRight = calcVec3;
495
496                 int focalSpot = (int) (col + row * sizeX);
497
498                 // find the heightmap point closest to this position (but will always
499                 // be to the left ( < x) and above (< z) of the spot.
500                 BufferUtils.populateFromBuffer( topLeft, normBuf, focalSpot );
501
502                 // now find the next point to the right of topLeft's position...
503                 BufferUtils.populateFromBuffer( topRight, normBuf, focalSpot + 1 );
504
505                 // now find the next point below topLeft's position...
506                 BufferUtils.populateFromBuffer( bottomLeft, normBuf, focalSpot + sizeX );
507
508                 // now find the next point below and to the right of topLeft's
509                 // position...
510                 BufferUtils.populateFromBuffer( bottomRight, normBuf, focalSpot + sizeX
511                                                                                                                           + 1 );
512
513                 // Use linear interpolation to find the height.
514                 topLeft.interpolate( topRight, intOnX );
515                 bottomLeft.interpolate( bottomRight, intOnX );
516                 topLeft.interpolate( bottomLeft, intOnZ );
517                 return topLeft.normalizeLocal();
518         }
519
520         /**
521          * <code>buildVertices</code> sets up the vertex and index arrays of the
522          * TriMesh.
523          */
524         private void buildVertices() {
525                 vertBuf = BufferUtils.createVector3Buffer( vertBuf, getVertexCount() );
526                 setVertexBuffer( vertBuf );
527
528                 Vector3f point = new Vector3f();
529                 for( int x = 0; x < sizeX; x++ ) {
530                         for( int y = 0; y < sizeY; y++ ) {
531                                 point.set( x, 0, y );
532                                 BufferUtils.setInBuffer( point, vertBuf, (x + (y * sizeX)) );
533                         }
534                 }
535
536                 //set up the indices
537                 int triangleQuantity = ((sizeX - 1) * (sizeY - 1)) * 2;
538                 setTriangleQuantity( triangleQuantity );
539                 indexBuffer = BufferUtils.createIntBuffer( triangleQuantity * 3 );
540                 setIndexBuffer( indexBuffer );
541
542                 //go through entire array up to the second to last column.
543                 for( int i = 0; i < (sizeX * (sizeY - 1)); i++ ) {
544                         //we want to skip the top row.
545                         if( i % ((sizeX * (i / sizeX + 1)) - 1) == 0 && i != 0 ) {
546 //                              logger.info("skip row: "+i+" cause: "+((sizeY * (i / sizeX + 1)) - 1));
547                                 continue;
548                         }
549                         else {
550 //                              logger.info("i: "+i);
551                         }
552                         //set the top left corner.
553                         indexBuffer.put( i );
554                         //set the bottom right corner.
555                         indexBuffer.put( (1 + sizeX) + i );
556                         //set the top right corner.
557                         indexBuffer.put( 1 + i );
558                         //set the top left corner
559                         indexBuffer.put( i );
560                         //set the bottom left corner
561                         indexBuffer.put( sizeX + i );
562                         //set the bottom right corner
563                         indexBuffer.put( (1 + sizeX) + i );
564                 }
565         }
566
567         /**
568          * <code>buildTextureCoordinates</code> calculates the texture coordinates
569          * of the terrain.
570          */
571         private void buildTextureCoordinates() {
572                 texs = BufferUtils.createVector2Buffer( getVertexCount() );
573                 setTextureCoords( new TexCoords(texs), 0 );
574                 texs.clear();
575
576                 vertBuf.rewind();
577                 for( int i = 0; i < getVertexCount(); i++ ) {
578                         texs.put( vertBuf.get() * textureScale );
579                         vertBuf.get(); // ignore vert y coord.
580                         texs.put( vertBuf.get() * textureScale );
581                 }
582         }
583
584         /**
585          * <code>buildNormals</code> calculates the normals of each vertex that
586          * makes up the block of terrain.
587          */
588         Vector3f oppositePoint = new Vector3f();
589         Vector3f adjacentPoint = new Vector3f();
590         Vector3f rootPoint = new Vector3f();
591         Vector3f tempNorm = new Vector3f();
592
593         private void buildNormals() {
594                 normBuf = BufferUtils.createVector3Buffer( normBuf, getVertexCount() );
595                 setNormalBuffer( normBuf );
596
597                 oppositePoint.set( 0, 0, 0 );
598                 adjacentPoint.set( 0, 0, 0 );
599                 rootPoint.set( 0, 0, 0 );
600                 tempNorm.set( 0, 0, 0 );
601                 int adj = 0, opp = 0, normalIndex = 0;
602                 for( int row = 0; row < sizeY; row++ ) {
603                         for( int col = 0; col < sizeX; col++ ) {
604                                 BufferUtils.populateFromBuffer( rootPoint, vertBuf, normalIndex );
605                                 if( row == sizeY - 1 ) {
606                                         if( col == sizeX - 1 ) { // last row, last col
607                                                 // up cross left
608                                                 adj = normalIndex - sizeX;
609                                                 opp = normalIndex - 1;
610                                         }
611                                         else { // last row, except for last col
612                                                 // right cross up
613                                                 adj = normalIndex + 1;
614                                                 opp = normalIndex - sizeX;
615                                         }
616                                 }
617                                 else {
618                                         if( col == sizeY - 1 ) { // last column except for last row
619                                                 // left cross down
620                                                 adj = normalIndex - 1;
621                                                 opp = normalIndex + sizeX;
622                                         }
623                                         else { // most cases
624                                                 // down cross right
625                                                 adj = normalIndex + sizeX;
626                                                 opp = normalIndex + 1;
627                                         }
628                                 }
629                                 BufferUtils.populateFromBuffer( adjacentPoint, vertBuf, adj );
630                                 BufferUtils.populateFromBuffer( oppositePoint, vertBuf, opp );
631                                 tempNorm.set( adjacentPoint ).subtractLocal( rootPoint )
632                                                 .crossLocal( oppositePoint.subtractLocal( rootPoint ) )
633                                                 .normalizeLocal();
634                                 BufferUtils.setInBuffer( tempNorm, normBuf, normalIndex );
635                                 normalIndex++;
636                         }
637                 }
638         }
639 }