/*
* License goes here.
* GPL?
*/
package edu.ups.gamedev.terrain;
import com.jme.math.Vector2f;
import com.jme.math.Vector3f;
import com.jme.renderer.Renderer;
import com.jme.scene.VBOInfo;
import com.jme.scene.batch.TriangleBatch;
import com.jme.util.geom.BufferUtils;
import com.jmex.terrain.TerrainBlock;
import java.nio.FloatBuffer;
import java.util.Random;
/**
*
* @author scanfield
*/
public class MaterialTerrainBlock extends TerrainBlock {
public MaterialMap materialMap;
public MaterialTerrainBlock(String name, int size, Vector3f stepScale,
int[] heightMap, Vector3f origin, boolean clod, int totalSize,
Vector2f offset, float offsetAmount, MaterialMap matMap) {
setUseClod(clod);
setSize(size);
setStepScale(stepScale);
setTotalSize(totalSize);
setOffsetAmount(offsetAmount);
setOffset(offset);
setHeightMap(heightMap);
this.materialMap = matMap;
setLocalTranslation(origin);
buildVertices();
buildTextureCoordinates();
buildNormals();
TriangleBatch batch = getBatch(0);
VBOInfo vbo = new VBOInfo(true);
batch.setVBOInfo(vbo);
if (isUseClod()) {
this.create(null);
this.setTrisPerPixel(0.02f);
}
}
int draw;
public MaterialTerrainBlock(String name, int getSize,
Vector3f getStepScale, int[] getHeightMap, Vector3f origin,
boolean clod, MaterialMap matMap) {
super(name, getSize, getStepScale, getHeightMap, origin, clod);
this.materialMap = matMap;
}
public MaterialTerrainBlock(String name) {
super(name);
}
public MaterialTerrainBlock() {
super();
}
private int TILE_SIZE = 32;
@Override
public void buildTextureCoordinates() {
float offsetX = getOffset().x + (getOffsetAmount() * getStepScale().x);
float offsetY = getOffset().y + (getOffsetAmount() * getStepScale().z);
TriangleBatch batch = getBatch(0);
FloatBuffer texs = BufferUtils.createVector2Buffer(batch
.getTextureBuffers().get(0), batch.getVertexCount());
batch.getTextureBuffers().set(0, texs);
texs.clear();
batch.getVertexBuffer().rewind();
float firstX = -1.0f;
float firstY = -1.0f;
for (int i = 0; i < batch.getVertexCount(); i++) {
Vector2f mapCoord = new Vector2f();
mapCoord.x = (batch.getVertexBuffer().get() + offsetX) / (getStepScale().x);
batch.getVertexBuffer().get(); // ignore vert y coord.
mapCoord.y = (batch.getVertexBuffer().get() + offsetY) / (getStepScale().z);
if( firstX == -1.0f ) {
firstX = mapCoord.x;
}
if( firstY == -1.0f ) {
firstY = mapCoord.y;
}
float up = 1.0f;//((float)TILE_SIZE+1.0f) / (float)TILE_SIZE;
float tileIndexX = (mapCoord.x % TILE_SIZE) / TILE_SIZE;
float tileIndexY = (mapCoord.y % TILE_SIZE) / TILE_SIZE;
float oX = tileIndexX * up;
float oY = tileIndexY * up;
if( tileIndexX == 0.0f ) {
if( mapCoord.x != firstX ) {
oX = 1.0f;
} else {
oX = 0.00f;
}
}
if( tileIndexY == 0.0f ) {
if( mapCoord.y != firstY ) {
oY = 1.0f;
} else {
oY = 0.00f;
}
}
Vector2f texCoord = materialMap.textureForMap(mapCoord);
float fX = texCoord.x + (0.5f * oX);
float fY = texCoord.y + (0.5f * oY);
texs.put(fX);
texs.put(fY);
}
}
private void buildVertices() {
TriangleBatch batch = getBatch(0);
batch.setVertexCount(getHeightMap().length);
batch.setVertexBuffer(BufferUtils.createVector3Buffer(batch
.getVertexBuffer(), batch.getVertexCount()));
Vector3f point = new Vector3f();
for (int x = 0; x < getSize(); x++) {
for (int y = 0; y < getSize(); y++) {
point.set(x * getStepScale().x,
getHeightMap()[x + (y * getSize())] * getStepScale().y,
y * getStepScale().z);
BufferUtils.setInBuffer(point, batch.getVertexBuffer(),
(x + (y * getSize())));
}
}
FloatBuffer fb = BufferUtils.createVector3Buffer( null, batch.getVertexCount());
float offsetX = getOffset().x + (getOffsetAmount() * getStepScale().x);
float offsetY = getOffset().y + (getOffsetAmount() * getStepScale().z);
for (int x = 0; x < getSize(); x++) {
for (int y = 0; y < getSize(); y++) {
Vector3f newPoint = new Vector3f();
Vector2f mapCoord = new Vector2f( x + offsetX, y + offsetY );
int indexMain = (x + (y * getSize()));
Vector2f texCoord = materialMap.textureForMap(mapCoord);
BufferUtils.populateFromBuffer( newPoint, batch.getVertexBuffer(), indexMain);
newPoint.y = averageHeight( batch, x, y );
BufferUtils.setInBuffer( newPoint, fb, indexMain);
}
}
batch.setVertexBuffer( fb );
for (int x = 0; x < getSize(); x++) {
for (int y = 0; y < getSize(); y++) {
// fixAllPoint( batch ,x,y);
}
}
// set up the indices
batch.setTriangleQuantity(((getSize() - 1) * (getSize() - 1)) * 2);
batch.setIndexBuffer(BufferUtils.createIntBuffer(batch
.getTriangleCount() * 3));
// go through entire array up to the second to last column.
for (int i = 0; i < (getSize() * (getSize() - 1)); i++) {
// we want to skip the top row.
if (i % ((getSize() * (i / getSize() + 1)) - 1) == 0 && i != 0) {
continue;
}
int x = i % getSize();
int y = i / getSize();
// set the top left corner.
batch.getIndexBuffer().put(i);
// set the bottom right corner.
batch.getIndexBuffer().put((1 + getSize()) + i);
// set the top right corner.
batch.getIndexBuffer().put(1 + i);
// set the top left corner
batch.getIndexBuffer().put(i);
// set the bottom left corner
batch.getIndexBuffer().put(getSize() + i);
// set the bottom right corner
batch.getIndexBuffer().put((1 + getSize()) + i);
}
}
public void fixAllPoint( TriangleBatch tb, int x, int y ) {
int i = 0;
int j = 0;
for( i = -1; i < 2; i++ ) {
for( j = -1; j < 2; j++ ) {
fixPoint( tb, x,y, x+i, y+j);
}
}
}
public void fixPoint( TriangleBatch tb, int x, int y, int x2, int y2 ) {
//System.out.println( x + " , " + y + " , " + x2 + " , " + y2);
float offsetX = getOffset().x + (getOffsetAmount() * getStepScale().x);
float offsetY = getOffset().y + (getOffsetAmount() * getStepScale().z);
if( y2 < getSize() && y2 > 0 && x2 > 0 && x2 < getSize() ) {
Vector3f here = new Vector3f();
int indexMain = (x + (y * getSize()));
BufferUtils.populateFromBuffer( here, tb.getVertexBuffer(), indexMain);
Vector3f above = new Vector3f();
int indexAbove = (x2 + ((y2) * getSize()));
BufferUtils.populateFromBuffer( above, tb.getVertexBuffer(), indexAbove);
Vector2f mapHere = new Vector2f( x + offsetX, y + offsetY );
Vector2f mapAbove = new Vector2f( x2 + offsetX, y2 + offsetY );
Vector2f textureHere = materialMap.textureForMap( mapHere );
Vector2f textureAbove = materialMap.textureForMap( mapAbove );
if( ! textureHere.equals( textureAbove )) {
System.out.println("The points " + here.toString() + "and " + above.toString() + " are on different textures " );
Vector3f avg = new Vector3f();
avg = avg.add( here );
avg = avg.add( above );
avg = avg.divide( 2.0f );
BufferUtils.setInBuffer( avg, tb.getVertexBuffer(), indexMain );
BufferUtils.setInBuffer( avg, tb.getVertexBuffer(), indexAbove );
}
}
}
public float averageHeight( TriangleBatch tb, int x, int y ) {
int numPoints = 0;
Vector3f accum = new Vector3f();
Vector3f store = new Vector3f();
if( x == 0 || x == getSize()-1 || y == 0 || y == getSize()-1) {
BufferUtils.populateFromBuffer( store , tb.getVertexBuffer(), indexForPoint( x, y ) );
return store.y;
}
if( x+1 < getSize() ) {
BufferUtils.populateFromBuffer( store , tb.getVertexBuffer(), indexForPoint( x+1, y ) );
numPoints++;
accum = accum.add( store );
}
if( x-1 > 0 ) {
BufferUtils.populateFromBuffer( store , tb.getVertexBuffer(), indexForPoint( x-1, y ) );
numPoints++;
accum = accum.add( store );
}
if( y+1 < getSize() ) {
BufferUtils.populateFromBuffer( store , tb.getVertexBuffer(), indexForPoint( x, y+1 ) );
numPoints++;
accum = accum.add( store );
}
if( y-1 > 0) {
BufferUtils.populateFromBuffer( store , tb.getVertexBuffer(), indexForPoint( x, y-1 ) );
numPoints++;
accum = accum.add( store );
}
BufferUtils.populateFromBuffer( store , tb.getVertexBuffer(), indexForPoint( x, y ) );
numPoints++;
accum = accum.add( store );
accum = accum.divide( numPoints );
return accum.y;
}
public int indexForPoint( int x, int y ) {
return (x + (y * getSize()));
}
/**
* <code>buildNormals</code> calculates the normals of each vertex that makes up the block of terrain.
*/
private void buildNormals() {
TriangleBatch batch = getBatch(0);
batch.setNormalBuffer(BufferUtils.createVector3Buffer(batch
.getNormalBuffer(), batch.getVertexCount()));
Vector3f oppositePoint = new Vector3f();
Vector3f adjacentPoint = new Vector3f();
Vector3f rootPoint = new Vector3f();
Vector3f tempNorm = new Vector3f();
int adj = 0, opp = 0, normalIndex = 0;
for (int row = 0; row < getSize(); row++) {
for (int col = 0; col < getSize(); col++) {
BufferUtils.populateFromBuffer(rootPoint, batch
.getVertexBuffer(), normalIndex);
if (row == getSize() - 1) {
if (col == getSize() - 1) { // last row, last col
// up cross left
adj = normalIndex - getSize();
opp = normalIndex - 1;
} else { // last row, except for last col
// right cross up
adj = normalIndex + 1;
opp = normalIndex - getSize();
}
} else {
if (col == getSize() - 1) { // last column except for last row
// left cross down
adj = normalIndex - 1;
opp = normalIndex + getSize();
} else { // most cases
// down cross right
adj = normalIndex + getSize();
opp = normalIndex + 1;
}
}
BufferUtils.populateFromBuffer(adjacentPoint, batch
.getVertexBuffer(), adj);
BufferUtils.populateFromBuffer(oppositePoint, batch
.getVertexBuffer(), opp);
tempNorm.set(adjacentPoint).subtractLocal(rootPoint)
.crossLocal(oppositePoint.subtractLocal(rootPoint))
.normalizeLocal();
BufferUtils.setInBuffer(tempNorm, batch.getNormalBuffer(),
normalIndex);
normalIndex++;
}
}
}
}