rendered paste body/*
* Copyright (c) 2006 World of Mystery Project Team
* 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.
*
* 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 de.worldofmystery.client.world;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.URL;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.logging.Logger;
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileFilter;
import com.jme.app.SimpleGame;
import com.jme.bounding.BoundingBox;
import com.jme.image.Image;
import com.jme.image.Texture;
import com.jme.input.InputHandler;
import com.jme.input.KeyInput;
import com.jme.input.MouseInput;
import com.jme.input.action.InputAction;
import com.jme.input.action.InputActionEvent;
import com.jme.light.Light;
import com.jme.light.PointLight;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.pass.BasicPassManager;
import com.jme.renderer.pass.RenderPass;
import com.jme.scene.Node;
import com.jme.scene.Point;
import com.jme.scene.Spatial;
import com.jme.scene.lod.AreaClodMesh;
import com.jme.scene.state.AlphaState;
import com.jme.scene.state.FragmentProgramState;
import com.jme.scene.state.TextureState;
import com.jme.system.DisplaySystem;
import com.jme.util.LoggingSystem;
import com.jme.util.TextureManager;
import com.jme.util.geom.BufferUtils;
import com.jmex.model.XMLparser.BinaryToXML;
import com.jmex.model.XMLparser.JmeBinaryWriter;
import de.worldofmystery.common.l3dt.AlphaData;
import de.worldofmystery.common.l3dt.HeightFieldFile;
import de.worldofmystery.common.l3dt.L3DTGroupFile;
/**
* test program to convert a L3DT terrain to jME node
* @author galun
* @version $Id: L3DTLoader.java,v 1.20 2006/05/21 20:26:08 galun Exp $
*/
public class L3DTLoader extends SimpleGame {
private final static String DATAOUT = "/tmp/scene";
private String sourceDirectory = System.getProperty("user.dir", ".");
private Logger log = LoggingSystem.getLogger();
private Node terrainNode;
private Node pointNode;
//private L3DTGroupFile prop = null;
private AlphaData alphaData = null;
private int tiles = 16;
private int mosaics = 1;
private boolean splatted = true;
private String loadedFile;
protected BasicPassManager pManager;
public static void main(String[] args) {
L3DTLoader loader = new L3DTLoader();
loader.start();
}
protected void simpleInitGame() {
pManager = new BasicPassManager();
display.setTitle( "jME-Desktop test" );
display.getRenderer().setBackgroundColor(ColorRGBA.blue);
File cachedScene = new File(DATAOUT);
InputAction togglePoints = new InputAction() {
public void performAction(InputActionEvent evt) {
if (evt.getTriggerCharacter() == '1') {
int cm = terrainNode.getCullMode();
if (cm == Spatial.CULL_DYNAMIC)
cm = Spatial.CULL_ALWAYS;
else
cm = Spatial.CULL_DYNAMIC;
terrainNode.setCullMode(cm);
} else if (evt.getTriggerCharacter() == '2') {
int cm = pointNode.getCullMode();
if (cm == Spatial.CULL_DYNAMIC)
cm = Spatial.CULL_ALWAYS;
else
cm = Spatial.CULL_DYNAMIC;
pointNode.setCullMode(cm);
}
}
};
input.addAction(togglePoints, InputHandler.DEVICE_KEYBOARD, KeyInput.KEY_1, InputHandler.AXIS_NONE, false);
input.addAction(togglePoints, InputHandler.DEVICE_KEYBOARD, KeyInput.KEY_2, InputHandler.AXIS_NONE, false);
try {
if (cachedScene.canRead()) {
long started = System.currentTimeMillis();
ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream(cachedScene)));
terrainNode = (Node)ois.readObject();
ois.close();
terrainNode.updateGeometricState(0, true);
log.info("loading scene took "+(System.currentTimeMillis()-started)+"ms");
rootNode.attachChild(terrainNode);
} else {
if (properties.get("SourceDirectory") != null)
sourceDirectory = properties.get("SourceDirectory");
long started = System.currentTimeMillis();
L3DTGroupFile prop = loadGroupFile();
HeightFieldFile hffTotal = new HeightFieldFile();
hffTotal.load(prop.getFileName("HF"));
log.info("hffTotal=" + hffTotal.toString());
Tile[] mosaic = new Tile[mosaics];
if (mosaics == 1) {
mosaic[0] = new Tile(hffTotal, prop.getProperty("TX"), prop.getFileName("TX"), prop.getDirectory() + File.separator);
}
for (int i = 0; i < mosaic.length; i++) {
if (tiles > 0) {
if (splatted)
terrainNode = createSplattedTerrainNode(mosaic[i], tiles);
else
terrainNode = createTiledTerrainNode(mosaic[i], tiles);
}
else
terrainNode = createTerrainNode(mosaic[i]);
pointNode = createPointNode(hffTotal);
terrainNode.updateGeometricState(0, true);
pointNode.updateGeometricState(0, true);
BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(DATAOUT + i + ".jme"));
JmeBinaryWriter jmeWriter = new JmeBinaryWriter();
jmeWriter.writeScene(terrainNode, os);
os.close();
FileWriter writer = new FileWriter(DATAOUT + i + ".xml");
new BinaryToXML().sendBinarytoXML(new BufferedInputStream(new FileInputStream(DATAOUT + i + ".jme")), writer);
rootNode.attachChild(terrainNode);
rootNode.attachChild(pointNode);
}
log.info("creating scene took "+(System.currentTimeMillis()-started)+"ms");
}
} catch (Exception ex) {
ex.printStackTrace();
}
rootNode.updateGeometricState(0, true);
rootNode.updateRenderState();
lightState.setGlobalAmbient(ColorRGBA.lightGray);
cam.setFrustumFar(16000);
cam.getLocation().y = 8000;
cam.update();
for (int i = 0; i < lightState.getQuantity(); i++) {
log.info("Light#" + i + ": " + lightInfo(lightState.get(i)));
if (lightState.get(i) instanceof PointLight)
((PointLight)lightState.get(i)).setLocation(new Vector3f(100, 10000, 100));
}
log.info("global ambient=" + lightState.getGlobalAmbient().toString());
log.info("init done");
log.info("max units: " + TextureState.getNumberOfUnits());
log.info("non-power-of-2 supported=" + TextureState.isSupportingNonPowerOfTwoTextureSize());
}
protected void simpleUpdate() {
if (pManager != null)
pManager.updatePasses(tpf);
}
private String lightInfo(Light l) {
String add = "";
if (l instanceof PointLight)
add = " pos="+((PointLight)l).getLocation().toString() +
" constant="+((PointLight)l).getConstant() +
" linear="+((PointLight)l).getLinear();
return l.getType()+" ambient="+l.getAmbient()+" diffuse="+l.getDiffuse()+" specular="+l.getSpecular()+add;
}
private L3DTGroupFile loadGroupFile() {
L3DTGroupFile group = new L3DTGroupFile();
String filename = null;
MouseInput.get().setCursorVisible(true);
JFileChooser chooser = new JFileChooser(sourceDirectory);
chooser.setFileFilter(new FileFilter() {
public boolean accept(File f) {
return f.isDirectory() || f.getName().endsWith(".mgf");
}
public String getDescription() {
return "L3DT Map Group File (*.mgf)";
}
});
if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION)
filename = chooser.getSelectedFile().getAbsolutePath();
else
return null;
try {
group.load(filename);
loadedFile = filename;
System.out.println(group.toString());
} catch (Exception ex) {
ex.printStackTrace();
}
MouseInput.get().setCursorVisible(false);
return group;
}
private Node createPointNode(HeightFieldFile hff) throws IOException {
Node node = new Node("points");
FloatBuffer vertices = BufferUtils.createFloatBuffer(hff.getVertices());
Point p = new Point("terrain", vertices, null, null, null);
node.attachChild(p);
return node;
}
private Node createTerrainNode(Tile tile) throws IOException {
Node node = new Node("terrain");
FloatBuffer vertices = BufferUtils.createFloatBuffer(tile.hff.getVertices());
IntBuffer indices = BufferUtils.createIntBuffer(tile.hff.getIndices());
FloatBuffer texs = BufferUtils.createFloatBuffer(tile.hff.getTexCoords());
AreaClodMesh terrainBlock = new AreaClodMesh("heightMap", vertices, null, null, texs, indices, null);
//TriMesh terrainBlock = new TriMesh("heightMap", vertices, null, null, null, indices);
terrainBlock.setDefaultColor(ColorRGBA.white);
TextureState textureState = DisplaySystem.getDisplaySystem().getRenderer().createTextureState();
Texture texture = TextureManager.loadTexture(tile.texturePath,
Texture.MM_LINEAR, Texture.FM_LINEAR, 1.0f, false);
//Texture lightMap = TextureManager.loadTexture(prop.getFileName("LM"), Texture.MM_LINEAR, Texture.FM_LINEAR, 1.0f, false);
log.fine("set texture location to " + tile.textureName);
texture.setImageLocation(tile.textureName);
texture.setApply(Texture.AM_COMBINE);
//lightMap.setApply(Texture.AM_COMBINE);
textureState.setTexture(texture, 0);
//textureState.setTexture(lightMap, 1);
textureState.setEnabled(true);
terrainBlock.setRenderState(textureState);
terrainBlock.setModelBound(new BoundingBox());
terrainBlock.updateModelBound();
terrainBlock.updateGeometricState(0, true);
node.attachChild(terrainBlock);
return node;
}
private Node createTiledTerrainNode(Tile tile, int tiles) throws IOException {
Node node = new Node("terrain");
float tileWidth = (float)tile.hff.getWidth() / tiles;
for (int zz = 0; zz < tiles; zz++)
for (int xx = 0; xx < tiles; xx++) {
HeightFieldFile hff = tile.hff.getTileAt(xx, zz, tiles);
FloatBuffer vertices = BufferUtils.createFloatBuffer(hff.getVertices());
IntBuffer indices = BufferUtils.createIntBuffer(hff.getIndices());
FloatBuffer texs = BufferUtils.createFloatBuffer(hff.getTexCoords(xx, zz, tiles));
AreaClodMesh terrainBlock = new AreaClodMesh("heightMap-"+xx+"-"+zz, vertices, null, null, texs, indices, null);
//TriMesh terrainBlock = new TriMesh("heightMap", vertices, null, null, null, indices);
terrainBlock.setDefaultColor(ColorRGBA.white);
TextureState textureState = DisplaySystem.getDisplaySystem().getRenderer().createTextureState();
Texture texture = TextureManager.loadTexture(tile.texturePath, Texture.MM_LINEAR, Texture.FM_LINEAR, 1.0f, true);
//Texture lightMap = TextureManager.loadTexture(prop.getFileName("LM"), Texture.MM_LINEAR, Texture.FM_LINEAR, 1.0f, false);
log.info("set texture location to " + tile.textureName);
texture.setImageLocation("file:data/meshes/" + tile.textureName);
texture.setApply(Texture.AM_COMBINE);
//lightMap.setApply(Texture.AM_COMBINE);
textureState.setTexture(texture, 0);
//textureState.setTexture(lightMap, 1);
textureState.setEnabled(true);
float posX = (-tiles/2 + xx + 0.5f) * tileWidth * tile.hff.getHorizontalScale();
float posZ = (-tiles/2 + zz + 0.5f) * tileWidth * tile.hff.getHorizontalScale();
terrainBlock.setLocalTranslation(new Vector3f(posX, 0, posZ));
terrainBlock.setRenderState(textureState);
terrainBlock.setModelBound(new BoundingBox());
terrainBlock.updateModelBound();
terrainBlock.updateGeometricState(0, true);
node.attachChild(terrainBlock);
}
return node;
}
private Node createSplattedTerrainNode(Tile tile, int tiles) throws IOException {
Node node = new Node("terrain");
Image[] alphaMaps;
String basename = loadedFile.replaceAll("\\.mgf$", "");
if (alphaData == null) {
alphaData = new AlphaData();
alphaData.load(basename + ".xml");
System.err.println(alphaData.toString());
}
alphaMaps = alphaData.getCombinedAlphaImages();
System.err.println("getCombinedAlphaImages() returns " + alphaMaps.length + " maps.");
for (int i = 0; i < alphaMaps.length; i++)
ImageWriter.write(basename + "-alpha-" + i, alphaMaps[i]);
float tileWidth = (float)tile.hff.getWidth() / tiles;
for (int zz = 0; zz < tiles; zz++)
for (int xx = 0; xx < tiles; xx++) {
HeightFieldFile hff = tile.hff.getTileAt(xx, zz, tiles);
FloatBuffer vertices = BufferUtils.createFloatBuffer(hff.getVertices());
IntBuffer indices = BufferUtils.createIntBuffer(hff.getIndices());
// these texture coordinates are spread over the whole terrain - one tile gets a fraction of the
// texture (1 / (tiles*tiles)
FloatBuffer texs = BufferUtils.createFloatBuffer(hff.getTexCoords(xx, zz, tiles));
AreaClodMesh terrainBlock = new AreaClodMesh("heightMap-"+xx+"-"+zz, vertices, null, null, texs, indices, null);
//TriMesh terrainBlock = new TriMesh("heightMap", vertices, null, null, null, indices);
terrainBlock.setDefaultColor(ColorRGBA.white);
terrainBlock.copyTextureCoords(0, 0, 1);
TextureState textureState = DisplaySystem.getDisplaySystem().getRenderer().createTextureState();
Texture alphaMap = createTexture(alphaMaps[0]);
textureState.setTexture(alphaMap, 0);
Texture tex1 = TextureManager.loadTexture(tile.baseDir + alphaData.getImages().get(0).layers.get(0).textures.get(0),
Texture.MM_LINEAR, Texture.FM_LINEAR, 1.0f, false);
//tex1.setScale(new Vector3f(3,3,3));
tex1.setWrap(Texture.WM_WRAP_S_WRAP_T);
textureState.setTexture(tex1, 1);
terrainBlock.copyTextureCoords(0, 0, 2, tiles);
Texture tex2 = TextureManager.loadTexture(tile.baseDir + alphaData.getImages().get(1).layers.get(0).textures.get(0),
Texture.MM_LINEAR, Texture.FM_LINEAR, 1.0f, false);
//tex2.setScale(new Vector3f(3,3,3));
tex2.setWrap(Texture.WM_WRAP_S_WRAP_T);
textureState.setTexture(tex2, 2);
terrainBlock.copyTextureCoords(0, 0, 3, tiles);
Texture tex3 = TextureManager.loadTexture(tile.baseDir + alphaData.getImages().get(2).layers.get(0).textures.get(0),
Texture.MM_LINEAR, Texture.FM_LINEAR, 1.0f, false);
//tex3.setScale(new Vector3f(3,3,3));
tex3.setWrap(Texture.WM_WRAP_S_WRAP_T);
textureState.setTexture(tex3, 3);
terrainBlock.copyTextureCoords(0, 0, 4, tiles);
Texture tex4 = TextureManager.loadTexture(tile.baseDir + alphaData.getImages().get(3).layers.get(0).textures.get(0),
Texture.MM_LINEAR, Texture.FM_LINEAR, 1.0f, false);
//tex4.setScale(new Vector3f(3,3,3));
tex4.setWrap(Texture.WM_WRAP_S_WRAP_T);
textureState.setTexture(tex4, 4);
terrainBlock.copyTextureCoords(0, 0, 5, tiles);
FragmentProgramState fp = DisplaySystem.getDisplaySystem().getRenderer().createFragmentProgramState();
URL prog = L3DTLoader.class.getClassLoader().getResource("de/worldofmystery/client/world/glsl/splatting_fp.fp");
fp.load(prog);
fp.setEnabled(true);
// log.info("set texture location to "+prop.getProperty("TX"));
// texture.setImageLocation("file:data/meshes/"+prop.getProperty("TX"));
// texture.setApply(Texture.AM_COMBINE);
//lightMap.setApply(Texture.AM_COMBINE);
// textureState.setTexture(alphaMap, 0);
//textureState.setTexture(lightMap, 1);
textureState.setEnabled(true);
float posX = (-tiles/2 + xx + 0.5f) * tileWidth * tile.hff.getHorizontalScale();
float posZ = (-tiles/2 + zz + 0.5f) * tileWidth * tile.hff.getHorizontalScale();
terrainBlock.setLocalTranslation(new Vector3f(posX, 0, posZ));
// terrainBlock.setRenderState(textureState);
// terrainBlock.setRenderState(fp);
RenderPass rp1 = new RenderPass();
rp1.setPassState(textureState);
rp1.setPassState(fp);
rp1.add(terrainBlock);
pManager.add(rp1);
AlphaState as = display.getRenderer().createAlphaState();
as.setBlendEnabled(true);
as.setSrcFunction(AlphaState.SB_DST_COLOR);
as.setDstFunction(AlphaState.DB_SRC_COLOR);
TextureState textureState2 = DisplaySystem.getDisplaySystem().getRenderer().createTextureState();
Texture alphaMap2 = createTexture(alphaMaps[1]);
textureState2.setTexture(alphaMap2, 0);
Texture tex5 = TextureManager.loadTexture(tile.baseDir + alphaData.getImages().get(4).layers.get(0).textures.get(0),
Texture.MM_LINEAR, Texture.FM_LINEAR, 1.0f, false);
//tex1.setScale(new Vector3f(3,3,3));
tex5.setWrap(Texture.WM_WRAP_S_WRAP_T);
textureState2.setTexture(tex5, 1);
terrainBlock.copyTextureCoords(0, 0, 6, tiles);
Texture tex6 = TextureManager.loadTexture(tile.baseDir + alphaData.getImages().get(5).layers.get(0).textures.get(0),
Texture.MM_LINEAR, Texture.FM_LINEAR, 1.0f, false);
//tex2.setScale(new Vector3f(3,3,3));
tex6.setWrap(Texture.WM_WRAP_S_WRAP_T);
textureState2.setTexture(tex6, 2);
terrainBlock.copyTextureCoords(0, 0, 7, tiles);
Texture tex7 = TextureManager.loadTexture(tile.baseDir + alphaData.getImages().get(6).layers.get(0).textures.get(0),
Texture.MM_LINEAR, Texture.FM_LINEAR, 1.0f, false);
//tex3.setScale(new Vector3f(3,3,3));
tex7.setWrap(Texture.WM_WRAP_S_WRAP_T);
textureState2.setTexture(tex7, 3);
terrainBlock.copyTextureCoords(0, 0, 8, tiles);
Texture tex8 = TextureManager.loadTexture(tile.baseDir + "dummy.png",
Texture.MM_LINEAR, Texture.FM_LINEAR, 1.0f, false);
//tex3.setScale(new Vector3f(3,3,3));
tex8.setWrap(Texture.WM_WRAP_S_WRAP_T);
textureState2.setTexture(tex8, 4);
terrainBlock.copyTextureCoords(0, 0, 9, tiles);
// terrainBlock.setRenderState(textureState2);
// terrainBlock.setRenderState(fp);
RenderPass rp2 = new RenderPass();
rp2.setPassState(textureState2);
rp1.setPassState(fp);
rp2.setPassState(as);
rp2.setZFactor(0f);
rp2.setZOffset(-5f);
rp2.add(terrainBlock);
pManager.add(rp2);
terrainBlock.setModelBound(new BoundingBox());
terrainBlock.updateModelBound();
terrainBlock.updateGeometricState(0, true);
log.info("created terrain block from " + hff.toString());
node.attachChild(terrainBlock);
}
return node;
}
private Texture createTexture(Image image) {
Texture texture = new Texture();
texture.setImage(image);
texture.setCorrection(Texture.CM_PERSPECTIVE);
texture.setFilter(Texture.FM_LINEAR);
texture.setMipmapState(Texture.MM_LINEAR);
return texture;
}
class Tile {
public HeightFieldFile hff;
public String textureName;
public String texturePath;
public String baseDir;
public Tile(HeightFieldFile hff, String textureName, String texturePath, String baseDir) {
this.hff = hff;
this.textureName = textureName;
this.texturePath = texturePath;
this.baseDir = baseDir;
}
}
}