diff --git a/net/terrain.json b/net/terrain.json index 8b629c3f..6cd55ebd 100644 --- a/net/terrain.json +++ b/net/terrain.json @@ -54,6 +54,19 @@ "type" : "FIXED_INT" }, + { + "name" : "voxelX", + "type" : "FIXED_INT" + }, + { + "name" : "voxelY", + "type" : "FIXED_INT" + }, + { + "name" : "voxelZ", + "type" : "FIXED_INT" + }, + @@ -111,11 +124,40 @@ ] }, { - "messageName" : "Update", + "messageName" : "RequestEditVoxel", "data" : [ "worldX", "worldY", - "worldZ" + "worldZ", + "voxelX", + "voxelY", + "voxelZ", + "terrainWeight", + "terrainValue" + ] + }, + { + "messageName" : "UpdateVoxel", + "data" : [ + "worldX", + "worldY", + "worldZ", + "voxelX", + "voxelY", + "voxelZ", + "terrainWeight", + "terrainValue" + ] + }, + { + "messageName" : "RequestUseTerrainPalette", + "data" : [ + "realLocationX", + "realLocationY", + "realLocationZ", + "value", + "terrainWeight", + "terrainValue" ] }, { diff --git a/src/main/java/electrosphere/client/foliagemanager/ClientFoliageManager.java b/src/main/java/electrosphere/client/foliagemanager/ClientFoliageManager.java index fa0bea75..a9fa819a 100644 --- a/src/main/java/electrosphere/client/foliagemanager/ClientFoliageManager.java +++ b/src/main/java/electrosphere/client/foliagemanager/ClientFoliageManager.java @@ -141,7 +141,7 @@ public class ClientFoliageManager { modelMatrix.rotate(new Quaterniond(grassRotation)); modelMatrix.scale(new Vector3d(EntityUtils.getScale(grassEntity))); - instancedActor.setAttribute(modelMatrixAttribute, modelMatrix); + instancedActor.setAttribute(modelMatrixAttribute, new Matrix4f(modelMatrix)); //draw // instancedActor.draw(Globals.renderingEngine.getRenderPipelineState()); diff --git a/src/main/java/electrosphere/client/terrain/cache/ChunkData.java b/src/main/java/electrosphere/client/terrain/cache/ChunkData.java index e81e1a74..41884b78 100644 --- a/src/main/java/electrosphere/client/terrain/cache/ChunkData.java +++ b/src/main/java/electrosphere/client/terrain/cache/ChunkData.java @@ -7,8 +7,10 @@ import electrosphere.server.terrain.manager.ServerTerrainChunk; */ public class ChunkData { - //The size of a chunk + //The size of a chunk in virtual data public static final int CHUNK_SIZE = ServerTerrainChunk.CHUNK_DIMENSION; + //The size of the data passed into marching cubes/transvoxel algorithm to get a fully connected and seamless chunk + public static final int CHUNK_DATA_GENERATOR_SIZE = ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; //What type of terrain is in this voxel, eg stone vs dirt vs grass, etc int[][][] voxelType; diff --git a/src/main/java/electrosphere/client/terrain/cells/DrawCell.java b/src/main/java/electrosphere/client/terrain/cells/DrawCell.java index 10429252..30573ca5 100644 --- a/src/main/java/electrosphere/client/terrain/cells/DrawCell.java +++ b/src/main/java/electrosphere/client/terrain/cells/DrawCell.java @@ -72,7 +72,7 @@ public class DrawCell { if(modelEntity != null){ Globals.clientScene.deregisterEntity(modelEntity); } - modelEntity = TerrainChunk.clientCreateTerrainChunkEntity(data.getVoxelWeight(), data.getVoxelType()); + modelEntity = TerrainChunk.clientCreateTerrainChunkEntity(data.getVoxelWeight(), data.getVoxelType(), 0); // TerrainChunk.createTerrainChunkEntity(); // Model terrainModel = RenderUtils.createMinimizedTerrainModelPrecomputedShader(heightmap, texturemap, program, stride); // Mesh terrainMesh = terrainModel.meshes.get(0); @@ -96,10 +96,6 @@ public class DrawCell { // EntityUtils.getPosition(modelEntity).set(getRealPos()); ClientEntityUtils.initiallyPositionEntity(modelEntity, getRealPos()); } - - public void retireCell(){ - EntityUtils.cleanUpEntity(modelEntity); - } protected Vector3d getRealPos(){ return new Vector3d( @@ -122,12 +118,12 @@ public class DrawCell { // // System.out.println("generate physics"); // } + /** + * Destroys a drawcell including its physics + */ public void destroy(){ - Realm realm = Globals.realmManager.getEntityRealm(modelEntity); - if(realm != null){ - CollisionEngine collisionEngine = Globals.realmManager.getEntityRealm(modelEntity).getCollisionEngine(); - collisionEngine.destroyEntityThatHasPhysics(modelEntity); - } + CollisionEngine collisionEngine = Globals.clientSceneWrapper.getCollisionEngine(); + collisionEngine.destroyEntityThatHasPhysics(modelEntity); EntityUtils.cleanUpEntity(modelEntity); } diff --git a/src/main/java/electrosphere/client/terrain/editing/TerrainEditing.java b/src/main/java/electrosphere/client/terrain/editing/TerrainEditing.java new file mode 100644 index 00000000..ccd375ef --- /dev/null +++ b/src/main/java/electrosphere/client/terrain/editing/TerrainEditing.java @@ -0,0 +1,71 @@ +package electrosphere.client.terrain.editing; + +import org.joml.Vector3d; +import org.joml.Vector3i; + +import electrosphere.client.terrain.cache.ChunkData; +import electrosphere.engine.Globals; +import electrosphere.net.parser.net.message.TerrainMessage; + +/** + * Utilities for editing terrain from client side of things + */ +public class TerrainEditing { + + /** + * Performs a terrain chunk edit. Basically has a sphere around the provided position that it attempts to add value to. + * @param position The position to perform the edit + * @param editMagnitude The magnitude of the edit to perform + * @param type The type of block to make all edited blocks + * @param weight The weight of the sphere to apply the edit to + */ + public static void editTerrain(Vector3d position, float editMagnitude, int type, float weight){ + if(position != null){ + Globals.clientConnection.queueOutgoingMessage(TerrainMessage.constructRequestUseTerrainPaletteMessage(position.x, position.y, position.z, editMagnitude, weight, type)); + //calculate kernel size + // int numPlacesToCheck = (int)((editMagnitude * 2 + 1) * (editMagnitude * 2 + 1) * (editMagnitude * 2 + 1)); + // //create and fill in kernel of positions to check + // int[] xOffsetSet = new int[numPlacesToCheck]; + // int[] yOffsetSet = new int[numPlacesToCheck]; + // int[] zOffsetSet = new int[numPlacesToCheck]; + // int i = 0; + // for(int x = -(int)editMagnitude; x <= (int)editMagnitude; x++){ + // for(int y = -(int)editMagnitude; y <= (int)editMagnitude; y++){ + // for(int z = -(int)editMagnitude; z <= (int)editMagnitude; z++){ + // xOffsetSet[i] = x; + // yOffsetSet[i] = y; + // zOffsetSet[i] = z; + // i++; + // } + // } + // } + // for(i = 0; i < numPlacesToCheck; i++){ + // //calculate position of edit + // Vector3d offsetPos = new Vector3d(position).add(xOffsetSet[i],yOffsetSet[i],zOffsetSet[i]); + // Vector3i chunkPos = Globals.clientWorldData.convertRealToChunkSpace(offsetPos); + // Vector3i voxelPos = Globals.clientWorldData.convertRealToVoxelSpace(offsetPos); + // //get distance from true center point of sphere to current voxel position in world space + // float distance = (float)new Vector3d(Math.floor(offsetPos.x),Math.floor(offsetPos.y),Math.floor(offsetPos.z)).distance(position); + // float currentPositionMagnitude = editMagnitude - distance; + // ChunkData data = Globals.clientTerrainManager.getChunkDataAtWorldPoint(chunkPos.x, chunkPos.y, chunkPos.z); + // if( + // voxelPos.x < ChunkData.CHUNK_SIZE && + // voxelPos.y < ChunkData.CHUNK_SIZE && + // voxelPos.z < ChunkData.CHUNK_SIZE && + // currentPositionMagnitude > 0 && + // data != null + // ){ + // float current = data.getVoxelWeight()[voxelPos.x][voxelPos.y][voxelPos.z]; + // //hard clamp so it doesn't go over 1 + // float finalValue = Math.max(Math.min(current + weight,1),-1); + // Globals.clientTerrainManager.updateChunk( + // chunkPos.x, chunkPos.y, chunkPos.z, + // voxelPos.x, voxelPos.y, voxelPos.z, + // finalValue, 1 + // ); + // } + // } + } + } + +} diff --git a/src/main/java/electrosphere/client/terrain/manager/ClientTerrainManager.java b/src/main/java/electrosphere/client/terrain/manager/ClientTerrainManager.java index 5420478a..a6694317 100644 --- a/src/main/java/electrosphere/client/terrain/manager/ClientTerrainManager.java +++ b/src/main/java/electrosphere/client/terrain/manager/ClientTerrainManager.java @@ -56,22 +56,22 @@ public class ClientTerrainManager { messageQueue.remove(message); switch(message.getMessageSubtype()){ case SENDCHUNKDATA: { - int[][][] values = new int[ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE]; - float[][][] weights = new float[ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE]; + int[][][] values = new int[ChunkData.CHUNK_DATA_GENERATOR_SIZE][ChunkData.CHUNK_DATA_GENERATOR_SIZE][ChunkData.CHUNK_DATA_GENERATOR_SIZE]; + float[][][] weights = new float[ChunkData.CHUNK_DATA_GENERATOR_SIZE][ChunkData.CHUNK_DATA_GENERATOR_SIZE][ChunkData.CHUNK_DATA_GENERATOR_SIZE]; ByteBuffer buffer = ByteBuffer.wrap(message.getchunkData()); FloatBuffer floatBuffer = buffer.asFloatBuffer(); - for(int x = 0; x < ChunkData.CHUNK_SIZE; x++){ - for(int y = 0; y < ChunkData.CHUNK_SIZE; y++){ - for(int z = 0; z < ChunkData.CHUNK_SIZE; z++){ + for(int x = 0; x < ChunkData.CHUNK_DATA_GENERATOR_SIZE; x++){ + for(int y = 0; y < ChunkData.CHUNK_DATA_GENERATOR_SIZE; y++){ + for(int z = 0; z < ChunkData.CHUNK_DATA_GENERATOR_SIZE; z++){ weights[x][y][z] = floatBuffer.get(); } } } IntBuffer intView = buffer.asIntBuffer(); intView.position(floatBuffer.position()); - for(int x = 0; x < ChunkData.CHUNK_SIZE; x++){ - for(int y = 0; y < ChunkData.CHUNK_SIZE; y++){ - for(int z = 0; z < ChunkData.CHUNK_SIZE; z++){ + for(int x = 0; x < ChunkData.CHUNK_DATA_GENERATOR_SIZE; x++){ + for(int y = 0; y < ChunkData.CHUNK_DATA_GENERATOR_SIZE; y++){ + for(int z = 0; z < ChunkData.CHUNK_DATA_GENERATOR_SIZE; z++){ values[x][y][z] = intView.get(); } } diff --git a/src/main/java/electrosphere/collision/CollisionEngine.java b/src/main/java/electrosphere/collision/CollisionEngine.java index 716b1cc1..3c37ea6d 100644 --- a/src/main/java/electrosphere/collision/CollisionEngine.java +++ b/src/main/java/electrosphere/collision/CollisionEngine.java @@ -10,6 +10,8 @@ import static org.ode4j.ode.internal.Common.dRecip; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.Semaphore; @@ -468,131 +470,7 @@ public class CollisionEngine { // double entityHeight = EntityUtils.getPosition(e).y; // return entityHeight > worldHeight + 0.1f; // } - - public float sweepTest(DBody body, Vector3f startPos, Vector3f endPos){ - // space.collide2(body.getFirstGeom(), endPos, nearCallback); -// SphereShape sphere = new SphereShape(0.1f); -// // CollisionObject collider = new CollisionObject(); -// // collider.setCollisionShape(sphere); -// ClosestConvexResultCallbackImpl callback = new ClosestConvexResultCallbackImpl(startPos,endPos,object,dispatcher,world.getPairCache()); -// callback.collisionFilterGroup = 1; -// callback.collisionFilterMask = 1; -// world.convexSweepTest(sphere, PhysicsUtils.jomlVecToTransform(startPos), PhysicsUtils.jomlVecToTransform(endPos), callback); -// // callback.hasHit() -// if(callback.hasHit()){ -// return callback.closestHitFraction; -// } else { -// return -1.0f; -// } - return -1.0f; - } - boolean RaycastQuery(DSpace space, DVector3 start, DVector3 end) { - - // Calculate direction - DVector3 direction = new DVector3(); - dSubtractVectors3(direction, end, start); - - // Get length - double length = dCalcVectorLengthSquare3(direction); - double inverseLength = dRecip(length); - - // Normalize - direction.scale(inverseLength); - - // Create ray - DRay ray = OdeHelper.createRay(space, length); - ray.set(start.get0(), start.get1(), start.get2(), direction.get0(), direction.get1(), direction.get2()); - - // Check collisions - DVector4 hitPosition = new DVector4(); - hitPosition.set3(dInfinity); - space.collide2(ray, null, nearCallback); - - // Cleanup - ray.destroy(); - - // Check for hit - if(hitPosition.get3() != dInfinity) { - end.set0(hitPosition.get0()); - end.set1(hitPosition.get1()); - end.set2(hitPosition.get2()); - return true; - } - return false; - } - - - - - // private static class ClosestConvexResultCallbackImpl extends ClosestConvexResultCallback { - - // CollisionObject me; - // private OverlappingPairCache pairCache; - // private Dispatcher dispatcher; - - // public ClosestConvexResultCallbackImpl(Vector3f startPos, Vector3f endPos, CollisionObject me, Dispatcher dispatcher, OverlappingPairCache pairCache){ - // super(PhysicsUtils.jomlToVecmathVector3f(startPos),PhysicsUtils.jomlToVecmathVector3f(endPos)); - // this.me = me; - // this.pairCache = pairCache; - // this.dispatcher = dispatcher; - // } - - // @Override - // public float addSingleResult(LocalConvexResult convexResult, boolean normalInWorldSpace) { - // if (convexResult.hitCollisionObject == me) { - // return 1f; - // } - - // Vector3f linVelA = new Vector3f(), linVelB = new Vector3f(); - // linVelA.sub(PhysicsUtils.vecmathToJomlVector3f(convexToWorld), PhysicsUtils.vecmathToJomlVector3f(convexFromWorld)); - // linVelB.set(0f, 0f, 0f);//toB.getOrigin()-fromB.getOrigin(); - - // Vector3f relativeVelocity = new Vector3f(); - // relativeVelocity.sub(linVelA, linVelB); - // // don't report time of impact for motion away from the contact normal (or causes minor penetration) - // if (convexResult.hitNormalLocal.dot(PhysicsUtils.jomlToVecmathVector3f(relativeVelocity)) >= -0f) { - // return 1f; - // } - - // return super.addSingleResult(convexResult, normalInWorldSpace); - // } - - // @Override - // public boolean needsCollision(BroadphaseProxy proxy0) { - // // don't collide with itself - // if (proxy0.clientObject == me) { - // return false; - // } - - // // don't do CCD when the collision filters are not matching - // if (!super.needsCollision(proxy0)) { - // return false; - // } - - // CollisionObject otherObj = (CollisionObject)proxy0.clientObject; - - // // call needsResponse, see http://code.google.com/p/bullet/issues/detail?id=179 - // if (dispatcher.needsResponse(me, otherObj)) { - // // don't do CCD when there are already contact points (touching contact/penetration) - // ObjectArrayList manifoldArray = new ObjectArrayList(); - // BroadphasePair collisionPair = pairCache.findPair(me.getBroadphaseHandle(), proxy0); - // if (collisionPair != null) { - // if (collisionPair.algorithm != null) { - // //manifoldArray.resize(0); - // collisionPair.algorithm.getAllContactManifolds(manifoldArray); - // for (int j=0; j 0) { - // return false; - // } - // } - // } - // } - // } - // return true; - // } - // } /** * Casts a ray into the scene and returns the first entity that the ray collides with. @@ -653,6 +531,29 @@ public class CollisionEngine { spaceLock.release(); return data.collisionPosition; } + + /** + * Ray casts into the scene and gets the position of the closest collision's position in world space. + * @param start The start position of the ray to cast + * @param direction The direction of the ray to cast + * @param length The length of the ray to cast + * @param typeMask The mask of types to collide the ray with + * @return The position, in world coordinates, of the closest collision of the way, or null if it did not collide with anything. + */ + public Vector3d rayCastPositionMasked(Vector3d start, Vector3d direction, double length, List typeMask){ + spaceLock.acquireUninterruptibly(); + //create the ray + DRay ray = OdeHelper.createRay(space, length); + ray.set(start.x, start.y, start.z, direction.x, direction.y, direction.z); + //collide + RayCastCallbackData data = new RayCastCallbackData(bodyPointerMap, typeMask); + rayCastCallback.setLength(length); + space.collide2(ray, data, rayCastCallback); + //destroy ray + ray.destroy(); + spaceLock.release(); + return data.collisionPosition; + } public void registerPhysicsObject(DBody body){ if(!bodies.contains(body)){ @@ -661,11 +562,23 @@ public class CollisionEngine { } } + /** + * Destroys a body and all geometry under the body + * @param body The DBody to destroy + */ public void deregisterPhysicsObject(DBody body){ + spaceLock.acquireUninterruptibly(); if(bodies.contains(body)){ bodies.remove(body); } + Iterator geomIterator = body.getGeomIterator(); + while(geomIterator.hasNext()){ + DGeom geom = geomIterator.next(); + space.remove(geom); + geom.destroy(); + } body.destroy(); + spaceLock.release(); } public void deregisterRigidBody(DBody body){ @@ -695,7 +608,7 @@ public class CollisionEngine { public void destroyEntityThatHasPhysics(Entity e){ //make uncollidable - if(e.containsKey(EntityDataStrings.PHYSICS_COLLISION_BODY) && e.containsKey(EntityDataStrings.PHYSICS_COLLIDABLE)){ + if(e.containsKey(EntityDataStrings.PHYSICS_COLLISION_BODY)){ DBody rigidBody = (DBody)e.getData(EntityDataStrings.PHYSICS_COLLISION_BODY); deregisterPhysicsObject(rigidBody); } diff --git a/src/main/java/electrosphere/collision/CollisionMasks.java b/src/main/java/electrosphere/collision/CollisionMasks.java new file mode 100644 index 00000000..6d83a494 --- /dev/null +++ b/src/main/java/electrosphere/collision/CollisionMasks.java @@ -0,0 +1,24 @@ +package electrosphere.collision; + +import java.util.LinkedList; + +import electrosphere.collision.collidable.Collidable; + +/** + * Contains masks for different collision engine functions + */ +public class CollisionMasks { + + //Only terrain + public static final LinkedList terrainMask = new LinkedList(); + + + /** + * Fills in all the collision engine masks + */ + public static void initMasks(){ + //terrain mask + terrainMask.add(Collidable.TYPE_TERRAIN); + } + +} diff --git a/src/main/java/electrosphere/controls/ControlHandler.java b/src/main/java/electrosphere/controls/ControlHandler.java index 32a65ed2..858074a7 100644 --- a/src/main/java/electrosphere/controls/ControlHandler.java +++ b/src/main/java/electrosphere/controls/ControlHandler.java @@ -69,12 +69,11 @@ import java.util.List; import org.joml.Vector2f; import org.joml.Vector3d; import org.joml.Vector3f; -import org.joml.Vector3i; import org.lwjgl.glfw.GLFW; import electrosphere.audio.AudioUtils; import electrosphere.client.targeting.crosshair.Crosshair; -import electrosphere.client.terrain.cache.ChunkData; +import electrosphere.client.terrain.editing.TerrainEditing; import electrosphere.collision.CollisionEngine; import electrosphere.controls.Control.ControlMethod; import electrosphere.controls.Control.ControlType; @@ -134,6 +133,7 @@ public class ControlHandler { public static final String INPUT_CODE_CHARACTER_OPEN = "characterOpen"; public static final String INPUT_CODE_IRON_SIGHT = "ironSight"; public static final String INPUT_CODE_PLACE_TERRAIN = "placeTerrain"; + public static final String INPUT_CODE_REMOVE_TERRAIN = "removeTerrain"; public static final String DATA_STRING_INPUT_CODE_MENU_NAVIGATE_FORWARD = "menuNavigateForward"; public static final String DATA_STRING_INPUT_CODE_MENU_NAVIGATE_BACKWARDS = "menuNavigateBackwards"; @@ -328,6 +328,7 @@ public class ControlHandler { Terrain controls */ handler.addControl(INPUT_CODE_PLACE_TERRAIN, new Control(ControlType.KEY,GLFW_KEY_T)); + handler.addControl(INPUT_CODE_REMOVE_TERRAIN, new Control(ControlType.KEY,GLFW_KEY_Y)); /* framestep controls @@ -942,50 +943,52 @@ public class ControlHandler { Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(camera)); Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(camera)); Vector3d cursorPos = collisionEngine.rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0); - int[] xOffsetSet = new int[]{ - 0,1,0,1,0,1,0,1, - }; - int[] yOffsetSet = new int[]{ - 0,0,0,0,1,1,1,1, - }; - int[] zOffsetSet = new int[]{ - 0,0,1,1,0,0,1,1, - }; - if(cursorPos != null){ - Vector3i chunkPos = Globals.clientWorldData.convertRealToChunkSpace(cursorPos); - Vector3i voxelPos = Globals.clientWorldData.convertRealToVoxelSpace(cursorPos); - for(int i = 0; i < 8; i++){ - Vector3i actualPos = new Vector3i( - voxelPos.x + xOffsetSet[i], - voxelPos.y + yOffsetSet[i], - voxelPos.z + zOffsetSet[i] - ); - if( - actualPos.x < ChunkData.CHUNK_SIZE && - actualPos.y < ChunkData.CHUNK_SIZE && - actualPos.z < ChunkData.CHUNK_SIZE - ){ - Globals.clientTerrainManager.updateChunk( - chunkPos.x, chunkPos.y, chunkPos.z, - actualPos.x, actualPos.y, actualPos.z, - 1.0f, 1 - ); - } - } - // Globals.clientTerrainManager.getChunkDataAtWorldPoint(chunkPos.x, chunkPos.y, chunkPos.z) - // .updatePosition(voxelPos.x, voxelPos.y, voxelPos.z, 1.0f, 1); - // Globals.clientTerrainManager.updateChunk( - // chunkPos.x, chunkPos.y, chunkPos.z, - // voxelPos.x, voxelPos.y, voxelPos.z, - // 1.0f, 1 - // ); - // System.out.println("Terrain"); - // System.out.println(Globals.clientWorldData.convertRealToChunkSpace(cursorPos)); - // System.out.println(Globals.clientWorldData.convertRealToVoxelSpace(cursorPos)); - } + TerrainEditing.editTerrain(cursorPos, 1.1f, 1, 0.01f); } }}); - controls.get(INPUT_CODE_PLACE_TERRAIN).setRepeatTimeout(0.5f * Main.targetFrameRate); + controls.get(INPUT_CODE_PLACE_TERRAIN).setOnRepeat(new ControlMethod(){public void execute(){ + CollisionEngine collisionEngine = Globals.clientSceneWrapper.getCollisionEngine(); + Entity camera = Globals.playerCamera; + if( + collisionEngine != null && + camera != null + ){ + Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(camera)); + Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(camera)); + Vector3d cursorPos = collisionEngine.rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0); + TerrainEditing.editTerrain(cursorPos, 1.1f, 1, 0.01f); + } + }}); + controls.get(INPUT_CODE_PLACE_TERRAIN).setRepeatTimeout(0.2f * Main.targetFrameRate); + + mainGameControlList.add(controls.get(INPUT_CODE_REMOVE_TERRAIN)); + controls.get(INPUT_CODE_REMOVE_TERRAIN).setOnPress(new ControlMethod(){public void execute(){ + CollisionEngine collisionEngine = Globals.clientSceneWrapper.getCollisionEngine(); + Entity camera = Globals.playerCamera; + if( + collisionEngine != null && + camera != null + ){ + Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(camera)); + Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(camera)); + Vector3d cursorPos = collisionEngine.rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0); + TerrainEditing.editTerrain(cursorPos, 1.1f, 1, -0.01f); + } + }}); + controls.get(INPUT_CODE_REMOVE_TERRAIN).setOnRepeat(new ControlMethod(){public void execute(){ + CollisionEngine collisionEngine = Globals.clientSceneWrapper.getCollisionEngine(); + Entity camera = Globals.playerCamera; + if( + collisionEngine != null && + camera != null + ){ + Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(camera)); + Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(camera)); + Vector3d cursorPos = collisionEngine.rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0); + TerrainEditing.editTerrain(cursorPos, 1.1f, 1, -0.01f); + } + }}); + controls.get(INPUT_CODE_REMOVE_TERRAIN).setRepeatTimeout(0.2f * Main.targetFrameRate); } diff --git a/src/main/java/electrosphere/engine/Globals.java b/src/main/java/electrosphere/engine/Globals.java index 8e8d4402..545ef92d 100644 --- a/src/main/java/electrosphere/engine/Globals.java +++ b/src/main/java/electrosphere/engine/Globals.java @@ -20,6 +20,7 @@ import electrosphere.client.sim.ClientSimulation; import electrosphere.client.terrain.cells.DrawCellManager; import electrosphere.client.terrain.manager.ClientTerrainManager; import electrosphere.collision.CollisionEngine; +import electrosphere.collision.CollisionMasks; import electrosphere.collision.CollisionWorldData; import electrosphere.controls.CameraHandler; import electrosphere.controls.ControlCallback; @@ -396,6 +397,8 @@ public class Globals { if(Globals.userSettings.getNetRunNetMonitor()){ netMonitor = new NetMonitor(); } + //init collision masks + CollisionMasks.initMasks(); } public static void initDefaultAudioResources(){ diff --git a/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java b/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java index f836952a..4c69959c 100644 --- a/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java +++ b/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java @@ -225,6 +225,8 @@ public class ClientLoading { Vector3d cursorPos = collisionEngine.rayCastPosition(centerPos, new Vector3d(eyePos).mul(-1.0), 5.0); if(cursorPos != null){ EntityUtils.getPosition(cursorTracker).set(cursorPos); + } else { + EntityUtils.getPosition(cursorTracker).set(new Vector3d(centerPos).add(new Vector3d(eyePos).normalize().mul(-5.0))); } } } diff --git a/src/main/java/electrosphere/engine/loadingthreads/DebugSPWorldLoading.java b/src/main/java/electrosphere/engine/loadingthreads/DebugSPWorldLoading.java index d587af19..33d165e2 100644 --- a/src/main/java/electrosphere/engine/loadingthreads/DebugSPWorldLoading.java +++ b/src/main/java/electrosphere/engine/loadingthreads/DebugSPWorldLoading.java @@ -13,6 +13,7 @@ import electrosphere.logger.LoggerInterface; import electrosphere.menu.MenuGenerators; import electrosphere.menu.WindowStrings; import electrosphere.menu.WindowUtils; +import electrosphere.net.parser.net.message.TerrainMessage; import electrosphere.renderer.ui.Window; import electrosphere.server.saves.SaveUtils; import electrosphere.server.terrain.manager.ServerTerrainManager; @@ -53,14 +54,20 @@ public class DebugSPWorldLoading { LoggerInterface.loggerEngine.INFO("run server: " + Globals.RUN_SERVER + " run client: " + Globals.RUN_CLIENT); - //init the data of the world - // LoadingUtils.initTerrainDataCellManager(); //init authentication LoadingUtils.initAuthenticationManager(); //initialize the local connection Globals.clientUsername = "testuser"; Globals.clientPassword = AuthenticationManager.getHashedString("testpass"); LoadingUtils.initLocalConnection(); + //wait for player object creation + while(Globals.playerManager.getPlayers().size() < 1){ + try { + TimeUnit.MILLISECONDS.sleep(10); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } //initialize the "real" objects simulation LoadingUtils.initMicroSimulation(); //init game specific stuff (ie different skybox colors) @@ -77,29 +84,14 @@ public class DebugSPWorldLoading { } catch (InterruptedException ex) {} } - + //spawn player character LoadingUtils.spawnLocalPlayerTestEntity(); - initWorldBaseGraphicalEntities(); + //request terrain data + Globals.clientConnection.queueOutgoingMessage(TerrainMessage.constructRequestMetadataMessage()); - // SeekTown.attachToCreature(Globals.playerEntity); - - //hide cursor - Globals.controlHandler.hideMouse(); - //make loading window disappear - loadingWindow.setVisible(false); - //recapture screen - Globals.controlHandler.setShouldRecapture(true); - //set rendering flags to main game mode - Globals.RENDER_FLAG_RENDER_SHADOW_MAP = true; - Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER_CONTENT = true; - Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER = true; - Globals.RENDER_FLAG_RENDER_UI = true; - Globals.RENDER_FLAG_RENDER_BLACK_BACKGROUND = false; - Globals.RENDER_FLAG_RENDER_WHITE_BACKGROUND = false; - LoggerInterface.loggerEngine.INFO("[Client]Finished loading main game"); - //set controls state - Globals.controlHandler.setHandlerState(ControlHandler.ControlsState.MAIN_GAME); + //Run client startup process + ClientLoading.loadClientWorld(); } diff --git a/src/main/java/electrosphere/engine/loadingthreads/LoadingUtils.java b/src/main/java/electrosphere/engine/loadingthreads/LoadingUtils.java index f5df7411..4a1ae1f0 100644 --- a/src/main/java/electrosphere/engine/loadingthreads/LoadingUtils.java +++ b/src/main/java/electrosphere/engine/loadingthreads/LoadingUtils.java @@ -239,6 +239,7 @@ public class LoadingUtils { } } Realm realm = Globals.realmManager.getRealms().iterator().next(); + //create player //spawn entity Entity newPlayerEntity = CreatureUtils.serverSpawnBasicCreature(realm,Globals.spawnPoint,template.getCreatureType(),template); Globals.playerEntity = newPlayerEntity; diff --git a/src/main/java/electrosphere/entity/state/collidable/ClientCollidableTree.java b/src/main/java/electrosphere/entity/state/collidable/ClientCollidableTree.java index fbb1971a..0c084ef3 100644 --- a/src/main/java/electrosphere/entity/state/collidable/ClientCollidableTree.java +++ b/src/main/java/electrosphere/entity/state/collidable/ClientCollidableTree.java @@ -142,32 +142,32 @@ public class ClientCollidableTree implements BehaviorTree { // System.out.println(cumulativeTorque); // } //friction - if(angularVelocity.lengthSquared() > 0.001){ - angularVelocity.slerp(new Quaterniond(0,0,0,1), 0.03); - // angularVelocity.scale((float)(Math.sqrt(angularVelocity.lengthSquared()) * 0.9)); - // System.out.println(angularVelocity); - } - // if(cumulativeTorque.w > 0.001){ - // Vector4f holder = inverseInertiaTensor.transform(new Vector4f((float)cumulativeTorque.x,(float)cumulativeTorque.y,(float)cumulativeTorque.z,(float)cumulativeTorque.w)); - // cumulativeTorque = new Vector4d(holder.x,holder.y,holder.z,holder.w); - // angularVelocity = angularVelocity.add(cumulativeTorque).normalize(); - // cumulativeTorque.set(0,0,0,0); - // // Vector3d normalizedTorqueDir = new Vector3d(cumulativeTorque.x,cumulativeTorque.y,cumulativeTorque.z).normalize(); - // // double newMag = cumulativeTorque.w * 0.9; - // // cumulativeTorque.set(normalizedTorqueDir.x,normalizedTorqueDir.y,normalizedTorqueDir.z,newMag); + // if(angularVelocity.lengthSquared() > 0.001){ + // angularVelocity.slerp(new Quaterniond(0,0,0,1), 0.03); + // // angularVelocity.scale((float)(Math.sqrt(angularVelocity.lengthSquared()) * 0.9)); + // // System.out.println(angularVelocity); + // } + // // if(cumulativeTorque.w > 0.001){ + // // Vector4f holder = inverseInertiaTensor.transform(new Vector4f((float)cumulativeTorque.x,(float)cumulativeTorque.y,(float)cumulativeTorque.z,(float)cumulativeTorque.w)); + // // cumulativeTorque = new Vector4d(holder.x,holder.y,holder.z,holder.w); + // // angularVelocity = angularVelocity.add(cumulativeTorque).normalize(); + // // cumulativeTorque.set(0,0,0,0); + // // // Vector3d normalizedTorqueDir = new Vector3d(cumulativeTorque.x,cumulativeTorque.y,cumulativeTorque.z).normalize(); + // // // double newMag = cumulativeTorque.w * 0.9; + // // // cumulativeTorque.set(normalizedTorqueDir.x,normalizedTorqueDir.y,normalizedTorqueDir.z,newMag); + // // } + // if(angularVelocity.lengthSquared() > 0.001){ + // // System.out.println("-" + rotation); + // Quaterniond newRotation = new Quaterniond(rotation).mul(angularVelocity).normalize(); + // // if(new Quaternionf(newRotation).add(new Quaternionf(rotation).conjugate()).lengthSquared() > 0.2){ + // // newRotation.w = Math.copySign(newRotation.w, rotation.w); + // // newRotation.x = Math.copySign(newRotation.x, rotation.x); + // // newRotation.y = Math.copySign(newRotation.y, rotation.y); + // // newRotation.z = Math.copySign(newRotation.z, rotation.z); + // // } + // rotation.set(newRotation); + // // System.out.println("=" + rotation); // } - if(angularVelocity.lengthSquared() > 0.001){ - // System.out.println("-" + rotation); - Quaterniond newRotation = new Quaterniond(rotation).mul(angularVelocity).normalize(); - // if(new Quaternionf(newRotation).add(new Quaternionf(rotation).conjugate()).lengthSquared() > 0.2){ - // newRotation.w = Math.copySign(newRotation.w, rotation.w); - // newRotation.x = Math.copySign(newRotation.x, rotation.x); - // newRotation.y = Math.copySign(newRotation.y, rotation.y); - // newRotation.z = Math.copySign(newRotation.z, rotation.z); - // } - rotation.set(newRotation); - // System.out.println("=" + rotation); - } // if(inverseInertiaTensor != null && angularVelocity.w > 0.01){ // // Vector4f angularMomentum = inverseInertiaTensor.transform(new Vector4f((float)cumulativeTorque.x,(float)cumulativeTorque.x,(float)cumulativeTorque.x,(float)cumulativeTorque.w)); // // Quaternionf nextRotation = new Quaternionf(rotation).mul(new Quaternionf(angularMomentum.x,angularMomentum.y,angularMomentum.z,angularMomentum.w).scale(0.001f)).normalize(); diff --git a/src/main/java/electrosphere/entity/state/gravity/ClientGravityTree.java b/src/main/java/electrosphere/entity/state/gravity/ClientGravityTree.java index 2b1d55d5..c19fc27c 100644 --- a/src/main/java/electrosphere/entity/state/gravity/ClientGravityTree.java +++ b/src/main/java/electrosphere/entity/state/gravity/ClientGravityTree.java @@ -1,5 +1,6 @@ package electrosphere.entity.state.gravity; +import java.util.LinkedList; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -9,6 +10,7 @@ import org.joml.Vector3d; import org.joml.Vector3f; import org.ode4j.ode.DBody; +import electrosphere.collision.CollisionMasks; import electrosphere.collision.collidable.Collidable; import electrosphere.engine.Globals; import electrosphere.entity.Entity; @@ -161,18 +163,24 @@ public class ClientGravityTree implements BehaviorTree { gravityVelocity = gravityConstant; } float gravityDif = gravityVelocity * (float)Math.pow(1.0f - linearDamping,deltaTime * 2); - Vector3d newGravityPos = new Vector3d(position.x,position.y - gravityDif,position.z); - float hitFraction = Globals.clientSceneWrapper.getCollisionEngine().sweepTest(body, new Vector3f((float)position.x,(float)position.y,(float)position.z), new Vector3f((float)newGravityPos.x,(float)newGravityPos.y,(float)newGravityPos.z)); + // Vector3d newGravityPos = new Vector3d(position.x,position.y - gravityDif,position.z); + // Entity terrainHit = Globals.clientSceneWrapper.getCollisionEngine().rayCast( + // position, + // new Vector3d(0,-1,0), + // gravityDif, + // CollisionMasks.terrainMask + // ); + // float hitFraction = Globals.clientSceneWrapper.getCollisionEngine().sweepTest(body, new Vector3f((float)position.x,(float)position.y,(float)position.z), new Vector3f((float)newGravityPos.x,(float)newGravityPos.y,(float)newGravityPos.z)); // if(hitFraction >= 0){ // collidable.addImpulse(new Impulse(new Vector3d(0,-1,0),gravityDif * hitFraction,"gravity")); // position.set(new Vector3d(position.x,position.y - gravityDif * hitFraction,position.z)); // } else { // position.set(new Vector3d(position.x,position.y - gravityDif,position.z)); // } - if(hitFraction < 0){ - hitFraction = 1; - } - collidable.addImpulse(new Impulse(new Vector3d(0,-1,0), new Vector3d(0,0,0), new Vector3d(position), gravityDif * hitFraction,"gravity")); + // if(hitFraction < 0){ + // hitFraction = 1; + // } + collidable.addImpulse(new Impulse(new Vector3d(0,-1,0), new Vector3d(0,0,0), new Vector3d(position), gravityDif,"gravity")); // System.out.println(hitFraction); // bodyTransformMatrix = new javax.vecmath.Matrix4f(PhysicsUtils.jomlToVecmathQuaternionf(rotation),PhysicsUtils.jomlToVecmathVector3f(new Vector3f((float)position.x,(float)position.y,(float)position.z)),1.0f); // body.setWorldTransform(new electrosphere.linearmath.Transform(bodyTransformMatrix)); diff --git a/src/main/java/electrosphere/entity/state/gravity/ServerGravityTree.java b/src/main/java/electrosphere/entity/state/gravity/ServerGravityTree.java index 1080a68c..541fe026 100644 --- a/src/main/java/electrosphere/entity/state/gravity/ServerGravityTree.java +++ b/src/main/java/electrosphere/entity/state/gravity/ServerGravityTree.java @@ -162,19 +162,19 @@ public class ServerGravityTree implements BehaviorTree { gravityVelocity = gravityConstant; } float gravityDif = gravityVelocity * (float)Math.pow(1.0f - linearDamping,deltaTime * 2); - Vector3d newGravityPos = new Vector3d(position.x,position.y - gravityDif,position.z); - Realm parentRealm = Globals.realmManager.getEntityRealm(parent); - float hitFraction = parentRealm.getCollisionEngine().sweepTest(body, new Vector3f((float)position.x,(float)position.y,(float)position.z), new Vector3f((float)newGravityPos.x,(float)newGravityPos.y,(float)newGravityPos.z)); + // Vector3d newGravityPos = new Vector3d(position.x,position.y - gravityDif,position.z); + // Realm parentRealm = Globals.realmManager.getEntityRealm(parent); + // float hitFraction = parentRealm.getCollisionEngine().sweepTest(body, new Vector3f((float)position.x,(float)position.y,(float)position.z), new Vector3f((float)newGravityPos.x,(float)newGravityPos.y,(float)newGravityPos.z)); // if(hitFraction >= 0){ // collidable.addImpulse(new Impulse(new Vector3d(0,-1,0),gravityDif * hitFraction,"gravity")); // position.set(new Vector3d(position.x,position.y - gravityDif * hitFraction,position.z)); // } else { // position.set(new Vector3d(position.x,position.y - gravityDif,position.z)); // } - if(hitFraction < 0){ - hitFraction = 1; - } - collidable.addImpulse(new Impulse(new Vector3d(0,-1,0), new Vector3d(0,0,0), new Vector3d(position), gravityDif * hitFraction,"gravity")); + // if(hitFraction < 0){ + // hitFraction = 1; + // } + collidable.addImpulse(new Impulse(new Vector3d(0,-1,0), new Vector3d(0,0,0), new Vector3d(position), gravityDif,"gravity")); // System.out.println(hitFraction); // bodyTransformMatrix = new javax.vecmath.Matrix4f(PhysicsUtils.jomlToVecmathQuaternionf(rotation),PhysicsUtils.jomlToVecmathVector3f(new Vector3f((float)position.x,(float)position.y,(float)position.z)),1.0f); // body.setWorldTransform(new electrosphere.linearmath.Transform(bodyTransformMatrix)); diff --git a/src/main/java/electrosphere/entity/types/terrain/TerrainChunk.java b/src/main/java/electrosphere/entity/types/terrain/TerrainChunk.java index b148210d..c0c58d35 100644 --- a/src/main/java/electrosphere/entity/types/terrain/TerrainChunk.java +++ b/src/main/java/electrosphere/entity/types/terrain/TerrainChunk.java @@ -21,16 +21,17 @@ public class TerrainChunk { * Creates a client terrain chunk based on weights and values provided * @param weights The terrain weights * @param values The values (block types) + * @param levelOfDetail Increasing value that increments level of detail. 0 would be full resolution, 1 would be half resolution and so on. Only generates physics if levelOfDetail is 0 * @return The terrain chunk entity */ - public static Entity clientCreateTerrainChunkEntity(float[][][] weights, int[][][] values){ + public static Entity clientCreateTerrainChunkEntity(float[][][] weights, int[][][] values, int levelOfDetail){ TerrainChunkData data = TerrainChunkModelGeneration.generateTerrainChunkData(weights, values); String modelPath = ClientTerrainManager.queueTerrainGridGeneration(data); Entity rVal = EntityCreationUtils.createClientSpatialEntity(); EntityCreationUtils.makeEntityDrawablePreexistingModel(rVal, modelPath); - if(data.vertices.size() > 0){ + if(data.vertices.size() > 0 && levelOfDetail < 1){ PhysicsUtils.clientAttachTerrainChunkRigidBody(rVal, data); } diff --git a/src/main/java/electrosphere/game/server/world/ServerWorldData.java b/src/main/java/electrosphere/game/server/world/ServerWorldData.java index b7e48885..67714a20 100644 --- a/src/main/java/electrosphere/game/server/world/ServerWorldData.java +++ b/src/main/java/electrosphere/game/server/world/ServerWorldData.java @@ -4,7 +4,10 @@ import electrosphere.server.datacell.ServerDataCell; import electrosphere.server.terrain.manager.ServerTerrainManager; import java.util.List; + +import org.joml.Vector3d; import org.joml.Vector3f; +import org.joml.Vector3i; /** * @@ -112,6 +115,30 @@ public class ServerWorldData { return isArena; } - + /** + * Converts a real coordinate to a world space coordinate + * @param position The real coordinate + * @return The world space coordinate + */ + public Vector3i convertRealToWorldSpace(Vector3d position){ + return new Vector3i( + convertRealToChunkSpace(position.x), + convertRealToChunkSpace(position.y), + convertRealToChunkSpace(position.z) + ); + } + + /** + * Converts a real coordinate to a voxel space coordinate, relative to the containing chunk of the real coordinate + * @param position The real coordinate + * @return The voxel space coordinate + */ + public Vector3i convertRealToVoxelSpace(Vector3d position){ + return new Vector3i( + (int)Math.floor(position.x - convertChunkToRealSpace(convertRealToChunkSpace(position.x))), + (int)Math.floor(position.y - convertChunkToRealSpace(convertRealToChunkSpace(position.y))), + (int)Math.floor(position.z - convertChunkToRealSpace(convertRealToChunkSpace(position.z))) + ); + } } diff --git a/src/main/java/electrosphere/net/client/protocol/TerrainProtocol.java b/src/main/java/electrosphere/net/client/protocol/TerrainProtocol.java index 453d0d69..8cfdaf78 100644 --- a/src/main/java/electrosphere/net/client/protocol/TerrainProtocol.java +++ b/src/main/java/electrosphere/net/client/protocol/TerrainProtocol.java @@ -34,6 +34,21 @@ public class TerrainProtocol { case SENDCHUNKDATA: Globals.clientTerrainManager.attachTerrainMessage(message); break; + case UPDATEVOXEL: { + if(Globals.clientTerrainManager.containsChunkDataAtWorldPoint(message.getworldX(), message.getworldY(), message.getworldZ())){ + ChunkData data = Globals.clientTerrainManager.getChunkDataAtWorldPoint(message.getworldX(), message.getworldY(), message.getworldZ()); + if(data != null){ + data.updatePosition( + message.getvoxelX(), + message.getvoxelY(), + message.getvoxelZ(), + message.getterrainWeight(), + message.getterrainValue() + ); + Globals.drawCellManager.markUpdateable(message.getworldX(), message.getworldY(), message.getworldZ()); + } + } + } break; default: LoggerInterface.loggerNetworking.WARNING("Client networking: Unhandled message of type: " + message.getMessageSubtype()); break; diff --git a/src/main/java/electrosphere/net/parser/net/message/NetworkMessage.java b/src/main/java/electrosphere/net/parser/net/message/NetworkMessage.java index 7eef63ee..7ca58411 100644 --- a/src/main/java/electrosphere/net/parser/net/message/NetworkMessage.java +++ b/src/main/java/electrosphere/net/parser/net/message/NetworkMessage.java @@ -200,9 +200,19 @@ INVENTORY_MESSAGE, rVal = TerrainMessage.parseRequestChunkMessage(byteBuffer); } break; - case TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATE: + case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTEDITVOXEL: if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){ - rVal = TerrainMessage.parseUpdateMessage(byteBuffer); + rVal = TerrainMessage.parseRequestEditVoxelMessage(byteBuffer); + } + break; + case TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATEVOXEL: + if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){ + rVal = TerrainMessage.parseUpdateVoxelMessage(byteBuffer); + } + break; + case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTUSETERRAINPALETTE: + if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){ + rVal = TerrainMessage.parseRequestUseTerrainPaletteMessage(byteBuffer); } break; case TypeBytes.TERRAIN_MESSAGE_TYPE_SPAWNPOSITION: diff --git a/src/main/java/electrosphere/net/parser/net/message/TerrainMessage.java b/src/main/java/electrosphere/net/parser/net/message/TerrainMessage.java index 2bf20e9c..854dffb9 100644 --- a/src/main/java/electrosphere/net/parser/net/message/TerrainMessage.java +++ b/src/main/java/electrosphere/net/parser/net/message/TerrainMessage.java @@ -11,7 +11,9 @@ public class TerrainMessage extends NetworkMessage { REQUESTMETADATA, RESPONSEMETADATA, REQUESTCHUNK, - UPDATE, + REQUESTEDITVOXEL, + UPDATEVOXEL, + REQUESTUSETERRAINPALETTE, SPAWNPOSITION, REQUESTCHUNKDATA, SENDCHUNKDATA, @@ -29,6 +31,9 @@ public class TerrainMessage extends NetworkMessage { int worldX; int worldY; int worldZ; + int voxelX; + int voxelY; + int voxelZ; double realLocationX; double realLocationY; double realLocationZ; @@ -133,6 +138,30 @@ public class TerrainMessage extends NetworkMessage { this.worldZ = worldZ; } + public int getvoxelX() { + return voxelX; + } + + public void setvoxelX(int voxelX) { + this.voxelX = voxelX; + } + + public int getvoxelY() { + return voxelY; + } + + public void setvoxelY(int voxelY) { + this.voxelY = voxelY; + } + + public int getvoxelZ() { + return voxelZ; + } + + public void setvoxelZ(int voxelZ) { + this.voxelZ = voxelZ; + } + public double getrealLocationX() { return realLocationX; } @@ -205,8 +234,20 @@ public class TerrainMessage extends NetworkMessage { } else { return false; } - case TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATE: - if(byteBuffer.getRemaining() >= TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATE_SIZE){ + case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTEDITVOXEL: + if(byteBuffer.getRemaining() >= TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTEDITVOXEL_SIZE){ + return true; + } else { + return false; + } + case TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATEVOXEL: + if(byteBuffer.getRemaining() >= TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATEVOXEL_SIZE){ + return true; + } else { + return false; + } + case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTUSETERRAINPALETTE: + if(byteBuffer.getRemaining() >= TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTUSETERRAINPALETTE_SIZE){ return true; } else { return false; @@ -283,20 +324,82 @@ public class TerrainMessage extends NetworkMessage { return rVal; } - public static TerrainMessage parseUpdateMessage(CircularByteBuffer byteBuffer){ - TerrainMessage rVal = new TerrainMessage(TerrainMessageType.UPDATE); + public static TerrainMessage parseRequestEditVoxelMessage(CircularByteBuffer byteBuffer){ + TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTEDITVOXEL); stripPacketHeader(byteBuffer); rVal.setworldX(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); rVal.setworldY(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); rVal.setworldZ(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); + rVal.setvoxelX(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); + rVal.setvoxelY(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); + rVal.setvoxelZ(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); + rVal.setterrainWeight(ByteStreamUtils.popFloatFromByteQueue(byteBuffer)); + rVal.setterrainValue(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); return rVal; } - public static TerrainMessage constructUpdateMessage(int worldX,int worldY,int worldZ){ - TerrainMessage rVal = new TerrainMessage(TerrainMessageType.UPDATE); + public static TerrainMessage constructRequestEditVoxelMessage(int worldX,int worldY,int worldZ,int voxelX,int voxelY,int voxelZ,float terrainWeight,int terrainValue){ + TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTEDITVOXEL); rVal.setworldX(worldX); rVal.setworldY(worldY); rVal.setworldZ(worldZ); + rVal.setvoxelX(voxelX); + rVal.setvoxelY(voxelY); + rVal.setvoxelZ(voxelZ); + rVal.setterrainWeight(terrainWeight); + rVal.setterrainValue(terrainValue); + rVal.serialize(); + return rVal; + } + + public static TerrainMessage parseUpdateVoxelMessage(CircularByteBuffer byteBuffer){ + TerrainMessage rVal = new TerrainMessage(TerrainMessageType.UPDATEVOXEL); + stripPacketHeader(byteBuffer); + rVal.setworldX(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); + rVal.setworldY(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); + rVal.setworldZ(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); + rVal.setvoxelX(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); + rVal.setvoxelY(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); + rVal.setvoxelZ(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); + rVal.setterrainWeight(ByteStreamUtils.popFloatFromByteQueue(byteBuffer)); + rVal.setterrainValue(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); + return rVal; + } + + public static TerrainMessage constructUpdateVoxelMessage(int worldX,int worldY,int worldZ,int voxelX,int voxelY,int voxelZ,float terrainWeight,int terrainValue){ + TerrainMessage rVal = new TerrainMessage(TerrainMessageType.UPDATEVOXEL); + rVal.setworldX(worldX); + rVal.setworldY(worldY); + rVal.setworldZ(worldZ); + rVal.setvoxelX(voxelX); + rVal.setvoxelY(voxelY); + rVal.setvoxelZ(voxelZ); + rVal.setterrainWeight(terrainWeight); + rVal.setterrainValue(terrainValue); + rVal.serialize(); + return rVal; + } + + public static TerrainMessage parseRequestUseTerrainPaletteMessage(CircularByteBuffer byteBuffer){ + TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTUSETERRAINPALETTE); + stripPacketHeader(byteBuffer); + rVal.setrealLocationX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer)); + rVal.setrealLocationY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer)); + rVal.setrealLocationZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer)); + rVal.setvalue(ByteStreamUtils.popFloatFromByteQueue(byteBuffer)); + rVal.setterrainWeight(ByteStreamUtils.popFloatFromByteQueue(byteBuffer)); + rVal.setterrainValue(ByteStreamUtils.popIntFromByteQueue(byteBuffer)); + return rVal; + } + + public static TerrainMessage constructRequestUseTerrainPaletteMessage(double realLocationX,double realLocationY,double realLocationZ,float value,float terrainWeight,int terrainValue){ + TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTUSETERRAINPALETTE); + rVal.setrealLocationX(realLocationX); + rVal.setrealLocationY(realLocationY); + rVal.setrealLocationZ(realLocationZ); + rVal.setvalue(value); + rVal.setterrainWeight(terrainWeight); + rVal.setterrainValue(terrainValue); rVal.serialize(); return rVal; } @@ -446,12 +549,12 @@ public class TerrainMessage extends NetworkMessage { rawBytes[6+i] = intValues[i]; } break; - case UPDATE: - rawBytes = new byte[2+4+4+4]; + case REQUESTEDITVOXEL: + rawBytes = new byte[2+4+4+4+4+4+4+4+4]; //message header rawBytes[0] = TypeBytes.MESSAGE_TYPE_TERRAIN; //entity messaage header - rawBytes[1] = TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATE; + rawBytes[1] = TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTEDITVOXEL; intValues = ByteStreamUtils.serializeIntToBytes(worldX); for(int i = 0; i < 4; i++){ rawBytes[2+i] = intValues[i]; @@ -464,6 +567,92 @@ public class TerrainMessage extends NetworkMessage { for(int i = 0; i < 4; i++){ rawBytes[10+i] = intValues[i]; } + intValues = ByteStreamUtils.serializeIntToBytes(voxelX); + for(int i = 0; i < 4; i++){ + rawBytes[14+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeIntToBytes(voxelY); + for(int i = 0; i < 4; i++){ + rawBytes[18+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeIntToBytes(voxelZ); + for(int i = 0; i < 4; i++){ + rawBytes[22+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeFloatToBytes(terrainWeight); + for(int i = 0; i < 4; i++){ + rawBytes[26+i] = intValues[i]; + } intValues = ByteStreamUtils.serializeIntToBytes(terrainValue); + for(int i = 0; i < 4; i++){ + rawBytes[30+i] = intValues[i]; + } + break; + case UPDATEVOXEL: + rawBytes = new byte[2+4+4+4+4+4+4+4+4]; + //message header + rawBytes[0] = TypeBytes.MESSAGE_TYPE_TERRAIN; + //entity messaage header + rawBytes[1] = TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATEVOXEL; + intValues = ByteStreamUtils.serializeIntToBytes(worldX); + for(int i = 0; i < 4; i++){ + rawBytes[2+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeIntToBytes(worldY); + for(int i = 0; i < 4; i++){ + rawBytes[6+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeIntToBytes(worldZ); + for(int i = 0; i < 4; i++){ + rawBytes[10+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeIntToBytes(voxelX); + for(int i = 0; i < 4; i++){ + rawBytes[14+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeIntToBytes(voxelY); + for(int i = 0; i < 4; i++){ + rawBytes[18+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeIntToBytes(voxelZ); + for(int i = 0; i < 4; i++){ + rawBytes[22+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeFloatToBytes(terrainWeight); + for(int i = 0; i < 4; i++){ + rawBytes[26+i] = intValues[i]; + } intValues = ByteStreamUtils.serializeIntToBytes(terrainValue); + for(int i = 0; i < 4; i++){ + rawBytes[30+i] = intValues[i]; + } + break; + case REQUESTUSETERRAINPALETTE: + rawBytes = new byte[2+8+8+8+4+4+4]; + //message header + rawBytes[0] = TypeBytes.MESSAGE_TYPE_TERRAIN; + //entity messaage header + rawBytes[1] = TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTUSETERRAINPALETTE; + intValues = ByteStreamUtils.serializeDoubleToBytes(realLocationX); + for(int i = 0; i < 8; i++){ + rawBytes[2+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeDoubleToBytes(realLocationY); + for(int i = 0; i < 8; i++){ + rawBytes[10+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeDoubleToBytes(realLocationZ); + for(int i = 0; i < 8; i++){ + rawBytes[18+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeFloatToBytes(value); + for(int i = 0; i < 4; i++){ + rawBytes[26+i] = intValues[i]; + } intValues = ByteStreamUtils.serializeFloatToBytes(terrainWeight); + for(int i = 0; i < 4; i++){ + rawBytes[30+i] = intValues[i]; + } intValues = ByteStreamUtils.serializeIntToBytes(terrainValue); + for(int i = 0; i < 4; i++){ + rawBytes[34+i] = intValues[i]; + } break; case SPAWNPOSITION: rawBytes = new byte[2+8+8+8]; diff --git a/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java b/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java index 2b7b5baa..5d9aed15 100644 --- a/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java +++ b/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java @@ -80,17 +80,21 @@ Message categories public static final byte TERRAIN_MESSAGE_TYPE_REQUESTMETADATA = 0; public static final byte TERRAIN_MESSAGE_TYPE_RESPONSEMETADATA = 1; public static final byte TERRAIN_MESSAGE_TYPE_REQUESTCHUNK = 2; - public static final byte TERRAIN_MESSAGE_TYPE_UPDATE = 3; - public static final byte TERRAIN_MESSAGE_TYPE_SPAWNPOSITION = 4; - public static final byte TERRAIN_MESSAGE_TYPE_REQUESTCHUNKDATA = 5; - public static final byte TERRAIN_MESSAGE_TYPE_SENDCHUNKDATA = 6; + public static final byte TERRAIN_MESSAGE_TYPE_REQUESTEDITVOXEL = 3; + public static final byte TERRAIN_MESSAGE_TYPE_UPDATEVOXEL = 4; + public static final byte TERRAIN_MESSAGE_TYPE_REQUESTUSETERRAINPALETTE = 5; + public static final byte TERRAIN_MESSAGE_TYPE_SPAWNPOSITION = 6; + public static final byte TERRAIN_MESSAGE_TYPE_REQUESTCHUNKDATA = 7; + public static final byte TERRAIN_MESSAGE_TYPE_SENDCHUNKDATA = 8; /* Terrain packet sizes */ public static final byte TERRAIN_MESSAGE_TYPE_REQUESTMETADATA_SIZE = 2; public static final byte TERRAIN_MESSAGE_TYPE_RESPONSEMETADATA_SIZE = 30; public static final byte TERRAIN_MESSAGE_TYPE_REQUESTCHUNK_SIZE = 10; - public static final byte TERRAIN_MESSAGE_TYPE_UPDATE_SIZE = 14; + public static final byte TERRAIN_MESSAGE_TYPE_REQUESTEDITVOXEL_SIZE = 34; + public static final byte TERRAIN_MESSAGE_TYPE_UPDATEVOXEL_SIZE = 34; + public static final byte TERRAIN_MESSAGE_TYPE_REQUESTUSETERRAINPALETTE_SIZE = 38; public static final byte TERRAIN_MESSAGE_TYPE_SPAWNPOSITION_SIZE = 26; public static final byte TERRAIN_MESSAGE_TYPE_REQUESTCHUNKDATA_SIZE = 14; /* diff --git a/src/main/java/electrosphere/net/server/protocol/TerrainProtocol.java b/src/main/java/electrosphere/net/server/protocol/TerrainProtocol.java index 448251d3..e0393c80 100644 --- a/src/main/java/electrosphere/net/server/protocol/TerrainProtocol.java +++ b/src/main/java/electrosphere/net/server/protocol/TerrainProtocol.java @@ -4,11 +4,16 @@ import java.nio.ByteBuffer; import java.nio.FloatBuffer; import java.nio.IntBuffer; +import org.joml.Vector3d; + import electrosphere.client.terrain.cache.ChunkData; import electrosphere.engine.Globals; import electrosphere.net.parser.net.message.TerrainMessage; import electrosphere.net.server.Server; import electrosphere.net.server.ServerConnectionHandler; +import electrosphere.net.server.player.Player; +import electrosphere.server.datacell.Realm; +import electrosphere.server.terrain.editing.TerrainEditing; import electrosphere.server.terrain.manager.ServerTerrainChunk; import electrosphere.server.terrain.models.TerrainModification; @@ -27,10 +32,16 @@ public class TerrainProtocol { message.getworldX(), message.getworldY(), message.getworldZ() ); break; + case REQUESTEDITVOXEL: { + attemptTerrainEdit(connectionHandler, message); + } break; + case REQUESTUSETERRAINPALETTE: { + attemptUseTerrainEditPalette(connectionHandler, message); + } break; //all ignored message types case RESPONSEMETADATA: case SPAWNPOSITION: - case UPDATE: + case UPDATEVOXEL: case SENDCHUNKDATA: //silently ignore break; @@ -69,12 +80,19 @@ public class TerrainProtocol { // long[][] randomizer = chunk.getRandomizer();//Globals.serverTerrainManager.getRandomizer(message.getworldX(), message.getworldY()); - ByteBuffer buffer = ByteBuffer.allocate(ServerTerrainChunk.CHUNK_DIMENSION*ServerTerrainChunk.CHUNK_DIMENSION*ServerTerrainChunk.CHUNK_DIMENSION*(4+4)); + //The length along each access of the chunk data. Typically, should be at least 17. + //Because CHUNK_SIZE is 16, 17 adds the necessary extra value. Each chunk needs the value of the immediately following position to generate + //chunk data that connects seamlessly to the next chunk. + int xWidth = chunk.getWeights().length; + int yWidth = chunk.getWeights()[0].length; + int zWidth = chunk.getWeights()[0][0].length; + + ByteBuffer buffer = ByteBuffer.allocate(xWidth*yWidth*zWidth*(4+4)); FloatBuffer floatView = buffer.asFloatBuffer(); - for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION; x++){ - for(int y = 0; y < ServerTerrainChunk.CHUNK_DIMENSION; y++){ - for(int z = 0; z < ServerTerrainChunk.CHUNK_DIMENSION; z++){ + for(int x = 0; x < xWidth; x++){ + for(int y = 0; y < yWidth; y++){ + for(int z = 0; z < zWidth; z++){ floatView.put(chunk.getWeights()[x][y][z]); } } @@ -83,9 +101,9 @@ public class TerrainProtocol { IntBuffer intView = buffer.asIntBuffer(); intView.position(floatView.position()); - for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION; x++){ - for(int y = 0; y < ServerTerrainChunk.CHUNK_DIMENSION; y++){ - for(int z = 0; z < ServerTerrainChunk.CHUNK_DIMENSION; z++){ + for(int x = 0; x < xWidth; x++){ + for(int y = 0; y < yWidth; y++){ + for(int z = 0; z < zWidth; z++){ intView.put(chunk.getValues()[x][y][z]); } } @@ -190,5 +208,25 @@ public class TerrainProtocol { ) ); } + + /** + * Attempts to perform an edit requested by a client + * @param message The message containing the edit request + */ + static void attemptTerrainEdit(ServerConnectionHandler connectionHandler, TerrainMessage message){ + Player player = Globals.playerManager.getPlayerFromId(connectionHandler.getPlayerId()); + } + + /** + * Attempts to use an edit palette on the terrain + * @param connectionHandler The connection handler + * @param message The message that contains the request to use an edit palette + */ + static void attemptUseTerrainEditPalette(ServerConnectionHandler connectionHandler, TerrainMessage message){ + Player player = Globals.playerManager.getPlayerFromId(connectionHandler.getPlayerId()); + Realm realm = Globals.realmManager.getPlayerRealm(player); + Vector3d location = new Vector3d(message.getrealLocationX(), message.getrealLocationY(), message.getrealLocationZ()); + TerrainEditing.editTerrain(realm, location, message.getvalue(), message.getterrainValue(), message.getterrainWeight()); + } } diff --git a/src/main/java/electrosphere/renderer/Mesh.java b/src/main/java/electrosphere/renderer/Mesh.java index 0b454e9d..59c02f23 100644 --- a/src/main/java/electrosphere/renderer/Mesh.java +++ b/src/main/java/electrosphere/renderer/Mesh.java @@ -582,35 +582,6 @@ public class Mesh { HomogenousInstancedArray buffer = uniformGlBufferMap.get(attribute); buffer.updateBuffer(buffers.get(attribute), 0); buffer.bind(renderPipelineState); - // switch(uniformTypeMap.get(uniformName)){ - // case VEC3F: { - // FloatBuffer buffer = (FloatBuffer)buffers.get(key); - // int bufferIndex = GL31.glGetUniformBlockIndex(shaderIndex, "Lights"); - // //bind that position to the slot '2' - // GL31.glUniformBlockBinding(shaderIndex, bufferIndex, BIND_POINT); - // //bind our buffer to slot '2' as well - // GL31.glBindBufferBase(GL_UNIFORM_BUFFER, BIND_POINT, uboIndex); - // //alternatively if want to use range, do glBindBufferRange(GL_UNIFORM_BUFFER, 2, uboExampleBlock, 0, 152); - // } break; - // case VEC3D: { - - // } break; - // case VEC4F: { - - // } break; - // case VEC4D: { - - // } break; - // case DOUBLE: { - - // } break; - // case FLOAT: { - - // } break; - // case INT: { - - // } break; - // } } } diff --git a/src/main/java/electrosphere/renderer/actor/instance/InstanceData.java b/src/main/java/electrosphere/renderer/actor/instance/InstanceData.java index a2bb736f..3ae8b454 100644 --- a/src/main/java/electrosphere/renderer/actor/instance/InstanceData.java +++ b/src/main/java/electrosphere/renderer/actor/instance/InstanceData.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Map; import java.util.PriorityQueue; +import org.joml.Matrix4d; import org.joml.Matrix4f; import org.joml.Vector3d; import org.joml.Vector3f; @@ -93,6 +94,9 @@ public class InstanceData { case MAT4F: { attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createFloatBuffer(capacity * 4 * 4)); } break; + case MAT4D: { + attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createFloatBuffer(capacity * 4 * 4)); + } break; } if(shaderAttribute.isSingleIndex()){ attributeGlBufferMap.put(shaderAttribute,HomogenousInstancedArray.createHomogenousInstancedArray(shaderAttribute.getIndex(), type, capacity)); @@ -156,6 +160,10 @@ public class InstanceData { buffer.limit(buffer.capacity()); // System.out.println(buffer.position() + " " + buffer.limit()); } break; + case MAT4D: { + FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute)); + buffer.limit(buffer.capacity()); + } break; case DOUBLE: { DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute)); buffer.limit(buffer.capacity()); @@ -227,27 +235,29 @@ public class InstanceData { buffer.put(mat.m31()); buffer.put(mat.m32()); buffer.put(mat.m33()); - /* - buffer.put(mat.m00()); - buffer.put(mat.m10()); - buffer.put(mat.m20()); - buffer.put(mat.m30()); + } break; + case MAT4D: { + FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute)); + Matrix4d mat = (Matrix4d)actor.getAttributeValue(attribute); + buffer.put((float)mat.m00()); + buffer.put((float)mat.m10()); + buffer.put((float)mat.m20()); + buffer.put((float)mat.m30()); - buffer.put(mat.m01()); - buffer.put(mat.m11()); - buffer.put(mat.m21()); - buffer.put(mat.m31()); + buffer.put((float)mat.m10()); + buffer.put((float)mat.m11()); + buffer.put((float)mat.m12()); + buffer.put((float)mat.m13()); + + buffer.put((float)mat.m20()); + buffer.put((float)mat.m21()); + buffer.put((float)mat.m22()); + buffer.put((float)mat.m23()); - buffer.put(mat.m02()); - buffer.put(mat.m12()); - buffer.put(mat.m22()); - buffer.put(mat.m32()); - - buffer.put(mat.m03()); - buffer.put(mat.m13()); - buffer.put(mat.m23()); - buffer.put(mat.m33()); - */ + buffer.put((float)mat.m30()); + buffer.put((float)mat.m31()); + buffer.put((float)mat.m32()); + buffer.put((float)mat.m33()); } break; case DOUBLE: { DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute)); @@ -293,6 +303,11 @@ public class InstanceData { buffer.flip(); // System.out.println(buffer.position() + " " + buffer.limit()); } break; + case MAT4D: { + FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute)); + buffer.flip(); + // System.out.println(buffer.position() + " " + buffer.limit()); + } break; case DOUBLE: { DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute)); buffer.flip(); @@ -333,6 +348,10 @@ public class InstanceData { FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute)); buffer.flip(); } break; + case MAT4D: { + FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute)); + buffer.flip(); + } break; case DOUBLE: { DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute)); buffer.flip(); diff --git a/src/main/java/electrosphere/renderer/actor/instance/InstancedActor.java b/src/main/java/electrosphere/renderer/actor/instance/InstancedActor.java index d6b74009..1a7d39e8 100644 --- a/src/main/java/electrosphere/renderer/actor/instance/InstancedActor.java +++ b/src/main/java/electrosphere/renderer/actor/instance/InstancedActor.java @@ -4,6 +4,7 @@ package electrosphere.renderer.actor.instance; import java.util.HashMap; import java.util.Map; +import org.joml.Matrix4d; import org.joml.Matrix4f; import electrosphere.engine.Globals; @@ -78,6 +79,13 @@ public class InstancedActor implements Comparable { attributes.put(attribute, new Matrix4f((Matrix4f)value)); } } + if(value instanceof Matrix4d){ + if(attributes.containsKey(attribute)){ + ((Matrix4d)attributes.get(attribute)).set((Matrix4d)value); + } else { + attributes.put(attribute, new Matrix4d((Matrix4d)value)); + } + } // attributes.put(attribute, value); } diff --git a/src/main/java/electrosphere/renderer/buffer/HomogenousInstancedArray.java b/src/main/java/electrosphere/renderer/buffer/HomogenousInstancedArray.java index dfadd6b9..88873bd3 100644 --- a/src/main/java/electrosphere/renderer/buffer/HomogenousInstancedArray.java +++ b/src/main/java/electrosphere/renderer/buffer/HomogenousInstancedArray.java @@ -119,6 +119,9 @@ public class HomogenousInstancedArray { case MAT4F: { return capacity * 4 * 4 * 4; } + case MAT4D: { + return capacity * 4 * 4 * 4; + } } return 0; } @@ -166,6 +169,29 @@ public class HomogenousInstancedArray { GL45.glVertexAttribDivisor(matrixAttributeIndices[1], 1); GL45.glVertexAttribDivisor(matrixAttributeIndices[2], 1); GL45.glVertexAttribDivisor(matrixAttributeIndices[3], 1); + } else if(type == HomogenousBufferTypes.MAT4D){ + //https://solhsa.com/instancing.html + //https://stackoverflow.com/questions/17355051/using-a-matrix-as-vertex-attribute-in-opengl3-core-profile + //"opengl matrix attribute" + //https://learnopengl.com/code_viewer_gh.php?code=src/4.advanced_opengl/10.3.asteroids_instanced/asteroids_instanced.cpp + GL45.glBindBuffer(GL45.GL_ARRAY_BUFFER, bufferPointer); + //enable attributes + GL45.glEnableVertexAttribArray(matrixAttributeIndices[0]); + GL45.glEnableVertexAttribArray(matrixAttributeIndices[1]); + GL45.glEnableVertexAttribArray(matrixAttributeIndices[2]); + GL45.glEnableVertexAttribArray(matrixAttributeIndices[3]); + //update attribute to point to buffer at correct offset + stride + GL45.glVertexAttribPointer(matrixAttributeIndices[0], 4, GL45.GL_FLOAT, false, 64, 0 * 4); + GL45.glVertexAttribPointer(matrixAttributeIndices[1], 4, GL45.GL_FLOAT, false, 64, 4 * 4); + GL45.glVertexAttribPointer(matrixAttributeIndices[2], 4, GL45.GL_FLOAT, false, 64, 4 * 8); + GL45.glVertexAttribPointer(matrixAttributeIndices[3], 4, GL45.GL_FLOAT, false, 64, 4 * 12); + //bind buffer + GL45.glBindBuffer(GL45.GL_ARRAY_BUFFER, bufferPointer); + //tell opengl to send a new value from buffer for each instance (instead of whole buffer for every instance) + GL45.glVertexAttribDivisor(matrixAttributeIndices[0], 1); + GL45.glVertexAttribDivisor(matrixAttributeIndices[1], 1); + GL45.glVertexAttribDivisor(matrixAttributeIndices[2], 1); + GL45.glVertexAttribDivisor(matrixAttributeIndices[3], 1); } else { LoggerInterface.loggerRenderer.ERROR("Unsupported operation", new Exception()); } @@ -211,7 +237,11 @@ public class HomogenousInstancedArray { } break; case MAT4F: { FloatBuffer buffer = (FloatBuffer)object; - // GL45.glNamedBufferSubData(bufferPointer, startIndex, buffer); + GL45.glNamedBufferSubData(bufferPointer, startIndex, buffer); + } break; + case MAT4D: { + FloatBuffer buffer = (FloatBuffer)object; + GL45.glNamedBufferSubData(bufferPointer, startIndex, buffer); } break; } //unbind the buffer diff --git a/src/main/java/electrosphere/renderer/buffer/HomogenousUniformBuffer.java b/src/main/java/electrosphere/renderer/buffer/HomogenousUniformBuffer.java index 68e50fbd..6ea26bcd 100644 --- a/src/main/java/electrosphere/renderer/buffer/HomogenousUniformBuffer.java +++ b/src/main/java/electrosphere/renderer/buffer/HomogenousUniformBuffer.java @@ -27,6 +27,7 @@ public class HomogenousUniformBuffer { VEC4F, VEC4D, MAT4F, + MAT4D, INT, FLOAT, DOUBLE, @@ -111,6 +112,9 @@ public class HomogenousUniformBuffer { case MAT4F: { return capacity * 4 * 4 * 4; } + case MAT4D: { + return capacity * 4 * 4 * 4; + } } return 0; } @@ -177,6 +181,10 @@ public class HomogenousUniformBuffer { FloatBuffer buffer = (FloatBuffer)object; GL45.glNamedBufferSubData(bufferPointer, startIndex, buffer); } break; + case MAT4D: { + FloatBuffer buffer = (FloatBuffer)object; + GL45.glNamedBufferSubData(bufferPointer, startIndex, buffer); + } break; } //unbind the buffer // GL45.glBindBuffer(GL45.GL_UNIFORM_BUFFER, 0); diff --git a/src/main/java/electrosphere/renderer/meshgen/TerrainChunkModelGeneration.java b/src/main/java/electrosphere/renderer/meshgen/TerrainChunkModelGeneration.java index 9a93ba4c..037dfd33 100644 --- a/src/main/java/electrosphere/renderer/meshgen/TerrainChunkModelGeneration.java +++ b/src/main/java/electrosphere/renderer/meshgen/TerrainChunkModelGeneration.java @@ -675,7 +675,11 @@ public class TerrainChunkModelGeneration { return rVal; } - + /** + * Generates a mesh based on a terrainchunkdata object + * @param data The terrain chunk data object + * @return The mesh + */ protected static Mesh generateTerrainMesh(TerrainChunkData data){ Mesh mesh = new Mesh(); @@ -780,7 +784,11 @@ public class TerrainChunkModelGeneration { } - + /** + * Generates a model based on a terrainchunkdata object + * @param data The terrain chunk data object + * @return The model + */ public static Model generateTerrainModel(TerrainChunkData data){ Model rVal = new Model(); rVal.meshes = new ArrayList(); diff --git a/src/main/java/electrosphere/renderer/meshgen/TransvoxelLookupTables.java b/src/main/java/electrosphere/renderer/meshgen/TransvoxelLookupTables.java new file mode 100644 index 00000000..18a4bd59 --- /dev/null +++ b/src/main/java/electrosphere/renderer/meshgen/TransvoxelLookupTables.java @@ -0,0 +1,1035 @@ +package electrosphere.renderer.meshgen; + + +//================================================================================ +// +// The Transvoxel Algorithm look-up tables +// +// Copyright 2009 by Eric Lengyel +// +// The following data originates from Eric Lengyel's Transvoxel Algorithm. +// http://transvoxel.org/ +// +// The data in this file may be freely used in implementations of the Transvoxel +// Algorithm. If you do use this data, or any transformation of it, in your own +// projects, commercial or otherwise, please give credit by indicating in your +// source code that the data is part of the author's implementation of the +// Transvoxel Algorithm and that it came from the web address given above. +// (Simply copying and pasting the two lines of the previous paragraph would be +// perfect.) If you distribute a commercial product with source code included, +// then the credit in the source code is required. +// +// If you distribute any kind of product that uses this data, a credit visible to +// the end-user would be appreciated, but it is not required. However, you may +// not claim that the entire implementation of the Transvoxel Algorithm is your +// own if you use the data in this file or any transformation of it. +// +// The format of the data in this file is described in the dissertation "Voxel- +// Based Terrain for Real-Time Virtual Simulations", available at the web page +// given above. References to sections and figures below pertain to that paper. +// +// The contents of this file are protected by copyright and may not be publicly +// reproduced without permission. +// +//================================================================================ + + +/** + * Lookup tables and data for performing the transvoxel algorithm + */ +public class TransvoxelLookupTables { + + + + + // The regularCellClass table maps an 8-bit regular Marching Cubes case index to + // an equivalence class index. Even though there are 18 equivalence classes in our + // modified Marching Cubes algorithm, a couple of them use the same exact triangulations, + // just with different vertex locations. We combined those classes for this table so + // that the class index ranges from 0 to 15. + public static final byte[] regularCellClass = + { + 0x00, 0x01, 0x01, 0x03, 0x01, 0x03, 0x02, 0x04, 0x01, 0x02, 0x03, 0x04, 0x03, 0x04, 0x04, 0x03, + 0x01, 0x03, 0x02, 0x04, 0x02, 0x04, 0x06, 0x0C, 0x02, 0x05, 0x05, 0x0B, 0x05, 0x0A, 0x07, 0x04, + 0x01, 0x02, 0x03, 0x04, 0x02, 0x05, 0x05, 0x0A, 0x02, 0x06, 0x04, 0x0C, 0x05, 0x07, 0x0B, 0x04, + 0x03, 0x04, 0x04, 0x03, 0x05, 0x0B, 0x07, 0x04, 0x05, 0x07, 0x0A, 0x04, 0x08, 0x0E, 0x0E, 0x03, + 0x01, 0x02, 0x02, 0x05, 0x03, 0x04, 0x05, 0x0B, 0x02, 0x06, 0x05, 0x07, 0x04, 0x0C, 0x0A, 0x04, + 0x03, 0x04, 0x05, 0x0A, 0x04, 0x03, 0x07, 0x04, 0x05, 0x07, 0x08, 0x0E, 0x0B, 0x04, 0x0E, 0x03, + 0x02, 0x06, 0x05, 0x07, 0x05, 0x07, 0x08, 0x0E, 0x06, 0x09, 0x07, 0x0F, 0x07, 0x0F, 0x0E, 0x0D, + 0x04, 0x0C, 0x0B, 0x04, 0x0A, 0x04, 0x0E, 0x03, 0x07, 0x0F, 0x0E, 0x0D, 0x0E, 0x0D, 0x02, 0x01, + 0x01, 0x02, 0x02, 0x05, 0x02, 0x05, 0x06, 0x07, 0x03, 0x05, 0x04, 0x0A, 0x04, 0x0B, 0x0C, 0x04, + 0x02, 0x05, 0x06, 0x07, 0x06, 0x07, 0x09, 0x0F, 0x05, 0x08, 0x07, 0x0E, 0x07, 0x0E, 0x0F, 0x0D, + 0x03, 0x05, 0x04, 0x0B, 0x05, 0x08, 0x07, 0x0E, 0x04, 0x07, 0x03, 0x04, 0x0A, 0x0E, 0x04, 0x03, + 0x04, 0x0A, 0x0C, 0x04, 0x07, 0x0E, 0x0F, 0x0D, 0x0B, 0x0E, 0x04, 0x03, 0x0E, 0x02, 0x0D, 0x01, + 0x03, 0x05, 0x05, 0x08, 0x04, 0x0A, 0x07, 0x0E, 0x04, 0x07, 0x0B, 0x0E, 0x03, 0x04, 0x04, 0x03, + 0x04, 0x0B, 0x07, 0x0E, 0x0C, 0x04, 0x0F, 0x0D, 0x0A, 0x0E, 0x0E, 0x02, 0x04, 0x03, 0x0D, 0x01, + 0x04, 0x07, 0x0A, 0x0E, 0x0B, 0x0E, 0x0E, 0x02, 0x0C, 0x0F, 0x04, 0x0D, 0x04, 0x0D, 0x03, 0x01, + 0x03, 0x04, 0x04, 0x03, 0x04, 0x03, 0x0D, 0x01, 0x04, 0x0D, 0x03, 0x01, 0x03, 0x01, 0x01, 0x00 + }; + + // The regularCellData table holds the triangulation data for all 16 distinct classes to + // which a case can be mapped by the regularCellClass table. + static RegularCellData[] regularCellData = new RegularCellData[16]; + static { + regularCellData[0] = new RegularCellData((byte)0x00, new byte[36]); + regularCellData[1] = new RegularCellData((byte)0x31, new byte[]{0, 1, 2}); + regularCellData[2] = new RegularCellData((byte)0x62, new byte[]{0, 1, 2, 3, 4, 5}); + regularCellData[3] = new RegularCellData((byte)0x42, new byte[]{0, 1, 2, 0, 2, 3}); + regularCellData[4] = new RegularCellData((byte)0x53, new byte[]{0, 1, 4, 1, 3, 4, 1, 2, 3}); + regularCellData[5] = new RegularCellData((byte)0x73, new byte[]{0, 1, 2, 0, 2, 3, 4, 5, 6}); + regularCellData[6] = new RegularCellData((byte)0x93, new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8}); + regularCellData[7] = new RegularCellData((byte)0x84, new byte[]{0, 1, 4, 1, 3, 4, 1, 2, 3, 5, 6, 7}); + regularCellData[8] = new RegularCellData((byte)0x84, new byte[]{0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7}); + regularCellData[9] = new RegularCellData((byte)0xC4, new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}); + regularCellData[10] = new RegularCellData((byte)0x64, new byte[]{0, 4, 5, 0, 1, 4, 1, 3, 4, 1, 2, 3}); + regularCellData[11] = new RegularCellData((byte)0x64, new byte[]{0, 5, 4, 0, 4, 1, 1, 4, 3, 1, 3, 2}); + regularCellData[12] = new RegularCellData((byte)0x64, new byte[]{0, 4, 5, 0, 3, 4, 0, 1, 3, 1, 2, 3}); + regularCellData[13] = new RegularCellData((byte)0x64, new byte[]{0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5}); + regularCellData[14] = new RegularCellData((byte)0x75, new byte[]{0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 6}); + regularCellData[15] = new RegularCellData((byte)0x95, new byte[]{0, 4, 5, 0, 3, 4, 0, 1, 3, 1, 2, 3, 6, 7, 8}); + }; + + // The regularVertexData table gives the vertex locations for every one of the 256 possible + // cases in the modified Marching Cubes algorithm. Each 16-bit value also provides information + // about whether a vertex can be reused from a neighboring cell. See Section 3.3 for details. + // The low byte contains the indexes for the two endpoints of the edge on which the vertex lies, + // as numbered in Figure 3.7. The high byte contains the vertex reuse data shown in Figure 3.8. + + public static int[][] regularVertexData = new int[][] { + {}, + {0x6201, 0x5102, 0x3304}, + {0x6201, 0x2315, 0x4113}, + {0x5102, 0x3304, 0x2315, 0x4113}, + {0x5102, 0x4223, 0x1326}, + {0x3304, 0x6201, 0x4223, 0x1326}, + {0x6201, 0x2315, 0x4113, 0x5102, 0x4223, 0x1326}, + {0x4223, 0x1326, 0x3304, 0x2315, 0x4113}, + {0x4113, 0x8337, 0x4223}, + {0x6201, 0x5102, 0x3304, 0x4223, 0x4113, 0x8337}, + {0x6201, 0x2315, 0x8337, 0x4223}, + {0x5102, 0x3304, 0x2315, 0x8337, 0x4223}, + {0x5102, 0x4113, 0x8337, 0x1326}, + {0x4113, 0x8337, 0x1326, 0x3304, 0x6201}, + {0x6201, 0x2315, 0x8337, 0x1326, 0x5102}, + {0x3304, 0x2315, 0x8337, 0x1326}, + {0x3304, 0x1146, 0x2245}, + {0x6201, 0x5102, 0x1146, 0x2245}, + {0x6201, 0x2315, 0x4113, 0x3304, 0x1146, 0x2245}, + {0x2315, 0x4113, 0x5102, 0x1146, 0x2245}, + {0x5102, 0x4223, 0x1326, 0x3304, 0x1146, 0x2245}, + {0x1146, 0x2245, 0x6201, 0x4223, 0x1326}, + {0x3304, 0x1146, 0x2245, 0x6201, 0x2315, 0x4113, 0x5102, 0x4223, 0x1326}, + {0x4223, 0x1326, 0x1146, 0x2245, 0x2315, 0x4113}, + {0x4223, 0x4113, 0x8337, 0x3304, 0x1146, 0x2245}, + {0x6201, 0x5102, 0x1146, 0x2245, 0x4223, 0x4113, 0x8337}, + {0x4223, 0x6201, 0x2315, 0x8337, 0x3304, 0x1146, 0x2245}, + {0x4223, 0x8337, 0x2315, 0x2245, 0x1146, 0x5102}, + {0x5102, 0x4113, 0x8337, 0x1326, 0x3304, 0x1146, 0x2245}, + {0x4113, 0x8337, 0x1326, 0x1146, 0x2245, 0x6201}, + {0x6201, 0x2315, 0x8337, 0x1326, 0x5102, 0x3304, 0x1146, 0x2245}, + {0x2245, 0x2315, 0x8337, 0x1326, 0x1146}, + {0x2315, 0x2245, 0x8157}, + {0x6201, 0x5102, 0x3304, 0x2315, 0x2245, 0x8157}, + {0x4113, 0x6201, 0x2245, 0x8157}, + {0x2245, 0x8157, 0x4113, 0x5102, 0x3304}, + {0x5102, 0x4223, 0x1326, 0x2315, 0x2245, 0x8157}, + {0x6201, 0x4223, 0x1326, 0x3304, 0x2315, 0x2245, 0x8157}, + {0x6201, 0x2245, 0x8157, 0x4113, 0x5102, 0x4223, 0x1326}, + {0x4223, 0x1326, 0x3304, 0x2245, 0x8157, 0x4113}, + {0x4223, 0x4113, 0x8337, 0x2315, 0x2245, 0x8157}, + {0x6201, 0x5102, 0x3304, 0x4223, 0x4113, 0x8337, 0x2315, 0x2245, 0x8157}, + {0x8337, 0x4223, 0x6201, 0x2245, 0x8157}, + {0x5102, 0x3304, 0x2245, 0x8157, 0x8337, 0x4223}, + {0x5102, 0x4113, 0x8337, 0x1326, 0x2315, 0x2245, 0x8157}, + {0x4113, 0x8337, 0x1326, 0x3304, 0x6201, 0x2315, 0x2245, 0x8157}, + {0x5102, 0x1326, 0x8337, 0x8157, 0x2245, 0x6201}, + {0x8157, 0x8337, 0x1326, 0x3304, 0x2245}, + {0x2315, 0x3304, 0x1146, 0x8157}, + {0x6201, 0x5102, 0x1146, 0x8157, 0x2315}, + {0x3304, 0x1146, 0x8157, 0x4113, 0x6201}, + {0x4113, 0x5102, 0x1146, 0x8157}, + {0x2315, 0x3304, 0x1146, 0x8157, 0x5102, 0x4223, 0x1326}, + {0x1326, 0x4223, 0x6201, 0x2315, 0x8157, 0x1146}, + {0x3304, 0x1146, 0x8157, 0x4113, 0x6201, 0x5102, 0x4223, 0x1326}, + {0x1326, 0x1146, 0x8157, 0x4113, 0x4223}, + {0x2315, 0x3304, 0x1146, 0x8157, 0x4223, 0x4113, 0x8337}, + {0x6201, 0x5102, 0x1146, 0x8157, 0x2315, 0x4223, 0x4113, 0x8337}, + {0x3304, 0x1146, 0x8157, 0x8337, 0x4223, 0x6201}, + {0x4223, 0x5102, 0x1146, 0x8157, 0x8337}, + {0x2315, 0x3304, 0x1146, 0x8157, 0x5102, 0x4113, 0x8337, 0x1326}, + {0x6201, 0x4113, 0x8337, 0x1326, 0x1146, 0x8157, 0x2315}, + {0x6201, 0x3304, 0x1146, 0x8157, 0x8337, 0x1326, 0x5102}, + {0x1326, 0x1146, 0x8157, 0x8337}, + {0x1326, 0x8267, 0x1146}, + {0x6201, 0x5102, 0x3304, 0x1326, 0x8267, 0x1146}, + {0x6201, 0x2315, 0x4113, 0x1326, 0x8267, 0x1146}, + {0x5102, 0x3304, 0x2315, 0x4113, 0x1326, 0x8267, 0x1146}, + {0x5102, 0x4223, 0x8267, 0x1146}, + {0x3304, 0x6201, 0x4223, 0x8267, 0x1146}, + {0x5102, 0x4223, 0x8267, 0x1146, 0x6201, 0x2315, 0x4113}, + {0x1146, 0x8267, 0x4223, 0x4113, 0x2315, 0x3304}, + {0x4113, 0x8337, 0x4223, 0x1326, 0x8267, 0x1146}, + {0x6201, 0x5102, 0x3304, 0x4223, 0x4113, 0x8337, 0x1326, 0x8267, 0x1146}, + {0x6201, 0x2315, 0x8337, 0x4223, 0x1326, 0x8267, 0x1146}, + {0x5102, 0x3304, 0x2315, 0x8337, 0x4223, 0x1326, 0x8267, 0x1146}, + {0x8267, 0x1146, 0x5102, 0x4113, 0x8337}, + {0x6201, 0x4113, 0x8337, 0x8267, 0x1146, 0x3304}, + {0x6201, 0x2315, 0x8337, 0x8267, 0x1146, 0x5102}, + {0x1146, 0x3304, 0x2315, 0x8337, 0x8267}, + {0x3304, 0x1326, 0x8267, 0x2245}, + {0x1326, 0x8267, 0x2245, 0x6201, 0x5102}, + {0x3304, 0x1326, 0x8267, 0x2245, 0x6201, 0x2315, 0x4113}, + {0x1326, 0x8267, 0x2245, 0x2315, 0x4113, 0x5102}, + {0x5102, 0x4223, 0x8267, 0x2245, 0x3304}, + {0x6201, 0x4223, 0x8267, 0x2245}, + {0x5102, 0x4223, 0x8267, 0x2245, 0x3304, 0x6201, 0x2315, 0x4113}, + {0x4113, 0x4223, 0x8267, 0x2245, 0x2315}, + {0x3304, 0x1326, 0x8267, 0x2245, 0x4223, 0x4113, 0x8337}, + {0x1326, 0x8267, 0x2245, 0x6201, 0x5102, 0x4223, 0x4113, 0x8337}, + {0x3304, 0x1326, 0x8267, 0x2245, 0x4223, 0x6201, 0x2315, 0x8337}, + {0x5102, 0x1326, 0x8267, 0x2245, 0x2315, 0x8337, 0x4223}, + {0x3304, 0x2245, 0x8267, 0x8337, 0x4113, 0x5102}, + {0x8337, 0x8267, 0x2245, 0x6201, 0x4113}, + {0x5102, 0x6201, 0x2315, 0x8337, 0x8267, 0x2245, 0x3304}, + {0x2315, 0x8337, 0x8267, 0x2245}, + {0x2315, 0x2245, 0x8157, 0x1326, 0x8267, 0x1146}, + {0x6201, 0x5102, 0x3304, 0x2315, 0x2245, 0x8157, 0x1326, 0x8267, 0x1146}, + {0x6201, 0x2245, 0x8157, 0x4113, 0x1326, 0x8267, 0x1146}, + {0x2245, 0x8157, 0x4113, 0x5102, 0x3304, 0x1326, 0x8267, 0x1146}, + {0x4223, 0x8267, 0x1146, 0x5102, 0x2315, 0x2245, 0x8157}, + {0x3304, 0x6201, 0x4223, 0x8267, 0x1146, 0x2315, 0x2245, 0x8157}, + {0x4223, 0x8267, 0x1146, 0x5102, 0x6201, 0x2245, 0x8157, 0x4113}, + {0x3304, 0x2245, 0x8157, 0x4113, 0x4223, 0x8267, 0x1146}, + {0x4223, 0x4113, 0x8337, 0x2315, 0x2245, 0x8157, 0x1326, 0x8267, 0x1146}, + {0x6201, 0x5102, 0x3304, 0x4223, 0x4113, 0x8337, 0x2315, 0x2245, 0x8157, 0x1326, 0x8267, 0x1146}, + {0x8337, 0x4223, 0x6201, 0x2245, 0x8157, 0x1326, 0x8267, 0x1146}, + {0x4223, 0x5102, 0x3304, 0x2245, 0x8157, 0x8337, 0x1326, 0x8267, 0x1146}, + {0x8267, 0x1146, 0x5102, 0x4113, 0x8337, 0x2315, 0x2245, 0x8157}, + {0x6201, 0x4113, 0x8337, 0x8267, 0x1146, 0x3304, 0x2315, 0x2245, 0x8157}, + {0x8337, 0x8267, 0x1146, 0x5102, 0x6201, 0x2245, 0x8157}, + {0x3304, 0x2245, 0x8157, 0x8337, 0x8267, 0x1146}, + {0x8157, 0x2315, 0x3304, 0x1326, 0x8267}, + {0x8267, 0x8157, 0x2315, 0x6201, 0x5102, 0x1326}, + {0x8267, 0x1326, 0x3304, 0x6201, 0x4113, 0x8157}, + {0x8267, 0x8157, 0x4113, 0x5102, 0x1326}, + {0x5102, 0x4223, 0x8267, 0x8157, 0x2315, 0x3304}, + {0x2315, 0x6201, 0x4223, 0x8267, 0x8157}, + {0x3304, 0x5102, 0x4223, 0x8267, 0x8157, 0x4113, 0x6201}, + {0x4113, 0x4223, 0x8267, 0x8157}, + {0x8157, 0x2315, 0x3304, 0x1326, 0x8267, 0x4223, 0x4113, 0x8337}, + {0x8157, 0x2315, 0x6201, 0x5102, 0x1326, 0x8267, 0x4223, 0x4113, 0x8337}, + {0x8157, 0x8337, 0x4223, 0x6201, 0x3304, 0x1326, 0x8267}, + {0x5102, 0x1326, 0x8267, 0x8157, 0x8337, 0x4223}, + {0x8267, 0x8157, 0x2315, 0x3304, 0x5102, 0x4113, 0x8337}, + {0x6201, 0x4113, 0x8337, 0x8267, 0x8157, 0x2315}, + {0x6201, 0x3304, 0x5102, 0x8337, 0x8267, 0x8157}, + {0x8337, 0x8267, 0x8157}, + {0x8337, 0x8157, 0x8267}, + {0x6201, 0x5102, 0x3304, 0x8337, 0x8157, 0x8267}, + {0x6201, 0x2315, 0x4113, 0x8337, 0x8157, 0x8267}, + {0x5102, 0x3304, 0x2315, 0x4113, 0x8337, 0x8157, 0x8267}, + {0x5102, 0x4223, 0x1326, 0x8337, 0x8157, 0x8267}, + {0x6201, 0x4223, 0x1326, 0x3304, 0x8337, 0x8157, 0x8267}, + {0x6201, 0x2315, 0x4113, 0x5102, 0x4223, 0x1326, 0x8337, 0x8157, 0x8267}, + {0x4223, 0x1326, 0x3304, 0x2315, 0x4113, 0x8337, 0x8157, 0x8267}, + {0x4113, 0x8157, 0x8267, 0x4223}, + {0x4223, 0x4113, 0x8157, 0x8267, 0x6201, 0x5102, 0x3304}, + {0x8157, 0x8267, 0x4223, 0x6201, 0x2315}, + {0x3304, 0x2315, 0x8157, 0x8267, 0x4223, 0x5102}, + {0x1326, 0x5102, 0x4113, 0x8157, 0x8267}, + {0x8157, 0x4113, 0x6201, 0x3304, 0x1326, 0x8267}, + {0x1326, 0x5102, 0x6201, 0x2315, 0x8157, 0x8267}, + {0x8267, 0x1326, 0x3304, 0x2315, 0x8157}, + {0x3304, 0x1146, 0x2245, 0x8337, 0x8157, 0x8267}, + {0x6201, 0x5102, 0x1146, 0x2245, 0x8337, 0x8157, 0x8267}, + {0x6201, 0x2315, 0x4113, 0x3304, 0x1146, 0x2245, 0x8337, 0x8157, 0x8267}, + {0x2315, 0x4113, 0x5102, 0x1146, 0x2245, 0x8337, 0x8157, 0x8267}, + {0x5102, 0x4223, 0x1326, 0x3304, 0x1146, 0x2245, 0x8337, 0x8157, 0x8267}, + {0x1146, 0x2245, 0x6201, 0x4223, 0x1326, 0x8337, 0x8157, 0x8267}, + {0x6201, 0x2315, 0x4113, 0x5102, 0x4223, 0x1326, 0x3304, 0x1146, 0x2245, 0x8337, 0x8157, 0x8267}, + {0x4113, 0x4223, 0x1326, 0x1146, 0x2245, 0x2315, 0x8337, 0x8157, 0x8267}, + {0x4223, 0x4113, 0x8157, 0x8267, 0x3304, 0x1146, 0x2245}, + {0x6201, 0x5102, 0x1146, 0x2245, 0x4223, 0x4113, 0x8157, 0x8267}, + {0x8157, 0x8267, 0x4223, 0x6201, 0x2315, 0x3304, 0x1146, 0x2245}, + {0x2315, 0x8157, 0x8267, 0x4223, 0x5102, 0x1146, 0x2245}, + {0x1326, 0x5102, 0x4113, 0x8157, 0x8267, 0x3304, 0x1146, 0x2245}, + {0x1326, 0x1146, 0x2245, 0x6201, 0x4113, 0x8157, 0x8267}, + {0x5102, 0x6201, 0x2315, 0x8157, 0x8267, 0x1326, 0x3304, 0x1146, 0x2245}, + {0x1326, 0x1146, 0x2245, 0x2315, 0x8157, 0x8267}, + {0x2315, 0x2245, 0x8267, 0x8337}, + {0x2315, 0x2245, 0x8267, 0x8337, 0x6201, 0x5102, 0x3304}, + {0x4113, 0x6201, 0x2245, 0x8267, 0x8337}, + {0x5102, 0x4113, 0x8337, 0x8267, 0x2245, 0x3304}, + {0x2315, 0x2245, 0x8267, 0x8337, 0x5102, 0x4223, 0x1326}, + {0x6201, 0x4223, 0x1326, 0x3304, 0x8337, 0x2315, 0x2245, 0x8267}, + {0x4113, 0x6201, 0x2245, 0x8267, 0x8337, 0x5102, 0x4223, 0x1326}, + {0x4113, 0x4223, 0x1326, 0x3304, 0x2245, 0x8267, 0x8337}, + {0x2315, 0x2245, 0x8267, 0x4223, 0x4113}, + {0x2315, 0x2245, 0x8267, 0x4223, 0x4113, 0x6201, 0x5102, 0x3304}, + {0x6201, 0x2245, 0x8267, 0x4223}, + {0x3304, 0x2245, 0x8267, 0x4223, 0x5102}, + {0x5102, 0x4113, 0x2315, 0x2245, 0x8267, 0x1326}, + {0x4113, 0x2315, 0x2245, 0x8267, 0x1326, 0x3304, 0x6201}, + {0x5102, 0x6201, 0x2245, 0x8267, 0x1326}, + {0x3304, 0x2245, 0x8267, 0x1326}, + {0x8267, 0x8337, 0x2315, 0x3304, 0x1146}, + {0x5102, 0x1146, 0x8267, 0x8337, 0x2315, 0x6201}, + {0x3304, 0x1146, 0x8267, 0x8337, 0x4113, 0x6201}, + {0x8337, 0x4113, 0x5102, 0x1146, 0x8267}, + {0x8267, 0x8337, 0x2315, 0x3304, 0x1146, 0x5102, 0x4223, 0x1326}, + {0x1146, 0x8267, 0x8337, 0x2315, 0x6201, 0x4223, 0x1326}, + {0x8267, 0x8337, 0x4113, 0x6201, 0x3304, 0x1146, 0x5102, 0x4223, 0x1326}, + {0x4113, 0x4223, 0x1326, 0x1146, 0x8267, 0x8337}, + {0x3304, 0x2315, 0x4113, 0x4223, 0x8267, 0x1146}, + {0x2315, 0x6201, 0x5102, 0x1146, 0x8267, 0x4223, 0x4113}, + {0x1146, 0x8267, 0x4223, 0x6201, 0x3304}, + {0x5102, 0x1146, 0x8267, 0x4223}, + {0x8267, 0x1326, 0x5102, 0x4113, 0x2315, 0x3304, 0x1146}, + {0x6201, 0x4113, 0x2315, 0x1326, 0x1146, 0x8267}, + {0x6201, 0x3304, 0x1146, 0x8267, 0x1326, 0x5102}, + {0x1326, 0x1146, 0x8267}, + {0x1326, 0x8337, 0x8157, 0x1146}, + {0x8337, 0x8157, 0x1146, 0x1326, 0x6201, 0x5102, 0x3304}, + {0x8337, 0x8157, 0x1146, 0x1326, 0x6201, 0x2315, 0x4113}, + {0x4113, 0x5102, 0x3304, 0x2315, 0x1326, 0x8337, 0x8157, 0x1146}, + {0x8337, 0x8157, 0x1146, 0x5102, 0x4223}, + {0x6201, 0x4223, 0x8337, 0x8157, 0x1146, 0x3304}, + {0x8337, 0x8157, 0x1146, 0x5102, 0x4223, 0x6201, 0x2315, 0x4113}, + {0x4223, 0x8337, 0x8157, 0x1146, 0x3304, 0x2315, 0x4113}, + {0x4223, 0x4113, 0x8157, 0x1146, 0x1326}, + {0x4223, 0x4113, 0x8157, 0x1146, 0x1326, 0x6201, 0x5102, 0x3304}, + {0x1146, 0x8157, 0x2315, 0x6201, 0x4223, 0x1326}, + {0x4223, 0x5102, 0x3304, 0x2315, 0x8157, 0x1146, 0x1326}, + {0x4113, 0x8157, 0x1146, 0x5102}, + {0x6201, 0x4113, 0x8157, 0x1146, 0x3304}, + {0x2315, 0x8157, 0x1146, 0x5102, 0x6201}, + {0x2315, 0x8157, 0x1146, 0x3304}, + {0x2245, 0x3304, 0x1326, 0x8337, 0x8157}, + {0x6201, 0x2245, 0x8157, 0x8337, 0x1326, 0x5102}, + {0x2245, 0x3304, 0x1326, 0x8337, 0x8157, 0x6201, 0x2315, 0x4113}, + {0x2245, 0x2315, 0x4113, 0x5102, 0x1326, 0x8337, 0x8157}, + {0x4223, 0x8337, 0x8157, 0x2245, 0x3304, 0x5102}, + {0x8157, 0x2245, 0x6201, 0x4223, 0x8337}, + {0x2245, 0x3304, 0x5102, 0x4223, 0x8337, 0x8157, 0x4113, 0x6201, 0x2315}, + {0x4223, 0x8337, 0x8157, 0x2245, 0x2315, 0x4113}, + {0x4113, 0x8157, 0x2245, 0x3304, 0x1326, 0x4223}, + {0x1326, 0x4223, 0x4113, 0x8157, 0x2245, 0x6201, 0x5102}, + {0x8157, 0x2245, 0x3304, 0x1326, 0x4223, 0x6201, 0x2315}, + {0x5102, 0x1326, 0x4223, 0x2315, 0x8157, 0x2245}, + {0x3304, 0x5102, 0x4113, 0x8157, 0x2245}, + {0x4113, 0x8157, 0x2245, 0x6201}, + {0x5102, 0x6201, 0x2315, 0x8157, 0x2245, 0x3304}, + {0x2315, 0x8157, 0x2245}, + {0x1146, 0x1326, 0x8337, 0x2315, 0x2245}, + {0x1146, 0x1326, 0x8337, 0x2315, 0x2245, 0x6201, 0x5102, 0x3304}, + {0x6201, 0x2245, 0x1146, 0x1326, 0x8337, 0x4113}, + {0x2245, 0x1146, 0x1326, 0x8337, 0x4113, 0x5102, 0x3304}, + {0x5102, 0x1146, 0x2245, 0x2315, 0x8337, 0x4223}, + {0x1146, 0x3304, 0x6201, 0x4223, 0x8337, 0x2315, 0x2245}, + {0x8337, 0x4113, 0x6201, 0x2245, 0x1146, 0x5102, 0x4223}, + {0x4223, 0x8337, 0x4113, 0x3304, 0x2245, 0x1146}, + {0x4113, 0x2315, 0x2245, 0x1146, 0x1326, 0x4223}, + {0x1146, 0x1326, 0x4223, 0x4113, 0x2315, 0x2245, 0x6201, 0x5102, 0x3304}, + {0x1326, 0x4223, 0x6201, 0x2245, 0x1146}, + {0x4223, 0x5102, 0x3304, 0x2245, 0x1146, 0x1326}, + {0x2245, 0x1146, 0x5102, 0x4113, 0x2315}, + {0x4113, 0x2315, 0x2245, 0x1146, 0x3304, 0x6201}, + {0x6201, 0x2245, 0x1146, 0x5102}, + {0x3304, 0x2245, 0x1146}, + {0x3304, 0x1326, 0x8337, 0x2315}, + {0x5102, 0x1326, 0x8337, 0x2315, 0x6201}, + {0x6201, 0x3304, 0x1326, 0x8337, 0x4113}, + {0x5102, 0x1326, 0x8337, 0x4113}, + {0x4223, 0x8337, 0x2315, 0x3304, 0x5102}, + {0x6201, 0x4223, 0x8337, 0x2315}, + {0x3304, 0x5102, 0x4223, 0x8337, 0x4113, 0x6201}, + {0x4113, 0x4223, 0x8337}, + {0x4113, 0x2315, 0x3304, 0x1326, 0x4223}, + {0x1326, 0x4223, 0x4113, 0x2315, 0x6201, 0x5102}, + {0x3304, 0x1326, 0x4223, 0x6201}, + {0x5102, 0x1326, 0x4223}, + {0x5102, 0x4113, 0x2315, 0x3304}, + {0x6201, 0x4113, 0x2315}, + {0x6201, 0x3304, 0x5102}, + {} + }; + + // The transitionCellClass table maps a 9-bit transition cell case index to an equivalence + // class index. Even though there are 73 equivalence classes in the Transvoxel Algorithm, + // several of them use the same exact triangulations, just with different vertex locations. + // We combined those classes for this table so that the class index ranges from 0 to 55. + // The high bit is set in the cases for which the inverse state of the voxel data maps to + // the equivalence class, meaning that the winding order of each triangle should be reversed. + + public static short[] transitionCellClass = new short[]{ + 0x00, 0x01, 0x02, 0x84, 0x01, 0x05, 0x04, 0x04, 0x02, 0x87, 0x09, 0x8C, 0x84, 0x0B, 0x05, 0x05, + 0x01, 0x08, 0x07, 0x8D, 0x05, 0x0F, 0x8B, 0x0B, 0x04, 0x0D, 0x0C, 0x1C, 0x04, 0x8B, 0x85, 0x85, + 0x02, 0x07, 0x09, 0x8C, 0x87, 0x10, 0x0C, 0x0C, 0x09, 0x12, 0x15, 0x9A, 0x8C, 0x19, 0x90, 0x10, + 0x84, 0x8D, 0x8C, 0x9C, 0x0B, 0x9D, 0x0F, 0x0F, 0x05, 0x1B, 0x10, 0xAC, 0x05, 0x0F, 0x8B, 0x0B, + 0x01, 0x05, 0x87, 0x0B, 0x08, 0x0F, 0x0D, 0x8B, 0x07, 0x10, 0x12, 0x19, 0x8D, 0x9D, 0x1B, 0x0F, + 0x05, 0x0F, 0x10, 0x9D, 0x0F, 0x1E, 0x1D, 0xA1, 0x8B, 0x1D, 0x99, 0x32, 0x0B, 0xA1, 0x8F, 0x94, + 0x04, 0x8B, 0x0C, 0x0F, 0x0D, 0x1D, 0x1C, 0x8F, 0x0C, 0x99, 0x1A, 0x31, 0x1C, 0x32, 0x2C, 0xA7, + 0x04, 0x0B, 0x0C, 0x0F, 0x8B, 0xA1, 0x8F, 0x96, 0x85, 0x8F, 0x90, 0x27, 0x85, 0x94, 0x8B, 0x8A, + 0x02, 0x04, 0x09, 0x05, 0x07, 0x8B, 0x0C, 0x85, 0x09, 0x0C, 0x15, 0x90, 0x8C, 0x0F, 0x10, 0x8B, + 0x87, 0x0D, 0x12, 0x1B, 0x10, 0x1D, 0x99, 0x8F, 0x0C, 0x1C, 0x1A, 0x2C, 0x0C, 0x8F, 0x90, 0x8B, + 0x09, 0x0C, 0x15, 0x10, 0x12, 0x99, 0x1A, 0x90, 0x15, 0x1A, 0x23, 0x30, 0x9A, 0x31, 0x30, 0x19, + 0x8C, 0x1C, 0x9A, 0xAC, 0x19, 0x32, 0x31, 0x27, 0x90, 0x2C, 0x30, 0x29, 0x10, 0xA7, 0x19, 0x24, + 0x84, 0x04, 0x8C, 0x05, 0x8D, 0x0B, 0x1C, 0x85, 0x8C, 0x0C, 0x9A, 0x10, 0x9C, 0x0F, 0xAC, 0x0B, + 0x0B, 0x8B, 0x19, 0x0F, 0x9D, 0xA1, 0x32, 0x94, 0x0F, 0x8F, 0x31, 0xA7, 0x0F, 0x96, 0x27, 0x8A, + 0x05, 0x85, 0x90, 0x8B, 0x1B, 0x8F, 0x2C, 0x8B, 0x10, 0x90, 0x30, 0x19, 0xAC, 0x27, 0x29, 0x24, + 0x05, 0x85, 0x10, 0x0B, 0x0F, 0x94, 0xA7, 0x8A, 0x8B, 0x8B, 0x19, 0x24, 0x0B, 0x8A, 0x24, 0x83, + 0x03, 0x06, 0x0A, 0x8B, 0x06, 0x0E, 0x0B, 0x0B, 0x0A, 0x91, 0x14, 0x8F, 0x8B, 0x17, 0x05, 0x85, + 0x06, 0x13, 0x11, 0x98, 0x0E, 0x1F, 0x97, 0x2B, 0x0B, 0x18, 0x0F, 0x36, 0x0B, 0xAB, 0x05, 0x85, + 0x0A, 0x11, 0x16, 0x8F, 0x91, 0x20, 0x0F, 0x8F, 0x14, 0x22, 0x21, 0x1D, 0x8F, 0x2D, 0x0B, 0x8B, + 0x8B, 0x98, 0x8F, 0xB7, 0x17, 0xAE, 0x8C, 0x0C, 0x05, 0x2F, 0x8B, 0xB5, 0x85, 0xA6, 0x84, 0x04, + 0x06, 0x0E, 0x91, 0x17, 0x13, 0x1F, 0x18, 0xAB, 0x11, 0x20, 0x22, 0x2D, 0x98, 0xAE, 0x2F, 0xA6, + 0x0E, 0x1F, 0x20, 0xAE, 0x1F, 0x33, 0x2E, 0x2A, 0x97, 0x2E, 0xAD, 0x28, 0x2B, 0x2A, 0x26, 0x25, + 0x0B, 0x97, 0x0F, 0x8C, 0x18, 0x2E, 0x37, 0x8C, 0x0F, 0xAD, 0x9D, 0x90, 0x36, 0x28, 0x35, 0x07, + 0x0B, 0x2B, 0x8F, 0x0C, 0xAB, 0x2A, 0x8C, 0x89, 0x05, 0x26, 0x0B, 0x87, 0x85, 0x25, 0x84, 0x82, + 0x0A, 0x0B, 0x14, 0x05, 0x11, 0x97, 0x0F, 0x05, 0x16, 0x0F, 0x21, 0x0B, 0x8F, 0x8C, 0x8B, 0x84, + 0x91, 0x18, 0x22, 0x2F, 0x20, 0x2E, 0xAD, 0x26, 0x0F, 0x37, 0x9D, 0x35, 0x8F, 0x8C, 0x0B, 0x84, + 0x14, 0x0F, 0x21, 0x8B, 0x22, 0xAD, 0x9D, 0x0B, 0x21, 0x9D, 0x9E, 0x8F, 0x1D, 0x90, 0x8F, 0x85, + 0x8F, 0x36, 0x1D, 0xB5, 0x2D, 0x28, 0x90, 0x87, 0x0B, 0x35, 0x8F, 0x34, 0x8B, 0x07, 0x85, 0x81, + 0x8B, 0x0B, 0x8F, 0x85, 0x98, 0x2B, 0x36, 0x85, 0x8F, 0x8F, 0x1D, 0x8B, 0xB7, 0x0C, 0xB5, 0x04, + 0x17, 0xAB, 0x2D, 0xA6, 0xAE, 0x2A, 0x28, 0x25, 0x8C, 0x8C, 0x90, 0x07, 0x0C, 0x89, 0x87, 0x82, + 0x05, 0x05, 0x0B, 0x84, 0x2F, 0x26, 0x35, 0x84, 0x8B, 0x0B, 0x8F, 0x85, 0xB5, 0x87, 0x34, 0x81, + 0x85, 0x85, 0x8B, 0x04, 0xA6, 0x25, 0x07, 0x82, 0x84, 0x84, 0x85, 0x81, 0x04, 0x82, 0x81, 0x80 + }; + + // The transitionCellData table holds the triangulation data for all 56 distinct classes to + // which a case can be mapped by the transitionCellClass table. The class index should be ANDed + // with 0x7F before using it to look up triangulation data in this table. + public static final TransitionCellData[] transitionCellData = new TransitionCellData[56]; + static { + regularCellData[0] = new RegularCellData((byte)0x00, new byte[]{}); + regularCellData[1] = new RegularCellData((byte)0x42, new byte[]{0, 1, 3, 1, 2, 3}); + regularCellData[2] = new RegularCellData((byte)0x31, new byte[]{0, 1, 2}); + regularCellData[3] = new RegularCellData((byte)0x42, new byte[]{0, 1, 2, 0, 2, 3}); + regularCellData[4] = new RegularCellData((byte)0x53, new byte[]{0, 1, 4, 1, 3, 4, 1, 2, 3}); + regularCellData[5] = new RegularCellData((byte)0x64, new byte[]{0, 1, 5, 1, 2, 5, 2, 4, 5, 2, 3, 4}); + regularCellData[6] = new RegularCellData((byte)0x84, new byte[]{0, 1, 3, 1, 2, 3, 4, 5, 6, 4, 6, 7}); + regularCellData[7] = new RegularCellData((byte)0x73, new byte[]{0, 1, 3, 1, 2, 3, 4, 5, 6}); + regularCellData[8] = new RegularCellData((byte)0x84, new byte[]{0, 1, 3, 1, 2, 3, 4, 5, 7, 5, 6, 7}); + regularCellData[9] = new RegularCellData((byte)0x62, new byte[]{0, 1, 2, 3, 4, 5}); + regularCellData[10] = new RegularCellData((byte)0x53, new byte[]{0, 1, 3, 0, 3, 4, 1, 2, 3}); + regularCellData[11] = new RegularCellData((byte)0x75, new byte[]{0, 1, 6, 1, 2, 6, 2, 5, 6, 2, 3, 5, 3, 4, 5}); + regularCellData[12] = new RegularCellData((byte)0x84, new byte[]{0, 1, 4, 1, 3, 4, 1, 2, 3, 5, 6, 7}); + regularCellData[13] = new RegularCellData((byte)0x95, new byte[]{0, 1, 4, 1, 3, 4, 1, 2, 3, 5, 6, 8, 6, 7, 8}); + regularCellData[14] = new RegularCellData((byte)0xA6, new byte[]{0, 1, 5, 1, 2, 5, 2, 4, 5, 2, 3, 4, 6, 7, 8, 6, 8, 9}); + regularCellData[15] = new RegularCellData((byte)0x86, new byte[]{0, 1, 7, 1, 2, 7, 2, 3, 7, 3, 6, 7, 3, 4, 6, 4, 5, 6}); + regularCellData[16] = new RegularCellData((byte)0x95, new byte[]{0, 1, 5, 1, 2, 5, 2, 4, 5, 2, 3, 4, 6, 7, 8}); + regularCellData[17] = new RegularCellData((byte)0x95, new byte[]{0, 1, 3, 1, 2, 3, 4, 5, 7, 4, 7, 8, 5, 6, 7}); + regularCellData[18] = new RegularCellData((byte)0xA4, new byte[]{0, 1, 3, 1, 2, 3, 4, 5, 6, 7, 8, 9}); + regularCellData[19] = new RegularCellData((byte)0xC6, new byte[]{0, 1, 3, 1, 2, 3, 4, 5, 7, 5, 6, 7, 8, 9, 10, 8, 10, 11}); + regularCellData[20] = new RegularCellData((byte)0x64, new byte[]{0, 1, 3, 1, 2, 3, 0, 3, 4, 0, 4, 5}); + regularCellData[21] = new RegularCellData((byte)0x93, new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8}); + regularCellData[22] = new RegularCellData((byte)0x64, new byte[]{0, 1, 4, 0, 4, 5, 1, 3, 4, 1, 2, 3}); + regularCellData[23] = new RegularCellData((byte)0x97, new byte[]{0, 1, 8, 1, 7, 8, 1, 2, 7, 2, 3, 7, 3, 4, 7, 4, 5, 7, 5, 6, 7}); + regularCellData[24] = new RegularCellData((byte)0xB7, new byte[]{0, 1, 6, 1, 2, 6, 2, 5, 6, 2, 3, 5, 3, 4, 5, 7, 8, 10, 8, 9, 10}); + regularCellData[25] = new RegularCellData((byte)0xA6, new byte[]{0, 1, 6, 1, 2, 6, 2, 5, 6, 2, 3, 5, 3, 4, 5, 7, 8, 9}); + regularCellData[26] = new RegularCellData((byte)0xB5, new byte[]{0, 1, 4, 1, 3, 4, 1, 2, 3, 5, 6, 7, 8, 9, 10}); + regularCellData[27] = new RegularCellData((byte)0xA6, new byte[]{0, 1, 5, 1, 2, 5, 2, 4, 5, 2, 3, 4, 6, 7, 9, 7, 8, 9}); + regularCellData[28] = new RegularCellData((byte)0xA6, new byte[]{0, 1, 4, 1, 3, 4, 1, 2, 3, 5, 6, 9, 6, 8, 9, 6, 7, 8}); + regularCellData[29] = new RegularCellData((byte)0x97, new byte[]{0, 1, 8, 1, 2, 8, 2, 3, 8, 3, 7, 8, 3, 4, 7, 4, 5, 7, 5, 6, 7}); + regularCellData[30] = new RegularCellData((byte)0x86, new byte[]{0, 1, 7, 1, 6, 7, 1, 2, 6, 2, 5, 6, 2, 4, 5, 2, 3, 4}); + regularCellData[31] = new RegularCellData((byte)0xC8, new byte[]{0, 1, 7, 1, 2, 7, 2, 3, 7, 3, 6, 7, 3, 4, 6, 4, 5, 6, 8, 9, 10, 8, 10, 11}); + regularCellData[32] = new RegularCellData((byte)0xB7, new byte[]{0, 1, 5, 1, 2, 5, 2, 4, 5, 2, 3, 4, 6, 9, 10, 6, 7, 9, 7, 8, 9}); + regularCellData[33] = new RegularCellData((byte)0x75, new byte[]{0, 1, 6, 1, 3, 6, 1, 2, 3, 3, 4, 6, 4, 5, 6}); + regularCellData[34] = new RegularCellData((byte)0xA6, new byte[]{0, 1, 3, 1, 2, 3, 4, 5, 9, 5, 8, 9, 5, 6, 8, 6, 7, 8}); + regularCellData[35] = new RegularCellData((byte)0xC4, new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}); + regularCellData[36] = new RegularCellData((byte)0x86, new byte[]{1, 2, 4, 2, 3, 4, 0, 1, 7, 1, 4, 7, 4, 6, 7, 4, 5, 6}); + regularCellData[37] = new RegularCellData((byte)0x64, new byte[]{0, 4, 5, 0, 1, 4, 1, 3, 4, 1, 2, 3}); + regularCellData[38] = new RegularCellData((byte)0x86, new byte[]{0, 1, 4, 1, 3, 4, 1, 2, 3, 0, 4, 7, 4, 6, 7, 4, 5, 6}); + regularCellData[39] = new RegularCellData((byte)0x97, new byte[]{1, 2, 3, 1, 3, 4, 1, 4, 5, 0, 1, 8, 1, 5, 8, 5, 7, 8, 5, 6, 7}); + regularCellData[40] = new RegularCellData((byte)0xA6, new byte[]{0, 1, 3, 1, 2, 3, 4, 5, 9, 5, 8, 9, 5, 6, 8, 6, 7, 8}); + regularCellData[41] = new RegularCellData((byte)0xC8, new byte[]{0, 1, 5, 1, 2, 5, 2, 4, 5, 2, 3, 4, 6, 7, 11, 7, 10, 11, 7, 8, 10, 8, 9, 10}); + regularCellData[42] = new RegularCellData((byte)0x97, new byte[]{0, 1, 8, 1, 2, 8, 2, 7, 8, 2, 3, 7, 3, 6, 7, 3, 4, 6, 4, 5, 6}); + regularCellData[43] = new RegularCellData((byte)0x97, new byte[]{0, 1, 4, 1, 3, 4, 1, 2, 3, 0, 4, 8, 4, 7, 8, 4, 5, 7, 5, 6, 7}); + regularCellData[44] = new RegularCellData((byte)0xB7, new byte[]{0, 1, 5, 1, 2, 5, 2, 4, 5, 2, 3, 4, 6, 7, 10, 7, 9, 10, 7, 8, 9}); + regularCellData[45] = new RegularCellData((byte)0xA8, new byte[]{0, 1, 9, 1, 2, 9, 2, 8, 9, 2, 3, 8, 3, 7, 8, 3, 4, 7, 4, 6, 7, 4, 5, 6}); + regularCellData[46] = new RegularCellData((byte)0xB9, new byte[]{0, 1, 7, 1, 6, 7, 1, 2, 6, 2, 5, 6, 2, 3, 5, 3, 4, 5, 0, 7, 10, 7, 9, 10, 7, 8, 9}); + regularCellData[47] = new RegularCellData((byte)0xA6, new byte[]{0, 1, 5, 1, 4, 5, 1, 2, 4, 2, 3, 4, 6, 7, 9, 7, 8, 9}); + regularCellData[48] = new RegularCellData((byte)0xC6, new byte[]{0, 1, 5, 1, 2, 5, 2, 4, 5, 2, 3, 4, 6, 7, 8, 9, 10, 11}); + regularCellData[49] = new RegularCellData((byte)0xB7, new byte[]{0, 1, 7, 1, 2, 7, 2, 3, 7, 3, 6, 7, 3, 4, 6, 4, 5, 6, 8, 9, 10}); + regularCellData[50] = new RegularCellData((byte)0xA8, new byte[]{1, 2, 3, 1, 3, 4, 1, 4, 6, 4, 5, 6, 0, 1, 9, 1, 6, 9, 6, 8, 9, 6, 7, 8}); + regularCellData[51] = new RegularCellData((byte)0xCC, new byte[]{0, 1, 9, 1, 8, 9, 1, 2, 8, 2, 11, 8, 2, 3, 11, 3, 4, 11, 4, 5, 11, 5, 10, 11, 5, 6, 10, 6, 9, 10, 6, 7, 9, 7, 0, 9}); + regularCellData[52] = new RegularCellData((byte)0x86, new byte[]{0, 1, 2, 0, 2, 3, 0, 6, 7, 0, 3, 6, 1, 4, 5, 1, 5, 2}); + regularCellData[53] = new RegularCellData((byte)0x97, new byte[]{0, 1, 4, 1, 3, 4, 1, 2, 3, 2, 5, 6, 2, 6, 3, 0, 7, 8, 0, 4, 7}); + regularCellData[54] = new RegularCellData((byte)0xA8, new byte[]{0, 1, 5, 1, 4, 5, 1, 2, 4, 2, 3, 4, 3, 6, 7, 3, 7, 4, 0, 8, 9, 0, 5, 8}); + regularCellData[55] = new RegularCellData((byte)0xA8, new byte[]{0, 1, 5, 1, 4, 5, 1, 2, 4, 2, 3, 4, 2, 6, 3, 3, 6, 7, 0, 8, 9, 0, 5, 8}); + }; + + // The transitionCornerData table contains the transition cell corner reuse data + // shown in Figure 4.18. + public static final char[] transitionCornerData = new char[]{ + 0x30, 0x21, 0x20, 0x12, 0x40, 0x82, 0x10, 0x81, 0x80, 0x37, 0x27, 0x17, 0x87 + }; + + + // The transitionVertexData table gives the vertex locations for every one of the 512 possible + // cases in the Tranvoxel Algorithm. Each 16-bit value also provides information about whether + // a vertex can be reused from a neighboring cell. See Section 4.5 for details. The low byte + // contains the indexes for the two endpoints of the edge on which the vertex lies, as numbered + // in Figure 4.16. The high byte contains the vertex reuse data shown in Figure 4.17. + public static final int[][] transitionVertexData = new int[][]{ + {}, + {0x2301, 0x1503, 0x199B, 0x289A}, + {0x2301, 0x2412, 0x4514}, + {0x1503, 0x4514, 0x2412, 0x289A, 0x199B}, + {0x8525, 0x2412, 0x289A, 0x89AC}, + {0x8525, 0x2412, 0x2301, 0x1503, 0x199B, 0x89AC}, + {0x8525, 0x4514, 0x2301, 0x289A, 0x89AC}, + {0x8525, 0x4514, 0x1503, 0x199B, 0x89AC}, + {0x8525, 0x8658, 0x4445}, + {0x1503, 0x2301, 0x289A, 0x199B, 0x8658, 0x8525, 0x4445}, + {0x8525, 0x8658, 0x4445, 0x2301, 0x2412, 0x4514}, + {0x1503, 0x4514, 0x2412, 0x289A, 0x199B, 0x8658, 0x8525, 0x4445}, + {0x2412, 0x4445, 0x8658, 0x89AC, 0x289A}, + {0x8658, 0x4445, 0x2412, 0x2301, 0x1503, 0x199B, 0x89AC}, + {0x8658, 0x4445, 0x4514, 0x2301, 0x289A, 0x89AC}, + {0x8658, 0x4445, 0x4514, 0x1503, 0x199B, 0x89AC}, + {0x8478, 0x8658, 0x89AC, 0x88BC}, + {0x2301, 0x1503, 0x199B, 0x289A, 0x8478, 0x8658, 0x89AC, 0x88BC}, + {0x8478, 0x8658, 0x89AC, 0x88BC, 0x2301, 0x2412, 0x4514}, + {0x1503, 0x4514, 0x2412, 0x289A, 0x199B, 0x8658, 0x8478, 0x88BC, 0x89AC}, + {0x8478, 0x8658, 0x8525, 0x2412, 0x289A, 0x88BC}, + {0x8478, 0x8658, 0x8525, 0x2412, 0x2301, 0x1503, 0x199B, 0x88BC}, + {0x2301, 0x4514, 0x8525, 0x8658, 0x8478, 0x88BC, 0x289A}, + {0x8478, 0x8658, 0x8525, 0x4514, 0x1503, 0x199B, 0x88BC}, + {0x8478, 0x4445, 0x8525, 0x89AC, 0x88BC}, + {0x8478, 0x4445, 0x8525, 0x89AC, 0x88BC, 0x2301, 0x1503, 0x199B, 0x289A}, + {0x8478, 0x4445, 0x8525, 0x89AC, 0x88BC, 0x2301, 0x2412, 0x4514}, + {0x8478, 0x4445, 0x8525, 0x89AC, 0x88BC, 0x2412, 0x4514, 0x1503, 0x199B, 0x289A}, + {0x8478, 0x4445, 0x2412, 0x289A, 0x88BC}, + {0x1503, 0x2301, 0x2412, 0x4445, 0x8478, 0x88BC, 0x199B}, + {0x2301, 0x4514, 0x4445, 0x8478, 0x88BC, 0x289A}, + {0x1503, 0x4514, 0x4445, 0x8478, 0x88BC, 0x199B}, + {0x8478, 0x8367, 0x4647}, + {0x2301, 0x1503, 0x199B, 0x289A, 0x8478, 0x8367, 0x4647}, + {0x2301, 0x2412, 0x4514, 0x8478, 0x8367, 0x4647}, + {0x1503, 0x4514, 0x2412, 0x289A, 0x199B, 0x8367, 0x8478, 0x4647}, + {0x2412, 0x8525, 0x89AC, 0x289A, 0x8367, 0x8478, 0x4647}, + {0x8525, 0x2412, 0x2301, 0x1503, 0x199B, 0x89AC, 0x8478, 0x8367, 0x4647}, + {0x8525, 0x4514, 0x2301, 0x289A, 0x89AC, 0x8478, 0x8367, 0x4647}, + {0x8525, 0x4514, 0x1503, 0x199B, 0x89AC, 0x8478, 0x8367, 0x4647}, + {0x8478, 0x8367, 0x4647, 0x8525, 0x8658, 0x4445}, + {0x2301, 0x1503, 0x199B, 0x289A, 0x8478, 0x8367, 0x4647, 0x8525, 0x8658, 0x4445}, + {0x8478, 0x8367, 0x4647, 0x8525, 0x8658, 0x4445, 0x2301, 0x2412, 0x4514}, + {0x1503, 0x4514, 0x2412, 0x289A, 0x199B, 0x8658, 0x8525, 0x4445, 0x8367, 0x8478, 0x4647}, + {0x2412, 0x4445, 0x8658, 0x89AC, 0x289A, 0x8367, 0x8478, 0x4647}, + {0x8658, 0x4445, 0x2412, 0x2301, 0x1503, 0x199B, 0x89AC, 0x8478, 0x8367, 0x4647}, + {0x2301, 0x4514, 0x4445, 0x8658, 0x89AC, 0x289A, 0x8367, 0x8478, 0x4647}, + {0x8658, 0x4445, 0x4514, 0x1503, 0x199B, 0x89AC, 0x8478, 0x8367, 0x4647}, + {0x8658, 0x4647, 0x8367, 0x88BC, 0x89AC}, + {0x8658, 0x4647, 0x8367, 0x88BC, 0x89AC, 0x1503, 0x2301, 0x289A, 0x199B}, + {0x8658, 0x4647, 0x8367, 0x88BC, 0x89AC, 0x2412, 0x2301, 0x4514}, + {0x1503, 0x4514, 0x2412, 0x289A, 0x199B, 0x8658, 0x4647, 0x8367, 0x88BC, 0x89AC}, + {0x8367, 0x4647, 0x8658, 0x8525, 0x2412, 0x289A, 0x88BC}, + {0x1503, 0x2301, 0x2412, 0x8525, 0x8658, 0x4647, 0x8367, 0x88BC, 0x199B}, + {0x8367, 0x4647, 0x8658, 0x8525, 0x4514, 0x2301, 0x289A, 0x88BC}, + {0x8367, 0x4647, 0x8658, 0x8525, 0x4514, 0x1503, 0x199B, 0x88BC}, + {0x8367, 0x4647, 0x4445, 0x8525, 0x89AC, 0x88BC}, + {0x8367, 0x4647, 0x4445, 0x8525, 0x89AC, 0x88BC, 0x2301, 0x1503, 0x199B, 0x289A}, + {0x8367, 0x4647, 0x4445, 0x8525, 0x89AC, 0x88BC, 0x2301, 0x2412, 0x4514}, + {0x8525, 0x4445, 0x4647, 0x8367, 0x88BC, 0x89AC, 0x1503, 0x4514, 0x2412, 0x289A, 0x199B}, + {0x8367, 0x4647, 0x4445, 0x2412, 0x289A, 0x88BC}, + {0x8367, 0x4647, 0x4445, 0x2412, 0x2301, 0x1503, 0x199B, 0x88BC}, + {0x2301, 0x4514, 0x4445, 0x4647, 0x8367, 0x88BC, 0x289A}, + {0x8367, 0x4647, 0x4445, 0x4514, 0x1503, 0x199B, 0x88BC}, + {0x1636, 0x8367, 0x88BC, 0x199B}, + {0x2301, 0x1503, 0x1636, 0x8367, 0x88BC, 0x289A}, + {0x8367, 0x1636, 0x199B, 0x88BC, 0x2412, 0x2301, 0x4514}, + {0x2412, 0x4514, 0x1503, 0x1636, 0x8367, 0x88BC, 0x289A}, + {0x8525, 0x2412, 0x289A, 0x89AC, 0x1636, 0x8367, 0x88BC, 0x199B}, + {0x8525, 0x2412, 0x2301, 0x1503, 0x1636, 0x8367, 0x88BC, 0x89AC}, + {0x8525, 0x4514, 0x2301, 0x289A, 0x89AC, 0x1636, 0x8367, 0x88BC, 0x199B}, + {0x8367, 0x1636, 0x1503, 0x4514, 0x8525, 0x89AC, 0x88BC}, + {0x1636, 0x8367, 0x88BC, 0x199B, 0x8525, 0x8658, 0x4445}, + {0x2301, 0x1503, 0x1636, 0x8367, 0x88BC, 0x289A, 0x8525, 0x8658, 0x4445}, + {0x1636, 0x8367, 0x88BC, 0x199B, 0x8525, 0x8658, 0x4445, 0x2301, 0x2412, 0x4514}, + {0x2412, 0x4514, 0x1503, 0x1636, 0x8367, 0x88BC, 0x289A, 0x8525, 0x8658, 0x4445}, + {0x2412, 0x4445, 0x8658, 0x89AC, 0x289A, 0x8367, 0x1636, 0x199B, 0x88BC}, + {0x8367, 0x1636, 0x1503, 0x2301, 0x2412, 0x4445, 0x8658, 0x89AC, 0x88BC}, + {0x8658, 0x4445, 0x4514, 0x2301, 0x289A, 0x89AC, 0x1636, 0x8367, 0x88BC, 0x199B}, + {0x8658, 0x4445, 0x4514, 0x1503, 0x1636, 0x8367, 0x88BC, 0x89AC}, + {0x1636, 0x8367, 0x8478, 0x8658, 0x89AC, 0x199B}, + {0x2301, 0x1503, 0x1636, 0x8367, 0x8478, 0x8658, 0x89AC, 0x289A}, + {0x1636, 0x8367, 0x8478, 0x8658, 0x89AC, 0x199B, 0x2301, 0x2412, 0x4514}, + {0x8658, 0x8478, 0x8367, 0x1636, 0x1503, 0x4514, 0x2412, 0x289A, 0x89AC}, + {0x1636, 0x8367, 0x8478, 0x8658, 0x8525, 0x2412, 0x289A, 0x199B}, + {0x1636, 0x8367, 0x8478, 0x8658, 0x8525, 0x2412, 0x2301, 0x1503}, + {0x1636, 0x8367, 0x8478, 0x8658, 0x8525, 0x4514, 0x2301, 0x289A, 0x199B}, + {0x1503, 0x4514, 0x8525, 0x8658, 0x8478, 0x8367, 0x1636}, + {0x8525, 0x4445, 0x8478, 0x8367, 0x1636, 0x199B, 0x89AC}, + {0x2301, 0x1503, 0x1636, 0x8367, 0x8478, 0x4445, 0x8525, 0x89AC, 0x289A}, + {0x8525, 0x4445, 0x8478, 0x8367, 0x1636, 0x199B, 0x89AC, 0x2412, 0x2301, 0x4514}, + {0x2412, 0x4514, 0x1503, 0x1636, 0x8367, 0x8478, 0x4445, 0x8525, 0x89AC, 0x289A}, + {0x1636, 0x8367, 0x8478, 0x4445, 0x2412, 0x289A, 0x199B}, + {0x2412, 0x4445, 0x8478, 0x8367, 0x1636, 0x1503, 0x2301}, + {0x2301, 0x4514, 0x4445, 0x8478, 0x8367, 0x1636, 0x199B, 0x289A}, + {0x8367, 0x1636, 0x1503, 0x4514, 0x4445, 0x8478}, + {0x1636, 0x4647, 0x8478, 0x88BC, 0x199B}, + {0x8478, 0x4647, 0x1636, 0x1503, 0x2301, 0x289A, 0x88BC}, + {0x1636, 0x4647, 0x8478, 0x88BC, 0x199B, 0x2301, 0x2412, 0x4514}, + {0x2412, 0x4514, 0x1503, 0x1636, 0x4647, 0x8478, 0x88BC, 0x289A}, + {0x1636, 0x4647, 0x8478, 0x88BC, 0x199B, 0x8525, 0x2412, 0x289A, 0x89AC}, + {0x8525, 0x2412, 0x2301, 0x1503, 0x1636, 0x4647, 0x8478, 0x88BC, 0x89AC}, + {0x8525, 0x4514, 0x2301, 0x289A, 0x89AC, 0x1636, 0x4647, 0x8478, 0x88BC, 0x199B}, + {0x8478, 0x4647, 0x1636, 0x1503, 0x4514, 0x8525, 0x89AC, 0x88BC}, + {0x1636, 0x4647, 0x8478, 0x88BC, 0x199B, 0x8525, 0x8658, 0x4445}, + {0x8478, 0x4647, 0x1636, 0x1503, 0x2301, 0x289A, 0x88BC, 0x8658, 0x8525, 0x4445}, + {0x1636, 0x4647, 0x8478, 0x88BC, 0x199B, 0x8525, 0x8658, 0x4445, 0x2301, 0x2412, 0x4514}, + {0x2412, 0x4514, 0x1503, 0x1636, 0x4647, 0x8478, 0x88BC, 0x289A, 0x8525, 0x8658, 0x4445}, + {0x1636, 0x4647, 0x8478, 0x88BC, 0x199B, 0x8658, 0x4445, 0x2412, 0x289A, 0x89AC}, + {0x8658, 0x4445, 0x2412, 0x2301, 0x1503, 0x1636, 0x4647, 0x8478, 0x88BC, 0x89AC}, + {0x8658, 0x4445, 0x4514, 0x2301, 0x289A, 0x89AC, 0x1636, 0x4647, 0x8478, 0x88BC, 0x199B}, + {0x8478, 0x4647, 0x1636, 0x1503, 0x4514, 0x4445, 0x8658, 0x89AC, 0x88BC}, + {0x1636, 0x4647, 0x8658, 0x89AC, 0x199B}, + {0x2301, 0x1503, 0x1636, 0x4647, 0x8658, 0x89AC, 0x289A}, + {0x1636, 0x4647, 0x8658, 0x89AC, 0x199B, 0x2301, 0x2412, 0x4514}, + {0x2412, 0x4514, 0x1503, 0x1636, 0x4647, 0x8658, 0x89AC, 0x289A}, + {0x2412, 0x8525, 0x8658, 0x4647, 0x1636, 0x199B, 0x289A}, + {0x8658, 0x4647, 0x1636, 0x1503, 0x2301, 0x2412, 0x8525}, + {0x2301, 0x4514, 0x8525, 0x8658, 0x4647, 0x1636, 0x199B, 0x289A}, + {0x1503, 0x4514, 0x8525, 0x8658, 0x4647, 0x1636}, + {0x8525, 0x4445, 0x4647, 0x1636, 0x199B, 0x89AC}, + {0x8525, 0x4445, 0x4647, 0x1636, 0x1503, 0x2301, 0x289A, 0x89AC}, + {0x8525, 0x4445, 0x4647, 0x1636, 0x199B, 0x89AC, 0x2412, 0x2301, 0x4514}, + {0x2412, 0x4514, 0x1503, 0x1636, 0x4647, 0x4445, 0x8525, 0x89AC, 0x289A}, + {0x2412, 0x4445, 0x4647, 0x1636, 0x199B, 0x289A}, + {0x1503, 0x2301, 0x2412, 0x4445, 0x4647, 0x1636}, + {0x2301, 0x4514, 0x4445, 0x4647, 0x1636, 0x199B, 0x289A}, + {0x1503, 0x4514, 0x4445, 0x4647, 0x1636}, + {0x1636, 0x1503, 0x4334}, + {0x2301, 0x4334, 0x1636, 0x199B, 0x289A}, + {0x2301, 0x2412, 0x4514, 0x1636, 0x1503, 0x4334}, + {0x2412, 0x4514, 0x4334, 0x1636, 0x199B, 0x289A}, + {0x8525, 0x2412, 0x289A, 0x89AC, 0x1636, 0x1503, 0x4334}, + {0x1636, 0x4334, 0x2301, 0x2412, 0x8525, 0x89AC, 0x199B}, + {0x8525, 0x4514, 0x2301, 0x289A, 0x89AC, 0x1636, 0x1503, 0x4334}, + {0x1636, 0x4334, 0x4514, 0x8525, 0x89AC, 0x199B}, + {0x1636, 0x1503, 0x4334, 0x8525, 0x8658, 0x4445}, + {0x2301, 0x4334, 0x1636, 0x199B, 0x289A, 0x8525, 0x8658, 0x4445}, + {0x8525, 0x8658, 0x4445, 0x2301, 0x2412, 0x4514, 0x1636, 0x1503, 0x4334}, + {0x1636, 0x4334, 0x4514, 0x2412, 0x289A, 0x199B, 0x8658, 0x8525, 0x4445}, + {0x2412, 0x4445, 0x8658, 0x89AC, 0x289A, 0x1503, 0x1636, 0x4334}, + {0x8658, 0x4445, 0x2412, 0x2301, 0x4334, 0x1636, 0x199B, 0x89AC}, + {0x8658, 0x4445, 0x4514, 0x2301, 0x289A, 0x89AC, 0x1636, 0x1503, 0x4334}, + {0x1636, 0x4334, 0x4514, 0x4445, 0x8658, 0x89AC, 0x199B}, + {0x8658, 0x8478, 0x88BC, 0x89AC, 0x1503, 0x1636, 0x4334}, + {0x2301, 0x4334, 0x1636, 0x199B, 0x289A, 0x8478, 0x8658, 0x89AC, 0x88BC}, + {0x8478, 0x8658, 0x89AC, 0x88BC, 0x2301, 0x2412, 0x4514, 0x1636, 0x1503, 0x4334}, + {0x2412, 0x4514, 0x4334, 0x1636, 0x199B, 0x289A, 0x8478, 0x8658, 0x89AC, 0x88BC}, + {0x8478, 0x8658, 0x8525, 0x2412, 0x289A, 0x88BC, 0x1636, 0x1503, 0x4334}, + {0x8478, 0x8658, 0x8525, 0x2412, 0x2301, 0x4334, 0x1636, 0x199B, 0x88BC}, + {0x2301, 0x4514, 0x8525, 0x8658, 0x8478, 0x88BC, 0x289A, 0x1503, 0x1636, 0x4334}, + {0x1636, 0x4334, 0x4514, 0x8525, 0x8658, 0x8478, 0x88BC, 0x199B}, + {0x8478, 0x4445, 0x8525, 0x89AC, 0x88BC, 0x1636, 0x1503, 0x4334}, + {0x2301, 0x4334, 0x1636, 0x199B, 0x289A, 0x8478, 0x4445, 0x8525, 0x89AC, 0x88BC}, + {0x8478, 0x4445, 0x8525, 0x89AC, 0x88BC, 0x2301, 0x2412, 0x4514, 0x1636, 0x1503, 0x4334}, + {0x2412, 0x4514, 0x4334, 0x1636, 0x199B, 0x289A, 0x8478, 0x4445, 0x8525, 0x89AC, 0x88BC}, + {0x8478, 0x4445, 0x2412, 0x289A, 0x88BC, 0x1636, 0x1503, 0x4334}, + {0x1636, 0x4334, 0x2301, 0x2412, 0x4445, 0x8478, 0x88BC, 0x199B}, + {0x2301, 0x4514, 0x4445, 0x8478, 0x88BC, 0x289A, 0x1503, 0x1636, 0x4334}, + {0x1636, 0x4334, 0x4514, 0x4445, 0x8478, 0x88BC, 0x199B}, + {0x1636, 0x1503, 0x4334, 0x8478, 0x8367, 0x4647}, + {0x2301, 0x4334, 0x1636, 0x199B, 0x289A, 0x8478, 0x8367, 0x4647}, + {0x2301, 0x2412, 0x4514, 0x1636, 0x1503, 0x4334, 0x8478, 0x8367, 0x4647}, + {0x2412, 0x4514, 0x4334, 0x1636, 0x199B, 0x289A, 0x8478, 0x8367, 0x4647}, + {0x8525, 0x2412, 0x289A, 0x89AC, 0x1636, 0x1503, 0x4334, 0x8478, 0x8367, 0x4647}, + {0x1636, 0x4334, 0x2301, 0x2412, 0x8525, 0x89AC, 0x199B, 0x8367, 0x8478, 0x4647}, + {0x8525, 0x4514, 0x2301, 0x289A, 0x89AC, 0x1636, 0x1503, 0x4334, 0x8478, 0x8367, 0x4647}, + {0x1636, 0x4334, 0x4514, 0x8525, 0x89AC, 0x199B, 0x8367, 0x8478, 0x4647}, + {0x1636, 0x1503, 0x4334, 0x8478, 0x8367, 0x4647, 0x8525, 0x8658, 0x4445}, + {0x2301, 0x4334, 0x1636, 0x199B, 0x289A, 0x8478, 0x8367, 0x4647, 0x8525, 0x8658, 0x4445}, + {0x2301, 0x2412, 0x4514, 0x1636, 0x1503, 0x4334, 0x8478, 0x8367, 0x4647, 0x8525, 0x8658, 0x4445}, + {0x2412, 0x4514, 0x4334, 0x1636, 0x199B, 0x289A, 0x8478, 0x8367, 0x4647, 0x8525, 0x8658, 0x4445}, + {0x2412, 0x4445, 0x8658, 0x89AC, 0x289A, 0x8367, 0x8478, 0x4647, 0x1503, 0x1636, 0x4334}, + {0x8658, 0x4445, 0x2412, 0x2301, 0x4334, 0x1636, 0x199B, 0x89AC, 0x8478, 0x8367, 0x4647}, + {0x8658, 0x4445, 0x4514, 0x2301, 0x289A, 0x89AC, 0x1636, 0x1503, 0x4334, 0x8478, 0x8367, 0x4647}, + {0x8658, 0x4445, 0x4514, 0x4334, 0x1636, 0x199B, 0x89AC, 0x8478, 0x8367, 0x4647}, + {0x8658, 0x4647, 0x8367, 0x88BC, 0x89AC, 0x1503, 0x1636, 0x4334}, + {0x2301, 0x4334, 0x1636, 0x199B, 0x289A, 0x8367, 0x4647, 0x8658, 0x89AC, 0x88BC}, + {0x8658, 0x4647, 0x8367, 0x88BC, 0x89AC, 0x1503, 0x1636, 0x4334, 0x2412, 0x2301, 0x4514}, + {0x1636, 0x4334, 0x4514, 0x2412, 0x289A, 0x199B, 0x8658, 0x4647, 0x8367, 0x88BC, 0x89AC}, + {0x8367, 0x4647, 0x8658, 0x8525, 0x2412, 0x289A, 0x88BC, 0x1636, 0x1503, 0x4334}, + {0x8367, 0x4647, 0x8658, 0x8525, 0x2412, 0x2301, 0x4334, 0x1636, 0x199B, 0x88BC}, + {0x8367, 0x4647, 0x8658, 0x8525, 0x4514, 0x2301, 0x289A, 0x88BC, 0x1636, 0x1503, 0x4334}, + {0x8367, 0x4647, 0x8658, 0x8525, 0x4514, 0x4334, 0x1636, 0x199B, 0x88BC}, + {0x8525, 0x4445, 0x4647, 0x8367, 0x88BC, 0x89AC, 0x1503, 0x1636, 0x4334}, + {0x8367, 0x4647, 0x4445, 0x8525, 0x89AC, 0x88BC, 0x2301, 0x4334, 0x1636, 0x199B, 0x289A}, + {0x8367, 0x4647, 0x4445, 0x8525, 0x89AC, 0x88BC, 0x2301, 0x2412, 0x4514, 0x1636, 0x1503, 0x4334}, + {0x8367, 0x4647, 0x4445, 0x8525, 0x89AC, 0x88BC, 0x2412, 0x4514, 0x4334, 0x1636, 0x199B, 0x289A}, + {0x8367, 0x4647, 0x4445, 0x2412, 0x289A, 0x88BC, 0x1636, 0x1503, 0x4334}, + {0x1636, 0x4334, 0x2301, 0x2412, 0x4445, 0x4647, 0x8367, 0x88BC, 0x199B}, + {0x8367, 0x4647, 0x4445, 0x4514, 0x2301, 0x289A, 0x88BC, 0x1636, 0x1503, 0x4334}, + {0x8367, 0x4647, 0x4445, 0x4514, 0x4334, 0x1636, 0x199B, 0x88BC}, + {0x8367, 0x4334, 0x1503, 0x199B, 0x88BC}, + {0x2301, 0x4334, 0x8367, 0x88BC, 0x289A}, + {0x8367, 0x4334, 0x1503, 0x199B, 0x88BC, 0x2412, 0x2301, 0x4514}, + {0x2412, 0x4514, 0x4334, 0x8367, 0x88BC, 0x289A}, + {0x8367, 0x4334, 0x1503, 0x199B, 0x88BC, 0x2412, 0x8525, 0x89AC, 0x289A}, + {0x8525, 0x2412, 0x2301, 0x4334, 0x8367, 0x88BC, 0x89AC}, + {0x8525, 0x4514, 0x2301, 0x289A, 0x89AC, 0x1503, 0x4334, 0x8367, 0x88BC, 0x199B}, + {0x8367, 0x4334, 0x4514, 0x8525, 0x89AC, 0x88BC}, + {0x8367, 0x4334, 0x1503, 0x199B, 0x88BC, 0x8658, 0x8525, 0x4445}, + {0x2301, 0x4334, 0x8367, 0x88BC, 0x289A, 0x8525, 0x8658, 0x4445}, + {0x8367, 0x4334, 0x1503, 0x199B, 0x88BC, 0x2412, 0x2301, 0x4514, 0x8658, 0x8525, 0x4445}, + {0x2412, 0x4514, 0x4334, 0x8367, 0x88BC, 0x289A, 0x8525, 0x8658, 0x4445}, + {0x2412, 0x4445, 0x8658, 0x89AC, 0x289A, 0x8367, 0x4334, 0x1503, 0x199B, 0x88BC}, + {0x8658, 0x4445, 0x2412, 0x2301, 0x4334, 0x8367, 0x88BC, 0x89AC}, + {0x2301, 0x4514, 0x4445, 0x8658, 0x89AC, 0x289A, 0x8367, 0x4334, 0x1503, 0x199B, 0x88BC}, + {0x8658, 0x4445, 0x4514, 0x4334, 0x8367, 0x88BC, 0x89AC}, + {0x1503, 0x4334, 0x8367, 0x8478, 0x8658, 0x89AC, 0x199B}, + {0x8658, 0x8478, 0x8367, 0x4334, 0x2301, 0x289A, 0x89AC}, + {0x1503, 0x4334, 0x8367, 0x8478, 0x8658, 0x89AC, 0x199B, 0x2301, 0x2412, 0x4514}, + {0x2412, 0x4514, 0x4334, 0x8367, 0x8478, 0x8658, 0x89AC, 0x289A}, + {0x2412, 0x8525, 0x8658, 0x8478, 0x8367, 0x4334, 0x1503, 0x199B, 0x289A}, + {0x8367, 0x4334, 0x2301, 0x2412, 0x8525, 0x8658, 0x8478}, + {0x1503, 0x4334, 0x8367, 0x8478, 0x8658, 0x8525, 0x4514, 0x2301, 0x289A, 0x199B}, + {0x8658, 0x8478, 0x8367, 0x4334, 0x4514, 0x8525}, + {0x1503, 0x4334, 0x8367, 0x8478, 0x4445, 0x8525, 0x89AC, 0x199B}, + {0x8525, 0x4445, 0x8478, 0x8367, 0x4334, 0x2301, 0x289A, 0x89AC}, + {0x1503, 0x4334, 0x8367, 0x8478, 0x4445, 0x8525, 0x89AC, 0x199B, 0x2301, 0x2412, 0x4514}, + {0x8525, 0x4445, 0x8478, 0x8367, 0x4334, 0x4514, 0x2412, 0x289A, 0x89AC}, + {0x1503, 0x4334, 0x8367, 0x8478, 0x4445, 0x2412, 0x289A, 0x199B}, + {0x8367, 0x4334, 0x2301, 0x2412, 0x4445, 0x8478}, + {0x1503, 0x4334, 0x8367, 0x8478, 0x4445, 0x4514, 0x2301, 0x289A, 0x199B}, + {0x8367, 0x4334, 0x4514, 0x4445, 0x8478}, + {0x1503, 0x4334, 0x4647, 0x8478, 0x88BC, 0x199B}, + {0x8478, 0x4647, 0x4334, 0x2301, 0x289A, 0x88BC}, + {0x8478, 0x4647, 0x4334, 0x1503, 0x199B, 0x88BC, 0x2412, 0x2301, 0x4514}, + {0x8478, 0x4647, 0x4334, 0x4514, 0x2412, 0x289A, 0x88BC}, + {0x1503, 0x4334, 0x4647, 0x8478, 0x88BC, 0x199B, 0x8525, 0x2412, 0x289A, 0x89AC}, + {0x8478, 0x4647, 0x4334, 0x2301, 0x2412, 0x8525, 0x89AC, 0x88BC}, + {0x1503, 0x4334, 0x4647, 0x8478, 0x88BC, 0x199B, 0x8525, 0x4514, 0x2301, 0x289A, 0x89AC}, + {0x8478, 0x4647, 0x4334, 0x4514, 0x8525, 0x89AC, 0x88BC}, + {0x1503, 0x4334, 0x4647, 0x8478, 0x88BC, 0x199B, 0x8525, 0x8658, 0x4445}, + {0x8478, 0x4647, 0x4334, 0x2301, 0x289A, 0x88BC, 0x8658, 0x8525, 0x4445}, + {0x1503, 0x4334, 0x4647, 0x8478, 0x88BC, 0x199B, 0x8525, 0x8658, 0x4445, 0x2301, 0x2412, 0x4514}, + {0x2412, 0x4514, 0x4334, 0x4647, 0x8478, 0x88BC, 0x289A, 0x8525, 0x8658, 0x4445}, + {0x8478, 0x4647, 0x4334, 0x1503, 0x199B, 0x88BC, 0x2412, 0x4445, 0x8658, 0x89AC, 0x289A}, + {0x8658, 0x4445, 0x2412, 0x2301, 0x4334, 0x4647, 0x8478, 0x88BC, 0x89AC}, + {0x8658, 0x4445, 0x4514, 0x2301, 0x289A, 0x89AC, 0x1503, 0x4334, 0x4647, 0x8478, 0x88BC, 0x199B}, + {0x8658, 0x4445, 0x4514, 0x4334, 0x4647, 0x8478, 0x88BC, 0x89AC}, + {0x1503, 0x4334, 0x4647, 0x8658, 0x89AC, 0x199B}, + {0x8658, 0x4647, 0x4334, 0x2301, 0x289A, 0x89AC}, + {0x1503, 0x4334, 0x4647, 0x8658, 0x89AC, 0x199B, 0x2301, 0x2412, 0x4514}, + {0x2412, 0x4514, 0x4334, 0x4647, 0x8658, 0x89AC, 0x289A}, + {0x1503, 0x4334, 0x4647, 0x8658, 0x8525, 0x2412, 0x289A, 0x199B}, + {0x2412, 0x8525, 0x8658, 0x4647, 0x4334, 0x2301}, + {0x2301, 0x4514, 0x8525, 0x8658, 0x4647, 0x4334, 0x1503, 0x199B, 0x289A}, + {0x8658, 0x4647, 0x4334, 0x4514, 0x8525}, + {0x8525, 0x4445, 0x4647, 0x4334, 0x1503, 0x199B, 0x89AC}, + {0x8525, 0x4445, 0x4647, 0x4334, 0x2301, 0x289A, 0x89AC}, + {0x1503, 0x4334, 0x4647, 0x4445, 0x8525, 0x89AC, 0x199B, 0x2301, 0x2412, 0x4514}, + {0x2412, 0x4514, 0x4334, 0x4647, 0x4445, 0x8525, 0x89AC, 0x289A}, + {0x1503, 0x4334, 0x4647, 0x4445, 0x2412, 0x289A, 0x199B}, + {0x2412, 0x4445, 0x4647, 0x4334, 0x2301}, + {0x1503, 0x4334, 0x4647, 0x4445, 0x4514, 0x2301, 0x289A, 0x199B}, + {0x4514, 0x4445, 0x4647, 0x4334}, + {0x4514, 0x4445, 0x4647, 0x4334}, + {0x2301, 0x1503, 0x199B, 0x289A, 0x4334, 0x4514, 0x4445, 0x4647}, + {0x2412, 0x4445, 0x4647, 0x4334, 0x2301}, + {0x1503, 0x4334, 0x4647, 0x4445, 0x2412, 0x289A, 0x199B}, + {0x8525, 0x2412, 0x289A, 0x89AC, 0x4514, 0x4445, 0x4647, 0x4334}, + {0x8525, 0x2412, 0x2301, 0x1503, 0x199B, 0x89AC, 0x4514, 0x4445, 0x4647, 0x4334}, + {0x8525, 0x4445, 0x4647, 0x4334, 0x2301, 0x289A, 0x89AC}, + {0x8525, 0x4445, 0x4647, 0x4334, 0x1503, 0x199B, 0x89AC}, + {0x8658, 0x4647, 0x4334, 0x4514, 0x8525}, + {0x1503, 0x2301, 0x289A, 0x199B, 0x8525, 0x4514, 0x4334, 0x4647, 0x8658}, + {0x2412, 0x8525, 0x8658, 0x4647, 0x4334, 0x2301}, + {0x1503, 0x4334, 0x4647, 0x8658, 0x8525, 0x2412, 0x289A, 0x199B}, + {0x2412, 0x4514, 0x4334, 0x4647, 0x8658, 0x89AC, 0x289A}, + {0x8658, 0x4647, 0x4334, 0x4514, 0x2412, 0x2301, 0x1503, 0x199B, 0x89AC}, + {0x8658, 0x4647, 0x4334, 0x2301, 0x289A, 0x89AC}, + {0x1503, 0x4334, 0x4647, 0x8658, 0x89AC, 0x199B}, + {0x8478, 0x8658, 0x89AC, 0x88BC, 0x4445, 0x4647, 0x4334, 0x4514}, + {0x2301, 0x1503, 0x199B, 0x289A, 0x8478, 0x8658, 0x89AC, 0x88BC, 0x4334, 0x4514, 0x4445, 0x4647}, + {0x8478, 0x8658, 0x89AC, 0x88BC, 0x2412, 0x4445, 0x4647, 0x4334, 0x2301}, + {0x1503, 0x4334, 0x4647, 0x4445, 0x2412, 0x289A, 0x199B, 0x8658, 0x8478, 0x88BC, 0x89AC}, + {0x8478, 0x8658, 0x8525, 0x2412, 0x289A, 0x88BC, 0x4445, 0x4647, 0x4334, 0x4514}, + {0x8478, 0x8658, 0x8525, 0x2412, 0x2301, 0x1503, 0x199B, 0x88BC, 0x4514, 0x4445, 0x4647, 0x4334}, + {0x2301, 0x4334, 0x4647, 0x4445, 0x8525, 0x8658, 0x8478, 0x88BC, 0x289A}, + {0x8478, 0x8658, 0x8525, 0x4445, 0x4647, 0x4334, 0x1503, 0x199B, 0x88BC}, + {0x8478, 0x4647, 0x4334, 0x4514, 0x8525, 0x89AC, 0x88BC}, + {0x8478, 0x4647, 0x4334, 0x4514, 0x8525, 0x89AC, 0x88BC, 0x2301, 0x1503, 0x199B, 0x289A}, + {0x8478, 0x4647, 0x4334, 0x2301, 0x2412, 0x8525, 0x89AC, 0x88BC}, + {0x8478, 0x4647, 0x4334, 0x1503, 0x2412, 0x8525, 0x199B, 0x289A, 0x89AC, 0x88BC}, + {0x8478, 0x4647, 0x4334, 0x4514, 0x2412, 0x289A, 0x88BC}, + {0x1503, 0x2301, 0x2412, 0x4514, 0x4334, 0x4647, 0x8478, 0x88BC, 0x199B}, + {0x8478, 0x4647, 0x4334, 0x2301, 0x289A, 0x88BC}, + {0x1503, 0x4334, 0x4647, 0x8478, 0x88BC, 0x199B}, + {0x8367, 0x4334, 0x4514, 0x4445, 0x8478}, + {0x2301, 0x1503, 0x199B, 0x289A, 0x8367, 0x4334, 0x4514, 0x4445, 0x8478}, + {0x8367, 0x4334, 0x2301, 0x2412, 0x4445, 0x8478}, + {0x1503, 0x4334, 0x8367, 0x8478, 0x4445, 0x2412, 0x289A, 0x199B}, + {0x2412, 0x8525, 0x89AC, 0x289A, 0x8478, 0x4445, 0x4514, 0x4334, 0x8367}, + {0x8525, 0x2412, 0x2301, 0x1503, 0x199B, 0x89AC, 0x8367, 0x4334, 0x4514, 0x4445, 0x8478}, + {0x8525, 0x4445, 0x8478, 0x8367, 0x4334, 0x2301, 0x289A, 0x89AC}, + {0x1503, 0x4334, 0x8367, 0x8478, 0x4445, 0x8525, 0x89AC, 0x199B}, + {0x8658, 0x8478, 0x8367, 0x4334, 0x4514, 0x8525}, + {0x2301, 0x1503, 0x199B, 0x289A, 0x8367, 0x4334, 0x4514, 0x8525, 0x8658, 0x8478}, + {0x8367, 0x4334, 0x2301, 0x2412, 0x8525, 0x8658, 0x8478}, + {0x2412, 0x8525, 0x8658, 0x8478, 0x8367, 0x4334, 0x1503, 0x199B, 0x289A}, + {0x2412, 0x4514, 0x4334, 0x8367, 0x8478, 0x8658, 0x89AC, 0x289A}, + {0x8658, 0x8478, 0x8367, 0x4334, 0x4514, 0x2412, 0x2301, 0x1503, 0x199B, 0x89AC}, + {0x8658, 0x8478, 0x8367, 0x4334, 0x2301, 0x289A, 0x89AC}, + {0x1503, 0x4334, 0x8367, 0x8478, 0x8658, 0x89AC, 0x199B}, + {0x8658, 0x4445, 0x4514, 0x4334, 0x8367, 0x88BC, 0x89AC}, + {0x8658, 0x4445, 0x4514, 0x4334, 0x8367, 0x88BC, 0x89AC, 0x1503, 0x2301, 0x289A, 0x199B}, + {0x8658, 0x4445, 0x2412, 0x2301, 0x4334, 0x8367, 0x88BC, 0x89AC}, + {0x8658, 0x4445, 0x2412, 0x1503, 0x4334, 0x8367, 0x289A, 0x199B, 0x88BC, 0x89AC}, + {0x8367, 0x4334, 0x4514, 0x4445, 0x8658, 0x8525, 0x2412, 0x289A, 0x88BC}, + {0x1503, 0x2301, 0x2412, 0x8525, 0x8658, 0x4445, 0x4514, 0x4334, 0x8367, 0x88BC, 0x199B}, + {0x2301, 0x4334, 0x8367, 0x88BC, 0x289A, 0x8525, 0x8658, 0x4445}, + {0x8367, 0x4334, 0x1503, 0x199B, 0x88BC, 0x8658, 0x8525, 0x4445}, + {0x8367, 0x4334, 0x4514, 0x8525, 0x89AC, 0x88BC}, + {0x8367, 0x4334, 0x4514, 0x8525, 0x89AC, 0x88BC, 0x2301, 0x1503, 0x199B, 0x289A}, + {0x8525, 0x2412, 0x2301, 0x4334, 0x8367, 0x88BC, 0x89AC}, + {0x1503, 0x4334, 0x8367, 0x8525, 0x2412, 0x88BC, 0x89AC, 0x289A, 0x199B}, + {0x2412, 0x4514, 0x4334, 0x8367, 0x88BC, 0x289A}, + {0x1503, 0x2301, 0x2412, 0x4514, 0x4334, 0x8367, 0x88BC, 0x199B}, + {0x2301, 0x4334, 0x8367, 0x88BC, 0x289A}, + {0x8367, 0x4334, 0x1503, 0x199B, 0x88BC}, + {0x1636, 0x8367, 0x88BC, 0x199B, 0x4647, 0x4334, 0x4514, 0x4445}, + {0x2301, 0x1503, 0x1636, 0x8367, 0x88BC, 0x289A, 0x4334, 0x4514, 0x4445, 0x4647}, + {0x8367, 0x1636, 0x199B, 0x88BC, 0x2301, 0x4334, 0x4647, 0x4445, 0x2412}, + {0x2412, 0x4445, 0x4647, 0x4334, 0x1503, 0x1636, 0x8367, 0x88BC, 0x289A}, + {0x8525, 0x2412, 0x289A, 0x89AC, 0x1636, 0x8367, 0x88BC, 0x199B, 0x4514, 0x4445, 0x4647, 0x4334}, + {0x8525, 0x2412, 0x2301, 0x1503, 0x1636, 0x8367, 0x88BC, 0x89AC, 0x4334, 0x4514, 0x4445, 0x4647}, + {0x8525, 0x4445, 0x4647, 0x4334, 0x2301, 0x289A, 0x89AC, 0x1636, 0x8367, 0x88BC, 0x199B}, + {0x8367, 0x1636, 0x1503, 0x4334, 0x4647, 0x4445, 0x8525, 0x89AC, 0x88BC}, + {0x1636, 0x8367, 0x88BC, 0x199B, 0x8658, 0x4647, 0x4334, 0x4514, 0x8525}, + {0x2301, 0x1503, 0x1636, 0x8367, 0x88BC, 0x289A, 0x8658, 0x4647, 0x4334, 0x4514, 0x8525}, + {0x1636, 0x8367, 0x88BC, 0x199B, 0x8658, 0x4647, 0x4334, 0x2301, 0x2412, 0x8525}, + {0x2412, 0x8525, 0x8658, 0x4647, 0x4334, 0x1503, 0x1636, 0x8367, 0x88BC, 0x289A}, + {0x2412, 0x4514, 0x4334, 0x4647, 0x8658, 0x89AC, 0x289A, 0x8367, 0x1636, 0x199B, 0x88BC}, + {0x8367, 0x1636, 0x1503, 0x2301, 0x2412, 0x4514, 0x4334, 0x4647, 0x8658, 0x89AC, 0x88BC}, + {0x8658, 0x4647, 0x4334, 0x2301, 0x289A, 0x89AC, 0x1636, 0x8367, 0x88BC, 0x199B}, + {0x8367, 0x1636, 0x1503, 0x4334, 0x4647, 0x8658, 0x89AC, 0x88BC}, + {0x1636, 0x8367, 0x8478, 0x8658, 0x89AC, 0x199B, 0x4647, 0x4334, 0x4514, 0x4445}, + {0x2301, 0x1503, 0x1636, 0x8367, 0x8478, 0x8658, 0x89AC, 0x289A, 0x4647, 0x4334, 0x4514, 0x4445}, + {0x1636, 0x8367, 0x8478, 0x8658, 0x89AC, 0x199B, 0x2412, 0x4445, 0x4647, 0x4334, 0x2301}, + {0x8658, 0x8478, 0x8367, 0x1636, 0x1503, 0x4334, 0x4647, 0x4445, 0x2412, 0x289A, 0x89AC}, + {0x1636, 0x8367, 0x8478, 0x8658, 0x8525, 0x2412, 0x289A, 0x199B, 0x4445, 0x4647, 0x4334, 0x4514}, + {0x2301, 0x1503, 0x1636, 0x8367, 0x8478, 0x8658, 0x8525, 0x2412, 0x4334, 0x4514, 0x4445, 0x4647}, + {0x1636, 0x8367, 0x8478, 0x8658, 0x8525, 0x4445, 0x4647, 0x4334, 0x2301, 0x289A, 0x199B}, + {0x1503, 0x1636, 0x8367, 0x8478, 0x8658, 0x8525, 0x4445, 0x4647, 0x4334}, + {0x8525, 0x4514, 0x4334, 0x4647, 0x8478, 0x8367, 0x1636, 0x199B, 0x89AC}, + {0x2301, 0x1503, 0x1636, 0x8367, 0x8478, 0x4647, 0x4334, 0x4514, 0x8525, 0x89AC, 0x289A}, + {0x8525, 0x2412, 0x2301, 0x4334, 0x4647, 0x8478, 0x8367, 0x1636, 0x199B, 0x89AC}, + {0x2412, 0x8525, 0x89AC, 0x289A, 0x1503, 0x1636, 0x8367, 0x8478, 0x4647, 0x4334}, + {0x1636, 0x8367, 0x8478, 0x4647, 0x4334, 0x4514, 0x2412, 0x289A, 0x199B}, + {0x2412, 0x2301, 0x1503, 0x1636, 0x8367, 0x8478, 0x4647, 0x4334, 0x4514}, + {0x1636, 0x8367, 0x8478, 0x4647, 0x4334, 0x2301, 0x289A, 0x199B}, + {0x1636, 0x8367, 0x8478, 0x4647, 0x4334, 0x1503}, + {0x1636, 0x4334, 0x4514, 0x4445, 0x8478, 0x88BC, 0x199B}, + {0x8478, 0x4445, 0x4514, 0x4334, 0x1636, 0x1503, 0x2301, 0x289A, 0x88BC}, + {0x1636, 0x4334, 0x2301, 0x2412, 0x4445, 0x8478, 0x88BC, 0x199B}, + {0x8478, 0x4445, 0x2412, 0x289A, 0x88BC, 0x1636, 0x1503, 0x4334}, + {0x1636, 0x4334, 0x4514, 0x4445, 0x8478, 0x88BC, 0x199B, 0x8525, 0x2412, 0x289A, 0x89AC}, + {0x8525, 0x2412, 0x2301, 0x1503, 0x1636, 0x4334, 0x4514, 0x4445, 0x8478, 0x88BC, 0x89AC}, + {0x1636, 0x4334, 0x2301, 0x8525, 0x4445, 0x8478, 0x289A, 0x89AC, 0x88BC, 0x199B}, + {0x8478, 0x4445, 0x8525, 0x89AC, 0x88BC, 0x1636, 0x1503, 0x4334}, + {0x1636, 0x4334, 0x4514, 0x8525, 0x8658, 0x8478, 0x88BC, 0x199B}, + {0x8478, 0x8658, 0x8525, 0x4514, 0x4334, 0x1636, 0x1503, 0x2301, 0x289A, 0x88BC}, + {0x8478, 0x8658, 0x8525, 0x2412, 0x2301, 0x4334, 0x1636, 0x199B, 0x88BC}, + {0x8478, 0x8658, 0x8525, 0x2412, 0x289A, 0x88BC, 0x1636, 0x1503, 0x4334}, + {0x1636, 0x4334, 0x4514, 0x2412, 0x8658, 0x8478, 0x289A, 0x89AC, 0x88BC, 0x199B}, + {0x8658, 0x8478, 0x88BC, 0x89AC, 0x2412, 0x2301, 0x1503, 0x1636, 0x4334, 0x4514}, + {0x1636, 0x4334, 0x2301, 0x8658, 0x8478, 0x289A, 0x89AC, 0x88BC, 0x199B}, + {0x8658, 0x8478, 0x88BC, 0x89AC, 0x1503, 0x1636, 0x4334}, + {0x1636, 0x4334, 0x4514, 0x4445, 0x8658, 0x89AC, 0x199B}, + {0x2301, 0x1503, 0x1636, 0x4334, 0x4514, 0x4445, 0x8658, 0x89AC, 0x289A}, + {0x8658, 0x4445, 0x2412, 0x2301, 0x4334, 0x1636, 0x199B, 0x89AC}, + {0x2412, 0x4445, 0x8658, 0x89AC, 0x289A, 0x1503, 0x1636, 0x4334}, + {0x2412, 0x8525, 0x8658, 0x4445, 0x4514, 0x4334, 0x1636, 0x199B, 0x289A}, + {0x8658, 0x8525, 0x2412, 0x2301, 0x1503, 0x1636, 0x4334, 0x4514, 0x4445}, + {0x2301, 0x4334, 0x1636, 0x199B, 0x289A, 0x8525, 0x8658, 0x4445}, + {0x1636, 0x1503, 0x4334, 0x8525, 0x8658, 0x4445}, + {0x1636, 0x4334, 0x4514, 0x8525, 0x89AC, 0x199B}, + {0x2301, 0x1503, 0x1636, 0x4334, 0x4514, 0x8525, 0x89AC, 0x289A}, + {0x1636, 0x4334, 0x2301, 0x2412, 0x8525, 0x89AC, 0x199B}, + {0x8525, 0x2412, 0x289A, 0x89AC, 0x1636, 0x1503, 0x4334}, + {0x2412, 0x4514, 0x4334, 0x1636, 0x199B, 0x289A}, + {0x2301, 0x1503, 0x1636, 0x4334, 0x4514, 0x2412}, + {0x2301, 0x4334, 0x1636, 0x199B, 0x289A}, + {0x1636, 0x1503, 0x4334}, + {0x1503, 0x4514, 0x4445, 0x4647, 0x1636}, + {0x2301, 0x4514, 0x4445, 0x4647, 0x1636, 0x199B, 0x289A}, + {0x1503, 0x2301, 0x2412, 0x4445, 0x4647, 0x1636}, + {0x2412, 0x4445, 0x4647, 0x1636, 0x199B, 0x289A}, + {0x8525, 0x2412, 0x289A, 0x89AC, 0x1503, 0x4514, 0x4445, 0x4647, 0x1636}, + {0x1636, 0x4647, 0x4445, 0x4514, 0x2301, 0x2412, 0x8525, 0x89AC, 0x199B}, + {0x8525, 0x4445, 0x4647, 0x1636, 0x1503, 0x2301, 0x289A, 0x89AC}, + {0x8525, 0x4445, 0x4647, 0x1636, 0x199B, 0x89AC}, + {0x1503, 0x4514, 0x8525, 0x8658, 0x4647, 0x1636}, + {0x2301, 0x4514, 0x8525, 0x8658, 0x4647, 0x1636, 0x199B, 0x289A}, + {0x8658, 0x4647, 0x1636, 0x1503, 0x2301, 0x2412, 0x8525}, + {0x2412, 0x8525, 0x8658, 0x4647, 0x1636, 0x199B, 0x289A}, + {0x2412, 0x4514, 0x1503, 0x1636, 0x4647, 0x8658, 0x89AC, 0x289A}, + {0x1636, 0x4647, 0x8658, 0x89AC, 0x199B, 0x2301, 0x2412, 0x4514}, + {0x2301, 0x1503, 0x1636, 0x4647, 0x8658, 0x89AC, 0x289A}, + {0x1636, 0x4647, 0x8658, 0x89AC, 0x199B}, + {0x8658, 0x8478, 0x88BC, 0x89AC, 0x1636, 0x4647, 0x4445, 0x4514, 0x1503}, + {0x2301, 0x4514, 0x4445, 0x4647, 0x1636, 0x199B, 0x289A, 0x8478, 0x8658, 0x89AC, 0x88BC}, + {0x8478, 0x8658, 0x89AC, 0x88BC, 0x2412, 0x4445, 0x4647, 0x1636, 0x1503, 0x2301}, + {0x2412, 0x4445, 0x4647, 0x1636, 0x199B, 0x289A, 0x8478, 0x8658, 0x89AC, 0x88BC}, + {0x8478, 0x8658, 0x8525, 0x2412, 0x289A, 0x88BC, 0x1503, 0x4514, 0x4445, 0x4647, 0x1636}, + {0x8478, 0x8658, 0x8525, 0x2412, 0x2301, 0x4514, 0x4445, 0x4647, 0x1636, 0x199B, 0x88BC}, + {0x2301, 0x1503, 0x1636, 0x4647, 0x4445, 0x8525, 0x8658, 0x8478, 0x88BC, 0x289A}, + {0x8478, 0x8658, 0x8525, 0x4445, 0x4647, 0x1636, 0x199B, 0x88BC}, + {0x8478, 0x4647, 0x1636, 0x1503, 0x4514, 0x8525, 0x89AC, 0x88BC}, + {0x2301, 0x4514, 0x8525, 0x8478, 0x4647, 0x1636, 0x89AC, 0x88BC, 0x199B, 0x289A}, + {0x8525, 0x2412, 0x2301, 0x1503, 0x1636, 0x4647, 0x8478, 0x88BC, 0x89AC}, + {0x8478, 0x4647, 0x1636, 0x2412, 0x8525, 0x199B, 0x289A, 0x89AC, 0x88BC}, + {0x2412, 0x4514, 0x1503, 0x1636, 0x4647, 0x8478, 0x88BC, 0x289A}, + {0x1636, 0x4647, 0x8478, 0x88BC, 0x199B, 0x2301, 0x2412, 0x4514}, + {0x8478, 0x4647, 0x1636, 0x1503, 0x2301, 0x289A, 0x88BC}, + {0x1636, 0x4647, 0x8478, 0x88BC, 0x199B}, + {0x8367, 0x1636, 0x1503, 0x4514, 0x4445, 0x8478}, + {0x2301, 0x4514, 0x4445, 0x8478, 0x8367, 0x1636, 0x199B, 0x289A}, + {0x2412, 0x4445, 0x8478, 0x8367, 0x1636, 0x1503, 0x2301}, + {0x1636, 0x8367, 0x8478, 0x4445, 0x2412, 0x289A, 0x199B}, + {0x8525, 0x2412, 0x289A, 0x89AC, 0x1503, 0x4514, 0x4445, 0x8478, 0x8367, 0x1636}, + {0x1636, 0x8367, 0x8478, 0x4445, 0x4514, 0x2301, 0x2412, 0x8525, 0x89AC, 0x199B}, + {0x2301, 0x1503, 0x1636, 0x8367, 0x8478, 0x4445, 0x8525, 0x89AC, 0x289A}, + {0x8525, 0x4445, 0x8478, 0x8367, 0x1636, 0x199B, 0x89AC}, + {0x1503, 0x4514, 0x8525, 0x8658, 0x8478, 0x8367, 0x1636}, + {0x1636, 0x8367, 0x8478, 0x8658, 0x8525, 0x4514, 0x2301, 0x289A, 0x199B}, + {0x1636, 0x8367, 0x8478, 0x8658, 0x8525, 0x2412, 0x2301, 0x1503}, + {0x1636, 0x8367, 0x8478, 0x8658, 0x8525, 0x2412, 0x289A, 0x199B}, + {0x8658, 0x8478, 0x8367, 0x1636, 0x1503, 0x4514, 0x2412, 0x289A, 0x89AC}, + {0x1636, 0x8367, 0x8478, 0x8658, 0x89AC, 0x199B, 0x2301, 0x2412, 0x4514}, + {0x2301, 0x1503, 0x1636, 0x8367, 0x8478, 0x8658, 0x89AC, 0x289A}, + {0x1636, 0x8367, 0x8478, 0x8658, 0x89AC, 0x199B}, + {0x8658, 0x4445, 0x4514, 0x1503, 0x1636, 0x8367, 0x88BC, 0x89AC}, + {0x2301, 0x4514, 0x4445, 0x8658, 0x8367, 0x1636, 0x89AC, 0x88BC, 0x199B, 0x289A}, + {0x8367, 0x1636, 0x1503, 0x2301, 0x2412, 0x4445, 0x8658, 0x89AC, 0x88BC}, + {0x8658, 0x4445, 0x2412, 0x1636, 0x8367, 0x289A, 0x199B, 0x88BC, 0x89AC}, + {0x8367, 0x1636, 0x1503, 0x4514, 0x4445, 0x8658, 0x8525, 0x2412, 0x289A, 0x88BC}, + {0x8367, 0x1636, 0x199B, 0x88BC, 0x8658, 0x8525, 0x2412, 0x2301, 0x4514, 0x4445}, + {0x2301, 0x1503, 0x1636, 0x8367, 0x88BC, 0x289A, 0x8525, 0x8658, 0x4445}, + {0x1636, 0x8367, 0x88BC, 0x199B, 0x8525, 0x8658, 0x4445}, + {0x8367, 0x1636, 0x1503, 0x4514, 0x8525, 0x89AC, 0x88BC}, + {0x2301, 0x4514, 0x8525, 0x8367, 0x1636, 0x89AC, 0x88BC, 0x199B, 0x289A}, + {0x8525, 0x2412, 0x2301, 0x1503, 0x1636, 0x8367, 0x88BC, 0x89AC}, + {0x2412, 0x8525, 0x8367, 0x1636, 0x89AC, 0x88BC, 0x199B, 0x289A}, + {0x2412, 0x4514, 0x1503, 0x1636, 0x8367, 0x88BC, 0x289A}, + {0x8367, 0x1636, 0x199B, 0x88BC, 0x2412, 0x2301, 0x4514}, + {0x2301, 0x1503, 0x1636, 0x8367, 0x88BC, 0x289A}, + {0x1636, 0x8367, 0x88BC, 0x199B}, + {0x8367, 0x4647, 0x4445, 0x4514, 0x1503, 0x199B, 0x88BC}, + {0x2301, 0x4514, 0x4445, 0x4647, 0x8367, 0x88BC, 0x289A}, + {0x8367, 0x4647, 0x4445, 0x2412, 0x2301, 0x1503, 0x199B, 0x88BC}, + {0x8367, 0x4647, 0x4445, 0x2412, 0x289A, 0x88BC}, + {0x8367, 0x4647, 0x4445, 0x4514, 0x1503, 0x199B, 0x88BC, 0x2412, 0x8525, 0x89AC, 0x289A}, + {0x8525, 0x2412, 0x2301, 0x4514, 0x4445, 0x4647, 0x8367, 0x88BC, 0x89AC}, + {0x8525, 0x4445, 0x4647, 0x8367, 0x1503, 0x2301, 0x88BC, 0x199B, 0x289A, 0x89AC}, + {0x8367, 0x4647, 0x4445, 0x8525, 0x89AC, 0x88BC}, + {0x8367, 0x4647, 0x8658, 0x8525, 0x4514, 0x1503, 0x199B, 0x88BC}, + {0x8367, 0x4647, 0x8658, 0x8525, 0x4514, 0x2301, 0x289A, 0x88BC}, + {0x1503, 0x2301, 0x2412, 0x8525, 0x8658, 0x4647, 0x8367, 0x88BC, 0x199B}, + {0x8367, 0x4647, 0x8658, 0x8525, 0x2412, 0x289A, 0x88BC}, + {0x2412, 0x4514, 0x1503, 0x8367, 0x4647, 0x8658, 0x199B, 0x88BC, 0x89AC, 0x289A}, + {0x8658, 0x4647, 0x8367, 0x88BC, 0x89AC, 0x2412, 0x2301, 0x4514}, + {0x8367, 0x4647, 0x8658, 0x2301, 0x1503, 0x89AC, 0x289A, 0x199B, 0x88BC}, + {0x8658, 0x4647, 0x8367, 0x88BC, 0x89AC}, + {0x1503, 0x4514, 0x4445, 0x4647, 0x8367, 0x8478, 0x8658, 0x89AC, 0x199B}, + {0x8658, 0x8478, 0x8367, 0x4647, 0x4445, 0x4514, 0x2301, 0x289A, 0x89AC}, + {0x1503, 0x2301, 0x2412, 0x4445, 0x4647, 0x8367, 0x8478, 0x8658, 0x89AC, 0x199B}, + {0x8658, 0x8478, 0x8367, 0x4647, 0x4445, 0x2412, 0x289A, 0x89AC}, + {0x2412, 0x8525, 0x8658, 0x8478, 0x8367, 0x4647, 0x4445, 0x4514, 0x1503, 0x199B, 0x289A}, + {0x8367, 0x8478, 0x8658, 0x8525, 0x2412, 0x2301, 0x4514, 0x4445, 0x4647}, + {0x1503, 0x2301, 0x289A, 0x199B, 0x8367, 0x8478, 0x8658, 0x8525, 0x4445, 0x4647}, + {0x8478, 0x8658, 0x8525, 0x4445, 0x4647, 0x8367}, + {0x8525, 0x4514, 0x1503, 0x199B, 0x89AC, 0x8478, 0x8367, 0x4647}, + {0x8525, 0x4514, 0x2301, 0x289A, 0x89AC, 0x8478, 0x8367, 0x4647}, + {0x8525, 0x2412, 0x2301, 0x1503, 0x199B, 0x89AC, 0x8478, 0x8367, 0x4647}, + {0x2412, 0x8525, 0x89AC, 0x289A, 0x8367, 0x8478, 0x4647}, + {0x1503, 0x4514, 0x2412, 0x289A, 0x199B, 0x8367, 0x8478, 0x4647}, + {0x2301, 0x2412, 0x4514, 0x8478, 0x8367, 0x4647}, + {0x2301, 0x1503, 0x199B, 0x289A, 0x8478, 0x8367, 0x4647}, + {0x8478, 0x8367, 0x4647}, + {0x1503, 0x4514, 0x4445, 0x8478, 0x88BC, 0x199B}, + {0x2301, 0x4514, 0x4445, 0x8478, 0x88BC, 0x289A}, + {0x1503, 0x2301, 0x2412, 0x4445, 0x8478, 0x88BC, 0x199B}, + {0x8478, 0x4445, 0x2412, 0x289A, 0x88BC}, + {0x1503, 0x4514, 0x4445, 0x8478, 0x88BC, 0x199B, 0x8525, 0x2412, 0x289A, 0x89AC}, + {0x8525, 0x2412, 0x2301, 0x4514, 0x4445, 0x8478, 0x88BC, 0x89AC}, + {0x8525, 0x4445, 0x8478, 0x1503, 0x2301, 0x88BC, 0x199B, 0x289A, 0x89AC}, + {0x8478, 0x4445, 0x8525, 0x89AC, 0x88BC}, + {0x8478, 0x8658, 0x8525, 0x4514, 0x1503, 0x199B, 0x88BC}, + {0x2301, 0x4514, 0x8525, 0x8658, 0x8478, 0x88BC, 0x289A}, + {0x8478, 0x8658, 0x8525, 0x2412, 0x2301, 0x1503, 0x199B, 0x88BC}, + {0x8478, 0x8658, 0x8525, 0x2412, 0x289A, 0x88BC}, + {0x2412, 0x4514, 0x1503, 0x8478, 0x8658, 0x199B, 0x88BC, 0x89AC, 0x289A}, + {0x8478, 0x8658, 0x89AC, 0x88BC, 0x2301, 0x2412, 0x4514}, + {0x1503, 0x2301, 0x8658, 0x8478, 0x289A, 0x89AC, 0x88BC, 0x199B}, + {0x8478, 0x8658, 0x89AC, 0x88BC}, + {0x8658, 0x4445, 0x4514, 0x1503, 0x199B, 0x89AC}, + {0x8658, 0x4445, 0x4514, 0x2301, 0x289A, 0x89AC}, + {0x8658, 0x4445, 0x2412, 0x2301, 0x1503, 0x199B, 0x89AC}, + {0x2412, 0x4445, 0x8658, 0x89AC, 0x289A}, + {0x2412, 0x8525, 0x8658, 0x4445, 0x4514, 0x1503, 0x199B, 0x289A}, + {0x8525, 0x2412, 0x2301, 0x4514, 0x4445, 0x8658}, + {0x1503, 0x2301, 0x289A, 0x199B, 0x8658, 0x8525, 0x4445}, + {0x8525, 0x8658, 0x4445}, + {0x8525, 0x4514, 0x1503, 0x199B, 0x89AC}, + {0x8525, 0x4514, 0x2301, 0x289A, 0x89AC}, + {0x8525, 0x2412, 0x2301, 0x1503, 0x199B, 0x89AC}, + {0x8525, 0x2412, 0x289A, 0x89AC}, + {0x1503, 0x4514, 0x2412, 0x289A, 0x199B}, + {0x2301, 0x2412, 0x4514}, + {0x2301, 0x1503, 0x199B, 0x289A}, + {} + }; + + // The RegularCellData structure holds information about the triangulation + // used for a single equivalence class in the modified Marching Cubes algorithm, + // described in Section 3.2. + + static class RegularCellData { + byte geometryCounts; // High nibble is vertex count, low nibble is triangle count. + byte[] vertexIndex = new byte[15]; // Groups of 3 indexes giving the triangulation. + + protected RegularCellData(byte geometryCounts, byte[] vertexIndex){ + this.geometryCounts = geometryCounts; + for(int i = 0; i < vertexIndex.length; i++){ + this.vertexIndex[i] = vertexIndex[i]; + } + } + + long GetVertexCount(){ + return (geometryCounts >> 4); + } + + long GetTriangleCount(){ + return (geometryCounts & 0x0F); + } + }; + + + // The TransitionCellData structure holds information about the triangulation + // used for a single equivalence class in the Transvoxel Algorithm transition cell, + // described in Section 4.3. + static class TransitionCellData { + long geometryCounts; // High nibble is vertex count, low nibble is triangle count. + byte[] vertexIndex = new byte[36]; // Groups of 3 indexes giving the triangulation. + + protected TransitionCellData(long geometryCounts, byte[] vertexIndex){ + this.geometryCounts = geometryCounts; + this.vertexIndex = vertexIndex; + } + + long GetVertexCount(){ + return (geometryCounts >> 4); + } + + long GetTriangleCount(){ + return (geometryCounts & 0x0F); + } + }; + +} diff --git a/src/main/java/electrosphere/renderer/meshgen/TransvoxelModelGeneration.java b/src/main/java/electrosphere/renderer/meshgen/TransvoxelModelGeneration.java new file mode 100644 index 00000000..6da72f6b --- /dev/null +++ b/src/main/java/electrosphere/renderer/meshgen/TransvoxelModelGeneration.java @@ -0,0 +1,371 @@ +package electrosphere.renderer.meshgen; + +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.joml.Vector3f; +import org.lwjgl.BufferUtils; + +import electrosphere.engine.Globals; +import electrosphere.entity.types.terrain.TerrainChunkData; +import electrosphere.renderer.Material; +import electrosphere.renderer.Mesh; +import electrosphere.renderer.Model; +import electrosphere.renderer.meshgen.TerrainChunkModelGeneration.GridCell; +import electrosphere.renderer.meshgen.TerrainChunkModelGeneration.Triangle; + +/** + * Utility functions for generating transvoxel based meshes + */ +public class TransvoxelModelGeneration { + + // static class Triangle { + // int[] indices = new int[3]; //array of size 3 + + // public Triangle(int index0, int index1, int index2){ + // indices[0] = index0; + // indices[1] = index1; + // indices[2] = index2; + // } + // } + + // static class GridCell { + // Vector3f[] points = new Vector3f[8]; //array of size 8 + // double[] val = new double[8]; //array of size 8 + // public void setValues( + // Vector3f p1, Vector3f p2, Vector3f p3, Vector3f p4, + // Vector3f p5, Vector3f p6, Vector3f p7, Vector3f p8, + // double val1, double val2, double val3, double val4, + // double val5, double val6, double val7, double val8 + // ){ + // points[0] = p1; points[1] = p2; points[2] = p3; points[3] = p4; + // points[4] = p5; points[5] = p6; points[6] = p7; points[7] = p8; + // val[0] = val1; val[1] = val2; val[2] = val3; val[3] = val4; + // val[4] = val5; val[5] = val6; val[6] = val7; val[7] = val8; + // } + // } + + // protected static int polygonize( + // GridCell grid, + // double isolevel, + // List triangles, + // Map vertMap, + // List verts, + // List normals, + // List trianglesSharingVert + // ){ + // int i; + // int ntriang; + // int cubeIndex = 0; + // Vector3f[] vertList = new Vector3f[12]; + + // //get lookup key (index) for edge table + // //edge table tells us which vertices are inside of the surface + // if (grid.val[0] < isolevel) cubeIndex |= 1; + // if (grid.val[1] < isolevel) cubeIndex |= 2; + // if (grid.val[2] < isolevel) cubeIndex |= 4; + // if (grid.val[3] < isolevel) cubeIndex |= 8; + // if (grid.val[4] < isolevel) cubeIndex |= 16; + // if (grid.val[5] < isolevel) cubeIndex |= 32; + // if (grid.val[6] < isolevel) cubeIndex |= 64; + // if (grid.val[7] < isolevel) cubeIndex |= 128; + + // //Cube is entirely in/out of the surface + // if (edgeTable[cubeIndex] == 0) + // return(0); + + // //instead of having all intersections be perfectly at the midpoint, + // //for each edge this code calculates where along the edge to place the vertex + // //this should dramatically smooth the surface + // if ((edgeTable[cubeIndex] & 1) > 0) + // vertList[0] = + // VertexInterp(isolevel,grid.points[0],grid.points[1],grid.val[0],grid.val[1]); + // if ((edgeTable[cubeIndex] & 2) > 0) + // vertList[1] = + // VertexInterp(isolevel,grid.points[1],grid.points[2],grid.val[1],grid.val[2]); + // if ((edgeTable[cubeIndex] & 4) > 0) + // vertList[2] = + // VertexInterp(isolevel,grid.points[2],grid.points[3],grid.val[2],grid.val[3]); + // if ((edgeTable[cubeIndex] & 8) > 0) + // vertList[3] = + // VertexInterp(isolevel,grid.points[3],grid.points[0],grid.val[3],grid.val[0]); + // if ((edgeTable[cubeIndex] & 16) > 0) + // vertList[4] = + // VertexInterp(isolevel,grid.points[4],grid.points[5],grid.val[4],grid.val[5]); + // if ((edgeTable[cubeIndex] & 32) > 0) + // vertList[5] = + // VertexInterp(isolevel,grid.points[5],grid.points[6],grid.val[5],grid.val[6]); + // if ((edgeTable[cubeIndex] & 64) > 0) + // vertList[6] = + // VertexInterp(isolevel,grid.points[6],grid.points[7],grid.val[6],grid.val[7]); + // if ((edgeTable[cubeIndex] & 128) > 0) + // vertList[7] = + // VertexInterp(isolevel,grid.points[7],grid.points[4],grid.val[7],grid.val[4]); + // if ((edgeTable[cubeIndex] & 256) > 0) + // vertList[8] = + // VertexInterp(isolevel,grid.points[0],grid.points[4],grid.val[0],grid.val[4]); + // if ((edgeTable[cubeIndex] & 512) > 0) + // vertList[9] = + // VertexInterp(isolevel,grid.points[1],grid.points[5],grid.val[1],grid.val[5]); + // if ((edgeTable[cubeIndex] & 1024) > 0) + // vertList[10] = + // VertexInterp(isolevel,grid.points[2],grid.points[6],grid.val[2],grid.val[6]); + // if ((edgeTable[cubeIndex] & 2048) > 0) + // vertList[11] = + // VertexInterp(isolevel,grid.points[3],grid.points[7],grid.val[3],grid.val[7]); + + // //Create the triangle + // ntriang = 0; + // for (i=0; triTable[cubeIndex][i]!=-1; i+=3) { + // // + // // Triangles calculation + // // + // //get indices + // Vector3f vert0 = vertList[triTable[cubeIndex][i+0]]; + // Vector3f vert1 = vertList[triTable[cubeIndex][i+1]]; + // Vector3f vert2 = vertList[triTable[cubeIndex][i+2]]; + // int index0 = getVertIndex(vert0,vertMap,verts); + // int index1 = getVertIndex(vert1,vertMap,verts); + // int index2 = getVertIndex(vert2,vertMap,verts); + + // //add 0's to normals until it matches vert count + // while(trianglesSharingVert.size() < verts.size()){ + // trianglesSharingVert.add(0); + // normals.add(new Vector3f()); + // } + + + // //add new triangle + // Triangle newTriangle = new Triangle(index0,index1,index2); + // triangles.add(newTriangle); + // ntriang++; + + + + // // + // // Normals calculation + // // + + + // //calculate normal for new triangle + // Vector3f u = verts.get(index1).sub(verts.get(index0), new Vector3f()); + // Vector3f v = verts.get(index2).sub(verts.get(index1), new Vector3f()); + // Vector3f n = new Vector3f(u.y * v.z - u.z * v.y, u.z * v.x - u.x * v.z, u.x * v.y - u.y * v.x).normalize(); + + + + // //for each vertex, average the new normal with the normals that are already there + // int trianglesSharingIndex0 = trianglesSharingVert.get(index0); + // //calculate proportion of each normal + // float oldProportion = trianglesSharingIndex0 / (float)(trianglesSharingIndex0 + 1); + // float newProportion = 1.0f / (float)(trianglesSharingIndex0 + 1); + // //increment number of triangles sharing vert + // trianglesSharingVert.set(index0, trianglesSharingIndex0 + 1); + + // Vector3f currentNormal = normals.get(index0); + // currentNormal = averageNormals(currentNormal,oldProportion,n,newProportion); + // normals.get(index0).set(currentNormal); + + + + + + // int trianglesSharingIndex1 = trianglesSharingVert.get(index1); + // //calculate proportion of each normal + // oldProportion = trianglesSharingIndex1 / (float)(trianglesSharingIndex1 + 1); + // newProportion = 1.0f / (float)(trianglesSharingIndex1 + 1); + // //increment number of triangles sharing vert + // trianglesSharingVert.set(index1, trianglesSharingIndex1 + 1); + + // currentNormal = normals.get(index1); + // currentNormal = averageNormals(currentNormal,oldProportion,n,newProportion); + // normals.get(index1).set(currentNormal); + + + + + + + + + // int trianglesSharingIndex2 = trianglesSharingVert.get(index2); + // //calculate proportion of each normal + // oldProportion = trianglesSharingIndex2 / (float)(trianglesSharingIndex2 + 1); + // newProportion = 1.0f / (float)(trianglesSharingIndex2 + 1); + // //increment number of triangles sharing vert + // trianglesSharingVert.set(index2, trianglesSharingIndex2 + 1); + + // currentNormal = normals.get(index2); + // currentNormal = averageNormals(currentNormal,oldProportion,n,newProportion); + // normals.get(index2).set(currentNormal); + + // } + + // return(ntriang); + // } + + // //interpolates the location that the edge gets cut based on the magnitudes of the scalars of the vertices at either end of the edge + // static Vector3f VertexInterp(double isolevel, Vector3f p1, Vector3f p2, double valp1, double valp2){ + // double mu; + // float x, y, z; + + // if (Math.abs(isolevel-valp1) < 0.00001) + // return(p1); + // if (Math.abs(isolevel-valp2) < 0.00001) + // return(p2); + // if (Math.abs(valp1-valp2) < 0.00001) + // return(p1); + // mu = (isolevel - valp1) / (valp2 - valp1); + // x = (float)(p1.x + mu * (p2.x - p1.x)); + // y = (float)(p1.y + mu * (p2.y - p1.y)); + // z = (float)(p1.z + mu * (p2.z - p1.z)); + + // return new Vector3f(x,y,z); + // } + + // /** + // * Creates terrain chunk data based on data provided + // * @param terrainGrid the grid of weights to generate off of + // * @param textureGrid the grid of texture indices to generate off of + // * @param neighborLODLevels The lod levels of all neighbors and this cell. Should be 3x3x3 array of lod level values. + // */ + // public static TerrainChunkData generateTerrainChunkData(float[][][] terrainGrid, int[][][] textureGrid, int[][][] neighborLODLevels){ + + // // 5 6 + // // +-------------+ +-----5-------+ ^ Y + // // / | / | / | /| | _ + // // / | / | 4 9 6 10 | /\ Z + // // 4 +-----+-------+ 7 | +-----+7------+ | | / + // // | 1 +-------+-----+ 2 | +-----1-+-----+ | / + // // | / | / 8 0 11 2 | / + // // | / | / | / | / |/ + // // 0 +-------------+ 3 +------3------+ +---------------> X + + // //the current grid cell + // GridCell currentCell = new GridCell(); + // //the list of all triangles + // List triangles = new LinkedList(); + // //the map of vertex to index + // Map vertMap = new HashMap(); + // //the list of all verts + // List verts = new LinkedList(); + // //the list of all normals + // List normals = new LinkedList(); + // //the list of number of triangles that share a vert + // List trianglesSharingVert = new LinkedList(); + // //List of elements in order + // List faceElements = new LinkedList(); + // //List of UVs + // List UVs = new LinkedList(); + + + + // for(int x = 0; x < terrainGrid.length - 1; x++){ + // for(int y = 0; y < terrainGrid[0].length - 1; y++){ + // for(int z = 0; z < terrainGrid[0][0].length - 1; z++){ + // //push the current cell's values into the gridcell + // currentCell.setValues( + // new Vector3f(x+0,y+0,z+0), new Vector3f(x+0,y+0,z+1), new Vector3f(x+1,y+0,z+1), new Vector3f(x+1,y+0,z+0), + // new Vector3f(x+0,y+1,z+0), new Vector3f(x+0,y+1,z+1), new Vector3f(x+1,y+1,z+1), new Vector3f(x+1,y+1,z+0), + // terrainGrid[x+0][y+0][z+0], terrainGrid[x+0][y+0][z+1], terrainGrid[x+1][y+0][z+1], terrainGrid[x+1][y+0][z+0], + // terrainGrid[x+0][y+1][z+0], terrainGrid[x+0][y+1][z+1], terrainGrid[x+1][y+1][z+1], terrainGrid[x+1][y+1][z+0] + // ); + // //polygonize the current gridcell + // polygonize(currentCell, 0, triangles, vertMap, verts, normals, trianglesSharingVert); + // } + // } + // } + + // //all verts in order, flattened as an array of floats instead of vecs + // List vertsFlat = new LinkedList(); + // //all normals in order, flattened as an array of floats instead of vecs + // List normalsFlat = new LinkedList(); + // //all elements of faces in order + // List elementsFlat = new LinkedList(); + + // //flatten verts + normals + // for(Vector3f vert : verts){ + // vertsFlat.add(vert.x); + // vertsFlat.add(vert.y); + // vertsFlat.add(vert.z); + // } + + // for(Vector3f normal : normals){ + // normalsFlat.add(normal.x); + // normalsFlat.add(normal.y); + // normalsFlat.add(normal.z); + // } + + + // for(Triangle triangle : triangles){ + // elementsFlat.add(triangle.indices[0]); + // elementsFlat.add(triangle.indices[1]); + // elementsFlat.add(triangle.indices[2]); + // } + + // float[] temp = new float[3]; + // int i = 0; + // for(Vector3f normal : normals){ + // Vector3f vert = verts.get(i); + + // float absX = Math.abs(normal.x); + // float absY = Math.abs(normal.y); + // float absZ = Math.abs(normal.z); + + // float uvX = vert.z * absX + vert.x * absY + vert.x * absZ; + // float uvY = vert.y * absX + vert.z * absY + vert.y * absZ; + // temp[0] = uvX; + // temp[1] = uvY; + + // // if(absX >= absZ && absX >= absY){ + // // temp[0] = normal.z / 2.0f + 0.5f + vert.z * (absX / (absX + absZ)) + vert.x * (absZ / (absX + absZ)); + // // temp[1] = normal.y / 2.0f + 0.5f + vert.x * (absY / (absX + absY)) + vert.y * (absX / (absX + absY)); + // // } else if(absZ >= absX && absZ >= absY){ + // // temp[0] = normal.x / 2.0f + 0.5f + vert.z * (absX / (absX + absZ)) + vert.x * (absZ / (absX + absZ)); + // // temp[1] = normal.y / 2.0f + 0.5f + vert.z * (absY / (absZ + absY)) + vert.y * (absZ / (absZ + absY)); + // // } else if(absY >= absX && absY >= absZ){ + // // temp[0] = normal.x / 2.0f + 0.5f + vert.y * (absX / (absX + absY)) + vert.x * (absY / (absX + absY)); + // // temp[1] = normal.z / 2.0f + 0.5f + vert.y * (absZ / (absZ + absY)) + vert.z * (absY / (absZ + absY)); + // // } else { + // // temp[0] = vert.x / 1.5f + vert.z / 1.5f; + // // temp[1] = vert.y / 1.5f + vert.z / 1.5f; + // // } + // i++; + // UVs.add(temp[0]); + // UVs.add(temp[1]); + // } + + // //List vertices, List normals, List faceElements, List uvs + // TerrainChunkData rVal = new TerrainChunkData(vertsFlat, normalsFlat, elementsFlat, UVs); + // return rVal; + // } + + // private static String getVertKeyFromPoints(float x, float y, float z){ + // return x + "_" + y + "_" + z; + // } + + // private static int getVertIndex(Vector3f vert, Map vertMap, List verts){ + // int rVal = -1; + // String vertKey = getVertKeyFromPoints(vert.x,vert.y,vert.z); + // if(vertMap.containsKey(vertKey)){ + // return vertMap.get(vertKey); + // } else { + // rVal = verts.size(); + // verts.add(vert); + // vertMap.put(vertKey,rVal); + // return rVal; + // } + // } + + // private static Vector3f averageNormals(Vector3f normal0, float proportion0, Vector3f normal1, float proportion1){ + // Vector3f rVal = new Vector3f(normal0); + // rVal = rVal.mul(proportion0).add(new Vector3f(normal1).mul(proportion1)); + // return rVal; + // } + +} diff --git a/src/main/java/electrosphere/script/ScriptEngine.java b/src/main/java/electrosphere/script/ScriptEngine.java index 8d79f39a..40d731f9 100644 --- a/src/main/java/electrosphere/script/ScriptEngine.java +++ b/src/main/java/electrosphere/script/ScriptEngine.java @@ -27,7 +27,7 @@ public class ScriptEngine { //create context context = Context.newBuilder("js").engine(engine).build(); //read scripts into source map - readScriptsDirectory("/Scripts", FileUtils.getAssetFile("/Scripts")); + readScriptsDirectory("/src/main/sql", FileUtils.getAssetFile("/src/main/sql")); //create bindings // try { // String content = FileUtils.getAssetFileAsString("/Scripts/test.js"); diff --git a/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java b/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java index 77bf4da9..53fa79e9 100644 --- a/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java +++ b/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java @@ -2,8 +2,6 @@ package electrosphere.server.datacell; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Semaphore; @@ -14,11 +12,12 @@ import org.joml.Vector3i; import electrosphere.engine.Globals; import electrosphere.entity.Entity; import electrosphere.entity.EntityUtils; -import electrosphere.entity.Scene; import electrosphere.game.server.world.ServerWorldData; import electrosphere.logger.LoggerInterface; +import electrosphere.net.parser.net.message.TerrainMessage; import electrosphere.net.server.player.Player; import electrosphere.server.datacell.interfaces.DataCellManager; +import electrosphere.server.datacell.interfaces.VoxelCellManager; import electrosphere.server.datacell.physics.PhysicsDataCell; import electrosphere.server.terrain.manager.ServerTerrainManager; import electrosphere.server.terrain.manager.ServerTerrainChunk; @@ -26,7 +25,7 @@ import electrosphere.server.terrain.manager.ServerTerrainChunk; /** * Implementation of DataCellManager that lays out cells in a logical grid (array). Useful for eg 3d terrain gridded world. */ -public class GriddedDataCellManager implements DataCellManager { +public class GriddedDataCellManager implements DataCellManager, VoxelCellManager { //these are going to be the natural ground grid of data cells, but we're going to have more than this Map groundDataCells = new HashMap(); //loaded cells @@ -37,6 +36,8 @@ public class GriddedDataCellManager implements DataCellManager { Realm parent; //Manager for terrain for this particular cell manager ServerTerrainManager serverTerrainManager; + //lock for terrain editing + Semaphore terrainEditLock = new Semaphore(1); /** * Constructor @@ -61,6 +62,7 @@ public class GriddedDataCellManager implements DataCellManager { * @param player The player */ public void addPlayerToRealm(Player player){ + Globals.realmManager.setPlayerRealm(player, parent); int playerSimulationRadius = player.getSimulationRadius(); Vector3i worldPos = player.getWorldPos(); for(int x = worldPos.x - playerSimulationRadius; x < worldPos.x + playerSimulationRadius + 1; x++){ @@ -342,4 +344,56 @@ public class GriddedDataCellManager implements DataCellManager { return rVal; } + @Override + /** + * Gets the weight of a single voxel at a position + * @param worldPosition The position in world coordinates of the chunk to grab data from + * @param voxelPosition The position in voxel coordinates (local/relative to the chunk) to get voxel values from + * @return The weight of the described voxel + */ + public float getVoxelWeightAtLocalPosition(Vector3i worldPosition, Vector3i voxelPosition) { + return serverTerrainManager.getChunk(worldPosition.x, worldPosition.y, worldPosition.z).getWeights()[voxelPosition.x][voxelPosition.y][voxelPosition.z]; + } + + @Override + /** + * Gets the type of a single voxel at a position + * @param worldPosition The position in world coordinates of the chunk to grab data from + * @param voxelPosition The position in voxel coordinates (local/relative to the chunk) to get voxel values from + * @return The type of the described voxel + */ + public int getVoxelTypeAtLocalPosition(Vector3i worldPosition, Vector3i voxelPosition) { + return serverTerrainManager.getChunk(worldPosition.x, worldPosition.y, worldPosition.z).getValues()[voxelPosition.x][voxelPosition.y][voxelPosition.z]; + } + + @Override + /** + * Gets the chunk data at a given world position + * @param worldPosition The position in world coordinates + * @return The ServerTerrainChunk of data at that position, or null if it is out of bounds or otherwise doesn't exist + */ + public ServerTerrainChunk getChunkAtPosition(Vector3i worldPosition) { + return serverTerrainManager.getChunk(worldPosition.x, worldPosition.y, worldPosition.z); + } + + @Override + /** + * Edits a single voxel + * @param worldPosition The world position of the chunk to edit + * @param voxelPosition The voxel position of the voxel to edit + * @param weight The weight to set the voxel to + * @param type The type to set the voxel to + */ + public void editChunk(Vector3i worldPosition, Vector3i voxelPosition, float weight, int type) { + terrainEditLock.acquireUninterruptibly(); + //update terrain + serverTerrainManager.deformTerrainAtLocationToValue(worldPosition, voxelPosition, weight, type); + //broadcast update to terrain + groundDataCells.get(getServerDataCellKey(worldPosition)).broadcastNetworkMessage(TerrainMessage.constructUpdateVoxelMessage( + worldPosition.x, worldPosition.y, worldPosition.z, + voxelPosition.x, voxelPosition.y, voxelPosition.z, + weight, type)); + terrainEditLock.release(); + } + } diff --git a/src/main/java/electrosphere/server/datacell/Realm.java b/src/main/java/electrosphere/server/datacell/Realm.java index e10b0ed1..f9adf5e8 100644 --- a/src/main/java/electrosphere/server/datacell/Realm.java +++ b/src/main/java/electrosphere/server/datacell/Realm.java @@ -1,33 +1,26 @@ package electrosphere.server.datacell; import electrosphere.collision.CollisionEngine; -import electrosphere.collision.CollisionWorldData; import electrosphere.engine.Globals; import electrosphere.engine.Main; import electrosphere.entity.Entity; -import electrosphere.entity.EntityUtils; import electrosphere.entity.Scene; import electrosphere.entity.types.hitbox.HitboxManager; -import electrosphere.game.server.world.ServerWorldData; -import electrosphere.logger.LoggerInterface; import electrosphere.net.parser.net.message.NetworkMessage; -import electrosphere.net.server.Server; -import electrosphere.net.server.player.Player; import electrosphere.server.datacell.interfaces.DataCellManager; -import electrosphere.server.terrain.manager.ServerTerrainManager; -import java.util.LinkedList; -import java.util.List; -import org.joml.Vector3d; -import org.joml.Vector3f; -import org.joml.Vector3i; +import java.util.HashSet; +import java.util.Set; + /** * Manages data cells on the server side */ public class Realm { - List loadedDataCells = new LinkedList(); + //The set containing all data cells loaded into this realm + Set loadedDataCells = new HashSet(); + //this is the cell that all players loading into the game (via connection startup, death, etc) reside in ServerDataCell loadingCell = new ServerDataCell(new Scene()); @@ -91,11 +84,22 @@ public class Realm { cell.broadcastNetworkMessage(message); } + //Used for cleaning server data cells no longer in use from the realm + Set toCleanQueue = new HashSet(); /** * Unloads all chunks that haven't had players in them for a set amount of time */ public void unloadPlayerlessChunks(){ - //TODO: implement and actually call it + //TODO: improve to make have less performance impact + for(ServerDataCell cell : loadedDataCells){ + if(cell.getPlayers().size() < 1){ + toCleanQueue.add(cell); + } + } + for(ServerDataCell cell : toCleanQueue){ + deregisterCell(cell); + } + toCleanQueue.clear(); } diff --git a/src/main/java/electrosphere/server/datacell/RealmManager.java b/src/main/java/electrosphere/server/datacell/RealmManager.java index 8ee4a75a..bb87f791 100644 --- a/src/main/java/electrosphere/server/datacell/RealmManager.java +++ b/src/main/java/electrosphere/server/datacell/RealmManager.java @@ -1,7 +1,5 @@ package electrosphere.server.datacell; -import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -13,6 +11,7 @@ import electrosphere.engine.Globals; import electrosphere.entity.Entity; import electrosphere.entity.types.hitbox.HitboxManager; import electrosphere.game.server.world.ServerWorldData; +import electrosphere.net.server.player.Player; /** * Manages all realms for the engine. Should be a singleton @@ -23,6 +22,8 @@ public class RealmManager { Set realms = new CopyOnWriteArraySet(); //Map of entities to the realm the entity is in Map entityToRealmMap = new ConcurrentHashMap(); + //Map of player to the realm the player is in + Map playerToRealmMap = new ConcurrentHashMap(); /** @@ -108,5 +109,24 @@ public class RealmManager { } } + //TODO: !!URGENT!! come up with some mechanism to enforce this actually being called every time a player is added to a server data cell + /** + * Adds a player to a realm + * @param player The player + * @param realm The realm + */ + public void setPlayerRealm(Player player, Realm realm){ + playerToRealmMap.put(player, realm); + } + + /** + * Gets the realm of a given player + * @param player The player + * @return The realm + */ + public Realm getPlayerRealm(Player player){ + return playerToRealmMap.get(player); + } + } diff --git a/src/main/java/electrosphere/server/datacell/ServerDataCell.java b/src/main/java/electrosphere/server/datacell/ServerDataCell.java index 32cc33a9..cb48169f 100644 --- a/src/main/java/electrosphere/server/datacell/ServerDataCell.java +++ b/src/main/java/electrosphere/server/datacell/ServerDataCell.java @@ -14,8 +14,8 @@ import electrosphere.server.content.EnvironmentGenerator; import electrosphere.server.pathfinding.NavMeshUtils; import electrosphere.server.pathfinding.navmesh.NavMesh; -import java.util.LinkedList; -import java.util.List; +import java.util.HashSet; +import java.util.Set; /** * Container for entities loaded into memory. This isn't intended to be in charge @@ -28,9 +28,15 @@ import java.util.List; */ public class ServerDataCell { - List activePlayers = new LinkedList(); + //all players attached to this server data cell + Set activePlayers = new HashSet(); + + //the navmesh for the data cell NavMesh navMesh; + + //the scene backing the server data cell Scene scene; + //controls whether the server data cell simulates its entities or not boolean ready = false; @@ -72,6 +78,14 @@ public class ServerDataCell { public void removePlayer(Player p){ activePlayers.remove(p); } + + /** + * Gets the set of all players in the server data cell + * @return The set of players in the data cell + */ + public Set getPlayers(){ + return activePlayers; + } /** * This should be used to translate a character from macrolevel simulation to @@ -84,25 +98,6 @@ public class ServerDataCell { throw new UnsupportedOperationException("Not implemented yet"); } - // /** - // * This should be used to translate an entity from one data cell to another. - // * @param e - // */ - // protected void addEntity(Entity e){ - // loadedEntities.add(e); - // } - - // /** - // * Intention of this function is to entirely remove the entity from microlevel simulation. - // * This should be conbined with code to convert the entity into a tracked macrolevel character. - // * The previous should not be true if you're tracking something inconsequential like - // * a rabbit or something. Then just delete it. - // * @param e - // */ - // public void removeEntity(Entity e){ - // loadedEntities.remove(e); - // } - /** * Broadcast a message to all players within range of this cell. * @param message diff --git a/src/main/java/electrosphere/server/datacell/interfaces/VoxelCellManager.java b/src/main/java/electrosphere/server/datacell/interfaces/VoxelCellManager.java new file mode 100644 index 00000000..81d3d004 --- /dev/null +++ b/src/main/java/electrosphere/server/datacell/interfaces/VoxelCellManager.java @@ -0,0 +1,44 @@ +package electrosphere.server.datacell.interfaces; + +import org.joml.Vector3i; + +import electrosphere.server.terrain.manager.ServerTerrainChunk; + +/** + * Extension of a DataCellManager that provides voxel terrain access and editing functions + */ +public interface VoxelCellManager { + + /** + * Gets the weight of a single voxel at a position + * @param worldPosition The position in world coordinates of the chunk to grab data from + * @param voxelPosition The position in voxel coordinates (local/relative to the chunk) to get voxel values from + * @return The weight of the described voxel + */ + public float getVoxelWeightAtLocalPosition(Vector3i worldPosition, Vector3i voxelPosition); + + /** + * Gets the type of a single voxel at a position + * @param worldPosition The position in world coordinates of the chunk to grab data from + * @param voxelPosition The position in voxel coordinates (local/relative to the chunk) to get voxel values from + * @return The type of the described voxel + */ + public int getVoxelTypeAtLocalPosition(Vector3i worldPosition, Vector3i voxelPosition); + + /** + * Gets the chunk data at a given world position + * @param worldPosition The position in world coordinates + * @return The ServerTerrainChunk of data at that position, or null if it is out of bounds or otherwise doesn't exist + */ + public ServerTerrainChunk getChunkAtPosition(Vector3i worldPosition); + + /** + * Edits a single voxel + * @param worldPosition The world position of the chunk to edit + * @param voxelPosition The voxel position of the voxel to edit + * @param weight The weight to set the voxel to + * @param type The type to set the voxel to + */ + public void editChunk(Vector3i worldPosition, Vector3i voxelPosition, float weight, int type); + +} diff --git a/src/main/java/electrosphere/server/terrain/editing/TerrainEditing.java b/src/main/java/electrosphere/server/terrain/editing/TerrainEditing.java new file mode 100644 index 00000000..dfcda246 --- /dev/null +++ b/src/main/java/electrosphere/server/terrain/editing/TerrainEditing.java @@ -0,0 +1,69 @@ +package electrosphere.server.terrain.editing; + +import org.joml.Vector3d; +import org.joml.Vector3i; + +import electrosphere.engine.Globals; +import electrosphere.server.datacell.Realm; +import electrosphere.server.datacell.interfaces.VoxelCellManager; +import electrosphere.server.terrain.manager.ServerTerrainChunk; + +/** + * Provides utilities for editing terrain (particularly brushes, etc) + */ +public class TerrainEditing { + + /** + * Performs a terrain chunk edit. Basically has a sphere around the provided position that it attempts to add value to. + * @param position The position to perform the edit + * @param editMagnitude The magnitude of the edit to perform + * @param type The type of block to make all edited blocks + * @param weight The weight of the sphere to apply the edit to + */ + public static void editTerrain(Realm realm, Vector3d position, float editMagnitude, int type, float weight){ + if(position != null && realm != null && realm.getDataCellManager() instanceof VoxelCellManager){ + VoxelCellManager voxelCellManager = (VoxelCellManager) realm.getDataCellManager(); + //calculate kernel size + int numPlacesToCheck = (int)((editMagnitude * 2 + 1) * (editMagnitude * 2 + 1) * (editMagnitude * 2 + 1)); + //create and fill in kernel of positions to check + int[] xOffsetSet = new int[numPlacesToCheck]; + int[] yOffsetSet = new int[numPlacesToCheck]; + int[] zOffsetSet = new int[numPlacesToCheck]; + int i = 0; + for(int x = -(int)editMagnitude; x <= (int)editMagnitude; x++){ + for(int y = -(int)editMagnitude; y <= (int)editMagnitude; y++){ + for(int z = -(int)editMagnitude; z <= (int)editMagnitude; z++){ + xOffsetSet[i] = x; + yOffsetSet[i] = y; + zOffsetSet[i] = z; + i++; + } + } + } + for(i = 0; i < numPlacesToCheck; i++){ + //calculate position of edit + Vector3d offsetPos = new Vector3d(position).add(xOffsetSet[i],yOffsetSet[i],zOffsetSet[i]); + Vector3i chunkPos = Globals.serverWorldData.convertRealToWorldSpace(offsetPos); + Vector3i voxelPos = Globals.serverWorldData.convertRealToVoxelSpace(offsetPos); + //get distance from true center point of sphere to current voxel position in world space + float distance = (float)new Vector3d(Math.floor(offsetPos.x),Math.floor(offsetPos.y),Math.floor(offsetPos.z)).distance(position); + float currentPositionMagnitude = editMagnitude - distance; + + ServerTerrainChunk data = voxelCellManager.getChunkAtPosition(chunkPos); + if( + voxelPos.x < ServerTerrainChunk.CHUNK_DIMENSION && + voxelPos.y < ServerTerrainChunk.CHUNK_DIMENSION && + voxelPos.z < ServerTerrainChunk.CHUNK_DIMENSION && + currentPositionMagnitude > 0 && + data != null + ){ + float current = data.getWeights()[voxelPos.x][voxelPos.y][voxelPos.z]; + //hard clamp so it doesn't go over 1 + float finalValue = Math.max(Math.min(current + weight,1),-1); + voxelCellManager.editChunk(chunkPos, voxelPos, finalValue, type); + } + } + } + } + +} diff --git a/src/main/java/electrosphere/server/terrain/manager/ServerTerrainChunk.java b/src/main/java/electrosphere/server/terrain/manager/ServerTerrainChunk.java index 9ce9b163..29dd47d2 100644 --- a/src/main/java/electrosphere/server/terrain/manager/ServerTerrainChunk.java +++ b/src/main/java/electrosphere/server/terrain/manager/ServerTerrainChunk.java @@ -12,6 +12,8 @@ public class ServerTerrainChunk { //all chunks are 16x16x16 public static final int CHUNK_DIMENSION = 16; + //The size of the data passed into marching cubes/transvoxel to generate a fully connected and seamless chunk + public static final int CHUNK_DATA_GENERATOR_SIZE = CHUNK_DIMENSION + 1; int worldX, worldY, worldZ; List modifications = new LinkedList(); @@ -26,20 +28,29 @@ public class ServerTerrainChunk { this.values = values; } + /** + * Returns an arena chunk. Should be flat land if worldY=0, otherwise all air + * @param worldX The world x position + * @param worldY The world y position + * @param worldZ The world z position + * @return The ServerTerrainChunk + */ public static ServerTerrainChunk getArenaChunk(int worldX, int worldY, int worldZ){ - float[][][] weights = new float[CHUNK_DIMENSION][CHUNK_DIMENSION][CHUNK_DIMENSION]; - int[][][] values = new int[CHUNK_DIMENSION][CHUNK_DIMENSION][CHUNK_DIMENSION]; - for(int inc = 0; inc < CHUNK_DIMENSION; inc++){ - for(int weightX = 0; weightX < CHUNK_DIMENSION; weightX++){ - for(int weightZ = 0; weightZ < CHUNK_DIMENSION; weightZ++){ + //Each chunk also needs custody of the next chunk's first values so that they can perfectly overlap. + //Hence, width should actually be chunk dimension + 1 + float[][][] weights = new float[CHUNK_DATA_GENERATOR_SIZE][CHUNK_DATA_GENERATOR_SIZE][CHUNK_DATA_GENERATOR_SIZE]; + int[][][] values = new int[CHUNK_DATA_GENERATOR_SIZE][CHUNK_DATA_GENERATOR_SIZE][CHUNK_DATA_GENERATOR_SIZE]; + for(int inc = 0; inc < CHUNK_DATA_GENERATOR_SIZE; inc++){ + for(int weightX = 0; weightX < CHUNK_DATA_GENERATOR_SIZE; weightX++){ + for(int weightZ = 0; weightZ < CHUNK_DATA_GENERATOR_SIZE; weightZ++){ weights[weightX][inc][weightZ] = -1; values[weightX][inc][weightZ] = 0; } } } if(worldY < 1){ - for(int weightX = 0; weightX < CHUNK_DIMENSION; weightX++){ - for(int weightZ = 0; weightZ < CHUNK_DIMENSION; weightZ++){ + for(int weightX = 0; weightX < CHUNK_DATA_GENERATOR_SIZE; weightX++){ + for(int weightZ = 0; weightZ < CHUNK_DATA_GENERATOR_SIZE; weightZ++){ weights[weightX][0][weightZ] = 0.1f; values[weightX][0][weightZ] = 1; } diff --git a/src/main/java/electrosphere/server/terrain/manager/ServerTerrainManager.java b/src/main/java/electrosphere/server/terrain/manager/ServerTerrainManager.java index 5ca41b3b..d7bda5fc 100644 --- a/src/main/java/electrosphere/server/terrain/manager/ServerTerrainManager.java +++ b/src/main/java/electrosphere/server/terrain/manager/ServerTerrainManager.java @@ -268,6 +268,13 @@ public class ServerTerrainManager { return worldX + "_" + worldY + "_" + worldZ; } + /** + * Gets a server terrain chunk + * @param worldX The world x position + * @param worldY The world y position + * @param worldZ The world z position + * @return The ServerTerrainChunk + */ public ServerTerrainChunk getChunk(int worldX, int worldY, int worldZ){ if(model != null){ //THIS FIRES IF THERE IS A MAIN GAME WORLD RUNNING @@ -279,13 +286,15 @@ public class ServerTerrainManager { returnedChunk = chunkCache.get(key); return returnedChunk; } else { + //Each chunk also needs custody of the next chunk's first values so that they can perfectly overlap. + //Hence, width should actually be chunk dimension + 1 float[][] heightmap = getHeightmap(worldX, worldZ); - float[][][] weights = new float[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION]; - int[][][] values = new int[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION]; - for(int weightX = 0; weightX < ServerTerrainChunk.CHUNK_DIMENSION; weightX++){ - for(int weightY = 0; weightY < ServerTerrainChunk.CHUNK_DIMENSION; weightY++){ - for(int weightZ = 0; weightZ < ServerTerrainChunk.CHUNK_DIMENSION; weightZ++){ - if(weightY < heightmap[ServerTerrainChunk.CHUNK_DIMENSION * worldX + weightX][ServerTerrainChunk.CHUNK_DIMENSION * worldZ + weightZ]){ + float[][][] weights = new float[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE]; + int[][][] values = new int[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE]; + for(int weightX = 0; weightX < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; weightX++){ + for(int weightY = 0; weightY < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; weightY++){ + for(int weightZ = 0; weightZ < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; weightZ++){ + if(weightY < heightmap[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE * worldX + weightX][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE * worldZ + weightZ]){ weights[weightX][weightY][weightZ] = 1; values[weightX][weightY][weightZ] = 1; } else { @@ -346,14 +355,19 @@ public class ServerTerrainManager { } } - public void deformTerrainAtLocationToValue( - Vector3i worldPos, - Vector3i subChunkPos, - Vector3i voxelPos, - float weight, int value){ - System.out.println("Add modification at " + worldPos.x + "," + worldPos.z + " subloc " + voxelPos.x + "," + voxelPos.z); - TerrainModification modification = new TerrainModification(worldPos,subChunkPos,voxelPos,weight,value); - model.addModification(modification); + /** + * Applies a deform to terrain at a given location + * @param worldPos The world coordinates of the chunk to modify + * @param voxelPos The voxel coordinates of the voxel to modify + * @param weight The weight to set it to + * @param value The value to set it to + */ + public void deformTerrainAtLocationToValue(Vector3i worldPos, Vector3i voxelPos, float weight, int value){ + TerrainModification modification = new TerrainModification(worldPos,voxelPos,weight,value); + //could be null if, for instance, arena mode + if(model != null){ + model.addModification(modification); + } String key = getKey(worldPos.x,worldPos.y,worldPos.z); if(chunkCache.containsKey(key)){ ServerTerrainChunk chunk = chunkCache.get(key); diff --git a/src/main/java/electrosphere/server/terrain/models/TerrainModification.java b/src/main/java/electrosphere/server/terrain/models/TerrainModification.java index dea89e0e..065935f4 100644 --- a/src/main/java/electrosphere/server/terrain/models/TerrainModification.java +++ b/src/main/java/electrosphere/server/terrain/models/TerrainModification.java @@ -10,14 +10,12 @@ import electrosphere.server.terrain.manager.ServerTerrainChunk; */ public class TerrainModification { Vector3i worldPos; - Vector3i subChunkPos; Vector3i voxelPos; float weight; int value; - public TerrainModification(Vector3i worldPos, Vector3i subChunkPos, Vector3i voxelPos, float weight, int value) { + public TerrainModification(Vector3i worldPos, Vector3i voxelPos, float weight, int value) { this.worldPos = worldPos; - this.subChunkPos = subChunkPos; this.voxelPos = voxelPos; this.weight = weight; this.value = value; @@ -27,10 +25,6 @@ public class TerrainModification { return worldPos; } - public Vector3i getSubChunkPos() { - return subChunkPos; - } - public Vector3i getVoxelPos() { return voxelPos; } diff --git a/src/main/java/electrosphere/util/FileUtils.java b/src/main/java/electrosphere/util/FileUtils.java index 2f37c371..b64f4576 100644 --- a/src/main/java/electrosphere/util/FileUtils.java +++ b/src/main/java/electrosphere/util/FileUtils.java @@ -186,7 +186,7 @@ public class FileUtils { public static String getSQLScriptFileAsString(String pathName) throws IOException { String sanitizedFilePath = sanitizeFilePath(pathName); - File targetFile = new File("./Scripts" + sanitizedFilePath); + File targetFile = new File("./src/main/sql" + sanitizedFilePath); return Files.readString(targetFile.toPath()); }