diff options
author | neothemachine <[email protected]> | 2013-02-21 16:40:08 +0100 |
---|---|---|
committer | neothemachine <[email protected]> | 2013-02-21 16:40:08 +0100 |
commit | f774bd917e9dfd8cf46e5ed66d41aad64477a238 (patch) | |
tree | 8d33aa0cf24165710d420c677f3336641223cff8 /ardor3d-terrain/src/main | |
parent | edbc5c757c66d56eb2cffffa4076f0f2bfd6e748 (diff) |
normalized line endings
see
http://www.hanselman.com/blog/YoureJustAnotherCarriageReturnLineFeedInTheWall.aspx
and https://help.github.com/articles/dealing-with-line-endings
Diffstat (limited to 'ardor3d-terrain/src/main')
26 files changed, 4392 insertions, 4392 deletions
diff --git a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/client/ClipmapLevel.java b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/client/ClipmapLevel.java index 6817b5e..1c48584 100644 --- a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/client/ClipmapLevel.java +++ b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/client/ClipmapLevel.java @@ -1,630 +1,630 @@ -/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.terrain.client;
-
-import java.nio.FloatBuffer;
-import java.util.Set;
-
-import com.ardor3d.bounding.BoundingBox;
-import com.ardor3d.extension.terrain.util.Region;
-import com.ardor3d.extension.terrain.util.Tile;
-import com.ardor3d.math.MathUtils;
-import com.ardor3d.math.Vector3;
-import com.ardor3d.renderer.Camera;
-import com.ardor3d.renderer.Camera.FrustumIntersect;
-import com.ardor3d.renderer.IndexMode;
-import com.ardor3d.scenegraph.FloatBufferData;
-import com.ardor3d.scenegraph.IndexBufferData;
-import com.ardor3d.scenegraph.Mesh;
-import com.ardor3d.scenegraph.event.DirtyType;
-import com.ardor3d.util.geom.BufferUtils;
-
-/**
- * ClipmapLevel is the visual representation of one lod level of height data.
- */
-public class ClipmapLevel extends Mesh {
-
- /**
- * Precalculated useful variables.
- */
- private final int doubleVertexDistance; // vertexDistance * 2;
- private final int frameDistance; // (frameSize - 1) * vertexDistance
-
- /**
- * Gets the distance between two horizontal/vertical vertices. The finest level L = 0 has a distance of
- * vertexDistance = 1. Then every level it doubles so vertexDistance is always 2^L
- */
- private final int vertexDistance;
-
- /**
- * Gets framesize in number of vertices between outer border of current clip and outer border of next finer (inner)
- * clip.
- */
- private final int frameSize;
-
- /**
- * Gets the width of a clip in number of vertices. This is always one less than power of two (2^x - 1)
- */
- private final int clipSideSize;
-
- /**
- * Gets the region of the current clip.
- */
- private final Region clipRegion;
- private final Region intersectionRegion;
-
- /**
- * Value that indicates the height scaling. It is also represents the maximum terrain height.
- */
- private final float heightScale;
-
- private float heightRangeMin = 0.0f;
- private float heightRangeMax = 1.0f;
-
- /**
- * Index to indicate how much vertices are added to the triangle strip.
- */
- private int stripIndex = 0;
-
- /**
- * The used terrain heightfield. This must be set per reference so all clip levels share the same memory for that
- * variable. The values are between 0.0f and 1.0f
- */
- private final TerrainCache cache;
-
- /**
- * Number of components for vertices
- */
- public static final int VERT_SIZE = 4;
-
- /**
- * Camera frustum to test clipmap tiles against for culling
- */
- private final Camera clipmapTestFrustum;
-
- /**
- * Used to handle transformations of the terrain
- */
- private final Vector3 transformedFrustumPos = new Vector3();
-
- /**
- * Should the clipmap generate per vertex normals
- */
- private final boolean generateNormals = false;
-
- /**
- * Bounding box used for culling
- */
- private final BoundingBox frustumCheckBounds = new BoundingBox();
-
- /**
- * Possible nio speedup when storing indices
- */
- private int[] tmpIndices;
-
- /**
- * Should cull blocks outside camera frustum
- */
- private boolean cullingEnabled = true;
-
- /**
- * Creates a new clipmaplevel.
- *
- * @param levelIndex
- * Levelindex of the clipmap. If is 0 this will be the finest level
- * @param clipSideSize
- * Number of vertices per clipside. Must be one less than power of two.
- * @param heightScale
- * Maximum terrainheight and heightscale
- * @param fieldsize
- * Width and heightvalue of the heightfield
- * @param heightfield
- * Heightvalues with a range of 0.0f - 1.0f
- * @exception Exception
- */
- public ClipmapLevel(final int levelIndex, final Camera clipmapTestFrustum, final int clipSideSize,
- final float heightScale, final TerrainCache cache) throws Exception {
- super("Clipmap Level " + levelIndex);
-
- // Check some exception cases
- if (levelIndex < 0) {
- throw new Exception("levelIndex must be positive");
- }
- if (!MathUtils.isPowerOfTwo(clipSideSize + 1)) {
- throw new Exception("clipSideSize must be one less than power of two");
- }
-
- // Apply the values
- this.clipmapTestFrustum = clipmapTestFrustum;
- this.cache = cache;
-
- this.heightScale = heightScale;
- this.clipSideSize = clipSideSize;
-
- // Calculate common variables
- vertexDistance = (int) Math.pow(2, levelIndex);
- frameSize = (clipSideSize + 1) / 4;
- doubleVertexDistance = vertexDistance * 2;
- frameDistance = (frameSize - 1) * vertexDistance;
- clipRegion = new Region(0, 0, (clipSideSize - 1) * vertexDistance, (clipSideSize - 1) * vertexDistance);
- intersectionRegion = new Region(0, 0, clipSideSize * vertexDistance, clipSideSize * vertexDistance);
-
- // Initialize the vertices
- initialize();
- }
-
- /**
- * Initializes the vertices and indices.
- */
- private void initialize() {
- getMeshData().setIndexMode(IndexMode.TriangleStrip);
-
- // clipSideSize is the number of vertices per clipmapside, so number of all vertices is clipSideSize *
- // clipSideSize
- final FloatBuffer vertices = BufferUtils.createVector4Buffer(clipSideSize * clipSideSize);
- getMeshData().setVertexCoords(new FloatBufferData(vertices, 4));
-
- if (generateNormals) {
- final FloatBuffer normals = BufferUtils.createVector3Buffer(clipSideSize * clipSideSize);
- getMeshData().setNormalCoords(new FloatBufferData(normals, 3));
- }
-
- // final FloatBuffer textureCoords = BufferUtils.createVector2Buffer(N * N);
- // getMeshData().setTextureBuffer(textureCoords, 0);
-
- final int indicesSize = 4 * (3 * frameSize * frameSize + clipSideSize * clipSideSize / 2 + 4 * frameSize - 10);
- final IndexBufferData<?> indices = BufferUtils.createIndexBufferData(indicesSize, vertices.capacity() - 1);
- tmpIndices = new int[indicesSize];
- getMeshData().setIndices(indices);
-
- // Go through all rows and fill them with vertexindices.
- for (int z = 0; z < clipSideSize - 1; z++) {
- fillRow(0, clipSideSize - 1, z, z + 1);
- }
- }
-
- public void updateCache() {
- getWorldTransform().applyInverse(clipmapTestFrustum.getLocation(), transformedFrustumPos);
- final int cx = (int) transformedFrustumPos.getX();
- final int cz = (int) transformedFrustumPos.getZ();
-
- // Calculate the new position
- int clipX = cx - (clipSideSize + 1) * vertexDistance / 2;
- int clipY = cz - (clipSideSize + 1) * vertexDistance / 2;
-
- // Calculate the modulo to doubleVertexDistance of the new position.
- // This makes sure that the current level always fits in the hole of the
- // coarser level. The gridspacing of the coarser level is vertexDistance * 2, so here doubleVertexDistance.
- final int modX = MathUtils.moduloPositive(clipX, doubleVertexDistance);
- final int modY = MathUtils.moduloPositive(clipY, doubleVertexDistance);
- clipX = clipX + doubleVertexDistance - modX;
- clipY = clipY + doubleVertexDistance - modY;
-
- cache.setCurrentPosition(clipX / vertexDistance, clipY / vertexDistance);
-
- // TODO
- cache.handleUpdateRequests();
- }
-
- /**
- * Update clipmap vertices
- *
- * @param center
- */
- public void updateVertices() {
- getWorldTransform().applyInverse(clipmapTestFrustum.getLocation(), transformedFrustumPos);
- final int cx = (int) transformedFrustumPos.getX();
- final int cz = (int) transformedFrustumPos.getZ();
-
- // Store the old position to be able to recover it if needed
- final int oldX = clipRegion.getX();
- final int oldZ = clipRegion.getY();
-
- // Calculate the new position
- clipRegion.setX(cx - (clipSideSize + 1) * vertexDistance / 2);
- clipRegion.setY(cz - (clipSideSize + 1) * vertexDistance / 2);
-
- // Calculate the modulo to doubleVertexDistance of the new position.
- // This makes sure that the current level always fits in the hole of the
- // coarser level. The gridspacing of the coarser level is vertexDistance * 2, so here doubleVertexDistance.
- final int modX = MathUtils.moduloPositive(clipRegion.getX(), doubleVertexDistance);
- final int modY = MathUtils.moduloPositive(clipRegion.getY(), doubleVertexDistance);
- clipRegion.setX(clipRegion.getX() + doubleVertexDistance - modX);
- clipRegion.setY(clipRegion.getY() + doubleVertexDistance - modY);
-
- // Calculate the moving distance
- final int dx = clipRegion.getX() - oldX;
- final int dz = clipRegion.getY() - oldZ;
-
- intersectionRegion.setX(clipRegion.getX());
- intersectionRegion.setY(clipRegion.getY());
-
- cache.setCurrentPosition(clipRegion.getX() / vertexDistance, clipRegion.getY() / vertexDistance);
-
- updateVertices(dx, dz);
-
- final Set<Tile> updatedTiles = cache.handleUpdateRequests();
- if (updatedTiles != null) {
- // TODO: only update what's changed
- regenerate();
- }
- }
-
- public void regenerate() {
- updateVertices(clipRegion.getWidth(), clipRegion.getHeight());
- }
-
- /**
- *
- * @param cx
- * @param cz
- */
- private void updateVertices(int dx, int dz) {
- if (dx == 0 && dz == 0) {
- return;
- }
-
- dx = MathUtils.clamp(dx, -clipSideSize + 1, clipSideSize - 1);
- dz = MathUtils.clamp(dz, -clipSideSize + 1, clipSideSize - 1);
-
- // Create some better readable variables.
- // This are just the bounds of the current level (the new region).
- final int xmin = clipRegion.getLeft() / vertexDistance;
- final int xmax = clipRegion.getRight() / vertexDistance;
- final int zmin = clipRegion.getTop() / vertexDistance;
- final int zmax = clipRegion.getBottom() / vertexDistance;
-
- final FloatBuffer vertices = getMeshData().getVertexBuffer();
-
- // Update the L shaped region.
- // This replaces the old data with the new one.
- if (dz > 0) {
- if (dx > 0) {
- cache.updateRegion(vertices, xmax - dx, zmin, dx + 1, zmax - zmin - dz + 1);
- } else if (dx < 0) {
- cache.updateRegion(vertices, xmin, zmin, -dx + 1, zmax - zmin - dz + 1);
- }
-
- cache.updateRegion(vertices, xmin, zmax - dz, xmax - xmin + 1, dz + 1);
- } else {
- if (dx > 0) {
- cache.updateRegion(vertices, xmax - dx, zmin - dz, dx + 1, zmax - zmin + dz + 1);
- } else if (dx < 0) {
- cache.updateRegion(vertices, xmin, zmin - dz, -dx + 1, zmax - zmin + dz + 1);
- }
-
- if (dz < 0) {
- cache.updateRegion(vertices, xmin, zmin, xmax - xmin + 1, -dz + 1);
- }
- }
- markDirty(DirtyType.Bounding);
- }
-
- /**
- * Updates the whole indexarray.
- *
- * @param nextFinerLevel
- * @param frustum
- */
- public void updateIndices(final ClipmapLevel nextFinerLevel) {
- // set the stripindex to zero. We start count vertices from here.
- // The stripindex will tell us how much of the array is used.
- stripIndex = 0;
-
- // MxM Block 1
- fillBlock(clipRegion.getLeft(), clipRegion.getLeft() + frameDistance, clipRegion.getTop(), clipRegion.getTop()
- + frameDistance);
-
- // MxM Block 2
- fillBlock(clipRegion.getLeft() + frameDistance, clipRegion.getLeft() + 2 * frameDistance, clipRegion.getTop(),
- clipRegion.getTop() + frameDistance);
-
- // MxM Block 3
- fillBlock(clipRegion.getRight() - 2 * frameDistance, clipRegion.getRight() - frameDistance,
- clipRegion.getTop(), clipRegion.getTop() + frameDistance);
-
- // MxM Block 4
- fillBlock(clipRegion.getRight() - frameDistance, clipRegion.getRight(), clipRegion.getTop(),
- clipRegion.getTop() + frameDistance);
-
- // MxM Block 5
- fillBlock(clipRegion.getLeft(), clipRegion.getLeft() + frameDistance, clipRegion.getTop() + frameDistance,
- clipRegion.getTop() + 2 * frameDistance);
-
- // MxM Block 6
- fillBlock(clipRegion.getRight() - frameDistance, clipRegion.getRight(), clipRegion.getTop() + frameDistance,
- clipRegion.getTop() + 2 * frameDistance);
-
- // MxM Block 7
- fillBlock(clipRegion.getLeft(), clipRegion.getLeft() + frameDistance, clipRegion.getBottom() - 2
- * frameDistance, clipRegion.getBottom() - frameDistance);
-
- // MxM Block 8
- fillBlock(clipRegion.getRight() - frameDistance, clipRegion.getRight(), clipRegion.getBottom() - 2
- * frameDistance, clipRegion.getBottom() - frameDistance);
-
- // MxM Block 9
- fillBlock(clipRegion.getLeft(), clipRegion.getLeft() + frameDistance, clipRegion.getBottom() - frameDistance,
- clipRegion.getBottom());
-
- // MxM Block 10
- fillBlock(clipRegion.getLeft() + frameDistance, clipRegion.getLeft() + 2 * frameDistance,
- clipRegion.getBottom() - frameDistance, clipRegion.getBottom());
-
- // MxM Block 11
- fillBlock(clipRegion.getRight() - 2 * frameDistance, clipRegion.getRight() - frameDistance,
- clipRegion.getBottom() - frameDistance, clipRegion.getBottom());
-
- // MxM Block 12
- fillBlock(clipRegion.getRight() - frameDistance, clipRegion.getRight(), clipRegion.getBottom() - frameDistance,
- clipRegion.getBottom());
-
- // Fixup Top
- fillBlock(clipRegion.getLeft() + 2 * frameDistance, clipRegion.getLeft() + 2 * frameDistance
- + doubleVertexDistance, clipRegion.getTop(), clipRegion.getTop() + frameDistance);
-
- // Fixup Left
- fillBlock(clipRegion.getLeft(), clipRegion.getLeft() + frameDistance, clipRegion.getTop() + 2 * frameDistance,
- clipRegion.getTop() + 2 * frameDistance + doubleVertexDistance);
-
- // Fixup Right
- fillBlock(clipRegion.getRight() - frameDistance, clipRegion.getRight(),
- clipRegion.getTop() + 2 * frameDistance, clipRegion.getTop() + 2 * frameDistance + doubleVertexDistance);
-
- // Fixup Bottom
- fillBlock(clipRegion.getLeft() + 2 * frameDistance, clipRegion.getLeft() + 2 * frameDistance
- + doubleVertexDistance, clipRegion.getBottom() - frameDistance, clipRegion.getBottom());
-
- if (nextFinerLevel != null) {
- if ((nextFinerLevel.clipRegion.getX() - clipRegion.getX()) / vertexDistance == frameSize) {
- if ((nextFinerLevel.clipRegion.getY() - clipRegion.getY()) / vertexDistance == frameSize) {
- // Upper Left L Shape
-
- // Up
- fillBlock(clipRegion.getLeft() + frameDistance, clipRegion.getRight() - frameDistance,
- clipRegion.getTop() + frameDistance, clipRegion.getTop() + frameDistance + vertexDistance);
- // Left
- fillBlock(clipRegion.getLeft() + frameDistance, clipRegion.getLeft() + frameDistance
- + vertexDistance, clipRegion.getTop() + frameDistance + vertexDistance,
- clipRegion.getBottom() - frameDistance);
- } else {
- // Lower Left L Shape
-
- // Left
- fillBlock(clipRegion.getLeft() + frameDistance, clipRegion.getLeft() + frameDistance
- + vertexDistance, clipRegion.getTop() + frameDistance, clipRegion.getBottom()
- - frameDistance - vertexDistance);
-
- // Bottom
- fillBlock(clipRegion.getLeft() + frameDistance, clipRegion.getRight() - frameDistance,
- clipRegion.getBottom() - frameDistance - vertexDistance, clipRegion.getBottom()
- - frameDistance);
- }
- } else {
- if ((nextFinerLevel.clipRegion.getY() - clipRegion.getY()) / vertexDistance == frameSize) {
- // Upper Right L Shape
-
- // Up
- fillBlock(clipRegion.getLeft() + frameDistance, clipRegion.getRight() - frameDistance,
- clipRegion.getTop() + frameDistance, clipRegion.getTop() + frameDistance + vertexDistance);
- // Right
- fillBlock(clipRegion.getRight() - frameDistance - vertexDistance, clipRegion.getRight()
- - frameDistance, clipRegion.getTop() + frameDistance + vertexDistance,
- clipRegion.getBottom() - frameDistance);
- } else {
- // Lower Right L Shape
-
- // Right
- fillBlock(clipRegion.getRight() - frameDistance - vertexDistance, clipRegion.getRight()
- - frameDistance, clipRegion.getTop() + frameDistance, clipRegion.getBottom()
- - frameDistance - vertexDistance);
-
- // Bottom
- fillBlock(clipRegion.getLeft() + frameDistance, clipRegion.getRight() - frameDistance,
- clipRegion.getBottom() - frameDistance - vertexDistance, clipRegion.getBottom()
- - frameDistance);
- }
- }
- }
-
- // Fill in the middle patch if most detailed layer
- if (nextFinerLevel == null) {
- fillBlock(clipRegion.getLeft() + frameDistance, clipRegion.getLeft() + frameDistance + clipSideSize / 2,
- clipRegion.getTop() + frameDistance, clipRegion.getTop() + frameDistance + clipSideSize / 2);
-
- fillBlock(clipRegion.getLeft() + frameDistance + clipSideSize / 2, clipRegion.getRight() - frameDistance,
- clipRegion.getTop() + frameDistance, clipRegion.getTop() + frameDistance + clipSideSize / 2);
-
- fillBlock(clipRegion.getLeft() + frameDistance, clipRegion.getLeft() + frameDistance + clipSideSize / 2,
- clipRegion.getTop() + frameDistance + clipSideSize / 2, clipRegion.getBottom() - frameDistance);
-
- fillBlock(clipRegion.getLeft() + frameDistance + clipSideSize / 2, clipRegion.getRight() - frameDistance,
- clipRegion.getTop() + frameDistance + clipSideSize / 2, clipRegion.getBottom() - frameDistance);
- }
-
- final IndexBufferData<?> indices = getMeshData().getIndices();
- indices.clear();
- indices.put(tmpIndices, 0, getStripIndex());
- indices.flip();
- }
-
- /**
- * Fills a specified area to indexarray. This will be added only after a bounding test pass.
- *
- * @param left
- * @param right
- * @param top
- * @param bottom
- */
- private void fillBlock(int left, int right, int top, int bottom) {
- if (cullingEnabled) {
- // Setup the boundingbox of the block to fill.
- // The lowest value is zero, the highest is the scalesize.
- frustumCheckBounds.setCenter((left + right) * 0.5, (heightRangeMax + heightRangeMin) * heightScale * 0.5,
- (top + bottom) * 0.5);
- frustumCheckBounds.setXExtent((left - right) * 0.5);
- frustumCheckBounds.setYExtent((heightRangeMax - heightRangeMin) * heightScale * 0.5);
- frustumCheckBounds.setZExtent((top - bottom) * 0.5);
-
- frustumCheckBounds.transform(getWorldTransform(), frustumCheckBounds);
-
- final int state = clipmapTestFrustum.getPlaneState();
-
- final boolean isVisible = clipmapTestFrustum.contains(frustumCheckBounds) != FrustumIntersect.Outside;
- clipmapTestFrustum.setPlaneState(state);
-
- if (!isVisible) {
- return;
- }
- }
-
- // Same moduloprocedure as when we updated the vertices.
- // Maps the terrainposition to arrayposition.
- left = left / vertexDistance % clipSideSize;
- right = right / vertexDistance % clipSideSize;
- top = top / vertexDistance % clipSideSize;
- bottom = bottom / vertexDistance % clipSideSize;
- left += left < 0 ? clipSideSize : 0;
- right += right < 0 ? clipSideSize : 0;
- top += top < 0 ? clipSideSize : 0;
- bottom += bottom < 0 ? clipSideSize : 0;
-
- // Now fill the block.
- if (bottom < top) {
- // Bottom border is positioned somwhere over the top border,
- // we have a wrapover so we must split up the update in two parts.
-
- // Go from top border to the end of the array and update every row
- for (int z = top; z <= clipSideSize - 2; z++) {
- fillRow(left, right, z, z + 1);
- }
-
- // Update the wrapover row
- fillRow(left, right, clipSideSize - 1, 0);
-
- // Go from arraystart to the bottom border and update every row.
- for (int z = 0; z <= bottom - 1; z++) {
- fillRow(left, right, z, z + 1);
- }
- } else {
- // Top border is over the bottom border. Update from top to bottom.
- for (int z = top; z <= bottom - 1; z++) {
- fillRow(left, right, z, z + 1);
- }
- }
- }
-
- /**
- * Fills a strip of triangles that can be build between vertices row Zn and Zn1.
- *
- * @param startX
- * Start x-coordinate
- * @param endX
- * End x-coordinate
- * @param rowZ
- * Row n
- * @param rowZPlus1
- * Row n + 1
- */
- private void fillRow(final int startX, final int endX, final int rowZ, final int rowZPlus1) {
- addIndex(startX, rowZPlus1);
- if (startX <= endX) {
- for (int x = startX; x <= endX; x++) {
- addIndex(x, rowZPlus1);
- addIndex(x, rowZ);
- }
- } else {
- for (int x = startX; x <= clipSideSize - 1; x++) {
- addIndex(x, rowZPlus1);
- addIndex(x, rowZ);
- }
- for (int x = 0; x <= endX; x++) {
- addIndex(x, rowZPlus1);
- addIndex(x, rowZ);
- }
- }
- addIndex(endX, rowZ);
- }
-
- /**
- * Adds a specific index to indexarray.
- *
- * @param x
- * @param z
- */
- private void addIndex(final int x, final int z) {
- // add the index and increment counter.
- tmpIndices[stripIndex++] = x + z * clipSideSize;
- }
-
- /**
- * Gets the number of triangles that are visible in current frame. This changes every frame.
- */
- public int getStripIndex() {
- return stripIndex;
- }
-
- /**
- * @return the vertexDistance
- */
- public int getVertexDistance() {
- return vertexDistance;
- }
-
- public boolean isReady() {
- return cache.isValid();
- }
-
- public TerrainCache getCache() {
- return cache;
- }
-
- public void setHeightRange(final float heightRangeMin, final float heightRangeMax) {
- this.heightRangeMin = heightRangeMin;
- this.heightRangeMax = heightRangeMax;
- }
-
- public float getHeightRangeMax() {
- return heightRangeMax;
- }
-
- public float getHeightRangeMin() {
- return heightRangeMin;
- }
-
- public int getClipSideSize() {
- return clipSideSize;
- }
-
- public Region getClipRegion() {
- return clipRegion;
- }
-
- public Region getIntersectionRegion() {
- return intersectionRegion;
- }
-
- public float getHeightScale() {
- return heightScale;
- }
-
- public boolean isCullingEnabled() {
- return cullingEnabled;
- }
-
- public void setCullingEnabled(final boolean cullingEnabled) {
- this.cullingEnabled = cullingEnabled;
- }
-
- public void shutdown() {
- cache.shutdown();
- }
+/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.terrain.client; + +import java.nio.FloatBuffer; +import java.util.Set; + +import com.ardor3d.bounding.BoundingBox; +import com.ardor3d.extension.terrain.util.Region; +import com.ardor3d.extension.terrain.util.Tile; +import com.ardor3d.math.MathUtils; +import com.ardor3d.math.Vector3; +import com.ardor3d.renderer.Camera; +import com.ardor3d.renderer.Camera.FrustumIntersect; +import com.ardor3d.renderer.IndexMode; +import com.ardor3d.scenegraph.FloatBufferData; +import com.ardor3d.scenegraph.IndexBufferData; +import com.ardor3d.scenegraph.Mesh; +import com.ardor3d.scenegraph.event.DirtyType; +import com.ardor3d.util.geom.BufferUtils; + +/** + * ClipmapLevel is the visual representation of one lod level of height data. + */ +public class ClipmapLevel extends Mesh { + + /** + * Precalculated useful variables. + */ + private final int doubleVertexDistance; // vertexDistance * 2; + private final int frameDistance; // (frameSize - 1) * vertexDistance + + /** + * Gets the distance between two horizontal/vertical vertices. The finest level L = 0 has a distance of + * vertexDistance = 1. Then every level it doubles so vertexDistance is always 2^L + */ + private final int vertexDistance; + + /** + * Gets framesize in number of vertices between outer border of current clip and outer border of next finer (inner) + * clip. + */ + private final int frameSize; + + /** + * Gets the width of a clip in number of vertices. This is always one less than power of two (2^x - 1) + */ + private final int clipSideSize; + + /** + * Gets the region of the current clip. + */ + private final Region clipRegion; + private final Region intersectionRegion; + + /** + * Value that indicates the height scaling. It is also represents the maximum terrain height. + */ + private final float heightScale; + + private float heightRangeMin = 0.0f; + private float heightRangeMax = 1.0f; + + /** + * Index to indicate how much vertices are added to the triangle strip. + */ + private int stripIndex = 0; + + /** + * The used terrain heightfield. This must be set per reference so all clip levels share the same memory for that + * variable. The values are between 0.0f and 1.0f + */ + private final TerrainCache cache; + + /** + * Number of components for vertices + */ + public static final int VERT_SIZE = 4; + + /** + * Camera frustum to test clipmap tiles against for culling + */ + private final Camera clipmapTestFrustum; + + /** + * Used to handle transformations of the terrain + */ + private final Vector3 transformedFrustumPos = new Vector3(); + + /** + * Should the clipmap generate per vertex normals + */ + private final boolean generateNormals = false; + + /** + * Bounding box used for culling + */ + private final BoundingBox frustumCheckBounds = new BoundingBox(); + + /** + * Possible nio speedup when storing indices + */ + private int[] tmpIndices; + + /** + * Should cull blocks outside camera frustum + */ + private boolean cullingEnabled = true; + + /** + * Creates a new clipmaplevel. + * + * @param levelIndex + * Levelindex of the clipmap. If is 0 this will be the finest level + * @param clipSideSize + * Number of vertices per clipside. Must be one less than power of two. + * @param heightScale + * Maximum terrainheight and heightscale + * @param fieldsize + * Width and heightvalue of the heightfield + * @param heightfield + * Heightvalues with a range of 0.0f - 1.0f + * @exception Exception + */ + public ClipmapLevel(final int levelIndex, final Camera clipmapTestFrustum, final int clipSideSize, + final float heightScale, final TerrainCache cache) throws Exception { + super("Clipmap Level " + levelIndex); + + // Check some exception cases + if (levelIndex < 0) { + throw new Exception("levelIndex must be positive"); + } + if (!MathUtils.isPowerOfTwo(clipSideSize + 1)) { + throw new Exception("clipSideSize must be one less than power of two"); + } + + // Apply the values + this.clipmapTestFrustum = clipmapTestFrustum; + this.cache = cache; + + this.heightScale = heightScale; + this.clipSideSize = clipSideSize; + + // Calculate common variables + vertexDistance = (int) Math.pow(2, levelIndex); + frameSize = (clipSideSize + 1) / 4; + doubleVertexDistance = vertexDistance * 2; + frameDistance = (frameSize - 1) * vertexDistance; + clipRegion = new Region(0, 0, (clipSideSize - 1) * vertexDistance, (clipSideSize - 1) * vertexDistance); + intersectionRegion = new Region(0, 0, clipSideSize * vertexDistance, clipSideSize * vertexDistance); + + // Initialize the vertices + initialize(); + } + + /** + * Initializes the vertices and indices. + */ + private void initialize() { + getMeshData().setIndexMode(IndexMode.TriangleStrip); + + // clipSideSize is the number of vertices per clipmapside, so number of all vertices is clipSideSize * + // clipSideSize + final FloatBuffer vertices = BufferUtils.createVector4Buffer(clipSideSize * clipSideSize); + getMeshData().setVertexCoords(new FloatBufferData(vertices, 4)); + + if (generateNormals) { + final FloatBuffer normals = BufferUtils.createVector3Buffer(clipSideSize * clipSideSize); + getMeshData().setNormalCoords(new FloatBufferData(normals, 3)); + } + + // final FloatBuffer textureCoords = BufferUtils.createVector2Buffer(N * N); + // getMeshData().setTextureBuffer(textureCoords, 0); + + final int indicesSize = 4 * (3 * frameSize * frameSize + clipSideSize * clipSideSize / 2 + 4 * frameSize - 10); + final IndexBufferData<?> indices = BufferUtils.createIndexBufferData(indicesSize, vertices.capacity() - 1); + tmpIndices = new int[indicesSize]; + getMeshData().setIndices(indices); + + // Go through all rows and fill them with vertexindices. + for (int z = 0; z < clipSideSize - 1; z++) { + fillRow(0, clipSideSize - 1, z, z + 1); + } + } + + public void updateCache() { + getWorldTransform().applyInverse(clipmapTestFrustum.getLocation(), transformedFrustumPos); + final int cx = (int) transformedFrustumPos.getX(); + final int cz = (int) transformedFrustumPos.getZ(); + + // Calculate the new position + int clipX = cx - (clipSideSize + 1) * vertexDistance / 2; + int clipY = cz - (clipSideSize + 1) * vertexDistance / 2; + + // Calculate the modulo to doubleVertexDistance of the new position. + // This makes sure that the current level always fits in the hole of the + // coarser level. The gridspacing of the coarser level is vertexDistance * 2, so here doubleVertexDistance. + final int modX = MathUtils.moduloPositive(clipX, doubleVertexDistance); + final int modY = MathUtils.moduloPositive(clipY, doubleVertexDistance); + clipX = clipX + doubleVertexDistance - modX; + clipY = clipY + doubleVertexDistance - modY; + + cache.setCurrentPosition(clipX / vertexDistance, clipY / vertexDistance); + + // TODO + cache.handleUpdateRequests(); + } + + /** + * Update clipmap vertices + * + * @param center + */ + public void updateVertices() { + getWorldTransform().applyInverse(clipmapTestFrustum.getLocation(), transformedFrustumPos); + final int cx = (int) transformedFrustumPos.getX(); + final int cz = (int) transformedFrustumPos.getZ(); + + // Store the old position to be able to recover it if needed + final int oldX = clipRegion.getX(); + final int oldZ = clipRegion.getY(); + + // Calculate the new position + clipRegion.setX(cx - (clipSideSize + 1) * vertexDistance / 2); + clipRegion.setY(cz - (clipSideSize + 1) * vertexDistance / 2); + + // Calculate the modulo to doubleVertexDistance of the new position. + // This makes sure that the current level always fits in the hole of the + // coarser level. The gridspacing of the coarser level is vertexDistance * 2, so here doubleVertexDistance. + final int modX = MathUtils.moduloPositive(clipRegion.getX(), doubleVertexDistance); + final int modY = MathUtils.moduloPositive(clipRegion.getY(), doubleVertexDistance); + clipRegion.setX(clipRegion.getX() + doubleVertexDistance - modX); + clipRegion.setY(clipRegion.getY() + doubleVertexDistance - modY); + + // Calculate the moving distance + final int dx = clipRegion.getX() - oldX; + final int dz = clipRegion.getY() - oldZ; + + intersectionRegion.setX(clipRegion.getX()); + intersectionRegion.setY(clipRegion.getY()); + + cache.setCurrentPosition(clipRegion.getX() / vertexDistance, clipRegion.getY() / vertexDistance); + + updateVertices(dx, dz); + + final Set<Tile> updatedTiles = cache.handleUpdateRequests(); + if (updatedTiles != null) { + // TODO: only update what's changed + regenerate(); + } + } + + public void regenerate() { + updateVertices(clipRegion.getWidth(), clipRegion.getHeight()); + } + + /** + * + * @param cx + * @param cz + */ + private void updateVertices(int dx, int dz) { + if (dx == 0 && dz == 0) { + return; + } + + dx = MathUtils.clamp(dx, -clipSideSize + 1, clipSideSize - 1); + dz = MathUtils.clamp(dz, -clipSideSize + 1, clipSideSize - 1); + + // Create some better readable variables. + // This are just the bounds of the current level (the new region). + final int xmin = clipRegion.getLeft() / vertexDistance; + final int xmax = clipRegion.getRight() / vertexDistance; + final int zmin = clipRegion.getTop() / vertexDistance; + final int zmax = clipRegion.getBottom() / vertexDistance; + + final FloatBuffer vertices = getMeshData().getVertexBuffer(); + + // Update the L shaped region. + // This replaces the old data with the new one. + if (dz > 0) { + if (dx > 0) { + cache.updateRegion(vertices, xmax - dx, zmin, dx + 1, zmax - zmin - dz + 1); + } else if (dx < 0) { + cache.updateRegion(vertices, xmin, zmin, -dx + 1, zmax - zmin - dz + 1); + } + + cache.updateRegion(vertices, xmin, zmax - dz, xmax - xmin + 1, dz + 1); + } else { + if (dx > 0) { + cache.updateRegion(vertices, xmax - dx, zmin - dz, dx + 1, zmax - zmin + dz + 1); + } else if (dx < 0) { + cache.updateRegion(vertices, xmin, zmin - dz, -dx + 1, zmax - zmin + dz + 1); + } + + if (dz < 0) { + cache.updateRegion(vertices, xmin, zmin, xmax - xmin + 1, -dz + 1); + } + } + markDirty(DirtyType.Bounding); + } + + /** + * Updates the whole indexarray. + * + * @param nextFinerLevel + * @param frustum + */ + public void updateIndices(final ClipmapLevel nextFinerLevel) { + // set the stripindex to zero. We start count vertices from here. + // The stripindex will tell us how much of the array is used. + stripIndex = 0; + + // MxM Block 1 + fillBlock(clipRegion.getLeft(), clipRegion.getLeft() + frameDistance, clipRegion.getTop(), clipRegion.getTop() + + frameDistance); + + // MxM Block 2 + fillBlock(clipRegion.getLeft() + frameDistance, clipRegion.getLeft() + 2 * frameDistance, clipRegion.getTop(), + clipRegion.getTop() + frameDistance); + + // MxM Block 3 + fillBlock(clipRegion.getRight() - 2 * frameDistance, clipRegion.getRight() - frameDistance, + clipRegion.getTop(), clipRegion.getTop() + frameDistance); + + // MxM Block 4 + fillBlock(clipRegion.getRight() - frameDistance, clipRegion.getRight(), clipRegion.getTop(), + clipRegion.getTop() + frameDistance); + + // MxM Block 5 + fillBlock(clipRegion.getLeft(), clipRegion.getLeft() + frameDistance, clipRegion.getTop() + frameDistance, + clipRegion.getTop() + 2 * frameDistance); + + // MxM Block 6 + fillBlock(clipRegion.getRight() - frameDistance, clipRegion.getRight(), clipRegion.getTop() + frameDistance, + clipRegion.getTop() + 2 * frameDistance); + + // MxM Block 7 + fillBlock(clipRegion.getLeft(), clipRegion.getLeft() + frameDistance, clipRegion.getBottom() - 2 + * frameDistance, clipRegion.getBottom() - frameDistance); + + // MxM Block 8 + fillBlock(clipRegion.getRight() - frameDistance, clipRegion.getRight(), clipRegion.getBottom() - 2 + * frameDistance, clipRegion.getBottom() - frameDistance); + + // MxM Block 9 + fillBlock(clipRegion.getLeft(), clipRegion.getLeft() + frameDistance, clipRegion.getBottom() - frameDistance, + clipRegion.getBottom()); + + // MxM Block 10 + fillBlock(clipRegion.getLeft() + frameDistance, clipRegion.getLeft() + 2 * frameDistance, + clipRegion.getBottom() - frameDistance, clipRegion.getBottom()); + + // MxM Block 11 + fillBlock(clipRegion.getRight() - 2 * frameDistance, clipRegion.getRight() - frameDistance, + clipRegion.getBottom() - frameDistance, clipRegion.getBottom()); + + // MxM Block 12 + fillBlock(clipRegion.getRight() - frameDistance, clipRegion.getRight(), clipRegion.getBottom() - frameDistance, + clipRegion.getBottom()); + + // Fixup Top + fillBlock(clipRegion.getLeft() + 2 * frameDistance, clipRegion.getLeft() + 2 * frameDistance + + doubleVertexDistance, clipRegion.getTop(), clipRegion.getTop() + frameDistance); + + // Fixup Left + fillBlock(clipRegion.getLeft(), clipRegion.getLeft() + frameDistance, clipRegion.getTop() + 2 * frameDistance, + clipRegion.getTop() + 2 * frameDistance + doubleVertexDistance); + + // Fixup Right + fillBlock(clipRegion.getRight() - frameDistance, clipRegion.getRight(), + clipRegion.getTop() + 2 * frameDistance, clipRegion.getTop() + 2 * frameDistance + doubleVertexDistance); + + // Fixup Bottom + fillBlock(clipRegion.getLeft() + 2 * frameDistance, clipRegion.getLeft() + 2 * frameDistance + + doubleVertexDistance, clipRegion.getBottom() - frameDistance, clipRegion.getBottom()); + + if (nextFinerLevel != null) { + if ((nextFinerLevel.clipRegion.getX() - clipRegion.getX()) / vertexDistance == frameSize) { + if ((nextFinerLevel.clipRegion.getY() - clipRegion.getY()) / vertexDistance == frameSize) { + // Upper Left L Shape + + // Up + fillBlock(clipRegion.getLeft() + frameDistance, clipRegion.getRight() - frameDistance, + clipRegion.getTop() + frameDistance, clipRegion.getTop() + frameDistance + vertexDistance); + // Left + fillBlock(clipRegion.getLeft() + frameDistance, clipRegion.getLeft() + frameDistance + + vertexDistance, clipRegion.getTop() + frameDistance + vertexDistance, + clipRegion.getBottom() - frameDistance); + } else { + // Lower Left L Shape + + // Left + fillBlock(clipRegion.getLeft() + frameDistance, clipRegion.getLeft() + frameDistance + + vertexDistance, clipRegion.getTop() + frameDistance, clipRegion.getBottom() + - frameDistance - vertexDistance); + + // Bottom + fillBlock(clipRegion.getLeft() + frameDistance, clipRegion.getRight() - frameDistance, + clipRegion.getBottom() - frameDistance - vertexDistance, clipRegion.getBottom() + - frameDistance); + } + } else { + if ((nextFinerLevel.clipRegion.getY() - clipRegion.getY()) / vertexDistance == frameSize) { + // Upper Right L Shape + + // Up + fillBlock(clipRegion.getLeft() + frameDistance, clipRegion.getRight() - frameDistance, + clipRegion.getTop() + frameDistance, clipRegion.getTop() + frameDistance + vertexDistance); + // Right + fillBlock(clipRegion.getRight() - frameDistance - vertexDistance, clipRegion.getRight() + - frameDistance, clipRegion.getTop() + frameDistance + vertexDistance, + clipRegion.getBottom() - frameDistance); + } else { + // Lower Right L Shape + + // Right + fillBlock(clipRegion.getRight() - frameDistance - vertexDistance, clipRegion.getRight() + - frameDistance, clipRegion.getTop() + frameDistance, clipRegion.getBottom() + - frameDistance - vertexDistance); + + // Bottom + fillBlock(clipRegion.getLeft() + frameDistance, clipRegion.getRight() - frameDistance, + clipRegion.getBottom() - frameDistance - vertexDistance, clipRegion.getBottom() + - frameDistance); + } + } + } + + // Fill in the middle patch if most detailed layer + if (nextFinerLevel == null) { + fillBlock(clipRegion.getLeft() + frameDistance, clipRegion.getLeft() + frameDistance + clipSideSize / 2, + clipRegion.getTop() + frameDistance, clipRegion.getTop() + frameDistance + clipSideSize / 2); + + fillBlock(clipRegion.getLeft() + frameDistance + clipSideSize / 2, clipRegion.getRight() - frameDistance, + clipRegion.getTop() + frameDistance, clipRegion.getTop() + frameDistance + clipSideSize / 2); + + fillBlock(clipRegion.getLeft() + frameDistance, clipRegion.getLeft() + frameDistance + clipSideSize / 2, + clipRegion.getTop() + frameDistance + clipSideSize / 2, clipRegion.getBottom() - frameDistance); + + fillBlock(clipRegion.getLeft() + frameDistance + clipSideSize / 2, clipRegion.getRight() - frameDistance, + clipRegion.getTop() + frameDistance + clipSideSize / 2, clipRegion.getBottom() - frameDistance); + } + + final IndexBufferData<?> indices = getMeshData().getIndices(); + indices.clear(); + indices.put(tmpIndices, 0, getStripIndex()); + indices.flip(); + } + + /** + * Fills a specified area to indexarray. This will be added only after a bounding test pass. + * + * @param left + * @param right + * @param top + * @param bottom + */ + private void fillBlock(int left, int right, int top, int bottom) { + if (cullingEnabled) { + // Setup the boundingbox of the block to fill. + // The lowest value is zero, the highest is the scalesize. + frustumCheckBounds.setCenter((left + right) * 0.5, (heightRangeMax + heightRangeMin) * heightScale * 0.5, + (top + bottom) * 0.5); + frustumCheckBounds.setXExtent((left - right) * 0.5); + frustumCheckBounds.setYExtent((heightRangeMax - heightRangeMin) * heightScale * 0.5); + frustumCheckBounds.setZExtent((top - bottom) * 0.5); + + frustumCheckBounds.transform(getWorldTransform(), frustumCheckBounds); + + final int state = clipmapTestFrustum.getPlaneState(); + + final boolean isVisible = clipmapTestFrustum.contains(frustumCheckBounds) != FrustumIntersect.Outside; + clipmapTestFrustum.setPlaneState(state); + + if (!isVisible) { + return; + } + } + + // Same moduloprocedure as when we updated the vertices. + // Maps the terrainposition to arrayposition. + left = left / vertexDistance % clipSideSize; + right = right / vertexDistance % clipSideSize; + top = top / vertexDistance % clipSideSize; + bottom = bottom / vertexDistance % clipSideSize; + left += left < 0 ? clipSideSize : 0; + right += right < 0 ? clipSideSize : 0; + top += top < 0 ? clipSideSize : 0; + bottom += bottom < 0 ? clipSideSize : 0; + + // Now fill the block. + if (bottom < top) { + // Bottom border is positioned somwhere over the top border, + // we have a wrapover so we must split up the update in two parts. + + // Go from top border to the end of the array and update every row + for (int z = top; z <= clipSideSize - 2; z++) { + fillRow(left, right, z, z + 1); + } + + // Update the wrapover row + fillRow(left, right, clipSideSize - 1, 0); + + // Go from arraystart to the bottom border and update every row. + for (int z = 0; z <= bottom - 1; z++) { + fillRow(left, right, z, z + 1); + } + } else { + // Top border is over the bottom border. Update from top to bottom. + for (int z = top; z <= bottom - 1; z++) { + fillRow(left, right, z, z + 1); + } + } + } + + /** + * Fills a strip of triangles that can be build between vertices row Zn and Zn1. + * + * @param startX + * Start x-coordinate + * @param endX + * End x-coordinate + * @param rowZ + * Row n + * @param rowZPlus1 + * Row n + 1 + */ + private void fillRow(final int startX, final int endX, final int rowZ, final int rowZPlus1) { + addIndex(startX, rowZPlus1); + if (startX <= endX) { + for (int x = startX; x <= endX; x++) { + addIndex(x, rowZPlus1); + addIndex(x, rowZ); + } + } else { + for (int x = startX; x <= clipSideSize - 1; x++) { + addIndex(x, rowZPlus1); + addIndex(x, rowZ); + } + for (int x = 0; x <= endX; x++) { + addIndex(x, rowZPlus1); + addIndex(x, rowZ); + } + } + addIndex(endX, rowZ); + } + + /** + * Adds a specific index to indexarray. + * + * @param x + * @param z + */ + private void addIndex(final int x, final int z) { + // add the index and increment counter. + tmpIndices[stripIndex++] = x + z * clipSideSize; + } + + /** + * Gets the number of triangles that are visible in current frame. This changes every frame. + */ + public int getStripIndex() { + return stripIndex; + } + + /** + * @return the vertexDistance + */ + public int getVertexDistance() { + return vertexDistance; + } + + public boolean isReady() { + return cache.isValid(); + } + + public TerrainCache getCache() { + return cache; + } + + public void setHeightRange(final float heightRangeMin, final float heightRangeMax) { + this.heightRangeMin = heightRangeMin; + this.heightRangeMax = heightRangeMax; + } + + public float getHeightRangeMax() { + return heightRangeMax; + } + + public float getHeightRangeMin() { + return heightRangeMin; + } + + public int getClipSideSize() { + return clipSideSize; + } + + public Region getClipRegion() { + return clipRegion; + } + + public Region getIntersectionRegion() { + return intersectionRegion; + } + + public float getHeightScale() { + return heightScale; + } + + public boolean isCullingEnabled() { + return cullingEnabled; + } + + public void setCullingEnabled(final boolean cullingEnabled) { + this.cullingEnabled = cullingEnabled; + } + + public void shutdown() { + cache.shutdown(); + } }
\ No newline at end of file diff --git a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/client/Terrain.java b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/client/Terrain.java index 5da7e51..cad6281 100644 --- a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/client/Terrain.java +++ b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/client/Terrain.java @@ -1,712 +1,712 @@ -/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.terrain.client;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.FloatBuffer;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import com.ardor3d.bounding.BoundingBox;
-import com.ardor3d.extension.terrain.util.AbstractBresenhamTracer;
-import com.ardor3d.extension.terrain.util.ClipmapTerrainPicker;
-import com.ardor3d.extension.terrain.util.DoubleBufferedList;
-import com.ardor3d.extension.terrain.util.Region;
-import com.ardor3d.intersection.IntersectionRecord;
-import com.ardor3d.intersection.Pickable;
-import com.ardor3d.math.ColorRGBA;
-import com.ardor3d.math.MathUtils;
-import com.ardor3d.math.Ray3;
-import com.ardor3d.math.Vector3;
-import com.ardor3d.renderer.Camera;
-import com.ardor3d.renderer.ContextCapabilities;
-import com.ardor3d.renderer.ContextManager;
-import com.ardor3d.renderer.Renderer;
-import com.ardor3d.renderer.queue.RenderBucketType;
-import com.ardor3d.renderer.state.BlendState;
-import com.ardor3d.renderer.state.CullState;
-import com.ardor3d.renderer.state.GLSLShaderDataLogic;
-import com.ardor3d.renderer.state.GLSLShaderObjectsState;
-import com.ardor3d.renderer.state.MaterialState;
-import com.ardor3d.renderer.state.MaterialState.MaterialFace;
-import com.ardor3d.renderer.state.TextureState;
-import com.ardor3d.scenegraph.Mesh;
-import com.ardor3d.scenegraph.Node;
-import com.ardor3d.scenegraph.event.DirtyType;
-import com.ardor3d.scenegraph.hint.DataMode;
-import com.ardor3d.util.resource.ResourceLocatorTool;
-import com.google.common.collect.Lists;
-import com.google.common.io.InputSupplier;
-
-/**
- * An implementation of geometry clipmapping
- */
-public class Terrain extends Node implements Pickable {
- /** The Constant logger. */
- private static final Logger logger = Logger.getLogger(Terrain.class.getName());
-
- /** Our picker. */
- private ClipmapTerrainPicker _picker = null;
-
- private List<ClipmapLevel> _clips;
- private int _visibleLevels = 0;
- private int _minVisibleLevel = 0;
- private final Camera _terrainCamera;
- private final int _clipSideSize;
-
- private final BlendState blendState;
-
- private boolean _initialized = false;
-
- /** Shader for rendering clipmap geometry with morphing. */
- private GLSLShaderObjectsState _geometryClipmapShader;
-
- /** Reference to the texture clipmap */
- private final List<TextureClipmap> _textureClipmaps = Lists.newArrayList();
-
- /** Reference to normal map */
- private TextureClipmap _normalClipmap;
- private int _normalUnit = 5;
-
- private final Vector3 transformedFrustumPos = new Vector3();
-
- private final DoubleBufferedList<Region> mailBox = new DoubleBufferedList<Region>();
-
- private InputSupplier<? extends InputStream> vertexShader;
- private InputSupplier<? extends InputStream> pixelShader;
-
- /** Timers for mailbox updates */
- private long oldTime = 0;
- private long updateTimer = 0;
- private final long updateThreashold = 300;
-
- final TextureState clipTextureState = new TextureState();
-
- private final Comparator<Region> regionSorter = new Comparator<Region>() {
- @Override
- public int compare(final Region r1, final Region r2) {
- return r1.getLevel() - r2.getLevel();
- }
- };
-
- public Terrain(final Camera camera, final List<TerrainCache> cacheList, final int clipSideSize,
- final TerrainConfiguration terrainConfiguration) {
- _terrainCamera = camera;
- _clipSideSize = clipSideSize;
-
- _worldBound = new BoundingBox(Vector3.ZERO, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY,
- Double.POSITIVE_INFINITY);
-
- getSceneHints().setRenderBucketType(RenderBucketType.Opaque);
- final CullState cs = new CullState();
- cs.setEnabled(true);
- cs.setCullFace(CullState.Face.Back);
- setRenderState(cs);
-
- final MaterialState materialState = new MaterialState();
- materialState.setAmbient(MaterialFace.FrontAndBack, new ColorRGBA(1, 1, 1, 1));
- materialState.setDiffuse(MaterialFace.FrontAndBack, new ColorRGBA(1, 1, 1, 1));
- materialState.setSpecular(MaterialFace.FrontAndBack, new ColorRGBA(1, 1, 1, 1));
- materialState.setShininess(MaterialFace.FrontAndBack, 64.0f);
- setRenderState(materialState);
-
- blendState = new BlendState();
- blendState.setBlendEnabled(true);
- blendState.setSourceFunction(BlendState.SourceFunction.SourceAlpha);
- blendState.setDestinationFunction(BlendState.DestinationFunction.OneMinusSourceAlpha);
- setRenderState(blendState);
-
- // getSceneHints().setLightCombineMode(LightCombineMode.Off);
-
- try {
- _clips = new ArrayList<ClipmapLevel>();
-
- final float heightScale = terrainConfiguration.getScale().getYf();
-
- for (int i = 0; i < cacheList.size(); i++) {
- final TerrainCache cache = cacheList.get(i);
- cache.setMailBox(mailBox);
- final ClipmapLevel clipmap = new ClipmapLevel(i, camera, clipSideSize, heightScale, cache);
- _clips.add(clipmap);
- attachChild(clipmap);
-
- clipmap.getSceneHints().setDataMode(DataMode.Arrays);
-
- // clipmap.getSceneHints().setDataMode(DataMode.VBOInterleaved);
- // final FloatBufferData interleavedData = new FloatBufferData();
- // interleavedData.setVboAccessMode(VBOAccessMode.DynamicDraw);
- // clipmap.getMeshData().setInterleavedData(interleavedData);
-
- // clipmap.getSceneHints().setDataMode(DataMode.VBO);
- // clipmap.getMeshData().getVertexCoords().setVboAccessMode(VBOAccessMode.DynamicDraw);
- // clipmap.getMeshData().getIndices().setVboAccessMode(VBOAccessMode.DynamicDraw);
- }
- } catch (final Exception ex) {
- ex.printStackTrace();
- }
-
- vertexShader = new UrlInputSupplier(ResourceLocatorTool.getClassPathResource(Terrain.class,
- "com/ardor3d/extension/terrain/texturedGeometryClipmapShader.vert"));
- pixelShader = new UrlInputSupplier(ResourceLocatorTool.getClassPathResource(Terrain.class,
- "com/ardor3d/extension/terrain/texturedGeometryClipmapShader.frag"));
-
- // setScale(terrainConfiguration.getScale());
- // TODO: hack. unify scale handling over cache etc
- setScale(terrainConfiguration.getScale().getX(), 1, terrainConfiguration.getScale().getZ());
- setHeightRange(terrainConfiguration.getHeightRangeMin(), terrainConfiguration.getHeightRangeMax());
- }
-
- private final List<Long> timers = Lists.newArrayList();
-
- @Override
- protected void updateChildren(final double time) {
- super.updateChildren(time);
-
- for (int i = _minVisibleLevel; i < _clips.size(); i++) {
- if (_clips.get(i).isReady()) {
- _visibleLevels = i;
- break;
- }
- }
-
- // TODO: improve calcs for removing levels based on height above terrain
- // getWorldTransform().applyInverse(_terrainCamera.getLocation(), transformedFrustumPos);
- // final float heightRangeMax = 1f;
- // if (transformedFrustumPos.getYf() > heightRangeMax) {
- // final float diff = transformedFrustumPos.getYf() - heightRangeMax;
- // final float x = (float) (diff * Math.tan(Math.toRadians(30)));
- // for (int unit = _visibleLevels; unit < _clips.size(); unit++) {
- // final float heightTest = _clipSideSize * MathUtils.pow2(unit) / x;
- // if (heightTest > 1) {
- // _visibleLevels = unit;
- // break;
- // }
- // }
- // }
-
- if (timers.size() < _visibleLevels) {
- for (int unit = 0; unit < _visibleLevels; unit++) {
- timers.add(System.currentTimeMillis());
- }
- }
- for (int unit = 0; unit < _visibleLevels; unit++) {
- final long t = System.currentTimeMillis() - timers.get(unit);
- if (t > 500) {
- timers.set(unit, System.currentTimeMillis());
- _clips.get(unit).updateCache();
- }
- }
-
- // Update vertices.
- for (int i = _clips.size() - 1; i >= _visibleLevels; i--) {
- _clips.get(i).updateVertices();
- }
-
- // Update from mailbox
- updateFromMailbox();
-
- // Update indices.
- for (int i = _clips.size() - 1; i >= _visibleLevels; i--) {
- if (i == _visibleLevels) {
- // Level 0 has no nested level, so pass null as parameter.
- _clips.get(i).updateIndices(null);
- } else {
- // All other levels i have the level i-1 nested in.
- _clips.get(i).updateIndices(_clips.get(i - 1));
- }
- }
-
- for (int i = _clips.size() - 1; i >= _visibleLevels; i--) {
- _clips.get(i).getMeshData().getVertexCoords().setNeedsRefresh(true);
- _clips.get(i).getMeshData().getIndices().setNeedsRefresh(true);
- }
- }
-
- @Override
- public void draw(final Renderer r) {
- updateShader(r);
-
- boolean first = true;
- if (_normalClipmap != null) {
- clipTextureState.setTexture(_normalClipmap.getTexture(), _normalUnit);
- }
- for (final TextureClipmap textureClipmap : _textureClipmaps) {
- clipTextureState.setTexture(textureClipmap.getTexture());
- if (first) {
- blendState.setEnabled(false);
- first = false;
- } else {
- blendState.setEnabled(true);
- }
-
- if (_textureClipmaps.size() > 1) {
- r.getQueue().pushBuckets();
- }
-
- for (int i = _clips.size() - 1; i >= 0; i--) {
- final ClipmapLevel clip = _clips.get(i);
- clip.setRenderState(clipTextureState);
- }
-
- if (_textureClipmaps.size() > 1) {
- _geometryClipmapShader.setUniform("scale", 1f / textureClipmap.getScale());
- _geometryClipmapShader.setUniform("textureSize", (float) textureClipmap.getTextureSize());
- _geometryClipmapShader.setUniform("texelSize", 1f / textureClipmap.getTextureSize());
- _geometryClipmapShader.setUniform("levels", (float) textureClipmap.getTextureLevels());
- _geometryClipmapShader.setUniform("validLevels", (float) textureClipmap.getValidLevels() - 1);
- _geometryClipmapShader.setUniform("showDebug", textureClipmap.isShowDebug() ? 1.0f : 0.0f);
- _geometryClipmapShader.setNeedsRefresh(true);
- }
-
- blendState.setNeedsRefresh(true);
- this.updateWorldRenderStates(true);
-
- if (!_initialized) {
- for (int i = _clips.size() - 1; i >= _visibleLevels; i--) {
- final ClipmapLevel clip = _clips.get(i);
-
- clip.getMeshData().getIndices().limit(clip.getMeshData().getIndices().capacity());
- }
-
- _initialized = true;
- }
-
- // draw levels from coarse to fine.
- for (int i = _clips.size() - 1; i >= _visibleLevels; i--) {
- final ClipmapLevel clip = _clips.get(i);
-
- if (clip.getStripIndex() > 0) {
- clip.draw(r);
- }
- }
-
- if (_textureClipmaps.size() > 1) {
- r.renderBuckets();
- r.getQueue().popBuckets();
- }
- }
- }
-
- private void updateFromMailbox() {
- if (updateTimer > updateThreashold) {
- final List<Region> regionList = mailBox.switchAndGet();
- if (!regionList.isEmpty()) {
- for (int i = regionList.size() - 1; i >= 0; i--) {
- final Region region = regionList.get(i);
-
- final ClipmapLevel clip = _clips.get(region.getLevel());
- final Region clipRegion = clip.getIntersectionRegion();
-
- if (clipRegion.intersects(region)) {
- clipRegion.intersection(region);
- } else {
- regionList.remove(i);
- }
- }
-
- Collections.sort(regionList, regionSorter);
-
- final int start = regionList.size() - 1;
- for (int i = start; i >= 0; i--) {
- final Region region = regionList.get(i);
-
- recursiveAddUpdates(regionList, region.getLevel(), region.getX(), region.getY(), region.getWidth(),
- region.getHeight());
- }
-
- for (int i = regionList.size() - 1; i >= 0; i--) {
- final Region region = regionList.get(i);
-
- final ClipmapLevel clip = _clips.get(region.getLevel());
- final Region clipRegion = clip.getIntersectionRegion();
-
- if (clipRegion.intersects(region)) {
- clipRegion.intersection(region);
- } else {
- regionList.remove(i);
- }
- }
-
- Collections.sort(regionList, regionSorter);
-
- for (int i = regionList.size() - 1; i >= 0; i--) {
- final Region region = regionList.get(i);
- final ClipmapLevel clip = _clips.get(region.getLevel());
- final FloatBuffer vertices = clip.getMeshData().getVertexBuffer();
- final int vertexDistance = clip.getVertexDistance();
-
- clip.getCache().updateRegion(vertices, region.getX() / vertexDistance,
- region.getY() / vertexDistance, region.getWidth() / vertexDistance,
- region.getHeight() / vertexDistance);
- }
- }
- updateTimer %= updateThreashold;
- }
- final long time = System.currentTimeMillis();
- updateTimer += time - oldTime;
- oldTime = time;
- }
-
- private void recursiveAddUpdates(final List<Region> regionList, final int level, final int x, final int y,
- final int width, final int height) {
- if (level == 0) {
- return;
- }
-
- final Region region = new Region(level - 1, x, y, width, height);
- if (!regionList.contains(region)) {
- regionList.add(region);
- recursiveAddUpdates(regionList, region.getLevel(), region.getX(), region.getY(), region.getWidth(),
- region.getHeight());
- }
- }
-
- private final Vector3 _boundsCenter = new Vector3();
- private final Vector3 _boundsExtents = new Vector3();
-
- @Override
- public void updateWorldBound(final boolean recurse) {
- final BoundingBox worldBound = (BoundingBox) _worldBound;
- final Vector3 center = _boundsCenter.set(_terrainCamera.getLocation());
- final double distanceToEdge = _clipSideSize * MathUtils.pow2(_clips.size() - 1) * 0.5;
- final double heightScale = _clips.get(0).getHeightScale();
- final double heightMin = _clips.get(0).getHeightRangeMin() * heightScale;
- final double heightMax = _clips.get(0).getHeightRangeMax() * heightScale;
-
- final Vector3 extents = _boundsExtents.set(distanceToEdge, (heightMax - heightMin) * 0.5, distanceToEdge);
- worldToLocal(center, center);
- worldBound.setXExtent(extents.getX());
- worldBound.setYExtent(extents.getY());
- worldBound.setZExtent(extents.getZ());
- worldBound.setCenter(center.getX(), (heightMax + heightMin) * 0.5, center.getZ());
- worldBound.transform(_worldTransform, worldBound);
- clearDirty(DirtyType.Bounding);
- }
-
- /**
- * Initialize/Update shaders
- */
- public void updateShader(final Renderer r) {
- if (_geometryClipmapShader != null) {
- getWorldTransform().applyInverse(_terrainCamera.getLocation(), transformedFrustumPos);
- _geometryClipmapShader.setUniform("eyePosition", transformedFrustumPos);
- for (final TextureClipmap textureClipmap : _textureClipmaps) {
- textureClipmap.update(r, transformedFrustumPos);
- }
- if (_normalClipmap != null) {
- _normalClipmap.update(r, transformedFrustumPos);
- }
-
- return;
- }
-
- reloadShader();
- }
-
- public void reloadShader() {
- final ContextCapabilities caps = ContextManager.getCurrentContext().getCapabilities();
- if (caps.isGLSLSupported()) {
- _geometryClipmapShader = new GLSLShaderObjectsState();
- try {
- _geometryClipmapShader.setVertexShader(vertexShader.getInput());
- _geometryClipmapShader.setFragmentShader(pixelShader.getInput());
- } catch (final IOException ex) {
- Terrain.logger
- .logp(Level.SEVERE, getClass().getName(), "init(Renderer)", "Could not load shaders.", ex);
- }
-
- _geometryClipmapShader.setUniform("texture", 0);
- _geometryClipmapShader.setUniform("clipSideSize", (float) _clipSideSize);
-
- if (!_textureClipmaps.isEmpty()) {
- final TextureClipmap textureClipmap = _textureClipmaps.get(0);
- _geometryClipmapShader.setUniform("scale", 1f / textureClipmap.getScale());
- _geometryClipmapShader.setUniform("textureSize", (float) textureClipmap.getTextureSize());
- _geometryClipmapShader.setUniform("texelSize", 1f / textureClipmap.getTextureSize());
-
- _geometryClipmapShader.setUniform("levels", (float) textureClipmap.getTextureLevels());
- _geometryClipmapShader.setUniform("validLevels", (float) textureClipmap.getValidLevels() - 1);
- _geometryClipmapShader.setUniform("minLevel", 0f);
-
- _geometryClipmapShader.setUniform("showDebug", textureClipmap.isShowDebug() ? 1.0f : 0.0f);
- }
-
- _geometryClipmapShader.setShaderDataLogic(new GLSLShaderDataLogic() {
- public void applyData(final GLSLShaderObjectsState shader, final Mesh mesh, final Renderer renderer) {
- if (mesh instanceof ClipmapLevel) {
- shader.setUniform("vertexDistance", (float) ((ClipmapLevel) mesh).getVertexDistance());
- }
- }
- });
-
- applyToClips();
-
- for (final TextureClipmap textureClipmap : _textureClipmaps) {
- textureClipmap.setShaderState(_geometryClipmapShader);
- }
-
- if (_normalClipmap != null) {
- _normalClipmap.setShaderState(_geometryClipmapShader);
- }
-
- updateWorldRenderStates(false);
- }
- }
-
- protected void applyToClips() {
- for (int i = _clips.size() - 1; i >= 0; i--) {
- final ClipmapLevel clip = _clips.get(i);
- clip.setRenderState(_geometryClipmapShader);
- }
- }
-
- public void regenerate(final Renderer renderer) {
- for (int i = _clips.size() - 1; i >= 0; i--) {
- if (!_clips.get(i).isReady()) {
- _visibleLevels = i + 1;
- break;
- }
- }
-
- // Update vertices.
- for (int i = _clips.size() - 1; i >= _visibleLevels; i--) {
- _clips.get(i).regenerate();
- }
-
- // Update indices.
- for (int i = _clips.size() - 1; i >= _visibleLevels; i--) {
- if (i == _visibleLevels) {
- // Level 0 has no nested level, so pass null as parameter.
- _clips.get(i).updateIndices(null);
- } else {
- // All other levels i have the level i-1 nested in.
- _clips.get(i).updateIndices(_clips.get(i - 1));
- }
- }
-
- for (int i = _clips.size() - 1; i >= _visibleLevels; i--) {
- _clips.get(i).getMeshData().getVertexCoords().setNeedsRefresh(true);
- _clips.get(i).getMeshData().getIndices().setNeedsRefresh(true);
- }
-
- for (final TextureClipmap textureClipmap : _textureClipmaps) {
- textureClipmap.regenerate(renderer);
- }
-
- if (_normalClipmap != null) {
- _normalClipmap.regenerate(renderer);
- }
- }
-
- /**
- * @return the visibleLevels
- */
- public int getVisibleLevels() {
- return _visibleLevels;
- }
-
- /**
- * @param visibleLevels
- * the visibleLevels to set
- */
- public void setVisibleLevels(final int visibleLevels) {
- _visibleLevels = visibleLevels;
- }
-
- public void setHeightRange(final float heightRangeMin, final float heightRangeMax) {
- for (int i = _clips.size() - 1; i >= 0; i--) {
- final ClipmapLevel clip = _clips.get(i);
- clip.setHeightRange(heightRangeMin, heightRangeMax);
- }
- }
-
- public void setCullingEnabled(final boolean cullingEnabled) {
- for (int i = _clips.size() - 1; i >= 0; i--) {
- final ClipmapLevel clip = _clips.get(i);
- clip.setCullingEnabled(cullingEnabled);
- }
- }
-
- public void makePickable(final Class<? extends AbstractBresenhamTracer> tracerClass, final int maxChecks,
- final Vector3 initialSpacing) throws InstantiationException, IllegalAccessException {
- // init the terrain picker
- _picker = new ClipmapTerrainPicker(_clips, tracerClass, maxChecks, initialSpacing);
- }
-
- public TextureClipmap getTextureClipmap() {
- return _textureClipmaps.get(0);
- }
-
- public List<TextureClipmap> getTextureClipmaps() {
- return _textureClipmaps;
- }
-
- public GLSLShaderObjectsState getGeometryClipmapShader() {
- return _geometryClipmapShader;
- }
-
- public void setGeometryClipmapShader(final GLSLShaderObjectsState shaderState) {
- _geometryClipmapShader = shaderState;
-
- applyToClips();
-
- for (final TextureClipmap textureClipmap : _textureClipmaps) {
- textureClipmap.setShaderState(_geometryClipmapShader);
- }
-
- if (_normalClipmap != null) {
- _normalClipmap.setShaderState(_geometryClipmapShader);
- }
- }
-
- public ClipmapTerrainPicker getPicker() {
- return _picker;
- }
-
- @Override
- public boolean supportsBoundsIntersectionRecord() {
- // for now we are not compatible with bounding volume picks
- return false;
- }
-
- @Override
- public boolean supportsPrimitivesIntersectionRecord() {
- return true;
- }
-
- @Override
- public boolean intersectsWorldBound(final Ray3 ray) {
- // XXX: could optimize this by grabbing edges of terrain and checking if we are outside of that...
- // for now we just return true.
- return true;
- }
-
- @Override
- public IntersectionRecord intersectsWorldBoundsWhere(final Ray3 ray) {
- // for now we are not compatible with bounding volume picks
- return null;
- }
-
- @Override
- public IntersectionRecord intersectsPrimitivesWhere(final Ray3 ray) {
- if (_picker != null) {
- final Vector3 normalStore = new Vector3();
- final Vector3 intersect = _picker.getTerrainIntersection(getWorldTransform(), _terrainCamera.getLocation(),
- ray, null, normalStore);
- if (intersect != null) {
- final double distance = intersect.distance(ray.getOrigin());
- final IntersectionRecord record = new IntersectionRecord(new double[] { distance },
- new Vector3[] { intersect }, new Vector3[] { normalStore }, null);
- return record;
- }
- }
- return null;
- }
-
- public List<ClipmapLevel> getClipmaps() {
- return _clips;
- }
-
- public void setVertexShader(final InputSupplier<? extends InputStream> vertexShader) {
- this.vertexShader = vertexShader;
- }
-
- public void setPixelShader(final InputSupplier<? extends InputStream> pixelShader) {
- this.pixelShader = pixelShader;
- }
-
- public void addTextureClipmap(final TextureClipmap textureClipmap) {
- _textureClipmaps.add(textureClipmap);
- }
-
- /**
- * set the minimum (highest resolution) clipmap level visible
- *
- * @param level
- * clamped to valid range
- */
- public void setMinVisibleLevel(final int level) {
- if (level < 0) {
- _minVisibleLevel = 0;
- } else if (level >= _clips.size()) {
- _minVisibleLevel = _clips.size() - 1;
- } else {
- _minVisibleLevel = level;
- }
- }
-
- public int getMinVisibleLevel() {
- return _minVisibleLevel;
- }
-
- /**
- * convenience function to set minimum (highest resolution) texture clipmap level on all TextureClipmaps held by
- * this terrain
- */
- public void setTextureMinVisibleLevel(final int level) {
- for (final TextureClipmap tc : _textureClipmaps) {
- tc.setMinVisibleLevel(level);
- }
- }
-
- public int getTextureMinVisibleLevel() {
- if (!_textureClipmaps.isEmpty()) {
- return _textureClipmaps.get(0).getMinVisibleLevel();
- }
- return 0;
- }
-
- public float getHeightAt(final double x, final double z) {
- final Vector3 heightCalc = new Vector3(x, 0, z);
- worldToLocal(heightCalc, heightCalc);
- final float height = getClipmaps().get(0).getCache().getSubHeight(heightCalc.getXf(), heightCalc.getZf());
- heightCalc.set(x, height, z);
- localToWorld(heightCalc, heightCalc);
- return heightCalc.getYf();
- }
-
- public void shutdown() {
- for (final TextureClipmap textureClipmap : _textureClipmaps) {
- textureClipmap.shutdown();
- }
- for (final ClipmapLevel terrainClipmap : _clips) {
- terrainClipmap.shutdown();
- }
- if (_normalClipmap != null) {
- _normalClipmap.shutdown();
- }
- }
-
- public TextureState getClipTextureState() {
- return clipTextureState;
- }
-
- public void setNormalClipmap(final TextureClipmap normalClipmap) {
- _normalClipmap = normalClipmap;
- }
-
- public TextureClipmap getNormalClipmap() {
- return _normalClipmap;
- }
-
- public int getNormalUnit() {
- return _normalUnit;
- }
-
- public void setNormalUnit(final int unit) {
- _normalUnit = unit;
- }
-}
+/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.terrain.client; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.FloatBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.ardor3d.bounding.BoundingBox; +import com.ardor3d.extension.terrain.util.AbstractBresenhamTracer; +import com.ardor3d.extension.terrain.util.ClipmapTerrainPicker; +import com.ardor3d.extension.terrain.util.DoubleBufferedList; +import com.ardor3d.extension.terrain.util.Region; +import com.ardor3d.intersection.IntersectionRecord; +import com.ardor3d.intersection.Pickable; +import com.ardor3d.math.ColorRGBA; +import com.ardor3d.math.MathUtils; +import com.ardor3d.math.Ray3; +import com.ardor3d.math.Vector3; +import com.ardor3d.renderer.Camera; +import com.ardor3d.renderer.ContextCapabilities; +import com.ardor3d.renderer.ContextManager; +import com.ardor3d.renderer.Renderer; +import com.ardor3d.renderer.queue.RenderBucketType; +import com.ardor3d.renderer.state.BlendState; +import com.ardor3d.renderer.state.CullState; +import com.ardor3d.renderer.state.GLSLShaderDataLogic; +import com.ardor3d.renderer.state.GLSLShaderObjectsState; +import com.ardor3d.renderer.state.MaterialState; +import com.ardor3d.renderer.state.MaterialState.MaterialFace; +import com.ardor3d.renderer.state.TextureState; +import com.ardor3d.scenegraph.Mesh; +import com.ardor3d.scenegraph.Node; +import com.ardor3d.scenegraph.event.DirtyType; +import com.ardor3d.scenegraph.hint.DataMode; +import com.ardor3d.util.resource.ResourceLocatorTool; +import com.google.common.collect.Lists; +import com.google.common.io.InputSupplier; + +/** + * An implementation of geometry clipmapping + */ +public class Terrain extends Node implements Pickable { + /** The Constant logger. */ + private static final Logger logger = Logger.getLogger(Terrain.class.getName()); + + /** Our picker. */ + private ClipmapTerrainPicker _picker = null; + + private List<ClipmapLevel> _clips; + private int _visibleLevels = 0; + private int _minVisibleLevel = 0; + private final Camera _terrainCamera; + private final int _clipSideSize; + + private final BlendState blendState; + + private boolean _initialized = false; + + /** Shader for rendering clipmap geometry with morphing. */ + private GLSLShaderObjectsState _geometryClipmapShader; + + /** Reference to the texture clipmap */ + private final List<TextureClipmap> _textureClipmaps = Lists.newArrayList(); + + /** Reference to normal map */ + private TextureClipmap _normalClipmap; + private int _normalUnit = 5; + + private final Vector3 transformedFrustumPos = new Vector3(); + + private final DoubleBufferedList<Region> mailBox = new DoubleBufferedList<Region>(); + + private InputSupplier<? extends InputStream> vertexShader; + private InputSupplier<? extends InputStream> pixelShader; + + /** Timers for mailbox updates */ + private long oldTime = 0; + private long updateTimer = 0; + private final long updateThreashold = 300; + + final TextureState clipTextureState = new TextureState(); + + private final Comparator<Region> regionSorter = new Comparator<Region>() { + @Override + public int compare(final Region r1, final Region r2) { + return r1.getLevel() - r2.getLevel(); + } + }; + + public Terrain(final Camera camera, final List<TerrainCache> cacheList, final int clipSideSize, + final TerrainConfiguration terrainConfiguration) { + _terrainCamera = camera; + _clipSideSize = clipSideSize; + + _worldBound = new BoundingBox(Vector3.ZERO, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, + Double.POSITIVE_INFINITY); + + getSceneHints().setRenderBucketType(RenderBucketType.Opaque); + final CullState cs = new CullState(); + cs.setEnabled(true); + cs.setCullFace(CullState.Face.Back); + setRenderState(cs); + + final MaterialState materialState = new MaterialState(); + materialState.setAmbient(MaterialFace.FrontAndBack, new ColorRGBA(1, 1, 1, 1)); + materialState.setDiffuse(MaterialFace.FrontAndBack, new ColorRGBA(1, 1, 1, 1)); + materialState.setSpecular(MaterialFace.FrontAndBack, new ColorRGBA(1, 1, 1, 1)); + materialState.setShininess(MaterialFace.FrontAndBack, 64.0f); + setRenderState(materialState); + + blendState = new BlendState(); + blendState.setBlendEnabled(true); + blendState.setSourceFunction(BlendState.SourceFunction.SourceAlpha); + blendState.setDestinationFunction(BlendState.DestinationFunction.OneMinusSourceAlpha); + setRenderState(blendState); + + // getSceneHints().setLightCombineMode(LightCombineMode.Off); + + try { + _clips = new ArrayList<ClipmapLevel>(); + + final float heightScale = terrainConfiguration.getScale().getYf(); + + for (int i = 0; i < cacheList.size(); i++) { + final TerrainCache cache = cacheList.get(i); + cache.setMailBox(mailBox); + final ClipmapLevel clipmap = new ClipmapLevel(i, camera, clipSideSize, heightScale, cache); + _clips.add(clipmap); + attachChild(clipmap); + + clipmap.getSceneHints().setDataMode(DataMode.Arrays); + + // clipmap.getSceneHints().setDataMode(DataMode.VBOInterleaved); + // final FloatBufferData interleavedData = new FloatBufferData(); + // interleavedData.setVboAccessMode(VBOAccessMode.DynamicDraw); + // clipmap.getMeshData().setInterleavedData(interleavedData); + + // clipmap.getSceneHints().setDataMode(DataMode.VBO); + // clipmap.getMeshData().getVertexCoords().setVboAccessMode(VBOAccessMode.DynamicDraw); + // clipmap.getMeshData().getIndices().setVboAccessMode(VBOAccessMode.DynamicDraw); + } + } catch (final Exception ex) { + ex.printStackTrace(); + } + + vertexShader = new UrlInputSupplier(ResourceLocatorTool.getClassPathResource(Terrain.class, + "com/ardor3d/extension/terrain/texturedGeometryClipmapShader.vert")); + pixelShader = new UrlInputSupplier(ResourceLocatorTool.getClassPathResource(Terrain.class, + "com/ardor3d/extension/terrain/texturedGeometryClipmapShader.frag")); + + // setScale(terrainConfiguration.getScale()); + // TODO: hack. unify scale handling over cache etc + setScale(terrainConfiguration.getScale().getX(), 1, terrainConfiguration.getScale().getZ()); + setHeightRange(terrainConfiguration.getHeightRangeMin(), terrainConfiguration.getHeightRangeMax()); + } + + private final List<Long> timers = Lists.newArrayList(); + + @Override + protected void updateChildren(final double time) { + super.updateChildren(time); + + for (int i = _minVisibleLevel; i < _clips.size(); i++) { + if (_clips.get(i).isReady()) { + _visibleLevels = i; + break; + } + } + + // TODO: improve calcs for removing levels based on height above terrain + // getWorldTransform().applyInverse(_terrainCamera.getLocation(), transformedFrustumPos); + // final float heightRangeMax = 1f; + // if (transformedFrustumPos.getYf() > heightRangeMax) { + // final float diff = transformedFrustumPos.getYf() - heightRangeMax; + // final float x = (float) (diff * Math.tan(Math.toRadians(30))); + // for (int unit = _visibleLevels; unit < _clips.size(); unit++) { + // final float heightTest = _clipSideSize * MathUtils.pow2(unit) / x; + // if (heightTest > 1) { + // _visibleLevels = unit; + // break; + // } + // } + // } + + if (timers.size() < _visibleLevels) { + for (int unit = 0; unit < _visibleLevels; unit++) { + timers.add(System.currentTimeMillis()); + } + } + for (int unit = 0; unit < _visibleLevels; unit++) { + final long t = System.currentTimeMillis() - timers.get(unit); + if (t > 500) { + timers.set(unit, System.currentTimeMillis()); + _clips.get(unit).updateCache(); + } + } + + // Update vertices. + for (int i = _clips.size() - 1; i >= _visibleLevels; i--) { + _clips.get(i).updateVertices(); + } + + // Update from mailbox + updateFromMailbox(); + + // Update indices. + for (int i = _clips.size() - 1; i >= _visibleLevels; i--) { + if (i == _visibleLevels) { + // Level 0 has no nested level, so pass null as parameter. + _clips.get(i).updateIndices(null); + } else { + // All other levels i have the level i-1 nested in. + _clips.get(i).updateIndices(_clips.get(i - 1)); + } + } + + for (int i = _clips.size() - 1; i >= _visibleLevels; i--) { + _clips.get(i).getMeshData().getVertexCoords().setNeedsRefresh(true); + _clips.get(i).getMeshData().getIndices().setNeedsRefresh(true); + } + } + + @Override + public void draw(final Renderer r) { + updateShader(r); + + boolean first = true; + if (_normalClipmap != null) { + clipTextureState.setTexture(_normalClipmap.getTexture(), _normalUnit); + } + for (final TextureClipmap textureClipmap : _textureClipmaps) { + clipTextureState.setTexture(textureClipmap.getTexture()); + if (first) { + blendState.setEnabled(false); + first = false; + } else { + blendState.setEnabled(true); + } + + if (_textureClipmaps.size() > 1) { + r.getQueue().pushBuckets(); + } + + for (int i = _clips.size() - 1; i >= 0; i--) { + final ClipmapLevel clip = _clips.get(i); + clip.setRenderState(clipTextureState); + } + + if (_textureClipmaps.size() > 1) { + _geometryClipmapShader.setUniform("scale", 1f / textureClipmap.getScale()); + _geometryClipmapShader.setUniform("textureSize", (float) textureClipmap.getTextureSize()); + _geometryClipmapShader.setUniform("texelSize", 1f / textureClipmap.getTextureSize()); + _geometryClipmapShader.setUniform("levels", (float) textureClipmap.getTextureLevels()); + _geometryClipmapShader.setUniform("validLevels", (float) textureClipmap.getValidLevels() - 1); + _geometryClipmapShader.setUniform("showDebug", textureClipmap.isShowDebug() ? 1.0f : 0.0f); + _geometryClipmapShader.setNeedsRefresh(true); + } + + blendState.setNeedsRefresh(true); + this.updateWorldRenderStates(true); + + if (!_initialized) { + for (int i = _clips.size() - 1; i >= _visibleLevels; i--) { + final ClipmapLevel clip = _clips.get(i); + + clip.getMeshData().getIndices().limit(clip.getMeshData().getIndices().capacity()); + } + + _initialized = true; + } + + // draw levels from coarse to fine. + for (int i = _clips.size() - 1; i >= _visibleLevels; i--) { + final ClipmapLevel clip = _clips.get(i); + + if (clip.getStripIndex() > 0) { + clip.draw(r); + } + } + + if (_textureClipmaps.size() > 1) { + r.renderBuckets(); + r.getQueue().popBuckets(); + } + } + } + + private void updateFromMailbox() { + if (updateTimer > updateThreashold) { + final List<Region> regionList = mailBox.switchAndGet(); + if (!regionList.isEmpty()) { + for (int i = regionList.size() - 1; i >= 0; i--) { + final Region region = regionList.get(i); + + final ClipmapLevel clip = _clips.get(region.getLevel()); + final Region clipRegion = clip.getIntersectionRegion(); + + if (clipRegion.intersects(region)) { + clipRegion.intersection(region); + } else { + regionList.remove(i); + } + } + + Collections.sort(regionList, regionSorter); + + final int start = regionList.size() - 1; + for (int i = start; i >= 0; i--) { + final Region region = regionList.get(i); + + recursiveAddUpdates(regionList, region.getLevel(), region.getX(), region.getY(), region.getWidth(), + region.getHeight()); + } + + for (int i = regionList.size() - 1; i >= 0; i--) { + final Region region = regionList.get(i); + + final ClipmapLevel clip = _clips.get(region.getLevel()); + final Region clipRegion = clip.getIntersectionRegion(); + + if (clipRegion.intersects(region)) { + clipRegion.intersection(region); + } else { + regionList.remove(i); + } + } + + Collections.sort(regionList, regionSorter); + + for (int i = regionList.size() - 1; i >= 0; i--) { + final Region region = regionList.get(i); + final ClipmapLevel clip = _clips.get(region.getLevel()); + final FloatBuffer vertices = clip.getMeshData().getVertexBuffer(); + final int vertexDistance = clip.getVertexDistance(); + + clip.getCache().updateRegion(vertices, region.getX() / vertexDistance, + region.getY() / vertexDistance, region.getWidth() / vertexDistance, + region.getHeight() / vertexDistance); + } + } + updateTimer %= updateThreashold; + } + final long time = System.currentTimeMillis(); + updateTimer += time - oldTime; + oldTime = time; + } + + private void recursiveAddUpdates(final List<Region> regionList, final int level, final int x, final int y, + final int width, final int height) { + if (level == 0) { + return; + } + + final Region region = new Region(level - 1, x, y, width, height); + if (!regionList.contains(region)) { + regionList.add(region); + recursiveAddUpdates(regionList, region.getLevel(), region.getX(), region.getY(), region.getWidth(), + region.getHeight()); + } + } + + private final Vector3 _boundsCenter = new Vector3(); + private final Vector3 _boundsExtents = new Vector3(); + + @Override + public void updateWorldBound(final boolean recurse) { + final BoundingBox worldBound = (BoundingBox) _worldBound; + final Vector3 center = _boundsCenter.set(_terrainCamera.getLocation()); + final double distanceToEdge = _clipSideSize * MathUtils.pow2(_clips.size() - 1) * 0.5; + final double heightScale = _clips.get(0).getHeightScale(); + final double heightMin = _clips.get(0).getHeightRangeMin() * heightScale; + final double heightMax = _clips.get(0).getHeightRangeMax() * heightScale; + + final Vector3 extents = _boundsExtents.set(distanceToEdge, (heightMax - heightMin) * 0.5, distanceToEdge); + worldToLocal(center, center); + worldBound.setXExtent(extents.getX()); + worldBound.setYExtent(extents.getY()); + worldBound.setZExtent(extents.getZ()); + worldBound.setCenter(center.getX(), (heightMax + heightMin) * 0.5, center.getZ()); + worldBound.transform(_worldTransform, worldBound); + clearDirty(DirtyType.Bounding); + } + + /** + * Initialize/Update shaders + */ + public void updateShader(final Renderer r) { + if (_geometryClipmapShader != null) { + getWorldTransform().applyInverse(_terrainCamera.getLocation(), transformedFrustumPos); + _geometryClipmapShader.setUniform("eyePosition", transformedFrustumPos); + for (final TextureClipmap textureClipmap : _textureClipmaps) { + textureClipmap.update(r, transformedFrustumPos); + } + if (_normalClipmap != null) { + _normalClipmap.update(r, transformedFrustumPos); + } + + return; + } + + reloadShader(); + } + + public void reloadShader() { + final ContextCapabilities caps = ContextManager.getCurrentContext().getCapabilities(); + if (caps.isGLSLSupported()) { + _geometryClipmapShader = new GLSLShaderObjectsState(); + try { + _geometryClipmapShader.setVertexShader(vertexShader.getInput()); + _geometryClipmapShader.setFragmentShader(pixelShader.getInput()); + } catch (final IOException ex) { + Terrain.logger + .logp(Level.SEVERE, getClass().getName(), "init(Renderer)", "Could not load shaders.", ex); + } + + _geometryClipmapShader.setUniform("texture", 0); + _geometryClipmapShader.setUniform("clipSideSize", (float) _clipSideSize); + + if (!_textureClipmaps.isEmpty()) { + final TextureClipmap textureClipmap = _textureClipmaps.get(0); + _geometryClipmapShader.setUniform("scale", 1f / textureClipmap.getScale()); + _geometryClipmapShader.setUniform("textureSize", (float) textureClipmap.getTextureSize()); + _geometryClipmapShader.setUniform("texelSize", 1f / textureClipmap.getTextureSize()); + + _geometryClipmapShader.setUniform("levels", (float) textureClipmap.getTextureLevels()); + _geometryClipmapShader.setUniform("validLevels", (float) textureClipmap.getValidLevels() - 1); + _geometryClipmapShader.setUniform("minLevel", 0f); + + _geometryClipmapShader.setUniform("showDebug", textureClipmap.isShowDebug() ? 1.0f : 0.0f); + } + + _geometryClipmapShader.setShaderDataLogic(new GLSLShaderDataLogic() { + public void applyData(final GLSLShaderObjectsState shader, final Mesh mesh, final Renderer renderer) { + if (mesh instanceof ClipmapLevel) { + shader.setUniform("vertexDistance", (float) ((ClipmapLevel) mesh).getVertexDistance()); + } + } + }); + + applyToClips(); + + for (final TextureClipmap textureClipmap : _textureClipmaps) { + textureClipmap.setShaderState(_geometryClipmapShader); + } + + if (_normalClipmap != null) { + _normalClipmap.setShaderState(_geometryClipmapShader); + } + + updateWorldRenderStates(false); + } + } + + protected void applyToClips() { + for (int i = _clips.size() - 1; i >= 0; i--) { + final ClipmapLevel clip = _clips.get(i); + clip.setRenderState(_geometryClipmapShader); + } + } + + public void regenerate(final Renderer renderer) { + for (int i = _clips.size() - 1; i >= 0; i--) { + if (!_clips.get(i).isReady()) { + _visibleLevels = i + 1; + break; + } + } + + // Update vertices. + for (int i = _clips.size() - 1; i >= _visibleLevels; i--) { + _clips.get(i).regenerate(); + } + + // Update indices. + for (int i = _clips.size() - 1; i >= _visibleLevels; i--) { + if (i == _visibleLevels) { + // Level 0 has no nested level, so pass null as parameter. + _clips.get(i).updateIndices(null); + } else { + // All other levels i have the level i-1 nested in. + _clips.get(i).updateIndices(_clips.get(i - 1)); + } + } + + for (int i = _clips.size() - 1; i >= _visibleLevels; i--) { + _clips.get(i).getMeshData().getVertexCoords().setNeedsRefresh(true); + _clips.get(i).getMeshData().getIndices().setNeedsRefresh(true); + } + + for (final TextureClipmap textureClipmap : _textureClipmaps) { + textureClipmap.regenerate(renderer); + } + + if (_normalClipmap != null) { + _normalClipmap.regenerate(renderer); + } + } + + /** + * @return the visibleLevels + */ + public int getVisibleLevels() { + return _visibleLevels; + } + + /** + * @param visibleLevels + * the visibleLevels to set + */ + public void setVisibleLevels(final int visibleLevels) { + _visibleLevels = visibleLevels; + } + + public void setHeightRange(final float heightRangeMin, final float heightRangeMax) { + for (int i = _clips.size() - 1; i >= 0; i--) { + final ClipmapLevel clip = _clips.get(i); + clip.setHeightRange(heightRangeMin, heightRangeMax); + } + } + + public void setCullingEnabled(final boolean cullingEnabled) { + for (int i = _clips.size() - 1; i >= 0; i--) { + final ClipmapLevel clip = _clips.get(i); + clip.setCullingEnabled(cullingEnabled); + } + } + + public void makePickable(final Class<? extends AbstractBresenhamTracer> tracerClass, final int maxChecks, + final Vector3 initialSpacing) throws InstantiationException, IllegalAccessException { + // init the terrain picker + _picker = new ClipmapTerrainPicker(_clips, tracerClass, maxChecks, initialSpacing); + } + + public TextureClipmap getTextureClipmap() { + return _textureClipmaps.get(0); + } + + public List<TextureClipmap> getTextureClipmaps() { + return _textureClipmaps; + } + + public GLSLShaderObjectsState getGeometryClipmapShader() { + return _geometryClipmapShader; + } + + public void setGeometryClipmapShader(final GLSLShaderObjectsState shaderState) { + _geometryClipmapShader = shaderState; + + applyToClips(); + + for (final TextureClipmap textureClipmap : _textureClipmaps) { + textureClipmap.setShaderState(_geometryClipmapShader); + } + + if (_normalClipmap != null) { + _normalClipmap.setShaderState(_geometryClipmapShader); + } + } + + public ClipmapTerrainPicker getPicker() { + return _picker; + } + + @Override + public boolean supportsBoundsIntersectionRecord() { + // for now we are not compatible with bounding volume picks + return false; + } + + @Override + public boolean supportsPrimitivesIntersectionRecord() { + return true; + } + + @Override + public boolean intersectsWorldBound(final Ray3 ray) { + // XXX: could optimize this by grabbing edges of terrain and checking if we are outside of that... + // for now we just return true. + return true; + } + + @Override + public IntersectionRecord intersectsWorldBoundsWhere(final Ray3 ray) { + // for now we are not compatible with bounding volume picks + return null; + } + + @Override + public IntersectionRecord intersectsPrimitivesWhere(final Ray3 ray) { + if (_picker != null) { + final Vector3 normalStore = new Vector3(); + final Vector3 intersect = _picker.getTerrainIntersection(getWorldTransform(), _terrainCamera.getLocation(), + ray, null, normalStore); + if (intersect != null) { + final double distance = intersect.distance(ray.getOrigin()); + final IntersectionRecord record = new IntersectionRecord(new double[] { distance }, + new Vector3[] { intersect }, new Vector3[] { normalStore }, null); + return record; + } + } + return null; + } + + public List<ClipmapLevel> getClipmaps() { + return _clips; + } + + public void setVertexShader(final InputSupplier<? extends InputStream> vertexShader) { + this.vertexShader = vertexShader; + } + + public void setPixelShader(final InputSupplier<? extends InputStream> pixelShader) { + this.pixelShader = pixelShader; + } + + public void addTextureClipmap(final TextureClipmap textureClipmap) { + _textureClipmaps.add(textureClipmap); + } + + /** + * set the minimum (highest resolution) clipmap level visible + * + * @param level + * clamped to valid range + */ + public void setMinVisibleLevel(final int level) { + if (level < 0) { + _minVisibleLevel = 0; + } else if (level >= _clips.size()) { + _minVisibleLevel = _clips.size() - 1; + } else { + _minVisibleLevel = level; + } + } + + public int getMinVisibleLevel() { + return _minVisibleLevel; + } + + /** + * convenience function to set minimum (highest resolution) texture clipmap level on all TextureClipmaps held by + * this terrain + */ + public void setTextureMinVisibleLevel(final int level) { + for (final TextureClipmap tc : _textureClipmaps) { + tc.setMinVisibleLevel(level); + } + } + + public int getTextureMinVisibleLevel() { + if (!_textureClipmaps.isEmpty()) { + return _textureClipmaps.get(0).getMinVisibleLevel(); + } + return 0; + } + + public float getHeightAt(final double x, final double z) { + final Vector3 heightCalc = new Vector3(x, 0, z); + worldToLocal(heightCalc, heightCalc); + final float height = getClipmaps().get(0).getCache().getSubHeight(heightCalc.getXf(), heightCalc.getZf()); + heightCalc.set(x, height, z); + localToWorld(heightCalc, heightCalc); + return heightCalc.getYf(); + } + + public void shutdown() { + for (final TextureClipmap textureClipmap : _textureClipmaps) { + textureClipmap.shutdown(); + } + for (final ClipmapLevel terrainClipmap : _clips) { + terrainClipmap.shutdown(); + } + if (_normalClipmap != null) { + _normalClipmap.shutdown(); + } + } + + public TextureState getClipTextureState() { + return clipTextureState; + } + + public void setNormalClipmap(final TextureClipmap normalClipmap) { + _normalClipmap = normalClipmap; + } + + public TextureClipmap getNormalClipmap() { + return _normalClipmap; + } + + public int getNormalUnit() { + return _normalUnit; + } + + public void setNormalUnit(final int unit) { + _normalUnit = unit; + } +} diff --git a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/client/TerrainDataProvider.java b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/client/TerrainDataProvider.java index 10e3e8b..e1ca2a7 100644 --- a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/client/TerrainDataProvider.java +++ b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/client/TerrainDataProvider.java @@ -1,50 +1,50 @@ -/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.terrain.client;
-
-import java.util.Map;
-
-/**
- * The TerrainDataProvider is the connection between the terrain core and external data.
- */
-public interface TerrainDataProvider {
- /**
- * Request for all available maps. Returns a Map with mapIDs and map names.
- *
- * @return Available maps
- * @throws Exception
- */
- Map<Integer, String> getAvailableMaps() throws Exception;
-
- /**
- * Request for a TerrainSource of valid type for this Provider.
- *
- * @param mapId
- * @return
- */
- TerrainSource getTerrainSource(int mapId);
-
- /**
- * Request for a TextureSource of valid type for this Provider.
- *
- * @param mapId
- * @return
- */
- TextureSource getTextureSource(int mapId);
-
- /**
- * Request for a normalmap TextureSource of valid type for this Provider.
- *
- * @param mapId
- * @return
- */
- TextureSource getNormalMapSource(int mapId);
-}
+/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.terrain.client; + +import java.util.Map; + +/** + * The TerrainDataProvider is the connection between the terrain core and external data. + */ +public interface TerrainDataProvider { + /** + * Request for all available maps. Returns a Map with mapIDs and map names. + * + * @return Available maps + * @throws Exception + */ + Map<Integer, String> getAvailableMaps() throws Exception; + + /** + * Request for a TerrainSource of valid type for this Provider. + * + * @param mapId + * @return + */ + TerrainSource getTerrainSource(int mapId); + + /** + * Request for a TextureSource of valid type for this Provider. + * + * @param mapId + * @return + */ + TextureSource getTextureSource(int mapId); + + /** + * Request for a normalmap TextureSource of valid type for this Provider. + * + * @param mapId + * @return + */ + TextureSource getNormalMapSource(int mapId); +} diff --git a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/heightmap/ImageHeightMap.java b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/heightmap/ImageHeightMap.java index 9984173..99a816a 100644 --- a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/heightmap/ImageHeightMap.java +++ b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/heightmap/ImageHeightMap.java @@ -1,61 +1,61 @@ -/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.terrain.heightmap;
-
-import com.ardor3d.image.Image;
-import com.ardor3d.image.ImageDataFormat;
-import com.ardor3d.math.MathUtils;
-
-public class ImageHeightMap {
-
- public static float[] generateHeightMap(final Image ardorImage, final float min, final float max) {
- if (max <= min) {
- throw new IllegalArgumentException("max must be greater than min");
- }
-
- final ImageDataFormat format = ardorImage.getDataFormat();
- if (format != ImageDataFormat.RGB && format != ImageDataFormat.RGBA && format != ImageDataFormat.Luminance) {
- throw new IllegalArgumentException("Unhandled format (must be Luminance, RGB or RGBA): " + format);
- }
-
- if (ardorImage.getWidth() != ardorImage.getHeight() || !MathUtils.isPowerOfTwo(ardorImage.getWidth())) {
- throw new IllegalArgumentException("Only pow2, square images are supported.");
- }
-
- final int size = ardorImage.getWidth(), comps = format.getComponents();
-
- // initialize the height data attributes
- final float[] heightData = new float[ardorImage.getWidth() * ardorImage.getHeight()];
- final byte[] data = new byte[heightData.length * comps];
- ardorImage.getData(0).get(data);
-
- int index = 0, dataIndex, gray;
- final int rowsize = size * comps;
- final float byteScale = (max - min) / 255f;
- for (int h = 0; h < size; h++) {
- for (int w = 0; w < size; w++) {
- dataIndex = h * rowsize + w * comps;
- if (comps == 1) {
- gray = data[dataIndex] & 0xFF;
- } else {
- final int red = data[dataIndex] & 0xFF;
- final int green = data[dataIndex + 1] & 0xFF;
- final int blue = data[dataIndex + 2] & 0xFF;
-
- gray = (int) (0.30 * red + 0.59 * green + 0.11 * blue);
- }
-
- heightData[index++] = gray * byteScale + min;
- }
- }
- return heightData;
- }
-}
+/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.terrain.heightmap; + +import com.ardor3d.image.Image; +import com.ardor3d.image.ImageDataFormat; +import com.ardor3d.math.MathUtils; + +public class ImageHeightMap { + + public static float[] generateHeightMap(final Image ardorImage, final float min, final float max) { + if (max <= min) { + throw new IllegalArgumentException("max must be greater than min"); + } + + final ImageDataFormat format = ardorImage.getDataFormat(); + if (format != ImageDataFormat.RGB && format != ImageDataFormat.RGBA && format != ImageDataFormat.Luminance) { + throw new IllegalArgumentException("Unhandled format (must be Luminance, RGB or RGBA): " + format); + } + + if (ardorImage.getWidth() != ardorImage.getHeight() || !MathUtils.isPowerOfTwo(ardorImage.getWidth())) { + throw new IllegalArgumentException("Only pow2, square images are supported."); + } + + final int size = ardorImage.getWidth(), comps = format.getComponents(); + + // initialize the height data attributes + final float[] heightData = new float[ardorImage.getWidth() * ardorImage.getHeight()]; + final byte[] data = new byte[heightData.length * comps]; + ardorImage.getData(0).get(data); + + int index = 0, dataIndex, gray; + final int rowsize = size * comps; + final float byteScale = (max - min) / 255f; + for (int h = 0; h < size; h++) { + for (int w = 0; w < size; w++) { + dataIndex = h * rowsize + w * comps; + if (comps == 1) { + gray = data[dataIndex] & 0xFF; + } else { + final int red = data[dataIndex] & 0xFF; + final int green = data[dataIndex + 1] & 0xFF; + final int blue = data[dataIndex + 2] & 0xFF; + + gray = (int) (0.30 * red + 0.59 * green + 0.11 * blue); + } + + heightData[index++] = gray * byteScale + min; + } + } + return heightData; + } +} diff --git a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/heightmap/MidPointHeightMapGenerator.java b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/heightmap/MidPointHeightMapGenerator.java index d633fd2..20c26fa 100644 --- a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/heightmap/MidPointHeightMapGenerator.java +++ b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/heightmap/MidPointHeightMapGenerator.java @@ -1,307 +1,307 @@ -/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.terrain.heightmap;
-
-import java.util.Random;
-import java.util.logging.Logger;
-
-import com.ardor3d.math.MathUtils;
-import com.ardor3d.util.Ardor3dException;
-
-public class MidPointHeightMapGenerator {
- private static final Logger logger = Logger.getLogger(MidPointHeightMapGenerator.class.getName());
-
- private float roughness;
-
- /** Height data information. */
- protected float[] heightData = null;
-
- /** The size of the height map's width. */
- protected int size = 0;
-
- /** Allows scaling the Y height of the map. */
- protected float heightScale = 1.0f;
-
- /** The filter is used to erode the terrain. */
- protected float filter = 0.5f;
-
- /** The range used to normalize terrain */
- private float heightRange = 1f;
-
- private final Random random = new Random();
- private boolean loaded = false;
-
- /**
- * Constructor builds a new heightmap using the midpoint displacement algorithm. Roughness determines how chaotic
- * the terrain will be. Where 1 is perfectly self-similar, > 1 early iterations have a disproportionately large
- * effect creating smooth terrain, and < 1 late iteraions have a disproportionately large effect creating chaotic
- * terrain.
- *
- * @param size
- * the size of the terrain, must be a power of 2.
- * @param roughness
- * how chaotic to make the terrain.
- *
- * @throws Ardor3dException
- * if size is less than or equal to zero or roughtness is less than 0.
- */
- public MidPointHeightMapGenerator(final int size, final float roughness) {
- if (!MathUtils.isPowerOfTwo(size)) {
- throw new Ardor3dException("Size must be (2^N) sized.");
- }
- if (roughness < 0 || size <= 0) {
- throw new Ardor3dException("size and roughness must be " + "greater than 0");
- }
- this.roughness = roughness;
- this.size = size;
- }
-
- /**
- * Constructor builds a new heightmap using the midpoint displacement algorithm. Roughness determines how chaotic
- * the terrain will be. Where 1 is perfectly self-similar, > 1 early iterations have a disproportionately large
- * effect creating smooth terrain, and < 1 late iteraions have a disproportionately large effect creating chaotic
- * terrain.
- *
- * @param size
- * the size of the terrain, must be a power of 2.
- * @param roughness
- * how chaotic to make the terrain.
- *
- * @throws Ardor3dException
- * if size is less than or equal to zero or roughtness is less than 0.
- */
- public MidPointHeightMapGenerator(final int size, final float roughness, final long seed) {
- this(size, roughness);
- random.setSeed(seed);
- }
-
- /**
- * @return the heightData
- */
- public float[] getHeightData() {
- if (!loaded) {
- generateHeightData();
- }
- return heightData;
- }
-
- /**
- * <code>load</code> generates the heightfield using the Midpoint Displacement algorithm. <code>load</code> uses the
- * latest attributes, so a call to <code>load</code> is recommended if attributes have changed using the set
- * methods.
- */
- public boolean generateHeightData() {
- float height;
- double heightReducer;
- float[][] tempBuffer;
-
- // holds the points of the square.
- int ni, nj;
- int mi, mj;
- int pmi, pmj;
-
- height = 1f;
- heightReducer = Math.pow(2, -1 * roughness);
-
- heightData = new float[size * size];
- tempBuffer = new float[size][size];
-
- int counter = size;
- while (counter > 0) {
- // displace the center of the square.
- for (int i = 0; i < size; i += counter) {
- for (int j = 0; j < size; j += counter) {
- // (0,0) point of the local square
- ni = (i + counter) % size;
- nj = (j + counter) % size;
- // middle point of the local square
- mi = i + counter / 2;
- mj = j + counter / 2;
-
- // displace the middle point by the average of the
- // corners, and a random value.
- tempBuffer[mi][mj] = (tempBuffer[i][j] + tempBuffer[ni][j] + tempBuffer[i][nj] + tempBuffer[ni][nj])
- / 4 + random.nextFloat() * height - height / 2;
- }
- }
-
- // next calculate the new midpoints of the line segments.
- for (int i = 0; i < size; i += counter) {
- for (int j = 0; j < size; j += counter) {
- // (0,0) of the local square
- ni = (i + counter) % size;
- nj = (j + counter) % size;
-
- // middle point of the local square.
- mi = i + counter / 2;
- mj = j + counter / 2;
-
- // middle point on the line in the x-axis direction.
- pmi = (i - counter / 2 + size) % size;
- // middle point on the line in the y-axis direction.
- pmj = (j - counter / 2 + size) % size;
-
- // Calculate the square value for the top side of the rectangle
- tempBuffer[mi][j] = (tempBuffer[i][j] + tempBuffer[ni][j] + tempBuffer[mi][pmj] + tempBuffer[mi][mj])
- / 4 + random.nextFloat() * height - height / 2;
-
- // Calculate the square value for the left side of the rectangle
- tempBuffer[i][mj] = (tempBuffer[i][j] + tempBuffer[i][nj] + tempBuffer[pmi][mj] + tempBuffer[mi][mj])
- / 4 + random.nextFloat() * height - height / 2;
-
- }
- }
-
- counter /= 2;
- height *= heightReducer;
- }
-
- normalizeTerrain(tempBuffer);
-
- // transfer the new terrain into the height map.
- for (int i = 0; i < size; i++) {
- for (int j = 0; j < size; j++) {
- setHeightAtPoint(tempBuffer[i][j], i, j);
- }
- }
-
- MidPointHeightMapGenerator.logger.info("Created Heightmap using Mid Point");
-
- loaded = true;
-
- return true;
- }
-
- /**
- * <code>setRoughness</code> sets the new roughness value of the heightmap. Roughness determines how chaotic the
- * terrain will be. Where 1 is perfectly self-similar, > 1 early iterations have a disproportionately large effect
- * creating smooth terrain, and < 1 late iteraions have a disproportionately large effect creating chaotic terrain.
- *
- * @param roughness
- * how chaotic will the heightmap be.
- */
- public void setRoughness(final float roughness) {
- if (roughness < 0) {
- throw new Ardor3dException("roughness must be greater than 0");
- }
- this.roughness = roughness;
- }
-
- /**
- * <code>setHeightAtPoint</code> sets the height value for a given coordinate.
- *
- * @param height
- * the new height for the coordinate.
- * @param x
- * the x (east/west) coordinate.
- * @param z
- * the z (north/south) coordinate.
- */
- protected void setHeightAtPoint(final float height, final int x, final int z) {
- heightData[x + z * size] = height;
- }
-
- /**
- * <code>normalizeTerrain</code> takes the current terrain data and converts it to values between 0 and
- * NORMALIZE_RANGE.
- *
- * @param tempBuffer
- * the terrain to normalize.
- */
- protected void normalizeTerrain(final float[][] tempBuffer) {
- float currentMin, currentMax;
- float height;
-
- currentMin = tempBuffer[0][0];
- currentMax = tempBuffer[0][0];
-
- // find the min/max values of the height fTemptemptempBuffer
- for (int i = 0; i < size; i++) {
- for (int j = 0; j < size; j++) {
- if (tempBuffer[i][j] > currentMax) {
- currentMax = tempBuffer[i][j];
- } else if (tempBuffer[i][j] < currentMin) {
- currentMin = tempBuffer[i][j];
- }
- }
- }
-
- // find the range of the altitude
- if (currentMax <= currentMin) {
- return;
- }
-
- height = currentMax - currentMin;
-
- // scale the values to a range of 0-255
- for (int i = 0; i < size; i++) {
- for (int j = 0; j < size; j++) {
- tempBuffer[i][j] = (tempBuffer[i][j] - currentMin) / height * heightRange;
- }
- }
- }
-
- /**
- * <code>erodeTerrain</code> is a convenience method that applies the FIR filter to a given height map. This
- * simulates water errosion.
- *
- * @param tempBuffer
- * the terrain to filter.
- */
- protected void erodeTerrain(final float[][] tempBuffer) {
- // erode left to right
- float v;
-
- for (int i = 0; i < size; i++) {
- v = tempBuffer[i][0];
- for (int j = 1; j < size; j++) {
- tempBuffer[i][j] = filter * v + (1 - filter) * tempBuffer[i][j];
- v = tempBuffer[i][j];
- }
- }
-
- // erode right to left
- for (int i = size - 1; i >= 0; i--) {
- v = tempBuffer[i][0];
- for (int j = 0; j < size; j++) {
- tempBuffer[i][j] = filter * v + (1 - filter) * tempBuffer[i][j];
- v = tempBuffer[i][j];
- // erodeBand(tempBuffer[size * i + size - 1], -1);
- }
- }
-
- // erode top to bottom
- for (int i = 0; i < size; i++) {
- v = tempBuffer[0][i];
- for (int j = 0; j < size; j++) {
- tempBuffer[j][i] = filter * v + (1 - filter) * tempBuffer[j][i];
- v = tempBuffer[j][i];
- }
- }
-
- // erode from bottom to top
- for (int i = size - 1; i >= 0; i--) {
- v = tempBuffer[0][i];
- for (int j = 0; j < size; j++) {
- tempBuffer[j][i] = filter * v + (1 - filter) * tempBuffer[j][i];
- v = tempBuffer[j][i];
- }
- }
- }
-
- public float getHeightRange() {
- return heightRange;
- }
-
- public void setHeightRange(final float heightRange) {
- this.heightRange = heightRange;
- }
-}
+/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.terrain.heightmap; + +import java.util.Random; +import java.util.logging.Logger; + +import com.ardor3d.math.MathUtils; +import com.ardor3d.util.Ardor3dException; + +public class MidPointHeightMapGenerator { + private static final Logger logger = Logger.getLogger(MidPointHeightMapGenerator.class.getName()); + + private float roughness; + + /** Height data information. */ + protected float[] heightData = null; + + /** The size of the height map's width. */ + protected int size = 0; + + /** Allows scaling the Y height of the map. */ + protected float heightScale = 1.0f; + + /** The filter is used to erode the terrain. */ + protected float filter = 0.5f; + + /** The range used to normalize terrain */ + private float heightRange = 1f; + + private final Random random = new Random(); + private boolean loaded = false; + + /** + * Constructor builds a new heightmap using the midpoint displacement algorithm. Roughness determines how chaotic + * the terrain will be. Where 1 is perfectly self-similar, > 1 early iterations have a disproportionately large + * effect creating smooth terrain, and < 1 late iteraions have a disproportionately large effect creating chaotic + * terrain. + * + * @param size + * the size of the terrain, must be a power of 2. + * @param roughness + * how chaotic to make the terrain. + * + * @throws Ardor3dException + * if size is less than or equal to zero or roughtness is less than 0. + */ + public MidPointHeightMapGenerator(final int size, final float roughness) { + if (!MathUtils.isPowerOfTwo(size)) { + throw new Ardor3dException("Size must be (2^N) sized."); + } + if (roughness < 0 || size <= 0) { + throw new Ardor3dException("size and roughness must be " + "greater than 0"); + } + this.roughness = roughness; + this.size = size; + } + + /** + * Constructor builds a new heightmap using the midpoint displacement algorithm. Roughness determines how chaotic + * the terrain will be. Where 1 is perfectly self-similar, > 1 early iterations have a disproportionately large + * effect creating smooth terrain, and < 1 late iteraions have a disproportionately large effect creating chaotic + * terrain. + * + * @param size + * the size of the terrain, must be a power of 2. + * @param roughness + * how chaotic to make the terrain. + * + * @throws Ardor3dException + * if size is less than or equal to zero or roughtness is less than 0. + */ + public MidPointHeightMapGenerator(final int size, final float roughness, final long seed) { + this(size, roughness); + random.setSeed(seed); + } + + /** + * @return the heightData + */ + public float[] getHeightData() { + if (!loaded) { + generateHeightData(); + } + return heightData; + } + + /** + * <code>load</code> generates the heightfield using the Midpoint Displacement algorithm. <code>load</code> uses the + * latest attributes, so a call to <code>load</code> is recommended if attributes have changed using the set + * methods. + */ + public boolean generateHeightData() { + float height; + double heightReducer; + float[][] tempBuffer; + + // holds the points of the square. + int ni, nj; + int mi, mj; + int pmi, pmj; + + height = 1f; + heightReducer = Math.pow(2, -1 * roughness); + + heightData = new float[size * size]; + tempBuffer = new float[size][size]; + + int counter = size; + while (counter > 0) { + // displace the center of the square. + for (int i = 0; i < size; i += counter) { + for (int j = 0; j < size; j += counter) { + // (0,0) point of the local square + ni = (i + counter) % size; + nj = (j + counter) % size; + // middle point of the local square + mi = i + counter / 2; + mj = j + counter / 2; + + // displace the middle point by the average of the + // corners, and a random value. + tempBuffer[mi][mj] = (tempBuffer[i][j] + tempBuffer[ni][j] + tempBuffer[i][nj] + tempBuffer[ni][nj]) + / 4 + random.nextFloat() * height - height / 2; + } + } + + // next calculate the new midpoints of the line segments. + for (int i = 0; i < size; i += counter) { + for (int j = 0; j < size; j += counter) { + // (0,0) of the local square + ni = (i + counter) % size; + nj = (j + counter) % size; + + // middle point of the local square. + mi = i + counter / 2; + mj = j + counter / 2; + + // middle point on the line in the x-axis direction. + pmi = (i - counter / 2 + size) % size; + // middle point on the line in the y-axis direction. + pmj = (j - counter / 2 + size) % size; + + // Calculate the square value for the top side of the rectangle + tempBuffer[mi][j] = (tempBuffer[i][j] + tempBuffer[ni][j] + tempBuffer[mi][pmj] + tempBuffer[mi][mj]) + / 4 + random.nextFloat() * height - height / 2; + + // Calculate the square value for the left side of the rectangle + tempBuffer[i][mj] = (tempBuffer[i][j] + tempBuffer[i][nj] + tempBuffer[pmi][mj] + tempBuffer[mi][mj]) + / 4 + random.nextFloat() * height - height / 2; + + } + } + + counter /= 2; + height *= heightReducer; + } + + normalizeTerrain(tempBuffer); + + // transfer the new terrain into the height map. + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + setHeightAtPoint(tempBuffer[i][j], i, j); + } + } + + MidPointHeightMapGenerator.logger.info("Created Heightmap using Mid Point"); + + loaded = true; + + return true; + } + + /** + * <code>setRoughness</code> sets the new roughness value of the heightmap. Roughness determines how chaotic the + * terrain will be. Where 1 is perfectly self-similar, > 1 early iterations have a disproportionately large effect + * creating smooth terrain, and < 1 late iteraions have a disproportionately large effect creating chaotic terrain. + * + * @param roughness + * how chaotic will the heightmap be. + */ + public void setRoughness(final float roughness) { + if (roughness < 0) { + throw new Ardor3dException("roughness must be greater than 0"); + } + this.roughness = roughness; + } + + /** + * <code>setHeightAtPoint</code> sets the height value for a given coordinate. + * + * @param height + * the new height for the coordinate. + * @param x + * the x (east/west) coordinate. + * @param z + * the z (north/south) coordinate. + */ + protected void setHeightAtPoint(final float height, final int x, final int z) { + heightData[x + z * size] = height; + } + + /** + * <code>normalizeTerrain</code> takes the current terrain data and converts it to values between 0 and + * NORMALIZE_RANGE. + * + * @param tempBuffer + * the terrain to normalize. + */ + protected void normalizeTerrain(final float[][] tempBuffer) { + float currentMin, currentMax; + float height; + + currentMin = tempBuffer[0][0]; + currentMax = tempBuffer[0][0]; + + // find the min/max values of the height fTemptemptempBuffer + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + if (tempBuffer[i][j] > currentMax) { + currentMax = tempBuffer[i][j]; + } else if (tempBuffer[i][j] < currentMin) { + currentMin = tempBuffer[i][j]; + } + } + } + + // find the range of the altitude + if (currentMax <= currentMin) { + return; + } + + height = currentMax - currentMin; + + // scale the values to a range of 0-255 + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + tempBuffer[i][j] = (tempBuffer[i][j] - currentMin) / height * heightRange; + } + } + } + + /** + * <code>erodeTerrain</code> is a convenience method that applies the FIR filter to a given height map. This + * simulates water errosion. + * + * @param tempBuffer + * the terrain to filter. + */ + protected void erodeTerrain(final float[][] tempBuffer) { + // erode left to right + float v; + + for (int i = 0; i < size; i++) { + v = tempBuffer[i][0]; + for (int j = 1; j < size; j++) { + tempBuffer[i][j] = filter * v + (1 - filter) * tempBuffer[i][j]; + v = tempBuffer[i][j]; + } + } + + // erode right to left + for (int i = size - 1; i >= 0; i--) { + v = tempBuffer[i][0]; + for (int j = 0; j < size; j++) { + tempBuffer[i][j] = filter * v + (1 - filter) * tempBuffer[i][j]; + v = tempBuffer[i][j]; + // erodeBand(tempBuffer[size * i + size - 1], -1); + } + } + + // erode top to bottom + for (int i = 0; i < size; i++) { + v = tempBuffer[0][i]; + for (int j = 0; j < size; j++) { + tempBuffer[j][i] = filter * v + (1 - filter) * tempBuffer[j][i]; + v = tempBuffer[j][i]; + } + } + + // erode from bottom to top + for (int i = size - 1; i >= 0; i--) { + v = tempBuffer[0][i]; + for (int j = 0; j < size; j++) { + tempBuffer[j][i] = filter * v + (1 - filter) * tempBuffer[j][i]; + v = tempBuffer[j][i]; + } + } + } + + public float getHeightRange() { + return heightRange; + } + + public void setHeightRange(final float heightRange) { + this.heightRange = heightRange; + } +} diff --git a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/heightmap/RawHeightMap.java b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/heightmap/RawHeightMap.java index b87bdb8..032f32d 100644 --- a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/heightmap/RawHeightMap.java +++ b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/heightmap/RawHeightMap.java @@ -1,246 +1,246 @@ -/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.terrain.heightmap;
-
-import java.io.BufferedInputStream;
-import java.io.DataInput;
-import java.io.DataInputStream;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.logging.Logger;
-
-import com.ardor3d.util.LittleEndianDataInput;
-
-public class RawHeightMap {
- private static final Logger logger = Logger.getLogger(RawHeightMap.class.getName());
-
- public enum HeightMapFormat {
- Byte, Short, UnsignedByte, UnsignedShort, Integer, Float
- }
-
- private HeightMapFormat format;
- private boolean isLittleEndian;
-
- private int size;
- private InputStream stream;
- private float heightData[];
-
- private boolean swapXY;
- private boolean flipX;
- private boolean flipY;
-
- private boolean loaded;
-
- public RawHeightMap(final String filename, final int size) throws Exception {
- // varify that filename and size are valid.
- if (null == filename || size <= 0) {
- throw new Exception("Must supply valid filename and " + "size (> 0)");
- }
- try {
- setup(new FileInputStream(filename), size);
- } catch (final FileNotFoundException e) {
- throw new Exception("height file not found: " + filename);
- }
- }
-
- public RawHeightMap(final InputStream stream, final int size) throws Exception {
- setup(stream, size);
- }
-
- public RawHeightMap(final URL resource, final int size) throws Exception {
- // varify that resource and size are valid.
- if (null == resource || size <= 0) {
- throw new Exception("Must supply valid resource and " + "size (> 0)");
- }
-
- try {
- setup(resource.openStream(), size);
- } catch (final IOException e) {
- throw new Exception("Unable to open height url: " + resource);
- }
- }
-
- private void setup(final InputStream stream, final int size) throws Exception {
- // varify that filename and size are valid.
- if (null == stream || size <= 0) {
- throw new Exception("Must supply valid stream and " + "size (> 0)");
- }
-
- this.stream = stream;
- this.size = size;
- }
-
- /**
- * <code>load</code> fills the height data array with the appropriate data from the set RAW image stream or file.
- *
- * @return true if the load is successful, false otherwise.
- */
- public boolean loadHeightmap() {
- // initialize the height data attributes
- heightData = new float[size * size];
-
- // attempt to connect to the supplied file.
- BufferedInputStream bis = null;
-
- try {
- bis = new BufferedInputStream(stream);
- final DataInputStream dis = new DataInputStream(bis);
- DataInput di = dis;
- if (isLittleEndian) {
- di = new LittleEndianDataInput(dis);
- }
-
- // read the raw file
- for (int y = 0; y < size; y++) {
- for (int x = 0; x < size; x++) {
- int index;
- int xIndex = x;
- int yIndex = y;
-
- if (flipX) {
- xIndex = size - x - 1;
- }
- if (flipY) {
- yIndex = size - y - 1;
- }
-
- if (swapXY) {
- index = xIndex * size + yIndex;
- } else {
- index = yIndex * size + xIndex;
- }
-
- switch (format) {
- case Byte:
- heightData[index] = di.readByte() * 0.5f / Byte.MAX_VALUE + 0.5f;
- break;
- case Short:
- heightData[index] = di.readShort() * 0.5f / Short.MAX_VALUE + 0.5f;
- break;
- case UnsignedByte:
- heightData[index] = di.readUnsignedByte() * 0.5f / Byte.MAX_VALUE;
- break;
- case UnsignedShort:
- heightData[index] = di.readUnsignedShort() * 0.5f / Short.MAX_VALUE;
- break;
- case Integer:
- heightData[index] = di.readInt() * 0.5f / Integer.MAX_VALUE + 0.5f;
- break;
- case Float:
- heightData[index] = di.readFloat() / Float.MAX_VALUE;
- break;
- }
- }
- }
- dis.close();
- } catch (final IOException e1) {
- logger.warning("Error reading height data from stream.");
- return false;
- }
- loaded = true;
- return true;
- }
-
- /**
- * @return the heightData
- */
- public float[] getHeightData() {
- if (!loaded) {
- loadHeightmap();
- }
- return heightData;
- }
-
- /**
- * @return the format
- */
- public HeightMapFormat getFormat() {
- return format;
- }
-
- /**
- * @param format
- * the format to set
- */
- public void setFormat(final HeightMapFormat format) {
- this.format = format;
- }
-
- /**
- * @return the isLittleEndian
- */
- public boolean isLittleEndian() {
- return isLittleEndian;
- }
-
- /**
- * @param isLittleEndian
- * the isLittleEndian to set
- */
- public void setLittleEndian(final boolean isLittleEndian) {
- this.isLittleEndian = isLittleEndian;
- }
-
- /**
- * @return the swapXY
- */
- public boolean isSwapXY() {
- return swapXY;
- }
-
- /**
- * @param swapXY
- * the swapXY to set
- */
- public void setSwapXY(final boolean swapXY) {
- this.swapXY = swapXY;
- }
-
- /**
- * @return the flipX
- */
- public boolean isFlipX() {
- return flipX;
- }
-
- /**
- * @param flipX
- * the flipX to set
- */
- public void setFlipX(final boolean flipX) {
- this.flipX = flipX;
- }
-
- /**
- * @return the flipY
- */
- public boolean isFlipY() {
- return flipY;
- }
-
- /**
- * @param flipY
- * the flipY to set
- */
- public void setFlipY(final boolean flipY) {
- this.flipY = flipY;
- }
-
- /**
- * @return the loaded
- */
- public boolean isLoaded() {
- return loaded;
- }
-}
+/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.terrain.heightmap; + +import java.io.BufferedInputStream; +import java.io.DataInput; +import java.io.DataInputStream; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.logging.Logger; + +import com.ardor3d.util.LittleEndianDataInput; + +public class RawHeightMap { + private static final Logger logger = Logger.getLogger(RawHeightMap.class.getName()); + + public enum HeightMapFormat { + Byte, Short, UnsignedByte, UnsignedShort, Integer, Float + } + + private HeightMapFormat format; + private boolean isLittleEndian; + + private int size; + private InputStream stream; + private float heightData[]; + + private boolean swapXY; + private boolean flipX; + private boolean flipY; + + private boolean loaded; + + public RawHeightMap(final String filename, final int size) throws Exception { + // varify that filename and size are valid. + if (null == filename || size <= 0) { + throw new Exception("Must supply valid filename and " + "size (> 0)"); + } + try { + setup(new FileInputStream(filename), size); + } catch (final FileNotFoundException e) { + throw new Exception("height file not found: " + filename); + } + } + + public RawHeightMap(final InputStream stream, final int size) throws Exception { + setup(stream, size); + } + + public RawHeightMap(final URL resource, final int size) throws Exception { + // varify that resource and size are valid. + if (null == resource || size <= 0) { + throw new Exception("Must supply valid resource and " + "size (> 0)"); + } + + try { + setup(resource.openStream(), size); + } catch (final IOException e) { + throw new Exception("Unable to open height url: " + resource); + } + } + + private void setup(final InputStream stream, final int size) throws Exception { + // varify that filename and size are valid. + if (null == stream || size <= 0) { + throw new Exception("Must supply valid stream and " + "size (> 0)"); + } + + this.stream = stream; + this.size = size; + } + + /** + * <code>load</code> fills the height data array with the appropriate data from the set RAW image stream or file. + * + * @return true if the load is successful, false otherwise. + */ + public boolean loadHeightmap() { + // initialize the height data attributes + heightData = new float[size * size]; + + // attempt to connect to the supplied file. + BufferedInputStream bis = null; + + try { + bis = new BufferedInputStream(stream); + final DataInputStream dis = new DataInputStream(bis); + DataInput di = dis; + if (isLittleEndian) { + di = new LittleEndianDataInput(dis); + } + + // read the raw file + for (int y = 0; y < size; y++) { + for (int x = 0; x < size; x++) { + int index; + int xIndex = x; + int yIndex = y; + + if (flipX) { + xIndex = size - x - 1; + } + if (flipY) { + yIndex = size - y - 1; + } + + if (swapXY) { + index = xIndex * size + yIndex; + } else { + index = yIndex * size + xIndex; + } + + switch (format) { + case Byte: + heightData[index] = di.readByte() * 0.5f / Byte.MAX_VALUE + 0.5f; + break; + case Short: + heightData[index] = di.readShort() * 0.5f / Short.MAX_VALUE + 0.5f; + break; + case UnsignedByte: + heightData[index] = di.readUnsignedByte() * 0.5f / Byte.MAX_VALUE; + break; + case UnsignedShort: + heightData[index] = di.readUnsignedShort() * 0.5f / Short.MAX_VALUE; + break; + case Integer: + heightData[index] = di.readInt() * 0.5f / Integer.MAX_VALUE + 0.5f; + break; + case Float: + heightData[index] = di.readFloat() / Float.MAX_VALUE; + break; + } + } + } + dis.close(); + } catch (final IOException e1) { + logger.warning("Error reading height data from stream."); + return false; + } + loaded = true; + return true; + } + + /** + * @return the heightData + */ + public float[] getHeightData() { + if (!loaded) { + loadHeightmap(); + } + return heightData; + } + + /** + * @return the format + */ + public HeightMapFormat getFormat() { + return format; + } + + /** + * @param format + * the format to set + */ + public void setFormat(final HeightMapFormat format) { + this.format = format; + } + + /** + * @return the isLittleEndian + */ + public boolean isLittleEndian() { + return isLittleEndian; + } + + /** + * @param isLittleEndian + * the isLittleEndian to set + */ + public void setLittleEndian(final boolean isLittleEndian) { + this.isLittleEndian = isLittleEndian; + } + + /** + * @return the swapXY + */ + public boolean isSwapXY() { + return swapXY; + } + + /** + * @param swapXY + * the swapXY to set + */ + public void setSwapXY(final boolean swapXY) { + this.swapXY = swapXY; + } + + /** + * @return the flipX + */ + public boolean isFlipX() { + return flipX; + } + + /** + * @param flipX + * the flipX to set + */ + public void setFlipX(final boolean flipX) { + this.flipX = flipX; + } + + /** + * @return the flipY + */ + public boolean isFlipY() { + return flipY; + } + + /** + * @param flipY + * the flipY to set + */ + public void setFlipY(final boolean flipY) { + this.flipY = flipY; + } + + /** + * @return the loaded + */ + public boolean isLoaded() { + return loaded; + } +} diff --git a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/array/ArrayTerrainDataProvider.java b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/array/ArrayTerrainDataProvider.java index 3e3b6ae..21e9062 100644 --- a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/array/ArrayTerrainDataProvider.java +++ b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/array/ArrayTerrainDataProvider.java @@ -1,135 +1,135 @@ -/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.terrain.providers.array;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-import com.ardor3d.extension.terrain.client.TerrainDataProvider;
-import com.ardor3d.extension.terrain.client.TerrainSource;
-import com.ardor3d.extension.terrain.client.TextureSource;
-import com.ardor3d.extension.terrain.providers.image.ImageTextureSource;
-import com.ardor3d.extension.terrain.util.NormalMapUtil;
-import com.ardor3d.image.Image;
-import com.ardor3d.math.type.ReadOnlyVector3;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-
-public class ArrayTerrainDataProvider implements TerrainDataProvider {
- private static final int tileSize = 128;
-
- private final List<float[]> heightMaps;
- private final List<Integer> heightMapSizes;
- private final ReadOnlyVector3 scale;
-
- private float heightMax = 1.0f;
- private float heightMin = 0.0f;
-
- private boolean generateNormalMap;
-
- public ArrayTerrainDataProvider(final float[] data, final int size, final ReadOnlyVector3 scale) {
- this(data, size, scale, false);
- }
-
- public ArrayTerrainDataProvider(final float[] data, final int size, final ReadOnlyVector3 scale,
- final boolean generateNormalMap) {
- this.scale = scale;
- this.generateNormalMap = generateNormalMap;
-
- // TODO: calculate clipLevelCount through size and tileSize
- final int clipLevelCount = 6;
-
- int currentSize = size;
- heightMaps = Lists.newArrayList();
- heightMapSizes = Lists.newArrayList();
- heightMaps.add(data);
- heightMapSizes.add(currentSize);
- float[] parentHeightMap = data;
- for (int i = 0; i < clipLevelCount; i++) {
- currentSize /= 2;
- final float[] heightMapMip = new float[currentSize * currentSize];
- heightMaps.add(heightMapMip);
- heightMapSizes.add(currentSize);
- for (int x = 0; x < currentSize; x++) {
- for (int z = 0; z < currentSize; z++) {
- heightMapMip[z * currentSize + x] = parentHeightMap[z * currentSize * 4 + x * 2];
- }
- }
- parentHeightMap = heightMapMip;
- }
-
- Collections.reverse(heightMaps);
- Collections.reverse(heightMapSizes);
- }
-
- @Override
- public Map<Integer, String> getAvailableMaps() throws Exception {
- final Map<Integer, String> maps = Maps.newHashMap();
- maps.put(0, "ArrayBasedMap");
-
- return maps;
- }
-
- @Override
- public TerrainSource getTerrainSource(final int mapId) {
- return new ArrayTerrainSource(tileSize, heightMaps, heightMapSizes, scale, heightMin, heightMax);
- }
-
- @Override
- public TextureSource getTextureSource(final int mapId) {
- return new ArrayTextureSource(tileSize, heightMaps, heightMapSizes);
- }
-
- @Override
- public TextureSource getNormalMapSource(final int mapId) {
- if (generateNormalMap) {
- try {
- final float[] data = heightMaps.get(heightMaps.size() - 1);
- final int size = heightMapSizes.get(heightMapSizes.size() - 1);
- final Image normalImage = NormalMapUtil.constructNormalMap(data, size, scale.getY() / heightMax,
- scale.getX(), scale.getZ());
- return new ImageTextureSource(tileSize, normalImage, heightMapSizes);
- } catch (final Exception e) {
- e.printStackTrace();
- }
- }
- return null;
- }
-
- public float getHeightMin() {
- return heightMin;
- }
-
- public void setHeightMin(final float heightMin) {
- this.heightMin = heightMin;
- }
-
- public float getHeightMax() {
- return heightMax;
- }
-
- public void setHeightMax(final float heightMax) {
- this.heightMax = heightMax;
- }
-
- public List<Integer> getHeightMapSizes() {
- return heightMapSizes;
- }
-
- public boolean isGenerateNormalMap() {
- return generateNormalMap;
- }
-
- public void setGenerateNormalMap(final boolean generateNormalMap) {
- this.generateNormalMap = generateNormalMap;
- }
-}
+/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.terrain.providers.array; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import com.ardor3d.extension.terrain.client.TerrainDataProvider; +import com.ardor3d.extension.terrain.client.TerrainSource; +import com.ardor3d.extension.terrain.client.TextureSource; +import com.ardor3d.extension.terrain.providers.image.ImageTextureSource; +import com.ardor3d.extension.terrain.util.NormalMapUtil; +import com.ardor3d.image.Image; +import com.ardor3d.math.type.ReadOnlyVector3; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; + +public class ArrayTerrainDataProvider implements TerrainDataProvider { + private static final int tileSize = 128; + + private final List<float[]> heightMaps; + private final List<Integer> heightMapSizes; + private final ReadOnlyVector3 scale; + + private float heightMax = 1.0f; + private float heightMin = 0.0f; + + private boolean generateNormalMap; + + public ArrayTerrainDataProvider(final float[] data, final int size, final ReadOnlyVector3 scale) { + this(data, size, scale, false); + } + + public ArrayTerrainDataProvider(final float[] data, final int size, final ReadOnlyVector3 scale, + final boolean generateNormalMap) { + this.scale = scale; + this.generateNormalMap = generateNormalMap; + + // TODO: calculate clipLevelCount through size and tileSize + final int clipLevelCount = 6; + + int currentSize = size; + heightMaps = Lists.newArrayList(); + heightMapSizes = Lists.newArrayList(); + heightMaps.add(data); + heightMapSizes.add(currentSize); + float[] parentHeightMap = data; + for (int i = 0; i < clipLevelCount; i++) { + currentSize /= 2; + final float[] heightMapMip = new float[currentSize * currentSize]; + heightMaps.add(heightMapMip); + heightMapSizes.add(currentSize); + for (int x = 0; x < currentSize; x++) { + for (int z = 0; z < currentSize; z++) { + heightMapMip[z * currentSize + x] = parentHeightMap[z * currentSize * 4 + x * 2]; + } + } + parentHeightMap = heightMapMip; + } + + Collections.reverse(heightMaps); + Collections.reverse(heightMapSizes); + } + + @Override + public Map<Integer, String> getAvailableMaps() throws Exception { + final Map<Integer, String> maps = Maps.newHashMap(); + maps.put(0, "ArrayBasedMap"); + + return maps; + } + + @Override + public TerrainSource getTerrainSource(final int mapId) { + return new ArrayTerrainSource(tileSize, heightMaps, heightMapSizes, scale, heightMin, heightMax); + } + + @Override + public TextureSource getTextureSource(final int mapId) { + return new ArrayTextureSource(tileSize, heightMaps, heightMapSizes); + } + + @Override + public TextureSource getNormalMapSource(final int mapId) { + if (generateNormalMap) { + try { + final float[] data = heightMaps.get(heightMaps.size() - 1); + final int size = heightMapSizes.get(heightMapSizes.size() - 1); + final Image normalImage = NormalMapUtil.constructNormalMap(data, size, scale.getY() / heightMax, + scale.getX(), scale.getZ()); + return new ImageTextureSource(tileSize, normalImage, heightMapSizes); + } catch (final Exception e) { + e.printStackTrace(); + } + } + return null; + } + + public float getHeightMin() { + return heightMin; + } + + public void setHeightMin(final float heightMin) { + this.heightMin = heightMin; + } + + public float getHeightMax() { + return heightMax; + } + + public void setHeightMax(final float heightMax) { + this.heightMax = heightMax; + } + + public List<Integer> getHeightMapSizes() { + return heightMapSizes; + } + + public boolean isGenerateNormalMap() { + return generateNormalMap; + } + + public void setGenerateNormalMap(final boolean generateNormalMap) { + this.generateNormalMap = generateNormalMap; + } +} diff --git a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/array/ArrayTerrainSource.java b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/array/ArrayTerrainSource.java index 71b6e04..990570c 100644 --- a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/array/ArrayTerrainSource.java +++ b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/array/ArrayTerrainSource.java @@ -1,111 +1,111 @@ -/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.terrain.providers.array;
-
-import java.util.List;
-import java.util.Set;
-
-import com.ardor3d.extension.terrain.client.TerrainConfiguration;
-import com.ardor3d.extension.terrain.client.TerrainSource;
-import com.ardor3d.extension.terrain.util.Tile;
-import com.ardor3d.math.type.ReadOnlyVector3;
-import com.google.common.collect.Sets;
-
-public class ArrayTerrainSource implements TerrainSource {
- private final int tileSize;
- private final List<float[]> heightMaps;
- private final List<Integer> heightMapSizes;
- private final ReadOnlyVector3 scale;
- private final float heightMin;
- private final float heightMax;
-
- private final ThreadLocal<float[]> tileDataPool = new ThreadLocal<float[]>() {
- @Override
- protected float[] initialValue() {
- return new float[tileSize * tileSize];
- }
- };
-
- public ArrayTerrainSource(final int tileSize, final List<float[]> heightMaps, final List<Integer> heightMapSizes,
- final ReadOnlyVector3 scale, final float heightMin, final float heightMax) {
- this.tileSize = tileSize;
- this.heightMaps = heightMaps;
- this.heightMapSizes = heightMapSizes;
- this.scale = scale;
- this.heightMin = heightMin;
- this.heightMax = heightMax;
- }
-
- @Override
- public TerrainConfiguration getConfiguration() throws Exception {
- return new TerrainConfiguration(heightMaps.size(), tileSize, scale, heightMin, heightMax, true);
- }
-
- @Override
- public Set<Tile> getValidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX,
- final int numTilesY) throws Exception {
- final Set<Tile> validTiles = Sets.newHashSet();
-
- final int heightMapSize = heightMapSizes.get(clipmapLevel);
- for (int y = 0; y < numTilesY; y++) {
- for (int x = 0; x < numTilesX; x++) {
- final int xx = tileX + x;
- final int yy = tileY + y;
- if (xx >= 0 && xx * tileSize <= heightMapSize && yy >= 0 && yy * tileSize <= heightMapSize) {
- final Tile tile = new Tile(xx, yy);
- validTiles.add(tile);
- }
- }
- }
-
- return validTiles;
- }
-
- @Override
- public Set<Tile> getInvalidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX,
- final int numTilesY) throws Exception {
- return null;
- }
-
- @Override
- public int getContributorId(final int clipmapLevel, final Tile tile) {
- return 0;
- }
-
- @Override
- public float[] getTile(final int clipmapLevel, final Tile tile) throws Exception {
- final int tileX = tile.getX();
- final int tileY = tile.getY();
-
- final float[] heightMap = heightMaps.get(clipmapLevel);
- final int heightMapSize = heightMapSizes.get(clipmapLevel);
-
- final float[] data = tileDataPool.get();
- for (int y = 0; y < tileSize; y++) {
- for (int x = 0; x < tileSize; x++) {
- final int index = x + y * tileSize;
-
- final int heightX = tileX * tileSize + x;
- final int heightY = tileY * tileSize + y;
- data[index] = getHeight(heightMap, heightMapSize, heightX, heightY);
- }
- }
- return data;
- }
-
- private float getHeight(final float[] heightMap, final int heightMapSize, final int x, final int y) {
- if (x < 0 || x >= heightMapSize || y < 0 || y >= heightMapSize) {
- return 0;
- }
-
- return heightMap[y * heightMapSize + x];
- }
-}
+/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.terrain.providers.array; + +import java.util.List; +import java.util.Set; + +import com.ardor3d.extension.terrain.client.TerrainConfiguration; +import com.ardor3d.extension.terrain.client.TerrainSource; +import com.ardor3d.extension.terrain.util.Tile; +import com.ardor3d.math.type.ReadOnlyVector3; +import com.google.common.collect.Sets; + +public class ArrayTerrainSource implements TerrainSource { + private final int tileSize; + private final List<float[]> heightMaps; + private final List<Integer> heightMapSizes; + private final ReadOnlyVector3 scale; + private final float heightMin; + private final float heightMax; + + private final ThreadLocal<float[]> tileDataPool = new ThreadLocal<float[]>() { + @Override + protected float[] initialValue() { + return new float[tileSize * tileSize]; + } + }; + + public ArrayTerrainSource(final int tileSize, final List<float[]> heightMaps, final List<Integer> heightMapSizes, + final ReadOnlyVector3 scale, final float heightMin, final float heightMax) { + this.tileSize = tileSize; + this.heightMaps = heightMaps; + this.heightMapSizes = heightMapSizes; + this.scale = scale; + this.heightMin = heightMin; + this.heightMax = heightMax; + } + + @Override + public TerrainConfiguration getConfiguration() throws Exception { + return new TerrainConfiguration(heightMaps.size(), tileSize, scale, heightMin, heightMax, true); + } + + @Override + public Set<Tile> getValidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX, + final int numTilesY) throws Exception { + final Set<Tile> validTiles = Sets.newHashSet(); + + final int heightMapSize = heightMapSizes.get(clipmapLevel); + for (int y = 0; y < numTilesY; y++) { + for (int x = 0; x < numTilesX; x++) { + final int xx = tileX + x; + final int yy = tileY + y; + if (xx >= 0 && xx * tileSize <= heightMapSize && yy >= 0 && yy * tileSize <= heightMapSize) { + final Tile tile = new Tile(xx, yy); + validTiles.add(tile); + } + } + } + + return validTiles; + } + + @Override + public Set<Tile> getInvalidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX, + final int numTilesY) throws Exception { + return null; + } + + @Override + public int getContributorId(final int clipmapLevel, final Tile tile) { + return 0; + } + + @Override + public float[] getTile(final int clipmapLevel, final Tile tile) throws Exception { + final int tileX = tile.getX(); + final int tileY = tile.getY(); + + final float[] heightMap = heightMaps.get(clipmapLevel); + final int heightMapSize = heightMapSizes.get(clipmapLevel); + + final float[] data = tileDataPool.get(); + for (int y = 0; y < tileSize; y++) { + for (int x = 0; x < tileSize; x++) { + final int index = x + y * tileSize; + + final int heightX = tileX * tileSize + x; + final int heightY = tileY * tileSize + y; + data[index] = getHeight(heightMap, heightMapSize, heightX, heightY); + } + } + return data; + } + + private float getHeight(final float[] heightMap, final int heightMapSize, final int x, final int y) { + if (x < 0 || x >= heightMapSize || y < 0 || y >= heightMapSize) { + return 0; + } + + return heightMap[y * heightMapSize + x]; + } +} diff --git a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/array/ArrayTextureSource.java b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/array/ArrayTextureSource.java index b97855f..218d39a 100644 --- a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/array/ArrayTextureSource.java +++ b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/array/ArrayTextureSource.java @@ -1,113 +1,113 @@ -/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.terrain.providers.array;
-
-import java.nio.ByteBuffer;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import com.ardor3d.extension.terrain.client.TextureConfiguration;
-import com.ardor3d.extension.terrain.client.TextureSource;
-import com.ardor3d.extension.terrain.util.Tile;
-import com.ardor3d.image.TextureStoreFormat;
-import com.ardor3d.util.geom.BufferUtils;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-
-public class ArrayTextureSource implements TextureSource {
- private final int tileSize;
- private final List<float[]> heightMaps;
- private final List<Integer> heightMapSizes;
-
- private final ThreadLocal<ByteBuffer> tileDataPool = new ThreadLocal<ByteBuffer>() {
- @Override
- protected ByteBuffer initialValue() {
- return BufferUtils.createByteBufferOnHeap(tileSize * tileSize);
- }
- };
-
- public ArrayTextureSource(final int tileSize, final List<float[]> heightMaps, final List<Integer> heightMapSizes) {
- this.tileSize = tileSize;
- this.heightMaps = heightMaps;
- this.heightMapSizes = heightMapSizes;
- }
-
- @Override
- public TextureConfiguration getConfiguration() throws Exception {
- final Map<Integer, TextureStoreFormat> textureStoreFormat = Maps.newHashMap();
- textureStoreFormat.put(0, TextureStoreFormat.Luminance8);
-
- return new TextureConfiguration(heightMaps.size(), textureStoreFormat, tileSize, 1f, true, false);
- }
-
- @Override
- public Set<Tile> getValidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX,
- final int numTilesY) throws Exception {
- final Set<Tile> validTiles = Sets.newHashSet();
-
- final int heightMapSize = heightMapSizes.get(clipmapLevel);
- for (int y = 0; y < numTilesY; y++) {
- for (int x = 0; x < numTilesX; x++) {
- final int xx = tileX + x;
- final int yy = tileY + y;
- if (xx >= 0 && xx * tileSize <= heightMapSize && yy >= 0 && yy * tileSize <= heightMapSize) {
- final Tile tile = new Tile(xx, yy);
- validTiles.add(tile);
- }
- }
- }
-
- return validTiles;
- }
-
- @Override
- public Set<Tile> getInvalidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX,
- final int numTilesY) throws Exception {
- return null;
- }
-
- @Override
- public int getContributorId(final int clipmapLevel, final Tile tile) {
- return 0;
- }
-
- @Override
- public ByteBuffer getTile(final int clipmapLevel, final Tile tile) throws Exception {
- final int tileX = tile.getX();
- final int tileY = tile.getY();
-
- final float[] heightMap = heightMaps.get(clipmapLevel);
- final int heightMapSize = heightMapSizes.get(clipmapLevel);
-
- final ByteBuffer data = tileDataPool.get();
- for (int y = 0; y < tileSize; y++) {
- for (int x = 0; x < tileSize; x++) {
- final int index = (x + y * tileSize) * 1;
-
- final int heightX = tileX * tileSize + x;
- final int heightY = tileY * tileSize + y;
- final float height = getHeight(heightMap, heightMapSize, heightX, heightY);
- final byte byteHeight = (byte) (height * 255 * 3);
- data.put(index, byteHeight);
- }
- }
- return data;
- }
-
- private float getHeight(final float[] heightMap, final int heightMapSize, final int x, final int y) {
- if (x < 0 || x >= heightMapSize || y < 0 || y >= heightMapSize) {
- return 0;
- }
-
- return heightMap[y * heightMapSize + x];
- }
-}
+/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.terrain.providers.array; + +import java.nio.ByteBuffer; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.ardor3d.extension.terrain.client.TextureConfiguration; +import com.ardor3d.extension.terrain.client.TextureSource; +import com.ardor3d.extension.terrain.util.Tile; +import com.ardor3d.image.TextureStoreFormat; +import com.ardor3d.util.geom.BufferUtils; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +public class ArrayTextureSource implements TextureSource { + private final int tileSize; + private final List<float[]> heightMaps; + private final List<Integer> heightMapSizes; + + private final ThreadLocal<ByteBuffer> tileDataPool = new ThreadLocal<ByteBuffer>() { + @Override + protected ByteBuffer initialValue() { + return BufferUtils.createByteBufferOnHeap(tileSize * tileSize); + } + }; + + public ArrayTextureSource(final int tileSize, final List<float[]> heightMaps, final List<Integer> heightMapSizes) { + this.tileSize = tileSize; + this.heightMaps = heightMaps; + this.heightMapSizes = heightMapSizes; + } + + @Override + public TextureConfiguration getConfiguration() throws Exception { + final Map<Integer, TextureStoreFormat> textureStoreFormat = Maps.newHashMap(); + textureStoreFormat.put(0, TextureStoreFormat.Luminance8); + + return new TextureConfiguration(heightMaps.size(), textureStoreFormat, tileSize, 1f, true, false); + } + + @Override + public Set<Tile> getValidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX, + final int numTilesY) throws Exception { + final Set<Tile> validTiles = Sets.newHashSet(); + + final int heightMapSize = heightMapSizes.get(clipmapLevel); + for (int y = 0; y < numTilesY; y++) { + for (int x = 0; x < numTilesX; x++) { + final int xx = tileX + x; + final int yy = tileY + y; + if (xx >= 0 && xx * tileSize <= heightMapSize && yy >= 0 && yy * tileSize <= heightMapSize) { + final Tile tile = new Tile(xx, yy); + validTiles.add(tile); + } + } + } + + return validTiles; + } + + @Override + public Set<Tile> getInvalidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX, + final int numTilesY) throws Exception { + return null; + } + + @Override + public int getContributorId(final int clipmapLevel, final Tile tile) { + return 0; + } + + @Override + public ByteBuffer getTile(final int clipmapLevel, final Tile tile) throws Exception { + final int tileX = tile.getX(); + final int tileY = tile.getY(); + + final float[] heightMap = heightMaps.get(clipmapLevel); + final int heightMapSize = heightMapSizes.get(clipmapLevel); + + final ByteBuffer data = tileDataPool.get(); + for (int y = 0; y < tileSize; y++) { + for (int x = 0; x < tileSize; x++) { + final int index = (x + y * tileSize) * 1; + + final int heightX = tileX * tileSize + x; + final int heightY = tileY * tileSize + y; + final float height = getHeight(heightMap, heightMapSize, heightX, heightY); + final byte byteHeight = (byte) (height * 255 * 3); + data.put(index, byteHeight); + } + } + return data; + } + + private float getHeight(final float[] heightMap, final int heightMapSize, final int x, final int y) { + if (x < 0 || x >= heightMapSize || y < 0 || y >= heightMapSize) { + return 0; + } + + return heightMap[y * heightMapSize + x]; + } +} diff --git a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/awt/AwtTextureSource.java b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/awt/AwtTextureSource.java index ed6b903..e83be4a 100644 --- a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/awt/AwtTextureSource.java +++ b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/awt/AwtTextureSource.java @@ -1,231 +1,231 @@ -/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.terrain.providers.awt;
-
-import java.awt.AlphaComposite;
-import java.awt.Composite;
-import java.awt.Graphics2D;
-import java.awt.image.BufferedImage;
-import java.awt.image.DataBufferInt;
-import java.nio.ByteBuffer;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import com.ardor3d.extension.terrain.client.TextureConfiguration;
-import com.ardor3d.extension.terrain.client.TextureSource;
-import com.ardor3d.extension.terrain.util.Tile;
-import com.ardor3d.image.TextureStoreFormat;
-import com.ardor3d.math.MathUtils;
-import com.ardor3d.math.Transform;
-import com.ardor3d.math.type.ReadOnlyVector4;
-import com.ardor3d.util.geom.BufferUtils;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-
-public class AwtTextureSource implements TextureSource, ElementUpdateListener {
- private static final int tileSize = 128;
- private final int availableClipmapLevels;
-
- private final AwtElementProvider provider;
- private final TextureStoreFormat format;
- private final boolean hasAlpha;
-
- private final BufferedImage _image[];
- private final Set<Tile> _updatedTiles[];
-
- private final ThreadLocal<byte[]> tileDataPool = new ThreadLocal<byte[]>() {
- @Override
- protected byte[] initialValue() {
- return new byte[tileSize * tileSize * (hasAlpha ? 4 : 3)];
- }
- };
-
- @SuppressWarnings("unchecked")
- public AwtTextureSource(final int availableClipmapLevels, final TextureStoreFormat format) {
- if (format != TextureStoreFormat.RGB8 && format != TextureStoreFormat.RGBA8) {
- throw new IllegalArgumentException("Only RGB8 and RGBA8 currently supported.");
- }
-
- this.availableClipmapLevels = availableClipmapLevels;
- this.format = format;
- hasAlpha = format == TextureStoreFormat.RGBA8;
-
- _image = new BufferedImage[availableClipmapLevels];
- _updatedTiles = new Set[availableClipmapLevels];
-
- provider = new AwtElementProvider();
- provider.addElementUpdateListener(this);
-
- for (int i = 0; i < availableClipmapLevels; i++) {
- _image[i] = new BufferedImage(tileSize, tileSize, BufferedImage.TYPE_INT_ARGB);
- _updatedTiles[i] = Sets.newHashSet();
- }
- }
-
- public AwtElementProvider getProvider() {
- return provider;
- }
-
- @Override
- public TextureConfiguration getConfiguration() throws Exception {
- final Map<Integer, TextureStoreFormat> textureStoreFormat = Maps.newHashMap();
- textureStoreFormat.put(0, format);
-
- return new TextureConfiguration(availableClipmapLevels, textureStoreFormat, tileSize, 1f, false, true);
- }
-
- @Override
- public Set<Tile> getValidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX,
- final int numTilesY) throws Exception {
- return null;
- }
-
- @Override
- public Set<Tile> getInvalidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX,
- final int numTilesY) throws Exception {
- final int baseClipmapLevel = availableClipmapLevels - clipmapLevel - 1;
-
- if (_updatedTiles[baseClipmapLevel].isEmpty()) {
- return null;
- }
-
- final Set<Tile> tiles = Sets.newHashSet();
-
- int checkX, checkY;
- for (final Iterator<Tile> it = _updatedTiles[baseClipmapLevel].iterator(); it.hasNext();) {
- final Tile tile = it.next();
- checkX = tile.getX();
- checkY = tile.getY();
- if (checkX >= tileX && checkX < tileX + numTilesX && checkY >= tileY && checkY < tileY + numTilesY) {
- tiles.add(tile);
- it.remove();
- }
- }
-
- return tiles;
- }
-
- @Override
- public int getContributorId(final int clipmapLevel, final Tile sourceTile) {
- return 0;
- }
-
- @Override
- public ByteBuffer getTile(final int clipmapLevel, final Tile tile) throws Exception {
- final int tileX = tile.getX();
- final int tileY = tile.getY();
-
- final int baseClipmapLevel = availableClipmapLevels - clipmapLevel - 1;
-
- // build a transform that would take us to the local space of the tile.
- final Transform localTransform = new Transform();
- localTransform.setTranslation(-tileX * tileSize, -tileY * tileSize, 0);
- final double scale = 1.0 / MathUtils.pow2(baseClipmapLevel);
- localTransform.setScale(scale);
-
- final double tileInScale = MathUtils.pow2(baseClipmapLevel) * tileSize;
- final double minX = tileInScale * tileX;
- final double minY = tileInScale * tileY;
- final double maxX = minX + tileInScale - 1;
- final double maxY = minY + tileInScale - 1;
-
- // Clear image
- final Graphics2D graphics = (Graphics2D) _image[baseClipmapLevel].getGraphics();
- final Composite composite = graphics.getComposite();
- // TODO: Add: do regular clear with black if no alpha channel right?
- graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
- graphics.fillRect(0, 0, tileSize, tileSize);
- graphics.setComposite(composite);
-
- // get list of elements that intersect the given region
- final List<AbstractAwtElement> elements = Lists.newArrayList(provider.getElements());
- for (final Iterator<AbstractAwtElement> it = elements.iterator(); it.hasNext();) {
- final AbstractAwtElement element = it.next();
-
- // check bounds to toss it or keep it.
- final ReadOnlyVector4 bounds = element.getBounds();
-
- if (bounds.getX() > maxX || bounds.getX() + bounds.getZ() <= minX || bounds.getY() > maxY
- || bounds.getY() + bounds.getW() <= minY) {
- // toss it
- it.remove();
- }
- }
-
- // make our buffer - init to all 0's
- final ByteBuffer data = BufferUtils.createByteBufferOnHeap(tileSize * tileSize * (hasAlpha ? 4 : 3));
-
- // shortcut - no data, return buffer.
- if (elements.isEmpty()) {
- // graphics.setBackground((tileX + tileY) % 2 == 0 ? Color.GREEN : Color.GRAY);
- // graphics.clearRect(0, 0, tileSize, tileSize);
- return data;
- }
-
- // otherwise draw... for each element, apply to our image.
- for (final AbstractAwtElement element : elements) {
- element.drawTo(_image[baseClipmapLevel], localTransform, clipmapLevel);
- }
-
- // if (clipmapLevel == 0) {
- // graphics.setBackground((tileX + tileY) % 2 == 0 ? Color.GREEN : Color.GRAY);
- // graphics.clearRect(0, 0, tileSize, tileSize);
- // }
-
- // grab image contents to buffer
- final byte[] byteArray = tileDataPool.get();
- final DataBufferInt dataBuffer = (DataBufferInt) _image[baseClipmapLevel].getData().getDataBuffer();
- final int[] tmpData = dataBuffer.getData();
- int index = 0;
- for (int i = 0; i < tileSize * tileSize; i++) {
- final int argb = tmpData[i];
- byteArray[index++] = (byte) (argb >> 16 & 0xFF);
- byteArray[index++] = (byte) (argb >> 8 & 0xFF);
- byteArray[index++] = (byte) (argb & 0xFF);
- if (hasAlpha) {
- byteArray[index++] = (byte) (argb >> 24 & 0xFF);
- }
- }
-
- data.put(byteArray);
- data.flip();
-
- // return buffer
- return data;
- }
-
- @Override
- public void elementUpdated(final ReadOnlyVector4 oldBounds, final ReadOnlyVector4 newBounds) {
- addTiles(oldBounds);
- addTiles(newBounds);
- }
-
- protected void addTiles(final ReadOnlyVector4 bounds) {
- for (int i = 0; i < availableClipmapLevels; i++) {
- final double scale = 1.0 / (tileSize * MathUtils.pow2(i));
- final int minX = (int) MathUtils.floor(bounds.getX() * scale);
- final int minY = (int) MathUtils.floor(bounds.getY() * scale);
- final int maxX = (int) MathUtils.floor((bounds.getX() + bounds.getZ() - 1) * scale);
- final int maxY = (int) MathUtils.floor((bounds.getY() + bounds.getW() - 1) * scale);
-
- Tile tile;
- for (int y = minY; y <= maxY; y++) {
- for (int x = minX; x <= maxX; x++) {
- tile = new Tile(x, y);
- _updatedTiles[i].add(tile);
- }
- }
- }
- }
-}
+/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.terrain.providers.awt; + +import java.awt.AlphaComposite; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferInt; +import java.nio.ByteBuffer; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.ardor3d.extension.terrain.client.TextureConfiguration; +import com.ardor3d.extension.terrain.client.TextureSource; +import com.ardor3d.extension.terrain.util.Tile; +import com.ardor3d.image.TextureStoreFormat; +import com.ardor3d.math.MathUtils; +import com.ardor3d.math.Transform; +import com.ardor3d.math.type.ReadOnlyVector4; +import com.ardor3d.util.geom.BufferUtils; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +public class AwtTextureSource implements TextureSource, ElementUpdateListener { + private static final int tileSize = 128; + private final int availableClipmapLevels; + + private final AwtElementProvider provider; + private final TextureStoreFormat format; + private final boolean hasAlpha; + + private final BufferedImage _image[]; + private final Set<Tile> _updatedTiles[]; + + private final ThreadLocal<byte[]> tileDataPool = new ThreadLocal<byte[]>() { + @Override + protected byte[] initialValue() { + return new byte[tileSize * tileSize * (hasAlpha ? 4 : 3)]; + } + }; + + @SuppressWarnings("unchecked") + public AwtTextureSource(final int availableClipmapLevels, final TextureStoreFormat format) { + if (format != TextureStoreFormat.RGB8 && format != TextureStoreFormat.RGBA8) { + throw new IllegalArgumentException("Only RGB8 and RGBA8 currently supported."); + } + + this.availableClipmapLevels = availableClipmapLevels; + this.format = format; + hasAlpha = format == TextureStoreFormat.RGBA8; + + _image = new BufferedImage[availableClipmapLevels]; + _updatedTiles = new Set[availableClipmapLevels]; + + provider = new AwtElementProvider(); + provider.addElementUpdateListener(this); + + for (int i = 0; i < availableClipmapLevels; i++) { + _image[i] = new BufferedImage(tileSize, tileSize, BufferedImage.TYPE_INT_ARGB); + _updatedTiles[i] = Sets.newHashSet(); + } + } + + public AwtElementProvider getProvider() { + return provider; + } + + @Override + public TextureConfiguration getConfiguration() throws Exception { + final Map<Integer, TextureStoreFormat> textureStoreFormat = Maps.newHashMap(); + textureStoreFormat.put(0, format); + + return new TextureConfiguration(availableClipmapLevels, textureStoreFormat, tileSize, 1f, false, true); + } + + @Override + public Set<Tile> getValidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX, + final int numTilesY) throws Exception { + return null; + } + + @Override + public Set<Tile> getInvalidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX, + final int numTilesY) throws Exception { + final int baseClipmapLevel = availableClipmapLevels - clipmapLevel - 1; + + if (_updatedTiles[baseClipmapLevel].isEmpty()) { + return null; + } + + final Set<Tile> tiles = Sets.newHashSet(); + + int checkX, checkY; + for (final Iterator<Tile> it = _updatedTiles[baseClipmapLevel].iterator(); it.hasNext();) { + final Tile tile = it.next(); + checkX = tile.getX(); + checkY = tile.getY(); + if (checkX >= tileX && checkX < tileX + numTilesX && checkY >= tileY && checkY < tileY + numTilesY) { + tiles.add(tile); + it.remove(); + } + } + + return tiles; + } + + @Override + public int getContributorId(final int clipmapLevel, final Tile sourceTile) { + return 0; + } + + @Override + public ByteBuffer getTile(final int clipmapLevel, final Tile tile) throws Exception { + final int tileX = tile.getX(); + final int tileY = tile.getY(); + + final int baseClipmapLevel = availableClipmapLevels - clipmapLevel - 1; + + // build a transform that would take us to the local space of the tile. + final Transform localTransform = new Transform(); + localTransform.setTranslation(-tileX * tileSize, -tileY * tileSize, 0); + final double scale = 1.0 / MathUtils.pow2(baseClipmapLevel); + localTransform.setScale(scale); + + final double tileInScale = MathUtils.pow2(baseClipmapLevel) * tileSize; + final double minX = tileInScale * tileX; + final double minY = tileInScale * tileY; + final double maxX = minX + tileInScale - 1; + final double maxY = minY + tileInScale - 1; + + // Clear image + final Graphics2D graphics = (Graphics2D) _image[baseClipmapLevel].getGraphics(); + final Composite composite = graphics.getComposite(); + // TODO: Add: do regular clear with black if no alpha channel right? + graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR)); + graphics.fillRect(0, 0, tileSize, tileSize); + graphics.setComposite(composite); + + // get list of elements that intersect the given region + final List<AbstractAwtElement> elements = Lists.newArrayList(provider.getElements()); + for (final Iterator<AbstractAwtElement> it = elements.iterator(); it.hasNext();) { + final AbstractAwtElement element = it.next(); + + // check bounds to toss it or keep it. + final ReadOnlyVector4 bounds = element.getBounds(); + + if (bounds.getX() > maxX || bounds.getX() + bounds.getZ() <= minX || bounds.getY() > maxY + || bounds.getY() + bounds.getW() <= minY) { + // toss it + it.remove(); + } + } + + // make our buffer - init to all 0's + final ByteBuffer data = BufferUtils.createByteBufferOnHeap(tileSize * tileSize * (hasAlpha ? 4 : 3)); + + // shortcut - no data, return buffer. + if (elements.isEmpty()) { + // graphics.setBackground((tileX + tileY) % 2 == 0 ? Color.GREEN : Color.GRAY); + // graphics.clearRect(0, 0, tileSize, tileSize); + return data; + } + + // otherwise draw... for each element, apply to our image. + for (final AbstractAwtElement element : elements) { + element.drawTo(_image[baseClipmapLevel], localTransform, clipmapLevel); + } + + // if (clipmapLevel == 0) { + // graphics.setBackground((tileX + tileY) % 2 == 0 ? Color.GREEN : Color.GRAY); + // graphics.clearRect(0, 0, tileSize, tileSize); + // } + + // grab image contents to buffer + final byte[] byteArray = tileDataPool.get(); + final DataBufferInt dataBuffer = (DataBufferInt) _image[baseClipmapLevel].getData().getDataBuffer(); + final int[] tmpData = dataBuffer.getData(); + int index = 0; + for (int i = 0; i < tileSize * tileSize; i++) { + final int argb = tmpData[i]; + byteArray[index++] = (byte) (argb >> 16 & 0xFF); + byteArray[index++] = (byte) (argb >> 8 & 0xFF); + byteArray[index++] = (byte) (argb & 0xFF); + if (hasAlpha) { + byteArray[index++] = (byte) (argb >> 24 & 0xFF); + } + } + + data.put(byteArray); + data.flip(); + + // return buffer + return data; + } + + @Override + public void elementUpdated(final ReadOnlyVector4 oldBounds, final ReadOnlyVector4 newBounds) { + addTiles(oldBounds); + addTiles(newBounds); + } + + protected void addTiles(final ReadOnlyVector4 bounds) { + for (int i = 0; i < availableClipmapLevels; i++) { + final double scale = 1.0 / (tileSize * MathUtils.pow2(i)); + final int minX = (int) MathUtils.floor(bounds.getX() * scale); + final int minY = (int) MathUtils.floor(bounds.getY() * scale); + final int maxX = (int) MathUtils.floor((bounds.getX() + bounds.getZ() - 1) * scale); + final int maxY = (int) MathUtils.floor((bounds.getY() + bounds.getW() - 1) * scale); + + Tile tile; + for (int y = minY; y <= maxY; y++) { + for (int x = minX; x <= maxX; x++) { + tile = new Tile(x, y); + _updatedTiles[i].add(tile); + } + } + } + } +} diff --git a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/image/ImageTextureSource.java b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/image/ImageTextureSource.java index 9deb52c..68e0bdc 100644 --- a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/image/ImageTextureSource.java +++ b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/image/ImageTextureSource.java @@ -1,140 +1,140 @@ -/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.terrain.providers.image;
-
-import java.nio.ByteBuffer;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import com.ardor3d.extension.terrain.client.TextureConfiguration;
-import com.ardor3d.extension.terrain.client.TextureSource;
-import com.ardor3d.extension.terrain.util.Tile;
-import com.ardor3d.image.Image;
-import com.ardor3d.image.TextureStoreFormat;
-import com.ardor3d.util.geom.BufferUtils;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-
-public class ImageTextureSource implements TextureSource {
- private final int tileSize;
- private final List<byte[]> maps;
- private final List<Integer> heightMapSizes;
-
- private final ThreadLocal<ByteBuffer> tileDataPool = new ThreadLocal<ByteBuffer>() {
- @Override
- protected ByteBuffer initialValue() {
- return BufferUtils.createByteBufferOnHeap(tileSize * tileSize * 3);
- }
- };
-
- public ImageTextureSource(final int tileSize, final Image map, final List<Integer> heightMapSizes) {
- this.tileSize = tileSize;
- maps = Lists.newArrayListWithExpectedSize(heightMapSizes.size());
- this.heightMapSizes = Lists.newArrayList(heightMapSizes);
- buildMips(map);
- }
-
- private void buildMips(final Image map) {
- final int max = heightMapSizes.size();
- int currentSize = heightMapSizes.get(max - 1);
- byte[] parentHeightMap = new byte[currentSize * currentSize * 3];
- // populate parentHeightMap from image
- map.getData(0).get(parentHeightMap);
-
- maps.add(parentHeightMap);
- // populate mips
- for (int i = 1; i < max; i++) {
- currentSize = heightMapSizes.get(max - i - 1);
- final byte[] heightMapMip = new byte[currentSize * currentSize * 3];
- for (int x = 0; x < currentSize; x++) {
- for (int z = 0; z < currentSize; z++) {
- heightMapMip[3 * (z * currentSize + x) + 0] = parentHeightMap[3 * (z * currentSize * 4 + x * 2) + 0];
- heightMapMip[3 * (z * currentSize + x) + 1] = parentHeightMap[3 * (z * currentSize * 4 + x * 2) + 1];
- heightMapMip[3 * (z * currentSize + x) + 2] = parentHeightMap[3 * (z * currentSize * 4 + x * 2) + 2];
- }
- }
- parentHeightMap = heightMapMip;
- maps.add(parentHeightMap);
- }
- Collections.reverse(maps);
- }
-
- @Override
- public TextureConfiguration getConfiguration() throws Exception {
- final Map<Integer, TextureStoreFormat> textureStoreFormat = Maps.newHashMap();
- textureStoreFormat.put(0, TextureStoreFormat.RGB8);
-
- return new TextureConfiguration(maps.size(), textureStoreFormat, tileSize, 1f, true, false);
- }
-
- @Override
- public Set<Tile> getValidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX,
- final int numTilesY) throws Exception {
- final Set<Tile> validTiles = Sets.newHashSet();
-
- final int heightMapSize = heightMapSizes.get(clipmapLevel);
- for (int y = 0; y < numTilesY; y++) {
- for (int x = 0; x < numTilesX; x++) {
- final int xx = tileX + x;
- final int yy = tileY + y;
- if (xx >= 0 && xx * tileSize <= heightMapSize && yy >= 0 && yy * tileSize <= heightMapSize) {
- final Tile tile = new Tile(xx, yy);
- validTiles.add(tile);
- }
- }
- }
-
- return validTiles;
- }
-
- @Override
- public Set<Tile> getInvalidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX,
- final int numTilesY) throws Exception {
- return null;
- }
-
- @Override
- public int getContributorId(final int clipmapLevel, final Tile tile) {
- return 0;
- }
-
- @Override
- public ByteBuffer getTile(final int clipmapLevel, final Tile tile) throws Exception {
- final int tileX = tile.getX();
- final int tileY = tile.getY();
-
- final byte[] heightMap = maps.get(clipmapLevel);
- final int heightMapSize = heightMapSizes.get(clipmapLevel);
-
- final ByteBuffer data = tileDataPool.get();
- for (int y = 0; y < tileSize; y++) {
- for (int x = 0; x < tileSize; x++) {
- final int index = x + y * tileSize;
-
- final int heightX = tileX * tileSize + x;
- final int heightY = tileY * tileSize + y;
- if (heightX < 0 || heightX >= heightMapSize || heightY < 0 || heightY >= heightMapSize) {
- data.put(index * 3 + 0, (byte) 0);
- data.put(index * 3 + 1, (byte) 0);
- data.put(index * 3 + 2, (byte) 0);
- } else {
- data.put(index * 3 + 0, heightMap[3 * (heightY * heightMapSize + heightX) + 0]);
- data.put(index * 3 + 1, heightMap[3 * (heightY * heightMapSize + heightX) + 1]);
- data.put(index * 3 + 2, heightMap[3 * (heightY * heightMapSize + heightX) + 2]);
- }
- }
- }
- return data;
- }
-}
+/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.terrain.providers.image; + +import java.nio.ByteBuffer; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.ardor3d.extension.terrain.client.TextureConfiguration; +import com.ardor3d.extension.terrain.client.TextureSource; +import com.ardor3d.extension.terrain.util.Tile; +import com.ardor3d.image.Image; +import com.ardor3d.image.TextureStoreFormat; +import com.ardor3d.util.geom.BufferUtils; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +public class ImageTextureSource implements TextureSource { + private final int tileSize; + private final List<byte[]> maps; + private final List<Integer> heightMapSizes; + + private final ThreadLocal<ByteBuffer> tileDataPool = new ThreadLocal<ByteBuffer>() { + @Override + protected ByteBuffer initialValue() { + return BufferUtils.createByteBufferOnHeap(tileSize * tileSize * 3); + } + }; + + public ImageTextureSource(final int tileSize, final Image map, final List<Integer> heightMapSizes) { + this.tileSize = tileSize; + maps = Lists.newArrayListWithExpectedSize(heightMapSizes.size()); + this.heightMapSizes = Lists.newArrayList(heightMapSizes); + buildMips(map); + } + + private void buildMips(final Image map) { + final int max = heightMapSizes.size(); + int currentSize = heightMapSizes.get(max - 1); + byte[] parentHeightMap = new byte[currentSize * currentSize * 3]; + // populate parentHeightMap from image + map.getData(0).get(parentHeightMap); + + maps.add(parentHeightMap); + // populate mips + for (int i = 1; i < max; i++) { + currentSize = heightMapSizes.get(max - i - 1); + final byte[] heightMapMip = new byte[currentSize * currentSize * 3]; + for (int x = 0; x < currentSize; x++) { + for (int z = 0; z < currentSize; z++) { + heightMapMip[3 * (z * currentSize + x) + 0] = parentHeightMap[3 * (z * currentSize * 4 + x * 2) + 0]; + heightMapMip[3 * (z * currentSize + x) + 1] = parentHeightMap[3 * (z * currentSize * 4 + x * 2) + 1]; + heightMapMip[3 * (z * currentSize + x) + 2] = parentHeightMap[3 * (z * currentSize * 4 + x * 2) + 2]; + } + } + parentHeightMap = heightMapMip; + maps.add(parentHeightMap); + } + Collections.reverse(maps); + } + + @Override + public TextureConfiguration getConfiguration() throws Exception { + final Map<Integer, TextureStoreFormat> textureStoreFormat = Maps.newHashMap(); + textureStoreFormat.put(0, TextureStoreFormat.RGB8); + + return new TextureConfiguration(maps.size(), textureStoreFormat, tileSize, 1f, true, false); + } + + @Override + public Set<Tile> getValidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX, + final int numTilesY) throws Exception { + final Set<Tile> validTiles = Sets.newHashSet(); + + final int heightMapSize = heightMapSizes.get(clipmapLevel); + for (int y = 0; y < numTilesY; y++) { + for (int x = 0; x < numTilesX; x++) { + final int xx = tileX + x; + final int yy = tileY + y; + if (xx >= 0 && xx * tileSize <= heightMapSize && yy >= 0 && yy * tileSize <= heightMapSize) { + final Tile tile = new Tile(xx, yy); + validTiles.add(tile); + } + } + } + + return validTiles; + } + + @Override + public Set<Tile> getInvalidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX, + final int numTilesY) throws Exception { + return null; + } + + @Override + public int getContributorId(final int clipmapLevel, final Tile tile) { + return 0; + } + + @Override + public ByteBuffer getTile(final int clipmapLevel, final Tile tile) throws Exception { + final int tileX = tile.getX(); + final int tileY = tile.getY(); + + final byte[] heightMap = maps.get(clipmapLevel); + final int heightMapSize = heightMapSizes.get(clipmapLevel); + + final ByteBuffer data = tileDataPool.get(); + for (int y = 0; y < tileSize; y++) { + for (int x = 0; x < tileSize; x++) { + final int index = x + y * tileSize; + + final int heightX = tileX * tileSize + x; + final int heightY = tileY * tileSize + y; + if (heightX < 0 || heightX >= heightMapSize || heightY < 0 || heightY >= heightMapSize) { + data.put(index * 3 + 0, (byte) 0); + data.put(index * 3 + 1, (byte) 0); + data.put(index * 3 + 2, (byte) 0); + } else { + data.put(index * 3 + 0, heightMap[3 * (heightY * heightMapSize + heightX) + 0]); + data.put(index * 3 + 1, heightMap[3 * (heightY * heightMapSize + heightX) + 1]); + data.put(index * 3 + 2, heightMap[3 * (heightY * heightMapSize + heightX) + 2]); + } + } + } + return data; + } +} diff --git a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/inmemory/InMemoryTerrainDataProvider.java b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/inmemory/InMemoryTerrainDataProvider.java index e737243..4df7c3b 100644 --- a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/inmemory/InMemoryTerrainDataProvider.java +++ b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/inmemory/InMemoryTerrainDataProvider.java @@ -1,89 +1,89 @@ -/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.terrain.providers.inmemory;
-
-import java.util.List;
-import java.util.Map;
-
-import com.ardor3d.extension.terrain.client.TerrainDataProvider;
-import com.ardor3d.extension.terrain.client.TerrainSource;
-import com.ardor3d.extension.terrain.client.TextureSource;
-import com.ardor3d.extension.terrain.providers.image.ImageTextureSource;
-import com.ardor3d.extension.terrain.providers.inmemory.data.InMemoryTerrainData;
-import com.ardor3d.extension.terrain.util.NormalMapUtil;
-import com.ardor3d.image.Image;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-
-public class InMemoryTerrainDataProvider implements TerrainDataProvider {
- private static final int tileSize = 128;
- private final InMemoryTerrainData inMemoryTerrainData;
-
- private boolean generateNormalMap;
-
- public InMemoryTerrainDataProvider(final InMemoryTerrainData inMemoryTerrainData) {
- this(inMemoryTerrainData, false);
- }
-
- public InMemoryTerrainDataProvider(final InMemoryTerrainData inMemoryTerrainData, final boolean generateNormalMap) {
- this.inMemoryTerrainData = inMemoryTerrainData;
- this.generateNormalMap = generateNormalMap;
- }
-
- @Override
- public Map<Integer, String> getAvailableMaps() throws Exception {
- final Map<Integer, String> maps = Maps.newHashMap();
- maps.put(0, "InMemoryData");
-
- return maps;
- }
-
- @Override
- public TerrainSource getTerrainSource(final int mapId) {
- return new InMemoryTerrainSource(tileSize, inMemoryTerrainData);
- }
-
- @Override
- public TextureSource getTextureSource(final int mapId) {
- return new InMemoryTextureSource(tileSize, inMemoryTerrainData);
- }
-
- @Override
- public TextureSource getNormalMapSource(final int mapId) {
- if (generateNormalMap) {
- try {
- final Image normalImage = NormalMapUtil.constructNormalMap(inMemoryTerrainData.getHeightData(),
- inMemoryTerrainData.getSide(), inMemoryTerrainData.getMaxHeight(), inMemoryTerrainData
- .getScale().getX(), inMemoryTerrainData.getScale().getY());
-
- final List<Integer> heightMapSizes = Lists.newArrayList();
- int currentSize = inMemoryTerrainData.getSide();
- heightMapSizes.add(currentSize);
- for (int i = 0; i < inMemoryTerrainData.getClipmapLevels(); i++) {
- currentSize /= 2;
- heightMapSizes.add(currentSize);
- }
- return new ImageTextureSource(tileSize, normalImage, heightMapSizes);
- } catch (final Exception e) {
- e.printStackTrace();
- }
- }
- return null;
- }
-
- public boolean isGenerateNormalMap() {
- return generateNormalMap;
- }
-
- public void setGenerateNormalMap(final boolean generateNormalMap) {
- this.generateNormalMap = generateNormalMap;
- }
-}
+/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.terrain.providers.inmemory; + +import java.util.List; +import java.util.Map; + +import com.ardor3d.extension.terrain.client.TerrainDataProvider; +import com.ardor3d.extension.terrain.client.TerrainSource; +import com.ardor3d.extension.terrain.client.TextureSource; +import com.ardor3d.extension.terrain.providers.image.ImageTextureSource; +import com.ardor3d.extension.terrain.providers.inmemory.data.InMemoryTerrainData; +import com.ardor3d.extension.terrain.util.NormalMapUtil; +import com.ardor3d.image.Image; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; + +public class InMemoryTerrainDataProvider implements TerrainDataProvider { + private static final int tileSize = 128; + private final InMemoryTerrainData inMemoryTerrainData; + + private boolean generateNormalMap; + + public InMemoryTerrainDataProvider(final InMemoryTerrainData inMemoryTerrainData) { + this(inMemoryTerrainData, false); + } + + public InMemoryTerrainDataProvider(final InMemoryTerrainData inMemoryTerrainData, final boolean generateNormalMap) { + this.inMemoryTerrainData = inMemoryTerrainData; + this.generateNormalMap = generateNormalMap; + } + + @Override + public Map<Integer, String> getAvailableMaps() throws Exception { + final Map<Integer, String> maps = Maps.newHashMap(); + maps.put(0, "InMemoryData"); + + return maps; + } + + @Override + public TerrainSource getTerrainSource(final int mapId) { + return new InMemoryTerrainSource(tileSize, inMemoryTerrainData); + } + + @Override + public TextureSource getTextureSource(final int mapId) { + return new InMemoryTextureSource(tileSize, inMemoryTerrainData); + } + + @Override + public TextureSource getNormalMapSource(final int mapId) { + if (generateNormalMap) { + try { + final Image normalImage = NormalMapUtil.constructNormalMap(inMemoryTerrainData.getHeightData(), + inMemoryTerrainData.getSide(), inMemoryTerrainData.getMaxHeight(), inMemoryTerrainData + .getScale().getX(), inMemoryTerrainData.getScale().getY()); + + final List<Integer> heightMapSizes = Lists.newArrayList(); + int currentSize = inMemoryTerrainData.getSide(); + heightMapSizes.add(currentSize); + for (int i = 0; i < inMemoryTerrainData.getClipmapLevels(); i++) { + currentSize /= 2; + heightMapSizes.add(currentSize); + } + return new ImageTextureSource(tileSize, normalImage, heightMapSizes); + } catch (final Exception e) { + e.printStackTrace(); + } + } + return null; + } + + public boolean isGenerateNormalMap() { + return generateNormalMap; + } + + public void setGenerateNormalMap(final boolean generateNormalMap) { + this.generateNormalMap = generateNormalMap; + } +} diff --git a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/inmemory/InMemoryTerrainSource.java b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/inmemory/InMemoryTerrainSource.java index dc5633a..32a0542 100644 --- a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/inmemory/InMemoryTerrainSource.java +++ b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/inmemory/InMemoryTerrainSource.java @@ -1,133 +1,133 @@ -/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.terrain.providers.inmemory;
-
-import java.util.Iterator;
-import java.util.Set;
-
-import com.ardor3d.extension.terrain.client.TerrainConfiguration;
-import com.ardor3d.extension.terrain.client.TerrainSource;
-import com.ardor3d.extension.terrain.providers.inmemory.data.InMemoryTerrainData;
-import com.ardor3d.extension.terrain.util.Tile;
-import com.google.common.collect.Sets;
-
-public class InMemoryTerrainSource implements TerrainSource {
- private final int tileSize;
- private final InMemoryTerrainData inMemoryTerrainData;
- private final int availableClipmapLevels;
-
- public InMemoryTerrainSource(final int tileSize, final InMemoryTerrainData inMemoryTerrainData) {
- this.tileSize = tileSize;
- this.inMemoryTerrainData = inMemoryTerrainData;
- availableClipmapLevels = inMemoryTerrainData.getClipmapLevels();
- }
-
- @Override
- public TerrainConfiguration getConfiguration() throws Exception {
- return new TerrainConfiguration(availableClipmapLevels, tileSize, inMemoryTerrainData.getScale(),
- inMemoryTerrainData.getMinHeight(), inMemoryTerrainData.getMaxHeight(), true);
- }
-
- @Override
- public Set<Tile> getValidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX,
- final int numTilesY) throws Exception {
- final int baseClipmapLevel = availableClipmapLevels - clipmapLevel - 1;
-
- final Set<Tile> validTiles = Sets.newHashSet();
-
- final int levelSize = 1 << baseClipmapLevel;
- final int size = inMemoryTerrainData.getSide();
-
- for (int y = 0; y < numTilesY; y++) {
- for (int x = 0; x < numTilesX; x++) {
- final int xx = tileX + x;
- final int yy = tileY + y;
- if (xx >= 0 && xx * tileSize * levelSize <= size && yy >= 0 && yy * tileSize * levelSize <= size) {
- final Tile tile = new Tile(xx, yy);
- validTiles.add(tile);
- }
- }
- }
-
- return validTiles;
- }
-
- @Override
- public Set<Tile> getInvalidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX,
- final int numTilesY) throws Exception {
- final Set<Tile> updatedTiles[] = inMemoryTerrainData.getUpdatedTerrainTiles();
- if (updatedTiles == null) {
- return null;
- }
-
- final int baseClipmapLevel = availableClipmapLevels - clipmapLevel - 1;
-
- final Set<Tile> tiles = Sets.newHashSet();
-
- synchronized (updatedTiles[baseClipmapLevel]) {
- if (updatedTiles[baseClipmapLevel].isEmpty()) {
- return null;
- }
-
- int checkX, checkY;
- for (final Iterator<Tile> it = updatedTiles[baseClipmapLevel].iterator(); it.hasNext();) {
- final Tile tile = it.next();
- checkX = tile.getX();
- checkY = tile.getY();
- if (checkX >= tileX && checkX < tileX + numTilesX && checkY >= tileY && checkY < tileY + numTilesY) {
- tiles.add(tile);
- it.remove();
- }
- }
- }
-
- return tiles;
- }
-
- @Override
- public int getContributorId(final int clipmapLevel, final Tile tile) {
- return 0;
- }
-
- @Override
- public float[] getTile(final int clipmapLevel, final Tile tile) throws Exception {
- final int tileX = tile.getX();
- final int tileY = tile.getY();
-
- final int baseClipmapLevel = availableClipmapLevels - clipmapLevel - 1;
-
- final int levelSize = 1 << baseClipmapLevel;
-
- final int size = inMemoryTerrainData.getSide();
-
- final float[] heightData = inMemoryTerrainData.getHeightData();
-
- final float[] data = new float[tileSize * tileSize];
- for (int y = 0; y < tileSize; y++) {
- for (int x = 0; x < tileSize; x++) {
- final int index = x + y * tileSize;
-
- final int heightX = (tileX * tileSize + x) * levelSize;
- final int heightY = (tileY * tileSize + y) * levelSize;
- data[index] = getHeight(heightData, size, heightX, heightY);
- }
- }
- return data;
- }
-
- private float getHeight(final float[] heightMap, final int heightMapSize, final int x, final int y) {
- if (x < 0 || x >= heightMapSize || y < 0 || y >= heightMapSize) {
- return 0;
- }
-
- return heightMap[y * heightMapSize + x];
- }
-}
+/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.terrain.providers.inmemory; + +import java.util.Iterator; +import java.util.Set; + +import com.ardor3d.extension.terrain.client.TerrainConfiguration; +import com.ardor3d.extension.terrain.client.TerrainSource; +import com.ardor3d.extension.terrain.providers.inmemory.data.InMemoryTerrainData; +import com.ardor3d.extension.terrain.util.Tile; +import com.google.common.collect.Sets; + +public class InMemoryTerrainSource implements TerrainSource { + private final int tileSize; + private final InMemoryTerrainData inMemoryTerrainData; + private final int availableClipmapLevels; + + public InMemoryTerrainSource(final int tileSize, final InMemoryTerrainData inMemoryTerrainData) { + this.tileSize = tileSize; + this.inMemoryTerrainData = inMemoryTerrainData; + availableClipmapLevels = inMemoryTerrainData.getClipmapLevels(); + } + + @Override + public TerrainConfiguration getConfiguration() throws Exception { + return new TerrainConfiguration(availableClipmapLevels, tileSize, inMemoryTerrainData.getScale(), + inMemoryTerrainData.getMinHeight(), inMemoryTerrainData.getMaxHeight(), true); + } + + @Override + public Set<Tile> getValidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX, + final int numTilesY) throws Exception { + final int baseClipmapLevel = availableClipmapLevels - clipmapLevel - 1; + + final Set<Tile> validTiles = Sets.newHashSet(); + + final int levelSize = 1 << baseClipmapLevel; + final int size = inMemoryTerrainData.getSide(); + + for (int y = 0; y < numTilesY; y++) { + for (int x = 0; x < numTilesX; x++) { + final int xx = tileX + x; + final int yy = tileY + y; + if (xx >= 0 && xx * tileSize * levelSize <= size && yy >= 0 && yy * tileSize * levelSize <= size) { + final Tile tile = new Tile(xx, yy); + validTiles.add(tile); + } + } + } + + return validTiles; + } + + @Override + public Set<Tile> getInvalidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX, + final int numTilesY) throws Exception { + final Set<Tile> updatedTiles[] = inMemoryTerrainData.getUpdatedTerrainTiles(); + if (updatedTiles == null) { + return null; + } + + final int baseClipmapLevel = availableClipmapLevels - clipmapLevel - 1; + + final Set<Tile> tiles = Sets.newHashSet(); + + synchronized (updatedTiles[baseClipmapLevel]) { + if (updatedTiles[baseClipmapLevel].isEmpty()) { + return null; + } + + int checkX, checkY; + for (final Iterator<Tile> it = updatedTiles[baseClipmapLevel].iterator(); it.hasNext();) { + final Tile tile = it.next(); + checkX = tile.getX(); + checkY = tile.getY(); + if (checkX >= tileX && checkX < tileX + numTilesX && checkY >= tileY && checkY < tileY + numTilesY) { + tiles.add(tile); + it.remove(); + } + } + } + + return tiles; + } + + @Override + public int getContributorId(final int clipmapLevel, final Tile tile) { + return 0; + } + + @Override + public float[] getTile(final int clipmapLevel, final Tile tile) throws Exception { + final int tileX = tile.getX(); + final int tileY = tile.getY(); + + final int baseClipmapLevel = availableClipmapLevels - clipmapLevel - 1; + + final int levelSize = 1 << baseClipmapLevel; + + final int size = inMemoryTerrainData.getSide(); + + final float[] heightData = inMemoryTerrainData.getHeightData(); + + final float[] data = new float[tileSize * tileSize]; + for (int y = 0; y < tileSize; y++) { + for (int x = 0; x < tileSize; x++) { + final int index = x + y * tileSize; + + final int heightX = (tileX * tileSize + x) * levelSize; + final int heightY = (tileY * tileSize + y) * levelSize; + data[index] = getHeight(heightData, size, heightX, heightY); + } + } + return data; + } + + private float getHeight(final float[] heightMap, final int heightMapSize, final int x, final int y) { + if (x < 0 || x >= heightMapSize || y < 0 || y >= heightMapSize) { + return 0; + } + + return heightMap[y * heightMapSize + x]; + } +} diff --git a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/inmemory/InMemoryTextureSource.java b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/inmemory/InMemoryTextureSource.java index 32a046d..80fdc82 100644 --- a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/inmemory/InMemoryTextureSource.java +++ b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/inmemory/InMemoryTextureSource.java @@ -1,142 +1,142 @@ -/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.terrain.providers.inmemory;
-
-import java.nio.ByteBuffer;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-import com.ardor3d.extension.terrain.client.TextureConfiguration;
-import com.ardor3d.extension.terrain.client.TextureSource;
-import com.ardor3d.extension.terrain.providers.inmemory.data.InMemoryTerrainData;
-import com.ardor3d.extension.terrain.util.Tile;
-import com.ardor3d.image.TextureStoreFormat;
-import com.ardor3d.util.geom.BufferUtils;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-
-public class InMemoryTextureSource implements TextureSource {
- private final int tileSize;
- private final InMemoryTerrainData inMemoryTerrainData;
- private final int availableClipmapLevels;
-
- public InMemoryTextureSource(final int tileSize, final InMemoryTerrainData inMemoryTerrainData) {
- this.tileSize = tileSize;
- this.inMemoryTerrainData = inMemoryTerrainData;
- availableClipmapLevels = inMemoryTerrainData.getClipmapLevels();
- }
-
- @Override
- public TextureConfiguration getConfiguration() throws Exception {
- final Map<Integer, TextureStoreFormat> textureStoreFormat = Maps.newHashMap();
- textureStoreFormat.put(0, TextureStoreFormat.RGBA8);
-
- return new TextureConfiguration(availableClipmapLevels, textureStoreFormat, tileSize, 1f, true, true);
- }
-
- @Override
- public Set<Tile> getValidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX,
- final int numTilesY) throws Exception {
- final int baseClipmapLevel = availableClipmapLevels - clipmapLevel - 1;
-
- final Set<Tile> validTiles = Sets.newHashSet();
-
- final int levelSize = 1 << baseClipmapLevel;
- final int size = inMemoryTerrainData.getSide();
-
- for (int y = 0; y < numTilesY; y++) {
- for (int x = 0; x < numTilesX; x++) {
- final int xx = tileX + x;
- final int yy = tileY + y;
- if (xx >= 0 && xx * tileSize * levelSize <= size && yy >= 0 && yy * tileSize * levelSize <= size) {
- final Tile tile = new Tile(xx, yy);
- validTiles.add(tile);
- }
- }
- }
-
- return validTiles;
- }
-
- @Override
- public Set<Tile> getInvalidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX,
- final int numTilesY) throws Exception {
- final Set<Tile> updatedTiles[] = inMemoryTerrainData.getUpdatedTextureTiles();
- if (updatedTiles == null) {
- return null;
- }
-
- final int baseClipmapLevel = availableClipmapLevels - clipmapLevel - 1;
-
- final Set<Tile> tiles = Sets.newHashSet();
-
- synchronized (updatedTiles[baseClipmapLevel]) {
- if (updatedTiles[baseClipmapLevel].isEmpty()) {
- return null;
- }
-
- int checkX, checkY;
- for (final Iterator<Tile> it = updatedTiles[baseClipmapLevel].iterator(); it.hasNext();) {
- final Tile tile = it.next();
- checkX = tile.getX();
- checkY = tile.getY();
- if (checkX >= tileX && checkX < tileX + numTilesX && checkY >= tileY && checkY < tileY + numTilesY) {
- tiles.add(tile);
- it.remove();
- }
- }
- }
-
- return tiles;
- }
-
- @Override
- public int getContributorId(final int clipmapLevel, final Tile tile) {
- return 0;
- }
-
- @Override
- public ByteBuffer getTile(final int clipmapLevel, final Tile tile) throws Exception {
- final int tileX = tile.getX();
- final int tileY = tile.getY();
-
- final int levelSize = 1 << availableClipmapLevels - clipmapLevel - 1;
-
- final int size = inMemoryTerrainData.getSide();
- final byte[] colorData = inMemoryTerrainData.getColorData();
-
- final ByteBuffer data = BufferUtils.createByteBufferOnHeap(tileSize * tileSize * 4);
- for (int y = 0; y < tileSize; y++) {
- for (int x = 0; x < tileSize; x++) {
- final int heightX = (tileX * tileSize + x) * levelSize;
- final int heightY = (tileY * tileSize + y) * levelSize;
-
- final int indexTile = (y * tileSize + x) * 4;
- final int index = heightY * size + heightX;
-
- if (heightX < 0 || heightX >= size || heightY < 0 || heightY >= size) {
- data.put(indexTile + 0, (byte) 0);
- data.put(indexTile + 1, (byte) 0);
- data.put(indexTile + 2, (byte) 0);
- data.put(indexTile + 3, (byte) 255);
- } else {
- data.put(indexTile + 0, colorData[index * 4 + 0]);
- data.put(indexTile + 1, colorData[index * 4 + 1]);
- data.put(indexTile + 2, colorData[index * 4 + 2]);
- data.put(indexTile + 3, colorData[index * 4 + 3]);
- }
- }
- }
-
- return data;
- }
-}
+/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.terrain.providers.inmemory; + +import java.nio.ByteBuffer; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import com.ardor3d.extension.terrain.client.TextureConfiguration; +import com.ardor3d.extension.terrain.client.TextureSource; +import com.ardor3d.extension.terrain.providers.inmemory.data.InMemoryTerrainData; +import com.ardor3d.extension.terrain.util.Tile; +import com.ardor3d.image.TextureStoreFormat; +import com.ardor3d.util.geom.BufferUtils; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +public class InMemoryTextureSource implements TextureSource { + private final int tileSize; + private final InMemoryTerrainData inMemoryTerrainData; + private final int availableClipmapLevels; + + public InMemoryTextureSource(final int tileSize, final InMemoryTerrainData inMemoryTerrainData) { + this.tileSize = tileSize; + this.inMemoryTerrainData = inMemoryTerrainData; + availableClipmapLevels = inMemoryTerrainData.getClipmapLevels(); + } + + @Override + public TextureConfiguration getConfiguration() throws Exception { + final Map<Integer, TextureStoreFormat> textureStoreFormat = Maps.newHashMap(); + textureStoreFormat.put(0, TextureStoreFormat.RGBA8); + + return new TextureConfiguration(availableClipmapLevels, textureStoreFormat, tileSize, 1f, true, true); + } + + @Override + public Set<Tile> getValidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX, + final int numTilesY) throws Exception { + final int baseClipmapLevel = availableClipmapLevels - clipmapLevel - 1; + + final Set<Tile> validTiles = Sets.newHashSet(); + + final int levelSize = 1 << baseClipmapLevel; + final int size = inMemoryTerrainData.getSide(); + + for (int y = 0; y < numTilesY; y++) { + for (int x = 0; x < numTilesX; x++) { + final int xx = tileX + x; + final int yy = tileY + y; + if (xx >= 0 && xx * tileSize * levelSize <= size && yy >= 0 && yy * tileSize * levelSize <= size) { + final Tile tile = new Tile(xx, yy); + validTiles.add(tile); + } + } + } + + return validTiles; + } + + @Override + public Set<Tile> getInvalidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX, + final int numTilesY) throws Exception { + final Set<Tile> updatedTiles[] = inMemoryTerrainData.getUpdatedTextureTiles(); + if (updatedTiles == null) { + return null; + } + + final int baseClipmapLevel = availableClipmapLevels - clipmapLevel - 1; + + final Set<Tile> tiles = Sets.newHashSet(); + + synchronized (updatedTiles[baseClipmapLevel]) { + if (updatedTiles[baseClipmapLevel].isEmpty()) { + return null; + } + + int checkX, checkY; + for (final Iterator<Tile> it = updatedTiles[baseClipmapLevel].iterator(); it.hasNext();) { + final Tile tile = it.next(); + checkX = tile.getX(); + checkY = tile.getY(); + if (checkX >= tileX && checkX < tileX + numTilesX && checkY >= tileY && checkY < tileY + numTilesY) { + tiles.add(tile); + it.remove(); + } + } + } + + return tiles; + } + + @Override + public int getContributorId(final int clipmapLevel, final Tile tile) { + return 0; + } + + @Override + public ByteBuffer getTile(final int clipmapLevel, final Tile tile) throws Exception { + final int tileX = tile.getX(); + final int tileY = tile.getY(); + + final int levelSize = 1 << availableClipmapLevels - clipmapLevel - 1; + + final int size = inMemoryTerrainData.getSide(); + final byte[] colorData = inMemoryTerrainData.getColorData(); + + final ByteBuffer data = BufferUtils.createByteBufferOnHeap(tileSize * tileSize * 4); + for (int y = 0; y < tileSize; y++) { + for (int x = 0; x < tileSize; x++) { + final int heightX = (tileX * tileSize + x) * levelSize; + final int heightY = (tileY * tileSize + y) * levelSize; + + final int indexTile = (y * tileSize + x) * 4; + final int index = heightY * size + heightX; + + if (heightX < 0 || heightX >= size || heightY < 0 || heightY >= size) { + data.put(indexTile + 0, (byte) 0); + data.put(indexTile + 1, (byte) 0); + data.put(indexTile + 2, (byte) 0); + data.put(indexTile + 3, (byte) 255); + } else { + data.put(indexTile + 0, colorData[index * 4 + 0]); + data.put(indexTile + 1, colorData[index * 4 + 1]); + data.put(indexTile + 2, colorData[index * 4 + 2]); + data.put(indexTile + 3, colorData[index * 4 + 3]); + } + } + } + + return data; + } +} diff --git a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/procedural/ProceduralNormalMapSource.java b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/procedural/ProceduralNormalMapSource.java index df07262..ec4313b 100644 --- a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/procedural/ProceduralNormalMapSource.java +++ b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/procedural/ProceduralNormalMapSource.java @@ -1,111 +1,111 @@ -/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.terrain.providers.procedural;
-
-import java.nio.ByteBuffer;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.locks.ReentrantLock;
-
-import com.ardor3d.extension.terrain.client.TextureConfiguration;
-import com.ardor3d.extension.terrain.client.TextureSource;
-import com.ardor3d.extension.terrain.util.Tile;
-import com.ardor3d.image.TextureStoreFormat;
-import com.ardor3d.math.Vector3;
-import com.ardor3d.math.functions.Function3D;
-import com.ardor3d.util.geom.BufferUtils;
-import com.google.common.collect.Maps;
-
-public class ProceduralNormalMapSource implements TextureSource {
- private final Function3D function;
-
- private static final int tileSize = 128;
- private static final int availableClipmapLevels = 8;
-
- private final ReentrantLock textureLock = new ReentrantLock();
- private final ThreadLocal<ByteBuffer> tileDataPool = new ThreadLocal<ByteBuffer>() {
- @Override
- protected ByteBuffer initialValue() {
- return BufferUtils.createByteBufferOnHeap(tileSize * tileSize * 3);
- }
- };
-
- public ProceduralNormalMapSource(final Function3D function) {
- this.function = function;
- }
-
- @Override
- public TextureConfiguration getConfiguration() throws Exception {
- final Map<Integer, TextureStoreFormat> textureStoreFormat = Maps.newHashMap();
- textureStoreFormat.put(0, TextureStoreFormat.RGB8);
-
- return new TextureConfiguration(availableClipmapLevels, textureStoreFormat, tileSize, 1f, false, false);
- }
-
- @Override
- public Set<Tile> getValidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX,
- final int numTilesY) throws Exception {
- return null;
- }
-
- @Override
- public Set<Tile> getInvalidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX,
- final int numTilesY) throws Exception {
- return null;
- }
-
- @Override
- public int getContributorId(final int clipmapLevel, final Tile tile) {
- return 0;
- }
-
- @Override
- public ByteBuffer getTile(final int clipmapLevel, final Tile tile) throws Exception {
- final ByteBuffer data = tileDataPool.get();
- final int tileX = tile.getX();
- final int tileY = tile.getY();
-
- final int baseClipmapLevel = availableClipmapLevels - clipmapLevel - 1;
-
- final Vector3 normal = new Vector3();
- textureLock.lock();
- try {
- for (int y = 0; y < tileSize; y++) {
- for (int x = 0; x < tileSize; x++) {
- if (Thread.interrupted()) {
- return null;
- }
-
- final int heightX = tileX * tileSize + x;
- final int heightY = tileY * tileSize + y;
-
- normal.setZ(1);
- final double eval1 = function.eval(heightX - 1 << baseClipmapLevel, heightY << baseClipmapLevel, 0);
- final double eval2 = function.eval(heightX + 1 << baseClipmapLevel, heightY << baseClipmapLevel, 0);
- final double eval3 = function.eval(heightX << baseClipmapLevel, heightY - 1 << baseClipmapLevel, 0);
- final double eval4 = function.eval(heightX << baseClipmapLevel, heightY + 1 << baseClipmapLevel, 0);
-
- normal.setX((eval1 - eval2) / 2.);
- normal.setY((eval3 - eval4) / 2.);
- normal.normalizeLocal();
-
- final int index = (x + y * tileSize) * 3;
- data.put(index, (byte) (normal.getX() * 255));
- data.put(index + 1, (byte) (normal.getY() * 255));
- data.put(index + 2, (byte) (normal.getZ() * 255));
- }
- }
- } finally {
- textureLock.unlock();
- }
- return data;
- }
-}
+/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.terrain.providers.procedural; + +import java.nio.ByteBuffer; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.locks.ReentrantLock; + +import com.ardor3d.extension.terrain.client.TextureConfiguration; +import com.ardor3d.extension.terrain.client.TextureSource; +import com.ardor3d.extension.terrain.util.Tile; +import com.ardor3d.image.TextureStoreFormat; +import com.ardor3d.math.Vector3; +import com.ardor3d.math.functions.Function3D; +import com.ardor3d.util.geom.BufferUtils; +import com.google.common.collect.Maps; + +public class ProceduralNormalMapSource implements TextureSource { + private final Function3D function; + + private static final int tileSize = 128; + private static final int availableClipmapLevels = 8; + + private final ReentrantLock textureLock = new ReentrantLock(); + private final ThreadLocal<ByteBuffer> tileDataPool = new ThreadLocal<ByteBuffer>() { + @Override + protected ByteBuffer initialValue() { + return BufferUtils.createByteBufferOnHeap(tileSize * tileSize * 3); + } + }; + + public ProceduralNormalMapSource(final Function3D function) { + this.function = function; + } + + @Override + public TextureConfiguration getConfiguration() throws Exception { + final Map<Integer, TextureStoreFormat> textureStoreFormat = Maps.newHashMap(); + textureStoreFormat.put(0, TextureStoreFormat.RGB8); + + return new TextureConfiguration(availableClipmapLevels, textureStoreFormat, tileSize, 1f, false, false); + } + + @Override + public Set<Tile> getValidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX, + final int numTilesY) throws Exception { + return null; + } + + @Override + public Set<Tile> getInvalidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX, + final int numTilesY) throws Exception { + return null; + } + + @Override + public int getContributorId(final int clipmapLevel, final Tile tile) { + return 0; + } + + @Override + public ByteBuffer getTile(final int clipmapLevel, final Tile tile) throws Exception { + final ByteBuffer data = tileDataPool.get(); + final int tileX = tile.getX(); + final int tileY = tile.getY(); + + final int baseClipmapLevel = availableClipmapLevels - clipmapLevel - 1; + + final Vector3 normal = new Vector3(); + textureLock.lock(); + try { + for (int y = 0; y < tileSize; y++) { + for (int x = 0; x < tileSize; x++) { + if (Thread.interrupted()) { + return null; + } + + final int heightX = tileX * tileSize + x; + final int heightY = tileY * tileSize + y; + + normal.setZ(1); + final double eval1 = function.eval(heightX - 1 << baseClipmapLevel, heightY << baseClipmapLevel, 0); + final double eval2 = function.eval(heightX + 1 << baseClipmapLevel, heightY << baseClipmapLevel, 0); + final double eval3 = function.eval(heightX << baseClipmapLevel, heightY - 1 << baseClipmapLevel, 0); + final double eval4 = function.eval(heightX << baseClipmapLevel, heightY + 1 << baseClipmapLevel, 0); + + normal.setX((eval1 - eval2) / 2.); + normal.setY((eval3 - eval4) / 2.); + normal.normalizeLocal(); + + final int index = (x + y * tileSize) * 3; + data.put(index, (byte) (normal.getX() * 255)); + data.put(index + 1, (byte) (normal.getY() * 255)); + data.put(index + 2, (byte) (normal.getZ() * 255)); + } + } + } finally { + textureLock.unlock(); + } + return data; + } +} diff --git a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/procedural/ProceduralTerrainDataProvider.java b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/procedural/ProceduralTerrainDataProvider.java index 575a514..6d1c8e3 100644 --- a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/procedural/ProceduralTerrainDataProvider.java +++ b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/procedural/ProceduralTerrainDataProvider.java @@ -1,74 +1,74 @@ -/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.terrain.providers.procedural;
-
-import java.util.Map;
-
-import com.ardor3d.extension.terrain.client.TerrainDataProvider;
-import com.ardor3d.extension.terrain.client.TerrainSource;
-import com.ardor3d.extension.terrain.client.TextureSource;
-import com.ardor3d.math.functions.Function3D;
-import com.ardor3d.math.type.ReadOnlyVector3;
-import com.google.common.collect.Maps;
-
-public class ProceduralTerrainDataProvider implements TerrainDataProvider {
- private final Function3D function;
- private final ReadOnlyVector3 scale;
- private final float minHeight;
- private final float maxHeight;
-
- private boolean generateNormalMap;
-
- public ProceduralTerrainDataProvider(final Function3D function, final ReadOnlyVector3 scale, final float minHeight,
- final float maxHeight) {
- this(function, scale, minHeight, maxHeight, false);
- }
-
- public ProceduralTerrainDataProvider(final Function3D function, final ReadOnlyVector3 scale, final float minHeight,
- final float maxHeight, final boolean generateNormalMap) {
- this.function = function;
- this.scale = scale;
- this.minHeight = minHeight;
- this.maxHeight = maxHeight;
- this.generateNormalMap = generateNormalMap;
- }
-
- @Override
- public Map<Integer, String> getAvailableMaps() throws Exception {
- final Map<Integer, String> maps = Maps.newHashMap();
- maps.put(0, "ProceduralMap");
-
- return maps;
- }
-
- @Override
- public TerrainSource getTerrainSource(final int mapId) {
- return new ProceduralTerrainSource(function, scale, minHeight, maxHeight);
- }
-
- @Override
- public TextureSource getTextureSource(final int mapId) {
- return new ProceduralTextureSource(function);
- }
-
- @Override
- public TextureSource getNormalMapSource(final int mapId) {
- return new ProceduralNormalMapSource(function);
- }
-
- public boolean isGenerateNormalMap() {
- return generateNormalMap;
- }
-
- public void setGenerateNormalMap(final boolean generateNormalMap) {
- this.generateNormalMap = generateNormalMap;
- }
-}
+/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.terrain.providers.procedural; + +import java.util.Map; + +import com.ardor3d.extension.terrain.client.TerrainDataProvider; +import com.ardor3d.extension.terrain.client.TerrainSource; +import com.ardor3d.extension.terrain.client.TextureSource; +import com.ardor3d.math.functions.Function3D; +import com.ardor3d.math.type.ReadOnlyVector3; +import com.google.common.collect.Maps; + +public class ProceduralTerrainDataProvider implements TerrainDataProvider { + private final Function3D function; + private final ReadOnlyVector3 scale; + private final float minHeight; + private final float maxHeight; + + private boolean generateNormalMap; + + public ProceduralTerrainDataProvider(final Function3D function, final ReadOnlyVector3 scale, final float minHeight, + final float maxHeight) { + this(function, scale, minHeight, maxHeight, false); + } + + public ProceduralTerrainDataProvider(final Function3D function, final ReadOnlyVector3 scale, final float minHeight, + final float maxHeight, final boolean generateNormalMap) { + this.function = function; + this.scale = scale; + this.minHeight = minHeight; + this.maxHeight = maxHeight; + this.generateNormalMap = generateNormalMap; + } + + @Override + public Map<Integer, String> getAvailableMaps() throws Exception { + final Map<Integer, String> maps = Maps.newHashMap(); + maps.put(0, "ProceduralMap"); + + return maps; + } + + @Override + public TerrainSource getTerrainSource(final int mapId) { + return new ProceduralTerrainSource(function, scale, minHeight, maxHeight); + } + + @Override + public TextureSource getTextureSource(final int mapId) { + return new ProceduralTextureSource(function); + } + + @Override + public TextureSource getNormalMapSource(final int mapId) { + return new ProceduralNormalMapSource(function); + } + + public boolean isGenerateNormalMap() { + return generateNormalMap; + } + + public void setGenerateNormalMap(final boolean generateNormalMap) { + this.generateNormalMap = generateNormalMap; + } +} diff --git a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/procedural/ProceduralTerrainSource.java b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/procedural/ProceduralTerrainSource.java index 19515b7..4fae73a 100644 --- a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/procedural/ProceduralTerrainSource.java +++ b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/procedural/ProceduralTerrainSource.java @@ -1,97 +1,97 @@ -/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.terrain.providers.procedural;
-
-import java.util.Set;
-import java.util.concurrent.locks.ReentrantLock;
-
-import com.ardor3d.extension.terrain.client.TerrainConfiguration;
-import com.ardor3d.extension.terrain.client.TerrainSource;
-import com.ardor3d.extension.terrain.util.Tile;
-import com.ardor3d.math.functions.Function3D;
-import com.ardor3d.math.type.ReadOnlyVector3;
-
-public class ProceduralTerrainSource implements TerrainSource {
- private final Function3D function;
- private final ReadOnlyVector3 scale;
- private final float minHeight;
- private final float maxHeight;
-
- private static final int tileSize = 128;
- private static final int availableClipmapLevels = 8;
-
- private final ReentrantLock terrainLock = new ReentrantLock();
- private final ThreadLocal<float[]> tileDataPool = new ThreadLocal<float[]>() {
- @Override
- protected float[] initialValue() {
- return new float[tileSize * tileSize];
- }
- };
-
- public ProceduralTerrainSource(final Function3D function, final ReadOnlyVector3 scale, final float minHeight,
- final float maxHeight) {
- this.function = function;
- this.scale = scale;
- this.minHeight = minHeight;
- this.maxHeight = maxHeight;
- }
-
- @Override
- public TerrainConfiguration getConfiguration() throws Exception {
- return new TerrainConfiguration(availableClipmapLevels, tileSize, scale, minHeight, maxHeight, false);
- }
-
- @Override
- public Set<Tile> getValidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX,
- final int numTilesY) throws Exception {
- return null;
- }
-
- @Override
- public Set<Tile> getInvalidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX,
- final int numTilesY) throws Exception {
- return null;
- }
-
- @Override
- public int getContributorId(final int clipmapLevel, final Tile tile) {
- return 0;
- }
-
- @Override
- public float[] getTile(final int clipmapLevel, final Tile tile) throws Exception {
- final float[] data = tileDataPool.get();
- final int tileX = tile.getX();
- final int tileY = tile.getY();
-
- final int baseClipmapLevel = availableClipmapLevels - clipmapLevel - 1;
-
- terrainLock.lock();
- try {
- for (int y = 0; y < tileSize; y++) {
- for (int x = 0; x < tileSize; x++) {
- if (Thread.interrupted()) {
- return null;
- }
-
- final int heightX = tileX * tileSize + x;
- final int heightY = tileY * tileSize + y;
-
- final int index = x + y * tileSize;
- data[index] = (float) function.eval(heightX << baseClipmapLevel, heightY << baseClipmapLevel, 0);
- }
- }
- } finally {
- terrainLock.unlock();
- }
- return data;
- }
-}
+/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.terrain.providers.procedural; + +import java.util.Set; +import java.util.concurrent.locks.ReentrantLock; + +import com.ardor3d.extension.terrain.client.TerrainConfiguration; +import com.ardor3d.extension.terrain.client.TerrainSource; +import com.ardor3d.extension.terrain.util.Tile; +import com.ardor3d.math.functions.Function3D; +import com.ardor3d.math.type.ReadOnlyVector3; + +public class ProceduralTerrainSource implements TerrainSource { + private final Function3D function; + private final ReadOnlyVector3 scale; + private final float minHeight; + private final float maxHeight; + + private static final int tileSize = 128; + private static final int availableClipmapLevels = 8; + + private final ReentrantLock terrainLock = new ReentrantLock(); + private final ThreadLocal<float[]> tileDataPool = new ThreadLocal<float[]>() { + @Override + protected float[] initialValue() { + return new float[tileSize * tileSize]; + } + }; + + public ProceduralTerrainSource(final Function3D function, final ReadOnlyVector3 scale, final float minHeight, + final float maxHeight) { + this.function = function; + this.scale = scale; + this.minHeight = minHeight; + this.maxHeight = maxHeight; + } + + @Override + public TerrainConfiguration getConfiguration() throws Exception { + return new TerrainConfiguration(availableClipmapLevels, tileSize, scale, minHeight, maxHeight, false); + } + + @Override + public Set<Tile> getValidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX, + final int numTilesY) throws Exception { + return null; + } + + @Override + public Set<Tile> getInvalidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX, + final int numTilesY) throws Exception { + return null; + } + + @Override + public int getContributorId(final int clipmapLevel, final Tile tile) { + return 0; + } + + @Override + public float[] getTile(final int clipmapLevel, final Tile tile) throws Exception { + final float[] data = tileDataPool.get(); + final int tileX = tile.getX(); + final int tileY = tile.getY(); + + final int baseClipmapLevel = availableClipmapLevels - clipmapLevel - 1; + + terrainLock.lock(); + try { + for (int y = 0; y < tileSize; y++) { + for (int x = 0; x < tileSize; x++) { + if (Thread.interrupted()) { + return null; + } + + final int heightX = tileX * tileSize + x; + final int heightY = tileY * tileSize + y; + + final int index = x + y * tileSize; + data[index] = (float) function.eval(heightX << baseClipmapLevel, heightY << baseClipmapLevel, 0); + } + } + } finally { + terrainLock.unlock(); + } + return data; + } +} diff --git a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/procedural/ProceduralTextureSource.java b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/procedural/ProceduralTextureSource.java index 0a48626..3b1b4dc 100644 --- a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/procedural/ProceduralTextureSource.java +++ b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/procedural/ProceduralTextureSource.java @@ -1,120 +1,120 @@ -/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.terrain.providers.procedural;
-
-import java.nio.ByteBuffer;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.locks.ReentrantLock;
-
-import com.ardor3d.extension.terrain.client.TextureConfiguration;
-import com.ardor3d.extension.terrain.client.TextureSource;
-import com.ardor3d.extension.terrain.util.Tile;
-import com.ardor3d.image.TextureStoreFormat;
-import com.ardor3d.image.util.GeneratedImageFactory;
-import com.ardor3d.math.ColorRGBA;
-import com.ardor3d.math.functions.Function3D;
-import com.ardor3d.math.type.ReadOnlyColorRGBA;
-import com.ardor3d.util.geom.BufferUtils;
-import com.google.common.collect.Maps;
-
-public class ProceduralTextureSource implements TextureSource {
- private final Function3D function;
-
- private static final int tileSize = 128;
- private static final int availableClipmapLevels = 8;
-
- private final ReadOnlyColorRGBA[] terrainColors;
-
- private final ReentrantLock textureLock = new ReentrantLock();
- private final ThreadLocal<ByteBuffer> tileDataPool = new ThreadLocal<ByteBuffer>() {
- @Override
- protected ByteBuffer initialValue() {
- return BufferUtils.createByteBufferOnHeap(tileSize * tileSize * 3);
- }
- };
-
- public ProceduralTextureSource(final Function3D function) {
- this.function = function;
-
- terrainColors = new ReadOnlyColorRGBA[256];
- terrainColors[0] = new ColorRGBA(0, 0, .5f, 1);
- terrainColors[95] = new ColorRGBA(0, 0, 1, 1);
- terrainColors[127] = new ColorRGBA(0, .5f, 1, 1);
- terrainColors[137] = new ColorRGBA(240 / 255f, 240 / 255f, 64 / 255f, 1);
- terrainColors[143] = new ColorRGBA(32 / 255f, 160 / 255f, 0, 1);
- terrainColors[175] = new ColorRGBA(224 / 255f, 224 / 255f, 0, 1);
- terrainColors[223] = new ColorRGBA(128 / 255f, 128 / 255f, 128 / 255f, 1);
- terrainColors[255] = ColorRGBA.WHITE;
- GeneratedImageFactory.fillInColorTable(terrainColors);
- }
-
- @Override
- public TextureConfiguration getConfiguration() throws Exception {
- final Map<Integer, TextureStoreFormat> textureStoreFormat = Maps.newHashMap();
- textureStoreFormat.put(0, TextureStoreFormat.RGB8);
-
- return new TextureConfiguration(availableClipmapLevels, textureStoreFormat, tileSize, 1f, false, false);
- }
-
- @Override
- public Set<Tile> getValidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX,
- final int numTilesY) throws Exception {
- return null;
- }
-
- @Override
- public Set<Tile> getInvalidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX,
- final int numTilesY) throws Exception {
- return null;
- }
-
- @Override
- public int getContributorId(final int clipmapLevel, final Tile tile) {
- return 0;
- }
-
- @Override
- public ByteBuffer getTile(final int clipmapLevel, final Tile tile) throws Exception {
- final ByteBuffer data = tileDataPool.get();
- final int tileX = tile.getX();
- final int tileY = tile.getY();
-
- final int baseClipmapLevel = availableClipmapLevels - clipmapLevel - 1;
-
- textureLock.lock();
- try {
- for (int y = 0; y < tileSize; y++) {
- for (int x = 0; x < tileSize; x++) {
- if (Thread.interrupted()) {
- return null;
- }
-
- final int heightX = tileX * tileSize + x;
- final int heightY = tileY * tileSize + y;
-
- final double eval = function.eval(heightX << baseClipmapLevel, heightY << baseClipmapLevel, 0) * 0.4167f + 0.5f;
- final byte colIndex = (byte) (eval * 255);
-
- final ReadOnlyColorRGBA c = terrainColors[colIndex & 0xFF];
-
- final int index = (x + y * tileSize) * 3;
- data.put(index, (byte) (c.getRed() * 255));
- data.put(index + 1, (byte) (c.getGreen() * 255));
- data.put(index + 2, (byte) (c.getBlue() * 255));
- }
- }
- } finally {
- textureLock.unlock();
- }
- return data;
- }
-}
+/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.terrain.providers.procedural; + +import java.nio.ByteBuffer; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.locks.ReentrantLock; + +import com.ardor3d.extension.terrain.client.TextureConfiguration; +import com.ardor3d.extension.terrain.client.TextureSource; +import com.ardor3d.extension.terrain.util.Tile; +import com.ardor3d.image.TextureStoreFormat; +import com.ardor3d.image.util.GeneratedImageFactory; +import com.ardor3d.math.ColorRGBA; +import com.ardor3d.math.functions.Function3D; +import com.ardor3d.math.type.ReadOnlyColorRGBA; +import com.ardor3d.util.geom.BufferUtils; +import com.google.common.collect.Maps; + +public class ProceduralTextureSource implements TextureSource { + private final Function3D function; + + private static final int tileSize = 128; + private static final int availableClipmapLevels = 8; + + private final ReadOnlyColorRGBA[] terrainColors; + + private final ReentrantLock textureLock = new ReentrantLock(); + private final ThreadLocal<ByteBuffer> tileDataPool = new ThreadLocal<ByteBuffer>() { + @Override + protected ByteBuffer initialValue() { + return BufferUtils.createByteBufferOnHeap(tileSize * tileSize * 3); + } + }; + + public ProceduralTextureSource(final Function3D function) { + this.function = function; + + terrainColors = new ReadOnlyColorRGBA[256]; + terrainColors[0] = new ColorRGBA(0, 0, .5f, 1); + terrainColors[95] = new ColorRGBA(0, 0, 1, 1); + terrainColors[127] = new ColorRGBA(0, .5f, 1, 1); + terrainColors[137] = new ColorRGBA(240 / 255f, 240 / 255f, 64 / 255f, 1); + terrainColors[143] = new ColorRGBA(32 / 255f, 160 / 255f, 0, 1); + terrainColors[175] = new ColorRGBA(224 / 255f, 224 / 255f, 0, 1); + terrainColors[223] = new ColorRGBA(128 / 255f, 128 / 255f, 128 / 255f, 1); + terrainColors[255] = ColorRGBA.WHITE; + GeneratedImageFactory.fillInColorTable(terrainColors); + } + + @Override + public TextureConfiguration getConfiguration() throws Exception { + final Map<Integer, TextureStoreFormat> textureStoreFormat = Maps.newHashMap(); + textureStoreFormat.put(0, TextureStoreFormat.RGB8); + + return new TextureConfiguration(availableClipmapLevels, textureStoreFormat, tileSize, 1f, false, false); + } + + @Override + public Set<Tile> getValidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX, + final int numTilesY) throws Exception { + return null; + } + + @Override + public Set<Tile> getInvalidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX, + final int numTilesY) throws Exception { + return null; + } + + @Override + public int getContributorId(final int clipmapLevel, final Tile tile) { + return 0; + } + + @Override + public ByteBuffer getTile(final int clipmapLevel, final Tile tile) throws Exception { + final ByteBuffer data = tileDataPool.get(); + final int tileX = tile.getX(); + final int tileY = tile.getY(); + + final int baseClipmapLevel = availableClipmapLevels - clipmapLevel - 1; + + textureLock.lock(); + try { + for (int y = 0; y < tileSize; y++) { + for (int x = 0; x < tileSize; x++) { + if (Thread.interrupted()) { + return null; + } + + final int heightX = tileX * tileSize + x; + final int heightY = tileY * tileSize + y; + + final double eval = function.eval(heightX << baseClipmapLevel, heightY << baseClipmapLevel, 0) * 0.4167f + 0.5f; + final byte colIndex = (byte) (eval * 255); + + final ReadOnlyColorRGBA c = terrainColors[colIndex & 0xFF]; + + final int index = (x + y * tileSize) * 3; + data.put(index, (byte) (c.getRed() * 255)); + data.put(index + 1, (byte) (c.getGreen() * 255)); + data.put(index + 2, (byte) (c.getBlue() * 255)); + } + } + } finally { + textureLock.unlock(); + } + return data; + } +} diff --git a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/simplearray/SimpleArrayTerrainDataProvider.java b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/simplearray/SimpleArrayTerrainDataProvider.java index 3d7878b..c41b4bf 100644 --- a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/simplearray/SimpleArrayTerrainDataProvider.java +++ b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/simplearray/SimpleArrayTerrainDataProvider.java @@ -1,91 +1,91 @@ -/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.terrain.providers.simplearray;
-
-import java.util.List;
-import java.util.Map;
-
-import com.ardor3d.extension.terrain.client.TerrainDataProvider;
-import com.ardor3d.extension.terrain.client.TerrainSource;
-import com.ardor3d.extension.terrain.client.TextureSource;
-import com.ardor3d.extension.terrain.providers.image.ImageTextureSource;
-import com.ardor3d.extension.terrain.util.NormalMapUtil;
-import com.ardor3d.image.Image;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-
-public class SimpleArrayTerrainDataProvider implements TerrainDataProvider {
- private static final int tileSize = 128;
-
- private final float[] heightData;
- private final byte[] colorData;
- private final int side;
-
- private boolean generateNormalMap;
-
- public SimpleArrayTerrainDataProvider(final float[] heightData, final byte[] colorData, final int side) {
- this(heightData, colorData, side, false);
- }
-
- public SimpleArrayTerrainDataProvider(final float[] heightData, final byte[] colorData, final int side,
- final boolean generateNormalMap) {
- this.heightData = heightData;
- this.colorData = colorData;
- this.side = side;
- this.generateNormalMap = generateNormalMap;
- }
-
- @Override
- public Map<Integer, String> getAvailableMaps() throws Exception {
- final Map<Integer, String> maps = Maps.newHashMap();
- maps.put(0, "InMemoryData");
-
- return maps;
- }
-
- @Override
- public TerrainSource getTerrainSource(final int mapId) {
- return new SimpleArrayTerrainSource(tileSize, heightData, side);
- }
-
- @Override
- public TextureSource getTextureSource(final int mapId) {
- return new SimpleArrayTextureSource(tileSize, colorData, side);
- }
-
- @Override
- public TextureSource getNormalMapSource(final int mapId) {
- if (generateNormalMap) {
- try {
- final Image normalImage = NormalMapUtil.constructNormalMap(heightData, side, 1, 1, 1);
- final List<Integer> heightMapSizes = Lists.newArrayList();
- int currentSize = side;
- heightMapSizes.add(currentSize);
- for (int i = 0; i < 8; i++) {
- currentSize /= 2;
- heightMapSizes.add(currentSize);
- }
- return new ImageTextureSource(tileSize, normalImage, heightMapSizes);
- } catch (final Exception e) {
- e.printStackTrace();
- }
- }
- return null;
- }
-
- public boolean isGenerateNormalMap() {
- return generateNormalMap;
- }
-
- public void setGenerateNormalMap(final boolean generateNormalMap) {
- this.generateNormalMap = generateNormalMap;
- }
-}
+/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.terrain.providers.simplearray; + +import java.util.List; +import java.util.Map; + +import com.ardor3d.extension.terrain.client.TerrainDataProvider; +import com.ardor3d.extension.terrain.client.TerrainSource; +import com.ardor3d.extension.terrain.client.TextureSource; +import com.ardor3d.extension.terrain.providers.image.ImageTextureSource; +import com.ardor3d.extension.terrain.util.NormalMapUtil; +import com.ardor3d.image.Image; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; + +public class SimpleArrayTerrainDataProvider implements TerrainDataProvider { + private static final int tileSize = 128; + + private final float[] heightData; + private final byte[] colorData; + private final int side; + + private boolean generateNormalMap; + + public SimpleArrayTerrainDataProvider(final float[] heightData, final byte[] colorData, final int side) { + this(heightData, colorData, side, false); + } + + public SimpleArrayTerrainDataProvider(final float[] heightData, final byte[] colorData, final int side, + final boolean generateNormalMap) { + this.heightData = heightData; + this.colorData = colorData; + this.side = side; + this.generateNormalMap = generateNormalMap; + } + + @Override + public Map<Integer, String> getAvailableMaps() throws Exception { + final Map<Integer, String> maps = Maps.newHashMap(); + maps.put(0, "InMemoryData"); + + return maps; + } + + @Override + public TerrainSource getTerrainSource(final int mapId) { + return new SimpleArrayTerrainSource(tileSize, heightData, side); + } + + @Override + public TextureSource getTextureSource(final int mapId) { + return new SimpleArrayTextureSource(tileSize, colorData, side); + } + + @Override + public TextureSource getNormalMapSource(final int mapId) { + if (generateNormalMap) { + try { + final Image normalImage = NormalMapUtil.constructNormalMap(heightData, side, 1, 1, 1); + final List<Integer> heightMapSizes = Lists.newArrayList(); + int currentSize = side; + heightMapSizes.add(currentSize); + for (int i = 0; i < 8; i++) { + currentSize /= 2; + heightMapSizes.add(currentSize); + } + return new ImageTextureSource(tileSize, normalImage, heightMapSizes); + } catch (final Exception e) { + e.printStackTrace(); + } + } + return null; + } + + public boolean isGenerateNormalMap() { + return generateNormalMap; + } + + public void setGenerateNormalMap(final boolean generateNormalMap) { + this.generateNormalMap = generateNormalMap; + } +} diff --git a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/simplearray/SimpleArrayTerrainSource.java b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/simplearray/SimpleArrayTerrainSource.java index 05d1747..3b52fe1 100644 --- a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/simplearray/SimpleArrayTerrainSource.java +++ b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/simplearray/SimpleArrayTerrainSource.java @@ -1,83 +1,83 @@ -/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.terrain.providers.simplearray;
-
-import java.util.Set;
-
-import com.ardor3d.extension.terrain.client.TerrainConfiguration;
-import com.ardor3d.extension.terrain.client.TerrainSource;
-import com.ardor3d.extension.terrain.util.Tile;
-import com.ardor3d.math.Vector3;
-
-public class SimpleArrayTerrainSource implements TerrainSource {
- private final int tileSize;
- private final float[] heightData;
- private final int size;
- private final int availableClipmapLevels = 8;
-
- public SimpleArrayTerrainSource(final int tileSize, final float[] heightData, final int size) {
- this.tileSize = tileSize;
- this.heightData = heightData;
- this.size = size;
- }
-
- @Override
- public TerrainConfiguration getConfiguration() throws Exception {
- return new TerrainConfiguration(availableClipmapLevels, tileSize, new Vector3(1, 1, 1), 0.0f, 1.0f, true);
- }
-
- @Override
- public Set<Tile> getValidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX,
- final int numTilesY) throws Exception {
- return null;
- }
-
- @Override
- public Set<Tile> getInvalidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX,
- final int numTilesY) throws Exception {
- return null;
- }
-
- @Override
- public int getContributorId(final int clipmapLevel, final Tile tile) {
- return 0;
- }
-
- @Override
- public float[] getTile(final int clipmapLevel, final Tile tile) throws Exception {
- final int tileX = tile.getX();
- final int tileY = tile.getY();
-
- final int baseClipmapLevel = availableClipmapLevels - clipmapLevel - 1;
-
- final int levelSize = 1 << baseClipmapLevel;
-
- final float[] data = new float[tileSize * tileSize];
- for (int y = 0; y < tileSize; y++) {
- for (int x = 0; x < tileSize; x++) {
- final int index = x + y * tileSize;
-
- final int heightX = (tileX * tileSize + x) * levelSize;
- final int heightY = (tileY * tileSize + y) * levelSize;
- data[index] = getHeight(heightData, size, heightX, heightY);
- }
- }
- return data;
- }
-
- private float getHeight(final float[] heightMap, final int heightMapSize, final int x, final int y) {
- if (x < 0 || x >= heightMapSize || y < 0 || y >= heightMapSize) {
- return 0;
- }
-
- return heightMap[y * heightMapSize + x];
- }
-}
+/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.terrain.providers.simplearray; + +import java.util.Set; + +import com.ardor3d.extension.terrain.client.TerrainConfiguration; +import com.ardor3d.extension.terrain.client.TerrainSource; +import com.ardor3d.extension.terrain.util.Tile; +import com.ardor3d.math.Vector3; + +public class SimpleArrayTerrainSource implements TerrainSource { + private final int tileSize; + private final float[] heightData; + private final int size; + private final int availableClipmapLevels = 8; + + public SimpleArrayTerrainSource(final int tileSize, final float[] heightData, final int size) { + this.tileSize = tileSize; + this.heightData = heightData; + this.size = size; + } + + @Override + public TerrainConfiguration getConfiguration() throws Exception { + return new TerrainConfiguration(availableClipmapLevels, tileSize, new Vector3(1, 1, 1), 0.0f, 1.0f, true); + } + + @Override + public Set<Tile> getValidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX, + final int numTilesY) throws Exception { + return null; + } + + @Override + public Set<Tile> getInvalidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX, + final int numTilesY) throws Exception { + return null; + } + + @Override + public int getContributorId(final int clipmapLevel, final Tile tile) { + return 0; + } + + @Override + public float[] getTile(final int clipmapLevel, final Tile tile) throws Exception { + final int tileX = tile.getX(); + final int tileY = tile.getY(); + + final int baseClipmapLevel = availableClipmapLevels - clipmapLevel - 1; + + final int levelSize = 1 << baseClipmapLevel; + + final float[] data = new float[tileSize * tileSize]; + for (int y = 0; y < tileSize; y++) { + for (int x = 0; x < tileSize; x++) { + final int index = x + y * tileSize; + + final int heightX = (tileX * tileSize + x) * levelSize; + final int heightY = (tileY * tileSize + y) * levelSize; + data[index] = getHeight(heightData, size, heightX, heightY); + } + } + return data; + } + + private float getHeight(final float[] heightMap, final int heightMapSize, final int x, final int y) { + if (x < 0 || x >= heightMapSize || y < 0 || y >= heightMapSize) { + return 0; + } + + return heightMap[y * heightMapSize + x]; + } +} diff --git a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/simplearray/SimpleArrayTextureSource.java b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/simplearray/SimpleArrayTextureSource.java index 02fa121..924265d 100644 --- a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/simplearray/SimpleArrayTextureSource.java +++ b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/providers/simplearray/SimpleArrayTextureSource.java @@ -1,111 +1,111 @@ -/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.terrain.providers.simplearray;
-
-import java.nio.ByteBuffer;
-import java.util.Map;
-import java.util.Set;
-
-import com.ardor3d.extension.terrain.client.TextureConfiguration;
-import com.ardor3d.extension.terrain.client.TextureSource;
-import com.ardor3d.extension.terrain.util.Tile;
-import com.ardor3d.image.TextureStoreFormat;
-import com.ardor3d.util.geom.BufferUtils;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-
-public class SimpleArrayTextureSource implements TextureSource {
- private final int tileSize;
- private final byte[] colorData;
- private final int size;
- private final int availableClipmapLevels = 8;
-
- public SimpleArrayTextureSource(final int tileSize, final byte[] colorData, final int size) {
- this.tileSize = tileSize;
- this.colorData = colorData;
- this.size = size;
- }
-
- @Override
- public TextureConfiguration getConfiguration() throws Exception {
- final Map<Integer, TextureStoreFormat> textureStoreFormat = Maps.newHashMap();
- textureStoreFormat.put(0, TextureStoreFormat.RGBA8);
-
- return new TextureConfiguration(availableClipmapLevels, textureStoreFormat, tileSize, 1f, true, true);
- }
-
- @Override
- public Set<Tile> getValidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX,
- final int numTilesY) throws Exception {
- final Set<Tile> validTiles = Sets.newHashSet();
-
- final int levelSize = 1 << availableClipmapLevels - clipmapLevel;
-
- for (int y = 0; y < numTilesY; y++) {
- for (int x = 0; x < numTilesX; x++) {
- final int xx = tileX + x;
- final int yy = tileY + y;
- if (xx >= 0 && xx * tileSize * levelSize <= size && yy >= 0 && yy * tileSize * levelSize <= size) {
- final Tile tile = new Tile(xx, yy);
- validTiles.add(tile);
- }
- }
- }
-
- return validTiles;
- }
-
- @Override
- public Set<Tile> getInvalidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX,
- final int numTilesY) throws Exception {
- return null;
- }
-
- @Override
- public int getContributorId(final int clipmapLevel, final Tile tile) {
- return 0;
- }
-
- @Override
- public ByteBuffer getTile(final int clipmapLevel, final Tile tile) throws Exception {
- final int tileX = tile.getX();
- final int tileY = tile.getY();
-
- final int baseClipmapLevel = availableClipmapLevels - clipmapLevel - 1;
-
- final int levelSize = 1 << baseClipmapLevel;
-
- final ByteBuffer data = BufferUtils.createByteBufferOnHeap(tileSize * tileSize * 4);
- for (int y = 0; y < tileSize; y++) {
- for (int x = 0; x < tileSize; x++) {
- final int heightX = (tileX * tileSize + x) * levelSize;
- final int heightY = (tileY * tileSize + y) * levelSize;
-
- final int indexTile = (y * tileSize + x) * 4;
- final int index = heightY * size + heightX;
-
- if (heightX < 0 || heightX >= size || heightY < 0 || heightY >= size) {
- data.put(indexTile + 0, (byte) 0);
- data.put(indexTile + 1, (byte) 0);
- data.put(indexTile + 2, (byte) 0);
- data.put(indexTile + 3, (byte) 0);
- } else {
- data.put(indexTile + 0, colorData[index * 4 + 0]);
- data.put(indexTile + 1, colorData[index * 4 + 1]);
- data.put(indexTile + 2, colorData[index * 4 + 2]);
- data.put(indexTile + 3, colorData[index * 4 + 3]);
- }
- }
- }
-
- return data;
- }
-}
+/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.terrain.providers.simplearray; + +import java.nio.ByteBuffer; +import java.util.Map; +import java.util.Set; + +import com.ardor3d.extension.terrain.client.TextureConfiguration; +import com.ardor3d.extension.terrain.client.TextureSource; +import com.ardor3d.extension.terrain.util.Tile; +import com.ardor3d.image.TextureStoreFormat; +import com.ardor3d.util.geom.BufferUtils; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +public class SimpleArrayTextureSource implements TextureSource { + private final int tileSize; + private final byte[] colorData; + private final int size; + private final int availableClipmapLevels = 8; + + public SimpleArrayTextureSource(final int tileSize, final byte[] colorData, final int size) { + this.tileSize = tileSize; + this.colorData = colorData; + this.size = size; + } + + @Override + public TextureConfiguration getConfiguration() throws Exception { + final Map<Integer, TextureStoreFormat> textureStoreFormat = Maps.newHashMap(); + textureStoreFormat.put(0, TextureStoreFormat.RGBA8); + + return new TextureConfiguration(availableClipmapLevels, textureStoreFormat, tileSize, 1f, true, true); + } + + @Override + public Set<Tile> getValidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX, + final int numTilesY) throws Exception { + final Set<Tile> validTiles = Sets.newHashSet(); + + final int levelSize = 1 << availableClipmapLevels - clipmapLevel; + + for (int y = 0; y < numTilesY; y++) { + for (int x = 0; x < numTilesX; x++) { + final int xx = tileX + x; + final int yy = tileY + y; + if (xx >= 0 && xx * tileSize * levelSize <= size && yy >= 0 && yy * tileSize * levelSize <= size) { + final Tile tile = new Tile(xx, yy); + validTiles.add(tile); + } + } + } + + return validTiles; + } + + @Override + public Set<Tile> getInvalidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX, + final int numTilesY) throws Exception { + return null; + } + + @Override + public int getContributorId(final int clipmapLevel, final Tile tile) { + return 0; + } + + @Override + public ByteBuffer getTile(final int clipmapLevel, final Tile tile) throws Exception { + final int tileX = tile.getX(); + final int tileY = tile.getY(); + + final int baseClipmapLevel = availableClipmapLevels - clipmapLevel - 1; + + final int levelSize = 1 << baseClipmapLevel; + + final ByteBuffer data = BufferUtils.createByteBufferOnHeap(tileSize * tileSize * 4); + for (int y = 0; y < tileSize; y++) { + for (int x = 0; x < tileSize; x++) { + final int heightX = (tileX * tileSize + x) * levelSize; + final int heightY = (tileY * tileSize + y) * levelSize; + + final int indexTile = (y * tileSize + x) * 4; + final int index = heightY * size + heightX; + + if (heightX < 0 || heightX >= size || heightY < 0 || heightY >= size) { + data.put(indexTile + 0, (byte) 0); + data.put(indexTile + 1, (byte) 0); + data.put(indexTile + 2, (byte) 0); + data.put(indexTile + 3, (byte) 0); + } else { + data.put(indexTile + 0, colorData[index * 4 + 0]); + data.put(indexTile + 1, colorData[index * 4 + 1]); + data.put(indexTile + 2, colorData[index * 4 + 2]); + data.put(indexTile + 3, colorData[index * 4 + 3]); + } + } + } + + return data; + } +} diff --git a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/util/BresenhamYUpGridTracer.java b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/util/BresenhamYUpGridTracer.java index 53e8c2c..6ea35cd 100644 --- a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/util/BresenhamYUpGridTracer.java +++ b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/util/BresenhamYUpGridTracer.java @@ -1,145 +1,145 @@ -/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.terrain.util;
-
-import com.ardor3d.math.MathUtils;
-import com.ardor3d.math.Ray3;
-import com.ardor3d.math.Vector2;
-import com.ardor3d.math.Vector3;
-import com.ardor3d.math.type.ReadOnlyVector3;
-
-/**
- * An implementation of AbstractBresenhamTracer that works on the XZ plane, with positive Y as up.
- */
-public class BresenhamYUpGridTracer extends AbstractBresenhamTracer {
-
- // a "near zero" value we will use to determine if the walkRay is
- // perpendicular to the grid.
- protected static double TOLERANCE = 0.0000001;
-
- private int _stepXDirection;
- private int _stepZDirection;
-
- // from current position along ray
- private double _distToNextXIntersection, _distToNextZIntersection;
- private double _distBetweenXIntersections, _distBetweenZIntersections;
-
- @Override
- public void startWalk(final Ray3 walkRay) {
- // store ray
- _walkRay.set(walkRay);
-
- // simplify access to direction
- final ReadOnlyVector3 direction = _walkRay.getDirection();
-
- // Move start point to grid space
- final Vector3 start = _walkRay.getOrigin().subtract(_gridOrigin, null);
-
- _gridLocation[0] = (int) MathUtils.floor(start.getX() / _gridSpacing.getX());
- _gridLocation[1] = (int) MathUtils.floor(start.getZ() / _gridSpacing.getZ());
-
- final double invDirX = 1.0 / direction.getX();
- final double invDirZ = 1.0 / direction.getZ();
-
- // Check which direction on the X world axis we are moving.
- if (direction.getX() > BresenhamYUpGridTracer.TOLERANCE) {
- _distToNextXIntersection = ((_gridLocation[0] + 1) * _gridSpacing.getX() - start.getX()) * invDirX;
- _distBetweenXIntersections = _gridSpacing.getX() * invDirX;
- _stepXDirection = 1;
- } else if (direction.getX() < -BresenhamYUpGridTracer.TOLERANCE) {
- _distToNextXIntersection = (start.getX() - _gridLocation[0] * _gridSpacing.getX()) * -direction.getX();
- _distBetweenXIntersections = -_gridSpacing.getX() * invDirX;
- _stepXDirection = -1;
- } else {
- _distToNextXIntersection = Double.MAX_VALUE;
- _distBetweenXIntersections = Double.MAX_VALUE;
- _stepXDirection = 0;
- }
-
- // Check which direction on the Z world axis we are moving.
- if (direction.getZ() > BresenhamYUpGridTracer.TOLERANCE) {
- _distToNextZIntersection = ((_gridLocation[1] + 1) * _gridSpacing.getZ() - start.getZ()) * invDirZ;
- _distBetweenZIntersections = _gridSpacing.getZ() * invDirZ;
- _stepZDirection = 1;
- } else if (direction.getZ() < -BresenhamYUpGridTracer.TOLERANCE) {
- _distToNextZIntersection = (start.getZ() - _gridLocation[1] * _gridSpacing.getZ()) * -direction.getZ();
- _distBetweenZIntersections = -_gridSpacing.getZ() * invDirZ;
- _stepZDirection = -1;
- } else {
- _distToNextZIntersection = Double.MAX_VALUE;
- _distBetweenZIntersections = Double.MAX_VALUE;
- _stepZDirection = 0;
- }
-
- // Reset some variables
- _rayLocation.set(start);
- _totalTravel = 0.0;
- _stepDirection = Direction.None;
- }
-
- @Override
- public void next() {
- // Walk us to our next location based on distances to next X or Z grid
- // line.
- if (_distToNextXIntersection < _distToNextZIntersection) {
- _totalTravel = _distToNextXIntersection;
- _gridLocation[0] += _stepXDirection;
- _distToNextXIntersection += _distBetweenXIntersections;
- switch (_stepXDirection) {
- case -1:
- _stepDirection = Direction.NegativeX;
- break;
- case 0:
- _stepDirection = Direction.None;
- break;
- case 1:
- _stepDirection = Direction.PositiveX;
- break;
- }
- } else {
- _totalTravel = _distToNextZIntersection;
- _gridLocation[1] += _stepZDirection;
- _distToNextZIntersection += _distBetweenZIntersections;
- switch (_stepZDirection) {
- case -1:
- _stepDirection = Direction.NegativeZ;
- break;
- case 0:
- _stepDirection = Direction.None;
- break;
- case 1:
- _stepDirection = Direction.PositiveZ;
- break;
- }
- }
-
- _rayLocation.set(_walkRay.getDirection()).multiplyLocal(_totalTravel).addLocal(_walkRay.getOrigin());
- }
-
- @Override
- public boolean isRayPerpendicularToGrid() {
- return _stepXDirection == 0 && _stepZDirection == 0;
- }
-
- @Override
- public Vector3 get3DPoint(final double gridX, final double gridY, final double height, final Vector3 store) {
- final Vector3 rVal = store != null ? store : new Vector3();
-
- return rVal.set(gridX, height, gridY);
- }
-
- @Override
- public Vector2 get2DPoint(final ReadOnlyVector3 worldLocation, final Vector2 store) {
- final Vector2 rVal = store != null ? store : new Vector2();
-
- return rVal.set(worldLocation.getX(), worldLocation.getZ());
- }
-}
+/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.terrain.util; + +import com.ardor3d.math.MathUtils; +import com.ardor3d.math.Ray3; +import com.ardor3d.math.Vector2; +import com.ardor3d.math.Vector3; +import com.ardor3d.math.type.ReadOnlyVector3; + +/** + * An implementation of AbstractBresenhamTracer that works on the XZ plane, with positive Y as up. + */ +public class BresenhamYUpGridTracer extends AbstractBresenhamTracer { + + // a "near zero" value we will use to determine if the walkRay is + // perpendicular to the grid. + protected static double TOLERANCE = 0.0000001; + + private int _stepXDirection; + private int _stepZDirection; + + // from current position along ray + private double _distToNextXIntersection, _distToNextZIntersection; + private double _distBetweenXIntersections, _distBetweenZIntersections; + + @Override + public void startWalk(final Ray3 walkRay) { + // store ray + _walkRay.set(walkRay); + + // simplify access to direction + final ReadOnlyVector3 direction = _walkRay.getDirection(); + + // Move start point to grid space + final Vector3 start = _walkRay.getOrigin().subtract(_gridOrigin, null); + + _gridLocation[0] = (int) MathUtils.floor(start.getX() / _gridSpacing.getX()); + _gridLocation[1] = (int) MathUtils.floor(start.getZ() / _gridSpacing.getZ()); + + final double invDirX = 1.0 / direction.getX(); + final double invDirZ = 1.0 / direction.getZ(); + + // Check which direction on the X world axis we are moving. + if (direction.getX() > BresenhamYUpGridTracer.TOLERANCE) { + _distToNextXIntersection = ((_gridLocation[0] + 1) * _gridSpacing.getX() - start.getX()) * invDirX; + _distBetweenXIntersections = _gridSpacing.getX() * invDirX; + _stepXDirection = 1; + } else if (direction.getX() < -BresenhamYUpGridTracer.TOLERANCE) { + _distToNextXIntersection = (start.getX() - _gridLocation[0] * _gridSpacing.getX()) * -direction.getX(); + _distBetweenXIntersections = -_gridSpacing.getX() * invDirX; + _stepXDirection = -1; + } else { + _distToNextXIntersection = Double.MAX_VALUE; + _distBetweenXIntersections = Double.MAX_VALUE; + _stepXDirection = 0; + } + + // Check which direction on the Z world axis we are moving. + if (direction.getZ() > BresenhamYUpGridTracer.TOLERANCE) { + _distToNextZIntersection = ((_gridLocation[1] + 1) * _gridSpacing.getZ() - start.getZ()) * invDirZ; + _distBetweenZIntersections = _gridSpacing.getZ() * invDirZ; + _stepZDirection = 1; + } else if (direction.getZ() < -BresenhamYUpGridTracer.TOLERANCE) { + _distToNextZIntersection = (start.getZ() - _gridLocation[1] * _gridSpacing.getZ()) * -direction.getZ(); + _distBetweenZIntersections = -_gridSpacing.getZ() * invDirZ; + _stepZDirection = -1; + } else { + _distToNextZIntersection = Double.MAX_VALUE; + _distBetweenZIntersections = Double.MAX_VALUE; + _stepZDirection = 0; + } + + // Reset some variables + _rayLocation.set(start); + _totalTravel = 0.0; + _stepDirection = Direction.None; + } + + @Override + public void next() { + // Walk us to our next location based on distances to next X or Z grid + // line. + if (_distToNextXIntersection < _distToNextZIntersection) { + _totalTravel = _distToNextXIntersection; + _gridLocation[0] += _stepXDirection; + _distToNextXIntersection += _distBetweenXIntersections; + switch (_stepXDirection) { + case -1: + _stepDirection = Direction.NegativeX; + break; + case 0: + _stepDirection = Direction.None; + break; + case 1: + _stepDirection = Direction.PositiveX; + break; + } + } else { + _totalTravel = _distToNextZIntersection; + _gridLocation[1] += _stepZDirection; + _distToNextZIntersection += _distBetweenZIntersections; + switch (_stepZDirection) { + case -1: + _stepDirection = Direction.NegativeZ; + break; + case 0: + _stepDirection = Direction.None; + break; + case 1: + _stepDirection = Direction.PositiveZ; + break; + } + } + + _rayLocation.set(_walkRay.getDirection()).multiplyLocal(_totalTravel).addLocal(_walkRay.getOrigin()); + } + + @Override + public boolean isRayPerpendicularToGrid() { + return _stepXDirection == 0 && _stepZDirection == 0; + } + + @Override + public Vector3 get3DPoint(final double gridX, final double gridY, final double height, final Vector3 store) { + final Vector3 rVal = store != null ? store : new Vector3(); + + return rVal.set(gridX, height, gridY); + } + + @Override + public Vector2 get2DPoint(final ReadOnlyVector3 worldLocation, final Vector2 store) { + final Vector2 rVal = store != null ? store : new Vector2(); + + return rVal.set(worldLocation.getX(), worldLocation.getZ()); + } +} diff --git a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/util/BresenhamZUpGridTracer.java b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/util/BresenhamZUpGridTracer.java index 9e39102..eaa288b 100644 --- a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/util/BresenhamZUpGridTracer.java +++ b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/util/BresenhamZUpGridTracer.java @@ -1,145 +1,145 @@ -/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.terrain.util;
-
-import com.ardor3d.math.MathUtils;
-import com.ardor3d.math.Ray3;
-import com.ardor3d.math.Vector2;
-import com.ardor3d.math.Vector3;
-import com.ardor3d.math.type.ReadOnlyVector3;
-
-/**
- * An implementation of AbstractBresenhamTracer that works on the XY plane, with positive Z as up.
- */
-public class BresenhamZUpGridTracer extends AbstractBresenhamTracer {
-
- // a "near zero" value we will use to determine if the walkRay is
- // perpendicular to the grid.
- protected static double TOLERANCE = 0.0000001;
-
- private int _stepXDirection;
- private int _stepYDirection;
-
- // from current position along ray
- private double _distToNextXIntersection, _distToNextYIntersection;
- private double _distBetweenXIntersections, _distBetweenYIntersections;
-
- @Override
- public void startWalk(final Ray3 walkRay) {
- // store ray
- _walkRay.set(walkRay);
-
- // simplify access to direction
- final ReadOnlyVector3 direction = _walkRay.getDirection();
-
- // Move start point to grid space
- final Vector3 start = _walkRay.getOrigin().subtract(_gridOrigin, null);
-
- _gridLocation[0] = (int) MathUtils.floor(start.getX() / _gridSpacing.getX());
- _gridLocation[1] = (int) MathUtils.floor(start.getY() / _gridSpacing.getY());
-
- final double invDirX = 1.0 / direction.getX();
- final double invDirY = 1.0 / direction.getY();
-
- // Check which direction on the X world axis we are moving.
- if (direction.getX() > BresenhamZUpGridTracer.TOLERANCE) {
- _distToNextXIntersection = ((_gridLocation[0] + 1) * _gridSpacing.getX() - start.getX()) * invDirX;
- _distBetweenXIntersections = _gridSpacing.getX() * invDirX;
- _stepXDirection = 1;
- } else if (direction.getX() < -BresenhamZUpGridTracer.TOLERANCE) {
- _distToNextXIntersection = (start.getX() - _gridLocation[0] * _gridSpacing.getX()) * -direction.getX();
- _distBetweenXIntersections = -_gridSpacing.getX() * invDirX;
- _stepXDirection = -1;
- } else {
- _distToNextXIntersection = Double.MAX_VALUE;
- _distBetweenXIntersections = Double.MAX_VALUE;
- _stepXDirection = 0;
- }
-
- // Check which direction on the Y world axis we are moving.
- if (direction.getY() > BresenhamZUpGridTracer.TOLERANCE) {
- _distToNextYIntersection = ((_gridLocation[1] + 1) * _gridSpacing.getY() - start.getY()) * invDirY;
- _distBetweenYIntersections = _gridSpacing.getY() * invDirY;
- _stepYDirection = 1;
- } else if (direction.getY() < -BresenhamZUpGridTracer.TOLERANCE) {
- _distToNextYIntersection = (start.getY() - _gridLocation[1] * _gridSpacing.getY()) * -direction.getY();
- _distBetweenYIntersections = -_gridSpacing.getY() * invDirY;
- _stepYDirection = -1;
- } else {
- _distToNextYIntersection = Double.MAX_VALUE;
- _distBetweenYIntersections = Double.MAX_VALUE;
- _stepYDirection = 0;
- }
-
- // Reset some variables
- _rayLocation.set(start);
- _totalTravel = 0.0;
- _stepDirection = Direction.None;
- }
-
- @Override
- public void next() {
- // Walk us to our next location based on distances to next X or Y grid
- // line.
- if (_distToNextXIntersection < _distToNextYIntersection) {
- _totalTravel = _distToNextXIntersection;
- _gridLocation[0] += _stepXDirection;
- _distToNextXIntersection += _distBetweenXIntersections;
- switch (_stepXDirection) {
- case -1:
- _stepDirection = Direction.NegativeX;
- break;
- case 0:
- _stepDirection = Direction.None;
- break;
- case 1:
- _stepDirection = Direction.PositiveX;
- break;
- }
- } else {
- _totalTravel = _distToNextYIntersection;
- _gridLocation[1] += _stepYDirection;
- _distToNextYIntersection += _distBetweenYIntersections;
- switch (_stepYDirection) {
- case -1:
- _stepDirection = Direction.NegativeY;
- break;
- case 0:
- _stepDirection = Direction.None;
- break;
- case 1:
- _stepDirection = Direction.PositiveY;
- break;
- }
- }
-
- _rayLocation.set(_walkRay.getDirection()).multiplyLocal(_totalTravel).addLocal(_walkRay.getOrigin());
- }
-
- @Override
- public boolean isRayPerpendicularToGrid() {
- return _stepXDirection == 0 && _stepYDirection == 0;
- }
-
- @Override
- public Vector3 get3DPoint(final double gridX, final double gridY, final double height, final Vector3 store) {
- final Vector3 rVal = store != null ? store : new Vector3();
-
- return rVal.set(gridX, gridY, height);
- }
-
- @Override
- public Vector2 get2DPoint(final ReadOnlyVector3 worldLocation, final Vector2 store) {
- final Vector2 rVal = store != null ? store : new Vector2();
-
- return rVal.set(worldLocation.getX(), worldLocation.getY());
- }
-}
+/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.terrain.util; + +import com.ardor3d.math.MathUtils; +import com.ardor3d.math.Ray3; +import com.ardor3d.math.Vector2; +import com.ardor3d.math.Vector3; +import com.ardor3d.math.type.ReadOnlyVector3; + +/** + * An implementation of AbstractBresenhamTracer that works on the XY plane, with positive Z as up. + */ +public class BresenhamZUpGridTracer extends AbstractBresenhamTracer { + + // a "near zero" value we will use to determine if the walkRay is + // perpendicular to the grid. + protected static double TOLERANCE = 0.0000001; + + private int _stepXDirection; + private int _stepYDirection; + + // from current position along ray + private double _distToNextXIntersection, _distToNextYIntersection; + private double _distBetweenXIntersections, _distBetweenYIntersections; + + @Override + public void startWalk(final Ray3 walkRay) { + // store ray + _walkRay.set(walkRay); + + // simplify access to direction + final ReadOnlyVector3 direction = _walkRay.getDirection(); + + // Move start point to grid space + final Vector3 start = _walkRay.getOrigin().subtract(_gridOrigin, null); + + _gridLocation[0] = (int) MathUtils.floor(start.getX() / _gridSpacing.getX()); + _gridLocation[1] = (int) MathUtils.floor(start.getY() / _gridSpacing.getY()); + + final double invDirX = 1.0 / direction.getX(); + final double invDirY = 1.0 / direction.getY(); + + // Check which direction on the X world axis we are moving. + if (direction.getX() > BresenhamZUpGridTracer.TOLERANCE) { + _distToNextXIntersection = ((_gridLocation[0] + 1) * _gridSpacing.getX() - start.getX()) * invDirX; + _distBetweenXIntersections = _gridSpacing.getX() * invDirX; + _stepXDirection = 1; + } else if (direction.getX() < -BresenhamZUpGridTracer.TOLERANCE) { + _distToNextXIntersection = (start.getX() - _gridLocation[0] * _gridSpacing.getX()) * -direction.getX(); + _distBetweenXIntersections = -_gridSpacing.getX() * invDirX; + _stepXDirection = -1; + } else { + _distToNextXIntersection = Double.MAX_VALUE; + _distBetweenXIntersections = Double.MAX_VALUE; + _stepXDirection = 0; + } + + // Check which direction on the Y world axis we are moving. + if (direction.getY() > BresenhamZUpGridTracer.TOLERANCE) { + _distToNextYIntersection = ((_gridLocation[1] + 1) * _gridSpacing.getY() - start.getY()) * invDirY; + _distBetweenYIntersections = _gridSpacing.getY() * invDirY; + _stepYDirection = 1; + } else if (direction.getY() < -BresenhamZUpGridTracer.TOLERANCE) { + _distToNextYIntersection = (start.getY() - _gridLocation[1] * _gridSpacing.getY()) * -direction.getY(); + _distBetweenYIntersections = -_gridSpacing.getY() * invDirY; + _stepYDirection = -1; + } else { + _distToNextYIntersection = Double.MAX_VALUE; + _distBetweenYIntersections = Double.MAX_VALUE; + _stepYDirection = 0; + } + + // Reset some variables + _rayLocation.set(start); + _totalTravel = 0.0; + _stepDirection = Direction.None; + } + + @Override + public void next() { + // Walk us to our next location based on distances to next X or Y grid + // line. + if (_distToNextXIntersection < _distToNextYIntersection) { + _totalTravel = _distToNextXIntersection; + _gridLocation[0] += _stepXDirection; + _distToNextXIntersection += _distBetweenXIntersections; + switch (_stepXDirection) { + case -1: + _stepDirection = Direction.NegativeX; + break; + case 0: + _stepDirection = Direction.None; + break; + case 1: + _stepDirection = Direction.PositiveX; + break; + } + } else { + _totalTravel = _distToNextYIntersection; + _gridLocation[1] += _stepYDirection; + _distToNextYIntersection += _distBetweenYIntersections; + switch (_stepYDirection) { + case -1: + _stepDirection = Direction.NegativeY; + break; + case 0: + _stepDirection = Direction.None; + break; + case 1: + _stepDirection = Direction.PositiveY; + break; + } + } + + _rayLocation.set(_walkRay.getDirection()).multiplyLocal(_totalTravel).addLocal(_walkRay.getOrigin()); + } + + @Override + public boolean isRayPerpendicularToGrid() { + return _stepXDirection == 0 && _stepYDirection == 0; + } + + @Override + public Vector3 get3DPoint(final double gridX, final double gridY, final double height, final Vector3 store) { + final Vector3 rVal = store != null ? store : new Vector3(); + + return rVal.set(gridX, gridY, height); + } + + @Override + public Vector2 get2DPoint(final ReadOnlyVector3 worldLocation, final Vector2 store) { + final Vector2 rVal = store != null ? store : new Vector2(); + + return rVal.set(worldLocation.getX(), worldLocation.getY()); + } +} diff --git a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/util/LevelData.java b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/util/LevelData.java index e2e3964..589f844 100644 --- a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/util/LevelData.java +++ b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/util/LevelData.java @@ -1,19 +1,19 @@ -
-package com.ardor3d.extension.terrain.util;
-
-import java.nio.ByteBuffer;
-
-public class LevelData {
- public int unit;
- public int x = Integer.MAX_VALUE, y = Integer.MAX_VALUE;
- public int offsetX, offsetY;
- public int textureOffsetX, textureOffsetY;
- public Region clipRegion;
-
- public ByteBuffer sliceData;
-
- public LevelData(final int unit, final int textureSize) {
- this.unit = unit;
- clipRegion = new Region(unit, 0, 0, textureSize, textureSize);
- }
-}
+ +package com.ardor3d.extension.terrain.util; + +import java.nio.ByteBuffer; + +public class LevelData { + public int unit; + public int x = Integer.MAX_VALUE, y = Integer.MAX_VALUE; + public int offsetX, offsetY; + public int textureOffsetX, textureOffsetY; + public Region clipRegion; + + public ByteBuffer sliceData; + + public LevelData(final int unit, final int textureSize) { + this.unit = unit; + clipRegion = new Region(unit, 0, 0, textureSize, textureSize); + } +} diff --git a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/util/Region.java b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/util/Region.java index 19a280a..d46d85f 100644 --- a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/util/Region.java +++ b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/util/Region.java @@ -1,249 +1,249 @@ -/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.terrain.util;
-
-/**
- * Used to calculate clipmap block boundaries etc
- */
-public class Region {
- private int x;
- private int y;
- private int width;
- private int height;
-
- private int left;
- private int right;
- private int top;
- private int bottom;
-
- private final int level;
-
- public Region(final int x, final int y, final int width, final int height) {
- this(0, x, y, width, height);
- }
-
- public Region(final int level, final int x, final int y, final int width, final int height) {
- this.level = level;
-
- this.x = x;
- this.y = y;
- this.width = width;
- this.height = height;
-
- left = x;
- right = x + width;
- top = y;
- bottom = y + height;
- }
-
- /**
- * @return the x
- */
- public int getX() {
- return x;
- }
-
- /**
- * @return the y
- */
- public int getY() {
- return y;
- }
-
- /**
- * @param x
- * the x to set
- */
- public void setX(final int x) {
- this.x = x;
- left = x;
- right = x + width;
- }
-
- /**
- * @param y
- * the y to set
- */
- public void setY(final int y) {
- this.y = y;
- top = y;
- bottom = y + height;
- }
-
- public void setWidth(final int width) {
- this.width = width;
- right = x + width;
- }
-
- public void setHeight(final int height) {
- this.height = height;
- bottom = y + height;
- }
-
- /**
- * @return the left
- */
- public int getLeft() {
- return left;
- }
-
- /**
- * @return the right
- */
- public int getRight() {
- return right;
- }
-
- /**
- * @return the top
- */
- public int getTop() {
- return top;
- }
-
- /**
- * @return the bottom
- */
- public int getBottom() {
- return bottom;
- }
-
- /**
- * @return the width
- */
- public int getWidth() {
- return width;
- }
-
- /**
- * @return the height
- */
- public int getHeight() {
- return height;
- }
-
- public boolean intersects(final Region r) {
- int tw = width;
- int th = height;
- int rw = r.width;
- int rh = r.height;
- if (rw <= 0 || rh <= 0 || tw <= 0 || th <= 0) {
- return false;
- }
- final int tx = x;
- final int ty = y;
- final int rx = r.x;
- final int ry = r.y;
- rw += rx;
- rh += ry;
- tw += tx;
- th += ty;
- // overflow || intersect
- return (rw < rx || rw > tx) && (rh < ry || rh > ty) && (tw < tx || tw > rx) && (th < ty || th > ry);
- }
-
- public Region intersection(final Region r) {
- int tx1 = x;
- int ty1 = y;
- final int rx1 = r.x;
- final int ry1 = r.y;
- long tx2 = tx1;
- tx2 += width;
- long ty2 = ty1;
- ty2 += height;
- long rx2 = rx1;
- rx2 += r.width;
- long ry2 = ry1;
- ry2 += r.height;
- if (tx1 < rx1) {
- tx1 = rx1;
- }
- if (ty1 < ry1) {
- ty1 = ry1;
- }
- if (tx2 > rx2) {
- tx2 = rx2;
- }
- if (ty2 > ry2) {
- ty2 = ry2;
- }
- tx2 -= tx1;
- ty2 -= ty1;
- // tx2,ty2 will never overflow (they will never be
- // larger than the smallest of the two source w,h)
- // they might underflow, though...
- if (tx2 < Integer.MIN_VALUE) {
- tx2 = Integer.MIN_VALUE;
- }
- if (ty2 < Integer.MIN_VALUE) {
- ty2 = Integer.MIN_VALUE;
- }
-
- r.setX(tx1);
- r.setY(ty1);
- r.setWidth((int) tx2);
- r.setHeight((int) ty2);
-
- return r;
- }
-
- public int getLevel() {
- return level;
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + height;
- result = prime * result + level;
- result = prime * result + width;
- result = prime * result + x;
- result = prime * result + y;
- return result;
- }
-
- @Override
- public boolean equals(final Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (!(obj instanceof Region)) {
- return false;
- }
- final Region other = (Region) obj;
- if (height != other.height) {
- return false;
- }
- if (level != other.level) {
- return false;
- }
- if (width != other.width) {
- return false;
- }
- if (x != other.x) {
- return false;
- }
- if (y != other.y) {
- return false;
- }
- return true;
- }
-
- @Override
- public String toString() {
- return "Region [level=" + level + ", x=" + x + ", y=" + y + ", width=" + width + ", height=" + height + "]";
- }
-
-}
+/** + * Copyright (c) 2008-2012 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.extension.terrain.util; + +/** + * Used to calculate clipmap block boundaries etc + */ +public class Region { + private int x; + private int y; + private int width; + private int height; + + private int left; + private int right; + private int top; + private int bottom; + + private final int level; + + public Region(final int x, final int y, final int width, final int height) { + this(0, x, y, width, height); + } + + public Region(final int level, final int x, final int y, final int width, final int height) { + this.level = level; + + this.x = x; + this.y = y; + this.width = width; + this.height = height; + + left = x; + right = x + width; + top = y; + bottom = y + height; + } + + /** + * @return the x + */ + public int getX() { + return x; + } + + /** + * @return the y + */ + public int getY() { + return y; + } + + /** + * @param x + * the x to set + */ + public void setX(final int x) { + this.x = x; + left = x; + right = x + width; + } + + /** + * @param y + * the y to set + */ + public void setY(final int y) { + this.y = y; + top = y; + bottom = y + height; + } + + public void setWidth(final int width) { + this.width = width; + right = x + width; + } + + public void setHeight(final int height) { + this.height = height; + bottom = y + height; + } + + /** + * @return the left + */ + public int getLeft() { + return left; + } + + /** + * @return the right + */ + public int getRight() { + return right; + } + + /** + * @return the top + */ + public int getTop() { + return top; + } + + /** + * @return the bottom + */ + public int getBottom() { + return bottom; + } + + /** + * @return the width + */ + public int getWidth() { + return width; + } + + /** + * @return the height + */ + public int getHeight() { + return height; + } + + public boolean intersects(final Region r) { + int tw = width; + int th = height; + int rw = r.width; + int rh = r.height; + if (rw <= 0 || rh <= 0 || tw <= 0 || th <= 0) { + return false; + } + final int tx = x; + final int ty = y; + final int rx = r.x; + final int ry = r.y; + rw += rx; + rh += ry; + tw += tx; + th += ty; + // overflow || intersect + return (rw < rx || rw > tx) && (rh < ry || rh > ty) && (tw < tx || tw > rx) && (th < ty || th > ry); + } + + public Region intersection(final Region r) { + int tx1 = x; + int ty1 = y; + final int rx1 = r.x; + final int ry1 = r.y; + long tx2 = tx1; + tx2 += width; + long ty2 = ty1; + ty2 += height; + long rx2 = rx1; + rx2 += r.width; + long ry2 = ry1; + ry2 += r.height; + if (tx1 < rx1) { + tx1 = rx1; + } + if (ty1 < ry1) { + ty1 = ry1; + } + if (tx2 > rx2) { + tx2 = rx2; + } + if (ty2 > ry2) { + ty2 = ry2; + } + tx2 -= tx1; + ty2 -= ty1; + // tx2,ty2 will never overflow (they will never be + // larger than the smallest of the two source w,h) + // they might underflow, though... + if (tx2 < Integer.MIN_VALUE) { + tx2 = Integer.MIN_VALUE; + } + if (ty2 < Integer.MIN_VALUE) { + ty2 = Integer.MIN_VALUE; + } + + r.setX(tx1); + r.setY(ty1); + r.setWidth((int) tx2); + r.setHeight((int) ty2); + + return r; + } + + public int getLevel() { + return level; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + height; + result = prime * result + level; + result = prime * result + width; + result = prime * result + x; + result = prime * result + y; + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof Region)) { + return false; + } + final Region other = (Region) obj; + if (height != other.height) { + return false; + } + if (level != other.level) { + return false; + } + if (width != other.width) { + return false; + } + if (x != other.x) { + return false; + } + if (y != other.y) { + return false; + } + return true; + } + + @Override + public String toString() { + return "Region [level=" + level + ", x=" + x + ", y=" + y + ", width=" + width + ", height=" + height + "]"; + } + +} diff --git a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/util/Tile.java b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/util/Tile.java index afefc37..7210382 100644 --- a/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/util/Tile.java +++ b/ardor3d-terrain/src/main/java/com/ardor3d/extension/terrain/util/Tile.java @@ -1,48 +1,48 @@ -
-package com.ardor3d.extension.terrain.util;
-
-import java.io.Serializable;
-
-public class Tile implements Serializable {
- private static final long serialVersionUID = 1L;
-
- private final int x, y;
-
- public Tile(final int x, final int y) {
- this.x = x;
- this.y = y;
- }
-
- public int getX() {
- return x;
- }
-
- public int getY() {
- return y;
- }
-
- @Override
- public int hashCode() {
- int result = 17;
- result += 31 * result + x;
- result += 31 * result + y;
- return result;
- }
-
- @Override
- public boolean equals(final Object obj) {
- if (this == obj) {
- return true;
- }
- if (!(obj instanceof Tile)) {
- return false;
- }
- final Tile other = (Tile) obj;
- return x == other.x && y == other.y;
- }
-
- @Override
- public String toString() {
- return "Tile [x=" + x + ", y=" + y + "]";
- }
-}
+ +package com.ardor3d.extension.terrain.util; + +import java.io.Serializable; + +public class Tile implements Serializable { + private static final long serialVersionUID = 1L; + + private final int x, y; + + public Tile(final int x, final int y) { + this.x = x; + this.y = y; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + @Override + public int hashCode() { + int result = 17; + result += 31 * result + x; + result += 31 * result + y; + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof Tile)) { + return false; + } + final Tile other = (Tile) obj; + return x == other.x && y == other.y; + } + + @Override + public String toString() { + return "Tile [x=" + x + ", y=" + y + "]"; + } +} |