diff options
29 files changed, 1886 insertions, 364 deletions
diff --git a/src/ru/olamedia/Options.java b/src/ru/olamedia/Options.java index e1c4d41..9adf252 100644 --- a/src/ru/olamedia/Options.java +++ b/src/ru/olamedia/Options.java @@ -1,5 +1,5 @@ package ru.olamedia; public class Options { - public static int renderDistance = 256; + public static int renderDistance = 128; } diff --git a/src/ru/olamedia/camera/MatrixCamera.java b/src/ru/olamedia/camera/MatrixCamera.java index de37fc8..2515daf 100644 --- a/src/ru/olamedia/camera/MatrixCamera.java +++ b/src/ru/olamedia/camera/MatrixCamera.java @@ -13,8 +13,6 @@ import static org.openmali.FastMath.*; import ru.olamedia.olacraft.game.Game; import ru.olamedia.input.Keyboard; import ru.olamedia.math.Frustum; -import ru.olamedia.olacraft.render.jogl.PlaneRenderer; -import ru.olamedia.olacraft.render.jogl.VectorRenderer; import com.jogamp.newt.event.KeyEvent; @@ -161,16 +159,16 @@ public class MatrixCamera { loadProjectionMatrix(drawable); loadViewMatrix(drawable); - gl.glColor3f(1, 0, 0); - PlaneRenderer.render(frustum.leftPlane, drawable); - gl.glColor3f(1, 1, 0); - PlaneRenderer.render(frustum.rightPlane, drawable); - gl.glColor3f(1, 0, 1); - PlaneRenderer.render(frustum.topPlane, drawable); - gl.glColor3f(1, 1, 1); - PlaneRenderer.render(frustum.bottomPlane, drawable); + // gl.glColor3f(1, 0, 0); + // PlaneRenderer.render(frustum.leftPlane, drawable); + // gl.glColor3f(1, 1, 0); + // PlaneRenderer.render(frustum.rightPlane, drawable); + // gl.glColor3f(1, 0, 1); + // PlaneRenderer.render(frustum.topPlane, drawable); + // gl.glColor3f(1, 1, 1); + // PlaneRenderer.render(frustum.bottomPlane, drawable); - VectorRenderer.render(nearc, frustum.leftPlane.n, drawable); + // VectorRenderer.render(nearc, frustum.leftPlane.n, drawable); } private void loadViewMatrix(GLAutoDrawable drawable) { diff --git a/src/ru/olamedia/game/GameManager.java b/src/ru/olamedia/game/GameManager.java index f8c05d9..d9efdfb 100644 --- a/src/ru/olamedia/game/GameManager.java +++ b/src/ru/olamedia/game/GameManager.java @@ -2,8 +2,6 @@ package ru.olamedia.game; import java.util.Set; -import javax.media.nativewindow.WindowClosingProtocol.WindowClosingMode; -import javax.media.opengl.DebugGL2ES2; import javax.media.opengl.GL; import javax.media.opengl.GL2ES2; import javax.media.opengl.GLAutoDrawable; @@ -13,9 +11,10 @@ import ru.olamedia.olacraft.game.Game; import ru.olamedia.olacraft.network.discovery.DiscoveryThread; import ru.olamedia.olacraft.render.jogl.DefaultRenderer; import ru.olamedia.olacraft.render.jogl.IRenderer; +import ru.olamedia.olacraft.world.chunk.ChunkMeshBulder; +import ru.olamedia.olacraft.world.location.BlockLocation; import ru.olamedia.tasks.TaskManager; - import com.jogamp.opengl.JoglVersion; public class GameManager implements GLEventListener { @@ -28,6 +27,37 @@ public class GameManager implements GLEventListener { public GameManager() { instance = this; + tests(); + } + + private void tests() { + BlockLocation b; + b = new BlockLocation(0, 0, 0); + assert b.getChunkLocation().x == 0; + assert b.getChunkLocation().getBlockLocation().x == 0; + b = new BlockLocation(14, 0, 0); + assert b.getChunkLocation().x == 0; + assert b.getChunkLocation().getBlockLocation().x == 0; + b = new BlockLocation(15, 0, 0); + assert b.getChunkLocation().x == 0; + assert b.getChunkLocation().getBlockLocation().x == 0; + b = new BlockLocation(16, 0, 0); + assert b.getChunkLocation().x == 1; + assert b.getChunkLocation().getBlockLocation().x == 0; + b = new BlockLocation(-1, 0, 0); + assert b.getChunkLocation().x == -1; + assert b.getChunkLocation().getBlockLocation().x == -1; + b = new BlockLocation(-14, 0, 0); + assert b.getChunkLocation().x == -1; + b = new BlockLocation(-15, 0, 0); + assert b.getChunkLocation().x == -1; + assert b.getChunkLocation().getBlockLocation().x == -1; + b = new BlockLocation(-16, 0, 0); + assert b.getChunkLocation().x == -1; + assert b.getChunkLocation().getBlockLocation().x == -1; + b = new BlockLocation(-17, 0, 0); + assert b.getChunkLocation().x == -2; + assert b.getChunkLocation().getBlockLocation().x == -17; } private void createServerGame() { @@ -107,12 +137,18 @@ public class GameManager implements GLEventListener { } } frame.dispose(); + if (ChunkMeshBulder.instance.isAlive()) { + ChunkMeshBulder.instance.interrupt(); + } // Get all threads Set<Thread> threadSet = Thread.getAllStackTraces().keySet(); for (Thread t : threadSet) { if (t instanceof DiscoveryThread) { t.interrupt(); } + if (t instanceof ChunkMeshBulder) { + t.interrupt(); + } } } @@ -120,10 +156,9 @@ public class GameManager implements GLEventListener { public void init(GLAutoDrawable drawable) { // GLContext.getContext().getGL() GL2ES2 gl = drawable.getGL().getGL2ES2(); - //drawable.setGL(new DebugGL2ES2(gl)); + // drawable.setGL(new DebugGL2ES2(gl)); System.err.println(JoglVersion.getGLInfo(drawable.getGL(), null)); - System.err.println(Thread.currentThread() + " Chosen GLCapabilities: " - + drawable.getChosenGLCapabilities()); + System.err.println(Thread.currentThread() + " Chosen GLCapabilities: " + drawable.getChosenGLCapabilities()); System.err.println(Thread.currentThread() + " INIT GL IS: " + gl.getClass().getName()); System.err.println(Thread.currentThread() + " GL_VENDOR: " + gl.glGetString(GL.GL_VENDOR)); System.err.println(Thread.currentThread() + " GL_RENDERER: " + gl.glGetString(GL.GL_RENDERER)); @@ -144,7 +179,7 @@ public class GameManager implements GLEventListener { public void display(GLAutoDrawable drawable) { GL2ES2 gl = drawable.getGL().getGL2ES2(); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); - //gl.glClearColor(0.2f, 0.2f, 0.2f, 1); + // gl.glClearColor(0.2f, 0.2f, 0.2f, 1); renderer.render(drawable); } @@ -153,7 +188,7 @@ public class GameManager implements GLEventListener { GL gl = drawable.getGL().getGL2ES2(); gl.glViewport(0, 0, width, height); } - + public void showMainMenu() { menu.setVisible(true); } diff --git a/src/ru/olamedia/geom/Mesh.java b/src/ru/olamedia/geom/Mesh.java index 140cc4d..842291f 100644 --- a/src/ru/olamedia/geom/Mesh.java +++ b/src/ru/olamedia/geom/Mesh.java @@ -7,8 +7,10 @@ import java.util.HashMap; import javax.media.opengl.GL; import javax.media.opengl.GL2; +import javax.media.opengl.GL2ES1; import javax.media.opengl.GL2ES2; import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLContext; import javax.media.opengl.fixedfunc.GLPointerFunc; import com.jogamp.opengl.util.GLArrayDataServer; @@ -240,50 +242,39 @@ public class Mesh { } - public void joglRender(GL glx) { + public void joglRender() { if (vertexCount < 1) { return; } - GL2 gl; - GL2ES2 es2; - gl = glx.getGL2(); - if (useDisplayList) { - gl.glEnable(GL2.GL_CULL_FACE); - gl.glEnable(GL2.GL_DEPTH_TEST); - } - if (wireframe) { - // Set wireframe mode - gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2.GL_LINE); - } else { - gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2.GL_FILL); - } - + GL glx = GLContext.getCurrentGL(); if (useVbo) { - // es2 = glx.getGL2ES2(); - // gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, data); - - // gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0); - // gl.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, 0); + //GL2ES2 gl = glx.getGL2ES2(); + GL2 gl = glx.getGL2(); for (Integer m : materials.keySet()) { - //final GLArrayDataServer interleaved = arrays.get(m); - arrays.get(m).enableBuffer(gl, true); gl.glEnable(GL.GL_TEXTURE_2D); - gl.glEnable(GL2.GL_CULL_FACE); - gl.glEnable(GL2.GL_DEPTH_TEST); + gl.glBindTexture(GL.GL_TEXTURE_2D, (int) m); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST_MIPMAP_NEAREST); - gl.glBindTexture(GL.GL_TEXTURE_2D, (int) m); + arrays.get(m).enableBuffer(gl, true); + gl.glEnable(GL.GL_CULL_FACE); + gl.glEnable(GL.GL_DEPTH_TEST); + //gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2.GL_FILL); gl.glDrawArrays(GL2.GL_QUADS, 0, arrays.get(m).getElementCount()); arrays.get(m).enableBuffer(gl, false); + //System.exit(0); } - /* - * gl.glEnableClientState(GL2.GL_VERTEX_ARRAY); - * gl.glVertexPointer(3, GL2.GL_FLOAT, 10, buffer); - * gl.glDrawArrays(GL2.GL_QUADS, 0, vertexCount); - * gl.glDisableClientState(GL2.GL_VERTEX_ARRAY); - */ - } else { + GL2 gl = glx.getGL2(); + if (useDisplayList) { + gl.glEnable(GL2.GL_CULL_FACE); + gl.glEnable(GL2.GL_DEPTH_TEST); + } + if (wireframe) { + // Set wireframe mode + gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2.GL_LINE); + } else { + gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2.GL_FILL); + } if (useDisplayList) { if (DL == null) { DL = new DisplayList(glx); @@ -343,4 +334,8 @@ public class Mesh { } } } + + public int getVertexCount() { + return vertexCount; + } } diff --git a/src/ru/olamedia/geom/SimpleQuadMesh.java b/src/ru/olamedia/geom/SimpleQuadMesh.java index 42cf439..e832789 100644 --- a/src/ru/olamedia/geom/SimpleQuadMesh.java +++ b/src/ru/olamedia/geom/SimpleQuadMesh.java @@ -110,4 +110,6 @@ public class SimpleQuadMesh extends Mesh { addBottomRightFrontVertex(); } + + } diff --git a/src/ru/olamedia/math/OpenBitSet.java b/src/ru/olamedia/math/OpenBitSet.java new file mode 100644 index 0000000..93c26b0 --- /dev/null +++ b/src/ru/olamedia/math/OpenBitSet.java @@ -0,0 +1,1389 @@ +package ru.olamedia.math; + +import java.io.Serializable; +import java.util.Arrays; + +/** + * http://www.apache.org/licenses/LICENSE-2.0 (Lucene) + * + * An "open" BitSet implementation that allows direct access to the + * array of words + * storing the bits. + * <p/> + * Unlike java.util.bitet, the fact that bits are packed into an array of longs + * is part of the interface. This allows efficient implementation of other + * algorithms by someone other than the author. It also allows one to + * efficiently implement alternate serialization or interchange formats. + * <p/> + * <code>OpenBitSet</code> is faster than <code>java.util.BitSet</code> in most + * operations and *much* faster at calculating cardinality of sets and results + * of set operations. It can also handle sets of larger cardinality (up to 64 * + * 2**32-1) + * <p/> + * The goals of <code>OpenBitSet</code> are the fastest implementation possible, + * and maximum code reuse. Extra safety and encapsulation may always be built on + * top, but if that's built in, the cost can never be removed (and hence people + * re-implement their own version in order to get better performance). If you + * want a "safe", totally encapsulated (and slower and limited) BitSet class, + * use <code>java.util.BitSet</code>. + * <p/> + * <h3>Performance Results</h3> + * + * Test system: Pentium 4, Sun Java 1.5_06 -server -Xbatch -Xmx64M <br/> + * BitSet size = 1,000,000 <br/> + * Results are java.util.BitSet time divided by OpenBitSet time. + * <table border="1"> + * <tr> + * <th></th> + * <th>cardinality</th> + * <th>intersect_count</th> + * <th>union</th> + * <th>nextSetBit</th> + * <th>get</th> + * <th>iterator</th> + * </tr> + * <tr> + * <th>50% full</th> + * <td>3.36</td> + * <td>3.96</td> + * <td>1.44</td> + * <td>1.46</td> + * <td>1.99</td> + * <td>1.58</td> + * </tr> + * <tr> + * <th>1% full</th> + * <td>3.31</td> + * <td>3.90</td> + * <td> </td> + * <td>1.04</td> + * <td> </td> + * <td>0.99</td> + * </tr> + * </table> + * + * @author olamedia (modified version) + * + * @author yonik + * @version $Id$ + */ + +public class OpenBitSet implements Cloneable, Serializable { + /** + * + */ + private static final long serialVersionUID = 7041505168827686846L; + public long[] bits; + public int wlen; // number of words (elements) used in the array + + public OpenBitSet() { + + } + + public OpenBitSet(long numBits) { + bits = new long[(int) (((numBits - 1) >>> 6) + 1)]; + wlen = bits.length; + } + + public OpenBitSet(long[] bits, int numWords) { + this.bits = bits; + this.wlen = numWords; + } + + public long[] getBits() { + return bits; + } + + public void setBits(long[] bits) { + this.bits = bits; + } + + public int getNumWords() { + return wlen; + } + + public void setNumWords(int nWords) { + this.wlen = nWords; + } + + public static int wordNum(int index) { + // java doesn't currently accept 64 bit array indicies, so returning + // a long isn't needed. + return index >> 6; // div 64 + } + + public static int wordNum(long index) { + // java doesn't currently accept 64 bit array indicies, so returning + // a long isn't needed. + return (int) (index >> 6); // div 64 + } + + public static int bitNum(int index) { + // should and or cast come first for best efficiency? + return index & 0x0000003f; // mod 64 + } + + public static int bitNum(long index) { + // should and or cast come first for best efficiency? + return (int) index & 0x0000003f; // mod 64 + } + + public static long bitMask(int index) { + return 1L << (index & 0x0000003f); + } + + /** Returns true or false for the specified bit index */ + public boolean get(int index) { + int i = index >> 6; // div 64 + // signed shift will keep a negative index and force an exception, + // removing the need for an explicit check. + int bit = index & 0x3f; // mod 64 + long bitmask = 1L << bit; + return (bits[i] & bitmask) != 0; + } + + /** Returns true or false for the specified bit index */ + public boolean get(long index) { + int i = (int) (index >> 6); // div 64 + // if (i>=bits.length) return false; + int bit = (int) index & 0x3f; // mod 64 + long bitmask = 1L << bit; + return (bits[i] & bitmask) != 0; + } + + // alternate implementation of get() + public boolean get1(int index) { + int i = index >> 6; // div 64 + int bit = index & 0x3f; // mod 64 + return ((bits[i] >>> bit) & 0x01) != 0; + // this does a long shift and a bittest (on x86) vs + // a long shift, and a long AND, (the test for zero is prob a no-op) + // testing on a P4 indicates this is slower than (bits[i] & bitmask) != + // 0; + } + + /** returns 1 if the bit is set, 0 if not */ + public int getBit(int index) { + int i = index >> 6; // div 64 + int bit = index & 0x3f; // mod 64 + return ((int) (bits[i] >>> bit)) & 0x01; + } + + /*** + * public boolean get2(int index) { + * int word = index >> 6; // div 64 + * int bit = index & 0x0000003f; // mod 64 + * return (bits[word] << bit) < 0; // hmmm, this would work if bit + * order were reversed + * // we could right shift and check for parity bit, if it was available to + * us. + * } + ***/ + + public void set(int index) { + int wordNum = index >> 6; // div 64 + int bit = index & 0x3f; // mod 64 + long bitmask = 1L << bit; + bits[wordNum] |= bitmask; + } + + public void set(long index) { + int wordNum = (int) (index >> 6); // div 64 + int bit = (int) index & 0x3f; // mod 64 + long bitmask = 1L << bit; + bits[wordNum] |= bitmask; + } + + public void clear(int index) { + int wordNum = index >> 6; // div 64 + int bit = index & 0x0000003f; // mod 64 + long bitmask = 1L << bit; + bits[wordNum] &= ~bitmask; + // hmmm, it takes one more instruction to clear than it does to set... + // any + // way to work around this? If there were only 63 bits per word, we + // could + // use a right shift of 10111111...111 in binary to position the 0 in + // the + // correct place (using sign extension). + // Could also use Long.rotateRight() or rotateLeft() *if* they were + // converted + // by the JVM into a native instruction. + } + + public void clear(long index) { + int wordNum = (int) (index >> 6); // div 64 + int bit = (int) index & 0x3f; // mod 64 + long bitmask = 1L << bit; + bits[wordNum] &= ~bitmask; + } + + /*** + * public void clear2(int index) { + * int word = index >> 6; // div 64 + * int bit = index & 0x0000003f; // mod 64 + * bits[word] &= Long.rotateLeft(0xfffffffe,bit); + * } + ***/ + + public boolean getAndSet(int index) { + int wordNum = index >> 6; // div 64 + int bit = index & 0x3f; // mod 64 + long bitmask = 1L << bit; + boolean val = (bits[wordNum] & bitmask) != 0; + bits[wordNum] |= bitmask; + return val; + } + + public boolean getAndSet(long index) { + int wordNum = (int) (index >> 6); // div 64 + int bit = (int) index & 0x3f; // mod 64 + long bitmask = 1L << bit; + boolean val = (bits[wordNum] & bitmask) != 0; + bits[wordNum] |= bitmask; + return val; + } + + /** flips a bit */ + public void flip(int index) { + int wordNum = index >> 6; // div 64 + int bit = index & 0x3f; // mod 64 + long bitmask = 1L << bit; + bits[wordNum] ^= bitmask; + } + + /** flips a bit */ + public void flip(long index) { + int wordNum = (int) (index >> 6); // div 64 + int bit = (int) index & 0x3f; // mod 64 + long bitmask = 1L << bit; + bits[wordNum] ^= bitmask; + } + + /** flips a bit and returns the resulting bit value */ + public boolean flipAndGet(int index) { + int wordNum = index >> 6; // div 64 + int bit = index & 0x3f; // mod 64 + long bitmask = 1L << bit; + bits[wordNum] ^= bitmask; + return (bits[wordNum] & bitmask) != 0; + } + + /** flips a bit and returns the resulting bit value */ + public boolean flipAndGet(long index) { + int wordNum = (int) (index >> 6); // div 64 + int bit = (int) index & 0x3f; // mod 64 + long bitmask = 1L << bit; + bits[wordNum] ^= bitmask; + return (bits[wordNum] & bitmask) != 0; + } + + static long pop_array5(long A[], int wordOffset, int numWords) { + int n = numWords; + long tot = 0; + long ones = 0, twos = 0, twosA, twosB, fours = 0, foursA, foursB, eights; + + int i; + for (i = wordOffset; i <= n - 8; i += 8) { + /*** + * #define CSA(h,l, a,b,c) \ + * {unsigned u = a ^ b; unsigned v = c; \ + * h = (a & b) | (u & v); l = u ^ v;} + ***/ + + // CSA(twosA, ones, ones, A[i], A[i+1]) + { + long a = ones, b = A[i], c = A[i + 1]; + long u = a ^ b, v = c; + long h = (a & b) | (u & v), l = u ^ v; + twosA = h; + ones = l; + } + + // CSA(twosB, ones, ones, A[i+2], A[i+3]) + { + long a = ones, b = A[i + 2], c = A[i + 3]; + long u = a ^ b, v = c; + long h = (a & b) | (u & v), l = u ^ v; + twosB = h; + ones = l; + } + + // CSA(foursA, twos, twos, twosA, twosB) + { + long a = twos, b = twosA, c = twosB; + long u = a ^ b, v = c; + long h = (a & b) | (u & v), l = u ^ v; + foursA = h; + twos = l; + } + + // CSA(twosA, ones, ones, A[i+4], A[i+5]) + { + long a = ones, b = A[i + 4], c = A[i + 5]; + long u = a ^ b, v = c; + long h = (a & b) | (u & v), l = u ^ v; + twosA = h; + ones = l; + } + + // CSA(twosB, ones, ones, A[i+6], A[i+7]) + { + long a = ones, b = A[i + 6], c = A[i + 7]; + long u = a ^ b, v = c; + long h = (a & b) | (u & v), l = u ^ v; + twosB = h; + ones = l; + } + + // CSA(foursB, twos, twos, twosA, twosB) + { + long a = twos, b = twosA, c = twosB; + long u = a ^ b, v = c; + long h = (a & b) | (u & v), l = u ^ v; + foursB = h; + twos = l; + } + + // CSA(eights, fours, fours, foursA, foursB) + // CSA(foursB, twos, twos, twosA, twosB) + { + long a = fours, b = foursA, c = foursB; + long u = a ^ b, v = c; + long h = (a & b) | (u & v), l = u ^ v; + eights = h; + fours = l; + } + + tot += pop(eights); + } + + tot = (pop(fours) << 2) + (pop(twos) << 1) + pop(ones) + (tot << 3); + + for (i = i; i < n; i++) + // Add in the last elements + tot = tot + pop(A[i]); + + return tot; + } + + /** + * Returns the number of bits set in the long + */ + public static int pop(long x) { + /*** + * Hacker's Delight 32 bit pop function: + * http://www.hackersdelight.org/HDcode/newCode/pop_arrayHS.cc + * + * int pop(unsigned x) { + * x = x - ((x >> 1) & 0x55555555); + * x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + * x = (x + (x >> 4)) & 0x0F0F0F0F; + * x = x + (x >> 8); + * x = x + (x >> 16); + * return x & 0x0000003F; + * } + ***/ + + // 64 bit extension of the C function from above + x = x - ((x >>> 1) & 0x5555555555555555L); + x = (x & 0x3333333333333333L) + ((x >>> 2) & 0x3333333333333333L); + x = (x + (x >>> 4)) & 0x0F0F0F0F0F0F0F0FL; + x = x + (x >>> 8); + x = x + (x >>> 16); + x = x + (x >>> 32); + return ((int) x) & 0x7F; + } + + /*** + * http://supertech.lcs.mit.edu/~heinz/dt/node7.html Ernst A. Heinz + * DARKTHOUGHT prefers the following non-iterative formulation that + * stems from the well-known ``Hacker's Memory'' collection of + * programming tricks. It performs better than intuitive methods with + * lookup tables because the tables get either too large or need too many + * lookups.1.3 + * + * #define m1 ((unsigned_64) 0x5555555555555555) + * #define m2 ((unsigned_64) 0x3333333333333333) + * + * unsigned int non_iterative_pop(const unsigned_64 b) { + * unsigned_32 n; + * const unsigned_64 a = b - ((b >> 1) & m1); + * const unsigned_64 c = (a & m2) + ((a >> 2) & m2); + * n = ((unsigned_32) c) + ((unsigned_32) (c >> 32)); + * n = (n & 0x0F0F0F0F) + ((n >> 4) & 0x0F0F0F0F); + * n = (n & 0xFFFF) + (n >> 16); + * n = (n & 0xFF) + (n >> 8); + * return n; + * } + * + * // Looks like 19 simple arithmetic operations -YCS + ***/ + + public static int pop(long v0, long v1, long v2, long v3) { + // derived from pop_array by setting last four elems to 0. + // exchanges one pop() call for 10 elementary operations + // saving about 7 instructions... is there a better way? + long twosA = v0 & v1; + long ones = v0 ^ v1; + + long u2 = ones ^ v2; + long twosB = (ones & v2) | (u2 & v3); + ones = u2 ^ v3; + + long fours = (twosA & twosB); + long twos = twosA ^ twosB; + + return (pop(fours) << 2) + (pop(twos) << 1) + pop(ones); + + } + + /*** + * Counts the number of set bits in an array of longs + */ + public static long pop_array(long A[], int wordOffset, int numWords) { + /* + * Robert Harley and David Seal's bit counting algorithm, as documented + * in the revisions of Hacker's Delight + * http://www.hackersdelight.org/revisions.pdf + * http://www.hackersdelight.org/HDcode/newCode/pop_arrayHS.cc + * + * This function was adapted to Java, and extended to use 64 bit words. + * if only we had access to wider registers like SSE from java... + * + * This function can be transformed to compute the popcoun of other + * functions + * on bitsets via something like this: + * sed 's/A\[\([^]]*\)\]/\(A[\1] \& B[\1]\)/g' + */ + int n = wordOffset + numWords; + long tot = 0, tot8 = 0; + long ones = 0, twos = 0, fours = 0; + + int i; + for (i = wordOffset; i <= n - 8; i += 8) { + /*** + * C macro from Hacker's Delight + * #define CSA(h,l, a,b,c) \ + * {unsigned u = a ^ b; unsigned v = c; \ + * h = (a & b) | (u & v); l = u ^ v;} + ***/ + + long twosA, twosB, foursA, foursB, eights; + + // CSA(twosA, ones, ones, A[i], A[i+1]) + { + long b = A[i], c = A[i + 1]; + long u = ones ^ b; + twosA = (ones & b) | (u & c); + ones = u ^ c; + } + // CSA(twosB, ones, ones, A[i+2], A[i+3]) + { + long b = A[i + 2], c = A[i + 3]; + long u = ones ^ b; + twosB = (ones & b) | (u & c); + ones = u ^ c; + } + // CSA(foursA, twos, twos, twosA, twosB) + { + long u = twos ^ twosA; + foursA = (twos & twosA) | (u & twosB); + twos = u ^ twosB; + } + // CSA(twosA, ones, ones, A[i+4], A[i+5]) + { + long b = A[i + 4], c = A[i + 5]; + long u = ones ^ b; + twosA = (ones & b) | (u & c); + ones = u ^ c; + } + // CSA(twosB, ones, ones, A[i+6], A[i+7]) + { + long b = A[i + 6], c = A[i + 7]; + long u = ones ^ b; + twosB = (ones & b) | (u & c); + ones = u ^ c; + } + // CSA(foursB, twos, twos, twosA, twosB) + { + long u = twos ^ twosA; + foursB = (twos & twosA) | (u & twosB); + twos = u ^ twosB; + } + + // CSA(eights, fours, fours, foursA, foursB) + { + long u = fours ^ foursA; + eights = (fours & foursA) | (u & foursB); + fours = u ^ foursB; + } + tot8 += pop(eights); + } + + if (i <= n - 4) { + long twosA, twosB, foursA, eights; + { + long b = A[i], c = A[i + 1]; + long u = ones ^ b; + twosA = (ones & b) | (u & c); + ones = u ^ c; + } + { + long b = A[i + 2], c = A[i + 3]; + long u = ones ^ b; + twosB = (ones & b) | (u & c); + ones = u ^ c; + } + { + long u = twos ^ twosA; + foursA = (twos & twosA) | (u & twosB); + twos = u ^ twosB; + } + eights = fours & foursA; + fours = fours ^ foursA; + + tot8 += pop(eights); + i += 4; + } + + if (i <= n - 2) { + long b = A[i], c = A[i + 1]; + long u = ones ^ b; + long twosA = (ones & b) | (u & c); + ones = u ^ c; + + long foursA = twos & twosA; + twos = twos ^ twosA; + + long eights = fours & foursA; + fours = fours ^ foursA; + + tot8 += pop(eights); + i += 2; + } + + if (i < n) { + tot += pop(A[i]); + } + + tot += (pop(fours) << 2) + (pop(twos) << 1) + pop(ones) + (tot8 << 3); + + return tot; + } + + /** + * Returns the popcount or cardinality of the two sets after an + * intersection. + * Neither array is modified. + */ + public static long pop_intersect(long A[], long B[], int wordOffset, int numWords) { + // generated from pop_array via sed 's/A\[\([^]]*\)\]/\(A[\1] \& + // B[\1]\)/g' + int n = wordOffset + numWords; + long tot = 0, tot8 = 0; + long ones = 0, twos = 0, fours = 0; + + int i; + for (i = wordOffset; i <= n - 8; i += 8) { + long twosA, twosB, foursA, foursB, eights; + + // CSA(twosA, ones, ones, (A[i] & B[i]), (A[i+1] & B[i+1])) + { + long b = (A[i] & B[i]), c = (A[i + 1] & B[i + 1]); + long u = ones ^ b; + twosA = (ones & b) | (u & c); + ones = u ^ c; + } + // CSA(twosB, ones, ones, (A[i+2] & B[i+2]), (A[i+3] & B[i+3])) + { + long b = (A[i + 2] & B[i + 2]), c = (A[i + 3] & B[i + 3]); + long u = ones ^ b; + twosB = (ones & b) | (u & c); + ones = u ^ c; + } + // CSA(foursA, twos, twos, twosA, twosB) + { + long u = twos ^ twosA; + foursA = (twos & twosA) | (u & twosB); + twos = u ^ twosB; + } + // CSA(twosA, ones, ones, (A[i+4] & B[i+4]), (A[i+5] & B[i+5])) + { + long b = (A[i + 4] & B[i + 4]), c = (A[i + 5] & B[i + 5]); + long u = ones ^ b; + twosA = (ones & b) | (u & c); + ones = u ^ c; + } + // CSA(twosB, ones, ones, (A[i+6] & B[i+6]), (A[i+7] & B[i+7])) + { + long b = (A[i + 6] & B[i + 6]), c = (A[i + 7] & B[i + 7]); + long u = ones ^ b; + twosB = (ones & b) | (u & c); + ones = u ^ c; + } + // CSA(foursB, twos, twos, twosA, twosB) + { + long u = twos ^ twosA; + foursB = (twos & twosA) | (u & twosB); + twos = u ^ twosB; + } + + // CSA(eights, fours, fours, foursA, foursB) + { + long u = fours ^ foursA; + eights = (fours & foursA) | (u & foursB); + fours = u ^ foursB; + } + tot8 += pop(eights); + } + + if (i <= n - 4) { + long twosA, twosB, foursA, eights; + { + long b = (A[i] & B[i]), c = (A[i + 1] & B[i + 1]); + long u = ones ^ b; + twosA = (ones & b) | (u & c); + ones = u ^ c; + } + { + long b = (A[i + 2] & B[i + 2]), c = (A[i + 3] & B[i + 3]); + long u = ones ^ b; + twosB = (ones & b) | (u & c); + ones = u ^ c; + } + { + long u = twos ^ twosA; + foursA = (twos & twosA) | (u & twosB); + twos = u ^ twosB; + } + eights = fours & foursA; + fours = fours ^ foursA; + + tot8 += pop(eights); + i += 4; + } + + if (i <= n - 2) { + long b = (A[i] & B[i]), c = (A[i + 1] & B[i + 1]); + long u = ones ^ b; + long twosA = (ones & b) | (u & c); + ones = u ^ c; + + long foursA = twos & twosA; + twos = twos ^ twosA; + + long eights = fours & foursA; + fours = fours ^ foursA; + + tot8 += pop(eights); + i += 2; + } + + if (i < n) { + tot += pop((A[i] & B[i])); + } + + tot += (pop(fours) << 2) + (pop(twos) << 1) + pop(ones) + (tot8 << 3); + + return tot; + } + + /** + * Returns the popcount or cardinality of the union of two sets. + * Neither array is modified. + */ + public static long pop_union(long A[], long B[], int wordOffset, int numWords) { + // generated from pop_array via sed 's/A\[\([^]]*\)\]/\(A[\1] \| + // B[\1]\)/g' + int n = wordOffset + numWords; + long tot = 0, tot8 = 0; + long ones = 0, twos = 0, fours = 0; + + int i; + for (i = wordOffset; i <= n - 8; i += 8) { + /*** + * C macro from Hacker's Delight + * #define CSA(h,l, a,b,c) \ + * {unsigned u = a ^ b; unsigned v = c; \ + * h = (a & b) | (u & v); l = u ^ v;} + ***/ + + long twosA, twosB, foursA, foursB, eights; + + // CSA(twosA, ones, ones, (A[i] | B[i]), (A[i+1] | B[i+1])) + { + long b = (A[i] | B[i]), c = (A[i + 1] | B[i + 1]); + long u = ones ^ b; + twosA = (ones & b) | (u & c); + ones = u ^ c; + } + // CSA(twosB, ones, ones, (A[i+2] | B[i+2]), (A[i+3] | B[i+3])) + { + long b = (A[i + 2] | B[i + 2]), c = (A[i + 3] | B[i + 3]); + long u = ones ^ b; + twosB = (ones & b) | (u & c); + ones = u ^ c; + } + // CSA(foursA, twos, twos, twosA, twosB) + { + long u = twos ^ twosA; + foursA = (twos & twosA) | (u & twosB); + twos = u ^ twosB; + } + // CSA(twosA, ones, ones, (A[i+4] | B[i+4]), (A[i+5] | B[i+5])) + { + long b = (A[i + 4] | B[i + 4]), c = (A[i + 5] | B[i + 5]); + long u = ones ^ b; + twosA = (ones & b) | (u & c); + ones = u ^ c; + } + // CSA(twosB, ones, ones, (A[i+6] | B[i+6]), (A[i+7] | B[i+7])) + { + long b = (A[i + 6] | B[i + 6]), c = (A[i + 7] | B[i + 7]); + long u = ones ^ b; + twosB = (ones & b) | (u & c); + ones = u ^ c; + } + // CSA(foursB, twos, twos, twosA, twosB) + { + long u = twos ^ twosA; + foursB = (twos & twosA) | (u & twosB); + twos = u ^ twosB; + } + + // CSA(eights, fours, fours, foursA, foursB) + { + long u = fours ^ foursA; + eights = (fours & foursA) | (u & foursB); + fours = u ^ foursB; + } + tot8 += pop(eights); + } + + if (i <= n - 4) { + long twosA, twosB, foursA, eights; + { + long b = (A[i] | B[i]), c = (A[i + 1] | B[i + 1]); + long u = ones ^ b; + twosA = (ones & b) | (u & c); + ones = u ^ c; + } + { + long b = (A[i + 2] | B[i + 2]), c = (A[i + 3] | B[i + 3]); + long u = ones ^ b; + twosB = (ones & b) | (u & c); + ones = u ^ c; + } + { + long u = twos ^ twosA; + foursA = (twos & twosA) | (u & twosB); + twos = u ^ twosB; + } + eights = fours & foursA; + fours = fours ^ foursA; + + tot8 += pop(eights); + i += 4; + } + + if (i <= n - 2) { + long b = (A[i] | B[i]), c = (A[i + 1] | B[i + 1]); + long u = ones ^ b; + long twosA = (ones & b) | (u & c); + ones = u ^ c; + + long foursA = twos & twosA; + twos = twos ^ twosA; + + long eights = fours & foursA; + fours = fours ^ foursA; + + tot8 += pop(eights); + i += 2; + } + + if (i < n) { + tot += pop((A[i] | B[i])); + } + + tot += (pop(fours) << 2) + (pop(twos) << 1) + pop(ones) + (tot8 << 3); + + return tot; + } + + /** + * Returns the popcount or cardinality of A & ~B + * Neither array is modified. + */ + public static long pop_andnot(long A[], long B[], int wordOffset, int numWords) { + // generated from pop_array via sed 's/A\[\([^]]*\)\]/\(A[\1] \& + // ~B[\1]\)/g' + int n = wordOffset + numWords; + long tot = 0, tot8 = 0; + long ones = 0, twos = 0, fours = 0; + + int i; + for (i = wordOffset; i <= n - 8; i += 8) { + /*** + * C macro from Hacker's Delight + * #define CSA(h,l, a,b,c) \ + * {unsigned u = a ^ b; unsigned v = c; \ + * h = (a & b) | (u & v); l = u ^ v;} + ***/ + + long twosA, twosB, foursA, foursB, eights; + + // CSA(twosA, ones, ones, (A[i] & ~B[i]), (A[i+1] & ~B[i+1])) + { + long b = (A[i] & ~B[i]), c = (A[i + 1] & ~B[i + 1]); + long u = ones ^ b; + twosA = (ones & b) | (u & c); + ones = u ^ c; + } + // CSA(twosB, ones, ones, (A[i+2] & ~B[i+2]), (A[i+3] & ~B[i+3])) + { + long b = (A[i + 2] & ~B[i + 2]), c = (A[i + 3] & ~B[i + 3]); + long u = ones ^ b; + twosB = (ones & b) | (u & c); + ones = u ^ c; + } + // CSA(foursA, twos, twos, twosA, twosB) + { + long u = twos ^ twosA; + foursA = (twos & twosA) | (u & twosB); + twos = u ^ twosB; + } + // CSA(twosA, ones, ones, (A[i+4] & ~B[i+4]), (A[i+5] & ~B[i+5])) + { + long b = (A[i + 4] & ~B[i + 4]), c = (A[i + 5] & ~B[i + 5]); + long u = ones ^ b; + twosA = (ones & b) | (u & c); + ones = u ^ c; + } + // CSA(twosB, ones, ones, (A[i+6] & ~B[i+6]), (A[i+7] & ~B[i+7])) + { + long b = (A[i + 6] & ~B[i + 6]), c = (A[i + 7] & ~B[i + 7]); + long u = ones ^ b; + twosB = (ones & b) | (u & c); + ones = u ^ c; + } + // CSA(foursB, twos, twos, twosA, twosB) + { + long u = twos ^ twosA; + foursB = (twos & twosA) | (u & twosB); + twos = u ^ twosB; + } + + // CSA(eights, fours, fours, foursA, foursB) + { + long u = fours ^ foursA; + eights = (fours & foursA) | (u & foursB); + fours = u ^ foursB; + } + tot8 += pop(eights); + } + + if (i <= n - 4) { + long twosA, twosB, foursA, eights; + { + long b = (A[i] & ~B[i]), c = (A[i + 1] & ~B[i + 1]); + long u = ones ^ b; + twosA = (ones & b) | (u & c); + ones = u ^ c; + } + { + long b = (A[i + 2] & ~B[i + 2]), c = (A[i + 3] & ~B[i + 3]); + long u = ones ^ b; + twosB = (ones & b) | (u & c); + ones = u ^ c; + } + { + long u = twos ^ twosA; + foursA = (twos & twosA) | (u & twosB); + twos = u ^ twosB; + } + eights = fours & foursA; + fours = fours ^ foursA; + + tot8 += pop(eights); + i += 4; + } + + if (i <= n - 2) { + long b = (A[i] & ~B[i]), c = (A[i + 1] & ~B[i + 1]); + long u = ones ^ b; + long twosA = (ones & b) | (u & c); + ones = u ^ c; + + long foursA = twos & twosA; + twos = twos ^ twosA; + + long eights = fours & foursA; + fours = fours ^ foursA; + + tot8 += pop(eights); + i += 2; + } + + if (i < n) { + tot += pop((A[i] & ~B[i])); + } + + tot += (pop(fours) << 2) + (pop(twos) << 1) + pop(ones) + (tot8 << 3); + + return tot; + } + + public static long pop_xor(long A[], long B[], int wordOffset, int numWords) { + int n = wordOffset + numWords; + long tot = 0, tot8 = 0; + long ones = 0, twos = 0, fours = 0; + + int i; + for (i = wordOffset; i <= n - 8; i += 8) { + /*** + * C macro from Hacker's Delight + * #define CSA(h,l, a,b,c) \ + * {unsigned u = a ^ b; unsigned v = c; \ + * h = (a & b) | (u & v); l = u ^ v;} + ***/ + + long twosA, twosB, foursA, foursB, eights; + + // CSA(twosA, ones, ones, (A[i] ^ B[i]), (A[i+1] ^ B[i+1])) + { + long b = (A[i] ^ B[i]), c = (A[i + 1] ^ B[i + 1]); + long u = ones ^ b; + twosA = (ones & b) | (u & c); + ones = u ^ c; + } + // CSA(twosB, ones, ones, (A[i+2] ^ B[i+2]), (A[i+3] ^ B[i+3])) + { + long b = (A[i + 2] ^ B[i + 2]), c = (A[i + 3] ^ B[i + 3]); + long u = ones ^ b; + twosB = (ones & b) | (u & c); + ones = u ^ c; + } + // CSA(foursA, twos, twos, twosA, twosB) + { + long u = twos ^ twosA; + foursA = (twos & twosA) | (u & twosB); + twos = u ^ twosB; + } + // CSA(twosA, ones, ones, (A[i+4] ^ B[i+4]), (A[i+5] ^ B[i+5])) + { + long b = (A[i + 4] ^ B[i + 4]), c = (A[i + 5] ^ B[i + 5]); + long u = ones ^ b; + twosA = (ones & b) | (u & c); + ones = u ^ c; + } + // CSA(twosB, ones, ones, (A[i+6] ^ B[i+6]), (A[i+7] ^ B[i+7])) + { + long b = (A[i + 6] ^ B[i + 6]), c = (A[i + 7] ^ B[i + 7]); + long u = ones ^ b; + twosB = (ones & b) | (u & c); + ones = u ^ c; + } + // CSA(foursB, twos, twos, twosA, twosB) + { + long u = twos ^ twosA; + foursB = (twos & twosA) | (u & twosB); + twos = u ^ twosB; + } + + // CSA(eights, fours, fours, foursA, foursB) + { + long u = fours ^ foursA; + eights = (fours & foursA) | (u & foursB); + fours = u ^ foursB; + } + tot8 += pop(eights); + } + + if (i <= n - 4) { + long twosA, twosB, foursA, eights; + { + long b = (A[i] ^ B[i]), c = (A[i + 1] ^ B[i + 1]); + long u = ones ^ b; + twosA = (ones & b) | (u & c); + ones = u ^ c; + } + { + long b = (A[i + 2] ^ B[i + 2]), c = (A[i + 3] ^ B[i + 3]); + long u = ones ^ b; + twosB = (ones & b) | (u & c); + ones = u ^ c; + } + { + long u = twos ^ twosA; + foursA = (twos & twosA) | (u & twosB); + twos = u ^ twosB; + } + eights = fours & foursA; + fours = fours ^ foursA; + + tot8 += pop(eights); + i += 4; + } + + if (i <= n - 2) { + long b = (A[i] ^ B[i]), c = (A[i + 1] ^ B[i + 1]); + long u = ones ^ b; + long twosA = (ones & b) | (u & c); + ones = u ^ c; + + long foursA = twos & twosA; + twos = twos ^ twosA; + + long eights = fours & foursA; + fours = fours ^ foursA; + + tot8 += pop(eights); + i += 2; + } + + if (i < n) { + tot += pop((A[i] ^ B[i])); + } + + tot += (pop(fours) << 2) + (pop(twos) << 1) + pop(ones) + (tot8 << 3); + + return tot; + } + + public long cardinality() { + return pop_array(bits, 0, wlen); + } + + /** + * Returns the popcount or cardinality of the intersection of the two sets. + * Neither set is modified. + */ + public static long intersectionCount(OpenBitSet a, OpenBitSet b) { + return pop_intersect(a.bits, b.bits, 0, Math.min(a.wlen, b.wlen)); + } + + /** + * Returns the popcount or cardinality of the union of the two sets. + * Neither set is modified. + */ + public static long unionCount(OpenBitSet a, OpenBitSet b) { + long tot = pop_union(a.bits, b.bits, 0, Math.min(a.wlen, b.wlen)); + if (a.wlen < b.wlen) { + tot += pop_array(b.bits, a.wlen, b.wlen - a.wlen); + } else if (a.wlen > b.wlen) { + tot += pop_array(a.bits, b.wlen, a.wlen - b.wlen); + } + return tot; + } + + /** + * Returns the popcount or cardinality of "a and not b" + * or "intersection(a, not(b))" + * Neither set is modified. + */ + public static long andNotCount(OpenBitSet a, OpenBitSet b) { + long tot = pop_andnot(a.bits, b.bits, 0, Math.min(a.wlen, b.wlen)); + if (a.wlen > b.wlen) { + tot += pop_array(a.bits, b.wlen, a.wlen - b.wlen); + } + return tot; + } + + /** + * Returns the popcount or cardinality of the exclusive-or of the two sets. + * Neither set is modified. + */ + public static long xorCount(OpenBitSet a, OpenBitSet b) { + long tot = pop_xor(a.bits, b.bits, 0, Math.min(a.wlen, b.wlen)); + if (a.wlen < b.wlen) { + tot += pop_array(b.bits, a.wlen, b.wlen - a.wlen); + } else if (a.wlen > b.wlen) { + tot += pop_array(a.bits, b.wlen, a.wlen - b.wlen); + } + return tot; + } + + /** + * Returns the index of the first set bit starting at the index specified. + * -1 is returned if there are no more set bits. + */ + public int nextSetBit(int index) { + int i = index >> 6; + if (i >= wlen) + return -1; + int subIndex = index & 0x3f; // index within the word + long word = bits[i] >> subIndex; // skip all the bits to the right of + // index + + if (word != 0) { + return (i << 6) + subIndex + ntz(word); + } + + while (++i < wlen) { + word = bits[i]; + if (word != 0) + return (i << 6) + ntz(word); + } + + return -1; + } + + /** + * Returns the index of the first set bit starting at the index specified. + * -1 is returned if there are no more set bits. + */ + public long nextSetBit(long index) { + int i = (int) (index >>> 6); + if (i >= wlen) + return -1; + int subIndex = (int) index & 0x3f; // index within the word + long word = bits[i] >>> subIndex; // skip all the bits to the right of + // index + + if (word != 0) { + return (((long) i) << 6) + (subIndex + ntz(word)); + } + + while (++i < wlen) { + word = bits[i]; + if (word != 0) + return (((long) i) << 6) + ntz(word); + } + + return -1; + } + + /*** + * python code to generate ntzTable + * def ntz(val): + * if val==0: return 8 + * i=0 + * while (val&0x01)==0: + * i = i+1 + * val >>= 1 + * return i + * print ','.join([ str(ntz(i)) for i in range(256) ]) + ***/ + public static final byte ntzTable[] = { 8, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, + 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, + 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, + 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, + 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, + 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, + 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, + 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 }; + + /** Returns number of trailing zeros in the 64 bit long value */ + public static int ntz(long val) { + // A full binary search to determine the low byte was slower than + // a linear search for nextSetBit(). This is most likely because + // the implementation of nextSetBit() shifts bits to the right, + // increasing + // the probability that the first non-zero byte is in the rhs. + // + // This implementation does a single binary search at the top level only + // so that all other bit shifting can be done on ints instead of longs + // to + // remain friendly to 32 bit architectures. In addition, the case of a + // non-zero first byte is checked for first because it is the most + // common + // in dense bit arrays. + + int lower = (int) val; + int lowByte = lower & 0xff; + if (lowByte != 0) + return ntzTable[lowByte]; + + if (lower != 0) { + lowByte = (lower >>> 8) & 0xff; + if (lowByte != 0) + return ntzTable[lowByte] + 8; + lowByte = (lower >>> 16) & 0xff; + if (lowByte != 0) + return ntzTable[lowByte] + 16; + // no need to mask off low byte for the last byte in the 32 bit word + // no need to check for zero on the last byte either. + return ntzTable[lower >>> 24] + 24; + } else { + // grab upper 32 bits + int upper = (int) (val >> 32); + lowByte = upper & 0xff; + if (lowByte != 0) + return ntzTable[lowByte] + 32; + lowByte = (upper >>> 8) & 0xff; + if (lowByte != 0) + return ntzTable[lowByte] + 40; + lowByte = (upper >>> 16) & 0xff; + if (lowByte != 0) + return ntzTable[lowByte] + 48; + // no need to mask off low byte for the last byte in the 32 bit word + // no need to check for zero on the last byte either. + return ntzTable[upper >>> 24] + 56; + } + } + + /** + * returns 0 based index of first set bit + * (only works for x!=0) + */ + public static int ntz2(long x) { + int n = 0; + int y = (int) x; + if (y == 0) { + n += 32; + y = (int) (x >>> 32); + } // the only 64 bit shift necessary + if ((y & 0x0000FFFF) == 0) { + n += 16; + y >>>= 16; + } + if ((y & 0x000000FF) == 0) { + n += 8; + y >>>= 8; + } + return (ntzTable[y & 0xff]) + n; + } + + int ntz3(long x) { + int n = 1; + + // do the first step as a long, all others as ints. + int y = (int) x; + if (y == 0) { + n += 32; + y = (int) (x >>> 32); + } + if ((y & 0x0000FFFF) == 0) { + n += 16; + y >>>= 16; + } + if ((y & 0x000000FF) == 0) { + n += 8; + y >>>= 8; + } + if ((y & 0x0000000F) == 0) { + n += 4; + y >>>= 4; + } + if ((y & 0x00000003) == 0) { + n += 2; + y >>>= 2; + } + return n - (y & 1); + } + + /*** + * Many 32 bit ntz algorithms at http://www.hackersdelight.org/HDcode/ntz.cc + */ + + public Object clone() { + try { + OpenBitSet obs = (OpenBitSet) super.clone(); + obs.bits = obs.bits.clone(); // hopefully an array clone is as + // fast(er) than arraycopy + return obs; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** this = this AND other */ + public void intersect(OpenBitSet other) { + int newLen = Math.min(this.wlen, other.wlen); + long[] thisArr = this.bits; + long[] otherArr = other.bits; + // testing against zero can be more efficient + int pos = newLen; + while (--pos >= 0) { + thisArr[pos] &= otherArr[pos]; + } + if (this.wlen > newLen) { + // fill zeros from the new shorter length to the old length + Arrays.fill(bits, newLen, this.wlen, 0); + } + this.wlen = newLen; + } + + /** this = this OR other */ + public void union(OpenBitSet other) { + int newLen = Math.max(wlen, other.wlen); + ensureCapacityWords(newLen); + + long[] thisArr = this.bits; + long[] otherArr = other.bits; + int pos = this.wlen; + while (--pos >= 0) { + thisArr[pos] |= otherArr[pos]; + } + if (this.wlen < newLen) { + System.arraycopy(otherArr, this.wlen, thisArr, this.wlen, newLen - this.wlen); + } + this.wlen = newLen; + } + + /** Remove all elements set in other. this = this AND_NOT other */ + public void remove(OpenBitSet other) { + int idx = Math.min(wlen, other.wlen); + long[] thisArr = this.bits; + long[] otherArr = other.bits; + while (--idx >= 0) { + thisArr[idx] &= ~otherArr[idx]; + } + } + + /** this = this XOR other */ + public void xor(OpenBitSet other) { + int newLen = Math.max(wlen, other.wlen); + ensureCapacityWords(newLen); + + long[] thisArr = this.bits; + long[] otherArr = other.bits; + int pos = this.wlen; + while (--pos >= 0) { + thisArr[pos] ^= otherArr[pos]; + } + if (this.wlen < newLen) { + System.arraycopy(otherArr, this.wlen, thisArr, this.wlen, newLen - this.wlen); + } + this.wlen = newLen; + } + + // some BitSet compatability methods + + // ** see {@link intersect} */ + public void and(OpenBitSet other) { + intersect(other); + } + + // ** see {@link union} */ + public void or(OpenBitSet other) { + union(other); + } + + // ** see {@link andNot} */ + public void andNot(OpenBitSet other) { + remove(other); + } + + /** + * Resize the bitset with the size given as a number of words (64 + * bit longs) + */ + public void ensureCapacityWords(int numWords) { + if (bits.length < numWords) { + long[] newBits = new long[numWords]; + System.arraycopy(bits, 0, newBits, 0, wlen); + bits = newBits; + } + } + + public void trimTrailingZeros() { + int idx = wlen - 1; + while (idx >= 0 && bits[idx] == 0) + idx--; + wlen = idx + 1; + } + +} diff --git a/src/ru/olamedia/olacraft/network/GameClient.java b/src/ru/olamedia/olacraft/network/GameClient.java index acd50fd..2312c3d 100644 --- a/src/ru/olamedia/olacraft/network/GameClient.java +++ b/src/ru/olamedia/olacraft/network/GameClient.java @@ -25,6 +25,7 @@ import ru.olamedia.olacraft.network.packet.WorldInfoPacket; import ru.olamedia.olacraft.scene.GameScene; import ru.olamedia.olacraft.world.WorldInfo; import ru.olamedia.olacraft.world.dataProvider.CachedChunkDataProvider; +import ru.olamedia.olacraft.world.dataProvider.LocalChunkDataProvider; import ru.olamedia.olacraft.world.dataProvider.RemoteChunkDataProvider; import ru.olamedia.olacraft.world.provider.WorldProvider; @@ -64,6 +65,7 @@ public class GameClient extends ConnectionStateListener implements IPacketListen // INIT WORLD worldProvider = new WorldProvider(); worldProvider.setChunkDataProvider(new CachedChunkDataProvider(new RemoteChunkDataProvider(this))); + //worldProvider.setChunkDataProvider(new CachedChunkDataProvider(new LocalChunkDataProvider(worldProvider.getInfo().name))); // CREATE SCENE scene = new GameScene(worldProvider); Kryo kryo = client.getKryo(); diff --git a/src/ru/olamedia/olacraft/network/GameServer.java b/src/ru/olamedia/olacraft/network/GameServer.java index 3d3832d..e1e7723 100644 --- a/src/ru/olamedia/olacraft/network/GameServer.java +++ b/src/ru/olamedia/olacraft/network/GameServer.java @@ -31,7 +31,7 @@ import com.esotericsoftware.kryonet.Server; public class GameServer { private WorldProvider worldProvider; - + private ExecutorService threadPool = Executors.newFixedThreadPool(1); public static Server server = new Server(10 * 1024 * 1024, 1024 * 1024) { @Override @@ -56,7 +56,10 @@ public class GameServer { public GameServer() { // INIT WORLD worldProvider = new WorldProvider(); - worldProvider.setChunkDataProvider(new CachedChunkDataProvider(new LocalChunkDataProvider(worldProvider.getInfo().name))); + // worldProvider.setChunkDataProvider(new + // LocalChunkDataProvider(worldProvider.getInfo().name)); + worldProvider.setChunkDataProvider(new CachedChunkDataProvider(new LocalChunkDataProvider(worldProvider + .getInfo().name))); // CREATE SCENE scene = new GameScene(worldProvider); // worldProvider.getInfo().name = "world"; @@ -78,8 +81,7 @@ public class GameServer { if (object instanceof GetRegionPacket) { GetRegionPacket p = (GetRegionPacket) object; RegionData data = worldProvider.getRegion(p.location); - RegionDataPacket response = new RegionDataPacket(); - response.data = data; + RegionDataPacket response = new RegionDataPacket(data); server.sendToTCP(connection.getID(), response); } if (object instanceof SpawnRequestPacket) { diff --git a/src/ru/olamedia/olacraft/network/Network.java b/src/ru/olamedia/olacraft/network/Network.java index 2ba8eab..22434f1 100644 --- a/src/ru/olamedia/olacraft/network/Network.java +++ b/src/ru/olamedia/olacraft/network/Network.java @@ -2,6 +2,9 @@ package ru.olamedia.olacraft.network; import java.util.BitSet; +import org.objenesis.strategy.SerializingInstantiatorStrategy; + +import ru.olamedia.math.OpenBitSet; import ru.olamedia.olacraft.network.packet.ChunkDataPacket; import ru.olamedia.olacraft.network.packet.ConnectionPacket; import ru.olamedia.olacraft.network.packet.ConnectionRequestPacket; @@ -26,7 +29,14 @@ import ru.olamedia.olacraft.world.location.SectorLocation; import com.esotericsoftware.kryo.Kryo; public class Network { + private static boolean isRegistered = false; + public static void registerPackets(Kryo kryo) { + if (isRegistered) { + // return; + } + isRegistered = true; + //kryo.setInstantiatorStrategy(new SerializingInstantiatorStrategy()); // types kryo.register(boolean.class); kryo.register(boolean[].class); @@ -39,7 +49,7 @@ public class Network { kryo.register(float[].class); kryo.register(long.class); kryo.register(long[].class); - kryo.register(BitSet.class); + kryo.register(OpenBitSet.class); kryo.register(HeightMap.class); kryo.register(WorldInfo.class); kryo.register(WorldInfoPacket.class); @@ -55,17 +65,11 @@ public class Network { kryo.register(RegionData.class); kryo.register(GetRegionPacket.class); kryo.register(RegionDataPacket.class); - - - kryo.register(ChunkLightData.class); - kryo.register(ChunkData.class); - // packets kryo.register(ConnectionRequestPacket.class); kryo.register(ConnectionPacket.class); kryo.register(SpawnRequestPacket.class); kryo.register(SpawnPacket.class); - kryo.register(GetChunkDataPacket.class); - kryo.register(ChunkDataPacket.class); kryo.register(LiveEntityLocationUpdatePacket.class); + // packets } } diff --git a/src/ru/olamedia/olacraft/network/packet/RegionDataPacket.java b/src/ru/olamedia/olacraft/network/packet/RegionDataPacket.java index 3a60230..72ddba3 100644 --- a/src/ru/olamedia/olacraft/network/packet/RegionDataPacket.java +++ b/src/ru/olamedia/olacraft/network/packet/RegionDataPacket.java @@ -3,5 +3,12 @@ package ru.olamedia.olacraft.network.packet; import ru.olamedia.olacraft.world.data.RegionData; public class RegionDataPacket implements IPacket { + public RegionDataPacket() { + } + + public RegionDataPacket(RegionData data) { + this.data = data; + } + public RegionData data; } diff --git a/src/ru/olamedia/olacraft/render/jogl/ChunkRenderer.java b/src/ru/olamedia/olacraft/render/jogl/ChunkRenderer.java index e24e8e9..22a88ab 100644 --- a/src/ru/olamedia/olacraft/render/jogl/ChunkRenderer.java +++ b/src/ru/olamedia/olacraft/render/jogl/ChunkRenderer.java @@ -4,6 +4,8 @@ import javax.media.opengl.GL; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLContext; +import ru.olamedia.Options; +import ru.olamedia.geom.SimpleQuadMesh; import ru.olamedia.math.Box; import ru.olamedia.math.Classifier; import ru.olamedia.olacraft.game.Game; @@ -11,6 +13,8 @@ import ru.olamedia.olacraft.world.chunk.BlockSlice; import ru.olamedia.olacraft.world.chunk.Chunk; import ru.olamedia.olacraft.world.chunk.ChunkMeshBulder; import ru.olamedia.olacraft.world.chunk.ChunkSlice; +import ru.olamedia.olacraft.world.location.BlockLocation; +import ru.olamedia.olacraft.world.location.ChunkLocation; public class ChunkRenderer { private BlockSlice slice; @@ -30,22 +34,21 @@ public class ChunkRenderer { public int frustumIntersectChunks = 0; public boolean renderChunk(Chunk chunk, boolean skipnew) { - GL gl = GLContext.getCurrentGL(); + if (!chunk.isAvailable()) { // System.out.println("not available"); chunk.request(); return skipnew; } - /* - * if (!chunk.isNeighborsAvailable()) { - * System.out.println("no neighbors"); - * chunk.requestNeighbors(); - * return; - * } - */ + + if (!chunk.isNeighborsAvailable()) { + chunk.requestNeighbors(); + return skipnew; + } + // System.out.println("available"); - Box box = new Box(chunk.getX(), chunk.getY(), chunk.getZ(), chunk.getX() + chunk.getWidth(), chunk.getY() - + chunk.getHeight(), chunk.getZ() + chunk.getDepth()); + Box box = new Box(chunk.getOffset().x, chunk.getOffset().y, chunk.getOffset().z, chunk.getOffset().x + + chunk.getWidth(), chunk.getOffset().y + chunk.getHeight(), chunk.getOffset().z + chunk.getDepth()); if (Game.instance.camera.frustum.quickClassify(box) == Classifier.OUTSIDE) { frustumCulledChunks++; return skipnew; @@ -74,20 +77,27 @@ public class ChunkRenderer { if (!chunk.isMeshCostructed) { ChunkMeshBulder.instance.add(chunk); if (ChunkMeshBulder.instance.isFull()) { + // System.out.println("queue is full, skipping"); skipnew = true; } + // System.out.println("not constructed"); return skipnew; } if (null == chunk.getMesh()) { + // System.out.println("mesh is null"); + // skipnew = true; } else { - chunk.getMesh().joglRender(gl); + SimpleQuadMesh mesh = chunk.getMesh(); + // System.out.println("render " + chunk + " " + + // mesh.getVertexCount()); + mesh.joglRender(); } return skipnew; } public void render(GLAutoDrawable drawable) { - if (!ChunkMeshBulder.instance.isAlive()) { + if (!ChunkMeshBulder.instance.isAlive() && !ChunkMeshBulder.instance.isInterrupted()) { ChunkMeshBulder.instance.start(); } @@ -100,47 +110,162 @@ public class ChunkRenderer { frustumCulledChunks = 0; boolean skipnew = false; ChunkSlice cs = slice.getChunkSlice(); + for (int x = cs.getX(); x < cs.getX() + cs.getWidth(); x++) { + for (int z = cs.getZ(); z < cs.getZ() + cs.getDepth(); z++) { + for (int y = cs.getY(); y < cs.getY() + cs.getHeight(); y++) { + skipnew = renderChunk(cs.getChunk(new ChunkLocation(x, y, z)), skipnew); + } + } + } + if (true) { + return; + } // rendering from center int x, y, z; - int dw = cs.getWidth() / 2; - int dd = cs.getDepth() / 2; - int dh = cs.getHeight() / 2; - for (int dx = 0; dx < dw; dx++) { - x = cs.getX() + dw + dx; - for (int dz = 0; dz < dd; dz++) { - z = cs.getZ() + dd + dz; - for (int dy = 0; dy < dh; dy++) { - y = cs.getY() + dh + dy; - skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); - y = cs.getY() + dh - dy - 1; - skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); + int half = (Options.renderDistance / 16) / 2 + 1; + BlockLocation camera = new BlockLocation(); + camera.x = (int) Game.client.getScene().getPlayer().getCameraX(); + camera.y = (int) Game.client.getScene().getPlayer().getCameraY(); + camera.z = (int) Game.client.getScene().getPlayer().getCameraZ(); + ChunkLocation cameraChunk = camera.getChunkLocation(); + int cx = cameraChunk.x; + int cy = cameraChunk.y; + int cz = cameraChunk.z; + ChunkLocation cLoc = new ChunkLocation(cx, cy, cz); + for (int r = 0; r <= half; r++) { + // +x + x = cx + r; + for (z = cz - r - 1; z <= cz + r; z++) { + for (y = cy - r - 1; y <= cy + r; y++) { + cLoc = new ChunkLocation(x, y, z); + skipnew = renderChunk(cs.getChunk(cLoc), skipnew); } - z = cs.getZ() + dd - dz - 1; - for (int dy = 0; dy < dh; dy++) { - y = cs.getY() + dh + dy; - skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); - y = cs.getY() + dh - dy - 1; - skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); + } + // -x + x = cx - r - 1; + for (z = cz - r - 1; z <= cz + r; z++) { + for (y = cy - r - 1; y <= cy + r; y++) { + cLoc = new ChunkLocation(x, y, z); + skipnew = renderChunk(cs.getChunk(cLoc), skipnew); + } + } + + // +z + z = cz + r; + for (x = cx - r - 1; x <= cz + r; x++) { + for (y = cy - r - 1; y <= cy + r; y++) { + cLoc = new ChunkLocation(x, y, z); + skipnew = renderChunk(cs.getChunk(cLoc), skipnew); } } - x = cs.getX() + dw - dx - 1; - for (int dz = 0; dz < dd; dz++) { - z = cs.getZ() + dd + dz; - for (int dy = 0; dy < dh; dy++) { - y = cs.getY() + dh + dy; - skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); - y = cs.getY() + dh - dy - 1; - skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); + // -z + z = cz - r - 1; + for (x = cx - r - 1; x <= cz + r; x++) { + for (y = cy - r - 1; y <= cy + r; y++) { + cLoc = new ChunkLocation(x, y, z); + skipnew = renderChunk(cs.getChunk(cLoc), skipnew); } - z = cs.getZ() + dd - dz - 1; - for (int dy = 0; dy < dh; dy++) { - y = cs.getY() + dh + dy; - skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); - y = cs.getY() + dh - dy - 1; - skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); + } + // +y + y = cy + r; + for (x = cx - r - 1; x <= cz + r; x++) { + for (z = cz - r - 1; z <= cz + r; z++) { + cLoc = new ChunkLocation(x, y, z); + skipnew = renderChunk(cs.getChunk(cLoc), skipnew); + } + } + // -y + y = cy - r - 1; + for (x = cx - r - 1; x <= cz + r; x++) { + for (z = cz - r - 1; z <= cz + r; z++) { + cLoc = new ChunkLocation(x, y, z); + skipnew = renderChunk(cs.getChunk(cLoc), skipnew); } } + if (skipnew) { + // break; + } + // break; } + + // int dw = cs.getWidth() / 2; + // int dd = cs.getDepth() / 2; + // int dh = cs.getHeight() / 2; + // for (int dx = 0; dx < dw; dx++) { + // x = cs.getX() + dw + dx; + // for (int dz = 0; dz < dd; dz++) { + // z = cs.getZ() + dd + dz; + // for (int dy = 0; dy < dh; dy++) { + // y = cs.getY() + dh + dy; + // skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); + // y = cs.getY() + dh - dy - 1; + // skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); + // } + // z = cs.getZ() + dd - dz - 1; + // for (int dy = 0; dy < dh; dy++) { + // y = cs.getY() + dh + dy; + // skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); + // y = cs.getY() + dh - dy - 1; + // skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); + // } + // } + // x = cs.getX() + dw - dx - 1; + // for (int dz = 0; dz < dd; dz++) { + // z = cs.getZ() + dd + dz; + // for (int dy = 0; dy < dh; dy++) { + // y = cs.getY() + dh + dy; + // int dd = cs.getDepth() / 2; + // int dh = cs.getHeight() / 2; + // for (int dx = 0; dx < dw; dx++) { + // x = cs.getX() + dw + dx; + // for (int dz = 0; dz < dd; dz++) { + // z = cs.getZ() + dd + dz; + // for (int dy = 0; dy < dh; dy++) { + // y = cs.getY() + dh + dy; + // skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); + // y = cs.getY() + dh - dy - 1; + // skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); + // } + // z = cs.getZ() + dd - dz - 1; + // for (int dy = 0; dy < dh; dy++) { + // y = cs.getY() + dh + dy; + // skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); + // y = cs.getY() + dh - dy - 1; + // skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); + // } + // } + // x = cs.getX() + dw - dx - 1; + // for (int dz = 0; dz < dd; dz++) { + // z = cs.getZ() + dd + dz; + // for (int dy = 0; dy < dh; dy++) { + // y = cs.getY() + dh + dy; + // skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); + // y = cs.getY() + dh - dy - 1; + // skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); + // } + // z = cs.getZ() + dd - dz - 1; + // for (int dy = 0; dy < dh; dy++) { + // y = cs.getY() + dh + dy; + // skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); + // y = cs.getY() + dh - dy - 1; + // skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); + // } + // } + // } + // skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); + // y = cs.getY() + dh - dy - 1; + // skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); + // } + // z = cs.getZ() + dd - dz - 1; + // for (int dy = 0; dy < dh; dy++) { + // y = cs.getY() + dh + dy; + // skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); + // y = cs.getY() + dh - dy - 1; + // skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); + // } + // } + // } + // System.out.println("visible top " + visibleTop); } } diff --git a/src/ru/olamedia/olacraft/render/jogl/PlaneRenderer.java b/src/ru/olamedia/olacraft/render/jogl/PlaneRenderer.java index 754a093..a6e796c 100644 --- a/src/ru/olamedia/olacraft/render/jogl/PlaneRenderer.java +++ b/src/ru/olamedia/olacraft/render/jogl/PlaneRenderer.java @@ -19,6 +19,9 @@ public class PlaneRenderer { } public static void render(Plane p, GLAutoDrawable drawable) { + if (true){ + return; + } GL2 gl = drawable.getGL().getGL2(); float size = 100; float step = size / 5; diff --git a/src/ru/olamedia/olacraft/scene/GameScene.java b/src/ru/olamedia/olacraft/scene/GameScene.java index 618e270..7f2e1fa 100644 --- a/src/ru/olamedia/olacraft/scene/GameScene.java +++ b/src/ru/olamedia/olacraft/scene/GameScene.java @@ -25,6 +25,7 @@ import ru.olamedia.olacraft.weapon.BulletScene; import ru.olamedia.olacraft.world.blockTypes.AbstractBlockType; import ru.olamedia.olacraft.world.blockTypes.GrassBlockType; import ru.olamedia.olacraft.world.chunk.BlockSlice; +import ru.olamedia.olacraft.world.chunk.ChunkSlice; import ru.olamedia.olacraft.world.provider.WorldProvider; import ru.olamedia.player.Player; import ru.olamedia.vbo.VBO; @@ -97,7 +98,7 @@ public class GameScene { */ public void setRenderDistance(int renderDistance) { this.renderDistance = renderDistance; - viewSlice = new BlockSlice(provider, renderDistance, renderDistance * 2, renderDistance); + viewSlice = new BlockSlice(provider, renderDistance, renderDistance, renderDistance); blockRenderer = new ChunkRenderer(viewSlice); } @@ -152,10 +153,12 @@ public class GameScene { gl.glClearColor(49f / 255f, 119f / 255f, 243f / 255f, 1); // GOING 3D gl.glPushMatrix(); + gl.glPushAttrib(GL2.GL_ALL_ATTRIB_BITS); Game.instance.camera.setUp(drawable); viewSlice.setCenter((int) Game.instance.camera.getX(), (int) Game.instance.camera.getY(), (int) Game.instance.camera.getZ()); // RENDER BLOCKS + gl.glPopAttrib(); gl.glPushAttrib(GL2.GL_ALL_ATTRIB_BITS); gl.glColor4f(0f, 1f, 0, 1); gl.glEnable(GL2.GL_DEPTH_TEST); @@ -180,6 +183,7 @@ public class GameScene { for (LiveEntity entity : liveEntities.values()) { gl.glPushMatrix(); gl.glTranslatef(entity.getX(), entity.getCameraY(), entity.getZ()); + gl.glPolygonMode(GL2.GL_FRONT_AND_BACK, GL2.GL_LINE); glu.gluSphere(qobj0, 0.5f, 10, 10); gl.glPopMatrix(); } @@ -187,7 +191,7 @@ public class GameScene { // bullets.render(drawable); gl.glPopMatrix(); - testObject.render(); + // testObject.render(); // GOIND 2D gl.glMatrixMode(GL2.GL_PROJECTION); @@ -227,7 +231,7 @@ public class GameScene { // inventoryprivate PMVMatrix matrix; if (null != inventoryRenderer) { - inventoryRenderer.render(drawable); + // inventoryRenderer.render(drawable); } viewport.drawText("avg fps: " + (int) Game.timer.getAvgFps(), 10, height - 20); @@ -244,9 +248,21 @@ public class GameScene { viewport.drawText("inAir: " + Game.instance.player.inAir(), width - msz - 10, height - msz - 110); viewport.drawText("rdistance: " + renderDistance, width - msz - 10, height - msz - 155); - viewport.drawText("cam x: " + Game.instance.camera.getX(), width - msz - 10, height - msz - 170); + ChunkSlice cs = viewSlice.getChunkSlice(); + viewport.drawText("slice x: " + cs.getX() + ".." + (cs.getX() + cs.getWidth() - 1) + " y: " + cs.getY() + ".." + + (cs.getY() + cs.getHeight() - 1) + " z: " + cs.getZ() + ".." + (cs.getZ() + cs.getDepth() - 1), width + - msz * 2 - 10, height - msz - 170); + // viewport.drawText("slice x: " + (cs.getX() + cs.getWidth() - 1) + + // " y: " + (cs.getY() + cs.getHeight() - 1) + // + " z: " + (cs.getY() + cs.getDepth() - 1), width - msz * 2 - 10, + // height - msz - 185); + gl.glPopAttrib(); gl.glPopMatrix(); gl.glFlush(); } + + public Player getPlayer() { + return player; + } } diff --git a/src/ru/olamedia/olacraft/world/chunk/BlockSlice.java b/src/ru/olamedia/olacraft/world/chunk/BlockSlice.java index ca4c92a..bc744c4 100644 --- a/src/ru/olamedia/olacraft/world/chunk/BlockSlice.java +++ b/src/ru/olamedia/olacraft/world/chunk/BlockSlice.java @@ -1,37 +1,20 @@ package ru.olamedia.olacraft.world.chunk; +import ru.olamedia.olacraft.world.location.BlockLocation; +import ru.olamedia.olacraft.world.location.ChunkLocation; import ru.olamedia.olacraft.world.provider.WorldProvider; public class BlockSlice { protected WorldProvider provider; - protected int leftX; - protected int bottomY; - protected int backZ; + protected BlockLocation offset; protected int width; protected int height; protected int depth; protected ChunkSlice chunkSlice; - // Memory leak: - //protected int[][] highest = new int[256][256]; - - public void invalidateCache(){ - //highest = new int[256][256]; + public void invalidateCache() { } - -/* public int getHighest(int blockX, int blockZ) { - if (highest[blockX - leftX][blockZ - backZ] > 0){ - return highest[blockX - leftX][blockZ - backZ]; - } - for (int y = 0; y < 128; y++) { - if (provider.isEmptyBlock(blockX, y, blockZ)){ - highest[blockX - leftX][blockZ - backZ] = y; - return y; - } - } - return 0; - }*/ /** * @@ -44,6 +27,7 @@ public class BlockSlice { * (blocks) */ public BlockSlice(WorldProvider provider, int width, int height, int depth) { + offset = new BlockLocation(); this.provider = provider; this.width = width; this.height = height; @@ -54,10 +38,8 @@ public class BlockSlice { if (null == chunkSlice) { chunkSlice = new ChunkSlice(provider, width / 16, height / 16, depth / 16); } - int x = Chunk.v(leftX); - int y = Chunk.v(bottomY); - int z = Chunk.v(backZ); - chunkSlice.setLocation(x, y, z); + ChunkLocation chunkOffset = offset.getChunkLocation(); + chunkSlice.setLocation(chunkOffset); return chunkSlice; } @@ -120,12 +102,12 @@ public class BlockSlice { * (blocks) */ public void setLocation(int x, int y, int z) { - if (x != leftX || y != bottomY || z != backZ){ + if (x != offset.x || y != offset.y || z != offset.z) { invalidateCache(); } - leftX = x; - bottomY = y; - backZ = z; + offset.x = x; + offset.y = y; + offset.z = z; } /** @@ -142,23 +124,14 @@ public class BlockSlice { } /** - * @return the left x (blocks) - */ - public int getX() { - return leftX; - } - - /** - * @return the bottom y (blocks) + * @return offset */ - public int getY() { - return bottomY; + public BlockLocation getOffset() { + return offset; } - /** - * @return the back z (blocks) - */ - public int getZ() { - return backZ; + @Override + public String toString() { + return this.getClass().getSimpleName() + "[" + offset + ";" + width + "x" + height + "x" + depth + "]"; } } diff --git a/src/ru/olamedia/olacraft/world/chunk/Chunk.java b/src/ru/olamedia/olacraft/world/chunk/Chunk.java index ca2d4bf..0eaad3c 100644 --- a/src/ru/olamedia/olacraft/world/chunk/Chunk.java +++ b/src/ru/olamedia/olacraft/world/chunk/Chunk.java @@ -37,6 +37,24 @@ public class Chunk extends BlockSlice { } /** + * Convert chunk coordinate into block coordinate (back left bottom) + * + * @param v + * block coordinate along one axis + * @return + */ + public static int rev(int v) { + return v * 16; // -32..-17 -16..-1 0..15 16..31 32.. + /* + * if (v >= 0) { + * return v * 16; + * } else { + * return (v + 1) * 16 - 1; + * } + */ + } + + /** * Convert block coordinate into block position inside of chunk * * @param v @@ -78,11 +96,11 @@ public class Chunk extends BlockSlice { if (isMeshCostructed) { return mesh; } - if (getY() > provider.getInfo().maxHeight) { + if (offset.y > provider.getInfo().maxHeight) { isMeshCostructed = true; return null; } - if (getY() < provider.getInfo().minHeight) { + if (offset.y < provider.getInfo().minHeight) { isMeshCostructed = true; return null; } @@ -95,9 +113,9 @@ public class Chunk extends BlockSlice { // gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL2.GL_FASTEST); // gl.glHint(GL2.GL_LINE_SMOOTH_HINT, GL2.GL_NICEST); GrassBlockType grass = new GrassBlockType(); - for (int x = getX(); x < getX() + getWidth(); x++) { - for (int y = getY(); y < getY() + getHeight(); y++) { - for (int z = getZ(); z < getZ() + getDepth(); z++) { + for (int x = offset.x; x < offset.x + getWidth(); x++) { + for (int y = offset.y; y < offset.y + getHeight(); y++) { + for (int z = offset.z; z < offset.z + getDepth(); z++) { // if (!isEmptyBlock(x, y, z)) { @@ -168,6 +186,9 @@ public class Chunk extends BlockSlice { mesh.addFrontQuad(); visibleFront++; } + // System.out.println("mesh not empty"); + } else { + // System.out.println("mesh empty"); } } } @@ -193,7 +214,7 @@ public class Chunk extends BlockSlice { } private BlockLocation getBlockLocation() { - return new BlockLocation(getX(), getY(), getZ()); + return offset; } public boolean isAvailable() { @@ -201,9 +222,9 @@ public class Chunk extends BlockSlice { } public boolean isNeighborsAvailable() { - int x = Chunk.v(getX()); - int y = Chunk.v(getY()); - int z = Chunk.v(getZ()); + int x = offset.getChunkLocation().x; + int y = offset.getChunkLocation().y; + int z = offset.getChunkLocation().z; return provider.isChunkAvailable(new ChunkLocation(x - 1, y, z)) && provider.isChunkAvailable(new ChunkLocation(x + 1, y, z)) && provider.isChunkAvailable(new ChunkLocation(x, y - 1, z)) @@ -213,9 +234,9 @@ public class Chunk extends BlockSlice { } public void requestNeighbors() { - int x = Chunk.v(getX()); - int y = Chunk.v(getY()); - int z = Chunk.v(getZ()); + int x = offset.getChunkLocation().x; + int y = offset.getChunkLocation().y; + int z = offset.getChunkLocation().z; if (!provider.isChunkAvailable(new ChunkLocation(x - 1, y, z))) { provider.loadChunk(new ChunkLocation(x - 1, y, z)); } @@ -237,11 +258,7 @@ public class Chunk extends BlockSlice { } public void request() { - BlockLocation blockLocation = new BlockLocation(getX(), getY(), getZ()); - // System.out.println("provider.requestChunk(" + - // blockLocation.getRegionLocation() + blockLocation.getChunkLocation() - // + ")"); - provider.loadChunk(blockLocation.getChunkLocation()); + provider.loadChunk(offset.getChunkLocation()); } // public BlockType getBlockType(int x, int y, int z) { @@ -287,4 +304,8 @@ public class Chunk extends BlockSlice { public WorldProvider getProvider() { return provider; } + + public void setLocation(ChunkLocation location) { + setLocation(location.getBlockLocation().x, location.getBlockLocation().y, location.getBlockLocation().z); + } } diff --git a/src/ru/olamedia/olacraft/world/chunk/ChunkSlice.java b/src/ru/olamedia/olacraft/world/chunk/ChunkSlice.java index e440740..d0307bb 100644 --- a/src/ru/olamedia/olacraft/world/chunk/ChunkSlice.java +++ b/src/ru/olamedia/olacraft/world/chunk/ChunkSlice.java @@ -2,13 +2,12 @@ package ru.olamedia.olacraft.world.chunk; import java.util.HashMap; +import ru.olamedia.olacraft.world.location.ChunkLocation; import ru.olamedia.olacraft.world.provider.WorldProvider; public class ChunkSlice { private WorldProvider provider; - private int leftX; - private int bottomY; - private int backZ; + private ChunkLocation offset; private int width; private int height; private int depth; @@ -18,17 +17,21 @@ public class ChunkSlice { this.width = width; this.height = height; this.depth = depth; + offset = new ChunkLocation(); } protected HashMap<String, Chunk> chunks = new HashMap<String, Chunk>(); - public Chunk getChunk(int x, int y, int z) { + public Chunk getChunk(ChunkLocation location) { + int x = location.x; + int y = location.y; + int z = location.z; String key = x + ";" + y + ";" + z; if (chunks.containsKey(key)) { return chunks.get(key); } else { Chunk chunk = new Chunk(provider); - chunk.setLocation(x * 16, y * 16, z * 16); + chunk.setLocation(location); chunks.put(key, chunk); return chunk; } @@ -79,36 +82,33 @@ public class ChunkSlice { this.depth = depth; } - public void setLocation(int x, int y, int z) { - leftX = x; - bottomY = y; - backZ = z; - } - public void setCenter(int x, int y, int z) { - leftX = x - width / 2; - bottomY = y - height / 2; - backZ = z - depth / 2; + offset.x = x - width / 2; + offset.y = y - height / 2; + offset.z = z - depth / 2; } /** * @return the leftX */ public int getX() { - return leftX; + return offset.x; } /** * @return the bottomY */ public int getY() { - return bottomY; + return offset.y; } /** * @return the backZ */ public int getZ() { - return backZ; + return offset.z; + } + public void setLocation(ChunkLocation chunkOffset) { + offset = chunkOffset; } } diff --git a/src/ru/olamedia/olacraft/world/data/ChunkData.java b/src/ru/olamedia/olacraft/world/data/ChunkData.java index a1abc9e..a6b9f34 100644 --- a/src/ru/olamedia/olacraft/world/data/ChunkData.java +++ b/src/ru/olamedia/olacraft/world/data/ChunkData.java @@ -1,8 +1,8 @@ package ru.olamedia.olacraft.world.data; import java.io.Serializable; -import java.util.BitSet; +import ru.olamedia.math.OpenBitSet; import ru.olamedia.olacraft.world.chunk.Chunk; import ru.olamedia.olacraft.world.location.BlockLocation; import ru.olamedia.olacraft.world.location.ChunkLocation; @@ -12,58 +12,30 @@ public class ChunkData implements Serializable { public ChunkLocation location; public static transient int SIZE = 4096; // private boolean[] notEmpty = new boolean[SIZE]; - private BitSet emptyBlocks = new BitSet(4096); + public OpenBitSet emptyBlocks = new OpenBitSet(4096); public int notEmptyCount = 0; // public transient int[] type = new int[SIZE]; - // /public transient ChunkLightData light; public ChunkData() { - // light = new ChunkLightData(); } public void compact() { - if (notEmptyCount == 0) { + if (emptyBlocks.cardinality() == 0) { emptyBlocks = null; } } - public static int normalize(int v) { - int n = v; - if (n > 15) { - n = n % 16; - } - if (n < 0) { - n = 16 + n % 16 - 1; - // v = 15 - v; - } - // System.out.println("normalize(" + v + ") = " + n); - return n; - } - - public static int getId(int xInsideChunk, int yInsideChunk, int zInsideChunk) { - xInsideChunk = normalize(xInsideChunk); - yInsideChunk = normalize(yInsideChunk); - zInsideChunk = normalize(zInsideChunk); - int id = xInsideChunk * 16 * 16 + yInsideChunk * 16 + zInsideChunk; - if (id > SIZE) { - System.err.println("Exception while getID(" + xInsideChunk + "," + yInsideChunk + "," + zInsideChunk + ")"); - throw new ArrayIndexOutOfBoundsException(id); - } - return id; - } - public boolean isEmpty(BlockLocation blockLocation) { - if (notEmptyCount == 0) { + if (emptyBlocks == null) { return true; } - int id = getId(Chunk.in(blockLocation.x), Chunk.in(blockLocation.y), Chunk.in(blockLocation.z)); + int id = Chunk.in(blockLocation.x) * 16 * 16 + Chunk.in(blockLocation.y) * 16 + Chunk.in(blockLocation.z); return isEmpty(id); - // return !notEmpty[id]; } public boolean isEmpty(int id) { - if (notEmptyCount == 0) { + if (emptyBlocks == null) { return true; } return emptyBlocks.get(id); @@ -77,10 +49,25 @@ public class ChunkData implements Serializable { notEmptyCount--; } } - emptyBlocks.set(id, isEmpty); + if (isEmpty) { + emptyBlocks.set(id); + } else { + emptyBlocks.clear(id); + } } public boolean isEmpty() { - return notEmptyCount == 0; + return emptyBlocks == null || emptyBlocks.cardinality() == 0; + } + + public void setEmpty(int inChunkX, int inChunkY, int inChunkZ, boolean isEmpty) { + int id = inChunkX * 16 * 16 + inChunkY * 16 + inChunkZ; + setEmpty(id, isEmpty); } + + public void setEmpty(BlockLocation blockLocation, boolean isEmpty) { + int id = Chunk.in(blockLocation.x) * 16 * 16 + Chunk.in(blockLocation.y) * 16 + Chunk.in(blockLocation.z); + setEmpty(id, isEmpty); + } + } diff --git a/src/ru/olamedia/olacraft/world/data/HeightMap.java b/src/ru/olamedia/olacraft/world/data/HeightMap.java index b2c0a63..4d5d458 100644 --- a/src/ru/olamedia/olacraft/world/data/HeightMap.java +++ b/src/ru/olamedia/olacraft/world/data/HeightMap.java @@ -12,10 +12,14 @@ import java.io.Serializable; public class HeightMap implements Serializable { private static final long serialVersionUID = -6777972159522169977L; public byte[][] map; // -128..127 + public int width; + public int height; public HeightMap(){ } public HeightMap(int width, int height) { + this.width = width; + this.height = height; map = new byte[width][height]; } diff --git a/src/ru/olamedia/olacraft/world/data/RegionData.java b/src/ru/olamedia/olacraft/world/data/RegionData.java index fa292d2..f58a424 100644 --- a/src/ru/olamedia/olacraft/world/data/RegionData.java +++ b/src/ru/olamedia/olacraft/world/data/RegionData.java @@ -24,6 +24,10 @@ public class RegionData implements Serializable { public HeightMap heightMap = new HeightMap(256, 256); public SectorData[][] sectorData = new SectorData[16][16]; + public RegionData(){ + + } + public void writeTo(OutputStream stream) throws IOException { ObjectOutputStream out = new ObjectOutputStream(stream); out.writeObject(this); diff --git a/src/ru/olamedia/olacraft/world/data/SectorData.java b/src/ru/olamedia/olacraft/world/data/SectorData.java index 12a97cd..31526a7 100644 --- a/src/ru/olamedia/olacraft/world/data/SectorData.java +++ b/src/ru/olamedia/olacraft/world/data/SectorData.java @@ -12,10 +12,14 @@ import ru.olamedia.olacraft.world.location.SectorLocation; */ public class SectorData implements Serializable{ private static final long serialVersionUID = 5304471397211814748L; - public HeightMap heightMap; // locations of highest nonempty blocks - public ChunkData[] chunkData; // 256/16 = 16 + public HeightMap heightMap = new HeightMap(16, 16); // locations of highest nonempty blocks + public ChunkData[] chunkData = new ChunkData[16]; // 256/16 = 16 public SectorLocation location; + public SectorData(){ + + } + public static int yIndex(int y) { return (y + 128) / 16; // 1: (-128 + 128) / 16 = 0 @@ -26,8 +30,6 @@ public class SectorData implements Serializable{ } public static SectorData generate(){ SectorData data = new SectorData(); - data.heightMap = new HeightMap(16, 16); - data.chunkData = new ChunkData[16]; return data; } } diff --git a/src/ru/olamedia/olacraft/world/dataProvider/CachedChunkDataProvider.java b/src/ru/olamedia/olacraft/world/dataProvider/CachedChunkDataProvider.java index 23270a7..444cff6 100644 --- a/src/ru/olamedia/olacraft/world/dataProvider/CachedChunkDataProvider.java +++ b/src/ru/olamedia/olacraft/world/dataProvider/CachedChunkDataProvider.java @@ -27,29 +27,19 @@ public class CachedChunkDataProvider extends AbstractChunkDataProvider { @Override public boolean isRegionAvailable(RegionLocation regionLocation) { String key = regionLocation.toString();// regionLocation.x + "-" + - // regionLocation.z; if (regionMap.containsKey(key)) { return true; } - if (loading.contains(key)) { - // return false; - } return provider.isRegionAvailable(regionLocation); } @Override public void loadRegion(RegionLocation regionLocation) { String key = regionLocation.toString(); - //debug("loadRegion(" + regionLocation + ")"); + // debug("loadRegion(" + regionLocation + ")"); if (!regionMap.containsKey(key)) { - if (!loading.contains(key)) { - debug("load()"); - loading.add(key); - provider.loadRegion(regionLocation); - }else{ - //debug("loadRegion(" + regionLocation + ") already in loading"); - } - }else{ + provider.loadRegion(regionLocation); + } else { debug("error: loadRegion(" + regionLocation + ") already in regionMap"); } } @@ -62,7 +52,6 @@ public class CachedChunkDataProvider extends AbstractChunkDataProvider { } else { RegionData data = provider.getRegion(regionLocation); regionMap.put(key, data); - loading.remove(key); return data; } } diff --git a/src/ru/olamedia/olacraft/world/dataProvider/LocalChunkDataProvider.java b/src/ru/olamedia/olacraft/world/dataProvider/LocalChunkDataProvider.java index 514081f..887421f 100644 --- a/src/ru/olamedia/olacraft/world/dataProvider/LocalChunkDataProvider.java +++ b/src/ru/olamedia/olacraft/world/dataProvider/LocalChunkDataProvider.java @@ -9,10 +9,10 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; -import ru.olamedia.olacraft.world.data.ChunkData; import ru.olamedia.olacraft.world.data.RegionData; -import ru.olamedia.olacraft.world.generator.HeightMapGenerator; import ru.olamedia.olacraft.world.generator.RegionGenerator; import ru.olamedia.olacraft.world.location.RegionLocation; @@ -80,41 +80,23 @@ public class LocalChunkDataProvider extends AbstractChunkDataProvider { debug("loadRegion(" + regionLocation + ")"); } - private ChunkData createChunk(int chunkX, int chunkY, int chunkZ) { - debug("createChunk " + chunkX + " " + chunkY + " " + chunkZ); - ChunkData data = new ChunkData(); - try { - getSeed(); - } catch (IOException e) { - e.printStackTrace(); - } - HeightMapGenerator.minValue = 1; - HeightMapGenerator.maxValue = 64; - HeightMapGenerator.init(); - HeightMapGenerator.seed = seed[0]; - int[][] heightMap = HeightMapGenerator.getChunkHeightMap(chunkX, chunkZ); - for (int y = 0; y < 16; y++) { - for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) { - data.setEmpty(ChunkData.getId(x, y, z), (heightMap[x][z] < chunkY * 16 + y)); - } - } - } - return data; - } - + @SuppressWarnings("unused") @Override public RegionData getRegion(RegionLocation regionLocation) { String filename = path + File.separator + regionLocation.getFilename(); RegionData data = null; - // TODO READ/WRITE FILE + if (true) { + return generateRegion(regionLocation); + } File chunkFile = new File(filename); - if (chunkFile.exists()) { + if (false && chunkFile.exists()) { InputStream in; try { - in = new FileInputStream(chunkFile); + FileInputStream fIn = new FileInputStream(chunkFile); + in = new GZIPInputStream(fIn); data = RegionData.loadFrom(in); in.close(); + fIn.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { @@ -124,11 +106,14 @@ public class LocalChunkDataProvider extends AbstractChunkDataProvider { } } else { data = generateRegion(regionLocation); + OutputStream out; try { chunkFile.createNewFile(); - FileOutputStream out = new FileOutputStream(chunkFile); + FileOutputStream fOut = new FileOutputStream(chunkFile); + out = new GZIPOutputStream(fOut); data.writeTo(out); out.close(); + fOut.close(); } catch (IOException e) { e.printStackTrace(); } @@ -139,7 +124,6 @@ public class LocalChunkDataProvider extends AbstractChunkDataProvider { public RegionData generateRegion(RegionLocation regionLocation) { RegionData data = new RegionData(); data.location = regionLocation; - // TODO FILL HERE RegionGenerator generator = new RegionGenerator(); try { generator.setSeed(getSeed()); @@ -150,69 +134,4 @@ public class LocalChunkDataProvider extends AbstractChunkDataProvider { return data; } - public ChunkData get(int chunkX, int chunkY, int chunkZ) { - debug("get " + chunkX + " " + chunkY + " " + chunkZ); - ChunkData data = null; - String filename = path + File.separator + chunkX + "_" + chunkY + "_" + chunkZ + ".chunk"; - /* - * File chunkFile = new File(filename); - * if (chunkFile.exists()) { - * try { - * InputStream in = new FileInputStream(chunkFile); - * DataInputStream din = new DataInputStream(in); - * data = new ChunkData(); - * data.readFrom(din); - * din.close(); - * in.close(); - * } catch (FileNotFoundException e) { - * e.printStackTrace(); - * } catch (IOException e) { - * e.printStackTrace(); - * } - * } else { - */ - data = createChunk(chunkX, chunkY, chunkZ); - /* - * OutputStream out = null; - * ByteArrayOutputStream bout = null; - * DataOutputStream dout = null; - * try { - * chunkFile.createNewFile(); - * out = new FileOutputStream(chunkFile); - * // bout = new ByteArrayOutputStream(4096); - * dout = new DataOutputStream(out); - * data.writeTo(dout); - * // dout.flush(); - * // out.write(bout.toByteArray()); - * out.flush(); - * } catch (IOException e) { - * e.printStackTrace(); - * } finally { - * if (null != dout) { - * try { - * dout.close(); - * } catch (IOException e) { - * e.printStackTrace(); - * } - * } - * if (null != bout) { - * try { - * bout.close(); - * } catch (IOException e) { - * e.printStackTrace(); - * } - * } - * if (null != out) { - * try { - * out.close(); - * } catch (IOException e) { - * e.printStackTrace(); - * } - * } - * } - * } - */ - return data; - } - } diff --git a/src/ru/olamedia/olacraft/world/dataProvider/RemoteChunkDataProvider.java b/src/ru/olamedia/olacraft/world/dataProvider/RemoteChunkDataProvider.java index 8284ff9..cd48071 100644 --- a/src/ru/olamedia/olacraft/world/dataProvider/RemoteChunkDataProvider.java +++ b/src/ru/olamedia/olacraft/world/dataProvider/RemoteChunkDataProvider.java @@ -36,8 +36,8 @@ public class RemoteChunkDataProvider extends AbstractChunkDataProvider implement @Override public void loadRegion(RegionLocation regionLocation) { String key = regionLocation.toString(); - debug("loadRegion(" + key + ")"); if (!loading.contains(key)) { + debug("loadRegion(" + key + ")"); loading.add(key); client.send(new GetRegionPacket(regionLocation)); debug("sent packet: GetRegionPacket"); @@ -64,8 +64,9 @@ public class RemoteChunkDataProvider extends AbstractChunkDataProvider implement @Override public void onPacket(Connection connection, IPacket p) { if (p instanceof RegionDataPacket) { - debug("received packet [conn " + connection.getID() + "]: ChunkDataPacket"); + debug("received packet [conn " + connection.getID() + "]: RegionDataPacket"); RegionData data = ((RegionDataPacket) p).data; + System.out.println(data.sectorData[0][0].chunkData[15].isEmpty(0) + ""); String key = data.location.toString(); map.put(key, data); loading.remove(key); diff --git a/src/ru/olamedia/olacraft/world/generator/HeightMapGenerator.java b/src/ru/olamedia/olacraft/world/generator/HeightMapGenerator.java index c3e32b5..649961f 100644 --- a/src/ru/olamedia/olacraft/world/generator/HeightMapGenerator.java +++ b/src/ru/olamedia/olacraft/world/generator/HeightMapGenerator.java @@ -77,6 +77,7 @@ public class HeightMapGenerator { maxTerrain = new Max(plains, turbulence); finalTerrain = new ScaleBias(maxTerrain); finalTerrain.setBias(2); + finalTerrain.setScale(0.4); setSeed(seed); } catch (ExceptionInvalidParam e) { e.printStackTrace(); @@ -117,7 +118,7 @@ public class HeightMapGenerator { for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { // System.out.print(((float) heights[x][z]) + ";"); - ints[x][z] = (int) (minValue + (maxValue - minValue) * (heights[x][z] + 1) / 2); + ints[x][z] = (int) (50 + minValue + (maxValue - minValue) * (heights[x][z] + 1) / 2); } } // System.out.println(""); @@ -137,15 +138,17 @@ public class HeightMapGenerator { builder.setSourceModule(finalTerrain); builder.setDestNoiseMap(heightMap); builder.setDestSize(256, 256); - float bx = location.x; - float bz = location.z; - builder.setBounds(bx, bx + 1, bz, bz + 1); + float bx = location.getBlockLocation().x; + float bz = location.getBlockLocation().z; + float cx = location.getChunkLocation().x; + float cz = location.getChunkLocation().z; + builder.setBounds(cx, cx + 16, cz, cz + 16); builder.build(); double[][] heights = heightMap.getNoiseMap(); for (int x = 0; x < 256; x++) { for (int z = 0; z < 256; z++) { - map.setHeight(x, z, 0); - //(int) (minValue + (maxValue - minValue) * (heights[x][z] + 1) / 2) + // map.setHeight(x, z, 0); + map.setHeight(x, z, (int) (minValue + ((1 + heights[x][z]) / 2) * (maxValue - minValue))); } } return map; diff --git a/src/ru/olamedia/olacraft/world/generator/RegionGenerator.java b/src/ru/olamedia/olacraft/world/generator/RegionGenerator.java index 9657e32..05fc067 100644 --- a/src/ru/olamedia/olacraft/world/generator/RegionGenerator.java +++ b/src/ru/olamedia/olacraft/world/generator/RegionGenerator.java @@ -21,42 +21,54 @@ public class RegionGenerator { public void generate(RegionData data) { HeightMapGenerator.minValue = -5; - HeightMapGenerator.maxValue = 100; + HeightMapGenerator.maxValue = 60; HeightMapGenerator.init(); HeightMapGenerator.seed = seed[0]; - BlockLocation offset = data.location.getBlockLocation(); + // BlockLocation blockOffset = data.location.getBlockLocation(); + SectorLocation sectorOffset = data.location.getSectorLocation(); // int[][] heightMap = // HeightMapGenerator.getHeightMap(data.location.getBlockLocation().x, // data.location.getBlockLocation().z, 256, 256); debug(data.location.toString()); data.heightMap = HeightMapGenerator.getHeightMap(data.location); - //debug(data.heightMap.toString()); + // debug(data.heightMap.toString()); data.sectorData = new SectorData[16][16]; for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { // CREATE SECTOR SectorData sector = new SectorData(); - sector.location = new SectorLocation(offset.x + x * 16, offset.z + z * 16); + sector.location = new SectorLocation(sectorOffset.x + x, sectorOffset.z + z); sector.heightMap = new HeightMap(16, 16); sector.chunkData = new ChunkData[16]; for (int y = 0; y < 16; y++) { // CREATE CHUNK ChunkData chunk = new ChunkData(); chunk.location = new ChunkLocation(sector.location.x, y, sector.location.z); - int chunkOffsetY = y * 16 - 128; + BlockLocation chunkOffset = chunk.location.getBlockLocation(); for (int inChunkX = 0; inChunkX < 16; inChunkX++) { for (int inChunkZ = 0; inChunkZ < 16; inChunkZ++) { int height = data.heightMap.getHeight(x * 16 + inChunkX, z * 16 + inChunkZ); - //System.out.println("height: " + height); + // System.out.println("height: " + height); sector.heightMap.setHeight(inChunkX, inChunkZ, height); + BlockLocation blockOffset = new BlockLocation(); + blockOffset.x = chunkOffset.x + inChunkX; + blockOffset.z = chunkOffset.z + inChunkZ; for (int inChunkY = 0; inChunkY < 16; inChunkY++) { - //height = sector.heightMap.getHeight(inChunkX, inChunkZ); - int id = ChunkData.getId(inChunkX, inChunkY, inChunkZ); - if (chunkOffsetY + inChunkY > height) { - chunk.setEmpty(id, true); + blockOffset.y = chunkOffset.y + inChunkY; + // height = sector.heightMap.getHeight(inChunkX, + // inChunkZ); + if (blockOffset.y > height) { + // System.out.println("--- height: " + + // height + " block:" + blockOffset); + chunk.setEmpty(blockOffset, true); } else { - //System.out.println("not empty, height: " + height); - chunk.setEmpty(id, false); + if (blockOffset.y > 0) { + // System.out.println("+++ height: " + + // height + " block:" + blockOffset); + // System.out.println("not empty, height: " + // + height); + } + chunk.setEmpty(blockOffset, false); } } } diff --git a/src/ru/olamedia/olacraft/world/location/ChunkLocation.java b/src/ru/olamedia/olacraft/world/location/ChunkLocation.java index 57acc52..a772c6d 100644 --- a/src/ru/olamedia/olacraft/world/location/ChunkLocation.java +++ b/src/ru/olamedia/olacraft/world/location/ChunkLocation.java @@ -32,9 +32,14 @@ public class ChunkLocation implements Serializable { public String toString() { return "chunkLocation[" + x + "," + y + "," + z + "]"; } + /* * public BlockSlice getSlice(){ * * } */ + + public BlockLocation getBlockLocation() { + return new BlockLocation(Chunk.rev(x), Chunk.rev(y) - 128, Chunk.rev(z)); + } } diff --git a/src/ru/olamedia/olacraft/world/location/RegionLocation.java b/src/ru/olamedia/olacraft/world/location/RegionLocation.java index 59a57ec..a1100c0 100644 --- a/src/ru/olamedia/olacraft/world/location/RegionLocation.java +++ b/src/ru/olamedia/olacraft/world/location/RegionLocation.java @@ -2,6 +2,8 @@ package ru.olamedia.olacraft.world.location; import java.io.Serializable; +import ru.olamedia.olacraft.world.chunk.Chunk; + public class RegionLocation implements Serializable { private static final long serialVersionUID = -141619138379029773L; public int x; @@ -23,7 +25,15 @@ public class RegionLocation implements Serializable { return "" + x + "_" + z + ".region"; } + public SectorLocation getSectorLocation() { + return new SectorLocation(Chunk.rev(x), Chunk.rev(z)); + } + + public ChunkLocation getChunkLocation() { + return new ChunkLocation(Chunk.rev(x), 0, Chunk.rev(z)); + } + public BlockLocation getBlockLocation() { - return new BlockLocation(x * 256, 0, z * 256); + return new BlockLocation(Chunk.rev(Chunk.rev(x)), 0, Chunk.rev(Chunk.rev(z))); } } diff --git a/src/ru/olamedia/olacraft/world/location/SectorLocation.java b/src/ru/olamedia/olacraft/world/location/SectorLocation.java index 59390b8..0c3af25 100644 --- a/src/ru/olamedia/olacraft/world/location/SectorLocation.java +++ b/src/ru/olamedia/olacraft/world/location/SectorLocation.java @@ -23,6 +23,14 @@ public class SectorLocation implements Serializable { return new RegionLocation(Chunk.v(x), Chunk.v(z)); } + public ChunkLocation getChunkLocation() { + return new ChunkLocation(Chunk.rev(x), 0, Chunk.rev(z)); + } + + public BlockLocation getBlockLocation() { + return new BlockLocation(Chunk.rev(Chunk.rev(x)), 0, Chunk.rev(Chunk.rev(z))); + } + public String toString() { return "sectorLocation[" + x + "," + z + "]"; } diff --git a/src/ru/olamedia/olacraft/world/provider/WorldProvider.java b/src/ru/olamedia/olacraft/world/provider/WorldProvider.java index 8dacce9..b7984bc 100644 --- a/src/ru/olamedia/olacraft/world/provider/WorldProvider.java +++ b/src/ru/olamedia/olacraft/world/provider/WorldProvider.java @@ -45,9 +45,7 @@ public class WorldProvider { spawnLocation.y = y; System.out.print(y + ". "); ChunkData chunk = dataProvider.getChunk(spawnLocation.getChunkLocation()); - boolean notEmpty = !chunk.isEmpty(ChunkData.getId(Chunk.in(spawnLocation.x), Chunk.in(spawnLocation.y), - Chunk.in(spawnLocation.z))); - if (notEmpty) { + if (!chunk.isEmpty(spawnLocation)) { // found l.y = y + 1; System.out.println("found: " + y); @@ -65,6 +63,9 @@ public class WorldProvider { } public boolean renderTop(int x, int y, int z) { + // System.out.println("Check render top " + y + "[" + x + " " + y + " " + // + z + "]" + !isEmptyBlock(x, y, z) + // + " && " + isEmptyBlock(x, y + 1, z)); return (!isEmptyBlock(x, y, z)) && (isEmptyBlock(x, y + 1, z)); } @@ -91,9 +92,14 @@ public class WorldProvider { ChunkData data = dataProvider.getChunk(blockLocation.getChunkLocation()); if (null != data) { return data.isEmpty(blockLocation); + } else { + // System.out.println("chunk null " + x + " " + y + " " + z); } + } else { + // System.out.println("chunk not available " + x + " " + y + " " + + // z); } - return false; + return true; } public void requestChunk(int chunkX, int chunkY, int chunkZ) { |