Currently showing src/Xith3DTerrainTest.java
/**
* Copyright (c) 2003, Xith3D Project Group
* All rights reserved.
*
* Portions based on the Java3D interface, Copyright by Sun Microsystems.
* Many thanks to the developers of Java3D and Sun Microsystems for their
* innovation and design.
*
* 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 the 'Xith3D Project Group' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* Modified by Michael Wright - Janus Research Group, Inc.
* michael.wright@janusresearch.com
*
* 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) A
* RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE
*
*/
package com.janusresearch.concept;
import com.xith3d.test.*;
import com.xith3d.utility.logs.*;
import java.awt.*;
import java.awt.event.*;
import com.xith3d.scenegraph.*;
import com.xith3d.render.*;
import com.xith3d.render.jogl.*;
import javax.vecmath.*;
import javax.swing.*;
import com.xith3d.image.*;
import com.xith3d.loaders.texture.*;
import com.xith3d.userinterface.UIWindowManager;
import com.xith3d.userinterface.UIWindow;
import com.xith3d.userinterface.UIEventAdapter;
import com.xith3d.terrain.TerrainSampleInterface;
import com.xith3d.terrain.Terrain;
import com.xith3d.terrain.TerrainRenderInterface;
import com.xith3d.utility.noise.Perlin2;
import com.xith3d.utility.noise.Noise;
import java.io.*;
/**
* Simple Xith3D Coloring Attributes test
*
* <p>Copyright: Copyright (c) 2003</p>
* <p>Company: JProof</p>
* @author YVG
*/
public class Xith3DTerrainTest
{
Transform3D testRotateY = new Transform3D();
TransformGroup testRotateYGroup = new TransformGroup();
Material mat;
UIWindowManager windowMgr;
Terrain terrain;
TerrainShape terrainShape;
float speed= 4;
protected BranchGroup createSceneGraph() throws Exception
{
BranchGroup objRoot = new BranchGroup();
AmbientLight light = new AmbientLight(true,new Color3f(0,0,1));
objRoot.addChild(light);
Transform3D testRotateX = new Transform3D();
TransformGroup testRotateXGroup = new TransformGroup();
testRotateX.rotX(0.0f);
testRotateXGroup.setTransform(testRotateX);
objRoot.addChild(testRotateXGroup);
testRotateYGroup.setTransform(testRotateY);
testRotateXGroup.addChild(testRotateYGroup);
TransformGroup sceneRootTransform = new TransformGroup();
Transform3D t = new Transform3D();
t.setIdentity();
sceneRootTransform.setTransform(t);
testRotateYGroup.addChild(sceneRootTransform);
mat = new Material();
mat.setAmbientColor(0.75f,0.75f,0.75f);
mat.setLightingEnable(true);
Shape3D shape = new Shape3D();
Geometry g = TestUtils.createCubeViaTriangles(0f, 0f, -0.6f, 0.8f, true);
Appearance a = new Appearance();
a.setPolygonAttributes(new PolygonAttributes(PolygonAttributes.POLYGON_FILL, PolygonAttributes.CULL_BACK, 0));
a.setMaterial(mat);
shape.setAppearance(a);
shape.setGeometry(g);
sceneRootTransform.addChild(shape);
return objRoot;
}
View view;
public void init() throws Exception
{
ConsoleLog myLog = new ConsoleLog(LogType.ALL);
Log.log.registerLog(myLog);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
VirtualUniverse universe = new VirtualUniverse();
view = new View();
view.setBackClipDistance(32000f);
view.setProjectionPolicy(View.PERSPECTIVE_PROJECTION);
view.getTransform().lookAt(
new Vector3f(100, 300, 100),
new Vector3f(2000, 100, 2000),
new Vector3f(0, 1, 0));
Locale locale = new Locale();
universe.addLocale(locale);
universe.addView(view);
RenderPeer renderPeer = new RenderPeerImpl();
int screenWidth = screenSize.width;
int screenHeight = screenSize.height;
float aspectRatio = (float)screenWidth / (float)screenHeight;
System.out.println("ratio: "+aspectRatio);
if (aspectRatio > 2) {
screenWidth= (screenWidth / 2);
}
CanvasPeer canvasPeer =
renderPeer.makeCanvas(
null,
screenWidth - 200,
screenHeight - 200,
16,
true);
canvasPeer.getWindow().setLocation(100, 100);
Canvas3D canvas = new Canvas3D();
canvas.set3DPeer(canvasPeer);
view.addCanvas3D(canvas);
windowMgr = new UIWindowManager(canvas);
TestWindow w = new TestWindow(100,200);
windowMgr.addOverlay(w);
windowMgr.setPosition(w,10,10);
windowMgr.setVisible(w,true);
UIEventAdapter eventAdapter = new UIEventAdapter(windowMgr);
canvas.get3DPeer().getComponent().addKeyListener(eventAdapter);
canvas.get3DPeer().getComponent().addMouseListener(eventAdapter);
canvas.get3DPeer().getComponent().addMouseMotionListener(eventAdapter);
canvas.get3DPeer().getComponent().setFocusable(true);
BranchGroup scene = createSceneGraph();
locale.addBranchGraph(scene);
buildTerrain();
buildSkybox(scene);
terrainShape.rebuild(view);
scene.addChild(terrainShape);
runTest();
}
private void buildTerrain() {
terrain = new Terrain(12,10);
System.out.println("Building terrain...");
terrain.addData(new TerrainGenerator());
System.out.println("Nodes = "+ terrain.CountNodes());
System.out.println("Removing nodes which are irrelevent...");
terrain.cullStaticData(40,4);
System.out.println("Nodes = "+ terrain.CountNodes());
terrainShape = new TerrainShape();
}
public QuadArray getSkySide() {
return new QuadArray(
4,
GeometryArray.TEXTURE_COORDINATE_2 | GeometryArray.COORDINATES
);
}
private Texture2D getSkyTexture(String texName) {
TextureLoader.tf.registerPath("./");
TextureLoader.tf.registerPath("../");
TextureLoader.tf.registerPath("./resources/textures/");
TextureLoader.tf.registerJarPath("/textures/");
return (Texture2D)TextureLoader.tf.getTextureClamp(texName);
}
public void buildSkybox(BranchGroup scene) {
float boxSize = (float)terrain.getWidth();
QuadArray[] skyboxGeo = new QuadArray[] {
getSkySide(),
getSkySide(),
getSkySide(),
getSkySide(),
getSkySide()
};
TexCoord2f[] texCoords = new TexCoord2f[]{
new TexCoord2f(1,0),
new TexCoord2f(1,1),
new TexCoord2f(0,1),
new TexCoord2f(0,0)
};
skyboxGeo[0].setCoordinates(
0,
new Point3f[] {
new Point3f(boxSize, 0.f, boxSize),
new Point3f(boxSize, boxSize, boxSize),
new Point3f(0.f, boxSize, boxSize),
new Point3f(0.f, 0.f, boxSize)
}
);
skyboxGeo[1].setCoordinates(
0,
new Point3f[] {
new Point3f(0.f, 0.f, 0.f),
new Point3f(0.f, boxSize, 0.f),
new Point3f(boxSize, boxSize, 0.f),
new Point3f(boxSize, 0.f, 0.f)
}
);
skyboxGeo[2].setCoordinates(
0,
new Point3f[] {
new Point3f(0.f, 0.f, boxSize),
new Point3f(0.f, boxSize, boxSize),
new Point3f(0.f, boxSize, 0.f),
new Point3f(0.f, 0.f, 0.f)
}
);
skyboxGeo[3].setCoordinates(
0,
new Point3f[] {
new Point3f(boxSize, 0.f, 0.f),
new Point3f(boxSize, boxSize, 0.f),
new Point3f(boxSize, boxSize, boxSize),
new Point3f(boxSize, 0.f, boxSize)
}
);
skyboxGeo[4].setCoordinates(
0,
new Point3f[] {
new Point3f(boxSize, boxSize, boxSize),
new Point3f(boxSize, boxSize, 0.f),
new Point3f(0.f, boxSize, 0.f),
new Point3f(0.f, boxSize, boxSize)
}
);
Appearance[] appearance = new Appearance[] {
new Appearance(),
new Appearance(),
new Appearance(),
new Appearance(),
new Appearance()
};
appearance[0].setTexture(getSkyTexture("ft.jpg"));
appearance[1].setTexture(getSkyTexture("bk.jpg"));
appearance[2].setTexture(getSkyTexture("lt.jpg"));
appearance[3].setTexture(getSkyTexture("rt.jpg"));
appearance[4].setTexture(getSkyTexture("up.jpg"));
for(int i=0; i<5; i++) {
skyboxGeo[i].setTextureCoordinates(0,0,texCoords);
scene.addChild(new Shape3D(skyboxGeo[i], appearance[i]));
}
}
final static float MAX_HEIGHT = 600;
class TerrainShape extends BranchGroup implements TerrainRenderInterface {
final static int MAX_INDICES = 20000;
final static int MAX_VERTICES = 30000;
int startIndex = 0;
int totalIndex = 0;
int totalVerts = 0;
Shape3D shape;
IndexedTriangleArray geo;
int index[] = new int[MAX_INDICES];
float quad[] = new float[50];
int vertexMap[] = new int[100];
PolygonAttributes pa;
public TerrainShape() {
/**
* One thing to note here, you need GeometryArray.TEXTURE_COORDINATE_2
* to do what we're doing in initVert
*
*/
geo = new IndexedTriangleArray(
MAX_VERTICES,
GeometryArray.COORDINATES | GeometryArray.NORMALS | GeometryArray.COLOR_3 | GeometryArray.TEXTURE_COORDINATE_2,
MAX_INDICES);
Appearance a = new Appearance();
pa = new PolygonAttributes(PolygonAttributes.POLYGON_FILL,PolygonAttributes.CULL_BACK,0);
a.setPolygonAttributes(pa);
TextureLoader.tf.registerPath(".");
TextureLoader.tf.registerPath("..");
TextureLoader.tf.registerPath("./resources/");
TextureLoader.tf.registerJarPath("/");
Texture2D texture = (Texture2D) TextureLoader.tf.getMinMapTexture("stone.jpg");
a.setTexture(texture);
shape = new Shape3D(geo,a);
shape.setBoundsAutoCompute(false);
shape.setBounds(new BoundingSphere(new Point3f(0,0,0),100000));
addChild(shape);
}
public void setLineMode(boolean yes) {
if (yes) pa.setPolygonMode(PolygonAttributes.POLYGON_LINE);
else pa.setPolygonMode(PolygonAttributes.POLYGON_FILL);
}
public void rebuild(View view) {
Point3f point = new Point3f();
view.getTransform().get(point);
terrain.update(point,117);
geo.drawStart();
totalIndex = 0;
totalVerts = 0;
terrain.render(this);
System.out.println("total vertices = "+totalVerts);
System.out.println("total indices = "+totalIndex);
geo.drawEnd();
geo.setIndex(index);
geo.setValidIndexCount(totalIndex);
geo.setValidVertexCount(totalVerts);
}
/**
* called at the beginning of rendering the triangles for one adaptive quad square
*/
public void start() {
}
public void initVert(int i, float x, float y, float z) {
// System.out.println("coordinate is "+x+","+y+","+z);
if (totalVerts>=MAX_VERTICES) return;
geo.newVertex();
geo.setCoordinate(x,y,z);
/**
* Ok, here we go with the texture coordinate stuff.
*
* First I set a texture scaling factor. This isn't really a good name for this.
* It's not really a scale, more like a wrapping multiplier. This number should
* defines how many copies of the texture will appear on *each side* of the
* terrain. Square this number and you get the total copies of the texture that
* will be seen on the terrain. To stretch a single texture across the entire terrain,
* you would set this number to 1.
*/
int textureScale = 16;
/**
* Next we have to divide out the texture coordinates. 2D textures have coordinates
* from 0 to 1 in what is called "S,T" space. Each coordinate in our X,Z world
* has to be mapped to its appropriate S,T texture coordinate. If we are stretching
* the texture all the way across the terrain, then 0,0 in X,Z would be 0,0 in S,T and
* the farthest point in X,Z from the origin would be 1,1 in S,T. Thus, mathematically,
* we should divide X and Z by the width and depth (should be equal) of the terrain. To
* wrap the texture, you would divide this depth and width by some number (set by textureScale)
* to make the textured patches smaller.
*/
float texCoordx = x / (terrain.getWidth() / textureScale);
float texCoordz = z / (terrain.getWidth() / textureScale);
TexCoord2f texCoords = new TexCoord2f(texCoordx, texCoordz);
/**
* Now for the fun part. We've already set the coordinate, now we set the texture
* coordinate. According to the Java3D API (from which Xith was birthed):
*
* <cut from API>
* public void setTextureCoordinate(int texCoordSet,
* int index,
* TexCoord2f texCoord)
*
* Sets the texture coordinate associated with the vertex at the specified
* index in the specified texture coordinate set for this object.
*
* Parameters:
* texCoordSet - texture coordinate set in this geometry array
* index - destination vertex index in this geometry array
* texCoord - the TexCoord2f containing the new texture coordinate
* </cut from API>
*
* In our case, we only have one texture coordinate set in this geometry array, so
* we'll set texCoordSet to 0. For our index, we'll use the totalVerts number that is
* being incremented as we step through this process (note the last line of this method).
* For the texCoord, we'll use our TexCoord2f that we set up above.
*/
geo.setTextureCoordinate(0,totalVerts,texCoords);
float c = y/1500;
geo.setColor(0.48f+c, 0.48f+c, 0.39f+c);
vertexMap[i] = totalVerts++;
}
public void tri(int a, int b, int c) {
if (totalIndex+3>=MAX_INDICES) return;
index[totalIndex++] = vertexMap[a];
index[totalIndex++] = vertexMap[b];
index[totalIndex++] = vertexMap[c];
}
/**
* called at the end of rendering the triangles for one adaptive quad square
*/
public void done() {
}
}
public void runTest()
{
float angle = 0f;
Point3f position = new Point3f(20,20,20);
Point3f lookat = new Point3f();
float distance = 20;
Transform3D viewT = new Transform3D();
Point3f lastUpdate = new Point3f(0,0,0);
float direction = 1;
while (true)
{
if (position.x>4000) {
position.x = 4000;
position.z = 4000;
direction = -1;
} else if (position.x<0) {
position.x = 0;
position.z = 0;
direction = 1;
}
position.x += speed*direction;
position.z += speed*direction;
position.y = terrain.getY(position.x, position.z) + 200;
lookat.set(position);
lookat.x += distance*direction;
lookat.z += distance*direction;
lookat.y = terrain.getY(lookat.x, lookat.z) + 200;
viewT.lookAt(new Point3f(position),new Point3f(lookat),new Point3f(0,1,0));
// System.out.println("position = "+position);
view.setTransform(viewT);
if (lastUpdate.distance(position)>200) {
terrainShape.rebuild(view);
lastUpdate.set(position);
}
view.renderOnce();
try
{
Thread.sleep(10L);
}
catch (Exception e)
{
}
angle += 0.005f;
testRotateY.rotY(angle);
testRotateYGroup.setTransform(testRotateY);
}
}
/**
* The following class is used to supply height sampling information to
* the terrain manager.
*/
class TerrainGenerator implements TerrainSampleInterface {
int scale;
Perlin2 perlin;
public TerrainGenerator() {
perlin = new Perlin2(Perlin2.METHOD_BASIC,0.5,2,2,1,0,new Noise());
scale = 3;
}
public int getScale() {
return scale;
}
public float sample(int x, int z) {
return (float)(perlin.value((float)x/1400f,(float)z/1400f)+1f)*MAX_HEIGHT;
}
public float getXOrg() {
return 0;
}
public float getZOrg() {
return 0;
}
public int getXDim() {
return 4000;
}
public int getZDim() {
return 4000;
}
}
class TestWindow extends UIWindow {
public TestWindow(int width, int height) {
super(width, height, false, false );
setRoot(buildGUI(width,height));
}
private JComponent buildGUI (int width, int height) {
JPanel p = new JPanel();
p.setDoubleBuffered(true);
p.setSize(new Dimension(width,height));
p.setLocation(0,0);
p.setBackground(Color.darkGray);
final JToggleButton lightButton = new JToggleButton();
lightButton.setText("Lines");
lightButton.setMargin(new Insets(0,0,0,0));
lightButton.setPreferredSize(new Dimension(90,25));
lightButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
if (lightButton.isSelected()) {
terrainShape.setLineMode(true);
lightButton.setText("Fill");
} else {
terrainShape.setLineMode(false);
lightButton.setText("Lines");
}
}
});
p.add(lightButton);
JButton exitButton = new JButton();
exitButton.setPreferredSize(new Dimension(80,25));
exitButton.setText("Exit");
exitButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
p.add(exitButton);
final JScrollBar progress = new JScrollBar(JScrollBar.HORIZONTAL,(int)speed,1,1,10);
progress.setPreferredSize(new Dimension(80,25));
progress.addAdjustmentListener(new AdjustmentListener() {
public void adjustmentValueChanged(AdjustmentEvent e) {
speed = progress.getValue();
}
});
p.add(progress);
return p;
}
}
public static void main(String[] args)
{
System.out.println("Hit SPACE to toggle projection policy, or ESC to exit");
try
{
Xith3DTerrainTest test = new Xith3DTerrainTest();
test.init();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
Total 634 Lines of Code.
|
Source code formatted using showsrc by William Denniss
|