├── src ├── structure_house.txt ├── de │ └── meinkraft │ │ ├── .gitignore │ │ ├── lib │ │ ├── InputController.java │ │ ├── Time.java │ │ ├── Main.java │ │ ├── Utils.java │ │ ├── Vector2.java │ │ ├── Transform.java │ │ ├── Vector4.java │ │ ├── Vector3.java │ │ ├── Display.java │ │ ├── VAO.java │ │ ├── Input.java │ │ ├── Camera.java │ │ ├── Shader.java │ │ ├── Texture.java │ │ └── Matrix4.java │ │ ├── ChunkState.java │ │ ├── EntityPlayer.java │ │ ├── Player.java │ │ ├── BlockAO.java │ │ ├── BlockAir.java │ │ ├── BlockDirt.java │ │ ├── BlockRose.java │ │ ├── Blockcheck.java │ │ ├── BlockGrass.java │ │ ├── BlockStone.java │ │ ├── BlockTallGrass.java │ │ ├── BlockWoodenPlanks.java │ │ ├── WorldGenerator.java │ │ ├── Entity.java │ │ ├── BlockTypeAir.java │ │ ├── Material.java │ │ ├── StructureLoader.java │ │ ├── gui │ │ ├── GUIFontCharacter.java │ │ ├── GUI.java │ │ ├── GUILabel.java │ │ ├── GUIObject.java │ │ └── GUIFont.java │ │ ├── WorldGeneratorFlat.java │ │ ├── BlockType.java │ │ ├── World.java │ │ ├── OpenSimplexNoise.java │ │ ├── Block.java │ │ ├── BlockTypePlant.java │ │ ├── WorldGeneratorNormal.java │ │ ├── BlockTypeCube.java │ │ ├── Chunk.java │ │ ├── Meinkraft.java │ │ ├── ChunkLoader.java │ │ ├── ChunkManager.java │ │ └── OpenSimplexNoiseOctave.java ├── bs.fs ├── gui.fs ├── bs.vs ├── gui.vs ├── shader.fs ├── font.vs ├── font.fs └── shader.vs ├── .gitignore └── .project /src/structure_house.txt: -------------------------------------------------------------------------------- 1 | 0,0,0:6 -------------------------------------------------------------------------------- /src/de/meinkraft/.gitignore: -------------------------------------------------------------------------------- 1 | /ChunkLoaderCM.java 2 | -------------------------------------------------------------------------------- /src/bs.fs: -------------------------------------------------------------------------------- 1 | #version 110 2 | 3 | void main() { 4 | gl_FragColor = vec4(1); 5 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | /libs/ 3 | /native/ 4 | /docs/ 5 | .classpath 6 | *.log 7 | *.png 8 | *.fnt 9 | *.db -------------------------------------------------------------------------------- /src/gui.fs: -------------------------------------------------------------------------------- 1 | #version 110 2 | 3 | varying vec4 color; 4 | 5 | void main() { 6 | gl_FragColor = color; 7 | } -------------------------------------------------------------------------------- /src/bs.vs: -------------------------------------------------------------------------------- 1 | #version 110 2 | 3 | uniform mat4 p; 4 | uniform mat4 v; 5 | uniform mat4 m; 6 | 7 | void main() { 8 | gl_Position = p * v * m * gl_Vertex; 9 | } -------------------------------------------------------------------------------- /src/de/meinkraft/lib/InputController.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft.lib; 2 | 3 | public interface InputController { 4 | 5 | public void input(); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/de/meinkraft/ChunkState.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | public enum ChunkState { 4 | 5 | UNLOADED, 6 | LOADING, 7 | LOADED; 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/de/meinkraft/EntityPlayer.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | public class EntityPlayer extends Entity { 4 | 5 | public EntityPlayer() { 6 | 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/de/meinkraft/Player.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | import de.meinkraft.lib.Vector3; 4 | 5 | public class Player { 6 | 7 | // temp 8 | public Vector3 dir; 9 | public Vector3 pos; 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/gui.vs: -------------------------------------------------------------------------------- 1 | #version 110 2 | 3 | uniform mat4 p; 4 | uniform mat4 v; 5 | uniform mat4 m; 6 | 7 | varying vec4 color; 8 | 9 | void main() { 10 | gl_Position = p * v * m * gl_Vertex; 11 | color = gl_Color; 12 | } -------------------------------------------------------------------------------- /src/de/meinkraft/BlockAO.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | public class BlockAO { 4 | 5 | public boolean nT, nB, eT, eB, sT, sB, wT, wB; 6 | public boolean cXYZ, c_XYZ, cX_YZ, cXY_Z, c_X_YZ, cX_Y_Z, c_XY_Z, c_X_Y_Z; 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/de/meinkraft/BlockAir.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | public class BlockAir extends Block { 4 | 5 | public BlockAir(int id, Material material, BlockType type) { 6 | super(id, material, type); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/de/meinkraft/BlockDirt.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | public class BlockDirt extends Block { 4 | 5 | public BlockDirt(int id, Material material, BlockType type, int... textures) { 6 | super(id, material, type, textures); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/de/meinkraft/BlockRose.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | public class BlockRose extends Block { 4 | 5 | public BlockRose(int id, Material material, BlockType type, int... textures) { 6 | super(id, material, type, textures); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/de/meinkraft/Blockcheck.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | public class Blockcheck { 4 | 5 | public boolean north, east, south, west, top, bottom; 6 | 7 | public boolean all() { 8 | return north && east && south && west && top && bottom; 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/de/meinkraft/BlockGrass.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | public class BlockGrass extends Block { 4 | 5 | public BlockGrass(int id, Material material, BlockType type, int... textures) { 6 | super(id, material, type, textures); 7 | // TODO Auto-generated constructor stub 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/de/meinkraft/BlockStone.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | public class BlockStone extends Block { 4 | 5 | public BlockStone(int id, Material material, BlockType type, int... textures) { 6 | super(id, material, type, textures); 7 | // TODO Auto-generated constructor stub 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/de/meinkraft/BlockTallGrass.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | public class BlockTallGrass extends Block { 4 | 5 | public BlockTallGrass(int id, Material material, BlockType type, int... textures) { 6 | super(id, material, type, textures); 7 | // TODO Auto-generated constructor stub 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/de/meinkraft/BlockWoodenPlanks.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | public class BlockWoodenPlanks extends Block { 4 | 5 | public BlockWoodenPlanks(int id, Material material, BlockType type, int... textures) { 6 | super(id, material, type, textures); 7 | // TODO Auto-generated constructor stub 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/de/meinkraft/WorldGenerator.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | import java.util.Random; 4 | 5 | public abstract class WorldGenerator { 6 | 7 | private final Random random = new Random(2015); 8 | 9 | public abstract void generate(Chunk chunk); 10 | 11 | public Random getRandom() { 12 | return random; 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/shader.fs: -------------------------------------------------------------------------------- 1 | #version 150 2 | 3 | in vec3 texCoord; 4 | in float ao; 5 | in float fogFactor; 6 | 7 | uniform sampler2DArray texture0; 8 | 9 | out vec4 color; 10 | 11 | void main() { 12 | color = texture(texture0, texCoord); 13 | 14 | if(color.a == 0) 15 | discard; 16 | 17 | color *= ao / 3.0; 18 | color = mix(vec4(1), color, fogFactor); 19 | } -------------------------------------------------------------------------------- /src/de/meinkraft/Entity.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | import de.meinkraft.lib.Vector3; 4 | 5 | public abstract class Entity { 6 | 7 | private Vector3 pos; 8 | 9 | public Entity() { 10 | pos = new Vector3(); 11 | } 12 | 13 | public Vector3 getPos() { 14 | return pos; 15 | } 16 | 17 | public void setPos(Vector3 pos) { 18 | this.pos = pos; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/font.vs: -------------------------------------------------------------------------------- 1 | #version 330 2 | 3 | uniform mat4 p; 4 | uniform mat4 v; 5 | uniform mat4 m; 6 | 7 | layout(location = 0) in vec2 position; 8 | layout(location = 1) in vec2 texCoord; 9 | layout(location = 2) in vec3 color; 10 | 11 | out vec3 pass_color; 12 | out vec2 pass_texCoord; 13 | 14 | void main() { 15 | gl_Position = p * v * m * vec4(position, 0.0, 1.0); 16 | pass_color = color; 17 | pass_texCoord = texCoord; 18 | } -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | Meinkraft 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/font.fs: -------------------------------------------------------------------------------- 1 | #version 330 2 | 3 | uniform sampler2D atlas; 4 | uniform float size; 5 | 6 | in vec3 pass_color; 7 | in vec2 pass_texCoord; 8 | 9 | out vec4 outColor; 10 | 11 | void main() { 12 | float smoothing = 1.0 / (16.0 * size); 13 | float distance = 1.0 - texture(atlas, pass_texCoord).a; 14 | float alpha = 1.0 - smoothstep(0.5 - smoothing, 0.5 + smoothing, distance); 15 | 16 | //if(alpha <= 0.0) 17 | // discard; 18 | 19 | outColor = vec4(1.0, 1.0, 0, alpha); 20 | } -------------------------------------------------------------------------------- /src/de/meinkraft/BlockTypeAir.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | import java.nio.FloatBuffer; 4 | 5 | public class BlockTypeAir extends BlockType { 6 | 7 | public BlockTypeAir(boolean solid, boolean both) { 8 | super(solid, both); 9 | } 10 | 11 | @Override 12 | public int getVerticesCount(Blockcheck check) { 13 | return 0; 14 | } 15 | 16 | @Override 17 | public void addVertices(float x, float y, float z, FloatBuffer buffer, Blockcheck check, BlockAO ao, int... textures) { 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/de/meinkraft/lib/Time.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft.lib; 2 | 3 | import static org.lwjgl.glfw.GLFW.glfwGetTime; 4 | 5 | public class Time { 6 | 7 | private static float delta = 0; 8 | private static double lastTime = 0; 9 | 10 | public static void update() { 11 | delta = (float) (glfwGetTime() - lastTime); 12 | lastTime = glfwGetTime(); 13 | } 14 | 15 | public static float getDelta() { 16 | return delta; 17 | } 18 | 19 | public static double getTime() { 20 | return glfwGetTime(); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/de/meinkraft/Material.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | public class Material { 4 | 5 | public static final Material AIR = new Material(); 6 | public static final Material STONE = new Material().setOpaque(true); 7 | public static final Material GROUND = new Material().setOpaque(true); 8 | public static final Material PLANT = new Material().setOpaque(false); 9 | 10 | private boolean opaque; 11 | 12 | public Material() { 13 | 14 | } 15 | 16 | public boolean isOpaque() { 17 | return opaque; 18 | } 19 | 20 | public Material setOpaque(boolean opaque) { 21 | this.opaque = opaque; 22 | return this; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/de/meinkraft/StructureLoader.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.InputStreamReader; 7 | 8 | public class StructureLoader { 9 | 10 | public static void loadStructure(World world, int x, int y, int z, InputStream path) throws IOException { 11 | BufferedReader br = new BufferedReader(new InputStreamReader(path)); 12 | 13 | String line; 14 | while((line = br.readLine()) != null) { 15 | String xyz = line.split(":")[0]; 16 | world.setBlockAt(x + Integer.parseInt(xyz.split(",")[0]), y + Integer.parseInt(xyz.split(",")[1]), z + Integer.parseInt(xyz.split(",")[2]), Block.getBlockById(Integer.parseInt(line.split(":")[1]))); 17 | } 18 | br.close(); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/de/meinkraft/gui/GUIFontCharacter.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft.gui; 2 | 3 | public class GUIFontCharacter { 4 | 5 | private final int x, y, w, h, xoff, yoff, xadv; 6 | 7 | public GUIFontCharacter(int x, int y, int w, int h, int xoff, int yoff, int xadv) { 8 | this.x = x; 9 | this.y = y; 10 | this.w = w; 11 | this.h = h; 12 | this.xoff = xoff; 13 | this.yoff = yoff; 14 | this.xadv = xadv; 15 | } 16 | 17 | public int getX() { 18 | return x; 19 | } 20 | 21 | public int getY() { 22 | return y; 23 | } 24 | 25 | public int getW() { 26 | return w; 27 | } 28 | 29 | public int getH() { 30 | return h; 31 | } 32 | 33 | public int getXoff() { 34 | return xoff; 35 | } 36 | 37 | public int getYoff() { 38 | return yoff; 39 | } 40 | 41 | public int getXadv() { 42 | return xadv; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/de/meinkraft/gui/GUI.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft.gui; 2 | 3 | import java.io.IOException; 4 | 5 | import de.meinkraft.lib.Display; 6 | import de.meinkraft.lib.Matrix4; 7 | import de.meinkraft.lib.Shader; 8 | import de.meinkraft.lib.Transform; 9 | 10 | public class GUI { 11 | 12 | public static final Matrix4 ORTHO = new Matrix4().initOrthographic(0, Display.getWidth(), 0, Display.getHeight(), -1, 1); 13 | public static Shader SHADER; 14 | static { 15 | try { 16 | SHADER = Shader.loadShader("/gui.vs", "/gui.fs", null); 17 | SHADER.addUniform("p"); 18 | SHADER.addUniform("v"); 19 | SHADER.addUniform("m"); 20 | 21 | SHADER.bind(); 22 | SHADER.setUniform("p", ORTHO); 23 | SHADER.setUniform("v", new Transform().getTransformationMatrix()); 24 | SHADER.setUniform("m", new Transform().getTransformationMatrix()); 25 | 26 | Shader.unbind(); 27 | } catch (IOException e) { 28 | e.printStackTrace(); 29 | } 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/de/meinkraft/WorldGeneratorFlat.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | public class WorldGeneratorFlat extends WorldGenerator { 4 | 5 | @Override 6 | public void generate(Chunk chunk) { 7 | for(int x = 0; x < Chunk.SIZE_X; x++) 8 | for(int y = 0; y < Chunk.SIZE_Y; y++) 9 | for(int z = 0; z < Chunk.SIZE_Z; z++) { 10 | if(y > 63) { 11 | if(y == 64) { 12 | if(getRandom().nextInt(5) == 0) 13 | chunk.setBlockAt(x, y, z, Block.TALL_GRASS); 14 | else if(getRandom().nextInt(50) == 0) 15 | chunk.setBlockAt(x, y, z, Block.ROSE); 16 | else 17 | chunk.setBlockAt(x, y, z, Block.AIR); 18 | } else 19 | chunk.setBlockAt(x, y, z, Block.AIR); 20 | } 21 | else { 22 | if(y == 63) 23 | chunk.setBlockAt(x, y, z, Block.GRASS); 24 | else if(y >= 60) 25 | chunk.setBlockAt(x, y, z, Block.DIRT); 26 | else 27 | chunk.setBlockAt(x, y, z, Block.STONE); 28 | } 29 | } 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/shader.vs: -------------------------------------------------------------------------------- 1 | #version 150 2 | #extension GL_ARB_explicit_attrib_location: enable 3 | 4 | layout(location = 0) in vec3 inPosition; 5 | layout(location = 1) in vec3 inTexCoord; 6 | layout(location = 2) in float inAO; 7 | 8 | uniform mat4 p; 9 | uniform mat4 v; 10 | uniform mat4 m; 11 | 12 | uniform bool enableFog; 13 | 14 | const float fogDensity = 0.04; 15 | const float fogStart = 60; 16 | 17 | out vec3 position; 18 | out vec3 texCoord; 19 | out float ao; 20 | out float fogFactor; 21 | 22 | void main() { 23 | gl_Position = p * v * m * vec4(inPosition, 1); 24 | position = inPosition; 25 | texCoord = inTexCoord; 26 | ao = inAO; 27 | 28 | float fogFragCoord = length(v * m * vec4(inPosition, 1)); 29 | if(!enableFog || fogFragCoord < fogStart) 30 | fogFragCoord = 0; 31 | else 32 | fogFragCoord = fogFragCoord - fogStart; 33 | 34 | fogFactor = exp(-fogDensity * fogDensity * fogFragCoord * fogFragCoord * 1.442695); 35 | fogFactor = clamp(fogFactor, 0.0, 1.0); 36 | } -------------------------------------------------------------------------------- /src/de/meinkraft/BlockType.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | import java.nio.FloatBuffer; 4 | 5 | public abstract class BlockType { 6 | 7 | public static final BlockType AIR = new BlockTypeAir(false, false); 8 | public static final BlockType CUBE = new BlockTypeCube(true, false); 9 | public static final BlockType PLANT = new BlockTypePlant(false, true); 10 | 11 | private final boolean solid, doubleSided; 12 | 13 | public BlockType(boolean solid, boolean doubleSided) { 14 | this.solid = solid; 15 | this.doubleSided = doubleSided; 16 | } 17 | 18 | public abstract int getVerticesCount(Blockcheck check); 19 | public abstract void addVertices(float x, float y, float z, FloatBuffer buffer, Blockcheck check, BlockAO ao, int...textures); 20 | 21 | public float getAO(boolean side1, boolean side2, boolean corner) { 22 | if(side1 && side2) 23 | return 0; 24 | 25 | return 3 - (side1 ? 1 : 0 + (side2 ? 1 : 0) + (corner ? 1 : 0)); 26 | } 27 | 28 | public boolean isSolid() { 29 | return solid; 30 | } 31 | 32 | public boolean isDoubleSided() { 33 | return doubleSided; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/de/meinkraft/lib/Main.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft.lib; 2 | 3 | import static org.lwjgl.glfw.GLFW.glfwPollEvents; 4 | import static org.lwjgl.glfw.GLFW.glfwSwapBuffers; 5 | import static org.lwjgl.glfw.GLFW.glfwWindowShouldClose; 6 | import static org.lwjgl.opengl.GL11.*; 7 | 8 | import org.lwjgl.openal.AL; 9 | import org.lwjgl.openal.ALContext; 10 | 11 | import de.meinkraft.Meinkraft; 12 | 13 | public class Main { 14 | 15 | public static void main(String[] args) { 16 | Display.create(1280, 720, "Meinkraft"); 17 | ALContext alc = ALContext.create(); 18 | // alDistanceModel 19 | 20 | glEnable(GL_DEPTH_TEST); 21 | glEnable(GL_CULL_FACE); 22 | // glEnable(GL_BLEND); 23 | // glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 24 | 25 | glClearColor(1, 1, 1, 1); 26 | 27 | Meinkraft mk = new Meinkraft(); 28 | 29 | while(glfwWindowShouldClose(Display.getWindow()) == 0) { 30 | Time.update(); 31 | 32 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 33 | 34 | mk.input(); 35 | Input.update(); 36 | glfwPollEvents(); 37 | mk.update(); 38 | mk.render(); 39 | 40 | glfwSwapBuffers(Display.getWindow()); 41 | } 42 | 43 | Input.destroy(); 44 | Display.destory(); 45 | AL.destroy(alc); 46 | 47 | System.exit(0); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/de/meinkraft/lib/Utils.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft.lib; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.InputStreamReader; 7 | import java.nio.FloatBuffer; 8 | import java.nio.IntBuffer; 9 | 10 | import org.lwjgl.BufferUtils; 11 | 12 | public class Utils { 13 | 14 | public static String readFileToString(String path) throws IOException { 15 | BufferedReader bR = new BufferedReader(new InputStreamReader(getResourceAsStream(path))); 16 | StringBuilder sB = new StringBuilder(); 17 | String line; 18 | 19 | while((line = bR.readLine()) != null) 20 | sB.append(line).append("\n"); 21 | 22 | bR.close(); 23 | 24 | return sB.toString(); 25 | } 26 | 27 | public static InputStream getResourceAsStream(String path) { 28 | return Class.class.getResourceAsStream(path); 29 | } 30 | 31 | public static FloatBuffer createFlippedFloatBuffer(float[] data) { 32 | FloatBuffer buffer = BufferUtils.createFloatBuffer(data.length); 33 | buffer.put(data); 34 | buffer.flip(); 35 | 36 | return buffer; 37 | } 38 | 39 | public static IntBuffer createFlippedIntBuffer(int[] data) { 40 | IntBuffer buffer = BufferUtils.createIntBuffer(data.length); 41 | buffer.put(data); 42 | buffer.flip(); 43 | 44 | return buffer; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/de/meinkraft/lib/Vector2.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft.lib; 2 | 3 | public class Vector2 { 4 | 5 | private float x, y; 6 | 7 | public Vector2() { 8 | this(0); 9 | } 10 | 11 | public Vector2(float v) { 12 | this(v, v); 13 | } 14 | 15 | public Vector2(float x, float y) { 16 | this.x = x; 17 | this.y = y; 18 | } 19 | 20 | public float angle(Vector2 v) { 21 | return (float) Math.toDegrees(Math.acos(dot(v) / (length() * v.length()))); 22 | } 23 | 24 | public float dot(Vector2 v) { 25 | return x * v.getX() + y * v.getY(); 26 | } 27 | 28 | public float length() { 29 | return (float) Math.sqrt(x * x + y * y); 30 | } 31 | 32 | public Vector2 negate() { 33 | return mul(-1); 34 | } 35 | 36 | public Vector2 normalised() { 37 | return new Vector2(x / length(), y / length()); 38 | } 39 | 40 | public Vector2 add(Vector2 v) { 41 | return new Vector2(x + v.getX(), y + v.getY()); 42 | } 43 | 44 | public Vector2 mul(float v) { 45 | return new Vector2(x * v, y * v); 46 | } 47 | 48 | public float getX() { 49 | return x; 50 | } 51 | 52 | public void setX(float x) { 53 | this.x = x; 54 | } 55 | 56 | public float getY() { 57 | return y; 58 | } 59 | 60 | public void setY(float y) { 61 | this.y = y; 62 | } 63 | 64 | @Override 65 | public String toString() { 66 | return "vec2(" + x + ", " + y + ")"; 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/de/meinkraft/World.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | import de.meinkraft.lib.Time; 4 | 5 | public class World { 6 | 7 | private final ChunkManager chunkManager; 8 | private final Player player; 9 | 10 | private String name; 11 | private WorldGenerator worldGenerator; 12 | 13 | public World(String name, WorldGenerator worldGenerator) { 14 | this.name = name; 15 | this.worldGenerator = worldGenerator; 16 | 17 | chunkManager = new ChunkManager(this); 18 | player = new Player(); 19 | } 20 | 21 | public void update() { 22 | chunkManager.update(); 23 | } 24 | 25 | public void render() { 26 | chunkManager.render(); 27 | } 28 | 29 | public Block getBlockAt(int x, int y, int z) { 30 | return chunkManager.getBlockAt(x, y, z); 31 | } 32 | 33 | public void setBlockAt(int x, int y, int z, Block block) { 34 | chunkManager.setBlockAt(x, y, z, block); 35 | } 36 | 37 | public ChunkManager getChunkManager() { 38 | return chunkManager; 39 | } 40 | 41 | public Player getPlayer() { 42 | return player; 43 | } 44 | 45 | public String getName() { 46 | return name; 47 | } 48 | 49 | public void setName(String name) { 50 | this.name = name; 51 | } 52 | 53 | public WorldGenerator getWorldGenerator() { 54 | return worldGenerator; 55 | } 56 | 57 | public void setWorldGenerator(WorldGenerator worldGenerator) { 58 | this.worldGenerator = worldGenerator; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/de/meinkraft/OpenSimplexNoise.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | import java.util.Random; 4 | 5 | public class OpenSimplexNoise { 6 | 7 | private OpenSimplexNoiseOctave[] o; 8 | private double[] f; 9 | private double[] a; 10 | 11 | private double persistance; 12 | 13 | public OpenSimplexNoise(int largestFeature, double persistance, long seed) { 14 | this.persistance = persistance; 15 | 16 | int numberOfOctaves = (int) Math.ceil(Math.log10(largestFeature) / Math.log10(2)); 17 | 18 | o = new OpenSimplexNoiseOctave[numberOfOctaves]; 19 | f = new double[numberOfOctaves]; 20 | a = new double[numberOfOctaves]; 21 | 22 | Random r = new Random(seed); 23 | 24 | for(int i = 0; i < numberOfOctaves; i++) { 25 | o[i] = new OpenSimplexNoiseOctave(r.nextInt()); 26 | 27 | f[i] = Math.pow(2, i); 28 | a[i] = Math.pow(persistance, o.length - i); 29 | } 30 | } 31 | 32 | public double getNoise(int x, int y) { 33 | double result = 0; 34 | 35 | for(int i = 0; i < o.length; i++) 36 | result += o[i].eval(x / f[i], y / f[i]) * a[i]; 37 | 38 | return result; 39 | } 40 | 41 | public double getNoise(double x, double y, double z) { 42 | double result = 0; 43 | 44 | for(int i = 0; i < o.length; i++) { 45 | double f = Math.pow(2, i); 46 | double a = Math.pow(persistance, o.length - i); 47 | result += o[i].eval(x / f, y / f, z / f) * a; 48 | } 49 | 50 | return result; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/de/meinkraft/lib/Transform.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft.lib; 2 | 3 | public class Transform { 4 | 5 | private Vector3 translation; 6 | private Vector3 rotation; 7 | private Vector3 scale; 8 | 9 | public Transform() { 10 | this(new Vector3()); 11 | } 12 | 13 | public Transform(Transform transform) { 14 | this(transform.getTranslation(), transform.getRotation(), transform.getScale()); 15 | } 16 | 17 | public Transform(Vector3 translation) { 18 | this(translation, new Vector3()); 19 | } 20 | 21 | public Transform(Vector3 translation, Vector3 rotation) { 22 | this(translation, rotation, new Vector3(1)); 23 | } 24 | 25 | public Transform(Vector3 translation, Vector3 rotation, Vector3 scale) { 26 | this.translation = translation; 27 | this.rotation = rotation; 28 | this.scale = scale; 29 | } 30 | 31 | public Matrix4 getTransformationMatrix() { 32 | Matrix4 t = new Matrix4().initTranslation(translation); 33 | Matrix4 r = new Matrix4().initRotation(rotation, Matrix4.XYZ); 34 | Matrix4 s = new Matrix4().initScale(scale); 35 | 36 | return t.mul(r.mul(s)); 37 | } 38 | 39 | public Vector3 getTranslation() { 40 | return translation; 41 | } 42 | 43 | public void setTranslation(Vector3 translation) { 44 | this.translation = translation; 45 | } 46 | 47 | public Vector3 getRotation() { 48 | return rotation; 49 | } 50 | 51 | public void setRotation(Vector3 rotation) { 52 | this.rotation = rotation; 53 | } 54 | 55 | public Vector3 getScale() { 56 | return scale; 57 | } 58 | 59 | public void setScale(Vector3 scale) { 60 | this.scale = scale; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/de/meinkraft/gui/GUILabel.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft.gui; 2 | 3 | import static org.lwjgl.opengl.GL11.GL_QUADS; 4 | import static org.lwjgl.opengl.GL11.glBegin; 5 | import static org.lwjgl.opengl.GL11.glColor4f; 6 | import static org.lwjgl.opengl.GL11.glEnd; 7 | import static org.lwjgl.opengl.GL11.glVertex2f; 8 | import de.meinkraft.lib.Display; 9 | import de.meinkraft.lib.Vector3; 10 | 11 | public class GUILabel extends GUIObject { 12 | 13 | public static GUIFont font; 14 | 15 | public GUILabel(float x, float y, int width, int height) { 16 | super(x, y, width, height); 17 | 18 | font = new GUIFont("font", 20); 19 | font.setColor(new Vector3(1,0,0)); 20 | } 21 | 22 | @Override 23 | public void draw() { 24 | int displayW = Display.getWidth(); 25 | int displayH = Display.getHeight(); 26 | 27 | float x = getX() * displayW; 28 | if(getOrientationX() == 1) 29 | x -= getWidth() / 2.0f; 30 | else if(getOrientationX() == 2) 31 | x -= - getWidth(); 32 | 33 | float y = getY() * displayH; 34 | if(getOrientationY() == 1) 35 | y -= getHeight() / 2.0f; 36 | else if(getOrientationY() == 2) 37 | y -= getHeight(); 38 | 39 | GUI.SHADER.bind(); 40 | glBegin(GL_QUADS); 41 | { 42 | glColor4f(0, 0, 1, 1); 43 | 44 | glVertex2f(x, y); 45 | glVertex2f(x + getWidth(), y); 46 | glVertex2f(x + getWidth(), y + getHeight()); 47 | glVertex2f(x, y + getHeight()); 48 | } 49 | glEnd(); 50 | 51 | font.drawString("Text", (int) (getX() * displayW), (int) (getY() * displayH)); 52 | } 53 | 54 | public void setFont(GUIFont font) { 55 | GUILabel.font = font; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/de/meinkraft/lib/Vector4.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft.lib; 2 | 3 | public class Vector4 { 4 | 5 | private float x, y, z, w; 6 | 7 | public Vector4() { 8 | this(0); 9 | } 10 | 11 | public Vector4(float v) { 12 | this(v, v, v, v); 13 | } 14 | 15 | public Vector4(float x, float y, float z, float w) { 16 | this.x = x; 17 | this.y = y; 18 | this.z = z; 19 | this.w = w; 20 | } 21 | 22 | public float dot(Vector4 v) { 23 | return x * v.getX() + y * v.getY() + z * v.getZ() + w * v.getW(); 24 | } 25 | 26 | public float length() { 27 | return (float) Math.sqrt(x * x + y * y + z * z + w * w); 28 | } 29 | 30 | public Vector4 negate() { 31 | return mul(-1); 32 | } 33 | 34 | public Vector4 normalised() { 35 | return new Vector4(x / length(), y / length(), z / length(), w / length()); 36 | } 37 | 38 | public Vector4 add(Vector4 v) { 39 | return new Vector4(x + v.getX(), y + v.getY(), z + v.getZ(), w + v.getW()); 40 | } 41 | 42 | public Vector4 mul(float v) { 43 | return new Vector4(x * v, y * v, z * v, w * v); 44 | } 45 | 46 | public float getX() { 47 | return x; 48 | } 49 | 50 | public void setX(float x) { 51 | this.x = x; 52 | } 53 | 54 | public float getY() { 55 | return y; 56 | } 57 | 58 | public void setY(float y) { 59 | this.y = y; 60 | } 61 | 62 | public float getZ() { 63 | return z; 64 | } 65 | 66 | public void setZ(float z) { 67 | this.z = z; 68 | } 69 | 70 | public float getW() { 71 | return w; 72 | } 73 | 74 | public void setW(float w) { 75 | this.w = w; 76 | } 77 | 78 | @Override 79 | public String toString() { 80 | return "vec4(" + x + ", " + y + ", " + z + ", " + w + ")"; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/de/meinkraft/lib/Vector3.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft.lib; 2 | 3 | public class Vector3 { 4 | 5 | private float x, y, z; 6 | 7 | public Vector3() { 8 | this(0); 9 | } 10 | 11 | public Vector3(float v) { 12 | this(v, v, v); 13 | } 14 | 15 | public Vector3(float x, float y, float z) { 16 | this.x = x; 17 | this.y = y; 18 | this.z = z; 19 | } 20 | 21 | public float angle(Vector3 v) { 22 | return (float) Math.toDegrees(Math.acos(dot(v) / (length() * v.length()))); 23 | } 24 | 25 | public Vector3 cross(Vector3 v) { 26 | return new Vector3(y * v.getZ() - z * v.getY(), z * v.getX() - x * v.getZ(), x * v.getY() - y * v.getX()); 27 | } 28 | 29 | public float dot(Vector3 v) { 30 | return x * v.getX() + y * v.getY() + z * v.getZ(); 31 | } 32 | 33 | public float length() { 34 | return (float) Math.sqrt(x * x + y * y + z * z); 35 | } 36 | 37 | public Vector3 negate() { 38 | return mul(-1); 39 | } 40 | 41 | public Vector3 normalised() { 42 | return new Vector3(x / length(), y / length(), z / length()); 43 | } 44 | 45 | public Vector3 add(Vector3 v) { 46 | return new Vector3(x + v.getX(), y + v.getY(), z + v.getZ()); 47 | } 48 | 49 | public Vector3 mul(float v) { 50 | return new Vector3(x * v, y * v, z * v); 51 | } 52 | 53 | public float getX() { 54 | return x; 55 | } 56 | 57 | public void setX(float x) { 58 | this.x = x; 59 | } 60 | 61 | public float getY() { 62 | return y; 63 | } 64 | 65 | public void setY(float y) { 66 | this.y = y; 67 | } 68 | 69 | public float getZ() { 70 | return z; 71 | } 72 | 73 | public void setZ(float z) { 74 | this.z = z; 75 | } 76 | 77 | @Override 78 | public String toString() { 79 | return "vec3(" + x + ", " + y + ", " + z + ")"; 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/de/meinkraft/Block.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | import java.lang.reflect.Field; 4 | 5 | public abstract class Block { 6 | 7 | public static final Block AIR = new BlockAir(0, Material.AIR, BlockType.AIR); 8 | public static final Block STONE = new BlockStone(1, Material.GROUND, BlockType.CUBE, 1,1,1,1,1,1); 9 | public static final Block DIRT = new BlockDirt(2, Material.GROUND, BlockType.CUBE, 2,2,2,2,2,2); 10 | public static final Block GRASS = new BlockGrass(3, Material.GROUND, BlockType.CUBE, 3,3,3,3,0,2); 11 | public static final Block ROSE = new BlockRose(4, Material.PLANT, BlockType.PLANT, 12); 12 | public static final Block TALL_GRASS = new BlockTallGrass(5, Material.PLANT, BlockType.PLANT, 39); 13 | public static final Block WOODEN_PLANKS = new BlockWoodenPlanks(6, Material.GROUND, BlockType.CUBE, 4,4,4,4,4,4); 14 | 15 | private final int id; 16 | private final Material material; 17 | private final BlockType type; 18 | private final int[] textures; 19 | 20 | public Block(int id, Material material, BlockType type, int... textures) { 21 | this.id = id; 22 | this.material = material; 23 | this.type = type; 24 | this.textures = textures; 25 | } 26 | 27 | // public abstract ItemStack getItemDrop(); 28 | // public abstract float[]? getVertices(); 29 | 30 | public static Block getBlockById(int id) { 31 | for(Field field : Block.class.getDeclaredFields()) { 32 | if(field.getType().getSimpleName().equals("Block")) { 33 | try { 34 | Block block = (Block) field.get(field.getName()); 35 | 36 | if(block.id == id) 37 | return block; 38 | } catch (IllegalArgumentException e) { 39 | e.printStackTrace(); 40 | } catch (IllegalAccessException e) { 41 | e.printStackTrace(); 42 | } 43 | } 44 | } 45 | 46 | return null; 47 | } 48 | 49 | public int getId() { 50 | return id; 51 | } 52 | 53 | public Material getMaterial() { 54 | return material; 55 | } 56 | 57 | public BlockType getType() { 58 | return type; 59 | } 60 | 61 | public int[] getTextures() { 62 | return textures; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/de/meinkraft/BlockTypePlant.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | import java.nio.FloatBuffer; 4 | 5 | import org.lwjgl.opengl.OpenGLException; 6 | 7 | public class BlockTypePlant extends BlockType { 8 | 9 | public BlockTypePlant(boolean solid, boolean both) { 10 | super(solid, both); 11 | } 12 | 13 | @Override 14 | public int getVerticesCount(Blockcheck check) { 15 | if(check.all()) 16 | return 0; 17 | else 18 | return 16; 19 | } 20 | 21 | @Override 22 | public void addVertices(float x, float y, float z, FloatBuffer buffer, Blockcheck check, BlockAO ao, int... textures) { 23 | if(textures.length != 1) 24 | throw new OpenGLException(getClass().getSimpleName() + " must have 1 texture"); 25 | 26 | if(!check.all()) { 27 | buffer.put(new float[] { 28 | x + 0, y + 0, z + 0, 0, 1, textures[0], getAO(false, false, false), 29 | x + 1, y + 0, z + 1, 1, 1, textures[0], getAO(false, false, false), 30 | x + 1, y + 1.4142f, z + 1, 1, 0, textures[0], getAO(false, false, false), 31 | x + 0, y + 1.4142f, z + 0, 0, 0, textures[0], getAO(false, false, false), 32 | 33 | x + 1, y + 0, z + 1, 1, 1, textures[0], getAO(false, false, false), 34 | x + 0, y + 0, z + 0, 0, 1, textures[0], getAO(false, false, false), 35 | x + 0, y + 1.4142f, z + 0, 0, 0, textures[0], getAO(false, false, false), 36 | x + 1, y + 1.4142f, z + 1, 1, 0, textures[0], getAO(false, false, false), 37 | 38 | x + 0, y + 0, z + 1, 0, 1, textures[0], getAO(false, false, false), 39 | x + 1, y + 0, z + 0, 1, 1, textures[0], getAO(false, false, false), 40 | x + 1, y + 1.4142f, z + 0, 1, 0, textures[0], getAO(false, false, false), 41 | x + 0, y + 1.4142f, z + 1, 0, 0, textures[0], getAO(false, false, false), 42 | 43 | x + 1, y + 0, z + 0, 1, 1, textures[0], getAO(false, false, false), 44 | x + 0, y + 0, z + 1, 0, 1, textures[0], getAO(false, false, false), 45 | x + 0, y + 1.4142f, z + 1, 0, 0, textures[0], getAO(false, false, false), 46 | x + 1, y + 1.4142f, z + 0, 1, 0, textures[0], getAO(false, false, false) 47 | }); 48 | } 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/de/meinkraft/gui/GUIObject.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft.gui; 2 | 3 | public abstract class GUIObject { 4 | 5 | /* 6 | * first 4 bits hold the orientation (where should the position set to? (relative to the object)) 0000xxxx 7 | * last 4 bits hold the alignment (where should the position align to?) xxxx0000 8 | */ 9 | private byte orientation; 10 | 11 | private float x, y; 12 | private int width, height; 13 | 14 | public GUIObject(float x, float y, int width, int height) { 15 | this.x = x; 16 | this.y = y; 17 | this.width = width; 18 | this.height = height; 19 | } 20 | 21 | protected void draw() { 22 | 23 | } 24 | 25 | public void setOrientationX(int x) { 26 | if(x < 0) x = 0; else if(x > 2) x = 2; 27 | 28 | orientation = (byte) ((orientation & 252) | (x & 3)); 29 | } 30 | 31 | public int getOrientationX() { 32 | return (orientation & 3) >> 0; 33 | } 34 | 35 | public void setOrientationY(int y) { 36 | if(y < 0) y = 0; else if(y > 2) y = 2; 37 | 38 | orientation = (byte) (orientation & 243 | (y & 3) << 2); 39 | } 40 | 41 | public int getOrientationY() { 42 | return (orientation & 12) >> 2; 43 | } 44 | 45 | public void setAlignmentX(int x) { 46 | if(x < 0) x = 0; else if(x > 2) x = 2; 47 | 48 | orientation = (byte) (orientation & 207 | (x & 3) << 4); 49 | } 50 | 51 | public int getAlignmentX() { 52 | return (orientation & 48) >> 4; 53 | } 54 | 55 | public void setAlignmentY(int y) { 56 | if(y < 0) y = 0; else if(y > 2) y = 2; 57 | 58 | orientation = (byte) (orientation & 63 | (y & 3) << 6); 59 | } 60 | 61 | public int getAlignmentY() { 62 | return (orientation & 192) >> 6; 63 | } 64 | 65 | public byte getOrientation() { 66 | return orientation; 67 | } 68 | 69 | public float getX() { 70 | return x; 71 | } 72 | 73 | public void setX(float x) { 74 | this.x = x; 75 | } 76 | 77 | public float getY() { 78 | return y; 79 | } 80 | 81 | public void setY(float y) { 82 | this.y = y; 83 | } 84 | 85 | public int getWidth() { 86 | return width; 87 | } 88 | 89 | public void setWidth(int width) { 90 | this.width = width; 91 | } 92 | 93 | public int getHeight() { 94 | return height; 95 | } 96 | 97 | public void setHeight(int height) { 98 | this.height = height; 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/de/meinkraft/WorldGeneratorNormal.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | public class WorldGeneratorNormal extends WorldGenerator { 4 | 5 | private OpenSimplexNoise osn0, osn1, osn2; 6 | 7 | public WorldGeneratorNormal() { 8 | osn0 = new OpenSimplexNoise(64, 0.1, 315123531234l); 9 | osn1 = new OpenSimplexNoise(30, 0.2, 315123531234l); 10 | osn2 = new OpenSimplexNoise(30, 0.2, 837538751238l); 11 | } 12 | 13 | @Override 14 | public void generate(Chunk chunk) { 15 | for(int x = 0; x < Chunk.SIZE_X; x++) 16 | for(int z = 0; z < Chunk.SIZE_Z; z++) { 17 | double v = osn0.getNoise((chunk.getX() * Chunk.SIZE_X + x), (chunk.getZ() * Chunk.SIZE_Z + z)) * 0.5 + 0.5; 18 | int h = (int) (Chunk.SIZE_Y * v); 19 | 20 | for(int y = 0; y < Chunk.SIZE_Y; y++) { 21 | if(y < h - 3) 22 | chunk.setBlockAt(x, y, z, Block.STONE); 23 | else if(y < h) 24 | chunk.setBlockAt(x, y, z, Block.DIRT); 25 | else if(y == h) 26 | chunk.setBlockAt(x, y, z, Block.GRASS); 27 | else 28 | chunk.setBlockAt(x, y, z, Block.AIR); 29 | } 30 | } 31 | 32 | for(int x = 0; x < Chunk.SIZE_X; x++) 33 | for(int z = 0; z < Chunk.SIZE_Z; z++) { 34 | for(int y = 0; y < Chunk.SIZE_Y; y++) { 35 | double v = osn1.getNoise((chunk.getX() * Chunk.SIZE_X + x), y / 1.5, (chunk.getZ() * Chunk.SIZE_Z + z)) * 0.5 + 0.5; 36 | double v2 = osn2.getNoise((chunk.getX() * Chunk.SIZE_X + x), y / 1.5, (chunk.getZ() * Chunk.SIZE_Z + z)) * 0.5 + 0.5; 37 | 38 | if(v > MIN && v < MAX && v2 > MIN && v2 < MAX) 39 | chunk.setBlockAt(x, y, z, Block.AIR); 40 | // else 41 | // chunk.setBlockAt(x, y, z, Block.AIR); 42 | 43 | // if(v > 0.50 && v < 0.51 && v2 > 0.50 && v2 < 0.51) 44 | // chunk.setBlockAt(x, y, z, Block.STONE); 45 | // else 46 | // chunk.setBlockAt(x, y, z, Block.AIR); 47 | } 48 | } 49 | } 50 | 51 | private final static double MIN = 0.52, MAX = 0.56; 52 | 53 | // @Override 54 | // public void generate(Chunk chunk) { 55 | // for(int x = 0; x < Chunk.SIZE_X; x++) 56 | // for(int z = 0; z < Chunk.SIZE_Z; z++) { 57 | // double v = osn.getNoise((chunk.getX() * Chunk.SIZE_X + x), (chunk.getZ() * Chunk.SIZE_Z + z)) * 0.5 + 0.5; 58 | // int h = (int) (Chunk.SIZE_Y * v); 59 | // 60 | // for(int y = 0; y < Chunk.SIZE_Y; y++) { 61 | // if(y < h - 3) 62 | // chunk.setBlockAt(x, y, z, Block.STONE); 63 | // else if(y < h) 64 | // chunk.setBlockAt(x, y, z, Block.DIRT); 65 | // else if(y == h) 66 | // chunk.setBlockAt(x, y, z, Block.GRASS); 67 | // else 68 | // chunk.setBlockAt(x, y, z, Block.AIR); 69 | // } 70 | // } 71 | // } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/de/meinkraft/lib/Display.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft.lib; 2 | 3 | import static org.lwjgl.glfw.GLFW.GLFW_RESIZABLE; 4 | import static org.lwjgl.glfw.GLFW.glfwCreateWindow; 5 | import static org.lwjgl.glfw.GLFW.glfwDestroyWindow; 6 | import static org.lwjgl.glfw.GLFW.glfwInit; 7 | import static org.lwjgl.glfw.GLFW.glfwMakeContextCurrent; 8 | import static org.lwjgl.glfw.GLFW.glfwSetErrorCallback; 9 | import static org.lwjgl.glfw.GLFW.glfwSetWindowSizeCallback; 10 | import static org.lwjgl.glfw.GLFW.glfwSetWindowTitle; 11 | import static org.lwjgl.glfw.GLFW.glfwSwapInterval; 12 | import static org.lwjgl.glfw.GLFW.glfwTerminate; 13 | import static org.lwjgl.glfw.GLFW.glfwWindowHint; 14 | 15 | import org.lwjgl.glfw.Callbacks; 16 | import org.lwjgl.glfw.GLFWErrorCallback; 17 | import org.lwjgl.glfw.GLFWWindowSizeCallback; 18 | import org.lwjgl.opengl.GLContext; 19 | 20 | public class Display { 21 | 22 | private static int WIDTH, HEIGHT; 23 | private static long WINDOW; 24 | 25 | private static GLFWErrorCallback errorCallback; 26 | private static GLFWWindowSizeCallback windowSizeCallback; 27 | 28 | private static boolean resized; 29 | 30 | public static void create(int w, int h, String t) { 31 | WIDTH = w; 32 | HEIGHT = h; 33 | 34 | glfwSetErrorCallback(errorCallback = Callbacks.errorCallbackPrint(System.err)); 35 | 36 | if(glfwInit() == 0) 37 | throw new RuntimeException("Unable to initialize GLFW"); 38 | 39 | glfwWindowHint(GLFW_RESIZABLE, 1); 40 | 41 | WINDOW = glfwCreateWindow(w, h, t, 0, 0); 42 | 43 | glfwMakeContextCurrent(WINDOW); 44 | GLContext.createFromCurrent(); 45 | 46 | glfwSwapInterval(1); 47 | setupCallbacks(); 48 | } 49 | 50 | public static void destory() { 51 | glfwDestroyWindow(WINDOW); 52 | windowSizeCallback.release(); 53 | glfwTerminate(); 54 | errorCallback.release(); 55 | } 56 | 57 | private static void setupCallbacks() { 58 | glfwSetWindowSizeCallback(Display.WINDOW, windowSizeCallback = new GLFWWindowSizeCallback() { 59 | 60 | @Override 61 | public void invoke(long window, int width, int height) { 62 | WIDTH = width; 63 | HEIGHT = height; 64 | 65 | resized = true; 66 | } 67 | 68 | }); 69 | } 70 | 71 | public static int getWidth() { 72 | return WIDTH; 73 | } 74 | 75 | public static int getHeight() { 76 | return HEIGHT; 77 | } 78 | 79 | public static long getWindow() { 80 | return WINDOW; 81 | } 82 | 83 | public static boolean wasResized() { 84 | if(resized) { 85 | resized = false; 86 | return true; 87 | } else 88 | return false; 89 | } 90 | 91 | public static void setTitle(String title) { 92 | glfwSetWindowTitle(WINDOW, title); 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/de/meinkraft/lib/VAO.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft.lib; 2 | 3 | import static org.lwjgl.opengl.GL11.glDrawElements; 4 | import static org.lwjgl.opengl.GL11.GL_FLOAT; 5 | import static org.lwjgl.opengl.GL11.GL_UNSIGNED_INT; 6 | import static org.lwjgl.opengl.GL15.glBindBuffer; 7 | import static org.lwjgl.opengl.GL15.glBufferData; 8 | import static org.lwjgl.opengl.GL15.glBufferSubData; 9 | import static org.lwjgl.opengl.GL15.glGenBuffers; 10 | import static org.lwjgl.opengl.GL15.glDeleteBuffers; 11 | import static org.lwjgl.opengl.GL15.GL_ARRAY_BUFFER; 12 | import static org.lwjgl.opengl.GL15.GL_STATIC_DRAW; 13 | import static org.lwjgl.opengl.GL15.GL_ELEMENT_ARRAY_BUFFER; 14 | import static org.lwjgl.opengl.GL20.glEnableVertexAttribArray; 15 | import static org.lwjgl.opengl.GL20.glVertexAttribPointer; 16 | import static org.lwjgl.opengl.GL30.glBindVertexArray; 17 | import static org.lwjgl.opengl.GL30.glDeleteVertexArrays; 18 | import static org.lwjgl.opengl.GL30.glGenVertexArrays; 19 | 20 | import java.nio.FloatBuffer; 21 | import java.nio.IntBuffer; 22 | 23 | public class VAO { 24 | 25 | private final int mode; 26 | private final int vaoID; 27 | private final int vboID; 28 | private final int iboID; 29 | 30 | public VAO(int mode) { 31 | this.mode = mode; 32 | this.vaoID = glGenVertexArrays(); 33 | this.vboID = glGenBuffers(); 34 | this.iboID = glGenBuffers(); 35 | } 36 | 37 | /** 38 | * @param values - "SIZE STRIDE OFFSET" 39 | */ 40 | public void initVAO(String...attributes) { 41 | glBindVertexArray(vaoID); 42 | glBindBuffer(GL_ARRAY_BUFFER, vboID); 43 | 44 | for(int i = 0; i < attributes.length; i++) { 45 | String[] values = attributes[i].split(" "); 46 | 47 | glEnableVertexAttribArray(i); 48 | glVertexAttribPointer(i, Integer.valueOf(values[0]), GL_FLOAT, false, 4 * Integer.valueOf(values[1]), 4 * Integer.valueOf(values[2])); 49 | } 50 | 51 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID); 52 | glBindVertexArray(0); 53 | } 54 | 55 | public void initVBO(FloatBuffer buffer) { 56 | glBindBuffer(GL_ARRAY_BUFFER, vboID); 57 | glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW); 58 | glBindBuffer(GL_ARRAY_BUFFER, 0); 59 | } 60 | 61 | public void updateVBO(FloatBuffer buffer, long offset) { 62 | glBindBuffer(GL_ARRAY_BUFFER, vboID); 63 | glBufferSubData(GL_ARRAY_BUFFER, 4 * offset, buffer); 64 | glBindBuffer(GL_ARRAY_BUFFER, 0); 65 | } 66 | 67 | public void initIBO(IntBuffer buffer) { 68 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID); 69 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, buffer, GL_STATIC_DRAW); 70 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 71 | } 72 | 73 | public void render(int indices_count, int indices_offset) { 74 | glBindVertexArray(vaoID); 75 | glDrawElements(mode, indices_count, GL_UNSIGNED_INT, 4 * indices_offset); 76 | glBindVertexArray(0); 77 | } 78 | 79 | public void delete() { 80 | glDeleteBuffers(vboID); 81 | glDeleteBuffers(iboID); 82 | glDeleteVertexArrays(vaoID); 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/de/meinkraft/BlockTypeCube.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | import java.nio.FloatBuffer; 4 | 5 | import org.lwjgl.opengl.OpenGLException; 6 | 7 | public class BlockTypeCube extends BlockType { 8 | 9 | public BlockTypeCube(boolean solid, boolean both) { 10 | super(solid, both); 11 | } 12 | 13 | @Override 14 | public int getVerticesCount(Blockcheck check) { 15 | int count = 0; 16 | 17 | if(!check.north) 18 | count += 4; 19 | 20 | if(!check.east) 21 | count += 4; 22 | 23 | if(!check.south) 24 | count += 4; 25 | 26 | if(!check.west) 27 | count += 4; 28 | 29 | if(!check.top) 30 | count += 4; 31 | 32 | if(!check.bottom) 33 | count += 4; 34 | 35 | return count; 36 | } 37 | 38 | @Override 39 | public void addVertices(float x, float y, float z, FloatBuffer buffer, Blockcheck check, BlockAO ao, int...textures) { 40 | if(textures.length != 6) 41 | throw new OpenGLException(getClass().getSimpleName() + " must have 6 textures"); 42 | 43 | if(!check.north) 44 | buffer.put(new float[] { 45 | x + 0, y + 0, z + 0, 1, 1, textures[0], getAO(ao.nB, ao.wB, ao.c_X_Y_Z), 46 | x + 0, y + 1, z + 0, 1, 0, textures[0], getAO(ao.nT, ao.wT, ao.c_XY_Z), 47 | x + 1, y + 1, z + 0, 0, 0, textures[0], getAO(ao.nT, ao.eT, ao.cXY_Z), 48 | x + 1, y + 0, z + 0, 0, 1, textures[0], getAO(ao.nB, ao.eB, ao.cX_Y_Z) 49 | }); 50 | 51 | if(!check.east) 52 | buffer.put(new float[] { 53 | x + 1, y + 0, z + 1, 0, 1, textures[1], getAO(ao.eB, ao.sB, ao.cX_YZ), 54 | x + 1, y + 0, z + 0, 1, 1, textures[1], getAO(ao.eB, ao.nB, ao.cX_Y_Z), 55 | x + 1, y + 1, z + 0, 1, 0, textures[1], getAO(ao.eT, ao.nT, ao.cXY_Z), 56 | x + 1, y + 1, z + 1, 0, 0, textures[1], getAO(ao.eT, ao.sT, ao.cXYZ) 57 | }); 58 | 59 | if(!check.south) 60 | buffer.put(new float[] { 61 | x + 0, y + 0, z + 1, 0, 1, textures[2], getAO(ao.sB, ao.wB, ao.c_X_YZ), 62 | x + 1, y + 0, z + 1, 1, 1, textures[2], getAO(ao.sB, ao.eB, ao.cX_YZ), 63 | x + 1, y + 1, z + 1, 1, 0, textures[2], getAO(ao.sT, ao.eT, ao.cXYZ), 64 | x + 0, y + 1, z + 1, 0, 0, textures[2], getAO(ao.sT, ao.wT, ao.c_XYZ) 65 | }); 66 | 67 | if(!check.west) 68 | buffer.put(new float[] { 69 | x + 0, y + 0, z + 0, 0, 1, textures[3], getAO(ao.wB, ao.nB, ao.c_X_Y_Z), 70 | x + 0, y + 0, z + 1, 1, 1, textures[3], getAO(ao.wB, ao.sB, ao.c_X_YZ), 71 | x + 0, y + 1, z + 1, 1, 0, textures[3], getAO(ao.wT, ao.sT, ao.c_XYZ), 72 | x + 0, y + 1, z + 0, 0, 0, textures[3], getAO(ao.wT, ao.nT, ao.c_XY_Z) 73 | }); 74 | 75 | if(!check.top) 76 | buffer.put(new float[] { 77 | x + 0, y + 1, z + 1, 0, 1, textures[4], getAO(ao.wT, ao.sT, ao.c_XYZ), 78 | x + 1, y + 1, z + 1, 1, 1, textures[4], getAO(ao.sT, ao.eT, ao.cXYZ), 79 | x + 1, y + 1, z + 0, 1, 0, textures[4], getAO(ao.eT, ao.nT, ao.cXY_Z), 80 | x + 0, y + 1, z + 0, 0, 0, textures[4], getAO(ao.nT, ao.wT, ao.c_XY_Z) 81 | }); 82 | 83 | if(!check.bottom) 84 | buffer.put(new float[] { 85 | x + 0, y + 0, z + 1, 0, 1, textures[5], getAO(ao.sB, ao.wB, ao.c_X_YZ), 86 | x + 0, y + 0, z + 0, 0, 0, textures[5], getAO(ao.wB, ao.nB, ao.c_X_Y_Z), 87 | x + 1, y + 0, z + 0, 1, 0, textures[5], getAO(ao.nB, ao.eB, ao.cX_Y_Z), 88 | x + 1, y + 0, z + 1, 1, 1, textures[5], getAO(ao.eB, ao.sB, ao.cX_YZ) 89 | }); 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/de/meinkraft/Chunk.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | import static org.lwjgl.opengl.GL11.GL_TRIANGLES; 4 | 5 | import java.nio.FloatBuffer; 6 | import java.nio.IntBuffer; 7 | 8 | import de.meinkraft.lib.VAO; 9 | 10 | public class Chunk { 11 | 12 | public static final int SIZE_X = 16, SIZE_Y = 128, SIZE_Z = 16; 13 | 14 | private final Block[][][] blocks; 15 | private final short[][][] lights; 16 | 17 | private VAO vao; 18 | public FloatBuffer vertices; 19 | public IntBuffer indices; 20 | private int solidBlocks; 21 | 22 | private boolean doLoad; 23 | 24 | private final int x, z; 25 | private ChunkState state; 26 | 27 | public Chunk(int x, int z) { 28 | this.x = x; 29 | this.z = z; 30 | this.state = ChunkState.UNLOADED; 31 | 32 | blocks = new Block[SIZE_X][SIZE_Y][SIZE_Z]; 33 | lights = new short[SIZE_X][SIZE_Y][SIZE_Z]; 34 | } 35 | 36 | public void update() { 37 | if(doLoad) 38 | load(); 39 | } 40 | 41 | public void render() { 42 | if(isLoaded()) 43 | vao.render(solidBlocks, 0); 44 | } 45 | 46 | public void load() { 47 | if(vao == null) 48 | vao = new VAO(GL_TRIANGLES); 49 | 50 | vao.initVBO(vertices); 51 | vao.initIBO(indices); 52 | vao.initVAO("3 7 0", "3 7 3", "1 7 6"); 53 | 54 | solidBlocks = indices.limit(); 55 | doLoad = false; 56 | state = ChunkState.LOADED; 57 | } 58 | 59 | public void unload() { 60 | if(isLoaded()) 61 | vao.delete(); 62 | 63 | vao = null; 64 | vertices = null; 65 | indices = null; 66 | state = ChunkState.UNLOADED; 67 | } 68 | 69 | public void deleteBlocks() { 70 | for(int x = 0; x < Chunk.SIZE_X; x++) 71 | for(int y = 0; y < Chunk.SIZE_Y; y++) 72 | for(int z = 0; z < Chunk.SIZE_Z; z++) { 73 | blocks[x][y][z] = null; 74 | } 75 | } 76 | 77 | public boolean isGenerated() { 78 | return blocks[SIZE_X - 1][SIZE_Y - 1][SIZE_Z - 1] != null; 79 | } 80 | 81 | public boolean isLoaded() { 82 | return vao != null; 83 | } 84 | 85 | public int getSkyLight(int x, int y, int z) { 86 | return lights[x][y][z] >> 12; 87 | } 88 | 89 | public void setSkyLight(int x, int y, int z, int value) { 90 | if(value < 0) value = 0; else if(value > 15) value = 15; 91 | 92 | lights[x][y][z] = (short) (lights[x][y][z] & 0x0FFF | value << 12); 93 | } 94 | 95 | public int getVoxelLightR(int x, int y, int z) { 96 | return lights[x][y][z] & 0x0F00 >> 8; 97 | } 98 | 99 | public int getVoxelLightG(int x, int y, int z) { 100 | return lights[x][y][z] & 0x00F0 >> 4; 101 | } 102 | 103 | public int getVoxelLightB(int x, int y, int z) { 104 | return lights[x][y][z] & 0x000F >> 0; 105 | } 106 | 107 | public void setVoxelLight(int x, int y, int z, int r, int g, int b) { 108 | if(r < 0) r = 0; else if(r > 15) r = 15; 109 | if(g < 0) g = 0; else if(g > 15) g = 15; 110 | if(b < 0) b = 0; else if(b > 15) b = 15; 111 | 112 | lights[x][y][z] = (short) (lights[x][y][z] & 0xF000 | r << 8 | g << 4 | b << 0); 113 | } 114 | 115 | public Block getBlockAt(int x, int y, int z) { 116 | if(isGenerated() && x >= 0 && x < SIZE_X && y >= 0 && y < SIZE_Y && z >= 0 && z < SIZE_Z) 117 | return blocks[x][y][z]; 118 | 119 | return Block.AIR; // temp 120 | } 121 | 122 | public void setBlockAt(int x, int y, int z, Block block) { 123 | if(x >= 0 && x < SIZE_X && y >= 0 && y < SIZE_Y && z >= 0 && z < SIZE_Z) 124 | blocks[x][y][z] = block; 125 | } 126 | 127 | public void doLoad() { 128 | doLoad = true; 129 | } 130 | 131 | public ChunkState getState() { 132 | return state; 133 | } 134 | 135 | public void setState(ChunkState state) { 136 | this.state = state; 137 | } 138 | 139 | public int getX() { 140 | return x; 141 | } 142 | 143 | public int getZ() { 144 | return z; 145 | } 146 | 147 | } 148 | -------------------------------------------------------------------------------- /src/de/meinkraft/lib/Input.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft.lib; 2 | 3 | import static org.lwjgl.glfw.GLFW.GLFW_CURSOR; 4 | import static org.lwjgl.glfw.GLFW.GLFW_PRESS; 5 | import static org.lwjgl.glfw.GLFW.GLFW_RELEASE; 6 | import static org.lwjgl.glfw.GLFW.glfwGetClipboardString; 7 | import static org.lwjgl.glfw.GLFW.glfwGetCursorPos; 8 | import static org.lwjgl.glfw.GLFW.glfwGetInputMode; 9 | import static org.lwjgl.glfw.GLFW.glfwGetKey; 10 | import static org.lwjgl.glfw.GLFW.glfwGetMouseButton; 11 | import static org.lwjgl.glfw.GLFW.glfwSetClipboardString; 12 | import static org.lwjgl.glfw.GLFW.glfwSetCursorPos; 13 | import static org.lwjgl.glfw.GLFW.glfwSetInputMode; 14 | import static org.lwjgl.glfw.GLFW.glfwSetScrollCallback; 15 | 16 | import java.nio.DoubleBuffer; 17 | 18 | import org.lwjgl.BufferUtils; 19 | import org.lwjgl.glfw.GLFWScrollCallback; 20 | 21 | public class Input { 22 | 23 | private static final boolean[] KEY_BUTTONS = new boolean[349]; 24 | private static final boolean[] MOUSE_BUTTONS = new boolean[8]; 25 | 26 | private static GLFWScrollCallback scrollCallback; 27 | static { 28 | glfwSetScrollCallback(Display.getWindow(), scrollCallback = new GLFWScrollCallback() { 29 | 30 | @Override 31 | public void invoke(long window, double xoffset, double yoffset) { 32 | mouseWheel = (int) yoffset; 33 | scrolled = true; 34 | } 35 | 36 | }); 37 | } 38 | private static int mouseWheel; 39 | private static boolean scrolled; 40 | 41 | private static int lastMouseX = (int) getMousePos().getX(); 42 | private static int lastMouseY = (int) getMousePos().getY(); 43 | 44 | private static int mouseDX; 45 | private static int mouseDY; 46 | 47 | public static void update() { 48 | for(int i = 0; i < KEY_BUTTONS.length; i++) 49 | KEY_BUTTONS[i] = getKey(i); 50 | 51 | for(int i = 0; i < MOUSE_BUTTONS.length; i++) 52 | MOUSE_BUTTONS[i] = getMouse(i); 53 | 54 | int mouseX = (int) getMousePos().getX(); 55 | int mouseY = (int) getMousePos().getY(); 56 | 57 | mouseDX = mouseX - lastMouseX; 58 | mouseDY = mouseY - lastMouseY; 59 | 60 | lastMouseX = mouseX; 61 | lastMouseY = mouseY; 62 | 63 | scrolled = false; 64 | } 65 | 66 | public static void destroy() { 67 | if(scrollCallback != null) 68 | scrollCallback.release(); 69 | } 70 | 71 | public static boolean getKey(int key) { 72 | return glfwGetKey(Display.getWindow(), key) == GLFW_PRESS; 73 | } 74 | 75 | public static boolean getKeyDown(int key) { 76 | return !KEY_BUTTONS[key] && glfwGetKey(Display.getWindow(), key) == GLFW_PRESS; 77 | } 78 | 79 | public static boolean getKeyUp(int key) { 80 | return KEY_BUTTONS[key] && glfwGetKey(Display.getWindow(), key) == GLFW_RELEASE; 81 | } 82 | 83 | public static boolean getMouse(int mouse) { 84 | return glfwGetMouseButton(Display.getWindow(), mouse) == GLFW_PRESS; 85 | } 86 | 87 | public static boolean getMouseDown(int mouse) { 88 | return !MOUSE_BUTTONS[mouse] && glfwGetMouseButton(Display.getWindow(), mouse) == GLFW_PRESS; 89 | } 90 | 91 | public static boolean getMouseUp(int mouse) { 92 | return MOUSE_BUTTONS[mouse] && glfwGetMouseButton(Display.getWindow(), mouse) == GLFW_RELEASE; 93 | } 94 | 95 | public static int getMouseDX() { 96 | return mouseDX; 97 | } 98 | 99 | public static int getMouseDY() { 100 | return mouseDY; 101 | } 102 | 103 | public static int getMouseWheel() { 104 | return scrolled ? mouseWheel : 0; 105 | } 106 | 107 | public static int getCursorMode() { 108 | return glfwGetInputMode(Display.getWindow(), GLFW_CURSOR); 109 | } 110 | 111 | public static void setCursorMode(int mode) { 112 | glfwSetInputMode(Display.getWindow(), GLFW_CURSOR, mode); 113 | } 114 | 115 | public static Vector2 getMousePos() { 116 | DoubleBuffer x = BufferUtils.createDoubleBuffer(1), y = BufferUtils.createDoubleBuffer(1); 117 | 118 | glfwGetCursorPos(Display.getWindow(), x, y); 119 | 120 | return new Vector2((float) x.get(), (float) y.get()); 121 | } 122 | 123 | public static void setMousePos(int x, int y) { 124 | glfwSetCursorPos(Display.getWindow(), x, y); 125 | } 126 | 127 | public static String getClipboard() { 128 | return glfwGetClipboardString(Display.getWindow()); 129 | } 130 | 131 | public static void setClipboard(String str) { 132 | glfwSetClipboardString(Display.getWindow(), str); 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /src/de/meinkraft/Meinkraft.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | import static org.lwjgl.glfw.GLFW.GLFW_KEY_F; 4 | import static org.lwjgl.glfw.GLFW.GLFW_KEY_P; 5 | import static org.lwjgl.glfw.GLFW.GLFW_KEY_R; 6 | import static org.lwjgl.opengl.GL11.*; 7 | import static org.lwjgl.opengl.GL12.GL_CLAMP_TO_EDGE; 8 | 9 | import java.io.IOException; 10 | import java.util.Locale; 11 | 12 | import de.meinkraft.gui.GUI; 13 | import de.meinkraft.gui.GUIFont; 14 | import de.meinkraft.gui.GUILabel; 15 | import de.meinkraft.lib.Camera; 16 | import de.meinkraft.lib.Display; 17 | import de.meinkraft.lib.Input; 18 | import de.meinkraft.lib.Matrix4; 19 | import de.meinkraft.lib.Shader; 20 | import de.meinkraft.lib.Texture; 21 | import de.meinkraft.lib.Time; 22 | import de.meinkraft.lib.Transform; 23 | import de.meinkraft.lib.Utils; 24 | 25 | public class Meinkraft { 26 | 27 | private Camera camera; 28 | private int textures; 29 | private Shader shader; 30 | 31 | private GUILabel guiText; 32 | 33 | private boolean fog; 34 | 35 | private World world; 36 | 37 | public Meinkraft() { 38 | camera = new Camera(new Matrix4().initPerspective(70f, (float) Display.getWidth() / (float) Display.getHeight(), 0.01f, 1000f)); 39 | 40 | try { 41 | textures = Texture.loadTexture2DArray(Utils.getResourceAsStream("/terrain.png"), 64, 64, GL_NEAREST, GL_NEAREST, GL_CLAMP_TO_EDGE); 42 | } catch (IOException e1) { 43 | e1.printStackTrace(); 44 | } 45 | try { 46 | shader = Shader.loadShader("/shader.vs", "/shader.fs", null); 47 | shader.addUniform("p"); 48 | shader.addUniform("v"); 49 | shader.addUniform("m"); 50 | shader.addUniform("enableFog"); 51 | 52 | shader.bind(); 53 | shader.setUniform("p", camera.getProjectionMatrix()); 54 | shader.setUniform("m", new Transform().getTransformationMatrix()); 55 | shader.setUniform("enableFog", 0); 56 | 57 | Shader.unbind(); 58 | } catch (IOException e) { 59 | e.printStackTrace(); 60 | } 61 | 62 | guiText = new GUILabel(0.5f, 0.05f, 200, 50); 63 | guiText.setOrientationX(1); 64 | guiText.setOrientationY(0); 65 | 66 | world = new World("World", new WorldGeneratorFlat()); 67 | } 68 | 69 | public void input() { 70 | camera.input(); 71 | 72 | if(Input.getKeyDown(GLFW_KEY_F)) { 73 | shader.bind(); 74 | shader.setUniform("enableFog", fog ? 0 : 1); 75 | fog = !fog; 76 | Shader.unbind(); 77 | } 78 | 79 | if(Input.getKeyDown(GLFW_KEY_P)) { 80 | try { 81 | StructureLoader.loadStructure(world, (int) Math.floor(-camera.getTransform().getTranslation().getX()), 64, (int) Math.floor(-camera.getTransform().getTranslation().getZ()), Utils.getResourceAsStream("/structure_house.txt")); 82 | } catch (IOException e) { 83 | // TODO Auto-generated catch block 84 | e.printStackTrace(); 85 | } 86 | } 87 | 88 | // for debug 89 | if(Input.getKeyDown(GLFW_KEY_R)) { 90 | world.setWorldGenerator(new WorldGeneratorNormal()); 91 | world.getChunkManager().regenerate(); 92 | } 93 | } 94 | 95 | public void update() { 96 | // temp 97 | world.getPlayer().pos = camera.getTransform().getTranslation().negate(); 98 | world.getPlayer().dir = camera.getDirection().negate(); 99 | world.update(); 100 | 101 | Display.setTitle("FPS " + String.format(Locale.ENGLISH, "%.2f", 1.0f / Time.getDelta()) + " cx:" + world.getChunkManager().getPlayerChunkPositionX() + " cz:" + world.getChunkManager().getPlayerChunkPositionZ()); 102 | if(Display.wasResized()) { 103 | camera.getProjectionMatrix().initPerspective(70f, (float) Display.getWidth() / (float) Display.getHeight(), 0.01f, 1000f); 104 | GUI.ORTHO.initOrthographic(0, Display.getWidth(), 0, Display.getHeight(), -1, 1); 105 | 106 | shader.bind(); 107 | shader.setUniform("p", camera.getProjectionMatrix()); 108 | 109 | GUI.SHADER.bind(); 110 | GUI.SHADER.setUniform("p", GUI.ORTHO); 111 | GUIFont.SHADER.bind(); 112 | GUIFont.SHADER.setUniform("p", GUI.ORTHO); 113 | Shader.unbind(); 114 | 115 | glViewport(0, 0, Display.getWidth(), Display.getHeight()); 116 | } 117 | } 118 | 119 | public void render() { 120 | shader.bind(); 121 | shader.setUniform("v", camera.getViewMatrix()); 122 | Texture.bindTexture2DArray(textures); 123 | world.render(); 124 | 125 | glCullFace(GL_FRONT); 126 | guiText.draw(); 127 | GUILabel.font.drawString("BlA", 0, 0); 128 | glCullFace(GL_BACK); 129 | 130 | Shader.unbind(); 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /src/de/meinkraft/gui/GUIFont.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft.gui; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStreamReader; 6 | 7 | import de.meinkraft.lib.Shader; 8 | import de.meinkraft.lib.Texture; 9 | import de.meinkraft.lib.Transform; 10 | import de.meinkraft.lib.Utils; 11 | import de.meinkraft.lib.Vector3; 12 | import static org.lwjgl.opengl.GL11.*; 13 | import static org.lwjgl.opengl.GL12.*; 14 | import static org.lwjgl.opengl.GL20.*; 15 | 16 | public class GUIFont { 17 | 18 | public static Shader SHADER; 19 | static { 20 | try { 21 | SHADER = Shader.loadShader("/font.vs", "/font.fs", null); 22 | SHADER.addUniform("p"); 23 | SHADER.addUniform("v"); 24 | SHADER.addUniform("m"); 25 | SHADER.addUniform("size"); 26 | 27 | SHADER.bind(); 28 | SHADER.setUniform("p", GUI.ORTHO); 29 | SHADER.setUniform("v", new Transform().getTransformationMatrix()); 30 | SHADER.setUniform("m", new Transform().getTransformationMatrix()); 31 | SHADER.setUniform("size", 1.0f); 32 | Shader.unbind(); 33 | } catch (IOException e) { 34 | e.printStackTrace(); 35 | } 36 | } 37 | 38 | private GUIFontCharacter[] chars; 39 | private int atlas; 40 | private int fontsize; 41 | private Vector3 color; 42 | 43 | public GUIFont(String name, int size) { 44 | chars = new GUIFontCharacter[256]; 45 | 46 | BufferedReader bR = new BufferedReader(new InputStreamReader(Utils.getResourceAsStream("/" + name + ".fnt"))); 47 | String line; 48 | try { 49 | while((line = bR.readLine()) != null) { 50 | line = line.replaceAll("\\s+", " "); 51 | 52 | if(line.startsWith("char ")) { 53 | String[] meta = line.split(" "); 54 | chars[Integer.parseInt(meta[1].split("=")[1])] = new GUIFontCharacter(Integer.parseInt(meta[2].split("=")[1]), Integer.parseInt(meta[3].split("=")[1]), Integer.parseInt(meta[4].split("=")[1]), Integer.parseInt(meta[5].split("=")[1]), Integer.parseInt(meta[6].split("=")[1]), Integer.parseInt(meta[7].split("=")[1]), Integer.parseInt(meta[8].split("=")[1])); 55 | } else if(line.startsWith("info ")) 56 | fontsize = Integer.parseInt(line.substring(line.indexOf("size=")).split(" ")[0].split("=")[1]); 57 | } 58 | } catch (IOException e) { 59 | e.printStackTrace(); 60 | } 61 | 62 | try { 63 | atlas = Texture.loadTexture2D(Utils.getResourceAsStream("/" + name + ".png"), GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_CLAMP_TO_EDGE); 64 | } catch (IOException e) { 65 | e.printStackTrace(); 66 | } 67 | 68 | setSize(size); 69 | color = new Vector3(); 70 | } 71 | 72 | public void drawString(String text, int x, int y) { 73 | int adv = 0; 74 | 75 | // glEnable(GL_BLEND); 76 | // glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 77 | 78 | SHADER.bind(); 79 | Texture.bindTexture2D(atlas); 80 | glBegin(GL_QUADS); 81 | { 82 | glVertexAttrib3f(2, color.getX(), color.getY(), color.getZ()); 83 | 84 | for(char c : text.toCharArray()) { 85 | GUIFontCharacter gfc = chars[(int) c]; 86 | 87 | glVertexAttrib2f(1, gfc.getX() / 512.0f, gfc.getY() / 512.0f); 88 | glVertex2f(adv + gfc.getXoff() + x, gfc.getYoff() + y - 8); 89 | 90 | glVertexAttrib2f(1, (gfc.getX() + gfc.getW()) / 512.0f, gfc.getY() / 512.0f); 91 | glVertex2f(adv + gfc.getXoff() + x + gfc.getW(), gfc.getYoff() + y - 8); 92 | 93 | glVertexAttrib2f(1, (gfc.getX() + gfc.getW()) / 512.0f, (gfc.getY() + gfc.getH()) / 512.0f); 94 | glVertex2f(adv + gfc.getXoff() + x + gfc.getW(), gfc.getYoff() + y + gfc.getH() - 8); 95 | 96 | glVertexAttrib2f(1, gfc.getX() / 512.0f, (gfc.getY() + gfc.getH()) / 512.0f); 97 | glVertex2f(adv + gfc.getXoff() + x, gfc.getYoff() + y + gfc.getH() - 8); 98 | 99 | adv += gfc.getXadv() - 16; // padding left & right 100 | } 101 | } 102 | glEnd(); 103 | } 104 | 105 | public int getWidth(String text) { 106 | int width = 0; 107 | 108 | for(char c : text.toCharArray()) { 109 | GUIFontCharacter gfc = chars[(int) c]; 110 | 111 | width += gfc.getW() + gfc.getXoff(); 112 | } 113 | 114 | return width; 115 | } 116 | 117 | public void setSize(int size) { 118 | SHADER.bind(); 119 | SHADER.setUniform("m", new Transform(new Vector3(), new Vector3(), new Vector3((float) size / fontsize)).getTransformationMatrix()); 120 | 121 | float fs = (float) size / fontsize; 122 | 123 | if(fs < 1) 124 | fs = 0.8f; 125 | 126 | SHADER.setUniform("size", fs); 127 | Shader.unbind(); 128 | } 129 | 130 | public void setColor(Vector3 color) { 131 | this.color = color; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/de/meinkraft/lib/Camera.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft.lib; 2 | 3 | import static org.lwjgl.glfw.GLFW.GLFW_CURSOR_DISABLED; 4 | import static org.lwjgl.glfw.GLFW.GLFW_CURSOR_NORMAL; 5 | import static org.lwjgl.glfw.GLFW.GLFW_KEY_A; 6 | import static org.lwjgl.glfw.GLFW.GLFW_KEY_D; 7 | import static org.lwjgl.glfw.GLFW.GLFW_KEY_E; 8 | import static org.lwjgl.glfw.GLFW.GLFW_KEY_ESCAPE; 9 | import static org.lwjgl.glfw.GLFW.GLFW_KEY_LEFT_SHIFT; 10 | import static org.lwjgl.glfw.GLFW.GLFW_KEY_Q; 11 | import static org.lwjgl.glfw.GLFW.GLFW_KEY_S; 12 | import static org.lwjgl.glfw.GLFW.GLFW_KEY_W; 13 | import static org.lwjgl.glfw.GLFW.GLFW_MOUSE_BUTTON_1; 14 | 15 | public class Camera implements InputController { 16 | 17 | public static final float MOV_SPEED = 5; 18 | public static final float ROT_SPEED = 0.1f; 19 | 20 | private boolean lockMov, lockRot; 21 | 22 | private Matrix4 projection; 23 | private Transform transform; 24 | 25 | public Camera(Matrix4 projection) { 26 | this.projection = projection; 27 | this.transform = new Transform(); 28 | } 29 | 30 | @Override 31 | public void input() { 32 | if(Input.getCursorMode() == GLFW_CURSOR_DISABLED) { 33 | if(Input.getKeyDown(GLFW_KEY_ESCAPE)) { 34 | Input.setCursorMode(GLFW_CURSOR_NORMAL); 35 | Input.setMousePos(Display.getWidth() / 2, Display.getHeight() / 2); 36 | } else { 37 | if(!lockMov) { 38 | Vector3 forward = getDirection(); 39 | Vector3 sideward = new Vector3(getViewMatrix().get(0, 0), getViewMatrix().get(0, 1), getViewMatrix().get(0, 2)); 40 | 41 | float MOV_SPEED = Camera.MOV_SPEED; 42 | if(Input.getKey(GLFW_KEY_LEFT_SHIFT)) 43 | MOV_SPEED *= 15; 44 | 45 | if(Input.getKey(GLFW_KEY_W)) 46 | transform.setTranslation(transform.getTranslation().add(forward.mul(MOV_SPEED * Time.getDelta()))); 47 | 48 | if(Input.getKey(GLFW_KEY_S)) 49 | transform.setTranslation(transform.getTranslation().add(forward.mul(-MOV_SPEED * Time.getDelta()))); 50 | 51 | if(Input.getKey(GLFW_KEY_A)) 52 | transform.setTranslation(transform.getTranslation().add(sideward.mul(MOV_SPEED * Time.getDelta()))); 53 | 54 | if(Input.getKey(GLFW_KEY_D)) 55 | transform.setTranslation(transform.getTranslation().add(sideward.mul(-MOV_SPEED * Time.getDelta()))); 56 | 57 | if(Input.getKey(GLFW_KEY_Q)) 58 | transform.setTranslation(transform.getTranslation().add(new Vector3(0, -MOV_SPEED, 0).mul(Time.getDelta()))); 59 | 60 | if(Input.getKey(GLFW_KEY_E)) 61 | transform.setTranslation(transform.getTranslation().add(new Vector3(0, MOV_SPEED, 0).mul(Time.getDelta()))); 62 | } 63 | 64 | if(!lockRot) { 65 | int x = Input.getMouseDX(); 66 | int y = Input.getMouseDY(); 67 | 68 | if(x != 0) 69 | transform.getRotation().setY(transform.getRotation().getY() + (float) x * ROT_SPEED); 70 | 71 | if(y != 0) 72 | transform.getRotation().setX(transform.getRotation().getX() + (float) y * ROT_SPEED); 73 | } 74 | } 75 | } else if(Input.getCursorMode() == GLFW_CURSOR_NORMAL) { 76 | if(Input.getMouseDown(GLFW_MOUSE_BUTTON_1)) 77 | Input.setCursorMode(GLFW_CURSOR_DISABLED); 78 | } 79 | } 80 | 81 | public void update() { 82 | // // AUDIO 83 | // alListener(AL_POSITION, transform.getTranslation().negate().asFloatBuffer()); 84 | // alListener(AL_VELOCITY, new Vector3().asFloatBuffer()); 85 | // 86 | // Vector3 at = getViewMatrix().zVector3().negate(); 87 | // Vector3 up = getViewMatrix().yVector3(); 88 | // FloatBuffer buffer = BufferUtils.createFloatBuffer(6).put(new float[] {at.getX(), at.getY(), at.getZ(), up.getX(), up.getY(), up.getZ()}); 89 | // buffer.flip(); 90 | // 91 | // alListenerfv(AL_ORIENTATION, buffer); 92 | } 93 | 94 | public Matrix4 getViewMatrix() { 95 | Matrix4 t = new Matrix4().initTranslation(transform.getTranslation()); 96 | Matrix4 r = new Matrix4().initRotation(transform.getRotation(), Matrix4.YXZ); 97 | 98 | return r.mul(t); 99 | } 100 | 101 | public Vector3 getDirection() { 102 | return new Vector3(getViewMatrix().get(2, 0), getViewMatrix().get(2, 1), getViewMatrix().get(2, 2)); 103 | } 104 | 105 | public void lockMovement(boolean lock) { 106 | lockMov = lock; 107 | } 108 | 109 | public void lockRotation(boolean lock) { 110 | lockRot = lock; 111 | } 112 | 113 | public Matrix4 getProjectionMatrix() { 114 | return projection; 115 | } 116 | 117 | public void setProjectionMatrix(Matrix4 projection) { 118 | this.projection = projection; 119 | } 120 | 121 | public Transform getTransform() { 122 | return transform; 123 | } 124 | 125 | public void setTransform(Transform transform) { 126 | this.transform = transform; 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /src/de/meinkraft/lib/Shader.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft.lib; 2 | 3 | import static org.lwjgl.opengl.GL20.GL_COMPILE_STATUS; 4 | import static org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER; 5 | import static org.lwjgl.opengl.GL20.GL_LINK_STATUS; 6 | import static org.lwjgl.opengl.GL20.GL_VALIDATE_STATUS; 7 | import static org.lwjgl.opengl.GL20.GL_VERTEX_SHADER; 8 | import static org.lwjgl.opengl.GL20.glAttachShader; 9 | import static org.lwjgl.opengl.GL20.glBindAttribLocation; 10 | import static org.lwjgl.opengl.GL20.glCompileShader; 11 | import static org.lwjgl.opengl.GL20.glCreateProgram; 12 | import static org.lwjgl.opengl.GL20.glCreateShader; 13 | import static org.lwjgl.opengl.GL20.glGetProgramInfoLog; 14 | import static org.lwjgl.opengl.GL20.glGetProgrami; 15 | import static org.lwjgl.opengl.GL20.glGetShaderInfoLog; 16 | import static org.lwjgl.opengl.GL20.glGetShaderi; 17 | import static org.lwjgl.opengl.GL20.glGetUniformLocation; 18 | import static org.lwjgl.opengl.GL20.glLinkProgram; 19 | import static org.lwjgl.opengl.GL20.glShaderSource; 20 | import static org.lwjgl.opengl.GL20.glUniform1i; 21 | import static org.lwjgl.opengl.GL20.glUniform1f; 22 | import static org.lwjgl.opengl.GL20.glUniform2f; 23 | import static org.lwjgl.opengl.GL20.glUniform3f; 24 | import static org.lwjgl.opengl.GL20.glUniform4f; 25 | import static org.lwjgl.opengl.GL20.glUniformMatrix4fv; 26 | import static org.lwjgl.opengl.GL20.glUseProgram; 27 | import static org.lwjgl.opengl.GL20.glValidateProgram; 28 | 29 | import org.lwjgl.BufferUtils; 30 | import org.lwjgl.opengl.OpenGLException; 31 | 32 | import java.io.IOException; 33 | import java.nio.FloatBuffer; 34 | import java.util.HashMap; 35 | 36 | public class Shader { 37 | 38 | private HashMap uniforms; 39 | 40 | private int id; 41 | 42 | public Shader(int id) { 43 | this.id = id; 44 | 45 | uniforms = new HashMap(); 46 | } 47 | 48 | public void bind() { 49 | glUseProgram(id); 50 | } 51 | 52 | public void bindAttribute(int index, String attribute) { 53 | glBindAttribLocation(id, index, attribute); 54 | } 55 | 56 | public void addUniform(String uniform) { 57 | int uniformLoc = glGetUniformLocation(id, uniform); 58 | 59 | if(uniformLoc == -1) 60 | throw new OpenGLException("Shader: could not find uniform " + uniform); 61 | 62 | uniforms.put(uniform, uniformLoc); 63 | } 64 | 65 | public void setUniform(String uniform, int v) { 66 | glUniform1i(uniforms.get(uniform), v); 67 | } 68 | 69 | public void setUniform(String uniform, float v) { 70 | glUniform1f(uniforms.get(uniform), v); 71 | } 72 | 73 | public void setUniform(String uniform, Vector2 v) { 74 | glUniform2f(uniforms.get(uniform), v.getX(), v.getY()); 75 | } 76 | 77 | public void setUniform(String uniform, Vector3 v) { 78 | glUniform3f(uniforms.get(uniform), v.getX(), v.getY(), v.getZ()); 79 | } 80 | 81 | public void setUniform(String uniform, Vector4 v) { 82 | glUniform4f(uniforms.get(uniform), v.getX(), v.getY(), v.getZ(), v.getW()); 83 | } 84 | 85 | public void setUniform(String uniform, Matrix4 v) { 86 | FloatBuffer buffer = BufferUtils.createFloatBuffer(4 * 4); 87 | 88 | for(int x = 0; x < 4; x++) 89 | for(int y = 0; y < 4; y++) 90 | buffer.put(v.get(x, y)); 91 | 92 | buffer.flip(); 93 | 94 | glUniformMatrix4fv(uniforms.get(uniform), true, buffer); 95 | } 96 | 97 | public int getId() { 98 | return id; 99 | } 100 | 101 | public static void unbind() { 102 | glUseProgram(0); 103 | } 104 | 105 | public static Shader loadShader(String vs, String fs, String[] attributes) throws IOException { 106 | int id = glCreateProgram(); 107 | 108 | if(id == 0) 109 | throw new OpenGLException("Could not find a valid memory location for shader program"); 110 | 111 | // vertex shader 112 | int vsId = glCreateShader(GL_VERTEX_SHADER); 113 | 114 | if(vsId == 0) 115 | throw new OpenGLException("Could not find a valid memory location for shader type"); 116 | 117 | glShaderSource(vsId, Utils.readFileToString(vs)); 118 | glCompileShader(vsId); 119 | 120 | if(glGetShaderi(vsId, GL_COMPILE_STATUS) == 0) 121 | throw new OpenGLException(glGetShaderInfoLog(vsId, 1024)); 122 | 123 | glAttachShader(id, vsId); 124 | 125 | // fragment shader 126 | int fsId = glCreateShader(GL_FRAGMENT_SHADER); 127 | 128 | if(fsId == 0) 129 | throw new OpenGLException("Could not find a valid memory location for shader type"); 130 | 131 | glShaderSource(fsId, Utils.readFileToString(fs)); 132 | glCompileShader(fsId); 133 | 134 | if(glGetShaderi(fsId, GL_COMPILE_STATUS) == 0) 135 | throw new OpenGLException(glGetShaderInfoLog(fsId, 1024)); 136 | 137 | glAttachShader(id, fsId); 138 | 139 | Shader shader = new Shader(id); 140 | if(attributes != null) { 141 | for(int i = 0; i < attributes.length; i++) 142 | shader.bindAttribute(i, attributes[i]); 143 | } 144 | 145 | glLinkProgram(id); 146 | 147 | if(glGetProgrami(id, GL_LINK_STATUS) == 0) 148 | throw new OpenGLException(glGetProgramInfoLog(id, 1024)); 149 | 150 | glValidateProgram(id); 151 | 152 | if(glGetProgrami(id, GL_VALIDATE_STATUS) == 0) 153 | throw new OpenGLException(glGetProgramInfoLog(id, 1024)); 154 | 155 | return shader; 156 | } 157 | 158 | } 159 | -------------------------------------------------------------------------------- /src/de/meinkraft/ChunkLoader.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | import java.util.ArrayDeque; 4 | 5 | import org.lwjgl.BufferUtils; 6 | 7 | public class ChunkLoader extends Thread { 8 | 9 | private ArrayDeque queue, queue2; 10 | 11 | private final ChunkManager chunkManager; 12 | 13 | public ChunkLoader(ChunkManager chunkManager) { 14 | this.chunkManager = chunkManager; 15 | 16 | queue = new ArrayDeque(); 17 | queue2 = new ArrayDeque(); 18 | start(); 19 | } 20 | 21 | public synchronized void addChunk(Chunk chunk) { 22 | if(queue.contains(chunk)) 23 | return; 24 | 25 | chunk.setState(ChunkState.LOADING); 26 | queue.add(chunk); 27 | notify(); 28 | } 29 | 30 | @Override 31 | public void run() { 32 | while(isAlive()) { 33 | if(!queue.isEmpty()) { 34 | Chunk chunk = queue.peek(); 35 | 36 | if(!chunkManager.isChunkInRange(chunk.getX(), chunk.getZ())) { 37 | if(chunkManager.hasChunkNeighboursLoading(chunk)) 38 | continue; 39 | 40 | chunk.setState(ChunkState.UNLOADED); 41 | queue.remove(); 42 | } else { 43 | // System.out.println(chunk.getX() + "," + chunk.getZ() + " generating"); 44 | chunkManager.getWorld().getWorldGenerator().generate(chunk); 45 | 46 | if(!queue2.contains(chunk)) 47 | queue2.add(queue.poll()); 48 | } 49 | } 50 | 51 | if(!queue2.isEmpty()) { 52 | Chunk chunk = queue2.peek(); 53 | 54 | if(!chunkManager.isChunkInRange(chunk.getX(), chunk.getZ())) { 55 | if(chunkManager.hasChunkNeighboursLoading(chunk)) 56 | continue; 57 | 58 | chunk.setState(ChunkState.UNLOADED); 59 | queue2.remove(); 60 | continue; 61 | } 62 | 63 | // if(chunk.isGenerated()) { 64 | if(!chunkManager.isChunkSurrounded(chunk)) 65 | continue; 66 | 67 | System.out.println(chunk.getX() + "," + chunk.getZ() + " loading"); 68 | int vcount = 0; 69 | for(int x = 0; x < Chunk.SIZE_X; x++) 70 | for(int y = 0; y < Chunk.SIZE_Y; y++) 71 | for(int z = 0; z < Chunk.SIZE_Z; z++) { 72 | Blockcheck bc = new Blockcheck(); 73 | 74 | int wx = chunk.getX() * Chunk.SIZE_X + x; 75 | int wz = chunk.getZ() * Chunk.SIZE_Z + z; 76 | 77 | if(chunkManager.getBlockAt(wx + 1, y, wz).getType().isSolid() && chunkManager.getBlockAt(wx + 1, y, wz).getMaterial().isOpaque()) 78 | bc.east = true; 79 | 80 | if(chunkManager.getBlockAt(wx - 1, y, wz).getType().isSolid() && chunkManager.getBlockAt(wx - 1, y, wz).getMaterial().isOpaque()) 81 | bc.west = true; 82 | 83 | if(chunkManager.getBlockAt(wx, y + 1, wz).getType().isSolid() && chunkManager.getBlockAt(wx, y + 1, wz).getMaterial().isOpaque()) 84 | bc.top = true; 85 | 86 | if(chunkManager.getBlockAt(wx, y - 1, wz).getType().isSolid() && chunkManager.getBlockAt(wx, y - 1, wz).getMaterial().isOpaque()) 87 | bc.bottom = true; 88 | 89 | if(chunkManager.getBlockAt(wx, y, wz + 1).getType().isSolid() && chunkManager.getBlockAt(wx, y, wz + 1).getMaterial().isOpaque()) 90 | bc.south = true; 91 | 92 | if(chunkManager.getBlockAt(wx, y, wz - 1).getType().isSolid() && chunkManager.getBlockAt(wx, y, wz - 1).getMaterial().isOpaque()) 93 | bc.north = true; 94 | 95 | vcount += chunk.getBlockAt(x, y, z).getType().getVerticesCount(bc); 96 | } 97 | 98 | chunk.vertices = BufferUtils.createFloatBuffer(vcount * 7); 99 | for(int x = 0; x < Chunk.SIZE_X; x++) 100 | for(int y = 0; y < Chunk.SIZE_Y; y++) 101 | for(int z = 0; z < Chunk.SIZE_Z; z++) { 102 | Blockcheck bc = new Blockcheck(); 103 | BlockAO ao = new BlockAO(); 104 | 105 | int wx = chunk.getX() * Chunk.SIZE_X + x; 106 | int wz = chunk.getZ() * Chunk.SIZE_Z + z; 107 | 108 | if(chunkManager.getBlockAt(wx + 1, y, wz).getType().isSolid() && chunkManager.getBlockAt(wx + 1, y, wz).getMaterial().isOpaque()) 109 | bc.east = true; 110 | 111 | if(chunkManager.getBlockAt(wx - 1, y, wz).getType().isSolid() && chunkManager.getBlockAt(wx - 1, y, wz).getMaterial().isOpaque()) 112 | bc.west = true; 113 | 114 | if(chunkManager.getBlockAt(wx, y + 1, wz).getType().isSolid() && chunkManager.getBlockAt(wx, y + 1, wz).getMaterial().isOpaque()) 115 | bc.top = true; 116 | 117 | if(chunkManager.getBlockAt(wx, y - 1, wz).getType().isSolid() && chunkManager.getBlockAt(wx, y - 1, wz).getMaterial().isOpaque()) 118 | bc.bottom = true; 119 | 120 | if(chunkManager.getBlockAt(wx, y, wz + 1).getType().isSolid() && chunkManager.getBlockAt(wx, y, wz + 1).getMaterial().isOpaque()) 121 | bc.south = true; 122 | 123 | if(chunkManager.getBlockAt(wx, y, wz - 1).getType().isSolid() && chunkManager.getBlockAt(wx, y, wz - 1).getMaterial().isOpaque()) 124 | bc.north = true; 125 | 126 | if(!bc.all()) { 127 | if(chunkManager.getBlockAt(wx + 1, y + 1, wz).getType().isSolid() && chunkManager.getBlockAt(wx + 1, y + 1, wz).getMaterial().isOpaque()) 128 | ao.eT = true; 129 | if(chunkManager.getBlockAt(wx + 1, y - 1, wz).getType().isSolid() && chunkManager.getBlockAt(wx + 1, y - 1, wz).getMaterial().isOpaque()) 130 | ao.eB = true; 131 | if(chunkManager.getBlockAt(wx - 1, y + 1, wz).getType().isSolid() && chunkManager.getBlockAt(wx - 1, y + 1, wz).getMaterial().isOpaque()) 132 | ao.wT = true; 133 | if(chunkManager.getBlockAt(wx - 1, y - 1, wz).getType().isSolid() && chunkManager.getBlockAt(wx - 1, y - 1, wz).getMaterial().isOpaque()) 134 | ao.wB = true; 135 | if(chunkManager.getBlockAt(wx, y + 1, wz + 1).getType().isSolid() && chunkManager.getBlockAt(wx, y + 1, wz + 1).getMaterial().isOpaque()) 136 | ao.sT = true; 137 | if(chunkManager.getBlockAt(wx, y - 1, wz + 1).getType().isSolid() && chunkManager.getBlockAt(wx, y - 1, wz + 1).getMaterial().isOpaque()) 138 | ao.sB = true; 139 | if(chunkManager.getBlockAt(wx, y + 1, wz - 1).getType().isSolid() && chunkManager.getBlockAt(wx, y + 1, wz - 1).getMaterial().isOpaque()) 140 | ao.nT = true; 141 | if(chunkManager.getBlockAt(wx, y - 1, wz - 1).getType().isSolid() && chunkManager.getBlockAt(wx, y - 1, wz - 1).getMaterial().isOpaque()) 142 | ao.nB = true; 143 | 144 | if(chunkManager.getBlockAt(wx + 1, y + 1, wz + 1).getType().isSolid() && chunkManager.getBlockAt(wx + 1, y + 1, wz + 1).getMaterial().isOpaque()) 145 | ao.cXYZ = true; 146 | if(chunkManager.getBlockAt(wx - 1, y + 1, wz + 1).getType().isSolid() && chunkManager.getBlockAt(wx - 1, y + 1, wz + 1).getMaterial().isOpaque()) 147 | ao.c_XYZ = true; 148 | if(chunkManager.getBlockAt(wx + 1, y - 1, wz + 1).getType().isSolid() && chunkManager.getBlockAt(wx + 1, y - 1, wz + 1).getMaterial().isOpaque()) 149 | ao.cX_YZ = true; 150 | if(chunkManager.getBlockAt(wx + 1, y + 1, wz - 1).getType().isSolid() && chunkManager.getBlockAt(wx + 1, y + 1, wz - 1).getMaterial().isOpaque()) 151 | ao.cXY_Z = true; 152 | if(chunkManager.getBlockAt(wx - 1, y - 1, wz + 1).getType().isSolid() && chunkManager.getBlockAt(wx - 1, y - 1, wz + 1).getMaterial().isOpaque()) 153 | ao.c_X_YZ = true; 154 | if(chunkManager.getBlockAt(wx + 1, y - 1, wz - 1).getType().isSolid() && chunkManager.getBlockAt(wx + 1, y - 1, wz - 1).getMaterial().isOpaque()) 155 | ao.cX_Y_Z = true; 156 | if(chunkManager.getBlockAt(wx - 1, y + 1, wz - 1).getType().isSolid() && chunkManager.getBlockAt(wx - 1, y + 1, wz - 1).getMaterial().isOpaque()) 157 | ao.c_XY_Z = true; 158 | if(chunkManager.getBlockAt(wx - 1, y - 1, wz - 1).getType().isSolid() && chunkManager.getBlockAt(wx - 1, y - 1, wz - 1).getMaterial().isOpaque()) 159 | ao.c_X_Y_Z = true; 160 | } 161 | 162 | chunk.getBlockAt(x, y, z).getType().addVertices(wx, y, wz, chunk.vertices, bc, ao, chunk.getBlockAt(x, y, z).getTextures()); 163 | } 164 | chunk.vertices.flip(); 165 | 166 | chunk.indices = BufferUtils.createIntBuffer(chunk.vertices.limit() / 4 * 6); 167 | for(int i = 0, j = 0; i < chunk.indices.limit(); i += 6, j += 4) { 168 | chunk.indices.put(j + 0); 169 | chunk.indices.put(j + 1); 170 | chunk.indices.put(j + 2); 171 | chunk.indices.put(j + 0); 172 | chunk.indices.put(j + 2); 173 | chunk.indices.put(j + 3); 174 | } 175 | chunk.indices.flip(); 176 | chunk.doLoad(); 177 | 178 | queue2.remove(); 179 | // } 180 | 181 | continue; 182 | } 183 | 184 | synchronized (this) { 185 | try { 186 | System.out.println("waiting"); 187 | wait(); 188 | } catch (InterruptedException e) { 189 | e.printStackTrace(); 190 | return; 191 | } 192 | } 193 | } 194 | } 195 | 196 | } 197 | -------------------------------------------------------------------------------- /src/de/meinkraft/lib/Texture.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft.lib; 2 | 3 | import static org.lwjgl.opengl.GL13.GL_MAX_TEXTURE_UNITS; 4 | import static org.lwjgl.opengl.GL11.GL_LINEAR_MIPMAP_LINEAR; 5 | import static org.lwjgl.opengl.GL11.GL_LINEAR_MIPMAP_NEAREST; 6 | import static org.lwjgl.opengl.GL11.GL_NEAREST_MIPMAP_LINEAR; 7 | import static org.lwjgl.opengl.GL11.GL_NEAREST_MIPMAP_NEAREST; 8 | import static org.lwjgl.opengl.GL11.GL_RGBA; 9 | import static org.lwjgl.opengl.GL11.GL_RGBA8; 10 | import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D; 11 | import static org.lwjgl.opengl.GL11.GL_TEXTURE_MAG_FILTER; 12 | import static org.lwjgl.opengl.GL11.GL_TEXTURE_MIN_FILTER; 13 | import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_S; 14 | import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_T; 15 | import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE; 16 | import static org.lwjgl.opengl.GL11.glGenTextures; 17 | import static org.lwjgl.opengl.GL11.glTexImage2D; 18 | import static org.lwjgl.opengl.GL11.glTexParameteri; 19 | import static org.lwjgl.opengl.GL30.GL_TEXTURE_2D_ARRAY; 20 | import static org.lwjgl.opengl.GL30.glGenerateMipmap; 21 | import static org.lwjgl.opengl.GL12.GL_TEXTURE_3D; 22 | import static org.lwjgl.opengl.GL12.GL_TEXTURE_WRAP_R; 23 | import static org.lwjgl.opengl.GL12.glTexImage3D; 24 | import static org.lwjgl.opengl.GL12.glTexSubImage3D; 25 | import static org.lwjgl.opengl.GL11.glBindTexture; 26 | import static org.lwjgl.opengl.GL13.glActiveTexture; 27 | 28 | import java.awt.image.BufferedImage; 29 | import java.io.IOException; 30 | import java.io.InputStream; 31 | import java.nio.ByteBuffer; 32 | 33 | import javax.imageio.ImageIO; 34 | 35 | import org.lwjgl.BufferUtils; 36 | import org.lwjgl.opengl.OpenGLException; 37 | 38 | public class Texture { 39 | 40 | private static int imageWidth; 41 | private static int imageHeight; 42 | 43 | // TEXTURE_2D 44 | public static void bindTexture2D(int id) { 45 | glBindTexture(GL_TEXTURE_2D, id); 46 | } 47 | 48 | public static void bindTexture2D(int id, int unit) { 49 | if(unit >= 0 && unit <= GL_MAX_TEXTURE_UNITS) { 50 | glActiveTexture(unit); 51 | glBindTexture(GL_TEXTURE_2D, id); 52 | } else 53 | throw new OpenGLException("Texture unit " + unit + " is not valid"); 54 | } 55 | 56 | public static void unbindTexture2D() { 57 | glBindTexture(GL_TEXTURE_2D, 0); 58 | } 59 | 60 | public static int loadTexture2D(InputStream iS, int magFilter, int minFilter, int wrapMode) throws IOException { 61 | ByteBuffer data = getImageData(iS); 62 | 63 | int id = glGenTextures(); 64 | 65 | glBindTexture(GL_TEXTURE_2D, id); 66 | 67 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter); 68 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter); 69 | 70 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode); 71 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode); 72 | 73 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, imageWidth, imageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); 74 | 75 | if(minFilter == GL_NEAREST_MIPMAP_NEAREST || minFilter == GL_NEAREST_MIPMAP_LINEAR || minFilter == GL_LINEAR_MIPMAP_NEAREST || minFilter == GL_LINEAR_MIPMAP_LINEAR) 76 | glGenerateMipmap(GL_TEXTURE_2D); 77 | 78 | glBindTexture(GL_TEXTURE_2D, 0); 79 | 80 | return id; 81 | } 82 | 83 | // TEXTURE_2D_ARRAY 84 | public static void bindTexture2DArray(int id) { 85 | glBindTexture(GL_TEXTURE_2D_ARRAY, id); 86 | } 87 | 88 | public static void bindTexture2DArray(int id, int unit) { 89 | if(unit >= 0 && unit <= GL_MAX_TEXTURE_UNITS) { 90 | glActiveTexture(unit); 91 | glBindTexture(GL_TEXTURE_2D_ARRAY, id); 92 | } else 93 | throw new OpenGLException("Texture unit " + unit + " is not valid"); 94 | } 95 | 96 | public static void unbindTexture2DArray() { 97 | glBindTexture(GL_TEXTURE_2D_ARRAY, 0); 98 | } 99 | 100 | public static int loadTexture2DArray(InputStream iS, int width, int height, int magFilter, int minFilter, int wrapMode) throws IOException { 101 | int id = glGenTextures(); 102 | 103 | glBindTexture(GL_TEXTURE_2D_ARRAY, id); 104 | 105 | glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, magFilter); 106 | glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, minFilter); 107 | 108 | glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, wrapMode); 109 | glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, wrapMode); 110 | 111 | ByteBuffer[] data = getImageDataArray(iS, width, height); 112 | 113 | int depth = (imageWidth / width) * (imageHeight / height); 114 | 115 | glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, width, height, depth, 0, GL_RGBA, GL_UNSIGNED_BYTE, (ByteBuffer) null); 116 | 117 | for(int i = 0; i < data.length; i++) 118 | glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, i, width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE, data[i]); 119 | 120 | if(minFilter == GL_NEAREST_MIPMAP_NEAREST || minFilter == GL_NEAREST_MIPMAP_LINEAR || minFilter == GL_LINEAR_MIPMAP_NEAREST || minFilter == GL_LINEAR_MIPMAP_LINEAR) 121 | glGenerateMipmap(GL_TEXTURE_2D_ARRAY); 122 | 123 | glBindTexture(GL_TEXTURE_2D_ARRAY, 0); 124 | 125 | return id; 126 | } 127 | 128 | // TEXTURE_3D 129 | public static void bindTexture3D(int id) { 130 | glBindTexture(GL_TEXTURE_3D, id); 131 | } 132 | 133 | public static void bindTexture3D(int id, int unit) { 134 | if(unit >= 0 && unit <= GL_MAX_TEXTURE_UNITS) { 135 | glActiveTexture(unit); 136 | glBindTexture(GL_TEXTURE_3D, id); 137 | } else 138 | throw new OpenGLException("Texture unit " + unit + " is not valid"); 139 | } 140 | 141 | public static void unbindTexture3D() { 142 | glBindTexture(GL_TEXTURE_3D, 0); 143 | } 144 | 145 | public static int loadTexture3D(InputStream iS, int width, int height, int magFilter, int minFilter, int wrapMode) throws IOException { 146 | int id = glGenTextures(); 147 | 148 | glBindTexture(GL_TEXTURE_3D, id); 149 | 150 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, magFilter); 151 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, minFilter); 152 | 153 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, wrapMode); 154 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, wrapMode); 155 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, wrapMode); 156 | 157 | ByteBuffer[] data = getImageDataArray(iS, width, height); 158 | 159 | int depth = (imageWidth / width) * (imageHeight / height); 160 | 161 | glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, width, height, depth, 0, GL_RGBA, GL_UNSIGNED_BYTE, (ByteBuffer) null); 162 | 163 | for(int i = 0; i < data.length; i++) 164 | glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, i, width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE, data[i]); 165 | 166 | if(minFilter == GL_NEAREST_MIPMAP_NEAREST || minFilter == GL_NEAREST_MIPMAP_LINEAR || minFilter == GL_LINEAR_MIPMAP_NEAREST || minFilter == GL_LINEAR_MIPMAP_LINEAR) 167 | glGenerateMipmap(GL_TEXTURE_3D); 168 | 169 | glBindTexture(GL_TEXTURE_3D, 0); 170 | 171 | return id; 172 | } 173 | 174 | private static ByteBuffer getImageData(InputStream iS) throws IOException { 175 | BufferedImage image = ImageIO.read(iS); 176 | 177 | imageWidth = image.getWidth(); 178 | imageHeight = image.getHeight(); 179 | 180 | int[] pixels = image.getRGB(0, 0, imageWidth, imageHeight, null, 0, imageWidth); 181 | ByteBuffer buffer = BufferUtils.createByteBuffer(imageWidth * imageHeight * 4); 182 | 183 | for(int y = 0; y < imageHeight; y++) { 184 | for(int x = 0; x < imageWidth; x++) { 185 | int pixel = pixels[y * imageWidth + x]; 186 | 187 | buffer.put((byte) ((pixel >> 16) & 0xFF)); 188 | buffer.put((byte) ((pixel >> 8) & 0xFF)); 189 | buffer.put((byte) (pixel & 0xFF)); 190 | buffer.put((byte) ((pixel >> 24) & 0xFF)); 191 | } 192 | } 193 | 194 | buffer.flip(); 195 | 196 | return buffer; 197 | } 198 | 199 | private static ByteBuffer[] getImageDataArray(InputStream iS, int singleW, int singleH) throws IOException { 200 | BufferedImage image = ImageIO.read(iS); 201 | 202 | imageWidth = image.getWidth(); 203 | imageHeight = image.getHeight(); 204 | 205 | int[] pixels = image.getRGB(0, 0, imageWidth, imageHeight, null, 0, imageWidth); 206 | 207 | int layerX = imageWidth / singleW; 208 | int layerY = imageHeight / singleH; 209 | int depth = layerX * layerY; 210 | ByteBuffer[] buffers = new ByteBuffer[depth]; 211 | 212 | int index = 0; 213 | for(int ly = 0; ly < layerY; ly++) { 214 | for(int lx = 0; lx < layerX; lx++) { 215 | buffers[index] = BufferUtils.createByteBuffer(singleW * singleH * 4); 216 | 217 | for(int y = 0; y < singleH; y++) { 218 | for(int x = 0; x < singleW; x++) { 219 | int pixel = pixels[(ly * singleH + y) * imageWidth + lx * singleW + x]; 220 | 221 | buffers[index].put((byte) ((pixel >> 16) & 0xFF)); 222 | buffers[index].put((byte) ((pixel >> 8) & 0xFF)); 223 | buffers[index].put((byte) (pixel & 0xFF)); 224 | buffers[index].put((byte) ((pixel >> 24) & 0xFF)); 225 | } 226 | } 227 | 228 | buffers[index].flip(); 229 | index++; 230 | } 231 | } 232 | 233 | return buffers; 234 | } 235 | 236 | } 237 | -------------------------------------------------------------------------------- /src/de/meinkraft/ChunkManager.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | import java.util.ArrayDeque; 4 | import static org.lwjgl.opengl.GL11.*; 5 | 6 | public class ChunkManager { 7 | 8 | // the radius in which chunks get generated 9 | public static final byte RADIUS = 4; 10 | 11 | private Chunk[][] chunks; 12 | 13 | private final World world; 14 | private final ChunkLoader chunkLoader; 15 | private final ArrayDeque queue; 16 | 17 | public ChunkManager(World world) { 18 | this.world = world; 19 | chunkLoader = new ChunkLoader(this); 20 | queue = new ArrayDeque(); 21 | 22 | chunks = new Chunk[2 * RADIUS + 1][2 * RADIUS + 1]; 23 | } 24 | 25 | public void update() { 26 | int px = getPlayerChunkPositionX(); 27 | int pz = getPlayerChunkPositionZ(); 28 | 29 | for(int x = 0; x < chunks.length; x++) 30 | for(int z = 0; z < chunks.length; z++) { 31 | Chunk chunk = chunks[x][z]; 32 | 33 | if(chunk == null) { 34 | cs:for(int lx = -RADIUS; lx <= RADIUS; lx++) 35 | for(int lz = -RADIUS; lz <= RADIUS; lz++) { 36 | if(getChunkAt(px + lx, pz + lz) == null) { 37 | chunks[x][z] = new Chunk(px + lx, pz + lz); 38 | chunkLoader.addChunk(chunks[x][z]); 39 | break cs; 40 | } 41 | } 42 | } else { 43 | if(isChunkInRange(chunk.getX(), chunk.getZ())) 44 | chunk.update(); 45 | else { 46 | if(chunk.getState() == ChunkState.LOADING || hasChunkNeighboursLoading(chunk)) { 47 | if(!queue.contains(chunk)) 48 | queue.add(chunk); 49 | } else { 50 | System.out.println("FIRST_HAS_NEIGHBOURS_LOADING: " + hasChunkNeighboursLoading(chunk) + " " + chunk.getX() + "," + chunk.getZ()); 51 | chunk.unload(); 52 | } 53 | 54 | chunks[x][z] = null; 55 | 56 | if(z > 0) 57 | z--; 58 | else { 59 | if(x > 0) { 60 | x--; 61 | z = chunks.length - 1; 62 | } 63 | } 64 | } 65 | } 66 | } 67 | 68 | if(!queue.isEmpty()) { 69 | Chunk chunk = queue.poll(); 70 | 71 | if(chunk.getState() != ChunkState.LOADING && !hasChunkNeighboursLoading(chunk)) { 72 | System.out.println("SECOND_HAS_NEIGHBOURS_LOADING: " + hasChunkNeighboursLoading(chunk) + " " + chunk.getX() + "," + chunk.getZ()); 73 | chunk.unload(); 74 | } 75 | else 76 | queue.add(chunk); 77 | } 78 | } 79 | 80 | public void render() { 81 | for(int x = 0; x < chunks.length; x++) 82 | for(int z = 0; z < chunks.length; z++) { 83 | Chunk chunk = chunks[x][z]; 84 | 85 | if(chunk == null || !chunk.isLoaded()) 86 | continue; 87 | 88 | // Vector3 playerPos = new Vector3(world.getPlayer().pos.getX(), world.getPlayer().pos.getY(), world.getPlayer().pos.getZ()); 89 | // Vector3 chunkDir1 = new Vector3(chunk.getX() * Chunk.SIZE_X, 0, chunk.getZ() * Chunk.SIZE_Z).add(playerPos.negate()).normalised(); 90 | // Vector3 chunkDir2 = new Vector3(chunk.getX() * Chunk.SIZE_X + 16, 0, chunk.getZ() * Chunk.SIZE_Z).add(playerPos.negate()).normalised(); 91 | // Vector3 chunkDir3 = new Vector3(chunk.getX() * Chunk.SIZE_X + 16, 0, chunk.getZ() * Chunk.SIZE_Z + 16).add(playerPos.negate()).normalised(); 92 | // Vector3 chunkDir4 = new Vector3(chunk.getX() * Chunk.SIZE_X, 0, chunk.getZ() * Chunk.SIZE_Z + 16).add(playerPos.negate()).normalised(); 93 | // 94 | // if(chunkDir1.dot(world.getPlayer().dir) > 0 && chunkDir2.dot(world.getPlayer().dir) > 0 && chunkDir3.dot(world.getPlayer().dir) > 0 && chunkDir4.dot(world.getPlayer().dir) > 0) { 95 | chunk.render(); 96 | // count++; 97 | // } 98 | } 99 | 100 | // debug 101 | glBegin(GL_LINE_STRIP); 102 | { 103 | for(int x = 0; x < chunks.length; x++) 104 | for(int z = 0; z < chunks.length; z++) { 105 | Chunk chunk = chunks[x][z]; 106 | 107 | if(chunk == null) 108 | continue; 109 | 110 | if(chunk.isGenerated()) { 111 | glVertex3f(chunk.getX() * Chunk.SIZE_X, 65, chunk.getZ() * Chunk.SIZE_Z); 112 | glVertex3f(chunk.getX() * Chunk.SIZE_X + Chunk.SIZE_X, 65, chunk.getZ() * Chunk.SIZE_Z); 113 | glVertex3f(chunk.getX() * Chunk.SIZE_X + Chunk.SIZE_X, 65, chunk.getZ() * Chunk.SIZE_Z + Chunk.SIZE_Z); 114 | glVertex3f(chunk.getX() * Chunk.SIZE_X, 65, chunk.getZ() * Chunk.SIZE_Z + Chunk.SIZE_Z); 115 | } 116 | } 117 | } 118 | glEnd(); 119 | } 120 | 121 | public void regenerate() { 122 | for(int xx = 0; xx < chunks.length; xx++) 123 | for(int zz = 0; zz < chunks.length; zz++) { 124 | if(chunks[xx][zz] == null) 125 | continue; 126 | 127 | chunks[xx][zz].deleteBlocks(); 128 | chunkLoader.addChunk(chunks[xx][zz]); 129 | } 130 | } 131 | 132 | public int getPlayerChunkPositionX() { 133 | return (int) Math.floor(world.getPlayer().pos.getX() / Chunk.SIZE_X); 134 | } 135 | 136 | public int getPlayerChunkPositionZ() { 137 | return (int) Math.floor(world.getPlayer().pos.getZ() / Chunk.SIZE_Z); 138 | } 139 | 140 | // public boolean allChunksGenerated() { 141 | // for(int x = 0; x < chunks.length; x++) 142 | // for(int z = 0; z < chunks.length; z++) { 143 | // if(chunks[x][z] == null || !chunks[x][z].isGenerated()) 144 | // return false; 145 | // } 146 | // 147 | // return true; 148 | // } 149 | 150 | public boolean isChunkInRange(int x, int z) { 151 | if(Math.abs((int) Math.floor(world.getPlayer().pos.getX() / Chunk.SIZE_X) - x) > RADIUS || Math.abs((int) Math.floor(world.getPlayer().pos.getZ() / Chunk.SIZE_Z) - z) > RADIUS) 152 | return false; 153 | else 154 | return true; 155 | } 156 | 157 | /** 158 | * 159 | * @param chunk 160 | * @return Returns true if the chunk is surrounded by generated chunks 161 | */ 162 | public boolean isChunkSurrounded(Chunk chunk) { 163 | if(isChunkInRange(chunk.getX() - 1, chunk.getZ())) { 164 | if(getChunkAt(chunk.getX() - 1, chunk.getZ()) == null || !getChunkAt(chunk.getX() - 1, chunk.getZ()).isGenerated()) 165 | return false; 166 | } 167 | 168 | if(isChunkInRange(chunk.getX() + 1, chunk.getZ())) { 169 | if(getChunkAt(chunk.getX() + 1, chunk.getZ()) == null || !getChunkAt(chunk.getX() + 1, chunk.getZ()).isGenerated()) 170 | return false; 171 | } 172 | 173 | if(isChunkInRange(chunk.getX(), chunk.getZ() - 1)) { 174 | if(getChunkAt(chunk.getX(), chunk.getZ() - 1) == null || !getChunkAt(chunk.getX(), chunk.getZ() - 1).isGenerated()) 175 | return false; 176 | } 177 | 178 | if(isChunkInRange(chunk.getX(), chunk.getZ() + 1)) { 179 | if(getChunkAt(chunk.getX(), chunk.getZ() + 1) == null || !getChunkAt(chunk.getX(), chunk.getZ() + 1).isGenerated()) 180 | return false; 181 | } 182 | 183 | return true; 184 | } 185 | 186 | /** 187 | * 188 | * @param chunk 189 | * @return Returns true if the chunk has a neighbour, which is in a loading state 190 | */ 191 | public boolean hasChunkNeighboursLoading(Chunk chunk) { 192 | if(getChunkAt(chunk.getX() - 1, chunk.getZ()) != null && !getChunkAt(chunk.getX() - 1, chunk.getZ()).isGenerated()) 193 | return true; 194 | 195 | if(getChunkAt(chunk.getX() + 1, chunk.getZ()) != null && !getChunkAt(chunk.getX() + 1, chunk.getZ()).isGenerated()) 196 | return true; 197 | 198 | if(getChunkAt(chunk.getX(), chunk.getZ() - 1) != null && !getChunkAt(chunk.getX(), chunk.getZ() - 1).isGenerated()) 199 | return true; 200 | 201 | if(getChunkAt(chunk.getX(), chunk.getZ() + 1) != null && !getChunkAt(chunk.getX(), chunk.getZ() + 1).isGenerated()) 202 | return true; 203 | 204 | return false; 205 | } 206 | 207 | public Chunk getChunkAt(int x, int z) { 208 | for(int xx = 0; xx < chunks.length; xx++) 209 | for(int zz = 0; zz < chunks.length; zz++) { 210 | if(chunks[xx][zz] == null) 211 | continue; 212 | 213 | if(chunks[xx][zz].getX() == x && chunks[xx][zz].getZ() == z) 214 | return chunks[xx][zz]; 215 | } 216 | 217 | if(!queue.isEmpty()) { 218 | Object[] chunks = queue.toArray(); 219 | for(Object obj : chunks) { 220 | if(obj instanceof Chunk) { 221 | Chunk chunk = (Chunk) obj; 222 | 223 | if(chunk.getX() == x && chunk.getZ() == z) 224 | return chunk; 225 | } 226 | } 227 | } 228 | 229 | return null; 230 | } 231 | 232 | public Block getBlockAt(int x, int y, int z) { 233 | int chunkX = (int) Math.floor((float) x / Chunk.SIZE_X); 234 | int chunkZ = (int) Math.floor((float) z / Chunk.SIZE_Z); 235 | 236 | for(int xx = 0; xx < chunks.length; xx++) 237 | for(int zz = 0; zz < chunks.length; zz++) { 238 | if(chunks[xx][zz] == null) 239 | continue; 240 | 241 | if(chunks[xx][zz].getX() == chunkX && chunks[xx][zz].getZ() == chunkZ) 242 | return chunks[xx][zz].getBlockAt(x - chunkX * Chunk.SIZE_X, y, z - chunkZ * Chunk.SIZE_Z); 243 | } 244 | 245 | if(!queue.isEmpty()) { 246 | Object[] chunks = queue.toArray(); 247 | for(Object obj : chunks) { 248 | if(obj instanceof Chunk) { 249 | Chunk chunk = (Chunk) obj; 250 | 251 | if(chunk.getX() == chunkX && chunk.getZ() == chunkZ) 252 | return chunk.getBlockAt(x - chunkX * Chunk.SIZE_X, y, z - chunkZ * Chunk.SIZE_Z); 253 | } 254 | } 255 | } 256 | 257 | return Block.AIR; 258 | } 259 | 260 | public void setBlockAt(int x, int y, int z, Block block) { 261 | int chunkX = (int) Math.floor((float) x / Chunk.SIZE_X); 262 | int chunkZ = (int) Math.floor((float) z / Chunk.SIZE_Z); 263 | 264 | for(int xx = 0; xx < chunks.length; xx++) 265 | for(int zz = 0; zz < chunks.length; zz++) { 266 | if(chunks[xx][zz] == null) 267 | continue; 268 | 269 | if(chunks[xx][zz].getX() == chunkX && chunks[xx][zz].getZ() == chunkZ) { 270 | chunks[xx][zz].setBlockAt(x - chunkX * Chunk.SIZE_X, y, z - chunkZ * Chunk.SIZE_Z, block); 271 | 272 | chunkLoader.addChunk(chunks[xx][zz]); 273 | } 274 | } 275 | } 276 | 277 | public World getWorld() { 278 | return world; 279 | } 280 | 281 | public Chunk[][] getChunks() { 282 | return chunks; 283 | } 284 | 285 | } 286 | -------------------------------------------------------------------------------- /src/de/meinkraft/lib/Matrix4.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft.lib; 2 | 3 | public class Matrix4 { 4 | 5 | public static final int XYZ = 0; 6 | public static final int ZXY = 1; 7 | public static final int YZX = 2; 8 | public static final int ZYX = 3; 9 | public static final int YXZ = 4; 10 | public static final int XZY = 5; 11 | 12 | private float[][] m; 13 | 14 | public Matrix4() { 15 | m = new float[4][4]; 16 | } 17 | 18 | public Matrix4 loadIdentity() { 19 | m[0][0] = 1; m[0][1] = 0; m[0][2] = 0; m[0][3] = 0; 20 | m[1][0] = 0; m[1][1] = 1; m[1][2] = 0; m[1][3] = 0; 21 | m[2][0] = 0; m[2][1] = 0; m[2][2] = 1; m[2][3] = 0; 22 | m[3][0] = 0; m[3][1] = 0; m[3][2] = 0; m[3][3] = 1; 23 | 24 | return this; 25 | } 26 | 27 | public Matrix4 initTranslation(Vector3 v) { 28 | return initTranslation(v.getX(), v.getY(), v.getZ()); 29 | } 30 | 31 | public Matrix4 initTranslation(float x, float y, float z) { 32 | m[0][0] = 1; m[0][1] = 0; m[0][2] = 0; m[0][3] = x; 33 | m[1][0] = 0; m[1][1] = 1; m[1][2] = 0; m[1][3] = y; 34 | m[2][0] = 0; m[2][1] = 0; m[2][2] = 1; m[2][3] = z; 35 | m[3][0] = 0; m[3][1] = 0; m[3][2] = 0; m[3][3] = 1; 36 | 37 | return this; 38 | } 39 | 40 | public Matrix4 initRotation(Vector3 v, int order) { 41 | return initRotation(v.getX(), v.getY(), v.getZ(), order); 42 | } 43 | 44 | public Matrix4 initRotation(float x, float y, float z, int order) { 45 | Matrix4 rx = new Matrix4(); 46 | Matrix4 ry = new Matrix4(); 47 | Matrix4 rz = new Matrix4(); 48 | 49 | x = (float) Math.toRadians(x); 50 | y = (float) Math.toRadians(y); 51 | z = (float) Math.toRadians(z); 52 | 53 | rx.m[0][0] = 1; rx.m[0][1] = 0; rx.m[0][2] = 0; rx.m[0][3] = 0; 54 | rx.m[1][0] = 0; rx.m[1][1] = (float) Math.cos(x); rx.m[1][2] = (float) -Math.sin(x); rx.m[1][3] = 0; 55 | rx.m[2][0] = 0; rx.m[2][1] = (float) Math.sin(x); rx.m[2][2] = (float) Math.cos(x); rx.m[2][3] = 0; 56 | rx.m[3][0] = 0; rx.m[3][1] = 0; rx.m[3][2] = 0; rx.m[3][3] = 1; 57 | 58 | ry.m[0][0] = (float) Math.cos(y); ry.m[0][1] = 0; ry.m[0][2] = (float) Math.sin(y); ry.m[0][3] = 0; 59 | ry.m[1][0] = 0; ry.m[1][1] = 1; ry.m[1][2] = 0; ry.m[1][3] = 0; 60 | ry.m[2][0] = (float) -Math.sin(y); ry.m[2][1] = 0; ry.m[2][2] = (float) Math.cos(y); ry.m[2][3] = 0; 61 | ry.m[3][0] = 0; ry.m[3][1] = 0; ry.m[3][2] = 0; ry.m[3][3] = 1; 62 | 63 | rz.m[0][0] = (float) Math.cos(z); rz.m[0][1] = (float) -Math.sin(z); rz.m[0][2] = 0; rz.m[0][3] = 0; 64 | rz.m[1][0] = (float) Math.sin(z); rz.m[1][1] = (float) Math.cos(z); rz.m[1][2] = 0; rz.m[1][3] = 0; 65 | rz.m[2][0] = 0; rz.m[2][1] = 0; rz.m[2][2] = 1; rz.m[2][3] = 0; 66 | rz.m[3][0] = 0; rz.m[3][1] = 0; rz.m[3][2] = 0; rz.m[3][3] = 1; 67 | 68 | switch(order) { 69 | case XYZ: 70 | m = rz.mul(ry.mul(rx)).getM(); 71 | break; 72 | case ZXY: 73 | m = ry.mul(rx.mul(rz)).getM(); 74 | break; 75 | case YZX: 76 | m = rx.mul(rz.mul(ry)).getM(); 77 | break; 78 | case ZYX: 79 | m = rx.mul(ry.mul(rz)).getM(); 80 | break; 81 | case YXZ: 82 | m = rz.mul(rx.mul(ry)).getM(); 83 | break; 84 | case XZY: 85 | m = ry.mul(rz.mul(rx)).getM(); 86 | break; 87 | } 88 | 89 | return this; 90 | } 91 | 92 | public Matrix4 initScale(Vector3 v) { 93 | return initScale(v.getX(), v.getY(), v.getZ()); 94 | } 95 | 96 | public Matrix4 initScale(float x, float y, float z) { 97 | m[0][0] = x; m[0][1] = 0; m[0][2] = 0; m[0][3] = 0; 98 | m[1][0] = 0; m[1][1] = y; m[1][2] = 0; m[1][3] = 0; 99 | m[2][0] = 0; m[2][1] = 0; m[2][2] = z; m[2][3] = 0; 100 | m[3][0] = 0; m[3][1] = 0; m[3][2] = 0; m[3][3] = 1; 101 | 102 | return this; 103 | } 104 | 105 | public Matrix4 initPerspective(float fov, float aspectRatio, float zNear, float zFar) { 106 | float t = (float) (zNear * Math.tan(Math.PI / 180.0f * (fov / 2))); 107 | float b = -t; 108 | float r = t * aspectRatio; 109 | float l = -r; 110 | 111 | m[0][0] = (2 * zNear) / (r - l); m[0][1] = 0; m[0][2] = (r + l) / (r - l); m[0][3] = 0; 112 | m[1][0] = 0; m[1][1] = (2 * zNear) / (t - b); m[1][2] = (t + b) / (t - b); m[1][3] = 0; 113 | m[2][0] = 0; m[2][1] = 0; m[2][2] = -(zFar + zNear) / (zFar - zNear); m[2][3] = (-2 * zFar * zNear) / (zFar - zNear); 114 | m[3][0] = 0; m[3][1] = 0; m[3][2] = -1; m[3][3] = 0; 115 | 116 | return this; 117 | } 118 | 119 | public Matrix4 initOrthographic(float left, float right, float top, float bottom, float zNear, float zFar) { 120 | m[0][0] = 2.0f / (right - left); m[0][1] = 0; m[0][2] = 0; m[0][3] = -(right + left) / (right - left); 121 | m[1][0] = 0; m[1][1] = 2.0f / (top - bottom); m[1][2] = 0; m[1][3] = -(top + bottom) / (top - bottom); 122 | m[2][0] = 0; m[2][1] = 0; m[2][2] = -2.0f / (zFar - zNear); m[2][3] = -(zFar + zNear) / (zFar - zNear); 123 | m[3][0] = 0; m[3][1] = 0; m[3][2] = 0; m[3][3] = 1; 124 | 125 | return this; 126 | } 127 | 128 | public Vector3 transform(Vector4 v) { 129 | return new Vector3(m[0][0] * v.getX() + m[1][0] * v.getY() + m[2][0] * v.getZ() + m[3][0] * v.getW(), 130 | m[0][1] * v.getX() + m[1][1] * v.getY() + m[2][1] * v.getZ() + m[3][1] * v.getW(), 131 | m[0][2] * v.getX() + m[1][2] * v.getY() + m[2][2] * v.getZ() + m[3][2] * v.getW()); 132 | } 133 | 134 | public Matrix4 transpose() { 135 | try { 136 | Matrix4 mat = (Matrix4) this.clone(); 137 | 138 | for(int x = 0; x < 4; x++) { 139 | for(int y = 0; y < 4; y++) { 140 | m[x][y] = mat.m[y][x]; 141 | } 142 | } 143 | 144 | return this; 145 | } catch (CloneNotSupportedException e) { 146 | e.printStackTrace(); 147 | } 148 | 149 | return null; 150 | } 151 | 152 | /** 153 | * A new matrix will be returned 154 | * @return Returns the inverse of this matrix 155 | */ 156 | public Matrix4 inverse() { 157 | Matrix4 matrix = new Matrix4(); 158 | 159 | matrix.m[0][0] = m[1][1] * m[2][2] * m[3][3] + m[1][2] * m[2][3] * m[3][1] + m[1][3] * m[2][1] * m[3][2] - m[1][1] * m[2][3] * m[3][2] - m[1][2] * m[2][1] * m[3][3] - m[1][3] * m[2][2] * m[3][1]; 160 | matrix.m[0][1] = m[0][1] * m[2][3] * m[3][2] + m[0][2] * m[2][1] * m[3][3] + m[0][3] * m[2][2] * m[3][1] - m[0][1] * m[2][2] * m[3][3] - m[0][2] * m[2][3] * m[3][1] - m[0][3] * m[2][1] * m[3][2]; 161 | matrix.m[0][2] = m[0][1] * m[1][2] * m[3][3] + m[0][2] * m[1][3] * m[3][1] + m[0][3] * m[1][1] * m[3][2] - m[0][1] * m[1][3] * m[3][2] - m[0][2] * m[1][1] * m[3][3] - m[0][3] * m[1][2] * m[3][1]; 162 | matrix.m[0][3] = m[0][1] * m[1][3] * m[2][2] + m[0][2] * m[1][1] * m[2][3] + m[0][3] * m[1][2] * m[2][1] - m[0][1] * m[1][2] * m[2][3] - m[0][2] * m[1][3] * m[2][1] - m[0][3] * m[1][1] * m[2][2]; 163 | matrix.m[1][0] = m[1][0] * m[2][3] * m[3][2] + m[1][2] * m[2][0] * m[3][3] + m[1][3] * m[2][2] * m[3][0] - m[1][0] * m[2][2] * m[3][3] - m[1][2] * m[2][3] * m[3][0] - m[1][3] * m[2][0] * m[3][2]; 164 | matrix.m[1][1] = m[0][0] * m[2][2] * m[3][3] + m[0][2] * m[2][3] * m[3][0] + m[0][3] * m[2][0] * m[3][2] - m[0][0] * m[2][3] * m[3][2] - m[0][2] * m[2][0] * m[3][3] - m[0][3] * m[2][2] * m[3][0]; 165 | matrix.m[1][2] = m[0][0] * m[1][3] * m[3][2] + m[0][2] * m[1][0] * m[3][3] + m[0][3] * m[1][3] * m[3][0] - m[0][0] * m[1][2] * m[3][3] - m[0][2] * m[1][3] * m[3][0] - m[0][3] * m[1][0] * m[3][2]; 166 | matrix.m[1][3] = m[0][0] * m[1][2] * m[2][3] + m[0][2] * m[1][3] * m[2][0] + m[0][3] * m[1][0] * m[2][2] - m[0][0] * m[1][3] * m[2][2] - m[0][2] * m[1][0] * m[2][3] - m[0][3] * m[1][2] * m[2][0]; 167 | matrix.m[2][0] = m[1][0] * m[2][1] * m[3][3] + m[1][1] * m[2][3] * m[3][0] + m[1][3] * m[2][0] * m[3][1] - m[1][0] * m[2][3] * m[3][1] - m[1][1] * m[2][0] * m[3][3] - m[1][3] * m[2][1] * m[3][0]; 168 | matrix.m[2][1] = m[0][0] * m[2][3] * m[3][1] + m[0][1] * m[2][0] * m[3][3] + m[0][3] * m[2][1] * m[3][0] - m[0][0] * m[2][1] * m[3][3] - m[0][1] * m[2][3] * m[3][0] - m[0][3] * m[2][0] * m[3][1]; 169 | matrix.m[2][2] = m[0][0] * m[1][1] * m[3][3] + m[0][1] * m[1][3] * m[3][0] + m[0][3] * m[1][0] * m[3][1] - m[0][0] * m[1][3] * m[3][1] - m[0][1] * m[1][0] * m[3][3] - m[0][3] * m[1][1] * m[3][0]; 170 | matrix.m[2][3] = m[0][0] * m[1][3] * m[2][1] + m[0][1] * m[1][0] * m[2][3] + m[0][3] * m[1][1] * m[2][0] - m[0][0] * m[1][1] * m[2][3] - m[0][1] * m[1][3] * m[2][0] - m[0][3] * m[1][0] * m[2][1]; 171 | matrix.m[3][0] = m[1][0] * m[2][2] * m[3][1] + m[1][1] * m[2][0] * m[3][2] + m[1][2] * m[2][1] * m[3][0] - m[1][0] * m[2][1] * m[3][2] - m[1][1] * m[2][2] * m[3][0] - m[1][2] * m[2][0] * m[3][1]; 172 | matrix.m[3][1] = m[0][0] * m[2][1] * m[3][2] + m[0][1] * m[2][2] * m[3][0] + m[0][2] * m[2][0] * m[3][1] - m[0][0] * m[2][2] * m[3][1] - m[0][1] * m[2][0] * m[3][2] - m[0][2] * m[2][1] * m[3][0]; 173 | matrix.m[3][2] = m[0][0] * m[1][2] * m[3][1] + m[0][1] * m[1][0] * m[3][2] + m[0][2] * m[1][1] * m[3][0] - m[0][0] * m[1][1] * m[3][2] - m[0][1] * m[1][2] * m[3][0] - m[0][2] * m[1][0] * m[3][1]; 174 | matrix.m[3][3] = m[0][0] * m[1][1] * m[2][2] + m[0][1] * m[1][2] * m[2][0] + m[0][2] * m[1][0] * m[2][1] - m[0][0] * m[1][2] * m[2][1] - m[0][1] * m[1][0] * m[2][2] - m[0][2] * m[1][1] * m[2][0]; 175 | 176 | return matrix; 177 | } 178 | 179 | public Matrix4 mul(Matrix4 v) { 180 | Matrix4 r = new Matrix4(); 181 | 182 | for(int x = 0; x < 4; x++) { 183 | for(int y = 0; y < 4; y++) { 184 | r.set(x, y, m[x][0] * v.get(0, y) + 185 | m[x][1] * v.get(1, y) + 186 | m[x][2] * v.get(2, y) + 187 | m[x][3] * v.get(3, y)); 188 | } 189 | } 190 | 191 | return r; 192 | } 193 | 194 | public float get(int x, int y) { 195 | return m[x][y]; 196 | } 197 | 198 | public void set(int x, int y, float v) { 199 | m[x][y] = v; 200 | } 201 | 202 | public float[][] getM() { 203 | return m; 204 | } 205 | 206 | public void setM(float[][] m) { 207 | this.m = m; 208 | } 209 | 210 | @Override 211 | public String toString() { 212 | StringBuilder sb = new StringBuilder(); 213 | 214 | int c = 0; 215 | for(int x = 0; x < 4; x++) { 216 | for(int y = 0; y < 4; y++) { 217 | if(c > 3) { 218 | sb.append("\n"); 219 | c = 0; 220 | } 221 | 222 | sb.append(m[x][y] + " | "); 223 | c++; 224 | } 225 | } 226 | 227 | return sb.toString(); 228 | } 229 | 230 | } 231 | -------------------------------------------------------------------------------- /src/de/meinkraft/OpenSimplexNoiseOctave.java: -------------------------------------------------------------------------------- 1 | package de.meinkraft; 2 | 3 | /* 4 | * OpenSimplex Noise in Java. 5 | * by Kurt Spencer 6 | * 7 | * v1.1 (October 5, 2014) 8 | * - Added 2D and 4D implementations. 9 | * - Proper gradient sets for all dimensions, from a 10 | * dimensionally-generalizable scheme with an actual 11 | * rhyme and reason behind it. 12 | * - Removed default permutation array in favor of 13 | * default seed. 14 | * - Changed seed-based constructor to be independent 15 | * of any particular randomization library, so results 16 | * will be the same when ported to other languages. 17 | */ 18 | 19 | public class OpenSimplexNoiseOctave { 20 | 21 | private static final double STRETCH_CONSTANT_2D = -0.211324865405187; //(1/Math.sqrt(2+1)-1)/2; 22 | private static final double SQUISH_CONSTANT_2D = 0.366025403784439; //(Math.sqrt(2+1)-1)/2; 23 | private static final double STRETCH_CONSTANT_3D = -1.0 / 6; //(1/Math.sqrt(3+1)-1)/3; 24 | private static final double SQUISH_CONSTANT_3D = 1.0 / 3; //(Math.sqrt(3+1)-1)/3; 25 | private static final double STRETCH_CONSTANT_4D = -0.138196601125011; //(1/Math.sqrt(4+1)-1)/4; 26 | private static final double SQUISH_CONSTANT_4D = 0.309016994374947; //(Math.sqrt(4+1)-1)/4; 27 | 28 | private static final double NORM_CONSTANT_2D = 47; 29 | private static final double NORM_CONSTANT_3D = 103; 30 | private static final double NORM_CONSTANT_4D = 30; 31 | 32 | private static final long DEFAULT_SEED = 0; 33 | 34 | private short[] perm; 35 | private short[] permGradIndex3D; 36 | 37 | public OpenSimplexNoiseOctave() { 38 | this(DEFAULT_SEED); 39 | } 40 | 41 | public OpenSimplexNoiseOctave(short[] perm) { 42 | this.perm = perm; 43 | permGradIndex3D = new short[256]; 44 | 45 | for (int i = 0; i < 256; i++) { 46 | //Since 3D has 24 gradients, simple bitmask won't work, so precompute modulo array. 47 | permGradIndex3D[i] = (short)((perm[i] % (gradients3D.length / 3)) * 3); 48 | } 49 | } 50 | 51 | //Initializes the class using a permutation array generated from a 64-bit seed. 52 | //Generates a proper permutation (i.e. doesn't merely perform N successive pair swaps on a base array) 53 | //Uses a simple 64-bit LCG. 54 | public OpenSimplexNoiseOctave(long seed) { 55 | perm = new short[256]; 56 | permGradIndex3D = new short[256]; 57 | short[] source = new short[256]; 58 | for (short i = 0; i < 256; i++) 59 | source[i] = i; 60 | seed = seed * 6364136223846793005l + 1442695040888963407l; 61 | seed = seed * 6364136223846793005l + 1442695040888963407l; 62 | seed = seed * 6364136223846793005l + 1442695040888963407l; 63 | for (int i = 255; i >= 0; i--) { 64 | seed = seed * 6364136223846793005l + 1442695040888963407l; 65 | int r = (int)((seed + 31) % (i + 1)); 66 | if (r < 0) 67 | r += (i + 1); 68 | perm[i] = source[r]; 69 | permGradIndex3D[i] = (short)((perm[i] % (gradients3D.length / 3)) * 3); 70 | source[r] = source[i]; 71 | } 72 | } 73 | 74 | //2D OpenSimplex Noise. 75 | public double eval(double x, double y) { 76 | 77 | //Place input coordinates onto grid. 78 | double stretchOffset = (x + y) * STRETCH_CONSTANT_2D; 79 | double xs = x + stretchOffset; 80 | double ys = y + stretchOffset; 81 | 82 | //Floor to get grid coordinates of rhombus (stretched square) super-cell origin. 83 | int xsb = fastFloor(xs); 84 | int ysb = fastFloor(ys); 85 | 86 | //Skew out to get actual coordinates of rhombus origin. We'll need these later. 87 | double squishOffset = (xsb + ysb) * SQUISH_CONSTANT_2D; 88 | double xb = xsb + squishOffset; 89 | double yb = ysb + squishOffset; 90 | 91 | //Compute grid coordinates relative to rhombus origin. 92 | double xins = xs - xsb; 93 | double yins = ys - ysb; 94 | 95 | //Sum those together to get a value that determines which region we're in. 96 | double inSum = xins + yins; 97 | 98 | //Positions relative to origin point. 99 | double dx0 = x - xb; 100 | double dy0 = y - yb; 101 | 102 | //We'll be defining these inside the next block and using them afterwards. 103 | double dx_ext, dy_ext; 104 | int xsv_ext, ysv_ext; 105 | 106 | double value = 0; 107 | 108 | //Contribution (1,0) 109 | double dx1 = dx0 - 1 - SQUISH_CONSTANT_2D; 110 | double dy1 = dy0 - 0 - SQUISH_CONSTANT_2D; 111 | double attn1 = 2 - dx1 * dx1 - dy1 * dy1; 112 | if (attn1 > 0) { 113 | attn1 *= attn1; 114 | value += attn1 * attn1 * extrapolate(xsb + 1, ysb + 0, dx1, dy1); 115 | } 116 | 117 | //Contribution (0,1) 118 | double dx2 = dx0 - 0 - SQUISH_CONSTANT_2D; 119 | double dy2 = dy0 - 1 - SQUISH_CONSTANT_2D; 120 | double attn2 = 2 - dx2 * dx2 - dy2 * dy2; 121 | if (attn2 > 0) { 122 | attn2 *= attn2; 123 | value += attn2 * attn2 * extrapolate(xsb + 0, ysb + 1, dx2, dy2); 124 | } 125 | 126 | if (inSum <= 1) { //We're inside the triangle (2-Simplex) at (0,0) 127 | double zins = 1 - inSum; 128 | if (zins > xins || zins > yins) { //(0,0) is one of the closest two triangular vertices 129 | if (xins > yins) { 130 | xsv_ext = xsb + 1; 131 | ysv_ext = ysb - 1; 132 | dx_ext = dx0 - 1; 133 | dy_ext = dy0 + 1; 134 | } else { 135 | xsv_ext = xsb - 1; 136 | ysv_ext = ysb + 1; 137 | dx_ext = dx0 + 1; 138 | dy_ext = dy0 - 1; 139 | } 140 | } else { //(1,0) and (0,1) are the closest two vertices. 141 | xsv_ext = xsb + 1; 142 | ysv_ext = ysb + 1; 143 | dx_ext = dx0 - 1 - 2 * SQUISH_CONSTANT_2D; 144 | dy_ext = dy0 - 1 - 2 * SQUISH_CONSTANT_2D; 145 | } 146 | } else { //We're inside the triangle (2-Simplex) at (1,1) 147 | double zins = 2 - inSum; 148 | if (zins < xins || zins < yins) { //(0,0) is one of the closest two triangular vertices 149 | if (xins > yins) { 150 | xsv_ext = xsb + 2; 151 | ysv_ext = ysb + 0; 152 | dx_ext = dx0 - 2 - 2 * SQUISH_CONSTANT_2D; 153 | dy_ext = dy0 + 0 - 2 * SQUISH_CONSTANT_2D; 154 | } else { 155 | xsv_ext = xsb + 0; 156 | ysv_ext = ysb + 2; 157 | dx_ext = dx0 + 0 - 2 * SQUISH_CONSTANT_2D; 158 | dy_ext = dy0 - 2 - 2 * SQUISH_CONSTANT_2D; 159 | } 160 | } else { //(1,0) and (0,1) are the closest two vertices. 161 | dx_ext = dx0; 162 | dy_ext = dy0; 163 | xsv_ext = xsb; 164 | ysv_ext = ysb; 165 | } 166 | xsb += 1; 167 | ysb += 1; 168 | dx0 = dx0 - 1 - 2 * SQUISH_CONSTANT_2D; 169 | dy0 = dy0 - 1 - 2 * SQUISH_CONSTANT_2D; 170 | } 171 | 172 | //Contribution (0,0) or (1,1) 173 | double attn0 = 2 - dx0 * dx0 - dy0 * dy0; 174 | if (attn0 > 0) { 175 | attn0 *= attn0; 176 | value += attn0 * attn0 * extrapolate(xsb, ysb, dx0, dy0); 177 | } 178 | 179 | //Extra Vertex 180 | double attn_ext = 2 - dx_ext * dx_ext - dy_ext * dy_ext; 181 | if (attn_ext > 0) { 182 | attn_ext *= attn_ext; 183 | value += attn_ext * attn_ext * extrapolate(xsv_ext, ysv_ext, dx_ext, dy_ext); 184 | } 185 | 186 | return value / NORM_CONSTANT_2D; 187 | } 188 | 189 | //3D OpenSimplex Noise. 190 | public double eval(double x, double y, double z) { 191 | 192 | //Place input coordinates on simplectic honeycomb. 193 | double stretchOffset = (x + y + z) * STRETCH_CONSTANT_3D; 194 | double xs = x + stretchOffset; 195 | double ys = y + stretchOffset; 196 | double zs = z + stretchOffset; 197 | 198 | //Floor to get simplectic honeycomb coordinates of rhombohedron (stretched cube) super-cell origin. 199 | int xsb = fastFloor(xs); 200 | int ysb = fastFloor(ys); 201 | int zsb = fastFloor(zs); 202 | 203 | //Skew out to get actual coordinates of rhombohedron origin. We'll need these later. 204 | double squishOffset = (xsb + ysb + zsb) * SQUISH_CONSTANT_3D; 205 | double xb = xsb + squishOffset; 206 | double yb = ysb + squishOffset; 207 | double zb = zsb + squishOffset; 208 | 209 | //Compute simplectic honeycomb coordinates relative to rhombohedral origin. 210 | double xins = xs - xsb; 211 | double yins = ys - ysb; 212 | double zins = zs - zsb; 213 | 214 | //Sum those together to get a value that determines which region we're in. 215 | double inSum = xins + yins + zins; 216 | 217 | //Positions relative to origin point. 218 | double dx0 = x - xb; 219 | double dy0 = y - yb; 220 | double dz0 = z - zb; 221 | 222 | //We'll be defining these inside the next block and using them afterwards. 223 | double dx_ext0, dy_ext0, dz_ext0; 224 | double dx_ext1, dy_ext1, dz_ext1; 225 | int xsv_ext0, ysv_ext0, zsv_ext0; 226 | int xsv_ext1, ysv_ext1, zsv_ext1; 227 | 228 | double value = 0; 229 | if (inSum <= 1) { //We're inside the tetrahedron (3-Simplex) at (0,0,0) 230 | 231 | //Determine which two of (0,0,1), (0,1,0), (1,0,0) are closest. 232 | byte aPoint = 0x01; 233 | double aScore = xins; 234 | byte bPoint = 0x02; 235 | double bScore = yins; 236 | if (aScore >= bScore && zins > bScore) { 237 | bScore = zins; 238 | bPoint = 0x04; 239 | } else if (aScore < bScore && zins > aScore) { 240 | aScore = zins; 241 | aPoint = 0x04; 242 | } 243 | 244 | //Now we determine the two lattice points not part of the tetrahedron that may contribute. 245 | //This depends on the closest two tetrahedral vertices, including (0,0,0) 246 | double wins = 1 - inSum; 247 | if (wins > aScore || wins > bScore) { //(0,0,0) is one of the closest two tetrahedral vertices. 248 | byte c = (bScore > aScore ? bPoint : aPoint); //Our other closest vertex is the closest out of a and b. 249 | 250 | if ((c & 0x01) == 0) { 251 | xsv_ext0 = xsb - 1; 252 | xsv_ext1 = xsb; 253 | dx_ext0 = dx0 + 1; 254 | dx_ext1 = dx0; 255 | } else { 256 | xsv_ext0 = xsv_ext1 = xsb + 1; 257 | dx_ext0 = dx_ext1 = dx0 - 1; 258 | } 259 | 260 | if ((c & 0x02) == 0) { 261 | ysv_ext0 = ysv_ext1 = ysb; 262 | dy_ext0 = dy_ext1 = dy0; 263 | if ((c & 0x01) == 0) { 264 | ysv_ext1 -= 1; 265 | dy_ext1 += 1; 266 | } else { 267 | ysv_ext0 -= 1; 268 | dy_ext0 += 1; 269 | } 270 | } else { 271 | ysv_ext0 = ysv_ext1 = ysb + 1; 272 | dy_ext0 = dy_ext1 = dy0 - 1; 273 | } 274 | 275 | if ((c & 0x04) == 0) { 276 | zsv_ext0 = zsb; 277 | zsv_ext1 = zsb - 1; 278 | dz_ext0 = dz0; 279 | dz_ext1 = dz0 + 1; 280 | } else { 281 | zsv_ext0 = zsv_ext1 = zsb + 1; 282 | dz_ext0 = dz_ext1 = dz0 - 1; 283 | } 284 | } else { //(0,0,0) is not one of the closest two tetrahedral vertices. 285 | byte c = (byte)(aPoint | bPoint); //Our two extra vertices are determined by the closest two. 286 | 287 | if ((c & 0x01) == 0) { 288 | xsv_ext0 = xsb; 289 | xsv_ext1 = xsb - 1; 290 | dx_ext0 = dx0 - 2 * SQUISH_CONSTANT_3D; 291 | dx_ext1 = dx0 + 1 - SQUISH_CONSTANT_3D; 292 | } else { 293 | xsv_ext0 = xsv_ext1 = xsb + 1; 294 | dx_ext0 = dx0 - 1 - 2 * SQUISH_CONSTANT_3D; 295 | dx_ext1 = dx0 - 1 - SQUISH_CONSTANT_3D; 296 | } 297 | 298 | if ((c & 0x02) == 0) { 299 | ysv_ext0 = ysb; 300 | ysv_ext1 = ysb - 1; 301 | dy_ext0 = dy0 - 2 * SQUISH_CONSTANT_3D; 302 | dy_ext1 = dy0 + 1 - SQUISH_CONSTANT_3D; 303 | } else { 304 | ysv_ext0 = ysv_ext1 = ysb + 1; 305 | dy_ext0 = dy0 - 1 - 2 * SQUISH_CONSTANT_3D; 306 | dy_ext1 = dy0 - 1 - SQUISH_CONSTANT_3D; 307 | } 308 | 309 | if ((c & 0x04) == 0) { 310 | zsv_ext0 = zsb; 311 | zsv_ext1 = zsb - 1; 312 | dz_ext0 = dz0 - 2 * SQUISH_CONSTANT_3D; 313 | dz_ext1 = dz0 + 1 - SQUISH_CONSTANT_3D; 314 | } else { 315 | zsv_ext0 = zsv_ext1 = zsb + 1; 316 | dz_ext0 = dz0 - 1 - 2 * SQUISH_CONSTANT_3D; 317 | dz_ext1 = dz0 - 1 - SQUISH_CONSTANT_3D; 318 | } 319 | } 320 | 321 | //Contribution (0,0,0) 322 | double attn0 = 2 - dx0 * dx0 - dy0 * dy0 - dz0 * dz0; 323 | if (attn0 > 0) { 324 | attn0 *= attn0; 325 | value += attn0 * attn0 * extrapolate(xsb + 0, ysb + 0, zsb + 0, dx0, dy0, dz0); 326 | } 327 | 328 | //Contribution (1,0,0) 329 | double dx1 = dx0 - 1 - SQUISH_CONSTANT_3D; 330 | double dy1 = dy0 - 0 - SQUISH_CONSTANT_3D; 331 | double dz1 = dz0 - 0 - SQUISH_CONSTANT_3D; 332 | double attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1; 333 | if (attn1 > 0) { 334 | attn1 *= attn1; 335 | value += attn1 * attn1 * extrapolate(xsb + 1, ysb + 0, zsb + 0, dx1, dy1, dz1); 336 | } 337 | 338 | //Contribution (0,1,0) 339 | double dx2 = dx0 - 0 - SQUISH_CONSTANT_3D; 340 | double dy2 = dy0 - 1 - SQUISH_CONSTANT_3D; 341 | double dz2 = dz1; 342 | double attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2; 343 | if (attn2 > 0) { 344 | attn2 *= attn2; 345 | value += attn2 * attn2 * extrapolate(xsb + 0, ysb + 1, zsb + 0, dx2, dy2, dz2); 346 | } 347 | 348 | //Contribution (0,0,1) 349 | double dx3 = dx2; 350 | double dy3 = dy1; 351 | double dz3 = dz0 - 1 - SQUISH_CONSTANT_3D; 352 | double attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3; 353 | if (attn3 > 0) { 354 | attn3 *= attn3; 355 | value += attn3 * attn3 * extrapolate(xsb + 0, ysb + 0, zsb + 1, dx3, dy3, dz3); 356 | } 357 | } else if (inSum >= 2) { //We're inside the tetrahedron (3-Simplex) at (1,1,1) 358 | 359 | //Determine which two tetrahedral vertices are the closest, out of (1,1,0), (1,0,1), (0,1,1) but not (1,1,1). 360 | byte aPoint = 0x06; 361 | double aScore = xins; 362 | byte bPoint = 0x05; 363 | double bScore = yins; 364 | if (aScore <= bScore && zins < bScore) { 365 | bScore = zins; 366 | bPoint = 0x03; 367 | } else if (aScore > bScore && zins < aScore) { 368 | aScore = zins; 369 | aPoint = 0x03; 370 | } 371 | 372 | //Now we determine the two lattice points not part of the tetrahedron that may contribute. 373 | //This depends on the closest two tetrahedral vertices, including (1,1,1) 374 | double wins = 3 - inSum; 375 | if (wins < aScore || wins < bScore) { //(1,1,1) is one of the closest two tetrahedral vertices. 376 | byte c = (bScore < aScore ? bPoint : aPoint); //Our other closest vertex is the closest out of a and b. 377 | 378 | if ((c & 0x01) != 0) { 379 | xsv_ext0 = xsb + 2; 380 | xsv_ext1 = xsb + 1; 381 | dx_ext0 = dx0 - 2 - 3 * SQUISH_CONSTANT_3D; 382 | dx_ext1 = dx0 - 1 - 3 * SQUISH_CONSTANT_3D; 383 | } else { 384 | xsv_ext0 = xsv_ext1 = xsb; 385 | dx_ext0 = dx_ext1 = dx0 - 3 * SQUISH_CONSTANT_3D; 386 | } 387 | 388 | if ((c & 0x02) != 0) { 389 | ysv_ext0 = ysv_ext1 = ysb + 1; 390 | dy_ext0 = dy_ext1 = dy0 - 1 - 3 * SQUISH_CONSTANT_3D; 391 | if ((c & 0x01) != 0) { 392 | ysv_ext1 += 1; 393 | dy_ext1 -= 1; 394 | } else { 395 | ysv_ext0 += 1; 396 | dy_ext0 -= 1; 397 | } 398 | } else { 399 | ysv_ext0 = ysv_ext1 = ysb; 400 | dy_ext0 = dy_ext1 = dy0 - 3 * SQUISH_CONSTANT_3D; 401 | } 402 | 403 | if ((c & 0x04) != 0) { 404 | zsv_ext0 = zsb + 1; 405 | zsv_ext1 = zsb + 2; 406 | dz_ext0 = dz0 - 1 - 3 * SQUISH_CONSTANT_3D; 407 | dz_ext1 = dz0 - 2 - 3 * SQUISH_CONSTANT_3D; 408 | } else { 409 | zsv_ext0 = zsv_ext1 = zsb; 410 | dz_ext0 = dz_ext1 = dz0 - 3 * SQUISH_CONSTANT_3D; 411 | } 412 | } else { //(1,1,1) is not one of the closest two tetrahedral vertices. 413 | byte c = (byte)(aPoint & bPoint); //Our two extra vertices are determined by the closest two. 414 | 415 | if ((c & 0x01) != 0) { 416 | xsv_ext0 = xsb + 1; 417 | xsv_ext1 = xsb + 2; 418 | dx_ext0 = dx0 - 1 - SQUISH_CONSTANT_3D; 419 | dx_ext1 = dx0 - 2 - 2 * SQUISH_CONSTANT_3D; 420 | } else { 421 | xsv_ext0 = xsv_ext1 = xsb; 422 | dx_ext0 = dx0 - SQUISH_CONSTANT_3D; 423 | dx_ext1 = dx0 - 2 * SQUISH_CONSTANT_3D; 424 | } 425 | 426 | if ((c & 0x02) != 0) { 427 | ysv_ext0 = ysb + 1; 428 | ysv_ext1 = ysb + 2; 429 | dy_ext0 = dy0 - 1 - SQUISH_CONSTANT_3D; 430 | dy_ext1 = dy0 - 2 - 2 * SQUISH_CONSTANT_3D; 431 | } else { 432 | ysv_ext0 = ysv_ext1 = ysb; 433 | dy_ext0 = dy0 - SQUISH_CONSTANT_3D; 434 | dy_ext1 = dy0 - 2 * SQUISH_CONSTANT_3D; 435 | } 436 | 437 | if ((c & 0x04) != 0) { 438 | zsv_ext0 = zsb + 1; 439 | zsv_ext1 = zsb + 2; 440 | dz_ext0 = dz0 - 1 - SQUISH_CONSTANT_3D; 441 | dz_ext1 = dz0 - 2 - 2 * SQUISH_CONSTANT_3D; 442 | } else { 443 | zsv_ext0 = zsv_ext1 = zsb; 444 | dz_ext0 = dz0 - SQUISH_CONSTANT_3D; 445 | dz_ext1 = dz0 - 2 * SQUISH_CONSTANT_3D; 446 | } 447 | } 448 | 449 | //Contribution (1,1,0) 450 | double dx3 = dx0 - 1 - 2 * SQUISH_CONSTANT_3D; 451 | double dy3 = dy0 - 1 - 2 * SQUISH_CONSTANT_3D; 452 | double dz3 = dz0 - 0 - 2 * SQUISH_CONSTANT_3D; 453 | double attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3; 454 | if (attn3 > 0) { 455 | attn3 *= attn3; 456 | value += attn3 * attn3 * extrapolate(xsb + 1, ysb + 1, zsb + 0, dx3, dy3, dz3); 457 | } 458 | 459 | //Contribution (1,0,1) 460 | double dx2 = dx3; 461 | double dy2 = dy0 - 0 - 2 * SQUISH_CONSTANT_3D; 462 | double dz2 = dz0 - 1 - 2 * SQUISH_CONSTANT_3D; 463 | double attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2; 464 | if (attn2 > 0) { 465 | attn2 *= attn2; 466 | value += attn2 * attn2 * extrapolate(xsb + 1, ysb + 0, zsb + 1, dx2, dy2, dz2); 467 | } 468 | 469 | //Contribution (0,1,1) 470 | double dx1 = dx0 - 0 - 2 * SQUISH_CONSTANT_3D; 471 | double dy1 = dy3; 472 | double dz1 = dz2; 473 | double attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1; 474 | if (attn1 > 0) { 475 | attn1 *= attn1; 476 | value += attn1 * attn1 * extrapolate(xsb + 0, ysb + 1, zsb + 1, dx1, dy1, dz1); 477 | } 478 | 479 | //Contribution (1,1,1) 480 | dx0 = dx0 - 1 - 3 * SQUISH_CONSTANT_3D; 481 | dy0 = dy0 - 1 - 3 * SQUISH_CONSTANT_3D; 482 | dz0 = dz0 - 1 - 3 * SQUISH_CONSTANT_3D; 483 | double attn0 = 2 - dx0 * dx0 - dy0 * dy0 - dz0 * dz0; 484 | if (attn0 > 0) { 485 | attn0 *= attn0; 486 | value += attn0 * attn0 * extrapolate(xsb + 1, ysb + 1, zsb + 1, dx0, dy0, dz0); 487 | } 488 | } else { //We're inside the octahedron (Rectified 3-Simplex) in between. 489 | double aScore; 490 | byte aPoint; 491 | boolean aIsFurtherSide; 492 | double bScore; 493 | byte bPoint; 494 | boolean bIsFurtherSide; 495 | 496 | //Decide between point (0,0,1) and (1,1,0) as closest 497 | double p1 = xins + yins; 498 | if (p1 > 1) { 499 | aScore = p1 - 1; 500 | aPoint = 0x03; 501 | aIsFurtherSide = true; 502 | } else { 503 | aScore = 1 - p1; 504 | aPoint = 0x04; 505 | aIsFurtherSide = false; 506 | } 507 | 508 | //Decide between point (0,1,0) and (1,0,1) as closest 509 | double p2 = xins + zins; 510 | if (p2 > 1) { 511 | bScore = p2 - 1; 512 | bPoint = 0x05; 513 | bIsFurtherSide = true; 514 | } else { 515 | bScore = 1 - p2; 516 | bPoint = 0x02; 517 | bIsFurtherSide = false; 518 | } 519 | 520 | //The closest out of the two (1,0,0) and (0,1,1) will replace the furthest out of the two decided above, if closer. 521 | double p3 = yins + zins; 522 | if (p3 > 1) { 523 | double score = p3 - 1; 524 | if (aScore <= bScore && aScore < score) { 525 | aScore = score; 526 | aPoint = 0x06; 527 | aIsFurtherSide = true; 528 | } else if (aScore > bScore && bScore < score) { 529 | bScore = score; 530 | bPoint = 0x06; 531 | bIsFurtherSide = true; 532 | } 533 | } else { 534 | double score = 1 - p3; 535 | if (aScore <= bScore && aScore < score) { 536 | aScore = score; 537 | aPoint = 0x01; 538 | aIsFurtherSide = false; 539 | } else if (aScore > bScore && bScore < score) { 540 | bScore = score; 541 | bPoint = 0x01; 542 | bIsFurtherSide = false; 543 | } 544 | } 545 | 546 | //Where each of the two closest points are determines how the extra two vertices are calculated. 547 | if (aIsFurtherSide == bIsFurtherSide) { 548 | if (aIsFurtherSide) { //Both closest points on (1,1,1) side 549 | 550 | //One of the two extra points is (1,1,1) 551 | dx_ext0 = dx0 - 1 - 3 * SQUISH_CONSTANT_3D; 552 | dy_ext0 = dy0 - 1 - 3 * SQUISH_CONSTANT_3D; 553 | dz_ext0 = dz0 - 1 - 3 * SQUISH_CONSTANT_3D; 554 | xsv_ext0 = xsb + 1; 555 | ysv_ext0 = ysb + 1; 556 | zsv_ext0 = zsb + 1; 557 | 558 | //Other extra point is based on the shared axis. 559 | byte c = (byte)(aPoint & bPoint); 560 | if ((c & 0x01) != 0) { 561 | dx_ext1 = dx0 - 2 - 2 * SQUISH_CONSTANT_3D; 562 | dy_ext1 = dy0 - 2 * SQUISH_CONSTANT_3D; 563 | dz_ext1 = dz0 - 2 * SQUISH_CONSTANT_3D; 564 | xsv_ext1 = xsb + 2; 565 | ysv_ext1 = ysb; 566 | zsv_ext1 = zsb; 567 | } else if ((c & 0x02) != 0) { 568 | dx_ext1 = dx0 - 2 * SQUISH_CONSTANT_3D; 569 | dy_ext1 = dy0 - 2 - 2 * SQUISH_CONSTANT_3D; 570 | dz_ext1 = dz0 - 2 * SQUISH_CONSTANT_3D; 571 | xsv_ext1 = xsb; 572 | ysv_ext1 = ysb + 2; 573 | zsv_ext1 = zsb; 574 | } else { 575 | dx_ext1 = dx0 - 2 * SQUISH_CONSTANT_3D; 576 | dy_ext1 = dy0 - 2 * SQUISH_CONSTANT_3D; 577 | dz_ext1 = dz0 - 2 - 2 * SQUISH_CONSTANT_3D; 578 | xsv_ext1 = xsb; 579 | ysv_ext1 = ysb; 580 | zsv_ext1 = zsb + 2; 581 | } 582 | } else {//Both closest points on (0,0,0) side 583 | 584 | //One of the two extra points is (0,0,0) 585 | dx_ext0 = dx0; 586 | dy_ext0 = dy0; 587 | dz_ext0 = dz0; 588 | xsv_ext0 = xsb; 589 | ysv_ext0 = ysb; 590 | zsv_ext0 = zsb; 591 | 592 | //Other extra point is based on the omitted axis. 593 | byte c = (byte)(aPoint | bPoint); 594 | if ((c & 0x01) == 0) { 595 | dx_ext1 = dx0 + 1 - SQUISH_CONSTANT_3D; 596 | dy_ext1 = dy0 - 1 - SQUISH_CONSTANT_3D; 597 | dz_ext1 = dz0 - 1 - SQUISH_CONSTANT_3D; 598 | xsv_ext1 = xsb - 1; 599 | ysv_ext1 = ysb + 1; 600 | zsv_ext1 = zsb + 1; 601 | } else if ((c & 0x02) == 0) { 602 | dx_ext1 = dx0 - 1 - SQUISH_CONSTANT_3D; 603 | dy_ext1 = dy0 + 1 - SQUISH_CONSTANT_3D; 604 | dz_ext1 = dz0 - 1 - SQUISH_CONSTANT_3D; 605 | xsv_ext1 = xsb + 1; 606 | ysv_ext1 = ysb - 1; 607 | zsv_ext1 = zsb + 1; 608 | } else { 609 | dx_ext1 = dx0 - 1 - SQUISH_CONSTANT_3D; 610 | dy_ext1 = dy0 - 1 - SQUISH_CONSTANT_3D; 611 | dz_ext1 = dz0 + 1 - SQUISH_CONSTANT_3D; 612 | xsv_ext1 = xsb + 1; 613 | ysv_ext1 = ysb + 1; 614 | zsv_ext1 = zsb - 1; 615 | } 616 | } 617 | } else { //One point on (0,0,0) side, one point on (1,1,1) side 618 | byte c1, c2; 619 | if (aIsFurtherSide) { 620 | c1 = aPoint; 621 | c2 = bPoint; 622 | } else { 623 | c1 = bPoint; 624 | c2 = aPoint; 625 | } 626 | 627 | //One contribution is a permutation of (1,1,-1) 628 | if ((c1 & 0x01) == 0) { 629 | dx_ext0 = dx0 + 1 - SQUISH_CONSTANT_3D; 630 | dy_ext0 = dy0 - 1 - SQUISH_CONSTANT_3D; 631 | dz_ext0 = dz0 - 1 - SQUISH_CONSTANT_3D; 632 | xsv_ext0 = xsb - 1; 633 | ysv_ext0 = ysb + 1; 634 | zsv_ext0 = zsb + 1; 635 | } else if ((c1 & 0x02) == 0) { 636 | dx_ext0 = dx0 - 1 - SQUISH_CONSTANT_3D; 637 | dy_ext0 = dy0 + 1 - SQUISH_CONSTANT_3D; 638 | dz_ext0 = dz0 - 1 - SQUISH_CONSTANT_3D; 639 | xsv_ext0 = xsb + 1; 640 | ysv_ext0 = ysb - 1; 641 | zsv_ext0 = zsb + 1; 642 | } else { 643 | dx_ext0 = dx0 - 1 - SQUISH_CONSTANT_3D; 644 | dy_ext0 = dy0 - 1 - SQUISH_CONSTANT_3D; 645 | dz_ext0 = dz0 + 1 - SQUISH_CONSTANT_3D; 646 | xsv_ext0 = xsb + 1; 647 | ysv_ext0 = ysb + 1; 648 | zsv_ext0 = zsb - 1; 649 | } 650 | 651 | //One contribution is a permutation of (0,0,2) 652 | dx_ext1 = dx0 - 2 * SQUISH_CONSTANT_3D; 653 | dy_ext1 = dy0 - 2 * SQUISH_CONSTANT_3D; 654 | dz_ext1 = dz0 - 2 * SQUISH_CONSTANT_3D; 655 | xsv_ext1 = xsb; 656 | ysv_ext1 = ysb; 657 | zsv_ext1 = zsb; 658 | if ((c2 & 0x01) != 0) { 659 | dx_ext1 -= 2; 660 | xsv_ext1 += 2; 661 | } else if ((c2 & 0x02) != 0) { 662 | dy_ext1 -= 2; 663 | ysv_ext1 += 2; 664 | } else { 665 | dz_ext1 -= 2; 666 | zsv_ext1 += 2; 667 | } 668 | } 669 | 670 | //Contribution (1,0,0) 671 | double dx1 = dx0 - 1 - SQUISH_CONSTANT_3D; 672 | double dy1 = dy0 - 0 - SQUISH_CONSTANT_3D; 673 | double dz1 = dz0 - 0 - SQUISH_CONSTANT_3D; 674 | double attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1; 675 | if (attn1 > 0) { 676 | attn1 *= attn1; 677 | value += attn1 * attn1 * extrapolate(xsb + 1, ysb + 0, zsb + 0, dx1, dy1, dz1); 678 | } 679 | 680 | //Contribution (0,1,0) 681 | double dx2 = dx0 - 0 - SQUISH_CONSTANT_3D; 682 | double dy2 = dy0 - 1 - SQUISH_CONSTANT_3D; 683 | double dz2 = dz1; 684 | double attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2; 685 | if (attn2 > 0) { 686 | attn2 *= attn2; 687 | value += attn2 * attn2 * extrapolate(xsb + 0, ysb + 1, zsb + 0, dx2, dy2, dz2); 688 | } 689 | 690 | //Contribution (0,0,1) 691 | double dx3 = dx2; 692 | double dy3 = dy1; 693 | double dz3 = dz0 - 1 - SQUISH_CONSTANT_3D; 694 | double attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3; 695 | if (attn3 > 0) { 696 | attn3 *= attn3; 697 | value += attn3 * attn3 * extrapolate(xsb + 0, ysb + 0, zsb + 1, dx3, dy3, dz3); 698 | } 699 | 700 | //Contribution (1,1,0) 701 | double dx4 = dx0 - 1 - 2 * SQUISH_CONSTANT_3D; 702 | double dy4 = dy0 - 1 - 2 * SQUISH_CONSTANT_3D; 703 | double dz4 = dz0 - 0 - 2 * SQUISH_CONSTANT_3D; 704 | double attn4 = 2 - dx4 * dx4 - dy4 * dy4 - dz4 * dz4; 705 | if (attn4 > 0) { 706 | attn4 *= attn4; 707 | value += attn4 * attn4 * extrapolate(xsb + 1, ysb + 1, zsb + 0, dx4, dy4, dz4); 708 | } 709 | 710 | //Contribution (1,0,1) 711 | double dx5 = dx4; 712 | double dy5 = dy0 - 0 - 2 * SQUISH_CONSTANT_3D; 713 | double dz5 = dz0 - 1 - 2 * SQUISH_CONSTANT_3D; 714 | double attn5 = 2 - dx5 * dx5 - dy5 * dy5 - dz5 * dz5; 715 | if (attn5 > 0) { 716 | attn5 *= attn5; 717 | value += attn5 * attn5 * extrapolate(xsb + 1, ysb + 0, zsb + 1, dx5, dy5, dz5); 718 | } 719 | 720 | //Contribution (0,1,1) 721 | double dx6 = dx0 - 0 - 2 * SQUISH_CONSTANT_3D; 722 | double dy6 = dy4; 723 | double dz6 = dz5; 724 | double attn6 = 2 - dx6 * dx6 - dy6 * dy6 - dz6 * dz6; 725 | if (attn6 > 0) { 726 | attn6 *= attn6; 727 | value += attn6 * attn6 * extrapolate(xsb + 0, ysb + 1, zsb + 1, dx6, dy6, dz6); 728 | } 729 | } 730 | 731 | //First extra vertex 732 | double attn_ext0 = 2 - dx_ext0 * dx_ext0 - dy_ext0 * dy_ext0 - dz_ext0 * dz_ext0; 733 | if (attn_ext0 > 0) 734 | { 735 | attn_ext0 *= attn_ext0; 736 | value += attn_ext0 * attn_ext0 * extrapolate(xsv_ext0, ysv_ext0, zsv_ext0, dx_ext0, dy_ext0, dz_ext0); 737 | } 738 | 739 | //Second extra vertex 740 | double attn_ext1 = 2 - dx_ext1 * dx_ext1 - dy_ext1 * dy_ext1 - dz_ext1 * dz_ext1; 741 | if (attn_ext1 > 0) 742 | { 743 | attn_ext1 *= attn_ext1; 744 | value += attn_ext1 * attn_ext1 * extrapolate(xsv_ext1, ysv_ext1, zsv_ext1, dx_ext1, dy_ext1, dz_ext1); 745 | } 746 | 747 | return value / NORM_CONSTANT_3D; 748 | } 749 | 750 | //4D OpenSimplex Noise. 751 | public double eval(double x, double y, double z, double w) { 752 | 753 | //Place input coordinates on simplectic honeycomb. 754 | double stretchOffset = (x + y + z + w) * STRETCH_CONSTANT_4D; 755 | double xs = x + stretchOffset; 756 | double ys = y + stretchOffset; 757 | double zs = z + stretchOffset; 758 | double ws = w + stretchOffset; 759 | 760 | //Floor to get simplectic honeycomb coordinates of rhombo-hypercube super-cell origin. 761 | int xsb = fastFloor(xs); 762 | int ysb = fastFloor(ys); 763 | int zsb = fastFloor(zs); 764 | int wsb = fastFloor(ws); 765 | 766 | //Skew out to get actual coordinates of stretched rhombo-hypercube origin. We'll need these later. 767 | double squishOffset = (xsb + ysb + zsb + wsb) * SQUISH_CONSTANT_4D; 768 | double xb = xsb + squishOffset; 769 | double yb = ysb + squishOffset; 770 | double zb = zsb + squishOffset; 771 | double wb = wsb + squishOffset; 772 | 773 | //Compute simplectic honeycomb coordinates relative to rhombo-hypercube origin. 774 | double xins = xs - xsb; 775 | double yins = ys - ysb; 776 | double zins = zs - zsb; 777 | double wins = ws - wsb; 778 | 779 | //Sum those together to get a value that determines which region we're in. 780 | double inSum = xins + yins + zins + wins; 781 | 782 | //Positions relative to origin point. 783 | double dx0 = x - xb; 784 | double dy0 = y - yb; 785 | double dz0 = z - zb; 786 | double dw0 = w - wb; 787 | 788 | //We'll be defining these inside the next block and using them afterwards. 789 | double dx_ext0, dy_ext0, dz_ext0, dw_ext0; 790 | double dx_ext1, dy_ext1, dz_ext1, dw_ext1; 791 | double dx_ext2, dy_ext2, dz_ext2, dw_ext2; 792 | int xsv_ext0, ysv_ext0, zsv_ext0, wsv_ext0; 793 | int xsv_ext1, ysv_ext1, zsv_ext1, wsv_ext1; 794 | int xsv_ext2, ysv_ext2, zsv_ext2, wsv_ext2; 795 | 796 | double value = 0; 797 | if (inSum <= 1) { //We're inside the pentachoron (4-Simplex) at (0,0,0,0) 798 | 799 | //Determine which two of (0,0,0,1), (0,0,1,0), (0,1,0,0), (1,0,0,0) are closest. 800 | byte aPoint = 0x01; 801 | double aScore = xins; 802 | byte bPoint = 0x02; 803 | double bScore = yins; 804 | if (aScore >= bScore && zins > bScore) { 805 | bScore = zins; 806 | bPoint = 0x04; 807 | } else if (aScore < bScore && zins > aScore) { 808 | aScore = zins; 809 | aPoint = 0x04; 810 | } 811 | if (aScore >= bScore && wins > bScore) { 812 | bScore = wins; 813 | bPoint = 0x08; 814 | } else if (aScore < bScore && wins > aScore) { 815 | aScore = wins; 816 | aPoint = 0x08; 817 | } 818 | 819 | //Now we determine the three lattice points not part of the pentachoron that may contribute. 820 | //This depends on the closest two pentachoron vertices, including (0,0,0,0) 821 | double uins = 1 - inSum; 822 | if (uins > aScore || uins > bScore) { //(0,0,0,0) is one of the closest two pentachoron vertices. 823 | byte c = (bScore > aScore ? bPoint : aPoint); //Our other closest vertex is the closest out of a and b. 824 | if ((c & 0x01) == 0) { 825 | xsv_ext0 = xsb - 1; 826 | xsv_ext1 = xsv_ext2 = xsb; 827 | dx_ext0 = dx0 + 1; 828 | dx_ext1 = dx_ext2 = dx0; 829 | } else { 830 | xsv_ext0 = xsv_ext1 = xsv_ext2 = xsb + 1; 831 | dx_ext0 = dx_ext1 = dx_ext2 = dx0 - 1; 832 | } 833 | 834 | if ((c & 0x02) == 0) { 835 | ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb; 836 | dy_ext0 = dy_ext1 = dy_ext2 = dy0; 837 | if ((c & 0x01) == 0x01) { 838 | ysv_ext0 -= 1; 839 | dy_ext0 += 1; 840 | } else { 841 | ysv_ext1 -= 1; 842 | dy_ext1 += 1; 843 | } 844 | } else { 845 | ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb + 1; 846 | dy_ext0 = dy_ext1 = dy_ext2 = dy0 - 1; 847 | } 848 | 849 | if ((c & 0x04) == 0) { 850 | zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb; 851 | dz_ext0 = dz_ext1 = dz_ext2 = dz0; 852 | if ((c & 0x03) != 0) { 853 | if ((c & 0x03) == 0x03) { 854 | zsv_ext0 -= 1; 855 | dz_ext0 += 1; 856 | } else { 857 | zsv_ext1 -= 1; 858 | dz_ext1 += 1; 859 | } 860 | } else { 861 | zsv_ext2 -= 1; 862 | dz_ext2 += 1; 863 | } 864 | } else { 865 | zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb + 1; 866 | dz_ext0 = dz_ext1 = dz_ext2 = dz0 - 1; 867 | } 868 | 869 | if ((c & 0x08) == 0) { 870 | wsv_ext0 = wsv_ext1 = wsb; 871 | wsv_ext2 = wsb - 1; 872 | dw_ext0 = dw_ext1 = dw0; 873 | dw_ext2 = dw0 + 1; 874 | } else { 875 | wsv_ext0 = wsv_ext1 = wsv_ext2 = wsb + 1; 876 | dw_ext0 = dw_ext1 = dw_ext2 = dw0 - 1; 877 | } 878 | } else { //(0,0,0,0) is not one of the closest two pentachoron vertices. 879 | byte c = (byte)(aPoint | bPoint); //Our three extra vertices are determined by the closest two. 880 | 881 | if ((c & 0x01) == 0) { 882 | xsv_ext0 = xsv_ext2 = xsb; 883 | xsv_ext1 = xsb - 1; 884 | dx_ext0 = dx0 - 2 * SQUISH_CONSTANT_4D; 885 | dx_ext1 = dx0 + 1 - SQUISH_CONSTANT_4D; 886 | dx_ext2 = dx0 - SQUISH_CONSTANT_4D; 887 | } else { 888 | xsv_ext0 = xsv_ext1 = xsv_ext2 = xsb + 1; 889 | dx_ext0 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D; 890 | dx_ext1 = dx_ext2 = dx0 - 1 - SQUISH_CONSTANT_4D; 891 | } 892 | 893 | if ((c & 0x02) == 0) { 894 | ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb; 895 | dy_ext0 = dy0 - 2 * SQUISH_CONSTANT_4D; 896 | dy_ext1 = dy_ext2 = dy0 - SQUISH_CONSTANT_4D; 897 | if ((c & 0x01) == 0x01) { 898 | ysv_ext1 -= 1; 899 | dy_ext1 += 1; 900 | } else { 901 | ysv_ext2 -= 1; 902 | dy_ext2 += 1; 903 | } 904 | } else { 905 | ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb + 1; 906 | dy_ext0 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D; 907 | dy_ext1 = dy_ext2 = dy0 - 1 - SQUISH_CONSTANT_4D; 908 | } 909 | 910 | if ((c & 0x04) == 0) { 911 | zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb; 912 | dz_ext0 = dz0 - 2 * SQUISH_CONSTANT_4D; 913 | dz_ext1 = dz_ext2 = dz0 - SQUISH_CONSTANT_4D; 914 | if ((c & 0x03) == 0x03) { 915 | zsv_ext1 -= 1; 916 | dz_ext1 += 1; 917 | } else { 918 | zsv_ext2 -= 1; 919 | dz_ext2 += 1; 920 | } 921 | } else { 922 | zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb + 1; 923 | dz_ext0 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D; 924 | dz_ext1 = dz_ext2 = dz0 - 1 - SQUISH_CONSTANT_4D; 925 | } 926 | 927 | if ((c & 0x08) == 0) { 928 | wsv_ext0 = wsv_ext1 = wsb; 929 | wsv_ext2 = wsb - 1; 930 | dw_ext0 = dw0 - 2 * SQUISH_CONSTANT_4D; 931 | dw_ext1 = dw0 - SQUISH_CONSTANT_4D; 932 | dw_ext2 = dw0 + 1 - SQUISH_CONSTANT_4D; 933 | } else { 934 | wsv_ext0 = wsv_ext1 = wsv_ext2 = wsb + 1; 935 | dw_ext0 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D; 936 | dw_ext1 = dw_ext2 = dw0 - 1 - SQUISH_CONSTANT_4D; 937 | } 938 | } 939 | 940 | //Contribution (0,0,0,0) 941 | double attn0 = 2 - dx0 * dx0 - dy0 * dy0 - dz0 * dz0 - dw0 * dw0; 942 | if (attn0 > 0) { 943 | attn0 *= attn0; 944 | value += attn0 * attn0 * extrapolate(xsb + 0, ysb + 0, zsb + 0, wsb + 0, dx0, dy0, dz0, dw0); 945 | } 946 | 947 | //Contribution (1,0,0,0) 948 | double dx1 = dx0 - 1 - SQUISH_CONSTANT_4D; 949 | double dy1 = dy0 - 0 - SQUISH_CONSTANT_4D; 950 | double dz1 = dz0 - 0 - SQUISH_CONSTANT_4D; 951 | double dw1 = dw0 - 0 - SQUISH_CONSTANT_4D; 952 | double attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1 - dw1 * dw1; 953 | if (attn1 > 0) { 954 | attn1 *= attn1; 955 | value += attn1 * attn1 * extrapolate(xsb + 1, ysb + 0, zsb + 0, wsb + 0, dx1, dy1, dz1, dw1); 956 | } 957 | 958 | //Contribution (0,1,0,0) 959 | double dx2 = dx0 - 0 - SQUISH_CONSTANT_4D; 960 | double dy2 = dy0 - 1 - SQUISH_CONSTANT_4D; 961 | double dz2 = dz1; 962 | double dw2 = dw1; 963 | double attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2 - dw2 * dw2; 964 | if (attn2 > 0) { 965 | attn2 *= attn2; 966 | value += attn2 * attn2 * extrapolate(xsb + 0, ysb + 1, zsb + 0, wsb + 0, dx2, dy2, dz2, dw2); 967 | } 968 | 969 | //Contribution (0,0,1,0) 970 | double dx3 = dx2; 971 | double dy3 = dy1; 972 | double dz3 = dz0 - 1 - SQUISH_CONSTANT_4D; 973 | double dw3 = dw1; 974 | double attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3 - dw3 * dw3; 975 | if (attn3 > 0) { 976 | attn3 *= attn3; 977 | value += attn3 * attn3 * extrapolate(xsb + 0, ysb + 0, zsb + 1, wsb + 0, dx3, dy3, dz3, dw3); 978 | } 979 | 980 | //Contribution (0,0,0,1) 981 | double dx4 = dx2; 982 | double dy4 = dy1; 983 | double dz4 = dz1; 984 | double dw4 = dw0 - 1 - SQUISH_CONSTANT_4D; 985 | double attn4 = 2 - dx4 * dx4 - dy4 * dy4 - dz4 * dz4 - dw4 * dw4; 986 | if (attn4 > 0) { 987 | attn4 *= attn4; 988 | value += attn4 * attn4 * extrapolate(xsb + 0, ysb + 0, zsb + 0, wsb + 1, dx4, dy4, dz4, dw4); 989 | } 990 | } else if (inSum >= 3) { //We're inside the pentachoron (4-Simplex) at (1,1,1,1) 991 | //Determine which two of (1,1,1,0), (1,1,0,1), (1,0,1,1), (0,1,1,1) are closest. 992 | byte aPoint = 0x0E; 993 | double aScore = xins; 994 | byte bPoint = 0x0D; 995 | double bScore = yins; 996 | if (aScore <= bScore && zins < bScore) { 997 | bScore = zins; 998 | bPoint = 0x0B; 999 | } else if (aScore > bScore && zins < aScore) { 1000 | aScore = zins; 1001 | aPoint = 0x0B; 1002 | } 1003 | if (aScore <= bScore && wins < bScore) { 1004 | bScore = wins; 1005 | bPoint = 0x07; 1006 | } else if (aScore > bScore && wins < aScore) { 1007 | aScore = wins; 1008 | aPoint = 0x07; 1009 | } 1010 | 1011 | //Now we determine the three lattice points not part of the pentachoron that may contribute. 1012 | //This depends on the closest two pentachoron vertices, including (0,0,0,0) 1013 | double uins = 4 - inSum; 1014 | if (uins < aScore || uins < bScore) { //(1,1,1,1) is one of the closest two pentachoron vertices. 1015 | byte c = (bScore < aScore ? bPoint : aPoint); //Our other closest vertex is the closest out of a and b. 1016 | 1017 | if ((c & 0x01) != 0) { 1018 | xsv_ext0 = xsb + 2; 1019 | xsv_ext1 = xsv_ext2 = xsb + 1; 1020 | dx_ext0 = dx0 - 2 - 4 * SQUISH_CONSTANT_4D; 1021 | dx_ext1 = dx_ext2 = dx0 - 1 - 4 * SQUISH_CONSTANT_4D; 1022 | } else { 1023 | xsv_ext0 = xsv_ext1 = xsv_ext2 = xsb; 1024 | dx_ext0 = dx_ext1 = dx_ext2 = dx0 - 4 * SQUISH_CONSTANT_4D; 1025 | } 1026 | 1027 | if ((c & 0x02) != 0) { 1028 | ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb + 1; 1029 | dy_ext0 = dy_ext1 = dy_ext2 = dy0 - 1 - 4 * SQUISH_CONSTANT_4D; 1030 | if ((c & 0x01) != 0) { 1031 | ysv_ext1 += 1; 1032 | dy_ext1 -= 1; 1033 | } else { 1034 | ysv_ext0 += 1; 1035 | dy_ext0 -= 1; 1036 | } 1037 | } else { 1038 | ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb; 1039 | dy_ext0 = dy_ext1 = dy_ext2 = dy0 - 4 * SQUISH_CONSTANT_4D; 1040 | } 1041 | 1042 | if ((c & 0x04) != 0) { 1043 | zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb + 1; 1044 | dz_ext0 = dz_ext1 = dz_ext2 = dz0 - 1 - 4 * SQUISH_CONSTANT_4D; 1045 | if ((c & 0x03) != 0x03) { 1046 | if ((c & 0x03) == 0) { 1047 | zsv_ext0 += 1; 1048 | dz_ext0 -= 1; 1049 | } else { 1050 | zsv_ext1 += 1; 1051 | dz_ext1 -= 1; 1052 | } 1053 | } else { 1054 | zsv_ext2 += 1; 1055 | dz_ext2 -= 1; 1056 | } 1057 | } else { 1058 | zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb; 1059 | dz_ext0 = dz_ext1 = dz_ext2 = dz0 - 4 * SQUISH_CONSTANT_4D; 1060 | } 1061 | 1062 | if ((c & 0x08) != 0) { 1063 | wsv_ext0 = wsv_ext1 = wsb + 1; 1064 | wsv_ext2 = wsb + 2; 1065 | dw_ext0 = dw_ext1 = dw0 - 1 - 4 * SQUISH_CONSTANT_4D; 1066 | dw_ext2 = dw0 - 2 - 4 * SQUISH_CONSTANT_4D; 1067 | } else { 1068 | wsv_ext0 = wsv_ext1 = wsv_ext2 = wsb; 1069 | dw_ext0 = dw_ext1 = dw_ext2 = dw0 - 4 * SQUISH_CONSTANT_4D; 1070 | } 1071 | } else { //(1,1,1,1) is not one of the closest two pentachoron vertices. 1072 | byte c = (byte)(aPoint & bPoint); //Our three extra vertices are determined by the closest two. 1073 | 1074 | if ((c & 0x01) != 0) { 1075 | xsv_ext0 = xsv_ext2 = xsb + 1; 1076 | xsv_ext1 = xsb + 2; 1077 | dx_ext0 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D; 1078 | dx_ext1 = dx0 - 2 - 3 * SQUISH_CONSTANT_4D; 1079 | dx_ext2 = dx0 - 1 - 3 * SQUISH_CONSTANT_4D; 1080 | } else { 1081 | xsv_ext0 = xsv_ext1 = xsv_ext2 = xsb; 1082 | dx_ext0 = dx0 - 2 * SQUISH_CONSTANT_4D; 1083 | dx_ext1 = dx_ext2 = dx0 - 3 * SQUISH_CONSTANT_4D; 1084 | } 1085 | 1086 | if ((c & 0x02) != 0) { 1087 | ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb + 1; 1088 | dy_ext0 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D; 1089 | dy_ext1 = dy_ext2 = dy0 - 1 - 3 * SQUISH_CONSTANT_4D; 1090 | if ((c & 0x01) != 0) { 1091 | ysv_ext2 += 1; 1092 | dy_ext2 -= 1; 1093 | } else { 1094 | ysv_ext1 += 1; 1095 | dy_ext1 -= 1; 1096 | } 1097 | } else { 1098 | ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb; 1099 | dy_ext0 = dy0 - 2 * SQUISH_CONSTANT_4D; 1100 | dy_ext1 = dy_ext2 = dy0 - 3 * SQUISH_CONSTANT_4D; 1101 | } 1102 | 1103 | if ((c & 0x04) != 0) { 1104 | zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb + 1; 1105 | dz_ext0 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D; 1106 | dz_ext1 = dz_ext2 = dz0 - 1 - 3 * SQUISH_CONSTANT_4D; 1107 | if ((c & 0x03) != 0) { 1108 | zsv_ext2 += 1; 1109 | dz_ext2 -= 1; 1110 | } else { 1111 | zsv_ext1 += 1; 1112 | dz_ext1 -= 1; 1113 | } 1114 | } else { 1115 | zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb; 1116 | dz_ext0 = dz0 - 2 * SQUISH_CONSTANT_4D; 1117 | dz_ext1 = dz_ext2 = dz0 - 3 * SQUISH_CONSTANT_4D; 1118 | } 1119 | 1120 | if ((c & 0x08) != 0) { 1121 | wsv_ext0 = wsv_ext1 = wsb + 1; 1122 | wsv_ext2 = wsb + 2; 1123 | dw_ext0 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D; 1124 | dw_ext1 = dw0 - 1 - 3 * SQUISH_CONSTANT_4D; 1125 | dw_ext2 = dw0 - 2 - 3 * SQUISH_CONSTANT_4D; 1126 | } else { 1127 | wsv_ext0 = wsv_ext1 = wsv_ext2 = wsb; 1128 | dw_ext0 = dw0 - 2 * SQUISH_CONSTANT_4D; 1129 | dw_ext1 = dw_ext2 = dw0 - 3 * SQUISH_CONSTANT_4D; 1130 | } 1131 | } 1132 | 1133 | //Contribution (1,1,1,0) 1134 | double dx4 = dx0 - 1 - 3 * SQUISH_CONSTANT_4D; 1135 | double dy4 = dy0 - 1 - 3 * SQUISH_CONSTANT_4D; 1136 | double dz4 = dz0 - 1 - 3 * SQUISH_CONSTANT_4D; 1137 | double dw4 = dw0 - 3 * SQUISH_CONSTANT_4D; 1138 | double attn4 = 2 - dx4 * dx4 - dy4 * dy4 - dz4 * dz4 - dw4 * dw4; 1139 | if (attn4 > 0) { 1140 | attn4 *= attn4; 1141 | value += attn4 * attn4 * extrapolate(xsb + 1, ysb + 1, zsb + 1, wsb + 0, dx4, dy4, dz4, dw4); 1142 | } 1143 | 1144 | //Contribution (1,1,0,1) 1145 | double dx3 = dx4; 1146 | double dy3 = dy4; 1147 | double dz3 = dz0 - 3 * SQUISH_CONSTANT_4D; 1148 | double dw3 = dw0 - 1 - 3 * SQUISH_CONSTANT_4D; 1149 | double attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3 - dw3 * dw3; 1150 | if (attn3 > 0) { 1151 | attn3 *= attn3; 1152 | value += attn3 * attn3 * extrapolate(xsb + 1, ysb + 1, zsb + 0, wsb + 1, dx3, dy3, dz3, dw3); 1153 | } 1154 | 1155 | //Contribution (1,0,1,1) 1156 | double dx2 = dx4; 1157 | double dy2 = dy0 - 3 * SQUISH_CONSTANT_4D; 1158 | double dz2 = dz4; 1159 | double dw2 = dw3; 1160 | double attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2 - dw2 * dw2; 1161 | if (attn2 > 0) { 1162 | attn2 *= attn2; 1163 | value += attn2 * attn2 * extrapolate(xsb + 1, ysb + 0, zsb + 1, wsb + 1, dx2, dy2, dz2, dw2); 1164 | } 1165 | 1166 | //Contribution (0,1,1,1) 1167 | double dx1 = dx0 - 3 * SQUISH_CONSTANT_4D; 1168 | double dz1 = dz4; 1169 | double dy1 = dy4; 1170 | double dw1 = dw3; 1171 | double attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1 - dw1 * dw1; 1172 | if (attn1 > 0) { 1173 | attn1 *= attn1; 1174 | value += attn1 * attn1 * extrapolate(xsb + 0, ysb + 1, zsb + 1, wsb + 1, dx1, dy1, dz1, dw1); 1175 | } 1176 | 1177 | //Contribution (1,1,1,1) 1178 | dx0 = dx0 - 1 - 4 * SQUISH_CONSTANT_4D; 1179 | dy0 = dy0 - 1 - 4 * SQUISH_CONSTANT_4D; 1180 | dz0 = dz0 - 1 - 4 * SQUISH_CONSTANT_4D; 1181 | dw0 = dw0 - 1 - 4 * SQUISH_CONSTANT_4D; 1182 | double attn0 = 2 - dx0 * dx0 - dy0 * dy0 - dz0 * dz0 - dw0 * dw0; 1183 | if (attn0 > 0) { 1184 | attn0 *= attn0; 1185 | value += attn0 * attn0 * extrapolate(xsb + 1, ysb + 1, zsb + 1, wsb + 1, dx0, dy0, dz0, dw0); 1186 | } 1187 | } else if (inSum <= 2) { //We're inside the first dispentachoron (Rectified 4-Simplex) 1188 | double aScore; 1189 | byte aPoint; 1190 | boolean aIsBiggerSide = true; 1191 | double bScore; 1192 | byte bPoint; 1193 | boolean bIsBiggerSide = true; 1194 | 1195 | //Decide between (1,1,0,0) and (0,0,1,1) 1196 | if (xins + yins > zins + wins) { 1197 | aScore = xins + yins; 1198 | aPoint = 0x03; 1199 | } else { 1200 | aScore = zins + wins; 1201 | aPoint = 0x0C; 1202 | } 1203 | 1204 | //Decide between (1,0,1,0) and (0,1,0,1) 1205 | if (xins + zins > yins + wins) { 1206 | bScore = xins + zins; 1207 | bPoint = 0x05; 1208 | } else { 1209 | bScore = yins + wins; 1210 | bPoint = 0x0A; 1211 | } 1212 | 1213 | //Closer between (1,0,0,1) and (0,1,1,0) will replace the further of a and b, if closer. 1214 | if (xins + wins > yins + zins) { 1215 | double score = xins + wins; 1216 | if (aScore >= bScore && score > bScore) { 1217 | bScore = score; 1218 | bPoint = 0x09; 1219 | } else if (aScore < bScore && score > aScore) { 1220 | aScore = score; 1221 | aPoint = 0x09; 1222 | } 1223 | } else { 1224 | double score = yins + zins; 1225 | if (aScore >= bScore && score > bScore) { 1226 | bScore = score; 1227 | bPoint = 0x06; 1228 | } else if (aScore < bScore && score > aScore) { 1229 | aScore = score; 1230 | aPoint = 0x06; 1231 | } 1232 | } 1233 | 1234 | //Decide if (1,0,0,0) is closer. 1235 | double p1 = 2 - inSum + xins; 1236 | if (aScore >= bScore && p1 > bScore) { 1237 | bScore = p1; 1238 | bPoint = 0x01; 1239 | bIsBiggerSide = false; 1240 | } else if (aScore < bScore && p1 > aScore) { 1241 | aScore = p1; 1242 | aPoint = 0x01; 1243 | aIsBiggerSide = false; 1244 | } 1245 | 1246 | //Decide if (0,1,0,0) is closer. 1247 | double p2 = 2 - inSum + yins; 1248 | if (aScore >= bScore && p2 > bScore) { 1249 | bScore = p2; 1250 | bPoint = 0x02; 1251 | bIsBiggerSide = false; 1252 | } else if (aScore < bScore && p2 > aScore) { 1253 | aScore = p2; 1254 | aPoint = 0x02; 1255 | aIsBiggerSide = false; 1256 | } 1257 | 1258 | //Decide if (0,0,1,0) is closer. 1259 | double p3 = 2 - inSum + zins; 1260 | if (aScore >= bScore && p3 > bScore) { 1261 | bScore = p3; 1262 | bPoint = 0x04; 1263 | bIsBiggerSide = false; 1264 | } else if (aScore < bScore && p3 > aScore) { 1265 | aScore = p3; 1266 | aPoint = 0x04; 1267 | aIsBiggerSide = false; 1268 | } 1269 | 1270 | //Decide if (0,0,0,1) is closer. 1271 | double p4 = 2 - inSum + wins; 1272 | if (aScore >= bScore && p4 > bScore) { 1273 | bScore = p4; 1274 | bPoint = 0x08; 1275 | bIsBiggerSide = false; 1276 | } else if (aScore < bScore && p4 > aScore) { 1277 | aScore = p4; 1278 | aPoint = 0x08; 1279 | aIsBiggerSide = false; 1280 | } 1281 | 1282 | //Where each of the two closest points are determines how the extra three vertices are calculated. 1283 | if (aIsBiggerSide == bIsBiggerSide) { 1284 | if (aIsBiggerSide) { //Both closest points on the bigger side 1285 | byte c1 = (byte)(aPoint | bPoint); 1286 | byte c2 = (byte)(aPoint & bPoint); 1287 | if ((c1 & 0x01) == 0) { 1288 | xsv_ext0 = xsb; 1289 | xsv_ext1 = xsb - 1; 1290 | dx_ext0 = dx0 - 3 * SQUISH_CONSTANT_4D; 1291 | dx_ext1 = dx0 + 1 - 2 * SQUISH_CONSTANT_4D; 1292 | } else { 1293 | xsv_ext0 = xsv_ext1 = xsb + 1; 1294 | dx_ext0 = dx0 - 1 - 3 * SQUISH_CONSTANT_4D; 1295 | dx_ext1 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D; 1296 | } 1297 | 1298 | if ((c1 & 0x02) == 0) { 1299 | ysv_ext0 = ysb; 1300 | ysv_ext1 = ysb - 1; 1301 | dy_ext0 = dy0 - 3 * SQUISH_CONSTANT_4D; 1302 | dy_ext1 = dy0 + 1 - 2 * SQUISH_CONSTANT_4D; 1303 | } else { 1304 | ysv_ext0 = ysv_ext1 = ysb + 1; 1305 | dy_ext0 = dy0 - 1 - 3 * SQUISH_CONSTANT_4D; 1306 | dy_ext1 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D; 1307 | } 1308 | 1309 | if ((c1 & 0x04) == 0) { 1310 | zsv_ext0 = zsb; 1311 | zsv_ext1 = zsb - 1; 1312 | dz_ext0 = dz0 - 3 * SQUISH_CONSTANT_4D; 1313 | dz_ext1 = dz0 + 1 - 2 * SQUISH_CONSTANT_4D; 1314 | } else { 1315 | zsv_ext0 = zsv_ext1 = zsb + 1; 1316 | dz_ext0 = dz0 - 1 - 3 * SQUISH_CONSTANT_4D; 1317 | dz_ext1 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D; 1318 | } 1319 | 1320 | if ((c1 & 0x08) == 0) { 1321 | wsv_ext0 = wsb; 1322 | wsv_ext1 = wsb - 1; 1323 | dw_ext0 = dw0 - 3 * SQUISH_CONSTANT_4D; 1324 | dw_ext1 = dw0 + 1 - 2 * SQUISH_CONSTANT_4D; 1325 | } else { 1326 | wsv_ext0 = wsv_ext1 = wsb + 1; 1327 | dw_ext0 = dw0 - 1 - 3 * SQUISH_CONSTANT_4D; 1328 | dw_ext1 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D; 1329 | } 1330 | 1331 | //One combination is a permutation of (0,0,0,2) based on c2 1332 | xsv_ext2 = xsb; 1333 | ysv_ext2 = ysb; 1334 | zsv_ext2 = zsb; 1335 | wsv_ext2 = wsb; 1336 | dx_ext2 = dx0 - 2 * SQUISH_CONSTANT_4D; 1337 | dy_ext2 = dy0 - 2 * SQUISH_CONSTANT_4D; 1338 | dz_ext2 = dz0 - 2 * SQUISH_CONSTANT_4D; 1339 | dw_ext2 = dw0 - 2 * SQUISH_CONSTANT_4D; 1340 | if ((c2 & 0x01) != 0) { 1341 | xsv_ext2 += 2; 1342 | dx_ext2 -= 2; 1343 | } else if ((c2 & 0x02) != 0) { 1344 | ysv_ext2 += 2; 1345 | dy_ext2 -= 2; 1346 | } else if ((c2 & 0x04) != 0) { 1347 | zsv_ext2 += 2; 1348 | dz_ext2 -= 2; 1349 | } else { 1350 | wsv_ext2 += 2; 1351 | dw_ext2 -= 2; 1352 | } 1353 | 1354 | } else { //Both closest points on the smaller side 1355 | //One of the two extra points is (0,0,0,0) 1356 | xsv_ext2 = xsb; 1357 | ysv_ext2 = ysb; 1358 | zsv_ext2 = zsb; 1359 | wsv_ext2 = wsb; 1360 | dx_ext2 = dx0; 1361 | dy_ext2 = dy0; 1362 | dz_ext2 = dz0; 1363 | dw_ext2 = dw0; 1364 | 1365 | //Other two points are based on the omitted axes. 1366 | byte c = (byte)(aPoint | bPoint); 1367 | 1368 | if ((c & 0x01) == 0) { 1369 | xsv_ext0 = xsb - 1; 1370 | xsv_ext1 = xsb; 1371 | dx_ext0 = dx0 + 1 - SQUISH_CONSTANT_4D; 1372 | dx_ext1 = dx0 - SQUISH_CONSTANT_4D; 1373 | } else { 1374 | xsv_ext0 = xsv_ext1 = xsb + 1; 1375 | dx_ext0 = dx_ext1 = dx0 - 1 - SQUISH_CONSTANT_4D; 1376 | } 1377 | 1378 | if ((c & 0x02) == 0) { 1379 | ysv_ext0 = ysv_ext1 = ysb; 1380 | dy_ext0 = dy_ext1 = dy0 - SQUISH_CONSTANT_4D; 1381 | if ((c & 0x01) == 0x01) 1382 | { 1383 | ysv_ext0 -= 1; 1384 | dy_ext0 += 1; 1385 | } else { 1386 | ysv_ext1 -= 1; 1387 | dy_ext1 += 1; 1388 | } 1389 | } else { 1390 | ysv_ext0 = ysv_ext1 = ysb + 1; 1391 | dy_ext0 = dy_ext1 = dy0 - 1 - SQUISH_CONSTANT_4D; 1392 | } 1393 | 1394 | if ((c & 0x04) == 0) { 1395 | zsv_ext0 = zsv_ext1 = zsb; 1396 | dz_ext0 = dz_ext1 = dz0 - SQUISH_CONSTANT_4D; 1397 | if ((c & 0x03) == 0x03) 1398 | { 1399 | zsv_ext0 -= 1; 1400 | dz_ext0 += 1; 1401 | } else { 1402 | zsv_ext1 -= 1; 1403 | dz_ext1 += 1; 1404 | } 1405 | } else { 1406 | zsv_ext0 = zsv_ext1 = zsb + 1; 1407 | dz_ext0 = dz_ext1 = dz0 - 1 - SQUISH_CONSTANT_4D; 1408 | } 1409 | 1410 | if ((c & 0x08) == 0) 1411 | { 1412 | wsv_ext0 = wsb; 1413 | wsv_ext1 = wsb - 1; 1414 | dw_ext0 = dw0 - SQUISH_CONSTANT_4D; 1415 | dw_ext1 = dw0 + 1 - SQUISH_CONSTANT_4D; 1416 | } else { 1417 | wsv_ext0 = wsv_ext1 = wsb + 1; 1418 | dw_ext0 = dw_ext1 = dw0 - 1 - SQUISH_CONSTANT_4D; 1419 | } 1420 | 1421 | } 1422 | } else { //One point on each "side" 1423 | byte c1, c2; 1424 | if (aIsBiggerSide) { 1425 | c1 = aPoint; 1426 | c2 = bPoint; 1427 | } else { 1428 | c1 = bPoint; 1429 | c2 = aPoint; 1430 | } 1431 | 1432 | //Two contributions are the bigger-sided point with each 0 replaced with -1. 1433 | if ((c1 & 0x01) == 0) { 1434 | xsv_ext0 = xsb - 1; 1435 | xsv_ext1 = xsb; 1436 | dx_ext0 = dx0 + 1 - SQUISH_CONSTANT_4D; 1437 | dx_ext1 = dx0 - SQUISH_CONSTANT_4D; 1438 | } else { 1439 | xsv_ext0 = xsv_ext1 = xsb + 1; 1440 | dx_ext0 = dx_ext1 = dx0 - 1 - SQUISH_CONSTANT_4D; 1441 | } 1442 | 1443 | if ((c1 & 0x02) == 0) { 1444 | ysv_ext0 = ysv_ext1 = ysb; 1445 | dy_ext0 = dy_ext1 = dy0 - SQUISH_CONSTANT_4D; 1446 | if ((c1 & 0x01) == 0x01) { 1447 | ysv_ext0 -= 1; 1448 | dy_ext0 += 1; 1449 | } else { 1450 | ysv_ext1 -= 1; 1451 | dy_ext1 += 1; 1452 | } 1453 | } else { 1454 | ysv_ext0 = ysv_ext1 = ysb + 1; 1455 | dy_ext0 = dy_ext1 = dy0 - 1 - SQUISH_CONSTANT_4D; 1456 | } 1457 | 1458 | if ((c1 & 0x04) == 0) { 1459 | zsv_ext0 = zsv_ext1 = zsb; 1460 | dz_ext0 = dz_ext1 = dz0 - SQUISH_CONSTANT_4D; 1461 | if ((c1 & 0x03) == 0x03) { 1462 | zsv_ext0 -= 1; 1463 | dz_ext0 += 1; 1464 | } else { 1465 | zsv_ext1 -= 1; 1466 | dz_ext1 += 1; 1467 | } 1468 | } else { 1469 | zsv_ext0 = zsv_ext1 = zsb + 1; 1470 | dz_ext0 = dz_ext1 = dz0 - 1 - SQUISH_CONSTANT_4D; 1471 | } 1472 | 1473 | if ((c1 & 0x08) == 0) { 1474 | wsv_ext0 = wsb; 1475 | wsv_ext1 = wsb - 1; 1476 | dw_ext0 = dw0 - SQUISH_CONSTANT_4D; 1477 | dw_ext1 = dw0 + 1 - SQUISH_CONSTANT_4D; 1478 | } else { 1479 | wsv_ext0 = wsv_ext1 = wsb + 1; 1480 | dw_ext0 = dw_ext1 = dw0 - 1 - SQUISH_CONSTANT_4D; 1481 | } 1482 | 1483 | //One contribution is a permutation of (0,0,0,2) based on the smaller-sided point 1484 | xsv_ext2 = xsb; 1485 | ysv_ext2 = ysb; 1486 | zsv_ext2 = zsb; 1487 | wsv_ext2 = wsb; 1488 | dx_ext2 = dx0 - 2 * SQUISH_CONSTANT_4D; 1489 | dy_ext2 = dy0 - 2 * SQUISH_CONSTANT_4D; 1490 | dz_ext2 = dz0 - 2 * SQUISH_CONSTANT_4D; 1491 | dw_ext2 = dw0 - 2 * SQUISH_CONSTANT_4D; 1492 | if ((c2 & 0x01) != 0) { 1493 | xsv_ext2 += 2; 1494 | dx_ext2 -= 2; 1495 | } else if ((c2 & 0x02) != 0) { 1496 | ysv_ext2 += 2; 1497 | dy_ext2 -= 2; 1498 | } else if ((c2 & 0x04) != 0) { 1499 | zsv_ext2 += 2; 1500 | dz_ext2 -= 2; 1501 | } else { 1502 | wsv_ext2 += 2; 1503 | dw_ext2 -= 2; 1504 | } 1505 | } 1506 | 1507 | //Contribution (1,0,0,0) 1508 | double dx1 = dx0 - 1 - SQUISH_CONSTANT_4D; 1509 | double dy1 = dy0 - 0 - SQUISH_CONSTANT_4D; 1510 | double dz1 = dz0 - 0 - SQUISH_CONSTANT_4D; 1511 | double dw1 = dw0 - 0 - SQUISH_CONSTANT_4D; 1512 | double attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1 - dw1 * dw1; 1513 | if (attn1 > 0) { 1514 | attn1 *= attn1; 1515 | value += attn1 * attn1 * extrapolate(xsb + 1, ysb + 0, zsb + 0, wsb + 0, dx1, dy1, dz1, dw1); 1516 | } 1517 | 1518 | //Contribution (0,1,0,0) 1519 | double dx2 = dx0 - 0 - SQUISH_CONSTANT_4D; 1520 | double dy2 = dy0 - 1 - SQUISH_CONSTANT_4D; 1521 | double dz2 = dz1; 1522 | double dw2 = dw1; 1523 | double attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2 - dw2 * dw2; 1524 | if (attn2 > 0) { 1525 | attn2 *= attn2; 1526 | value += attn2 * attn2 * extrapolate(xsb + 0, ysb + 1, zsb + 0, wsb + 0, dx2, dy2, dz2, dw2); 1527 | } 1528 | 1529 | //Contribution (0,0,1,0) 1530 | double dx3 = dx2; 1531 | double dy3 = dy1; 1532 | double dz3 = dz0 - 1 - SQUISH_CONSTANT_4D; 1533 | double dw3 = dw1; 1534 | double attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3 - dw3 * dw3; 1535 | if (attn3 > 0) { 1536 | attn3 *= attn3; 1537 | value += attn3 * attn3 * extrapolate(xsb + 0, ysb + 0, zsb + 1, wsb + 0, dx3, dy3, dz3, dw3); 1538 | } 1539 | 1540 | //Contribution (0,0,0,1) 1541 | double dx4 = dx2; 1542 | double dy4 = dy1; 1543 | double dz4 = dz1; 1544 | double dw4 = dw0 - 1 - SQUISH_CONSTANT_4D; 1545 | double attn4 = 2 - dx4 * dx4 - dy4 * dy4 - dz4 * dz4 - dw4 * dw4; 1546 | if (attn4 > 0) { 1547 | attn4 *= attn4; 1548 | value += attn4 * attn4 * extrapolate(xsb + 0, ysb + 0, zsb + 0, wsb + 1, dx4, dy4, dz4, dw4); 1549 | } 1550 | 1551 | //Contribution (1,1,0,0) 1552 | double dx5 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D; 1553 | double dy5 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D; 1554 | double dz5 = dz0 - 0 - 2 * SQUISH_CONSTANT_4D; 1555 | double dw5 = dw0 - 0 - 2 * SQUISH_CONSTANT_4D; 1556 | double attn5 = 2 - dx5 * dx5 - dy5 * dy5 - dz5 * dz5 - dw5 * dw5; 1557 | if (attn5 > 0) { 1558 | attn5 *= attn5; 1559 | value += attn5 * attn5 * extrapolate(xsb + 1, ysb + 1, zsb + 0, wsb + 0, dx5, dy5, dz5, dw5); 1560 | } 1561 | 1562 | //Contribution (1,0,1,0) 1563 | double dx6 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D; 1564 | double dy6 = dy0 - 0 - 2 * SQUISH_CONSTANT_4D; 1565 | double dz6 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D; 1566 | double dw6 = dw0 - 0 - 2 * SQUISH_CONSTANT_4D; 1567 | double attn6 = 2 - dx6 * dx6 - dy6 * dy6 - dz6 * dz6 - dw6 * dw6; 1568 | if (attn6 > 0) { 1569 | attn6 *= attn6; 1570 | value += attn6 * attn6 * extrapolate(xsb + 1, ysb + 0, zsb + 1, wsb + 0, dx6, dy6, dz6, dw6); 1571 | } 1572 | 1573 | //Contribution (1,0,0,1) 1574 | double dx7 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D; 1575 | double dy7 = dy0 - 0 - 2 * SQUISH_CONSTANT_4D; 1576 | double dz7 = dz0 - 0 - 2 * SQUISH_CONSTANT_4D; 1577 | double dw7 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D; 1578 | double attn7 = 2 - dx7 * dx7 - dy7 * dy7 - dz7 * dz7 - dw7 * dw7; 1579 | if (attn7 > 0) { 1580 | attn7 *= attn7; 1581 | value += attn7 * attn7 * extrapolate(xsb + 1, ysb + 0, zsb + 0, wsb + 1, dx7, dy7, dz7, dw7); 1582 | } 1583 | 1584 | //Contribution (0,1,1,0) 1585 | double dx8 = dx0 - 0 - 2 * SQUISH_CONSTANT_4D; 1586 | double dy8 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D; 1587 | double dz8 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D; 1588 | double dw8 = dw0 - 0 - 2 * SQUISH_CONSTANT_4D; 1589 | double attn8 = 2 - dx8 * dx8 - dy8 * dy8 - dz8 * dz8 - dw8 * dw8; 1590 | if (attn8 > 0) { 1591 | attn8 *= attn8; 1592 | value += attn8 * attn8 * extrapolate(xsb + 0, ysb + 1, zsb + 1, wsb + 0, dx8, dy8, dz8, dw8); 1593 | } 1594 | 1595 | //Contribution (0,1,0,1) 1596 | double dx9 = dx0 - 0 - 2 * SQUISH_CONSTANT_4D; 1597 | double dy9 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D; 1598 | double dz9 = dz0 - 0 - 2 * SQUISH_CONSTANT_4D; 1599 | double dw9 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D; 1600 | double attn9 = 2 - dx9 * dx9 - dy9 * dy9 - dz9 * dz9 - dw9 * dw9; 1601 | if (attn9 > 0) { 1602 | attn9 *= attn9; 1603 | value += attn9 * attn9 * extrapolate(xsb + 0, ysb + 1, zsb + 0, wsb + 1, dx9, dy9, dz9, dw9); 1604 | } 1605 | 1606 | //Contribution (0,0,1,1) 1607 | double dx10 = dx0 - 0 - 2 * SQUISH_CONSTANT_4D; 1608 | double dy10 = dy0 - 0 - 2 * SQUISH_CONSTANT_4D; 1609 | double dz10 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D; 1610 | double dw10 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D; 1611 | double attn10 = 2 - dx10 * dx10 - dy10 * dy10 - dz10 * dz10 - dw10 * dw10; 1612 | if (attn10 > 0) { 1613 | attn10 *= attn10; 1614 | value += attn10 * attn10 * extrapolate(xsb + 0, ysb + 0, zsb + 1, wsb + 1, dx10, dy10, dz10, dw10); 1615 | } 1616 | } else { //We're inside the second dispentachoron (Rectified 4-Simplex) 1617 | double aScore; 1618 | byte aPoint; 1619 | boolean aIsBiggerSide = true; 1620 | double bScore; 1621 | byte bPoint; 1622 | boolean bIsBiggerSide = true; 1623 | 1624 | //Decide between (0,0,1,1) and (1,1,0,0) 1625 | if (xins + yins < zins + wins) { 1626 | aScore = xins + yins; 1627 | aPoint = 0x0C; 1628 | } else { 1629 | aScore = zins + wins; 1630 | aPoint = 0x03; 1631 | } 1632 | 1633 | //Decide between (0,1,0,1) and (1,0,1,0) 1634 | if (xins + zins < yins + wins) { 1635 | bScore = xins + zins; 1636 | bPoint = 0x0A; 1637 | } else { 1638 | bScore = yins + wins; 1639 | bPoint = 0x05; 1640 | } 1641 | 1642 | //Closer between (0,1,1,0) and (1,0,0,1) will replace the further of a and b, if closer. 1643 | if (xins + wins < yins + zins) { 1644 | double score = xins + wins; 1645 | if (aScore <= bScore && score < bScore) { 1646 | bScore = score; 1647 | bPoint = 0x06; 1648 | } else if (aScore > bScore && score < aScore) { 1649 | aScore = score; 1650 | aPoint = 0x06; 1651 | } 1652 | } else { 1653 | double score = yins + zins; 1654 | if (aScore <= bScore && score < bScore) { 1655 | bScore = score; 1656 | bPoint = 0x09; 1657 | } else if (aScore > bScore && score < aScore) { 1658 | aScore = score; 1659 | aPoint = 0x09; 1660 | } 1661 | } 1662 | 1663 | //Decide if (0,1,1,1) is closer. 1664 | double p1 = 3 - inSum + xins; 1665 | if (aScore <= bScore && p1 < bScore) { 1666 | bScore = p1; 1667 | bPoint = 0x0E; 1668 | bIsBiggerSide = false; 1669 | } else if (aScore > bScore && p1 < aScore) { 1670 | aScore = p1; 1671 | aPoint = 0x0E; 1672 | aIsBiggerSide = false; 1673 | } 1674 | 1675 | //Decide if (1,0,1,1) is closer. 1676 | double p2 = 3 - inSum + yins; 1677 | if (aScore <= bScore && p2 < bScore) { 1678 | bScore = p2; 1679 | bPoint = 0x0D; 1680 | bIsBiggerSide = false; 1681 | } else if (aScore > bScore && p2 < aScore) { 1682 | aScore = p2; 1683 | aPoint = 0x0D; 1684 | aIsBiggerSide = false; 1685 | } 1686 | 1687 | //Decide if (1,1,0,1) is closer. 1688 | double p3 = 3 - inSum + zins; 1689 | if (aScore <= bScore && p3 < bScore) { 1690 | bScore = p3; 1691 | bPoint = 0x0B; 1692 | bIsBiggerSide = false; 1693 | } else if (aScore > bScore && p3 < aScore) { 1694 | aScore = p3; 1695 | aPoint = 0x0B; 1696 | aIsBiggerSide = false; 1697 | } 1698 | 1699 | //Decide if (1,1,1,0) is closer. 1700 | double p4 = 3 - inSum + wins; 1701 | if (aScore <= bScore && p4 < bScore) { 1702 | bScore = p4; 1703 | bPoint = 0x07; 1704 | bIsBiggerSide = false; 1705 | } else if (aScore > bScore && p4 < aScore) { 1706 | aScore = p4; 1707 | aPoint = 0x07; 1708 | aIsBiggerSide = false; 1709 | } 1710 | 1711 | //Where each of the two closest points are determines how the extra three vertices are calculated. 1712 | if (aIsBiggerSide == bIsBiggerSide) { 1713 | if (aIsBiggerSide) { //Both closest points on the bigger side 1714 | byte c1 = (byte)(aPoint & bPoint); 1715 | byte c2 = (byte)(aPoint | bPoint); 1716 | 1717 | //Two contributions are permutations of (0,0,0,1) and (0,0,0,2) based on c1 1718 | xsv_ext0 = xsv_ext1 = xsb; 1719 | ysv_ext0 = ysv_ext1 = ysb; 1720 | zsv_ext0 = zsv_ext1 = zsb; 1721 | wsv_ext0 = wsv_ext1 = wsb; 1722 | dx_ext0 = dx0 - SQUISH_CONSTANT_4D; 1723 | dy_ext0 = dy0 - SQUISH_CONSTANT_4D; 1724 | dz_ext0 = dz0 - SQUISH_CONSTANT_4D; 1725 | dw_ext0 = dw0 - SQUISH_CONSTANT_4D; 1726 | dx_ext1 = dx0 - 2 * SQUISH_CONSTANT_4D; 1727 | dy_ext1 = dy0 - 2 * SQUISH_CONSTANT_4D; 1728 | dz_ext1 = dz0 - 2 * SQUISH_CONSTANT_4D; 1729 | dw_ext1 = dw0 - 2 * SQUISH_CONSTANT_4D; 1730 | if ((c1 & 0x01) != 0) { 1731 | xsv_ext0 += 1; 1732 | dx_ext0 -= 1; 1733 | xsv_ext1 += 2; 1734 | dx_ext1 -= 2; 1735 | } else if ((c1 & 0x02) != 0) { 1736 | ysv_ext0 += 1; 1737 | dy_ext0 -= 1; 1738 | ysv_ext1 += 2; 1739 | dy_ext1 -= 2; 1740 | } else if ((c1 & 0x04) != 0) { 1741 | zsv_ext0 += 1; 1742 | dz_ext0 -= 1; 1743 | zsv_ext1 += 2; 1744 | dz_ext1 -= 2; 1745 | } else { 1746 | wsv_ext0 += 1; 1747 | dw_ext0 -= 1; 1748 | wsv_ext1 += 2; 1749 | dw_ext1 -= 2; 1750 | } 1751 | 1752 | //One contribution is a permutation of (1,1,1,-1) based on c2 1753 | xsv_ext2 = xsb + 1; 1754 | ysv_ext2 = ysb + 1; 1755 | zsv_ext2 = zsb + 1; 1756 | wsv_ext2 = wsb + 1; 1757 | dx_ext2 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D; 1758 | dy_ext2 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D; 1759 | dz_ext2 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D; 1760 | dw_ext2 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D; 1761 | if ((c2 & 0x01) == 0) { 1762 | xsv_ext2 -= 2; 1763 | dx_ext2 += 2; 1764 | } else if ((c2 & 0x02) == 0) { 1765 | ysv_ext2 -= 2; 1766 | dy_ext2 += 2; 1767 | } else if ((c2 & 0x04) == 0) { 1768 | zsv_ext2 -= 2; 1769 | dz_ext2 += 2; 1770 | } else { 1771 | wsv_ext2 -= 2; 1772 | dw_ext2 += 2; 1773 | } 1774 | } else { //Both closest points on the smaller side 1775 | //One of the two extra points is (1,1,1,1) 1776 | xsv_ext2 = xsb + 1; 1777 | ysv_ext2 = ysb + 1; 1778 | zsv_ext2 = zsb + 1; 1779 | wsv_ext2 = wsb + 1; 1780 | dx_ext2 = dx0 - 1 - 4 * SQUISH_CONSTANT_4D; 1781 | dy_ext2 = dy0 - 1 - 4 * SQUISH_CONSTANT_4D; 1782 | dz_ext2 = dz0 - 1 - 4 * SQUISH_CONSTANT_4D; 1783 | dw_ext2 = dw0 - 1 - 4 * SQUISH_CONSTANT_4D; 1784 | 1785 | //Other two points are based on the shared axes. 1786 | byte c = (byte)(aPoint & bPoint); 1787 | 1788 | if ((c & 0x01) != 0) { 1789 | xsv_ext0 = xsb + 2; 1790 | xsv_ext1 = xsb + 1; 1791 | dx_ext0 = dx0 - 2 - 3 * SQUISH_CONSTANT_4D; 1792 | dx_ext1 = dx0 - 1 - 3 * SQUISH_CONSTANT_4D; 1793 | } else { 1794 | xsv_ext0 = xsv_ext1 = xsb; 1795 | dx_ext0 = dx_ext1 = dx0 - 3 * SQUISH_CONSTANT_4D; 1796 | } 1797 | 1798 | if ((c & 0x02) != 0) { 1799 | ysv_ext0 = ysv_ext1 = ysb + 1; 1800 | dy_ext0 = dy_ext1 = dy0 - 1 - 3 * SQUISH_CONSTANT_4D; 1801 | if ((c & 0x01) == 0) 1802 | { 1803 | ysv_ext0 += 1; 1804 | dy_ext0 -= 1; 1805 | } else { 1806 | ysv_ext1 += 1; 1807 | dy_ext1 -= 1; 1808 | } 1809 | } else { 1810 | ysv_ext0 = ysv_ext1 = ysb; 1811 | dy_ext0 = dy_ext1 = dy0 - 3 * SQUISH_CONSTANT_4D; 1812 | } 1813 | 1814 | if ((c & 0x04) != 0) { 1815 | zsv_ext0 = zsv_ext1 = zsb + 1; 1816 | dz_ext0 = dz_ext1 = dz0 - 1 - 3 * SQUISH_CONSTANT_4D; 1817 | if ((c & 0x03) == 0) 1818 | { 1819 | zsv_ext0 += 1; 1820 | dz_ext0 -= 1; 1821 | } else { 1822 | zsv_ext1 += 1; 1823 | dz_ext1 -= 1; 1824 | } 1825 | } else { 1826 | zsv_ext0 = zsv_ext1 = zsb; 1827 | dz_ext0 = dz_ext1 = dz0 - 3 * SQUISH_CONSTANT_4D; 1828 | } 1829 | 1830 | if ((c & 0x08) != 0) 1831 | { 1832 | wsv_ext0 = wsb + 1; 1833 | wsv_ext1 = wsb + 2; 1834 | dw_ext0 = dw0 - 1 - 3 * SQUISH_CONSTANT_4D; 1835 | dw_ext1 = dw0 - 2 - 3 * SQUISH_CONSTANT_4D; 1836 | } else { 1837 | wsv_ext0 = wsv_ext1 = wsb; 1838 | dw_ext0 = dw_ext1 = dw0 - 3 * SQUISH_CONSTANT_4D; 1839 | } 1840 | } 1841 | } else { //One point on each "side" 1842 | byte c1, c2; 1843 | if (aIsBiggerSide) { 1844 | c1 = aPoint; 1845 | c2 = bPoint; 1846 | } else { 1847 | c1 = bPoint; 1848 | c2 = aPoint; 1849 | } 1850 | 1851 | //Two contributions are the bigger-sided point with each 1 replaced with 2. 1852 | if ((c1 & 0x01) != 0) { 1853 | xsv_ext0 = xsb + 2; 1854 | xsv_ext1 = xsb + 1; 1855 | dx_ext0 = dx0 - 2 - 3 * SQUISH_CONSTANT_4D; 1856 | dx_ext1 = dx0 - 1 - 3 * SQUISH_CONSTANT_4D; 1857 | } else { 1858 | xsv_ext0 = xsv_ext1 = xsb; 1859 | dx_ext0 = dx_ext1 = dx0 - 3 * SQUISH_CONSTANT_4D; 1860 | } 1861 | 1862 | if ((c1 & 0x02) != 0) { 1863 | ysv_ext0 = ysv_ext1 = ysb + 1; 1864 | dy_ext0 = dy_ext1 = dy0 - 1 - 3 * SQUISH_CONSTANT_4D; 1865 | if ((c1 & 0x01) == 0) { 1866 | ysv_ext0 += 1; 1867 | dy_ext0 -= 1; 1868 | } else { 1869 | ysv_ext1 += 1; 1870 | dy_ext1 -= 1; 1871 | } 1872 | } else { 1873 | ysv_ext0 = ysv_ext1 = ysb; 1874 | dy_ext0 = dy_ext1 = dy0 - 3 * SQUISH_CONSTANT_4D; 1875 | } 1876 | 1877 | if ((c1 & 0x04) != 0) { 1878 | zsv_ext0 = zsv_ext1 = zsb + 1; 1879 | dz_ext0 = dz_ext1 = dz0 - 1 - 3 * SQUISH_CONSTANT_4D; 1880 | if ((c1 & 0x03) == 0) { 1881 | zsv_ext0 += 1; 1882 | dz_ext0 -= 1; 1883 | } else { 1884 | zsv_ext1 += 1; 1885 | dz_ext1 -= 1; 1886 | } 1887 | } else { 1888 | zsv_ext0 = zsv_ext1 = zsb; 1889 | dz_ext0 = dz_ext1 = dz0 - 3 * SQUISH_CONSTANT_4D; 1890 | } 1891 | 1892 | if ((c1 & 0x08) != 0) { 1893 | wsv_ext0 = wsb + 1; 1894 | wsv_ext1 = wsb + 2; 1895 | dw_ext0 = dw0 - 1 - 3 * SQUISH_CONSTANT_4D; 1896 | dw_ext1 = dw0 - 2 - 3 * SQUISH_CONSTANT_4D; 1897 | } else { 1898 | wsv_ext0 = wsv_ext1 = wsb; 1899 | dw_ext0 = dw_ext1 = dw0 - 3 * SQUISH_CONSTANT_4D; 1900 | } 1901 | 1902 | //One contribution is a permutation of (1,1,1,-1) based on the smaller-sided point 1903 | xsv_ext2 = xsb + 1; 1904 | ysv_ext2 = ysb + 1; 1905 | zsv_ext2 = zsb + 1; 1906 | wsv_ext2 = wsb + 1; 1907 | dx_ext2 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D; 1908 | dy_ext2 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D; 1909 | dz_ext2 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D; 1910 | dw_ext2 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D; 1911 | if ((c2 & 0x01) == 0) { 1912 | xsv_ext2 -= 2; 1913 | dx_ext2 += 2; 1914 | } else if ((c2 & 0x02) == 0) { 1915 | ysv_ext2 -= 2; 1916 | dy_ext2 += 2; 1917 | } else if ((c2 & 0x04) == 0) { 1918 | zsv_ext2 -= 2; 1919 | dz_ext2 += 2; 1920 | } else { 1921 | wsv_ext2 -= 2; 1922 | dw_ext2 += 2; 1923 | } 1924 | } 1925 | 1926 | //Contribution (1,1,1,0) 1927 | double dx4 = dx0 - 1 - 3 * SQUISH_CONSTANT_4D; 1928 | double dy4 = dy0 - 1 - 3 * SQUISH_CONSTANT_4D; 1929 | double dz4 = dz0 - 1 - 3 * SQUISH_CONSTANT_4D; 1930 | double dw4 = dw0 - 3 * SQUISH_CONSTANT_4D; 1931 | double attn4 = 2 - dx4 * dx4 - dy4 * dy4 - dz4 * dz4 - dw4 * dw4; 1932 | if (attn4 > 0) { 1933 | attn4 *= attn4; 1934 | value += attn4 * attn4 * extrapolate(xsb + 1, ysb + 1, zsb + 1, wsb + 0, dx4, dy4, dz4, dw4); 1935 | } 1936 | 1937 | //Contribution (1,1,0,1) 1938 | double dx3 = dx4; 1939 | double dy3 = dy4; 1940 | double dz3 = dz0 - 3 * SQUISH_CONSTANT_4D; 1941 | double dw3 = dw0 - 1 - 3 * SQUISH_CONSTANT_4D; 1942 | double attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3 - dw3 * dw3; 1943 | if (attn3 > 0) { 1944 | attn3 *= attn3; 1945 | value += attn3 * attn3 * extrapolate(xsb + 1, ysb + 1, zsb + 0, wsb + 1, dx3, dy3, dz3, dw3); 1946 | } 1947 | 1948 | //Contribution (1,0,1,1) 1949 | double dx2 = dx4; 1950 | double dy2 = dy0 - 3 * SQUISH_CONSTANT_4D; 1951 | double dz2 = dz4; 1952 | double dw2 = dw3; 1953 | double attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2 - dw2 * dw2; 1954 | if (attn2 > 0) { 1955 | attn2 *= attn2; 1956 | value += attn2 * attn2 * extrapolate(xsb + 1, ysb + 0, zsb + 1, wsb + 1, dx2, dy2, dz2, dw2); 1957 | } 1958 | 1959 | //Contribution (0,1,1,1) 1960 | double dx1 = dx0 - 3 * SQUISH_CONSTANT_4D; 1961 | double dz1 = dz4; 1962 | double dy1 = dy4; 1963 | double dw1 = dw3; 1964 | double attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1 - dw1 * dw1; 1965 | if (attn1 > 0) { 1966 | attn1 *= attn1; 1967 | value += attn1 * attn1 * extrapolate(xsb + 0, ysb + 1, zsb + 1, wsb + 1, dx1, dy1, dz1, dw1); 1968 | } 1969 | 1970 | //Contribution (1,1,0,0) 1971 | double dx5 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D; 1972 | double dy5 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D; 1973 | double dz5 = dz0 - 0 - 2 * SQUISH_CONSTANT_4D; 1974 | double dw5 = dw0 - 0 - 2 * SQUISH_CONSTANT_4D; 1975 | double attn5 = 2 - dx5 * dx5 - dy5 * dy5 - dz5 * dz5 - dw5 * dw5; 1976 | if (attn5 > 0) { 1977 | attn5 *= attn5; 1978 | value += attn5 * attn5 * extrapolate(xsb + 1, ysb + 1, zsb + 0, wsb + 0, dx5, dy5, dz5, dw5); 1979 | } 1980 | 1981 | //Contribution (1,0,1,0) 1982 | double dx6 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D; 1983 | double dy6 = dy0 - 0 - 2 * SQUISH_CONSTANT_4D; 1984 | double dz6 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D; 1985 | double dw6 = dw0 - 0 - 2 * SQUISH_CONSTANT_4D; 1986 | double attn6 = 2 - dx6 * dx6 - dy6 * dy6 - dz6 * dz6 - dw6 * dw6; 1987 | if (attn6 > 0) { 1988 | attn6 *= attn6; 1989 | value += attn6 * attn6 * extrapolate(xsb + 1, ysb + 0, zsb + 1, wsb + 0, dx6, dy6, dz6, dw6); 1990 | } 1991 | 1992 | //Contribution (1,0,0,1) 1993 | double dx7 = dx0 - 1 - 2 * SQUISH_CONSTANT_4D; 1994 | double dy7 = dy0 - 0 - 2 * SQUISH_CONSTANT_4D; 1995 | double dz7 = dz0 - 0 - 2 * SQUISH_CONSTANT_4D; 1996 | double dw7 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D; 1997 | double attn7 = 2 - dx7 * dx7 - dy7 * dy7 - dz7 * dz7 - dw7 * dw7; 1998 | if (attn7 > 0) { 1999 | attn7 *= attn7; 2000 | value += attn7 * attn7 * extrapolate(xsb + 1, ysb + 0, zsb + 0, wsb + 1, dx7, dy7, dz7, dw7); 2001 | } 2002 | 2003 | //Contribution (0,1,1,0) 2004 | double dx8 = dx0 - 0 - 2 * SQUISH_CONSTANT_4D; 2005 | double dy8 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D; 2006 | double dz8 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D; 2007 | double dw8 = dw0 - 0 - 2 * SQUISH_CONSTANT_4D; 2008 | double attn8 = 2 - dx8 * dx8 - dy8 * dy8 - dz8 * dz8 - dw8 * dw8; 2009 | if (attn8 > 0) { 2010 | attn8 *= attn8; 2011 | value += attn8 * attn8 * extrapolate(xsb + 0, ysb + 1, zsb + 1, wsb + 0, dx8, dy8, dz8, dw8); 2012 | } 2013 | 2014 | //Contribution (0,1,0,1) 2015 | double dx9 = dx0 - 0 - 2 * SQUISH_CONSTANT_4D; 2016 | double dy9 = dy0 - 1 - 2 * SQUISH_CONSTANT_4D; 2017 | double dz9 = dz0 - 0 - 2 * SQUISH_CONSTANT_4D; 2018 | double dw9 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D; 2019 | double attn9 = 2 - dx9 * dx9 - dy9 * dy9 - dz9 * dz9 - dw9 * dw9; 2020 | if (attn9 > 0) { 2021 | attn9 *= attn9; 2022 | value += attn9 * attn9 * extrapolate(xsb + 0, ysb + 1, zsb + 0, wsb + 1, dx9, dy9, dz9, dw9); 2023 | } 2024 | 2025 | //Contribution (0,0,1,1) 2026 | double dx10 = dx0 - 0 - 2 * SQUISH_CONSTANT_4D; 2027 | double dy10 = dy0 - 0 - 2 * SQUISH_CONSTANT_4D; 2028 | double dz10 = dz0 - 1 - 2 * SQUISH_CONSTANT_4D; 2029 | double dw10 = dw0 - 1 - 2 * SQUISH_CONSTANT_4D; 2030 | double attn10 = 2 - dx10 * dx10 - dy10 * dy10 - dz10 * dz10 - dw10 * dw10; 2031 | if (attn10 > 0) { 2032 | attn10 *= attn10; 2033 | value += attn10 * attn10 * extrapolate(xsb + 0, ysb + 0, zsb + 1, wsb + 1, dx10, dy10, dz10, dw10); 2034 | } 2035 | } 2036 | 2037 | //First extra vertex 2038 | double attn_ext0 = 2 - dx_ext0 * dx_ext0 - dy_ext0 * dy_ext0 - dz_ext0 * dz_ext0 - dw_ext0 * dw_ext0; 2039 | if (attn_ext0 > 0) 2040 | { 2041 | attn_ext0 *= attn_ext0; 2042 | value += attn_ext0 * attn_ext0 * extrapolate(xsv_ext0, ysv_ext0, zsv_ext0, wsv_ext0, dx_ext0, dy_ext0, dz_ext0, dw_ext0); 2043 | } 2044 | 2045 | //Second extra vertex 2046 | double attn_ext1 = 2 - dx_ext1 * dx_ext1 - dy_ext1 * dy_ext1 - dz_ext1 * dz_ext1 - dw_ext1 * dw_ext1; 2047 | if (attn_ext1 > 0) 2048 | { 2049 | attn_ext1 *= attn_ext1; 2050 | value += attn_ext1 * attn_ext1 * extrapolate(xsv_ext1, ysv_ext1, zsv_ext1, wsv_ext1, dx_ext1, dy_ext1, dz_ext1, dw_ext1); 2051 | } 2052 | 2053 | //Third extra vertex 2054 | double attn_ext2 = 2 - dx_ext2 * dx_ext2 - dy_ext2 * dy_ext2 - dz_ext2 * dz_ext2 - dw_ext2 * dw_ext2; 2055 | if (attn_ext2 > 0) 2056 | { 2057 | attn_ext2 *= attn_ext2; 2058 | value += attn_ext2 * attn_ext2 * extrapolate(xsv_ext2, ysv_ext2, zsv_ext2, wsv_ext2, dx_ext2, dy_ext2, dz_ext2, dw_ext2); 2059 | } 2060 | 2061 | return value / NORM_CONSTANT_4D; 2062 | } 2063 | 2064 | private double extrapolate(int xsb, int ysb, double dx, double dy) 2065 | { 2066 | int index = perm[(perm[xsb & 0xFF] + ysb) & 0xFF] & 0x0E; 2067 | return gradients2D[index] * dx 2068 | + gradients2D[index + 1] * dy; 2069 | } 2070 | 2071 | private double extrapolate(int xsb, int ysb, int zsb, double dx, double dy, double dz) 2072 | { 2073 | int index = permGradIndex3D[(perm[(perm[xsb & 0xFF] + ysb) & 0xFF] + zsb) & 0xFF]; 2074 | return gradients3D[index] * dx 2075 | + gradients3D[index + 1] * dy 2076 | + gradients3D[index + 2] * dz; 2077 | } 2078 | 2079 | private double extrapolate(int xsb, int ysb, int zsb, int wsb, double dx, double dy, double dz, double dw) 2080 | { 2081 | int index = perm[(perm[(perm[(perm[xsb & 0xFF] + ysb) & 0xFF] + zsb) & 0xFF] + wsb) & 0xFF] & 0xFC; 2082 | return gradients4D[index] * dx 2083 | + gradients4D[index + 1] * dy 2084 | + gradients4D[index + 2] * dz 2085 | + gradients4D[index + 3] * dw; 2086 | } 2087 | 2088 | private static int fastFloor(double x) { 2089 | int xi = (int)x; 2090 | return x < xi ? xi - 1 : xi; 2091 | } 2092 | 2093 | //Gradients for 2D. They approximate the directions to the 2094 | //vertices of an octagon from the center. 2095 | private static byte[] gradients2D = new byte[] { 2096 | 5, 2, 2, 5, 2097 | -5, 2, -2, 5, 2098 | 5, -2, 2, -5, 2099 | -5, -2, -2, -5, 2100 | }; 2101 | 2102 | //Gradients for 3D. They approximate the directions to the 2103 | //vertices of a rhombicuboctahedron from the center, skewed so 2104 | //that the triangular and square facets can be inscribed inside 2105 | //circles of the same radius. 2106 | private static byte[] gradients3D = new byte[] { 2107 | -11, 4, 4, -4, 11, 4, -4, 4, 11, 2108 | 11, 4, 4, 4, 11, 4, 4, 4, 11, 2109 | -11, -4, 4, -4, -11, 4, -4, -4, 11, 2110 | 11, -4, 4, 4, -11, 4, 4, -4, 11, 2111 | -11, 4, -4, -4, 11, -4, -4, 4, -11, 2112 | 11, 4, -4, 4, 11, -4, 4, 4, -11, 2113 | -11, -4, -4, -4, -11, -4, -4, -4, -11, 2114 | 11, -4, -4, 4, -11, -4, 4, -4, -11, 2115 | }; 2116 | 2117 | //Gradients for 4D. They approximate the directions to the 2118 | //vertices of a disprismatotesseractihexadecachoron from the center, 2119 | //skewed so that the tetrahedral and cubic facets can be inscribed inside 2120 | //spheres of the same radius. 2121 | private static byte[] gradients4D = new byte[] { 2122 | 3, 1, 1, 1, 1, 3, 1, 1, 1, 1, 3, 1, 1, 1, 1, 3, 2123 | -3, 1, 1, 1, -1, 3, 1, 1, -1, 1, 3, 1, -1, 1, 1, 3, 2124 | 3, -1, 1, 1, 1, -3, 1, 1, 1, -1, 3, 1, 1, -1, 1, 3, 2125 | -3, -1, 1, 1, -1, -3, 1, 1, -1, -1, 3, 1, -1, -1, 1, 3, 2126 | 3, 1, -1, 1, 1, 3, -1, 1, 1, 1, -3, 1, 1, 1, -1, 3, 2127 | -3, 1, -1, 1, -1, 3, -1, 1, -1, 1, -3, 1, -1, 1, -1, 3, 2128 | 3, -1, -1, 1, 1, -3, -1, 1, 1, -1, -3, 1, 1, -1, -1, 3, 2129 | -3, -1, -1, 1, -1, -3, -1, 1, -1, -1, -3, 1, -1, -1, -1, 3, 2130 | 3, 1, 1, -1, 1, 3, 1, -1, 1, 1, 3, -1, 1, 1, 1, -3, 2131 | -3, 1, 1, -1, -1, 3, 1, -1, -1, 1, 3, -1, -1, 1, 1, -3, 2132 | 3, -1, 1, -1, 1, -3, 1, -1, 1, -1, 3, -1, 1, -1, 1, -3, 2133 | -3, -1, 1, -1, -1, -3, 1, -1, -1, -1, 3, -1, -1, -1, 1, -3, 2134 | 3, 1, -1, -1, 1, 3, -1, -1, 1, 1, -3, -1, 1, 1, -1, -3, 2135 | -3, 1, -1, -1, -1, 3, -1, -1, -1, 1, -3, -1, -1, 1, -1, -3, 2136 | 3, -1, -1, -1, 1, -3, -1, -1, 1, -1, -3, -1, 1, -1, -1, -3, 2137 | -3, -1, -1, -1, -1, -3, -1, -1, -1, -1, -3, -1, -1, -1, -1, -3, 2138 | }; 2139 | } --------------------------------------------------------------------------------