@ -1,9 +1,38 @@
/ *
/ *
* To change this template , choose Tools | Templates
* Copyright ( c ) 2009 - 2010 jMonkeyEngine
* and open the template in the editor .
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are
* met :
*
* * Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
*
* * Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
*
* * Neither the name of ' jMonkeyEngine ' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED
* TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL ,
* EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO ,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR
* PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING
* NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
* /
* /
package com.jme3.terrain.geomipmap ;
package com.jme3.terrain.geomipmap ;
import com.jme3.scene.control.UpdateControl ;
import com.jme3.app.Application ;
import com.jme3.bullet.PhysicsSpace ;
import com.jme3.bullet.PhysicsSpace ;
import com.jme3.bullet.collision.shapes.HeightfieldCollisionShape ;
import com.jme3.bullet.collision.shapes.HeightfieldCollisionShape ;
import com.jme3.bullet.control.RigidBodyControl ;
import com.jme3.bullet.control.RigidBodyControl ;
@ -19,10 +48,11 @@ import com.jme3.material.Material;
import com.jme3.math.FastMath ;
import com.jme3.math.FastMath ;
import com.jme3.math.Vector2f ;
import com.jme3.math.Vector2f ;
import com.jme3.math.Vector3f ;
import com.jme3.math.Vector3f ;
import com.jme3.renderer.Camera ;
import com.jme3.terrain.geomipmap.lodcalc.LodCalculatorFactory ;
import com.jme3.terrain.geomipmap.lodcalc.LodCalculatorFactory ;
import com.jme3.terrain.geomipmap.lodcalc.LodDistanceCalculatorFactory ;
import com.jme3.terrain.geomipmap.lodcalc.LodDistanceCalculatorFactory ;
import com.jme3.terrain.heightmap.HeightMapGrid ;
import com.jme3.terrain.heightmap.HeightMapGrid ;
import com.jme3.terrain.heightmap.RawHeightMap ;
import java.util.concurrent.Callable ;
/ * *
/ * *
* @author Anthyon
* @author Anthyon
@ -34,7 +64,7 @@ public class TerrainGrid extends TerrainQuad {
private int quarterSize ;
private int quarterSize ;
private int quadSize ;
private int quadSize ;
private HeightMapGrid heightMapGrid ;
private HeightMapGrid heightMapGrid ;
private Vector3f [ ] quadOrigins ;
//private Vector3f[] quadOrigins;
private Vector3f [ ] quadIndex ;
private Vector3f [ ] quadIndex ;
private Map < String , TerrainGridListener > listeners = new HashMap < String , TerrainGridListener > ( ) ;
private Map < String , TerrainGridListener > listeners = new HashMap < String , TerrainGridListener > ( ) ;
private Material material ;
private Material material ;
@ -45,77 +75,107 @@ public class TerrainGrid extends TerrainQuad {
private class UpdateQuadCache implements Runnable {
private class UpdateQuadCache implements Runnable {
private final Vector3f location ;
private final Vector3f location ;
private final boolean centerOnly ;
public UpdateQuadCache ( Vector3f location ) {
public UpdateQuadCache ( Vector3f location ) {
this . location = location ;
this . location = location ;
this . centerOnly = false ;
}
public UpdateQuadCache ( Vector3f location , boolean centerOnly ) {
this . location = location ;
this . centerOnly = centerOnly ;
}
}
public void run ( ) {
public void run ( ) {
for ( int i = centerOnly ? 1 : 0 ; i < ( centerOnly ? 3 : 4 ) ; i + + ) {
for ( int j = centerOnly ? 1 : 0 ; j < ( centerOnly ? 3 : 4 ) ; j + + ) {
for ( int i = 0 ; i < 4 ; i + + ) {
Vector3f temp = location . add ( quadIndex [ i * 4 + j ] ) ;
for ( int j = 0 ; j < 4 ; j + + ) {
if ( cache . get ( temp ) = = null ) {
int quadIdx = i * 4 + j ;
final Vector3f temp = location . add ( quadIndex [ quadIdx ] ) ;
TerrainQuad q = cache . get ( temp ) ;
if ( q = = null ) {
// create the new Quad since it doesn't exist
HeightMap heightMapAt = heightMapGrid . getHeightMapAt ( temp ) ;
HeightMap heightMapAt = heightMapGrid . getHeightMapAt ( temp ) ;
TerrainQuad q = new TerrainQuad ( getName ( ) + "Quad" + temp , patchSize , quadSize , heightMapAt = = null ? null : heightMapAt . getHeightMap ( ) , lodCalculatorFactory ) ;
q = new TerrainQuad ( getName ( ) + "Quad" + temp , patchSize , quadSize , total Size , heightMapAt = = null ? null : heightMapAt . getHeightMap ( ) , lodCalculatorFactory ) ;
Material mat = material . clone ( ) ;
Material mat = material . clone ( ) ;
for ( TerrainGridListener l : listeners . values ( ) ) {
for ( TerrainGridListener l : listeners . values ( ) ) {
mat = l . tileLoaded ( mat , temp ) ;
mat = l . tileLoaded ( mat , temp ) ;
}
}
q . setMaterial ( mat ) ;
q . setMaterial ( mat ) ;
log . log ( Level . FINE , "Loaded TerrainQuad {0}" , q . getName ( ) ) ;
}
cache . put ( temp , q ) ;
cache . put ( temp , q ) ;
if ( isCenter ( quadIdx ) ) {
// if it should be attached as a child right now, attach it
final int quadrant = getQuadrant ( quadIdx ) ;
final TerrainQuad newQuad = q ;
// back on the OpenGL thread:
getControl ( UpdateControl . class ) . enqueue ( new Callable ( ) {
public Object call ( ) throws Exception {
attachQuadAt ( newQuad , quadrant , temp ) ;
return null ;
}
} ) ;
}
}
}
}
}
}
}
}
private boolean isCenter ( int quadIndex ) {
return quadIndex = = 9 | | quadIndex = = 5 | | quadIndex = = 10 | | quadIndex = = 6 ;
}
}
private int getQuadrant ( int quadIndex ) {
if ( quadIndex = = 9 )
return 1 ;
else if ( quadIndex = = 5 )
return 2 ;
else if ( quadIndex = = 10 )
return 3 ;
else if ( quadIndex = = 6 )
return 4 ;
return 0 ; // error
}
}
public TerrainGrid ( String name , int patchSize , int size , Vector3f stepScale , HeightMapGrid heightMapGrid , int totalSize ,
public TerrainGrid ( String name , int patchSize , int maxVi sibleS ize, Vector3f scale , HeightMapGrid heightMapGrid ,
Vector2f offset , float offsetAmount , LodCalculatorFactory lodCalculatorFactory ) {
Vector2f offset , float offsetAmount , LodCalculatorFactory lodCalculatorFactory ) {
this . name = name ;
this . name = name ;
this . patchSize = patchSize ;
this . patchSize = patchSize ;
this . size = size ;
this . size = maxVi sibleS ize;
this . quarterSize = size > > 2 ;
this . quarterSize = maxVi sibleS ize > > 2 ;
this . quadSize = ( size + 1 ) > > 1 ;
this . quadSize = ( maxVi sibleS ize + 1 ) > > 1 ;
this . stepScale = stepScale ;
this . stepScale = scale ;
this . heightMapGrid = heightMapGrid ;
this . heightMapGrid = heightMapGrid ;
heightMapGrid . setSize ( this . quadSize ) ;
heightMapGrid . setSize ( this . quadSize ) ;
this . totalSize = total Size;
this . totalSize = maxVisible Size;
this . offset = offset ;
this . offset = offset ;
this . offsetAmount = offsetAmount ;
this . offsetAmount = offsetAmount ;
this . lodCalculatorFactory = lodCalculatorFactory ;
this . lodCalculatorFactory = lodCalculatorFactory ;
if ( lodCalculatorFactory = = null ) {
if ( lodCalculatorFactory = = null ) {
lodCalculatorFactory = new LodDistanceCalculatorFactory ( ) ;
lodCalculatorFactory = new LodDistanceCalculatorFactory ( ) ;
}
}
this . quadOrigins = new Vector3f [ ] { new Vector3f ( - this . quarterSize , 0 , - this . quarterSize ) . mult ( this . stepScale ) ,
// this.quadOrigins = new Vector3f[]{
new Vector3f ( - this . quarterSize , 0 , this . quarterSize ) . mult ( this . stepScale ) ,
// new Vector3f(-this.quarterSize, 0, -this.quarterSize).mult(this.stepScale),
new Vector3f ( this . quarterSize , 0 , - this . quarterSize ) . mult ( this . stepScale ) ,
// new Vector3f(-this.quarterSize, 0, this.quarterSize).mult(this.stepScale),
new Vector3f ( this . quarterSize , 0 , this . quarterSize ) . mult ( this . stepScale ) } ;
// new Vector3f(this.quarterSize, 0, -this.quarterSize).mult(this.stepScale),
// new Vector3f(this.quarterSize, 0, this.quarterSize).mult(this.stepScale)};
this . quadIndex = new Vector3f [ ] {
this . quadIndex = new Vector3f [ ] {
new Vector3f ( - 1 , 0 , - 1 ) , new Vector3f ( - 1 , 0 , 0 ) , new Vector3f ( - 1 , 0 , 1 ) , new Vector3f ( - 1 , 0 , 2 ) ,
new Vector3f ( - 1 , 0 , 2 ) , new Vector3f ( 0 , 0 , 2 ) , new Vector3f ( 1 , 0 , 2 ) , new Vector3f ( 2 , 0 , 2 ) ,
new Vector3f ( 0 , 0 , - 1 ) , new Vector3f ( 0 , 0 , 0 ) , new Vector3f ( 0 , 0 , 1 ) , new Vector3f ( 0 , 0 , 2 ) ,
new Vector3f ( - 1 , 0 , 1 ) , new Vector3f ( 0 , 0 , 1 ) , new Vector3f ( 1 , 0 , 1 ) , new Vector3f ( 2 , 0 , 1 ) ,
new Vector3f ( 1 , 0 , - 1 ) , new Vector3f ( 1 , 0 , 0 ) , new Vector3f ( 1 , 0 , 1 ) , new Vector3f ( 1 , 0 , 2 ) ,
new Vector3f ( - 1 , 0 , 0 ) , new Vector3f ( 0 , 0 , 0 ) , new Vector3f ( 1 , 0 , 0 ) , new Vector3f ( 2 , 0 , 0 ) ,
new Vector3f ( 2 , 0 , - 1 ) , new Vector3f ( 2 , 0 , 0 ) , new Vector3f ( 2 , 0 , 1 ) , new Vector3f ( 2 , 0 , 2 ) } ;
new Vector3f ( - 1 , 0 , - 1 ) , new Vector3f ( 0 , 0 , - 1 ) , new Vector3f ( 1 , 0 , - 1 ) , new Vector3f ( - 2 , 0 , - 1 ) } ;
addControl ( new UpdateControl ( ) ) ;
}
}
public TerrainGrid ( String name , int patchSize , int size , Vector3f scale , HeightMapGrid heightMapGrid ,
public TerrainGrid ( String name , int patchSize , int maxVi sibleS ize, Vector3f scale , HeightMapGrid heightMapGrid ,
LodCalculatorFactory lodCalculatorFactory ) {
LodCalculatorFactory lodCalculatorFactory ) {
this ( name , patchSize , size , scale , heightMapGrid , size , new Vector2f ( ) , 0 , lodCalculatorFactory ) ;
this ( name , patchSize , maxVi sibleS ize, scale , heightMapGrid , new Vector2f ( ) , 0 , lodCalculatorFactory ) ;
}
}
public TerrainGrid ( String name , int patchSize , int total Size, HeightMapGrid heightMapGrid , LodCalculatorFactory lodCalculatorFactory ) {
public TerrainGrid ( String name , int patchSize , int maxVisible Size, HeightMapGrid heightMapGrid , LodCalculatorFactory lodCalculatorFactory ) {
this ( name , patchSize , total Size, Vector3f . UNIT_XYZ , heightMapGrid , lodCalculatorFactory ) ;
this ( name , patchSize , maxVisible Size, Vector3f . UNIT_XYZ , heightMapGrid , lodCalculatorFactory ) ;
}
}
public TerrainGrid ( String name , int patchSize , int total Size, HeightMapGrid heightMapGrid ) {
public TerrainGrid ( String name , int patchSize , int maxVisible Size, HeightMapGrid heightMapGrid ) {
this ( name , patchSize , total Size, heightMapGrid , null ) ;
this ( name , patchSize , maxVisible Size, heightMapGrid , null ) ;
}
}
public TerrainGrid ( ) {
public TerrainGrid ( ) {
@ -164,13 +224,18 @@ public class TerrainGrid extends TerrainQuad {
}
}
}
}
/ * *
* Runs on the rendering thread
* /
protected void attachQuadAt ( TerrainQuad q , int quadrant , Vector3f cam ) {
protected void attachQuadAt ( TerrainQuad q , int quadrant , Vector3f cam ) {
this . removeQuad ( quadrant ) ;
//q.setMaterial(this.material);
//q.setMaterial(this.material);
//q.setLocalTranslation(quadOrigins[quadrant - 1]);
//q.setLocalTranslation(quadOrigins[quadrant - 1]);
q . setQuadrant ( ( short ) quadrant ) ;
q . setQuadrant ( ( short ) quadrant ) ;
this . attachChild ( q ) ;
this . attachChild ( q ) ;
q . setLocalTranslation ( cam . mult ( this . quadSize ) . add ( quadOrigins [ quadrant - 1 ] ) ) ;
Vector3f loc = cam . mult ( this . quadSize - 1 ) . subtract ( quarterSize , 0 , quarterSize ) ; // quadrant location handled TerrainQuad automatically now
q . setLocalTranslation ( loc ) ;
if ( quadControls ! = null ) {
if ( quadControls ! = null ) {
quadControls [ quadrant - 1 ] . setEnabled ( false ) ;
quadControls [ quadrant - 1 ] . setEnabled ( false ) ;
@ -181,6 +246,8 @@ public class TerrainGrid extends TerrainQuad {
//quadControls[quadrant - 1].setPhysicsLocation(cam.add(this.quadOrigins[quadrant - 1]));
//quadControls[quadrant - 1].setPhysicsLocation(cam.add(this.quadOrigins[quadrant - 1]));
} else {
} else {
}
}
updateModelBound ( ) ;
}
}
private void updateChildrens ( Vector3f cam ) {
private void updateChildrens ( Vector3f cam ) {
@ -203,11 +270,14 @@ public class TerrainGrid extends TerrainQuad {
}
}
}
}
TerrainQuad q1 = cache . get ( cam . add ( quadIndex [ 5 ] ) ) ;
//TerrainQuad q1 = cache.get(cam.add(quadIndex[9]));
TerrainQuad q2 = cache . get ( cam . add ( quadIndex [ 6 ] ) ) ;
//TerrainQuad q2 = cache.get(cam.add(quadIndex[5]));
TerrainQuad q3 = cache . get ( cam . add ( quadIndex [ 9 ] ) ) ;
//TerrainQuad q3 = cache.get(cam.add(quadIndex[10]));
TerrainQuad q4 = cache . get ( cam . add ( quadIndex [ 10 ] ) ) ;
//TerrainQuad q4 = cache.get(cam.add(quadIndex[6]));
// ---------------------------------------------------
// what does this block do?
// ---------------------------------------------------
int dx = 0 ;
int dx = 0 ;
int dy = 0 ;
int dy = 0 ;
if ( currentCell ! = null ) {
if ( currentCell ! = null ) {
@ -236,16 +306,21 @@ public class TerrainGrid extends TerrainQuad {
cache . get ( cam . add ( quadIndex [ i * 4 + j ] ) ) ;
cache . get ( cam . add ( quadIndex [ i * 4 + j ] ) ) ;
}
}
}
}
// ---------------------------------------------------
// ---------------------------------------------------
if ( q1 = = null | | q2 = = null | | q3 = = null | | q4 = = null ) {
try {
if ( executor = = null )
if ( executor = = null )
executor = createExecutorService ( ) ;
executor = createExecutorService ( ) ;
executor . submit ( new UpdateQuadCache ( cam , true ) ) . get ( ) ;
q1 = cache . get ( cam . add ( quadIndex [ 5 ] ) ) ;
executor . submit ( new UpdateQuadCache ( cam ) ) ;
q2 = cache . get ( cam . add ( quadIndex [ 6 ] ) ) ;
q3 = cache . get ( cam . add ( quadIndex [ 9 ] ) ) ;
/ * if ( q1 = = null | | q2 = = null | | q3 = = null | | q4 = = null ) {
q4 = cache . get ( cam . add ( quadIndex [ 10 ] ) ) ;
try {
executor . submit ( new UpdateQuadCache ( cam , true ) ) . get ( ) ; // BLOCKING
q1 = cache . get ( cam . add ( quadIndex [ 9 ] ) ) ;
q2 = cache . get ( cam . add ( quadIndex [ 5 ] ) ) ;
q3 = cache . get ( cam . add ( quadIndex [ 10 ] ) ) ;
q4 = cache . get ( cam . add ( quadIndex [ 6 ] ) ) ;
} catch ( InterruptedException ex ) {
} catch ( InterruptedException ex ) {
Logger . getLogger ( TerrainGrid . class . getName ( ) ) . log ( Level . SEVERE , null , ex ) ;
Logger . getLogger ( TerrainGrid . class . getName ( ) ) . log ( Level . SEVERE , null , ex ) ;
return ;
return ;
@ -263,13 +338,13 @@ public class TerrainGrid extends TerrainQuad {
this . removeQuad ( 3 ) ;
this . removeQuad ( 3 ) ;
this . removeQuad ( 4 ) ;
this . removeQuad ( 4 ) ;
attachQuadAt ( q1 , 1 , cam ) ;
attachQuadAt ( q1 , 1 , cam ) ; // quadIndex[9]
attachQuadAt ( q2 , 2 , cam ) ;
attachQuadAt ( q2 , 2 , cam ) ; // quadIndex[5]
attachQuadAt ( q3 , 3 , cam ) ;
attachQuadAt ( q3 , 3 , cam ) ; // quadIndex[10]
attachQuadAt ( q4 , 4 , cam ) ;
attachQuadAt ( q4 , 4 , cam ) ; // quadIndex[6]
* /
this . currentCell = cam ;
this . currentCell = cam ;
this . updateModelBound ( ) ;
// this.updateModelBound();
}
}
public void addListener ( String id , TerrainGridListener listener ) {
public void addListener ( String id , TerrainGridListener listener ) {
@ -293,4 +368,15 @@ public class TerrainGrid extends TerrainQuad {
public void setQuadSize ( int quadSize ) {
public void setQuadSize ( int quadSize ) {
this . quadSize = quadSize ;
this . quadSize = quadSize ;
}
}
@Override
public void adjustHeight ( List < Vector2f > xz , List < Float > height ) {
Vector3f currentGridLocation = getCurrentCell ( ) . mult ( getLocalScale ( ) ) . multLocal ( quadSize - 1 ) ;
for ( Vector2f vect : xz )
{
vect . x - = currentGridLocation . x ;
vect . y - = currentGridLocation . z ;
}
super . adjustHeight ( xz , height ) ;
}
}
}