diff options
author | olamedia <[email protected]> | 2012-09-28 18:46:42 +0600 |
---|---|---|
committer | olamedia <[email protected]> | 2012-09-28 18:46:42 +0600 |
commit | b4192c7a88bad111bebbd42d391d6e729c8617d6 (patch) | |
tree | b05a586dbc60c5427fcc7f3fe01cf2fdcb970272 /src/ru/olamedia |
initial
Diffstat (limited to 'src/ru/olamedia')
178 files changed, 9108 insertions, 0 deletions
diff --git a/src/ru/olamedia/Options.java b/src/ru/olamedia/Options.java new file mode 100644 index 0000000..e1c4d41 --- /dev/null +++ b/src/ru/olamedia/Options.java @@ -0,0 +1,5 @@ +package ru.olamedia; + +public class Options { + public static int renderDistance = 256; +} diff --git a/src/ru/olamedia/asset/Asset.java b/src/ru/olamedia/asset/Asset.java new file mode 100644 index 0000000..a420c10 --- /dev/null +++ b/src/ru/olamedia/asset/Asset.java @@ -0,0 +1,29 @@ +package ru.olamedia.asset; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +public class Asset { + protected URL url; + + public boolean inJar() { + return url.toString().startsWith("file:jar:"); + } + + public Asset(URL url) { + this.url = url; + } + + public URL getURL() { + return url; + } + + public InputStream getInputStream() throws IOException { + return url.openStream(); + } + + public String getFile() { + return url.getFile(); + } +} diff --git a/src/ru/olamedia/asset/AssetManager.java b/src/ru/olamedia/asset/AssetManager.java new file mode 100644 index 0000000..d1de11b --- /dev/null +++ b/src/ru/olamedia/asset/AssetManager.java @@ -0,0 +1,28 @@ +package ru.olamedia.asset; + +import java.net.URL; + +public class AssetManager { + + public static URL getBaseURL() { + return AssetManager.class.getResource(AssetManager.class.getSimpleName() + ".class"); + } + + public boolean inJar() { + // file:jar:c:/path/to/jar/somejar.jar! + return getBaseURL().toString().startsWith("file:jar:"); + // return getBaseURL().toString().indexOf(".jar!") > 0; + } + + public static URL getURL(String path) throws AssetNotFoundException { + URL url = AssetManager.class.getClassLoader().getResource(path); + if (null == url) { + throw new AssetNotFoundException(path); + } + return url; + } + + public static Asset getAsset(String path) throws AssetNotFoundException { + return new Asset(getURL(path)); + } +} diff --git a/src/ru/olamedia/asset/AssetNotFoundException.java b/src/ru/olamedia/asset/AssetNotFoundException.java new file mode 100644 index 0000000..29afdf0 --- /dev/null +++ b/src/ru/olamedia/asset/AssetNotFoundException.java @@ -0,0 +1,22 @@ +package ru.olamedia.asset; + +public class AssetNotFoundException extends Exception { + + public AssetNotFoundException() { + super(); + } + + public AssetNotFoundException(String message, Throwable cause) { + super(message, cause); + } + + public AssetNotFoundException(String message) { + super(message); + } + + public AssetNotFoundException(Throwable cause) { + super(cause); + } + + private static final long serialVersionUID = 2197816222986044998L; +} diff --git a/src/ru/olamedia/asset/package-info.java b/src/ru/olamedia/asset/package-info.java new file mode 100644 index 0000000..d2ed4df --- /dev/null +++ b/src/ru/olamedia/asset/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.asset;
\ No newline at end of file diff --git a/src/ru/olamedia/camera/CameraProjectionMatrix.java b/src/ru/olamedia/camera/CameraProjectionMatrix.java new file mode 100644 index 0000000..ec1c390 --- /dev/null +++ b/src/ru/olamedia/camera/CameraProjectionMatrix.java @@ -0,0 +1,77 @@ +package ru.olamedia.camera; + +import org.openmali.FastMath; +import org.openmali.vecmath2.Matrix4f; + +public class CameraProjectionMatrix extends Matrix4f { + + /** + * Creates a mesa-style perspective projection transform, that mimics a + * standard, camera-based, view-model. + * + * @param fovy + * specifies the field of view in the y direction, in radians + * @param aspect + * specifies the aspect ratio and thus the field of view in the x + * direction. The aspect ratio is the ratio of x to y, or width + * to height. + * @param zNear + * the distance to the frustum's near clipping plane. This value + * must be positive, (the value -zNear is the location of the + * near clip plane). + * @param zFar + * the distance to the frustum's far clipping plane. + */ + public final void perspectiveMesa(float fovy, float aspect, float zNear, + float zFar) { + final float ymax = zNear * FastMath.tan(fovy); + final float ymin = -ymax; + final float xmin = ymin * aspect; + final float xmax = ymax * aspect; + + // don't call glFrustum() because of error semantics (covglu) + frustumMesa(xmin, xmax, ymin, ymax, zNear, zFar); + } + + /** + * Creates a masa-style perspective projection transform, that mimics a + * standard, camera-based, view-model. The frustum function-call establishes + * a view-model with the eye at the apex of a symmetric view frustum. The + * arguments define the frustum and its associated perspective projection: + * (left, bottom, -near) and (right, top, -near) specify the point on the + * near clipping plane that maps onto the lower-left and upper-right corners + * of the window respectively, assuming the eye is located at (0, 0, 0). + * + * @param left + * the vertical line on the left edge of the near clipping plane + * mapped to the left edge of the graphics window + * @param right + * the vertical line on the right edge of the near clipping plane + * mapped to the right edge of the graphics window + * @param bottom + * the horizontal line on the bottom edge of the near clipping + * plane mapped to the bottom edge of the graphics window + * @param top + * the horizontal line on the top edge of the near + * @param zNear + * the distance to the frustum's near clipping plane. This value + * must be positive, (the value -near is the location of the near + * clip plane). + * @param zFar + * the distance to the frustum's far clipping plane. This value + * must be positive, and must be greater than near. + */ + public final void frustumMesa(float left, float right, float bottom, + float top, float zNear, float zFar) { + final float x = (2.0f * zNear) / (right - left); + final float y = (2.0f * zNear) / (top - bottom); + final float a = (right + left) / (right - left); + final float b = (top + bottom) / (top - bottom); + final float c = -(zFar + zNear) / (zFar - zNear); + final float d = -(2.0f * zFar * zNear) / (zFar - zNear); + + this.set(x, 0f, 0f, 0f, 0f, y, 0f, 0f, a, b, c, -1f, 0f, 0f, d, 0f); + + } + +} diff --git a/src/ru/olamedia/camera/Cameraman.java b/src/ru/olamedia/camera/Cameraman.java new file mode 100644 index 0000000..7dbbcc0 --- /dev/null +++ b/src/ru/olamedia/camera/Cameraman.java @@ -0,0 +1,21 @@ +package ru.olamedia.camera; + +/** + * Cameraman. + * + * @desc Primary purpose is providing eyes level: getCameraY() + * + * @author olamedia + * + */ +public interface Cameraman { + public float getCameraX(); + + public float getCameraY(); + + public float getCameraZ(); + + public void update(float delta); + + public void captureControls(); +} diff --git a/src/ru/olamedia/camera/MatrixCamera.java b/src/ru/olamedia/camera/MatrixCamera.java new file mode 100644 index 0000000..de37fc8 --- /dev/null +++ b/src/ru/olamedia/camera/MatrixCamera.java @@ -0,0 +1,545 @@ +package ru.olamedia.camera; + +import javax.media.opengl.GL2; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.glu.GLU; +import javax.vecmath.Vector3f; +import javax.vecmath.Matrix4f; + +import org.openmali.FastMath; + +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; + +public class MatrixCamera { + protected float fov = 90f; + protected float aspect = 1f; + protected float zNear = 0.1f; + protected float zFar = 1000f; + private boolean isPitchLocked = true; + private float minPitch = -80f; + private float maxPitch = 80f; + public Frustum frustum = new Frustum(); + + private Vector3f position = new Vector3f(); + private float yaw = 0; // around y + private float pitch = 0; + private float roll = 0; + public Matrix4f projectionMatrix = new Matrix4f(); + private Matrix4f translationMatrix = new Matrix4f(); + private Matrix4f xRotationMatrix = new Matrix4f(); + private Matrix4f yRotationMatrix = new Matrix4f(); + private Matrix4f zRotationMatrix = new Matrix4f(); + private Matrix4f rotationMatrix = new Matrix4f(); + public Matrix4f viewMatrix = new Matrix4f(); + public Matrix4f worldMatrix = new Matrix4f(); + + private Vector3f look = new Vector3f(); + private Vector3f right = new Vector3f(); + private Vector3f up = new Vector3f(); + public boolean isFrustumVisible = false; + + @SuppressWarnings("unused") + private org.openmali.vecmath2.Matrix4f matrixToOpenMali(Matrix4f m) { + return new org.openmali.vecmath2.Matrix4f(matrixToTransposeArray(m)); + } + + public void pack() { + if (isAttachedToCameraman) { + position.x = cameraman.getCameraX(); + position.y = cameraman.getCameraY(); + position.z = cameraman.getCameraZ(); + } + + worldMatrix.setIdentity(); + packProjectionMatrix(); + // projectionMatrix.transpose(); + // worldMatrix.mul(projectionMatrix); + translationMatrix.setIdentity(); + translationMatrix.m03 = position.x; + translationMatrix.m13 = position.y - 0.5f; // FIXME y is looking greater + // than it should + translationMatrix.m23 = position.z; + packRotation(); + packView(); + // after view matrix created, retrieve vectors: + viewMatrix.invert(); + viewMatrix.transpose(); + packLookVector(); + packRightVector(); + packUpVector(); + packFrustum(); + // worldMatrix.mul(projectionMatrix, viewMatrix); + // worldMatrix.transpose(); + // // oglViewMatrix.set(viewMatrix); + // // oglViewMatrix.transpose(); + // frustum = FrustumUtil.extractFrustum(worldMatrix); + // Matrix4f vm = new Matrix4f(viewMatrix); + // vm.invert(); + // frustum.compute(matrixToOpenMali(projectionMatrix), + // matrixToOpenMali(vm)); + // ...... + // finally + // ...... + } + + private ru.olamedia.math.Vector3f nearc; + + private void packFrustum() { + float nearD = zNear + (isFrustumVisible ? 0.2f : 0);// zNear; + float farD = zFar - (isFrustumVisible ? 1f : 0);// zFar; + ru.olamedia.math.Vector3f eye = new ru.olamedia.math.Vector3f(position.getX(), position.getY(), position.getZ()); + ru.olamedia.math.Vector3f eyef = eye;// .translate(look, 1f); + nearc = eyef.translate(look, nearD); + ru.olamedia.math.Vector3f farc = eyef.translate(look, farD); + final float tang = FastMath.tan(FastMath.toRad(fov) / 2.0f); + float nh = nearD * tang * (isFrustumVisible ? 0.3f : 1);// zNear * tang; + float nw = nh * aspect * aspect; + float fh = farD * tang * (isFrustumVisible ? 0.5f : 1);// zNear * tang; + float fw = fh * aspect * aspect; + ru.olamedia.math.Vector3f nrb = nearc.translate(right, -nw / 2).translate(up, -nh / 2); + ru.olamedia.math.Vector3f nlb = nearc.translate(right, nw / 2).translate(up, -nh / 2); + @SuppressWarnings("unused") + ru.olamedia.math.Vector3f nrt = nearc.translate(right, -nw / 2).translate(up, nh / 2); + ru.olamedia.math.Vector3f nlt = nearc.translate(right, nw / 2).translate(up, nh / 2); + ru.olamedia.math.Vector3f frb = farc.translate(right, -fw / 2).translate(up, -fh / 2); + ru.olamedia.math.Vector3f flb = farc.translate(right, fw / 2).translate(up, -fh / 2); + ru.olamedia.math.Vector3f frt = farc.translate(right, -fw / 2).translate(up, fh / 2); + ru.olamedia.math.Vector3f flt = farc.translate(right, fw / 2).translate(up, fh / 2); + + frustum.leftPlane.set3Points(nlb, flb, flt); + frustum.leftPlane.n.negate(); + frustum.rightPlane.set3Points(nrb, frt, frb); + // frustum.rightPlane.n.negate(); + frustum.topPlane.set3Points(nlb, frb, flb);// nlt, frt, flt); + // frustum.topPlane.n.negate(); + frustum.bottomPlane.set3Points(frt, nlt, flt); + // frustum.bottomPlane.n.negate(); + frustum.nearPlane.set3Points(nlb, nlt, nrb); + frustum.farPlane.set3Points(flt, flb, frb); + } + + private float[] matrixToTransposeArray(Matrix4f m) { + return new float[] { + // + m.m00, m.m01, m.m02, m.m03,// + m.m10, m.m11, m.m12, m.m13,// + m.m20, m.m21, m.m22, m.m23,// + m.m30, m.m31, m.m32, m.m33,// + }; + } + + private float[] matrixToArray(Matrix4f m) { + return new float[] { + // + m.m00, m.m10, m.m20, m.m30,// + m.m01, m.m11, m.m21, m.m31,// + m.m02, m.m12, m.m22, m.m32,// + m.m03, m.m13, m.m23, m.m33,// + }; + } + + private GLU glu; + + public void setUp(GLAutoDrawable drawable) { + GL2 gl = drawable.getGL().getGL2(); + updateKeyboard(); + updateMouse(); + if (glu == null) { + glu = new GLU(); + } + // gl.glMatrixMode(GL2.GL_PROJECTION); + // gl.glLoadIdentity(); + // glu.gluPerspective(100f, aspect, 0.2, 1000); + 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); + + VectorRenderer.render(nearc, frustum.leftPlane.n, drawable); + } + + private void loadViewMatrix(GLAutoDrawable drawable) { + GL2 gl = drawable.getGL().getGL2(); + gl.glMatrixMode(GL2.GL_MODELVIEW); + gl.glLoadTransposeMatrixf(matrixToArray(viewMatrix), 0); + } + + private void loadProjectionMatrix(GLAutoDrawable drawable) { + GL2 gl = drawable.getGL().getGL2(); + gl.glMatrixMode(GL2.GL_PROJECTION); + gl.glLoadTransposeMatrixf(matrixToArray(projectionMatrix), 0); + } + + private void packProjectionMatrix() { + projectionMatrix.setZero(); + final float tang = FastMath.tan(FastMath.toRad(fov) / 2.0f); + final float size = zNear * tang; + float left = -size, right = size, bottom = -size / aspect, top = size / aspect; + // First Column + projectionMatrix.m00 = 2 * zNear / (right - left); + // Second Column + projectionMatrix.m11 = 2 * zNear / (top - bottom); + // Third Column + projectionMatrix.m20 = (right + left) / (right - left); + projectionMatrix.m21 = (top + bottom) / (top - bottom); + projectionMatrix.m22 = -(zFar + zNear) / (zFar - zNear); + projectionMatrix.m23 = -1; + // Fourth Column + projectionMatrix.m32 = -(2 * zFar * zNear) / (zFar - zNear); + } + + private void packRotation() { + xRotationMatrix.rotX(toRad(pitch)); + yRotationMatrix.rotY(toRad(yaw)); + zRotationMatrix.rotZ(toRad(roll)); + + rotationMatrix.setIdentity(); + rotationMatrix.mul(zRotationMatrix); + rotationMatrix.mul(yRotationMatrix); + rotationMatrix.mul(xRotationMatrix); + } + + private void translatePoint(Vector3f point, Vector3f direction, float delta) { + point.x += direction.x * delta; + point.y += direction.y * delta; + point.z += direction.z * delta; + } + + private void translate(Vector3f direction, float delta) { + translatePoint(position, direction, delta); + } + + private void translate(float dx, float dy, float dz) { + translate(right, dx); + translate(up, dy); + translate(look, -dz); + } + + private void packView() { + viewMatrix.setIdentity(); + viewMatrix.mul(translationMatrix); + viewMatrix.mul(rotationMatrix); + + } + + private void packUpVector() { + up.set(viewMatrix.m01, viewMatrix.m11, viewMatrix.m21); + } + + private void packRightVector() { + right.set(viewMatrix.m00, viewMatrix.m10, viewMatrix.m20); + } + + private void packLookVector() { + look.set(viewMatrix.m02, viewMatrix.m12, viewMatrix.m22); + } + + public MatrixCamera() { + right = new Vector3f(1, 0, 0); + up = new Vector3f(0, 1, 0); + look = new Vector3f(0, 0, 1); + isPitchLocked = true; + pack(); + } + + public void captureControls() { + Keyboard.setName("flyForward", KeyEvent.VK_W); + Keyboard.setName("flyBack", KeyEvent.VK_S); + Keyboard.setName("strafeLeft", KeyEvent.VK_A); + Keyboard.setName("strafeRight", KeyEvent.VK_D); + Keyboard.setName("flyUp", KeyEvent.VK_SPACE); + Keyboard.setName("flyDown", KeyEvent.VK_SHIFT); + } + + public void mouseMoved(float dx, float dy) { + yaw += -dx; + pitch += -dy; + yaw = yaw % 360; + pitch = pitch % 360; + } + + public void updateMouse() { + if (isPitchLocked) { + if (pitch < minPitch) { + pitch = minPitch; + } else if (pitch > maxPitch) { + pitch = maxPitch; + } + } + pack(); + } + + public void lockPitch(float min, float max) { + this.minPitch = min; + this.maxPitch = max; + isPitchLocked = true; + } + + public void unlockPitch() { + isPitchLocked = false; + } + + public void updateKeyboard() { + if (isAttachedToCameraman) { + this.cameraman.update(Game.instance.getDelta()); + return; + } + // --- Keyboard + int left = Keyboard.isKeyDown("strafeLeft") ? 1 : 0; + int right = Keyboard.isKeyDown("strafeRight") ? 1 : 0; + int up = Keyboard.isKeyDown("flyForward") ? 1 : 0; + int down = Keyboard.isKeyDown("flyBack") ? 1 : 0; + int flyUp = Keyboard.isKeyDown("flyUp") ? 1 : 0; + int flyDown = Keyboard.isKeyDown("flyDown") ? 1 : 0; + float distance = 4f * 4.5f * Game.instance.getDelta(); // runspeed, m/s + if (up + down + right + left + flyDown + flyUp > 0) { + translate(// + right * distance - left * distance,// + (isAttachedToCameraman ? 0 : flyUp * distance - flyDown * distance),// + up * distance - down * distance// + ); + pack(); + // System.out.println("Moving... " + position.getX() + " " + // + position.getY() + " " + position.getZ()); + } + } + + protected Cameraman cameraman = null; + protected boolean isAttachedToCameraman = false; + protected float distanceFromCameraman = 0; // third-person view / 0 for + protected boolean lookToCameraman = false; // back/front third-person view + + /** + * @return the fov + */ + public float getFov() { + return fov; + } + + /** + * @param fov + * the fov to set + */ + public void setFov(float fov) { + this.fov = fov; + } + + /** + * @return the aspect + */ + public float getAspect() { + return aspect; + } + + /** + * @param aspect + * the aspect to set + */ + public void setAspect(float aspect) { + this.aspect = aspect; + } + + /** + * @return the zNear + */ + public float getzNear() { + return zNear; + } + + /** + * @param zNear + * the zNear to set + */ + public void setzNear(float zNear) { + this.zNear = zNear; + } + + /** + * @return the zFar + */ + public float getzFar() { + return zFar; + } + + /** + * @param zFar + * the zFar to set + */ + public void setzFar(float zFar) { + this.zFar = zFar; + } + + /** + * @return the yaw + */ + public float getYaw() { + return yaw; + } + + /** + * @param yaw + * the yaw to set + */ + public void setYaw(float yaw) { + this.yaw = yaw; + } + + /** + * @return the pitch + */ + public float getPitch() { + return pitch; + } + + /** + * @param pitch + * the pitch to set + */ + public void setPitch(float pitch) { + this.pitch = pitch; + } + + /** + * @return the cameraman + */ + public Cameraman getCameraman() { + return cameraman; + } + + /** + * @param cameraman + * the cameraman to set + */ + public void setCameraman(Cameraman cameraman) { + this.cameraman = cameraman; + } + + /** + * @return the isAttachedToCameraman + */ + public boolean isAttachedToCameraman() { + return isAttachedToCameraman; + } + + /** + * @param isAttachedToCameraman + * the isAttachedToCameraman to set + */ + public void setAttachedToCameraman(boolean isAttachedToCameraman) { + this.isAttachedToCameraman = isAttachedToCameraman; + } + + /** + * @return the distanceFromCameraman + */ + public float getDistanceFromCameraman() { + return distanceFromCameraman; + } + + /** + * @param distanceFromCameraman + * the distanceFromCameraman to set + */ + public void setDistanceFromCameraman(float distanceFromCameraman) { + this.distanceFromCameraman = distanceFromCameraman; + } + + /** + * @return the lookToCameraman + */ + public boolean isLookToCameraman() { + return lookToCameraman; + } + + /** + * @param lookToCameraman + * the lookToCameraman to set + */ + public void setLookToCameraman(boolean lookToCameraman) { + this.lookToCameraman = lookToCameraman; + } + + public void setX(float x) { + position.x = x; + } + + public void setY(float y) { + position.y = y; + } + + public void setZ(float z) { + position.z = z; + } + + public float getX() { + return position.x; + } + + public float getY() { + return position.y; + } + + public float getZ() { + return position.z; + } + + public float[] getViewMatrixArray() { + return matrixToArray(viewMatrix); + } + + public float[] getProjectionMatrixArray() { + return matrixToArray(viewMatrix); + } + + public float getRoll() { + return roll; + } + + public void attachTo(Cameraman player) { + this.cameraman = player; + this.isAttachedToCameraman = true; + this.cameraman.captureControls(); + } + + public void detach() { + this.isAttachedToCameraman = false; + this.captureControls(); + } + + /** + * @return the look + */ + public Vector3f getLook() { + return look; + } + + /** + * @return the right + */ + public Vector3f getRight() { + return right; + } + + /** + * @return the up + */ + public Vector3f getUp() { + return up; + } + +} diff --git a/src/ru/olamedia/camera/package-info.java b/src/ru/olamedia/camera/package-info.java new file mode 100644 index 0000000..7a19b7f --- /dev/null +++ b/src/ru/olamedia/camera/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.camera;
\ No newline at end of file diff --git a/src/ru/olamedia/controls/package-info.java b/src/ru/olamedia/controls/package-info.java new file mode 100644 index 0000000..09ce499 --- /dev/null +++ b/src/ru/olamedia/controls/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.controls;
\ No newline at end of file diff --git a/src/ru/olamedia/debug/SystemInfo.java b/src/ru/olamedia/debug/SystemInfo.java new file mode 100644 index 0000000..30060a5 --- /dev/null +++ b/src/ru/olamedia/debug/SystemInfo.java @@ -0,0 +1,24 @@ +package ru.olamedia.debug; + +public class SystemInfo { + public static void dump() { + int cpu = Runtime.getRuntime().availableProcessors(); + long maxMemory = Runtime.getRuntime().maxMemory(); + long totalMemory = Runtime.getRuntime().totalMemory(); + long freeMemory = Runtime.getRuntime().freeMemory(); + // String country = System.getProperty("user.country"); + String username = System.getProperty("user.name"); + String os = System.getProperty("os.name"); + String osver = System.getProperty("os.version"); + String arch = System.getProperty("os.arch"); + System.out.println("Hello, " + username + " :)"); + System.out.println("" + os + " " + arch + " " + osver); + System.out + .println("Total CPU: " + cpu + " Memory free/total/max: " + + ((int) Math.floor(freeMemory / (1024 * 1024))) + "/" + + ((int) Math.floor(totalMemory / (1024 * 1024))) + "/" + + ((int) Math.floor(maxMemory / (1024 * 1024)))); + System.out.println(System.getProperty("java.vendor") + " " + System.getProperty("java.version")); + System.out.println(System.getProperty("java.runtime.name") + " " + System.getProperty("java.runtime.version")); + } +} diff --git a/src/ru/olamedia/debug/package-info.java b/src/ru/olamedia/debug/package-info.java new file mode 100644 index 0000000..fbf0e84 --- /dev/null +++ b/src/ru/olamedia/debug/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.debug;
\ No newline at end of file diff --git a/src/ru/olamedia/game/ClientGame.java b/src/ru/olamedia/game/ClientGame.java new file mode 100644 index 0000000..1f0eeae --- /dev/null +++ b/src/ru/olamedia/game/ClientGame.java @@ -0,0 +1,13 @@ +package ru.olamedia.game; + +public class ClientGame extends Game { + GameManager manager; + public ClientGame(GameManager manager) { + this.manager = manager; + } + public void pause(){ + // open in-game menu + super.pause(); + manager.start(); + } +} diff --git a/src/ru/olamedia/game/DynamicJList.java b/src/ru/olamedia/game/DynamicJList.java new file mode 100644 index 0000000..f944ba3 --- /dev/null +++ b/src/ru/olamedia/game/DynamicJList.java @@ -0,0 +1,16 @@ +package ru.olamedia.game; + +import javax.swing.DefaultListModel; +import javax.swing.JList; + +public class DynamicJList extends JList { + private static final long serialVersionUID = 8188447632893130182L; + + public DynamicJList() { + super(new DefaultListModel()); + } + + public DefaultListModel getContents() { + return (DefaultListModel) getModel(); + } +} diff --git a/src/ru/olamedia/game/Game.java b/src/ru/olamedia/game/Game.java new file mode 100644 index 0000000..8e04259 --- /dev/null +++ b/src/ru/olamedia/game/Game.java @@ -0,0 +1,25 @@ +package ru.olamedia.game; + +public class Game { + public boolean isRunning = false; + public boolean isPaused = false; + public void dispose(){ + + } + public void start(){ + isRunning = true; + init(); + } + public void pause(){ + isPaused = true; + } + public void resume(){ + isPaused = false; + } + public void finish(){ + isRunning = false; + } + public void init(){ + + } +} diff --git a/src/ru/olamedia/game/GameFrame.java b/src/ru/olamedia/game/GameFrame.java new file mode 100644 index 0000000..e768b63 --- /dev/null +++ b/src/ru/olamedia/game/GameFrame.java @@ -0,0 +1,194 @@ +package ru.olamedia.game; + +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Image; +import java.awt.Toolkit; +import java.util.ArrayList; +import java.util.List; + +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLProfile; +import javax.swing.JFrame; + +import ru.olamedia.asset.AssetManager; +import ru.olamedia.asset.AssetNotFoundException; +import ru.olamedia.input.Keyboard; +import ru.olamedia.input.MouseJail; +import ru.olamedia.olacraft.OlaCraft; + +import jogamp.newt.awt.NewtFactoryAWT; + +import com.jogamp.newt.Display; +import com.jogamp.newt.Screen; +import com.jogamp.newt.awt.NewtCanvasAWT; +import com.jogamp.newt.event.KeyAdapter; +import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.util.Animator; + +public class GameFrame { + // java.awt.SystemTray + // http://www.oracle.com/technetwork/articles/javase/systemtray-139788.html + + public static GameFrame instance; + + Display display; + Screen screen; + int screenId; + GLProfile glProfile; + GLCapabilities caps; + protected Frame awtFrame; + protected static GLWindow glWindow; + protected static JFrame jFrame; + int width = 854; + int height = 480; + public static Animator animator; + NewtCanvasAWT newtCanvasAWT; + private boolean glMode = false; + + public void initGL() { + if (null == newtCanvasAWT) { + glProfile = GLProfile.get(GLProfile.GL2);// Default(); + // ES2 + caps = new GLCapabilities(glProfile); + caps.setHardwareAccelerated(true); + caps.setDoubleBuffered(true); + caps.setBackgroundOpaque(false); + + display = NewtFactoryAWT.createDisplay(null); + screen = NewtFactoryAWT.createScreen(display, screenId); + glWindow = GLWindow.create(screen, caps);// GLWindow.create(screen, + // caps); + newtCanvasAWT = new NewtCanvasAWT(glWindow); + glWindow.setUndecorated(false); + glWindow.setPointerVisible(true); + glWindow.confinePointer(false); + glWindow.addWindowListener(new QuitAdapter()); + animator = new Animator(glWindow); + animator.setRunAsFastAsPossible(true); // By default there is a + // brief + // pause in the animation + // loop + animator.start(); + glWindow.addMouseListener(MouseJail.instance); + glWindow.addKeyListener(Keyboard.instance); + glWindow.addKeyListener(new KeyAdapter() { + @Override + public void keyReleased(KeyEvent e) { + super.keyReleased(e); + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { + glWindow.confinePointer(false); + glWindow.setPointerVisible(true); + } + } + }); + // animator.setUpdateFPSFrames(100, System.err); + jFrame.add(newtCanvasAWT); + glWindow.addGLEventListener(GameManager.instance); + } + } + + public void setGLMode() { + if (!glMode) { + initGL(); + glMode = true; + newtCanvasAWT.setVisible(true); + } + } + + public void setUIMode() { + if (glMode) { + glMode = false; + newtCanvasAWT.setVisible(false); + } + } + + public static int getX() { + return jFrame.getX(); + } + + public static int getY() { + return jFrame.getY(); + } + + public static int getWidth() { + if (null == glWindow) { + return jFrame.getWidth(); + } + return glWindow.getWidth(); + } + + public static int getHeight() { + if (null == glWindow) { + return jFrame.getHeight(); + } + return glWindow.getHeight(); + } + + public GameFrame() { + instance = this; + jFrame = new JFrame(); + jFrame.setMinimumSize(new Dimension(200, 200)); + jFrame.setSize(width, height); + jFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); + jFrame.setTitle("OlaCraft " + OlaCraft.version); + setIcons(); + // glWindow.setLocation(100, 100); + jFrame.addWindowListener(new QuitAdapter()); + jFrame.setVisible(true); + } + + private void setIcons() { + List<Image> icons = new ArrayList<Image>(); + try { + icons.add(getImage("icon16x16.png")); + icons.add(getImage("icon32x32.png")); + icons.add(getImage("icon64x64.png")); + icons.add(getImage("icon128x128.png")); + icons.add(getImage("icon256x256.png")); + } catch (AssetNotFoundException e1) { + e1.printStackTrace(); + } + // if (!icons.isEmpty()) { + // awtFrame.setIconImage(getImage("icon32x32.png")); + jFrame.setIconImages(icons); + // } + } + + private Image getImage(String filename) throws AssetNotFoundException { + String iconFile = AssetManager.getAsset("ru/olamedia/game/" + filename).getFile(); + return Toolkit.getDefaultToolkit().createImage(iconFile); + } + + public Animator getAnimator() { + return animator; + } + + public static void confinePointer(boolean confine) { + if (glWindow != null) { + glWindow.confinePointer(confine); + } + } + + public static void setPointerVisible(boolean visible) { + if (glWindow != null) { + glWindow.setPointerVisible(visible); + } + } + + public static GLWindow getWindow() { + return glWindow; + } + + public static JFrame getFrame() { + return jFrame; + } + + public void dispose() { + // glWindow.destroy(); + // newtCanvasAWT.destroy(); + jFrame.dispose(); + // System.err.close(); + } +} diff --git a/src/ru/olamedia/game/GameManager.java b/src/ru/olamedia/game/GameManager.java new file mode 100644 index 0000000..f8c05d9 --- /dev/null +++ b/src/ru/olamedia/game/GameManager.java @@ -0,0 +1,165 @@ +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; +import javax.media.opengl.GLEventListener; + +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.tasks.TaskManager; + + +import com.jogamp.opengl.JoglVersion; + +public class GameManager implements GLEventListener { + public static GameManager instance; + private GameFrame frame; + private ClientGame clientGame; + private ServerGame serverGame; + private IRenderer renderer; + private MainMenu menu; + + public GameManager() { + instance = this; + } + + private void createServerGame() { + if (null == serverGame) { + serverGame = new ServerGame(this); + } + } + + private void createClientGame() { + if (null == clientGame) { + clientGame = new ClientGame(this); + } + } + + public void startServerGame() { + createServerGame(); + serverGame.start(); + } + + public void startClientGame() { + createClientGame(); + clientGame.start(); + } + + public void resumeClientGame() { + createClientGame(); + clientGame.resume(); + } + + public void finishClientGame() { + createClientGame(); + clientGame.finish(); + } + + public void resumeServerGame() { + createServerGame(); + serverGame.resume(); + } + + public void finishServerGame() { + createServerGame(); + clientGame.finish(); + serverGame.dispose(); + } + + private void init() { + this.frame = new GameFrame(); + menu = new MainMenu(); + this.renderer = new DefaultRenderer(); + GameFrame.getFrame().getContentPane().add(menu); + menu.setVisible(true); + GameFrame.getFrame().validate(); + } + + public void start() { + init(); + while (!QuitAdapter.shouldQuit) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + public void dispose() { + TaskManager.stopAll(); + if (null != Game.server) { + Game.server.dispose(); + } + if (null != Game.client) { + Game.client.dispose(); + } + if (null != GameFrame.animator) { + if (GameFrame.animator.isStarted()) { + GameFrame.animator.stop(); + } + } + frame.dispose(); + // Get all threads + Set<Thread> threadSet = Thread.getAllStackTraces().keySet(); + for (Thread t : threadSet) { + if (t instanceof DiscoveryThread) { + t.interrupt(); + } + } + } + + @Override + public void init(GLAutoDrawable drawable) { + // GLContext.getContext().getGL() + GL2ES2 gl = drawable.getGL().getGL2ES2(); + //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() + " 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)); + System.err.println(Thread.currentThread() + " GL_VERSION: " + gl.glGetString(GL.GL_VERSION)); + System.err.println(Thread.currentThread() + " GL Profile: " + gl.getGLProfile()); + System.err.println(Thread.currentThread() + " GL:" + gl); + System.err.println(Thread.currentThread() + " GL_VERSION=" + gl.glGetString(GL.GL_VERSION)); + renderer.init(drawable); + } + + @Override + public void dispose(GLAutoDrawable drawable) { + // TODO Auto-generated method stub + + } + + @Override + 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); + renderer.render(drawable); + } + + @Override + public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { + GL gl = drawable.getGL().getGL2ES2(); + gl.glViewport(0, 0, width, height); + } + + public void showMainMenu() { + menu.setVisible(true); + } + + public void hideMainMenu() { + menu.setVisible(false); + } + +} diff --git a/src/ru/olamedia/game/Launcher.java b/src/ru/olamedia/game/Launcher.java new file mode 100644 index 0000000..7849468 --- /dev/null +++ b/src/ru/olamedia/game/Launcher.java @@ -0,0 +1,17 @@ +package ru.olamedia.game; + +public class Launcher { + + public Launcher() { + } + + /** + * @param args + */ + public static void main(String[] args) { + GameManager manager = new GameManager(); + manager.start(); + manager.dispose(); + } + +} diff --git a/src/ru/olamedia/game/MainMenu.java b/src/ru/olamedia/game/MainMenu.java new file mode 100644 index 0000000..1b3db13 --- /dev/null +++ b/src/ru/olamedia/game/MainMenu.java @@ -0,0 +1,168 @@ +package ru.olamedia.game; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.net.InetAddress; + +import javax.swing.JButton; +import javax.swing.JPanel; +import javax.swing.border.Border; +import javax.swing.border.CompoundBorder; +import javax.swing.border.EmptyBorder; +import javax.swing.border.LineBorder; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; + +import ru.olamedia.olacraft.game.Game; +import ru.olamedia.olacraft.network.ConnectionState; +import ru.olamedia.olacraft.network.ConnectionStateListener; +import ru.olamedia.olacraft.network.discovery.DiscoveryClient; +import ru.olamedia.olacraft.network.discovery.DiscoveryListener; + +public class MainMenu extends JPanel implements ActionListener { + private JButton startButton; + private JButton startServerButton; + private JButton discoveryButton; + private DynamicJList hosts; + private DiscoveryClient discoveryClient = DiscoveryClient.getInstance(); + private Thread discoveryClientThread; + private static final long serialVersionUID = -271797500986576805L; + + private void stylizeButton(JButton b) { + Border line = new LineBorder(Color.BLACK); + Border margin = new EmptyBorder(5, 15, 5, 15); + Border compound = new CompoundBorder(line, margin); + b.setBackground(new Color(1f, 1f, 1f, 0.8f)); + b.setBorder(compound); + } + + private static boolean DEBUG = true; + + @SuppressWarnings("unused") + private void debug(String s) { + if (DEBUG) { + System.out.println("[MainMenu] " + s); + } + } + + public MainMenu() { + setSize(GameFrame.getWidth(), GameFrame.getHeight()); + setOpaque(false); + // setBackground(new Color(0f, 0f, 0f, 0.8f)); + startButton = new JButton(); + startButton.setSize(500, 40); + startButton.setLocation((GameFrame.getWidth() - 500) / 2, 200); + startButton.setText("JOIN GAME"); + startButton.setEnabled(false); + startButton.setActionCommand("connect"); + startButton.addActionListener(this); + stylizeButton(startButton); + startServerButton = new JButton(); + startServerButton.setSize(500, 40); + startServerButton.setLocation((GameFrame.getWidth() - 500) / 2, 260); + startServerButton.setText("START SERVER"); + startServerButton.setActionCommand("start server"); + startServerButton.addActionListener(this); + stylizeButton(startServerButton); + discoveryButton = new JButton(); + discoveryButton.setSize(500, 40); + discoveryButton.setLocation((GameFrame.getWidth() - 500) / 2, 320); + discoveryButton.setText("REFRESH"); + discoveryButton.setActionCommand("discovery lan"); + discoveryButton.addActionListener(this); + stylizeButton(discoveryButton); + hosts = new DynamicJList(); + hosts.setSize(500, 150); + hosts.setLocation((GameFrame.getWidth() - 500) / 2, 10); + hosts.addListSelectionListener(new ListSelectionListener() { + @Override + public void valueChanged(ListSelectionEvent e) { + if (hosts.getContents().isEmpty()) { + Game.client.setHostname("127.0.0.1"); + System.out.println("Selected: none"); + startButton.setEnabled(false); + } else { + String host = (String) hosts.getContents().get(e.getFirstIndex()); + Game.client.setHostname(host); + System.out.println("Selected: " + host); + startButton.setEnabled(true); + } + } + }); + add(hosts); + add(startButton); + add(startServerButton); + add(discoveryButton); + // LAN discover + // InetAddress address = Game.client.discoverHost(54777, 5000); + // System.out.println(address); + setLayout(new BorderLayout()); + validate(); + Game.client.addStateListener(new ConnectionStateListener() { + @Override + public void onChangeState(ConnectionState state) { + // debug("Client ConnectionState changed"); + if (state.isConnected()) { + GameFrame.instance.setGLMode(); + Game.instance.player.captureControls(); + startButton.setText("LEAVE GAME"); + } else { + GameFrame.instance.setUIMode(); + startButton.setText("JOIN GAME"); + } + } + }); + discoveryClient.addHostListener(new DiscoveryListener() { + @Override + public void onHost(InetAddress address) { + if (null == address) { + discoveryButton.setEnabled(true); + } else { + hosts.getContents().addElement(address.getHostAddress()); + } + } + }); + } + + @Override + public void actionPerformed(ActionEvent e) { + String cmd = e.getActionCommand(); + if (cmd.equals("connect")) { + if (null != Game.instance) { + Game.instance = null; + } + Game.instance = new Game(Game.MODE_MULTIPLAYER); + if (Game.client.isConnected()) { + // LEAVE GAME + Game.client.close(); + } else { + Game.client.connect(); + } + Game.instance.start(); + } + if (cmd.equals("start server")) { + startServerButton.setEnabled(false); + if (Game.server.isRunning()) { + Game.server.stop(); + startServerButton.setText("START SERVER"); + startServerButton.setEnabled(true); + } else { + Game.server.start(); + if (Game.server.isRunning()) { + startServerButton.setText("STOP SERVER"); + startServerButton.setEnabled(true); + } else { + startServerButton.setEnabled(true); + } + } + } + if (cmd.equals("discovery lan")) { + discoveryButton.setEnabled(false); + discoveryClientThread = new Thread(DiscoveryClient.getInstance(), "DISCOVERY CLIENT"); + discoveryClientThread.start(); + hosts.getContents().clear(); + } + } +} diff --git a/src/ru/olamedia/game/QuitAdapter.java b/src/ru/olamedia/game/QuitAdapter.java new file mode 100644 index 0000000..8de1e8a --- /dev/null +++ b/src/ru/olamedia/game/QuitAdapter.java @@ -0,0 +1,71 @@ +package ru.olamedia.game; + +import com.jogamp.newt.event.*; + +public class QuitAdapter extends WindowAdapter implements WindowListener, KeyListener, java.awt.event.WindowListener { + public static boolean shouldQuit = false; + + public boolean shouldQuit() { + return shouldQuit; + } + + public void windowDestroyNotify(WindowEvent e) { + System.err.println("QUIT Window " + Thread.currentThread()); + shouldQuit = true; + } + + public void keyTyped(KeyEvent e) { + if (e.getKeyChar() == 'q') { + System.err.println("QUIT Key " + Thread.currentThread()); + shouldQuit = true; + } + } + + public void keyPressed(KeyEvent e) { + } + + public void keyReleased(KeyEvent e) { + } + + @Override + public void windowActivated(java.awt.event.WindowEvent arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void windowClosed(java.awt.event.WindowEvent arg0) { + // TODO Auto-generated method stub + shouldQuit = true; + } + + @Override + public void windowClosing(java.awt.event.WindowEvent arg0) { + System.err.println("QUIT Window " + Thread.currentThread()); + shouldQuit = true; + } + + @Override + public void windowDeactivated(java.awt.event.WindowEvent arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void windowDeiconified(java.awt.event.WindowEvent arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void windowIconified(java.awt.event.WindowEvent arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void windowOpened(java.awt.event.WindowEvent arg0) { + // TODO Auto-generated method stub + + } +} diff --git a/src/ru/olamedia/game/ServerGame.java b/src/ru/olamedia/game/ServerGame.java new file mode 100644 index 0000000..900a93f --- /dev/null +++ b/src/ru/olamedia/game/ServerGame.java @@ -0,0 +1,10 @@ +package ru.olamedia.game; + +public class ServerGame extends Game { + GameManager manager; + + public ServerGame(GameManager manager) { + this.manager = manager; + } + +} diff --git a/src/ru/olamedia/game/icon128x128.png b/src/ru/olamedia/game/icon128x128.png Binary files differnew file mode 100644 index 0000000..3572950 --- /dev/null +++ b/src/ru/olamedia/game/icon128x128.png diff --git a/src/ru/olamedia/game/icon16x16.png b/src/ru/olamedia/game/icon16x16.png Binary files differnew file mode 100644 index 0000000..1e2d694 --- /dev/null +++ b/src/ru/olamedia/game/icon16x16.png diff --git a/src/ru/olamedia/game/icon256x256.png b/src/ru/olamedia/game/icon256x256.png Binary files differnew file mode 100644 index 0000000..441eae8 --- /dev/null +++ b/src/ru/olamedia/game/icon256x256.png diff --git a/src/ru/olamedia/game/icon32x32.png b/src/ru/olamedia/game/icon32x32.png Binary files differnew file mode 100644 index 0000000..78a1277 --- /dev/null +++ b/src/ru/olamedia/game/icon32x32.png diff --git a/src/ru/olamedia/game/icon64x64.png b/src/ru/olamedia/game/icon64x64.png Binary files differnew file mode 100644 index 0000000..34a184b --- /dev/null +++ b/src/ru/olamedia/game/icon64x64.png diff --git a/src/ru/olamedia/game/package-info.java b/src/ru/olamedia/game/package-info.java new file mode 100644 index 0000000..86a2d0d --- /dev/null +++ b/src/ru/olamedia/game/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.game;
\ No newline at end of file diff --git a/src/ru/olamedia/geom/DisplayList.java b/src/ru/olamedia/geom/DisplayList.java new file mode 100644 index 0000000..aeaffc7 --- /dev/null +++ b/src/ru/olamedia/geom/DisplayList.java @@ -0,0 +1,39 @@ +package ru.olamedia.geom; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2; +import javax.media.opengl.GLAutoDrawable; + +public class DisplayList { + private GL2 gl; + private int glDL; + + public DisplayList(GL glx) { + gl = glx.getGL2(); + glDL = gl.glGenLists(1); + } + + public void start() { + gl.glNewList(glDL, GL2.GL_COMPILE); + } + + public void stop() { + gl.glEndList(); + } + + public void render() { + gl.glCallList(glDL); + } + + public void destroy() { + gl.glDeleteLists(glDL, 1); + } + + public void begin() { + start(); + } + + public void end() { + stop(); + } +} diff --git a/src/ru/olamedia/geom/Frustum.java b/src/ru/olamedia/geom/Frustum.java new file mode 100644 index 0000000..5428302 --- /dev/null +++ b/src/ru/olamedia/geom/Frustum.java @@ -0,0 +1,11 @@ +package ru.olamedia.geom; + +//import org.openmali.spatial.bodies.Frustum; + +public class Frustum extends org.openmali.spatial.bodies.Frustum { + + public Frustum() { + super(); + } + +} diff --git a/src/ru/olamedia/geom/Mesh.java b/src/ru/olamedia/geom/Mesh.java new file mode 100644 index 0000000..140cc4d --- /dev/null +++ b/src/ru/olamedia/geom/Mesh.java @@ -0,0 +1,346 @@ +package ru.olamedia.geom; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; +import java.util.HashMap; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2; +import javax.media.opengl.GL2ES2; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.fixedfunc.GLPointerFunc; + +import com.jogamp.opengl.util.GLArrayDataServer; +import com.jogamp.opengl.util.texture.Texture; + +public class Mesh { + private FloatBuffer buffer; + private float[] data; + private int ptr; + private int vertexCount; + private int vertexPtr; + private float xOffset; + private float yOffset; + private float zOffset; + + private boolean useColor; + private float red = 1f; + private float green = 1f; + private float blue = 1f; + private float alpha = 1f; + + private boolean useTexture; + private float GLTexture; + private float u = 0f; + private float v = 0f; + @SuppressWarnings("unused") + private float uFactor = 1f; + @SuppressWarnings("unused") + private float vFactor = 1f; + + private boolean wireframe = false; + + private static int vertexSize = 10; + + private GLArrayDataServer interleaved; + private HashMap<Integer, Integer> materials = new HashMap<Integer, Integer>(); + private HashMap<Integer, GLArrayDataServer> arrays = new HashMap<Integer, GLArrayDataServer>(); + + public void setTexture(Texture tex) { + if (null != tex) { + setTextureSize(tex.getWidth(), tex.getHeight()); + setGLTexture(tex.getTextureObject(null)); + } + } + + public void setGLTexture(int tex) { + this.GLTexture = tex; + } + + @SuppressWarnings("unused") + private static boolean useVbo = true; + + private static boolean useQuad = true; + private static boolean useDisplayList = false; + private DisplayList DL; + + public Mesh(int size) { + vertexCount = 0; + data = new float[size * vertexSize]; + // data = new float[size * vertexSize]; + vertexPtr = 0; + useTexture = false; + useColor = false; + } + + private static FloatBuffer generateFloatBuffer(int size) { + return ByteBuffer.allocateDirect(size * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); + } + + /** + * Reallocates an array with a new size, and copies the contents of the old + * array to the new array. + * + * @param oldArray + * the old array, to be reallocated. + * @param newSize + * the new array size. + * @return A new array with the same contents. + */ + private static float[] resizeArray(float[] oldArray, int newSize) { + int oldSize = oldArray.length; + float[] newArray = new float[newSize]; + int preserveLength = Math.min(oldSize, newSize); + if (preserveLength > 0) + System.arraycopy(oldArray, 0, newArray, 0, preserveLength); + return newArray; + } + + public void compact() { + // data = resizeArray(data, vertexCount * vertexSize); + int size = vertexCount * vertexSize; + buffer = generateFloatBuffer(size); + buffer.position(0); + buffer.put(data, 0, size); + data = null; + // calc vertex count for each material + for (int n = 0; n < vertexCount; n++) { + int tex = (int) buffer.get(vertexSize * n + 9); + if (!materials.containsKey(tex)) { + materials.put(tex, 1); + } else { + materials.put(tex, materials.get(tex) + 1); + } + } + for (Integer m : materials.keySet()) { + int matVertCount = materials.get(m); + final GLArrayDataServer interleaved = GLArrayDataServer.createFixedInterleaved(9, GL2.GL_FLOAT, false, + matVertCount, GL.GL_STATIC_DRAW); + interleaved.addFixedSubArray(GLPointerFunc.GL_VERTEX_ARRAY, 3, GL.GL_ARRAY_BUFFER); + interleaved.addFixedSubArray(GLPointerFunc.GL_COLOR_ARRAY, 4, GL.GL_ARRAY_BUFFER); + interleaved.addFixedSubArray(GLPointerFunc.GL_TEXTURE_COORD_ARRAY, 2, GL.GL_ARRAY_BUFFER); + arrays.put(m, interleaved); + } + for (int n = 0; n < vertexCount; n++) { + int m = (int) buffer.get(vertexSize * n + 9); + final GLArrayDataServer interleaved = arrays.get(m); + interleaved.putf(buffer.get(vertexSize * n + 0)); + interleaved.putf(buffer.get(vertexSize * n + 1)); + interleaved.putf(buffer.get(vertexSize * n + 2)); + interleaved.putf(buffer.get(vertexSize * n + 3)); + interleaved.putf(buffer.get(vertexSize * n + 4)); + interleaved.putf(buffer.get(vertexSize * n + 5)); + interleaved.putf(buffer.get(vertexSize * n + 6)); + interleaved.putf(buffer.get(vertexSize * n + 7)); + interleaved.putf(buffer.get(vertexSize * n + 8)); + } + for (Integer m : materials.keySet()) { + final GLArrayDataServer interleaved = arrays.get(m); + interleaved.seal(true); + } + // interleaved.put(buffer); + if (vertexCount > 0) { + // System.out.println(interleaved); + } + /* + * buffer.position(0); + * buffer.limit(size * vertexSize); + * buffer.position(0); + * buffer.limit(vertexCount * vertexSize); + * buffer.compact(); + * buffer.position(0); + */ + } + + public void endMesh() { + compact(); + } + + public void setTranslation(float x, float y, float z) { + xOffset = x; + yOffset = y; + zOffset = z; + } + + public void setPoint3f(float x, float y, float z) { + ptr = vertexPtr * vertexSize; + data[ptr + 0] = x + xOffset; + // buffer.put(x + xOffset); + data[ptr + 1] = y + yOffset; + // buffer.put(y + yOffset); + data[ptr + 2] = z + zOffset; + // buffer.put(z + zOffset); + if (useColor) { + data[ptr + 3] = red; + // buffer.put(red); + data[ptr + 4] = green; + // buffer.put(green); + data[ptr + 5] = blue; + // buffer.put(blue); + data[ptr + 6] = alpha; + // buffer.put(alpha); + } else { + // buffer.put(1f); + // buffer.put(1f); + // buffer.put(1f); + // buffer.put(1f); + } + if (useTexture) { + // buffer.put(GLTexture); + data[ptr + 7] = u;// * uFactor; + // buffer.put(u); + data[ptr + 8] = v;// * vFactor; + data[ptr + 9] = GLTexture; + // buffer.put(v); + } else { + // buffer.put(0f); + // buffer.put(0f); + // buffer.put(0f); + } + vertexPtr++; + vertexCount++; + } + + public void setColor4f(float red, float green, float blue, float alpha) { + this.red = red; + this.green = green; + this.blue = blue; + this.alpha = alpha; + } + + public void useColor() { + useColor = true; + } + + public void useTexture() { + useTexture = true; + } + + public void setUV(float u, float v) { + this.u = u; + this.v = v; + } + + public void setTextureSize(float uSize, float vSize) { + this.uFactor = uSize; + this.vFactor = vSize; + } + + public boolean joglIsVBOAvailable(GLAutoDrawable drawable) { + GL2 gl = drawable.getGL().getGL2(); + return gl.isFunctionAvailable("glGenBuffers") && gl.isFunctionAvailable("glBindBuffer") + && gl.isFunctionAvailable("glBufferData") && gl.isFunctionAvailable("glDeleteBuffers"); + } + + public void joglCreateVBO(GLAutoDrawable drawable) { + @SuppressWarnings("unused") + GL2 gl = drawable.getGL().getGL2(); + // gl.glInterleavedArrays(GL2.GL_T2F_C4F_N3F_V3F, stride, pointer) + + } + + public void joglRender(GL glx) { + 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); + } + + 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); + 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.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); + gl.glDrawArrays(GL2.GL_QUADS, 0, arrays.get(m).getElementCount()); + arrays.get(m).enableBuffer(gl, false); + } + /* + * 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 { + if (useDisplayList) { + if (DL == null) { + DL = new DisplayList(glx); + } else { + 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); + DL.render(); + return; + } + DL.begin(); + } + gl.glPushAttrib(GL2.GL_ENABLE_BIT | GL2.GL_POLYGON_BIT | GL2.GL_TEXTURE_BIT); + if (useTexture) { + gl.glEnable(GL.GL_TEXTURE_2D); + 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); + } + for (int quadI = 0; quadI < vertexCount / 4; quadI++) { + ptr = (quadI * 4 + 0) * vertexSize; + if (useTexture) { + gl.glBindTexture(GL.GL_TEXTURE_2D, (int) buffer.get(ptr + 9)); + 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.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_REPEAT); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_REPEAT); + // gl.glDisable(GL.GL_BLEND); + // gl.glTexParameterf(GL.GL_TEXTURE_2D, + // GL.GL_TEXTURE_MAX_ANISOTROPY_EXT, 0); + } + if (useQuad) { + gl.glBegin(GL2.GL_QUADS); + } else { + gl.glBegin(GL2.GL_TRIANGLE_STRIP); + } + { + for (int i = 0; i < 4; i++) { + int k = (useQuad) ? i : ((i == 2) ? 3 : (i == 3 ? 2 : i)); + ptr = (quadI * 4 + k) * vertexSize; + if (useColor) { + gl.glColor4f(buffer.get(ptr + 3), buffer.get(ptr + 4), buffer.get(ptr + 5), + buffer.get(ptr + 6)); + } + if (useTexture) { + float u = buffer.get(ptr + 7); + float v = buffer.get(ptr + 8); + gl.glTexCoord2f(u, v); + } + gl.glVertex3f(buffer.get(ptr), buffer.get(ptr + 1), buffer.get(ptr + 2)); + } + } + gl.glEnd(); + } + gl.glPopAttrib(); + if (useDisplayList) { + DL.end(); + DL.render(); + } + } + } +} diff --git a/src/ru/olamedia/geom/Quad.java b/src/ru/olamedia/geom/Quad.java new file mode 100644 index 0000000..e3d34dd --- /dev/null +++ b/src/ru/olamedia/geom/Quad.java @@ -0,0 +1,12 @@ +package ru.olamedia.geom; + +public class Quad { + private float[] vertices; + private int vertexCount; + + public void addVertex(float x, float y, float z) { + vertices[vertexCount] = x; + vertices[vertexCount + 1] = y; + vertices[vertexCount + 2] = z; + } +} diff --git a/src/ru/olamedia/geom/SimpleQuadMesh.java b/src/ru/olamedia/geom/SimpleQuadMesh.java new file mode 100644 index 0000000..42cf439 --- /dev/null +++ b/src/ru/olamedia/geom/SimpleQuadMesh.java @@ -0,0 +1,113 @@ +package ru.olamedia.geom; + +public class SimpleQuadMesh extends Mesh { + + public SimpleQuadMesh(int size) { + super(size * 4); + } + + private void addBottomLeftBackVertex() { + setPoint3f(-0.5f, -0.5f, -0.5f); + } + + private void addBottomLeftFrontVertex() { + setPoint3f(-0.5f, -0.5f, 0.5f); + } + + private void addBottomRightBackVertex() { + setPoint3f(0.5f, -0.5f, -0.5f); + } + + private void addBottomRightFrontVertex() { + setPoint3f(0.5f, -0.5f, 0.5f); + } + + private void addTopLeftBackVertex() { + setPoint3f(-0.5f, 0.5f, -0.5f); + } + + private void addTopLeftFrontVertex() { + setPoint3f(-0.5f, 0.5f, 0.5f); + } + + private void addTopRightBackVertex() { + setPoint3f(0.5f, 0.5f, -0.5f); + } + + private void addTopRightFrontVertex() { + setPoint3f(0.5f, 0.5f, 0.5f); + } + + public void addFrontQuad() { + // triangle strip: И + setUV(0, 1); + addTopLeftFrontVertex(); // top left + setUV(0, 0); + addBottomLeftFrontVertex(); // bottom left + setUV(1, 0); + addBottomRightFrontVertex(); // bottom right + setUV(1, 1); + addTopRightFrontVertex(); // top right + } + + public void addBackQuad() { + // triangle strip: И + setUV(0, 1); + addTopRightBackVertex(); + setUV(0, 0); + addBottomRightBackVertex(); + setUV(1, 0); + addBottomLeftBackVertex(); + setUV(1, 1); + addTopLeftBackVertex(); + } + + public void addLeftQuad() { + // triangle strip: И + setUV(0, 1); + addTopLeftBackVertex(); + setUV(0, 0); + addBottomLeftBackVertex(); + setUV(1, 0); + addBottomLeftFrontVertex(); + setUV(1, 1); + addTopLeftFrontVertex(); + } + + public void addRightQuad() { + // triangle strip: И + setUV(0, 1); + addTopRightFrontVertex(); + setUV(0, 0); + addBottomRightFrontVertex(); + setUV(1, 0); + addBottomRightBackVertex(); + setUV(1, 1); + addTopRightBackVertex(); + } + + public void addTopQuad() { + // triangle strip: И + setUV(0, 0); + addTopLeftBackVertex(); + setUV(0, 1); + addTopLeftFrontVertex(); + setUV(1, 1); + addTopRightFrontVertex(); + setUV(1, 0); + addTopRightBackVertex(); + } + + public void addBottomQuad() { + // triangle strip: И + setUV(0, 0); + addBottomLeftFrontVertex(); + setUV(0, 1); + addBottomLeftBackVertex(); + setUV(1, 1); + addBottomRightBackVertex(); + setUV(1, 0); + addBottomRightFrontVertex(); + } + +} diff --git a/src/ru/olamedia/geom/package-info.java b/src/ru/olamedia/geom/package-info.java new file mode 100644 index 0000000..97fe3c5 --- /dev/null +++ b/src/ru/olamedia/geom/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.geom;
\ No newline at end of file diff --git a/src/ru/olamedia/input/AWTRobotUtil.java b/src/ru/olamedia/input/AWTRobotUtil.java new file mode 100644 index 0000000..9c6778c --- /dev/null +++ b/src/ru/olamedia/input/AWTRobotUtil.java @@ -0,0 +1,97 @@ +package ru.olamedia.input; + +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +import java.lang.reflect.InvocationTargetException; +import java.awt.AWTException; +import java.awt.Component; +import java.awt.Point; +import java.awt.Robot; + +public class AWTRobotUtil { + + private static final int ROBOT_DELAY = 100; // ms + + public static Point getCenterLocation(Object obj, boolean onTitleBarIfWindow) throws InterruptedException, + InvocationTargetException { + Component comp = null; + com.jogamp.newt.Window win = null; + + if (obj instanceof com.jogamp.newt.Window) { + win = (com.jogamp.newt.Window) obj; + } else if (obj instanceof Component) { + comp = (Component) obj; + } else { + throw new RuntimeException("Neither AWT nor NEWT: " + obj); + } + + int x0, y0; + if (null != comp) { + java.awt.Point p0 = comp.getLocationOnScreen(); + java.awt.Rectangle r0 = comp.getBounds(); + if (onTitleBarIfWindow && comp instanceof java.awt.Window) { + java.awt.Window window = (java.awt.Window) comp; + java.awt.Insets insets = window.getInsets(); + y0 = (int) (p0.getY() + insets.top / 2.0 + .5); + } else { + y0 = (int) (p0.getY() + r0.getHeight() / 2.0 + .5); + } + x0 = (int) (p0.getX() + r0.getWidth() / 2.0 + .5); + } else { + javax.media.nativewindow.util.Point p0 = win.getLocationOnScreen(null); + if (onTitleBarIfWindow) { + javax.media.nativewindow.util.InsetsImmutable insets = win.getInsets(); + p0.translate(win.getWidth() / 2, insets.getTopHeight() / 2); + } else { + javax.media.nativewindow.util.InsetsImmutable insets = win.getInsets(); + p0.translate(win.getWidth() / 2, (win.getHeight() - insets.getTopHeight()) / 2); + } + x0 = p0.getX(); + y0 = p0.getY(); + } + + return new Point(x0, y0); + } + + /** + * centerMouse + */ + public static Point centerMouse(Robot robot, Object obj, boolean onTitleBarIfWindow) throws AWTException, + InterruptedException, InvocationTargetException { + + Point p0 = getCenterLocation(obj, onTitleBarIfWindow); + // System.err.println("centerMouse: robot pos: " + p0 + + // ", onTitleBarIfWindow: " + onTitleBarIfWindow); + + robot.mouseMove((int) p0.getX(), (int) p0.getY()); + // robot.delay(ROBOT_DELAY); + return p0; + } + +} diff --git a/src/ru/olamedia/input/KeyListener.java b/src/ru/olamedia/input/KeyListener.java new file mode 100644 index 0000000..8fb5d49 --- /dev/null +++ b/src/ru/olamedia/input/KeyListener.java @@ -0,0 +1,10 @@ +package ru.olamedia.input; + +import com.jogamp.newt.event.KeyEvent; + +public interface KeyListener { + public void onKeyPressed(String name, KeyEvent e); + + public void onKeyReleased(String name, KeyEvent e); + +} diff --git a/src/ru/olamedia/input/Keyboard.java b/src/ru/olamedia/input/Keyboard.java new file mode 100644 index 0000000..6a9ecbd --- /dev/null +++ b/src/ru/olamedia/input/Keyboard.java @@ -0,0 +1,64 @@ +package ru.olamedia.input; + +import java.awt.event.KeyEvent; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.collections.BidiMap; +import org.apache.commons.collections.bidimap.DualHashBidiMap; + +public class Keyboard implements com.jogamp.newt.event.KeyListener { + public static Keyboard instance = new Keyboard(); + private static boolean[] downState = new boolean[256]; + private static BidiMap names = new DualHashBidiMap(); + + public static void setName(String name, int keyCode) { + names.put(name, keyCode); + } + + public static boolean isKeyDown(int keyCode) { + return downState[keyCode]; + } + + public static boolean isKeyDown(String name) { + if (names.containsKey(name)) { + return downState[((Integer) names.get(name)).intValue()]; + } + return false; + } + + private static List<ru.olamedia.input.KeyListener> listeners = new ArrayList<ru.olamedia.input.KeyListener>(); + + public static void attach(ru.olamedia.input.KeyListener l) { + listeners.add(l); + } + + @Override + public void keyPressed(com.jogamp.newt.event.KeyEvent e) { + downState[e.getKeyCode()] = true; + if (names.containsValue(e.getKeyCode())) { + String name = (String) names.getKey(e.getKeyCode()); + for (ru.olamedia.input.KeyListener l : listeners) { + l.onKeyPressed(name, e); + } + } + } + + @Override + public void keyReleased(com.jogamp.newt.event.KeyEvent e) { + downState[e.getKeyCode()] = false; + if (names.containsValue(e.getKeyCode())) { + String name = (String) names.getKey(e.getKeyCode()); + for (ru.olamedia.input.KeyListener l : listeners) { + l.onKeyReleased(name, e); + } + } + } + + @Override + public void keyTyped(com.jogamp.newt.event.KeyEvent arg0) { + // TODO Auto-generated method stub + + } +} diff --git a/src/ru/olamedia/input/MouseJail.java b/src/ru/olamedia/input/MouseJail.java new file mode 100644 index 0000000..bd12b0a --- /dev/null +++ b/src/ru/olamedia/input/MouseJail.java @@ -0,0 +1,113 @@ +package ru.olamedia.input; + +import java.awt.AWTException; +import java.awt.Point; +import java.awt.Robot; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; + +import com.jogamp.newt.event.MouseAdapter; +import com.jogamp.newt.event.MouseEvent; + +import ru.olamedia.game.GameFrame; + +public class MouseJail extends MouseAdapter { + public static MouseJail instance = new MouseJail(); + + public MouseJail() { + } + + private static boolean isActive = false; + + /** + * @return the isActive + */ + public static boolean isActive() { + return isActive; + } + + /** + * @param isActive + * the isActive to set + */ + public static void setActive(boolean isActive) { + System.out.println("Mouse jail " + (isActive ? "active" : "not active")); + MouseJail.isActive = isActive; + GameFrame.confinePointer(isActive); + GameFrame.setPointerVisible(!isActive); + } + + @Override + public void mouseClicked(MouseEvent e) { + if (e.isAltDown()) { + setActive(false); + } else { + setActive(true); + } + for (ru.olamedia.input.MouseListener l : listeners) { + l.onMouseClick(); + } + } + + @Override + public void mouseEntered(MouseEvent e) { + System.out.println("Entered"); + + } + + @Override + public void mouseExited(MouseEvent e) { + System.out.println("Exited"); + isActive = false; + if (isActive) { + //moveToCenter(); + } + } + + @Override + public void mousePressed(MouseEvent e) { + + } + + @Override + public void mouseReleased(MouseEvent e) { + + } + + @Override + public void mouseDragged(MouseEvent e) { + onMove(e); + } + + private float sensitivity = 2f; + + private void onMove(MouseEvent e) { + if (isActive) { + int cx = GameFrame.getWidth() / 2; + int cy = GameFrame.getHeight() / 2; + float dx = e.getX() - cx; + float dy = e.getY() - cy; + dx *= sensitivity / 10; + dy *= sensitivity / 10; + // System.out.println("Mouse moved " + " dx:" + dx + " dy:" + dy + // + " x:" + e.getX() + " y:" + e.getY()); + for (ru.olamedia.input.MouseListener l : listeners) { + l.onMouseMove(dx, dy); + } + GameFrame.getWindow().warpPointer(cx, cy); + } + } + + @Override + public void mouseMoved(MouseEvent e) { + onMove(e); + } + + private static List<ru.olamedia.input.MouseListener> listeners = new ArrayList<ru.olamedia.input.MouseListener>(); + + public static void attach(ru.olamedia.input.MouseListener l) { + listeners.add(l); + } + +} diff --git a/src/ru/olamedia/input/MouseListener.java b/src/ru/olamedia/input/MouseListener.java new file mode 100644 index 0000000..3d93d1d --- /dev/null +++ b/src/ru/olamedia/input/MouseListener.java @@ -0,0 +1,6 @@ +package ru.olamedia.input; + +public interface MouseListener { + public void onMouseMove(float dx, float dy); + public void onMouseClick(); +} diff --git a/src/ru/olamedia/input/package-info.java b/src/ru/olamedia/input/package-info.java new file mode 100644 index 0000000..ad3f418 --- /dev/null +++ b/src/ru/olamedia/input/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.input;
\ No newline at end of file diff --git a/src/ru/olamedia/liveEntity/LiveEntity.java b/src/ru/olamedia/liveEntity/LiveEntity.java new file mode 100644 index 0000000..ce31108 --- /dev/null +++ b/src/ru/olamedia/liveEntity/LiveEntity.java @@ -0,0 +1,683 @@ +package ru.olamedia.liveEntity; + +import javax.vecmath.Vector3f; + +import com.jogamp.newt.event.KeyEvent; + +import ru.olamedia.camera.Cameraman; +import ru.olamedia.olacraft.game.Game; +import ru.olamedia.olacraft.inventory.Inventory; +import ru.olamedia.olacraft.world.block.Block; +import ru.olamedia.olacraft.world.blockStack.BlockStack; +import ru.olamedia.olacraft.world.blockTypes.GravelBlockType; +import ru.olamedia.input.Keyboard; + +public class LiveEntity implements Cameraman { + private Inventory inventory; // every living entity can have inventory + private float x; + private float y; + private float z; + public Vector3f velocity = new Vector3f(0, 0, 0); + public Vector3f acceleration = new Vector3f(0, 0, 0); + + private float fov = 90f; + private float mouseSpeed = 1.0f; + private float maxLookUp = 80.0f; + private float maxLookDown = -80.0f; + private float maxHeight = 1.9f; + private float cameraLevel = 1.8f; + + private float pitch = 0f; + private float yaw = 0f; + private float roll = 0f; + + private float walkSpeed = 1.3f;// 1.3-1.5 m/s + private float runSpeed = 4.5f;// m/s + + private boolean isWalking = false; + private boolean isRunning = false; + private boolean isSneaking = false; + private boolean isCrouching = false; + private boolean isViewBobbing = true; + private float bob = 0f; + private float hSpeed = runSpeed; // horizontal speed + private float vVelocity = 0f; + + @SuppressWarnings("unused") + private float maxHealthPoints; + private float healthPoints; + public float qD = 0; + public float qInvD = 0; + public boolean inJump = false; + public boolean inFall = false; + public boolean onGround = false; + private float savedX; + private float savedY; + private float savedZ; + private int id; + private int connectionId; + private boolean isPositionChanged = false; + + protected void generateInventory() { + // can be overriden for mobs + for (int i = 0; i <= 9; i++) { + inventory.binded[i] = new BlockStack(new Block(), (int) Math.random() * 64); + inventory.binded[i].block.setType(new GravelBlockType()); + } + } + + public Inventory getInventory() { + if (null == inventory) { + inventory = new Inventory(); + generateInventory(); + } + return inventory; + } + + public float getHSpeed() { + return (hSpeed) * (isCrouching ? 0.4f : 1) * (isSneaking ? 0.5f : 1); + } + + public float getHeight() { + return maxHeight * (isCrouching ? 0.5f : 1) * (isSneaking ? 0.8f : 1); + } + + public float getMaxJumpHeight() { + // ~1.5 for 1.8 + return (float) ((float) (maxHeight * 0.83)) * (isCrouching ? 0.8f : 1f); + } + + /** + * Returns the vertical velocity needed to jump the specified height (based + * on current gravity). Uses the Math.sqrt() function. + */ + public float getJumpVelocity(float jumpHeight) { + // use velocity/acceleration formal: v*v = -2 * a(y-y0) + // (v is jump velocity, a is accel, y-y0 is max height) + return (float) Math.sqrt(2 * Game.client.getWorldInfo().gravity * jumpHeight); + } + + public float getCameraLevel() { + return getHeight() * 0.9f; + } + + public boolean isEmptyUnderFoot() { + return isEmptyBlock(0, -1, 0); + } + + /** + * @param delta + * the elapsed time since the last frame update in seconds + */ + public void updateKeyboard(float delta) { + acceleration.x = 0; + acceleration.y = 0; + acceleration.z = 0; + boolean keyLeft = Keyboard.isKeyDown("playerStrafeLeft"); + boolean keyRight = Keyboard.isKeyDown("playerStrafeRight"); + boolean keyForward = Keyboard.isKeyDown("playerForward"); + boolean keyBack = Keyboard.isKeyDown("playerBack"); + boolean keyJump = Keyboard.isKeyDown("playerJump"); + boolean keySneak = Keyboard.isKeyDown("playerSneak"); + boolean keyCrouch = Keyboard.isKeyDown("playerCrouch"); + + if (keySneak) { + if (!isSneaking) { + isSneaking = true; + if (!applyPosition()) { + isSneaking = false; + } + } + } else { + if (isSneaking) { + isSneaking = false; + if (!applyPosition()) { + isSneaking = true; + } + } + } + if (keyCrouch) { + if (!isCrouching) { + isCrouching = true; + if (!applyPosition()) { + isCrouching = false; + } + } + } else { + if (isCrouching) { + isCrouching = false; + if (!applyPosition()) { // Test if we don't have a block over + // head + isCrouching = true; + } + } + } + isWalking = false; + if ((keyForward && !keyBack) || (keyBack && !keyForward)) { + Vector3f look = Game.instance.camera.getLook(); + acceleration.x += look.x * (keyBack ? 1 : -1) * 1f; + acceleration.y += 0; + acceleration.z += look.z * (keyBack ? 1 : -1) * 1f; + } + if ((keyLeft && !keyRight) || (keyRight && !keyLeft)) { + Vector3f right = Game.instance.camera.getRight(); + acceleration.x += right.x * (keyRight ? 1 : -1) * 1f; + acceleration.y += 0; + acceleration.z += right.z * (keyRight ? 1 : -1) * 1f; + } + // acceleration.normalize(); + float normalSpeed = 4.5f; + acceleration.x *= normalSpeed;// running + acceleration.y *= normalSpeed; + acceleration.z *= normalSpeed; + + // if (inJump) { + // float FPS = (float) (delta / 1); + // float accelY = Game.world.gravity; + // float dt = (float) (delta / 1); // in seconds + // vVelocity -= accelY * dt; + // y += vVelocity * dt; + // if (vVelocity < 0) { + // inFall = true; + // } + // if (vVelocity > 0) { + // if (!keyJump) { + // vVelocity = 0; + // } + // } + // if (!applyPosition()) { + // if (vVelocity > 0) { + // // roof + // vVelocity = 0; + // } else { + // y = underFoot().getY() + 1; + // vVelocity = 0; + // inJump = false; + // inFall = false; + // } + // } + // + // } else { + // if (!inFall) { + // if (inAir()) { + // + // inJump = true; + // inFall = true; + // } + // } + // } + if (!onGround && !inAir()) { + // LANDING + onGround = true; + inJump = false; + velocity.y = 0; + acceleration.y = 0; + y = getJumperBlock().getY() + 1; + } + if (onGround && velocity.length() > 0 && acceleration.length() > 0) { + // BEFORE NEW JUMP + // Check direction changed + float vy = velocity.y; + float ay = acceleration.y; + velocity.y = 0; + acceleration.y = 0; + float dAngle = velocity.angle(acceleration); + float speedLimit = 10; + if (dAngle > 0) { + // changing angle + Vector3f newDirection = new Vector3f(velocity); + newDirection.add(acceleration); + if (newDirection.length() > 0) { + newDirection.normalize(); + newDirection.scale(velocity.length()); + } + velocity.set(newDirection); + // check velocity + if (velocity.length() * Math.cos(dAngle) > speedLimit) { + float deltaSpeed = (float) (velocity.length() * Math.cos(dAngle) - speedLimit); + velocity.scale((1 / velocity.length()) * (velocity.length() - deltaSpeed * 0.7f)); + // velocity.scale((float) (10 / velocity.length() * + // Math.cos(dAngle))); + // velocity.scale((float) (velocity.length() + // - (velocity.length() - (10 / velocity.length() * + // Math.cos(dAngle))) * 0.5f * delta)); + } + } else { + if (velocity.length() > speedLimit) { + float deltaSpeed = (float) (velocity.length() - speedLimit); + velocity.scale((1 / velocity.length()) * (velocity.length() - deltaSpeed * 0.7f)); + } + } + velocity.y = vy; + acceleration.y = ay; + } + if (onGround && keyJump) { + // JUMPING + inJump = true; + onGround = false; + velocity.y = getJumpVelocity(getMaxJumpHeight()); + acceleration.y = velocity.y; + // vVelocity = getJumpVelocity(getMaxJumpHeight()); + System.out.println("Max jump height " + getMaxJumpHeight()); + System.out.println("Starting velocity " + velocity.y); + } + + if (onGround && !inJump) { + if (velocity.length() > normalSpeed) { + velocity.scale(normalSpeed / velocity.length()); + } + // APPLY FRICTION + // Vector3f friction = new Vector3f(velocity); + // friction.negate(); + // friction.scale(friction.length()); + // friction.scale(delta); + // velocity.scale((float) Math.exp(-0.2 * delta)); + // acceleration.scale(friction.length()); + } + + if (velocity.length() > 0 && acceleration.length() > 0) { + qD = Math.abs(velocity.dot(acceleration)) / (velocity.length() * acceleration.length()); + } + + // Vector3f a = new Vector3f(acceleration); + // if (a.length() > 0) { + // a.normalize(); + // } + // + // if (qD > 0) { + // qInvD = (float) Math.acos(qD); + // acceleration.scale(qInvD * 10f); + // } + // if (qD > 10) { + // if (velocity.length() > 0) { + // velocity.normalize(); + // } + // velocity.scale(qD); + // } + // if (qd > 10) { + // qd = 10; + // } + // velocity.set(acceleration); + // if (velocity.length() > 1){ + // velocity.scale(1 / velocity.length()); + // } + // velocity.scale(qd); + + if (!onGround || inAir()) { // 0_o + acceleration.y = -Game.client.getWorldInfo().gravity; + } + + // float qangle = (float) Math.abs(Math.acos(qd)); + // if (qangle > 180){ + // acceleration.scale(10f); + // }else if (qangle > 90){ + // acceleration.scale(5f); + // }else if (qangle > 45){ + // acceleration.scale(2f); + // } + + // Quake-like tricks here... + // Vector3f qa = new Vector3f(acceleration); + // if (qa.length() != 0) { + // qa.scale(1 / qa.length()); + // float qd = acceleration.dot(velocity); + // float qangle = (float) Math.abs(Math.acos(qd)); + // if (qangle > 180) { + // // fast stop + // velocity.x *= 0.5f; + // velocity.z *= 0.5f; + // }else{ + // + // } + // if (qd > 14) { + // velocity.x *= 1 / qd; + // velocity.z *= 1 / qd; + // } + // } + if (onGround && (acceleration.length() == 0)) { + velocity.set(0f, 0f, 0f); + } else { + // acceleration.normalize(); + // Vector3f a = new Vector3f(acceleration); + // a.scale(delta); + + if (velocity.length() == 0) { + velocity.x = acceleration.x; + // velocity.y = acceleration.y; + velocity.z = acceleration.z; + } else { + velocity.x += acceleration.x * delta; + velocity.z += acceleration.z * delta; + velocity.y += acceleration.y * delta; + } + + Vector3f move = new Vector3f(velocity); + move.scale(delta); + float dx = 0; + while (move.x != 0) { + if (move.x > 1) { + dx = 1; + move.x -= 1; + } else if (move.x < -1) { + dx = -1; + move.x += 1; + } else { + dx = move.x; + move.x = 0; + } + x += dx; + if (applyPosition()) { + isWalking = true; + } else { + // full stop + velocity.x = 0; + } + } + float dz = 0; + while (move.z != 0) { + if (move.z > 1) { + dz = 1; + move.z -= 1; + } else if (move.z < -1) { + dz = -1; + move.z += 1; + } else { + dz = move.z; + move.z = 0; + } + z += dz; + if (applyPosition()) { + isWalking = true; + } else { + // full stop + velocity.z = 0; + } + } + float dy = 0; + if (move.y != 0) { + while (move.y != 0) { + if (move.y > 1) { + dy = 1; + move.y -= 1; + } else if (move.y < -1) { + dy = -1; + move.y += 1; + } else { + dy = move.y; + move.y = 0; + } + y += dy; + if (applyPosition()) { + isWalking = true; + } else { + // full stop + velocity.y = 0; + } + } + + } + } + } + + private Block underFoot() { + return getBlock(0, -1, 0); + } + + public boolean isEmptyBlock(int dx, int dy, int dz) { + return Game.client.getWorldProvider().isEmptyBlock((int) x + dx, (int) Math.ceil(y) + dy, (int) z + dz); + } + + public boolean haveBlockUnder(int dy) { + return !isEmptyBlock(0, -dy, 0); + } + + public boolean inAir() { + return !haveBlockUnder(1); + } + + public boolean underJumpHeight() { + return haveBlockUnder(1) || haveBlockUnder(2); + } + + public Block getJumperBlock() { + if (haveBlockUnder(1)) { + return getBlock(0, -1, 0); + } + if (haveBlockUnder(2)) { + return getBlock(0, -2, 0); + } + return null; + } + + private Block getBlock(int dx, int dy, int dz) { + return Game.client.getWorldProvider().getBlock((int) x + dx, (int) Math.ceil(y) + dy, (int) z + dz); + } + + public void backupPosition() { + savedX = x; + savedY = y; + savedZ = z; + } + + public void restorePosition() { + x = savedX; + y = savedY; + z = savedZ; + } + + public boolean hasValidPosition() { + Block foot = getBlock(0, 0, 0); + Block underFoot = getBlock(0, -1, 0); + Block head = getBlock(0, (int) getHeight(), 0); + if (!inJump) { + if (underFoot.isEmpty()) { + // In AIR while normal walking + if (isSneaking) { + // TODO Jumping while Sneaking fixes x,z while jumping + return false; + } + } + } + // Check if we're too near to the wall + float screenPlane = 0.2f; + float screenPlaneVertical = 0.4f; + Block[] headNeighbors = head.getNeighbors(); + for (Block b : headNeighbors) { + if (b.isEmpty()) { + continue; + } + if (b.getX() != head.getX()) { + // LEFT or RIGHT + float testX = b.getX(); + if (testX < head.getX()) { + // LEFT, fixing + testX = head.getX(); + } + float minDistance = Math.abs(testX - getX()); + if (minDistance < screenPlane) { + return false; + } + } + if (b.getY() > head.getY()) { // Upper block + float minDistance = Math.abs(b.getY() - getY() + this.getHeight());// player + // height + if (minDistance < screenPlaneVertical) { + return false; + } + } + + if (b.getZ() != head.getZ()) { + // FRONT OR BACK + float testZ = b.getZ(); + if (testZ < head.getZ()) { + // BACK, fixing + testZ = head.getZ(); + } + float minDistance = Math.abs(testZ - getZ()); + if (minDistance < screenPlane) { + return false; + } + } + } + return foot.isEmpty() && head.isEmpty(); + } + + public boolean applyPosition() { + isPositionChanged = false; + if (hasValidPosition()) { + backupPosition(); + isPositionChanged = true; + return true; + } + restorePosition(); + return false; + } + + public void notifyLocationUpdate() { + // overriden at player class + } + + public void fixPosition() { + float dx = x - savedX; + float dy = y - savedY; + float dz = z - savedZ; + restorePosition(); + if (Math.abs(dx) < 1) { // in a block range + x += dx; + applyPosition(); + } + if (Math.abs(dy) < 1) { // in a block range + y += dy; + applyPosition(); + } + if (Math.abs(dz) < 1) { // in a block range + y += dz; + applyPosition(); + } + } + + @Override + public void update(float delta) { + isPositionChanged = false; + backupPosition(); + onGround = false; + Block below = getBlock(0, -1, 0); + if (y == below.getY() + 1) { + onGround = true; + } + updateKeyboard(delta); + // Check if position is valid + // fixPosition(); + + if (y < -20) { + // spawnAt((int) x, (int) z); + } + pitch = Game.instance.camera.getPitch(); + yaw = Game.instance.camera.getYaw(); + // Game.camera.setRoll(roll); + // saveTrace(); + // if (isWalking && onGround) { + // if (!stepsound.isPlaying()) { + // stepsound.playAsSoundEffect(1f, 0.4f, true); + // } + // } else { + // if (stepsound.isPlaying()) { + // stepsound.stop(); + // } + // } + if (isPositionChanged) { + notifyLocationUpdate(); + } + } + + public void setLocation(float x, float y, float z) { + this.setX(x); + this.setY(y); + this.setZ(z); + } + + public void say(String message) { + + } + + public void die() { + healthPoints = 0; + LiveEntityEvent e = new LiveEntityEvent(this); + e.setType(LiveEntityEvent.ON_DIE); + e.dispatch(); + } + + public void acceptDamage(float amount) { + healthPoints -= amount; + if (healthPoints < 0) { + die(); + } + } + + public float getX() { + return x; + } + + public void setX(float x) { + this.x = x; + } + + public float getY() { + return y; + } + + public void setY(float y) { + this.y = y; + } + + public float getZ() { + return z; + } + + public void setZ(float z) { + this.z = z; + } + + @Override + public float getCameraX() { + return x; + } + + @Override + public float getCameraY() { + return y + getCameraLevel(); + } + + @Override + public float getCameraZ() { + return z; + } + + @Override + public void captureControls() { + System.out.println("Player took controls"); + Keyboard.setName("playerForward", KeyEvent.VK_W); + Keyboard.setName("playerBack", KeyEvent.VK_S); + Keyboard.setName("playerStrafeLeft", KeyEvent.VK_A); + Keyboard.setName("playerStrafeRight", KeyEvent.VK_D); + Keyboard.setName("playerJump", KeyEvent.VK_SPACE); + Keyboard.setName("playerSneak", KeyEvent.VK_SHIFT); + Keyboard.setName("playerCrouch", KeyEvent.VK_CONTROL); + } + + public void setId(int id) { + this.id = id; + } + + public int getId() { + return id; + } + + public int getConnectionId() { + return connectionId; + } + + public void setConnectionId(int connectionId) { + this.connectionId = connectionId; + } +} diff --git a/src/ru/olamedia/liveEntity/LiveEntityEvent.java b/src/ru/olamedia/liveEntity/LiveEntityEvent.java new file mode 100644 index 0000000..5c0ded5 --- /dev/null +++ b/src/ru/olamedia/liveEntity/LiveEntityEvent.java @@ -0,0 +1,31 @@ +package ru.olamedia.liveEntity; + +public class LiveEntityEvent { + public static int ON_DIE; + private Object source; + private int type; + + public LiveEntityEvent(Object source) { + this.setSource(source); + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public Object getSource() { + return source; + } + + public void setSource(Object source) { + this.source = source; + } + + public void dispatch() { + LiveEntityEventDispatcher.dispatch(this); + } +} diff --git a/src/ru/olamedia/liveEntity/LiveEntityEventDispatcher.java b/src/ru/olamedia/liveEntity/LiveEntityEventDispatcher.java new file mode 100644 index 0000000..5d29ae1 --- /dev/null +++ b/src/ru/olamedia/liveEntity/LiveEntityEventDispatcher.java @@ -0,0 +1,7 @@ +package ru.olamedia.liveEntity; + +public class LiveEntityEventDispatcher { + public static void dispatch(LiveEntityEvent e){ + + } +} diff --git a/src/ru/olamedia/liveEntity/package-info.java b/src/ru/olamedia/liveEntity/package-info.java new file mode 100644 index 0000000..9c27733 --- /dev/null +++ b/src/ru/olamedia/liveEntity/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.liveEntity;
\ No newline at end of file diff --git a/src/ru/olamedia/math/Box.java b/src/ru/olamedia/math/Box.java new file mode 100644 index 0000000..7b9d968 --- /dev/null +++ b/src/ru/olamedia/math/Box.java @@ -0,0 +1,74 @@ +package ru.olamedia.math; + +public class Box { + private Vector3f low = new Vector3f(); + private Vector3f high = new Vector3f(); + + /** + * @param x + * left + * @param y + * lower + * @param z + * back + * @param x2 + * right + * @param y2 + * higher + * @param z2 + * front + */ + public Box(float x, float y, float z, float x2, float y2, float z2) { + low.x = x; + low.y = y; + low.z = z; + high.x = x2; + high.y = y2; + high.z = z2; + } + + public Vector3f getVertex(int i) { + Vector3f vertex = new Vector3f(low); + if (i > 3) { + // 4, 5, 6, 7 + vertex.z = high.z; + } + if (i % 4 > 1) { + // 0 1 2 3 4 5 6 7 + // 0 1 2 3 0 1 2 3 + // - - + + - - + + + vertex.y = high.y; + } + if (i % 2 > 0) { + // 0 1 2 3 4 5 6 7 + // 0 1 0 1 0 1 0 1 + // - + - + - + - + + vertex.x = high.x; + } + return vertex; + } + + public float getLowerX() { + return low.x; + } + + public float getLowerY() { + return low.y; + } + + public float getLowerZ() { + return low.z; + } + + public float getUpperX() { + return high.x; + } + + public float getUpperY() { + return high.y; + } + + public float getUpperZ() { + return high.z; + } +} diff --git a/src/ru/olamedia/math/Classifier.java b/src/ru/olamedia/math/Classifier.java new file mode 100644 index 0000000..551bcf6 --- /dev/null +++ b/src/ru/olamedia/math/Classifier.java @@ -0,0 +1,8 @@ +package ru.olamedia.math; + +public class Classifier { + // INSIDE > INTERSECT > OUTSIDE + public static int OUTSIDE = 0; + public static int INTERSECT = 1; + public static int INSIDE = 2; +} diff --git a/src/ru/olamedia/math/Frustum.java b/src/ru/olamedia/math/Frustum.java new file mode 100644 index 0000000..e127cc0 --- /dev/null +++ b/src/ru/olamedia/math/Frustum.java @@ -0,0 +1,127 @@ +package ru.olamedia.math; + +public class Frustum { + public Plane topPlane = new Plane(); + public Plane bottomPlane = new Plane(); + public Plane leftPlane = new Plane(); + public Plane rightPlane = new Plane(); + public Plane nearPlane = new Plane(); + public Plane farPlane = new Plane(); + private Plane[] planes = getPlanes(); + + private Plane[] getPlanes() { + return new Plane[] { leftPlane, rightPlane, topPlane, bottomPlane };// , + // topPlane,, + // topPlane + // bottomPlane, + // leftPlane, + // rightPlane, farPlane }; + } + + public Vector3f[] getVertices() { + Vector3f[] v = new Vector3f[8]; + v[0] = topPlane.cross(leftPlane, nearPlane); + v[1] = topPlane.cross(leftPlane, farPlane); + v[2] = topPlane.cross(rightPlane, nearPlane); + v[3] = topPlane.cross(rightPlane, farPlane); + v[4] = bottomPlane.cross(leftPlane, nearPlane); + v[5] = bottomPlane.cross(leftPlane, farPlane); + v[6] = bottomPlane.cross(rightPlane, nearPlane); + v[7] = bottomPlane.cross(rightPlane, farPlane); + return v; + } + + public int test(Box b) { + return quickClassify(b); + // int out, in = 0, result; + // result = Classifier.INSIDE; + // int pc = 5; + // for (int i = 0; i < 5; i++) { + // Plane plane = planes[i]; + // out = 0; + // in = 0; + // for (int k = 0; k < 8 && (in == 0 || out == 0); k++) { + // if (plane.distance(b.getVertex(k)) > 0) { + // out++; + // } else { + // in++; + // } + // } + // if (out == 8) { + // System.out.println(i); + // return Classifier.OUTSIDE; + // } + // } + // if (in < pc) { + // result = Classifier.INTERSECT; + // } + // // for (int i = 0; i < 6; i++) { + // // for (int k = 0; k < 8 && (in == 0 || out == 0); k++) { + // // if (planes[i].distance(b.getVertex(k)) < 0) { + // // out++; + // // } else { + // // in++; + // // } + // // } + // // } + // // if (in < 1) { + // // return Classifier.OUTSIDE; + // // } else if (out > 0) { + // // result = Classifier.INTERSECT; + // // } + // return result; + } + + private static final boolean isPointInside(Plane plane, Vector3f p) { + return (plane.distance(p) <= 0.0f); + } + + @SuppressWarnings("unused") + private final boolean isPointInside(Vector3f p) { + return isPointInside(topPlane, p) && isPointInside(bottomPlane, p) && isPointInside(leftPlane, p) + && isPointInside(rightPlane, p) && isPointInside(nearPlane, p); + } + + /** + * Quick check to see if an orthogonal bounding box is inside the frustum + */ + public final int quickClassify(Box box) { + // If all vertices is outside of at least one of planes + for (Plane p : planes) { + int in = 0; + @SuppressWarnings("unused") + int out = 0; + for (int i = 0; i < 8; i++) { + Vector3f v = box.getVertex(i); + if (p.distance(v) > 0.0f) { + out++; + } else { + in++; + } + } + if (in < 1) { + return (Classifier.OUTSIDE); + } + } + + return (Classifier.INTERSECT); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "Frustum[\r\n" + // + "Top " + topPlane + "\r\n" + // + "Bottom " + bottomPlane + "\r\n" + // + "Left " + leftPlane + "\r\n" + // + "Right " + rightPlane + "\r\n" + // + "Near " + nearPlane + "\r\n" + // + "Far " + farPlane + "\r\n" + // + "]"; + } + +} diff --git a/src/ru/olamedia/math/FrustumUtil.java b/src/ru/olamedia/math/FrustumUtil.java new file mode 100644 index 0000000..80b01fb --- /dev/null +++ b/src/ru/olamedia/math/FrustumUtil.java @@ -0,0 +1,72 @@ +package ru.olamedia.math; + +public class FrustumUtil { + public static Plane[] extractPlanes(javax.vecmath.Matrix4f m, boolean normalize) { + + Plane[] planes = new Plane[6]; + for (int j = 0; j < 6; j++) { + planes[j] = new Plane(); + } + // Left: [30+00, 31+01, 32+02, 33+03] + + planes[0].n.x = m.m30 + m.m00; + planes[0].n.y = m.m31 + m.m01; + planes[0].n.z = m.m32 + m.m02; + planes[0].d = m.m33 + m.m03; + + // Right: [30-00, 31-01, 32-02, 33-03] + + planes[1].n.x = m.m30 - m.m00; + planes[1].n.y = m.m31 - m.m01; + planes[1].n.z = m.m32 - m.m02; + planes[1].d = m.m33 - m.m03; + + // Bottom: [30+10, 31+11, 32+12, 33+13] + + planes[2].n.x = m.m30 + m.m10; + planes[2].n.y = m.m31 + m.m11; + planes[2].n.z = m.m32 + m.m12; + planes[2].d = m.m33 + m.m13; + + // Top: [30-10, 31-11, 32-12, 33-13] + + planes[3].n.x = m.m30 - m.m10; + planes[3].n.y = m.m31 - m.m11; + planes[3].n.z = m.m32 - m.m12; + planes[3].d = m.m33 - m.m13; + + // Near: [30+20, 31+21, 32+22, 33+23] + + planes[4].n.x = m.m30 + m.m20; + planes[4].n.y = m.m31 + m.m21; + planes[4].n.z = m.m32 + m.m22; + planes[4].d = m.m33 + m.m23; + + // Far: [30-20, 31-21, 32-22, 33-23] + + planes[5].n.x = m.m30 - m.m20; + planes[5].n.y = m.m31 - m.m21; + planes[5].n.z = m.m32 - m.m22; + planes[5].d = m.m33 - m.m23; + + // Normalize + if (normalize) { + for (int i = 0; i < 6; ++i) { + planes[i].normalize(); + } + } + return planes; + } + + public static Frustum extractFrustum(javax.vecmath.Matrix4f m) { + Frustum f = new Frustum(); + Plane[] planes = extractPlanes(m, true); + f.leftPlane.set(planes[0]); + f.rightPlane.set(planes[1]); + f.bottomPlane.set(planes[2]); + f.topPlane.set(planes[3]); + f.nearPlane.set(planes[4]); + f.farPlane.set(planes[5]); + return f; + } +} diff --git a/src/ru/olamedia/math/Halfspace.java b/src/ru/olamedia/math/Halfspace.java new file mode 100644 index 0000000..64834df --- /dev/null +++ b/src/ru/olamedia/math/Halfspace.java @@ -0,0 +1,7 @@ +package ru.olamedia.math; + +public class Halfspace { + public static int NEGATIVE = -1; + public static int ON_PLANE = 0; + public static int POSITIVE = 1; +} diff --git a/src/ru/olamedia/math/Matrix4f.java b/src/ru/olamedia/math/Matrix4f.java new file mode 100644 index 0000000..1ce2eb6 --- /dev/null +++ b/src/ru/olamedia/math/Matrix4f.java @@ -0,0 +1,191 @@ +package ru.olamedia.math; + +import static org.openmali.FastMath.*; + +// 4x4 float matrix, column-major notation +public class Matrix4f { + protected float[] m; + + public Matrix4f() { + m = new float[16]; + } + + public Matrix4f(float[] m) { + this.m = m; + } + + public Matrix4f(javax.vecmath.Matrix4f m2) { + m = new float[16]; + m[0] = m2.m00; + m[1] = m2.m10; + m[2] = m2.m20; + m[3] = m2.m30; + m[4] = m2.m01; + m[5] = m2.m11; + m[6] = m2.m21; + m[7] = m2.m31; + m[8] = m2.m02; + m[9] = m2.m12; + m[10] = m2.m22; + m[11] = m2.m32; + m[12] = m2.m03; + m[13] = m2.m13; + m[14] = m2.m23; + m[15] = m2.m33; + } + + public float[] toFloatArray() { + return m; + } + + public void set(int i, float v) { + m[i] = v; + } + + public float get(int i) { + return m[i]; + } + + public void loadIdentity() { + setIdentity(); + } + + public void setIdentity() { + m[0] = m[5] = m[10] = m[15] = 1.0f; + m[1] = m[2] = m[3] = m[4] = 0.0f; + m[6] = m[7] = m[8] = m[9] = 0.0f; + m[11] = m[12] = m[13] = m[14] = 0.0f; + } + + public static Matrix4f translateMatrix(float x, float y, float z) { + Matrix4f m = new Matrix4f(); + m.setIdentity(); + // Translate slots. + m.set(12, x); + m.set(13, y); + m.set(14, z); + return m; + } + + public static Matrix4f scaleMatrix(float sx, float sy, float sz) { + Matrix4f m = new Matrix4f(); + m.setIdentity(); + // Scale slots. + m.set(0, sx); + m.set(5, sy); + m.set(10, sz); + return m; + } + + public static Matrix4f rotateXMatrix(float degrees) { + float radians = toRad(degrees); + float c = cos(radians); + float s = sin(radians); + Matrix4f m = new Matrix4f(); + m.setIdentity(); + // Rotate X formula. + m.set(5, c); + m.set(6, -s); + m.set(9, s); + m.set(10, c); + return m; + } + + public static Matrix4f rotateYMatrix(float degrees) { + float radians = toRad(degrees); + float c = cos(radians); + float s = sin(radians); + Matrix4f m = new Matrix4f(); + m.setIdentity(); + // Rotate Y formula. + m.set(0, c); + m.set(2, s); + m.set(8, -s); + m.set(10, c); + return m; + } + + public static Matrix4f rotateZMatrix(float degrees) { + float radians = toRad(degrees); + float c = cos(radians); + float s = sin(radians); + Matrix4f m = new Matrix4f(); + m.setIdentity(); + // Rotate Z formula. + m.set(0, c); + m.set(1, s); + m.set(4, -s); + m.set(5, c); + return m; + } + + public Vector3f getUpVector() { + return new Vector3f(m[1], m[5], m[9]); + } + + public Vector3f getLookVector() { // POSITIVE_Z + return new Vector3f(m[2], m[6], m[10]); + } + + public Vector3f getRightVector() { + return new Vector3f(m[0], m[4], m[8]); + } + + public Matrix4f multiply(Matrix4f m) { + return Matrix4fUtil.multiply(this, m); + } + + public void apply(Matrix4f m) { + this.m = multiply(m).toFloatArray(); + } + + public float[] getAngles() { + // TODO check majority + float ax, ay, az; + float cy; + ay = -asin(m[2]); /* Calculate Y-axis angle */ + cy = cos(ay); + ay = toDeg(ay); + float trX, trY; + + if (Math.abs(cy) > 0.005) /* Gimball lock? */ + { + trX = m[10] / cy; /* No, so get X-axis angle */ + trY = -m[6] / cy; + + ax = toDeg(atan2(trY, trX)); + + trX = m[0] / cy; /* Get Z-axis angle */ + trY = -m[1] / cy; + + az = toDeg(atan2(trY, trX)); + } else /* Gimball lock has occurred */ + { + ax = 0; /* Set X-axis angle to zero */ + + trX = m[5]; /* And calculate Z-axis angle */ + trY = m[4]; + + az = toDeg(atan2(trY, trX)); + } + + ax = clamp(ax, 0, 360); /* Clamp all angles to range */ + ay = clamp(ay, 0, 360); + az = clamp(az, 0, 360); + return new float[] { ax, ay, ax }; + } + + private float clamp(float a, float min, float max) { + a = a % max; + return a; + } + + public float c(int column, int row) { + // COLUMN-BASED + return m[column * 4 + row]; + } + + public void set(float[] m) { + this.m = m; + } +} diff --git a/src/ru/olamedia/math/Matrix4fUtil.java b/src/ru/olamedia/math/Matrix4fUtil.java new file mode 100644 index 0000000..46d153e --- /dev/null +++ b/src/ru/olamedia/math/Matrix4fUtil.java @@ -0,0 +1,36 @@ +package ru.olamedia.math; + +public class Matrix4fUtil { + public static Matrix4f multiply(Matrix4f m1, Matrix4f m2) { + return new Matrix4f(multiply(m1.toFloatArray(), m2.toFloatArray())); + } + + // MATRIX MULTIPLICATION + public static float[] multiply(float[] m1, float[] m2) { + float[] result = new float[16]; + // First Column + result[0] = m1[0] * m2[0] + m1[4] * m2[1] + m1[8] * m2[2] + m1[12] * m2[3]; + result[1] = m1[1] * m2[0] + m1[5] * m2[1] + m1[9] * m2[2] + m1[13] * m2[3]; + result[2] = m1[2] * m2[0] + m1[6] * m2[1] + m1[10] * m2[2] + m1[14] * m2[3]; + result[3] = m1[3] * m2[0] + m1[7] * m2[1] + m1[11] * m2[2] + m1[15] * m2[3]; + + // Second Column + result[4] = m1[0] * m2[4] + m1[4] * m2[5] + m1[8] * m2[6] + m1[12] * m2[7]; + result[5] = m1[1] * m2[4] + m1[5] * m2[5] + m1[9] * m2[6] + m1[13] * m2[7]; + result[6] = m1[2] * m2[4] + m1[6] * m2[5] + m1[10] * m2[6] + m1[14] * m2[7]; + result[7] = m1[3] * m2[4] + m1[7] * m2[5] + m1[11] * m2[6] + m1[15] * m2[7]; + + // Third Column + result[8] = m1[0] * m2[8] + m1[4] * m2[9] + m1[8] * m2[10] + m1[12] * m2[11]; + result[9] = m1[1] * m2[8] + m1[5] * m2[9] + m1[9] * m2[10] + m1[13] * m2[11]; + result[10] = m1[2] * m2[8] + m1[6] * m2[9] + m1[10] * m2[10] + m1[14] * m2[11]; + result[11] = m1[3] * m2[8] + m1[7] * m2[9] + m1[11] * m2[10] + m1[15] * m2[11]; + + // Fourth Column + result[12] = m1[0] * m2[12] + m1[4] * m2[13] + m1[8] * m2[14] + m1[12] * m2[15]; + result[13] = m1[1] * m2[12] + m1[5] * m2[13] + m1[9] * m2[14] + m1[13] * m2[15]; + result[14] = m1[2] * m2[12] + m1[6] * m2[13] + m1[10] * m2[14] + m1[14] * m2[15]; + result[15] = m1[3] * m2[12] + m1[7] * m2[13] + m1[11] * m2[14] + m1[15] * m2[15]; + return result; + } +} diff --git a/src/ru/olamedia/math/Plane.java b/src/ru/olamedia/math/Plane.java new file mode 100644 index 0000000..d5cd9d0 --- /dev/null +++ b/src/ru/olamedia/math/Plane.java @@ -0,0 +1,71 @@ +package ru.olamedia.math; + +import static java.lang.Math.sqrt; + +public class Plane { + // normal + public Vector3f n = new Vector3f(); + // distance + public float d; + + public void set(Plane p) { + n.x = p.n.x; + n.y = p.n.y; + n.z = p.n.z; + d = p.d; + } + + public float magnitude() { + return (float) sqrt(n.x * n.x + n.y * n.y + n.z * n.z); + } + + public void normalize() { + float mag = magnitude(); + n.x /= mag; + n.y /= mag; + n.z /= mag; + d /= mag; + } + + public float distance(float x, float y, float z) { + return n.x * x + n.y * y + n.z * z + d; + } + + public float distance(Vector3f point) { + return n.x * point.x + n.y * point.y + n.z * point.z + d; + } + + private float dec(float a) { + return (float) Math.floor(a * 100) / 100; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "Plane[nx=" + dec(n.x) + ";ny=" + dec(n.y) + ";nz=" + dec(n.z) + ";d=" + dec(d) + "]"; + } + + public Vector3f cross(Plane a, Plane b) { + return n.cross(a.n.cross(b.n)); + } + + public void set3Points(Vector3f va, Vector3f vb, Vector3f vc) { + // A = y1 (z2 - z3) + y2 (z3 - z1) + y3 (z1 - z2) + // B = z1 (x2 - x3) + z2 (x3 - x1) + z3 (x1 - x2) + // C = x1 (y2 - y3) + x2 (y3 - y1) + x3 (y1 - y2) + // - D = x1 (y2 z3 - y3 z2) + x2 (y3 z1 - y1 z3) + x3 (y1 z2 - y2 z1) + Vector3f ab = vb.sub(va); + Vector3f ac = vc.sub(va); + Vector3f vn = ab.cross(ac); + n.set(vn); + n.x = va.y * (vb.z - vc.z) + vb.y * (vc.z - va.z) + vc.y * (va.z - vb.z); + n.y = va.z * (vb.x - vc.x) + vb.z * (vc.x - va.x) + vc.z * (va.x - vb.x); + n.z = va.x * (vb.y - vc.y) + vb.x * (vc.y - va.y) + vc.x * (va.y - vb.y); + d = -(vn.x * va.x + vn.y * va.y + vn.z * va.z); + normalize(); + } +} diff --git a/src/ru/olamedia/math/Quaternion.java b/src/ru/olamedia/math/Quaternion.java new file mode 100644 index 0000000..a263f39 --- /dev/null +++ b/src/ru/olamedia/math/Quaternion.java @@ -0,0 +1,25 @@ +package ru.olamedia.math; + +public class Quaternion { + // identity: + public float x = 0; + public float y = 0; + public float z = 0; + public float w = 1; + + public static Quaternion identity() { + return new Quaternion(); + } + + public Quaternion inverse() { + return QuaternionUtil.inverse(this); + } + + public Quaternion mul(Quaternion q) { + return QuaternionUtil.multiply(this, q); + } + + public float[] toMatrixArray(){ + return QuaternionUtil.toMatrixArray(this); + } +} diff --git a/src/ru/olamedia/math/QuaternionUtil.java b/src/ru/olamedia/math/QuaternionUtil.java new file mode 100644 index 0000000..83ee005 --- /dev/null +++ b/src/ru/olamedia/math/QuaternionUtil.java @@ -0,0 +1,54 @@ +package ru.olamedia.math; + +public class QuaternionUtil { + // QUATERNION INVERSE + public static Quaternion inverse(Quaternion q) { + Quaternion newQ = new Quaternion(); + newQ.w = q.w; + newQ.x = -q.x; + newQ.y = -q.y; + newQ.z = -q.z; + // normalize here + return newQ; + } + + // QUATERNION MULTIPLICATION + public static Quaternion multiply(Quaternion q1, Quaternion q2) { + Quaternion newQ = new Quaternion(); + newQ.w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z; + newQ.x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y; + newQ.y = q1.w * q2.y - q1.x * q2.z + q1.y * q2.w + q1.z * q2.x; + newQ.z = q1.w * q2.z + q1.x * q2.y - q1.y * q2.x + q1.z * q2.w; + return newQ; + } + + // QUATERNION-TO-MATRIX, COLUMN-MAJOR NOTATION + public static float[] toMatrixArray(Quaternion q) { + float[] matrix = new float[16]; + // First Column + matrix[0] = 1 - 2 * (q.y * q.y + q.z * q.z); + matrix[1] = 2 * (q.x * q.y + q.z * q.w); + matrix[2] = 2 * (q.x * q.z - q.y * q.w); + matrix[3] = 0; + // Second Column + matrix[4] = 2 * (q.x * q.y - q.z * q.w); + matrix[5] = 1 - 2 * (q.x * q.x + q.z * q.z); + matrix[6] = 2 * (q.z * q.y + q.x * q.w); + matrix[7] = 0; + // Third Column + matrix[8] = 2 * (q.x * q.z + q.y * q.w); + matrix[9] = 2 * (q.y * q.z - q.x * q.w); + matrix[10] = 1 - 2 * (q.x * q.x + q.y * q.y); + matrix[11] = 0; + // Fourth Column + matrix[12] = 0; + matrix[13] = 0; + matrix[14] = 0; + matrix[15] = 1; + return matrix; + } + + public static float magnitude(Quaternion qa) { + return (float) (Math.sqrt((double) (qa.w * qa.w + qa.x * qa.x + qa.y * qa.y + qa.z * qa.z))); + } +} diff --git a/src/ru/olamedia/math/TransformMatrix.java b/src/ru/olamedia/math/TransformMatrix.java new file mode 100644 index 0000000..6f2ea9d --- /dev/null +++ b/src/ru/olamedia/math/TransformMatrix.java @@ -0,0 +1,15 @@ +package ru.olamedia.math; + +public class TransformMatrix extends Matrix4f { + public void applyTranslation(Matrix4f m) { + apply(m); + } + + public void applyRotation(Matrix4f m) { + apply(m); + } + + public void applyScale(Matrix4f m) { + apply(m); + } +} diff --git a/src/ru/olamedia/math/Vector3f.java b/src/ru/olamedia/math/Vector3f.java new file mode 100644 index 0000000..b16a356 --- /dev/null +++ b/src/ru/olamedia/math/Vector3f.java @@ -0,0 +1,70 @@ +package ru.olamedia.math; + +public class Vector3f { + public float x; + public float y; + public float z; + + public Vector3f() { + this(0, 0, 0); + } + + public Vector3f(float x, float y, float z) { + this.x = x; + this.y = y; + this.z = z; + } + + public Vector3f(Vector3f vector) { + this(vector.x, vector.y, vector.z); + } + + public float dot(Vector3f v) { + return (x * v.x + y * v.y + z * v.z); + } + + public Vector3f cross(Vector3f n) { + Vector3f r = new Vector3f(y * n.z - z * n.y, z * n.x - x * n.z, x * n.y - y * n.x); + return r; + } + + public Vector3f add(Vector3f n) { + Vector3f r = new Vector3f(x + n.x, y + n.y, z + n.z); + return r; + } + + public Vector3f sub(Vector3f n) { + return add(n.negate()); + } + + public Vector3f negate() { + Vector3f n = new Vector3f(this); + n.x = -n.x; + n.y = -n.y; + n.z = -n.z; + return n; + } + + public Vector3f translate(Vector3f look, float f) { + Vector3f v = new Vector3f(this); + v.x += look.x * f; + v.y += look.y * f; + v.z += look.z * f; + return v; + } + + public Vector3f translate(javax.vecmath.Vector3f look, float f) { + Vector3f v = new Vector3f(this); + v.x += look.x * f; + v.y += look.y * f; + v.z += look.z * f; + return v; + } + + public void set(Vector3f vn) { + x = vn.x; + y = vn.y; + z = vn.z; + } + +} diff --git a/src/ru/olamedia/math/ViewMatrix.java b/src/ru/olamedia/math/ViewMatrix.java new file mode 100644 index 0000000..dad4778 --- /dev/null +++ b/src/ru/olamedia/math/ViewMatrix.java @@ -0,0 +1,111 @@ +package ru.olamedia.math; + +public class ViewMatrix extends Matrix4f { + private Matrix4f translation = new Matrix4f(); + private Matrix4f scale = new Matrix4f(); + private Matrix4f rotation = new Matrix4f(); + private TransformMatrix transform = new TransformMatrix(); + + public ViewMatrix() { + translation.setIdentity(); + scale.setIdentity(); + rotation.setIdentity(); + transform.setIdentity(); + pack(); + } + + public void pack() { + loadIdentity(); + transform.loadIdentity(); + transform.applyScale(scale); + transform.applyRotation(rotation); + transform.applyTranslation(translation); + apply(transform); + @SuppressWarnings("unused") + float[] t = transform.toFloatArray(); + + // this.m[12] = 0; + // this.m[13] = 0; + // this.m[14] = 0; + // Fill translation: + // this.m[3] = -(t[0] * t[12] + t[1] * t[13] + t[2] * t[14]); + // this.m[7] = -(t[4] * t[12] + t[5] * t[13] + t[6] * t[14]); + // this.m[11] = (t[8] * t[12] + t[9] * t[13] + t[10] * t[14]); + // m[12] = -(t[0] * t[12] + t[1] * t[13] + t[2] * t[14]); + // m[13] = -(t[4] * t[12] + t[5] * t[13] + t[6] * t[14]); + // m[14] = (t[8] * t[12] + t[9] * t[13] + t[10] * t[14]); + } + + public float getX() { + return -translation.get(12); + } + + public float getY() { + return -translation.get(13); + } + + public float getZ() { + return -translation.get(14); + } + + /** + * @return the translation + */ + public Matrix4f getTranslation() { + return translation; + } + + /** + * @param translation + * the translation to set + */ + public void setTranslation(Matrix4f translation) { + this.translation = translation; + } + + /** + * @return the scale + */ + public Matrix4f getScale() { + return scale; + } + + /** + * @param scale + * the scale to set + */ + public void setScale(Matrix4f scale) { + this.scale = scale; + } + + /** + * @return the rotation + */ + public Matrix4f getRotation() { + return rotation; + } + + /** + * @param rotation + * the rotation to set + */ + public void setRotation(Matrix4f rotation) { + this.rotation = rotation; + } + + public void rotateX(float degrees) { + setRotation(getRotation().multiply(Matrix4f.rotateXMatrix(degrees))); + } + + public void rotateY(float degrees) { + setRotation(getRotation().multiply(Matrix4f.rotateYMatrix(degrees))); + } + + public void rotateZ(float degrees) { + setRotation(getRotation().multiply(Matrix4f.rotateZMatrix(degrees))); + } + + public Matrix4f getTransform() { + return transform; + } +} diff --git a/src/ru/olamedia/math/package-info.java b/src/ru/olamedia/math/package-info.java new file mode 100644 index 0000000..82b4066 --- /dev/null +++ b/src/ru/olamedia/math/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.math;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/OlaCraft.java b/src/ru/olamedia/olacraft/OlaCraft.java new file mode 100644 index 0000000..b5b3234 --- /dev/null +++ b/src/ru/olamedia/olacraft/OlaCraft.java @@ -0,0 +1,6 @@ +package ru.olamedia.olacraft; + +public class OlaCraft { + public static String version = "0.1.6"; + +} diff --git a/src/ru/olamedia/olacraft/OlaCraftFrame.java b/src/ru/olamedia/olacraft/OlaCraftFrame.java new file mode 100644 index 0000000..95f1835 --- /dev/null +++ b/src/ru/olamedia/olacraft/OlaCraftFrame.java @@ -0,0 +1,10 @@ +package ru.olamedia.olacraft; + +import ru.olamedia.game.GameFrame; + +public class OlaCraftFrame extends GameFrame { + public OlaCraftFrame() { + super(); + jFrame.setTitle("OlaCraft " + OlaCraft.version); + } +} diff --git a/src/ru/olamedia/olacraft/events/GameEvent.java b/src/ru/olamedia/olacraft/events/GameEvent.java new file mode 100644 index 0000000..94b291c --- /dev/null +++ b/src/ru/olamedia/olacraft/events/GameEvent.java @@ -0,0 +1,32 @@ +package ru.olamedia.olacraft.events; + +public class GameEvent { + public static int GAME_START = GameEventRegistry.get("game.start"); + public static int PLAYER_SPAWN = GameEventRegistry.get("player.spawn"); + private Object source; + private int type; + + public GameEvent(Object source) { + this.setSource(source); + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public Object getSource() { + return source; + } + + public void setSource(Object source) { + this.source = source; + } + + public void dispatch() { + GameEventDispatcher.dispatch(this); + } +} diff --git a/src/ru/olamedia/olacraft/events/GameEventDispatcher.java b/src/ru/olamedia/olacraft/events/GameEventDispatcher.java new file mode 100644 index 0000000..7cae41a --- /dev/null +++ b/src/ru/olamedia/olacraft/events/GameEventDispatcher.java @@ -0,0 +1,22 @@ +package ru.olamedia.olacraft.events; + +import java.util.ArrayList; +import java.util.List; + +public class GameEventDispatcher { + private static List<GameEventListener> listeners = new ArrayList<GameEventListener>(); + + public static void attach(GameEventListener listener) { + listeners.add(listener); + } + + public static void detach(GameEventListener listener) { + listeners.remove(listener); + } + + public static void dispatch(GameEvent e) { + for (GameEventListener l : listeners) { + l.on(e); + } + } +} diff --git a/src/ru/olamedia/olacraft/events/GameEventListener.java b/src/ru/olamedia/olacraft/events/GameEventListener.java new file mode 100644 index 0000000..1ff8185 --- /dev/null +++ b/src/ru/olamedia/olacraft/events/GameEventListener.java @@ -0,0 +1,5 @@ +package ru.olamedia.olacraft.events; + +public interface GameEventListener { + public void on(GameEvent e); +} diff --git a/src/ru/olamedia/olacraft/events/GameEventRegistry.java b/src/ru/olamedia/olacraft/events/GameEventRegistry.java new file mode 100644 index 0000000..a9e1885 --- /dev/null +++ b/src/ru/olamedia/olacraft/events/GameEventRegistry.java @@ -0,0 +1,17 @@ +package ru.olamedia.olacraft.events; + +import java.util.HashMap; + +public class GameEventRegistry { + private static HashMap<String, Integer> map = new HashMap<String, Integer>(); + private static int i = 0; + + public static int get(String name) { + if (map.containsKey(name)) { + return map.get(name); + } + i++; + map.put(name, i); + return i; + } +} diff --git a/src/ru/olamedia/olacraft/events/package-info.java b/src/ru/olamedia/olacraft/events/package-info.java new file mode 100644 index 0000000..2a5a677 --- /dev/null +++ b/src/ru/olamedia/olacraft/events/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.events;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/game/Game.java b/src/ru/olamedia/olacraft/game/Game.java new file mode 100644 index 0000000..0980505 --- /dev/null +++ b/src/ru/olamedia/olacraft/game/Game.java @@ -0,0 +1,106 @@ +package ru.olamedia.olacraft.game; + +import com.jogamp.newt.opengl.GLWindow; + +import ru.olamedia.camera.MatrixCamera; +import ru.olamedia.game.GameFrame; +import ru.olamedia.olacraft.events.GameEvent; +import ru.olamedia.olacraft.network.GameClient; +import ru.olamedia.olacraft.network.GameServer; +import ru.olamedia.olacraft.scene.GameScene; +import ru.olamedia.olacraft.world.dataProvider.AbstractChunkDataProvider; +import ru.olamedia.player.Player; + +public class Game { + public static Game instance = null; + public static int port = 26002; + public static boolean isServerRunning = false; + public static GameServer server = new GameServer(); + public static GameClient client = new GameClient(); + public static Timer timer = new Timer(); + + public MatrixCamera camera; + + public static int MODE_SINGLEPLAYER = 1; + public static int MODE_MULTIPLAYER = 2; + public static int MODE_SERVER = 4; + @SuppressWarnings("unused") + private int mode = 1; + private boolean isRunning = false; + @SuppressWarnings("unused") + // player + public Player player; + + // block world + // private blockWorld; + // live entities (including player and npcs) + // private liveEntities; + public Game() { + this(MODE_SINGLEPLAYER); + } + + public Game(int mode) { + this.mode = mode; + if ((MODE_MULTIPLAYER & mode) > 0) { + if ((MODE_SERVER & mode) > 0) { + // init server + } else { + // init client + } + } + player = new Player(); + camera = new MatrixCamera(); + camera.attachTo(player); + camera.setFov(90); + camera.pack(); + // scene.registerLiveEntity(player); + } + + public void start() { + isRunning = true; + GameEvent e = new GameEvent(null); + e.setType(GameEvent.GAME_START); + e.dispatch(); + } + + // Pause game in single mode + public void pause() { + + } + + public void stop() { + + } + + public boolean isRunning() { + return isRunning; + } + + public void spawnMe(int x, int y, int z) { + player.setLocation(x, y, z); + } + + public void tick() { + timer.update(); + + } + + public static class Display { + public static int getWidth() { + return (int) GameFrame.getWidth(); + } + + public static int getHeight() { + return (int) GameFrame.getHeight(); + } + + public static float getAspect() { + return ((float) getWidth()) / ((float) getHeight()); + } + } + + public float getDelta() { + return (float) timer.getElapsedTime() / 1000; + } + +} diff --git a/src/ru/olamedia/olacraft/game/GameInterface.java b/src/ru/olamedia/olacraft/game/GameInterface.java new file mode 100644 index 0000000..1f02071 --- /dev/null +++ b/src/ru/olamedia/olacraft/game/GameInterface.java @@ -0,0 +1,7 @@ +package ru.olamedia.olacraft.game; + +public class GameInterface { + public void requestSpawn(){ + + } +} diff --git a/src/ru/olamedia/olacraft/game/IGameWrapper.java b/src/ru/olamedia/olacraft/game/IGameWrapper.java new file mode 100644 index 0000000..a4a7ed1 --- /dev/null +++ b/src/ru/olamedia/olacraft/game/IGameWrapper.java @@ -0,0 +1,7 @@ +package ru.olamedia.olacraft.game; + +public interface IGameWrapper { + public void setMyId(int connectionId); + + public void spawn(int connectionId, int x, int y, int z); +} diff --git a/src/ru/olamedia/olacraft/game/LocalGameWrapper.java b/src/ru/olamedia/olacraft/game/LocalGameWrapper.java new file mode 100644 index 0000000..8c19ce6 --- /dev/null +++ b/src/ru/olamedia/olacraft/game/LocalGameWrapper.java @@ -0,0 +1,17 @@ +package ru.olamedia.olacraft.game; + +public class LocalGameWrapper implements IGameWrapper { + + @Override + public void setMyId(int connectionId) { + // TODO Auto-generated method stub + + } + + @Override + public void spawn(int connectionId, int x, int y, int z) { + // TODO Auto-generated method stub + + } + +} diff --git a/src/ru/olamedia/olacraft/game/SpawnLocation.java b/src/ru/olamedia/olacraft/game/SpawnLocation.java new file mode 100644 index 0000000..2ff0c39 --- /dev/null +++ b/src/ru/olamedia/olacraft/game/SpawnLocation.java @@ -0,0 +1,7 @@ +package ru.olamedia.olacraft.game; + +public class SpawnLocation { + public int x; + public int y; + public int z; +} diff --git a/src/ru/olamedia/olacraft/game/Timer.java b/src/ru/olamedia/olacraft/game/Timer.java new file mode 100644 index 0000000..1c0aaee --- /dev/null +++ b/src/ru/olamedia/olacraft/game/Timer.java @@ -0,0 +1,99 @@ +package ru.olamedia.olacraft.game; + +/** + * For frame-rate independent movement + * + * @author Oskar Veerhoek + */ +public class Timer { + private long lastTime; // nanoseconds + private double elapsedTime; + private float fps; + private int fpsCounter = 0; + private long lastFPS; + private float avgSeconds = 3; + + /** + * @return the fps + */ + public float getFps() { + return fps; + } + + /** + * @return the avgFps + */ + public float getAvgFps() { + return avgFps; + } + + private float avgFps; + + /** + * Creates a timer. + */ + public Timer() { + fps = 0; + } + + /** + * Initializes the timer. Call this just before entering the game loop. + */ + public void initialize() { + lastTime = System.nanoTime(); + } + + /** + * @return the elapsed time since the the next to last update call + */ + public double getElapsedTime() { + return elapsedTime; + } + + /** + * Updates the timer. Call this once every iteration of the game loop. + * + * @return the elapsed time in milliseconds + */ + public double update() { + if (lastTime == 0) { + lastTime = System.nanoTime(); + return 0; + } else { + long elapsedTime = System.nanoTime() - lastTime; + updateFps(elapsedTime); + lastTime = System.nanoTime(); + this.elapsedTime = elapsedTime / (double) 1000000; + return this.elapsedTime; + } + } + + public void updateFps(long elapsedTime) { + if (elapsedTime > 0) { + float ms = (float) (elapsedTime / 1000000); + if (ms > 0) { + fps = (float) (1000 / ms); + } + } + fpsCounter++; + if (lastFPS == 0) { + lastFPS = System.nanoTime(); + } else { + double elapsedFPS = (System.nanoTime() - lastFPS) / (double) 1000000; + if (elapsedFPS > 1000 * avgSeconds) { + avgFps = fpsCounter / avgSeconds; + fpsCounter = 0; + lastFPS = System.nanoTime(); + } + } + + // if (elapsedTime > 0) { + // fps = (float) (1000 / (elapsedTime / 1000000)); + // if (avgFps == 0) { + // avgFps = fps; + // } else { + // avgFps = avgFps + (fps - avgFps) / 1000; + // } + // } + } +}
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/game/package-info.java b/src/ru/olamedia/olacraft/game/package-info.java new file mode 100644 index 0000000..85b0f16 --- /dev/null +++ b/src/ru/olamedia/olacraft/game/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.game;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/inventory/Frame.java b/src/ru/olamedia/olacraft/inventory/Frame.java new file mode 100644 index 0000000..a5cd979 --- /dev/null +++ b/src/ru/olamedia/olacraft/inventory/Frame.java @@ -0,0 +1,44 @@ +package ru.olamedia.olacraft.inventory; + +import org.olamedia.olacraft.draw.DrawInterface; +import org.olamedia.olacraft.entity.AbstractEntity; + +import static org.olamedia.olacraft.blocks.Block.BLOCK_SIZE; +import org.olamedia.olacraft.util.CommonApi; + +public class Frame extends AbstractEntity implements DrawInterface { + public Frame(double x, double y, double z, double width, double height, + double depth) { + super(x, y, z, width, height, depth); + } + + public CommonApi api = CommonApi.instance; + + @Override + public void update(double delta) { + + } + + @Override + public void draw() { + api.draw.texRecti("inventory_frame", x, y, BLOCK_SIZE, BLOCK_SIZE); + return; + // Texture t = api.texture.get("inventory_frame"); + // t.bind(); + // glColor3f(1, 1, 1); + // glLoadIdentity(); + // glTranslated(x, y, 0); + // glBegin(GL_QUADS); + // glTexCoord2f(0, 0); + // glVertex2f(0, 0); // Upper-left + // glTexCoord2f(1, 0); + // glVertex2f(BLOCK_SIZE, 0); // Upper-right + // glTexCoord2f(1, 1); + // glVertex2f(BLOCK_SIZE, BLOCK_SIZE); // Bottom-right + // glTexCoord2f(0, 1); + // glVertex2f(0, BLOCK_SIZE); // Bottom-left + // glEnd(); + // glLoadIdentity(); + } + +} diff --git a/src/ru/olamedia/olacraft/inventory/Inventory.java b/src/ru/olamedia/olacraft/inventory/Inventory.java new file mode 100644 index 0000000..2ce843b --- /dev/null +++ b/src/ru/olamedia/olacraft/inventory/Inventory.java @@ -0,0 +1,76 @@ +package ru.olamedia.olacraft.inventory; + +import ru.olamedia.olacraft.world.block.Block; +import ru.olamedia.olacraft.world.blockStack.BlockStack; + +public class Inventory { + public static int BIND_NUM = 10; + public BlockStack[] binded = new BlockStack[BIND_NUM]; + public BlockStack selected; + public int selectedId; + private boolean isInventoryGUIOpen = false; + + public Inventory() { + } + + public void init() { + for (int i = 0; i < BIND_NUM; i++) { + Block block = new Block(x + bindedWrapperPadding + i * BLOCK_SIZE + bindedSpacing * i, y + + bindedWrapperPadding + 0, 0, "gravel"); + binded[i] = new BlockStack(block, 64); + } + binded[0].block.setName("dirt"); + binded[1].block.setName("grass"); + binded[2].block.setName("water"); + binded[3].block.setName("wood"); + binded[4].block.setName("asphalt"); + binded[5].block.setName("torch"); + binded[8].block.setName("grass"); + binded[9].block.setName("dirt"); + frame = new Frame(0, 0, 0, BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE); + select(0); + } + + public void onKeyDown() { + // System.out.println("keyName: " + api.keyboard.keyName); + int key = Keyboard.getEventKey(); + if (key == Keyboard.KEY_1) { + select(0); + } + if (key == Keyboard.KEY_2) { + select(1); + } + if (key == Keyboard.KEY_3) { + select(2); + } + if (key == Keyboard.KEY_4) { + select(3); + } + if (key == Keyboard.KEY_5) { + select(4); + } + if (key == Keyboard.KEY_6) { + select(5); + } + if (key == Keyboard.KEY_7) { + select(6); + } + if (key == Keyboard.KEY_8) { + select(7); + } + if (key == Keyboard.KEY_9) { + select(8); + } + if (key == Keyboard.KEY_0) { + select(9); + } + if (key == Keyboard.KEY_E) { + isInventoryGUIOpen = !isInventoryGUIOpen; + } + + } + + public void select(int i) { + selected = binded[i]; + } +} diff --git a/src/ru/olamedia/olacraft/inventory/package-info.java b/src/ru/olamedia/olacraft/inventory/package-info.java new file mode 100644 index 0000000..fe2b1fc --- /dev/null +++ b/src/ru/olamedia/olacraft/inventory/package-info.java @@ -0,0 +1,9 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.inventory; + diff --git a/src/ru/olamedia/olacraft/network/ConnectionState.java b/src/ru/olamedia/olacraft/network/ConnectionState.java new file mode 100644 index 0000000..2d6c5c5 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/ConnectionState.java @@ -0,0 +1,17 @@ +package ru.olamedia.olacraft.network; + +public class ConnectionState { + private int state; + + public ConnectionState(int state) { + this.state = state; + } + + public static ConnectionState STATE_DISCONNECTED = new ConnectionState(0); + public static ConnectionState STATE_CONNECTED = new ConnectionState(1); + public static ConnectionState STATE_CONNECTING = new ConnectionState(2); + + public boolean isConnected() { + return state == 1; + } +} diff --git a/src/ru/olamedia/olacraft/network/ConnectionStateListener.java b/src/ru/olamedia/olacraft/network/ConnectionStateListener.java new file mode 100644 index 0000000..6220029 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/ConnectionStateListener.java @@ -0,0 +1,7 @@ +package ru.olamedia.olacraft.network; + +public class ConnectionStateListener { + public void onChangeState(ConnectionState state){ + // override + } +} diff --git a/src/ru/olamedia/olacraft/network/GameClient.java b/src/ru/olamedia/olacraft/network/GameClient.java new file mode 100644 index 0000000..669d954 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/GameClient.java @@ -0,0 +1,209 @@ +package ru.olamedia.olacraft.network; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import com.esotericsoftware.kryo.Kryo; +import com.esotericsoftware.kryonet.Client; +import com.esotericsoftware.kryonet.Connection; +import com.esotericsoftware.kryonet.Listener; + +import ru.olamedia.game.GameManager; +import ru.olamedia.liveEntity.LiveEntity; +import ru.olamedia.olacraft.game.Game; +import ru.olamedia.olacraft.network.packet.ConnectionPacket; +import ru.olamedia.olacraft.network.packet.ConnectionRequestPacket; +import ru.olamedia.olacraft.network.packet.IPacket; +import ru.olamedia.olacraft.network.packet.IPacketListener; +import ru.olamedia.olacraft.network.packet.LiveEntityLocationUpdatePacket; +import ru.olamedia.olacraft.network.packet.SpawnPacket; +import ru.olamedia.olacraft.network.packet.SpawnRequestPacket; +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.RemoteChunkDataProvider; +import ru.olamedia.olacraft.world.provider.WorldProvider; + +public class GameClient extends ConnectionStateListener implements IPacketListener { + private WorldProvider worldProvider; + private GameScene scene; + + private Client client = new Client(70 * 1024 * 1024, 70 * 1024 * 1024); + private String hostname = "127.0.0.1"; + + @Override + public void onChangeState(ConnectionState state) { + if (state.isConnected()) { + GameManager.instance.hideMainMenu(); + client.sendTCP(new ConnectionRequestPacket()); + // + // provider.load(0, 0, 0); + // provider.load(1, 2, 3); + } + } + + /* + * public AbstractChunkDataProvider getChunkDataProvider() { + * return worldProvider.getChunkDataProvider(); + * } + */ + + public WorldProvider getWorldProvider() { + return worldProvider; + } + + private List<ConnectionStateListener> stateListeners = new ArrayList<ConnectionStateListener>(); + private List<IPacketListener> packetListeners = new ArrayList<IPacketListener>(); + private ExecutorService threadPool = Executors.newFixedThreadPool(1); + + public GameClient() { + // INIT WORLD + worldProvider = new WorldProvider(); + worldProvider.setChunkDataProvider(new CachedChunkDataProvider(new RemoteChunkDataProvider(this))); + // CREATE SCENE + scene = new GameScene(worldProvider); + Kryo kryo = client.getKryo(); + Network.registerPackets(kryo); + addStateListener(this); + addPacketListener(this); + client.addListener(new Listener.ThreadedListener(new Listener() { + + @Override + public void received(Connection connection, Object object) { + if (object instanceof IPacket) { + dispatchPacket(connection, (IPacket) object); + } + } + + @Override + public void disconnected(Connection connection) { + super.disconnected(connection); + dispatchState(ConnectionState.STATE_DISCONNECTED); + } + }, threadPool)); + client.start(); + } + + public void addStateListener(ConnectionStateListener listener) { + stateListeners.add(listener); + } + + private void dispatchState(ConnectionState state) { + for (ConnectionStateListener l : stateListeners) { + l.onChangeState(state); + } + } + + private void dispatchPacket(Connection connection, IPacket p) { + for (IPacketListener l : packetListeners) { + l.onPacket(connection, p); + } + } + + public void connect() { + new Thread("Connect") { + public void run() { + try { + dispatchState(ConnectionState.STATE_CONNECTING); + client.connect(5000, hostname, Game.port); + dispatchState(ConnectionState.STATE_CONNECTED); + } catch (IOException ex) { + dispatchState(ConnectionState.STATE_DISCONNECTED); + } + } + }.start(); + } + + public void close() { + client.close(); + } + + public void send(IPacket p) { + client.sendTCP(p); + } + + public void addPacketListener(IPacketListener listener) { + packetListeners.add(listener); + } + + public boolean isConnected() { + return client.isConnected(); + } + + private static boolean DEBUG = true; + + private void debug(String s) { + if (DEBUG) { + System.out.println("[GameClient] " + s); + } + } + + @Override + public void onPacket(Connection connection, IPacket p) { + debug("received " + p.getClass().getName()); + // 1. receive ConnectionPacket, send SpawnRequestPacket + if (p instanceof ConnectionPacket) { + Game.instance.player.setConnectionId(((ConnectionPacket) p).connectionId); + send(new SpawnRequestPacket()); + } + if (p instanceof WorldInfoPacket) { + worldProvider.setInfo(((WorldInfoPacket) p).info); + } + // 2. Receive SpawnPacket + if (p instanceof SpawnPacket) { + LiveEntity entity; + if (((SpawnPacket) p).connectionId == client.getID()) { + // me + entity = Game.instance.player; + } else { + // another player + entity = new LiveEntity(); + } + entity.setX(((SpawnPacket) p).x); + entity.setY(((SpawnPacket) p).y); + entity.setZ(((SpawnPacket) p).z); + entity.setConnectionId(((SpawnPacket) p).connectionId); + scene.registerLiveEntity(entity); + if (((SpawnPacket) p).connectionId == client.getID()) { + // me + scene.registerPlayer(entity); + } + } + if (p instanceof LiveEntityLocationUpdatePacket) { + LiveEntity entity = scene.getLiveEntity(((LiveEntityLocationUpdatePacket) p).connectionId); + if (null != entity) { + entity.setX(((LiveEntityLocationUpdatePacket) p).x); + entity.setY(((LiveEntityLocationUpdatePacket) p).y); + entity.setZ(((LiveEntityLocationUpdatePacket) p).z); + } + } + } + + public String getHostname() { + return hostname; + } + + public void setHostname(String hostname) { + this.hostname = hostname; + } + + public void dispose() { + client.close(); + client.stop(); + // threadPool.awaitTermination(1000, TimeUnit.MILLISECONDS); + threadPool.shutdownNow(); + } + + public GameScene getScene() { + return scene; + } + + public WorldInfo getWorldInfo() { + return worldProvider.getInfo(); + } + +} diff --git a/src/ru/olamedia/olacraft/network/GameServer.java b/src/ru/olamedia/olacraft/network/GameServer.java new file mode 100644 index 0000000..67dffc5 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/GameServer.java @@ -0,0 +1,169 @@ +package ru.olamedia.olacraft.network; + +import java.io.IOException; +import java.net.BindException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import ru.olamedia.liveEntity.LiveEntity; +import ru.olamedia.olacraft.game.Game; +import ru.olamedia.olacraft.game.SpawnLocation; +import ru.olamedia.olacraft.network.discovery.DiscoveryThread; +import ru.olamedia.olacraft.network.packet.ConnectionPacket; +import ru.olamedia.olacraft.network.packet.ConnectionRequestPacket; +import ru.olamedia.olacraft.network.packet.GetRegionPacket; +import ru.olamedia.olacraft.network.packet.IPacket; +import ru.olamedia.olacraft.network.packet.LiveEntityLocationUpdatePacket; +import ru.olamedia.olacraft.network.packet.RegionDataPacket; +import ru.olamedia.olacraft.network.packet.SpawnPacket; +import ru.olamedia.olacraft.network.packet.SpawnRequestPacket; +import ru.olamedia.olacraft.network.packet.WorldInfoPacket; +import ru.olamedia.olacraft.scene.GameScene; +import ru.olamedia.olacraft.world.data.RegionData; +import ru.olamedia.olacraft.world.dataProvider.CachedChunkDataProvider; +import ru.olamedia.olacraft.world.dataProvider.LocalChunkDataProvider; +import ru.olamedia.olacraft.world.provider.WorldProvider; + +import com.esotericsoftware.kryo.Kryo; +import com.esotericsoftware.kryonet.Connection; +import com.esotericsoftware.kryonet.Listener; +import com.esotericsoftware.kryonet.Server; + +public class GameServer { + private WorldProvider worldProvider; + + private ExecutorService threadPool = Executors.newFixedThreadPool(1); + public static Server server = new Server(70 * 1024 * 1024, 1024 * 1024) { + @Override + protected PlayerConnection newConnection() { + // By providing our own connection implementation, we can store per + // connection state without a connection ID to state look up. + return new PlayerConnection(); + } + }; + private boolean isServerRunning = false; + + private GameScene scene; + + private static boolean DEBUG = true; + + private void debug(String s) { + if (DEBUG) { + System.out.println("[GameServer] " + s); + } + } + + public GameServer() { + // INIT WORLD + worldProvider = new WorldProvider(); + worldProvider.setChunkDataProvider(new CachedChunkDataProvider(new LocalChunkDataProvider(worldProvider.getInfo().name))); + // CREATE SCENE + scene = new GameScene(worldProvider); + // worldProvider.getInfo().name = "world"; + Kryo kryo = server.getKryo(); + Network.registerPackets(kryo); + server.addListener(new Listener.ThreadedListener(new Listener() { + @Override + public void disconnected(Connection connection) { + } + + @Override + public void received(Connection connection, Object object) { + debug("received " + object.getClass()); + if (object instanceof ConnectionRequestPacket) { + ConnectionPacket p = new ConnectionPacket(); + p.connectionId = connection.getID(); + server.sendToTCP(connection.getID(), p); + } + if (object instanceof GetRegionPacket) { + GetRegionPacket p = (GetRegionPacket) object; + RegionData data = worldProvider.getRegion(p.location); + RegionDataPacket response = new RegionDataPacket(); + response.data = data; + server.sendToTCP(connection.getID(), response); + } + if (object instanceof SpawnRequestPacket) { + SpawnLocation loc = worldProvider.getSpawnLocation(connection.getID()); + if (null != loc) { + server.sendToTCP(connection.getID(), new WorldInfoPacket(worldProvider)); + LiveEntity entity = new LiveEntity(); + entity.setX(loc.x); + entity.setY(loc.y); + entity.setZ(loc.z); + entity.setConnectionId(connection.getID()); + scene.registerLiveEntity(entity); + // send all entity locations + for (LiveEntity nextEntity : scene.getLiveEntities().values()) { + SpawnPacket p = new SpawnPacket(); + p.x = nextEntity.getX(); + p.y = nextEntity.getY(); + p.z = nextEntity.getZ(); + p.connectionId = nextEntity.getConnectionId(); + if (p.connectionId == connection.getID()) { + server.sendToAllTCP(p); + } else { + server.sendToTCP(connection.getID(), p); + } + } + } + } + if (object instanceof LiveEntityLocationUpdatePacket) { + LiveEntityLocationUpdatePacket p = ((LiveEntityLocationUpdatePacket) object); + p.connectionId = connection.getID(); + LiveEntity entity = scene.getLiveEntity(connection.getID()); + if (null != entity) { + entity.setLocation(p.x, p.y, p.z); + server.sendToAllTCP(object); + } + } + + // super.received(connection, object); + } + }, threadPool)); + } + + private DiscoveryThread discovery; + + public void start() { + try { + server.start(); + server.bind(Game.port); + discovery = new DiscoveryThread("SERVER DISCOVERY"); + discovery.start(); + isServerRunning = true; + // server.addListener(new Listener()); + } catch (BindException ex) { + server.stop(); + if (null != discovery && discovery.isAlive()) { + discovery.interrupt(); + } + isServerRunning = false; + } catch (IOException e1) { + server.stop(); + if (null != discovery && discovery.isAlive()) { + discovery.interrupt(); + } + e1.printStackTrace(); + isServerRunning = false; + } + } + + public void stop() { + server.close(); + server.stop(); + isServerRunning = false; + } + + public boolean isRunning() { + return isServerRunning; + } + + public void send(IPacket p) { + } + + public void dispose() { + stop(); + // threadPool.awaitTermination(1000, TimeUnit.MILLISECONDS); + threadPool.shutdownNow(); + } +} diff --git a/src/ru/olamedia/olacraft/network/Network.java b/src/ru/olamedia/olacraft/network/Network.java new file mode 100644 index 0000000..2ba8eab --- /dev/null +++ b/src/ru/olamedia/olacraft/network/Network.java @@ -0,0 +1,71 @@ +package ru.olamedia.olacraft.network; + +import java.util.BitSet; + +import ru.olamedia.olacraft.network.packet.ChunkDataPacket; +import ru.olamedia.olacraft.network.packet.ConnectionPacket; +import ru.olamedia.olacraft.network.packet.ConnectionRequestPacket; +import ru.olamedia.olacraft.network.packet.GetChunkDataPacket; +import ru.olamedia.olacraft.network.packet.GetRegionPacket; +import ru.olamedia.olacraft.network.packet.LiveEntityLocationUpdatePacket; +import ru.olamedia.olacraft.network.packet.RegionDataPacket; +import ru.olamedia.olacraft.network.packet.SpawnPacket; +import ru.olamedia.olacraft.network.packet.SpawnRequestPacket; +import ru.olamedia.olacraft.network.packet.WorldInfoPacket; +import ru.olamedia.olacraft.world.WorldInfo; +import ru.olamedia.olacraft.world.data.ChunkData; +import ru.olamedia.olacraft.world.data.ChunkLightData; +import ru.olamedia.olacraft.world.data.HeightMap; +import ru.olamedia.olacraft.world.data.RegionData; +import ru.olamedia.olacraft.world.data.SectorData; +import ru.olamedia.olacraft.world.location.BlockLocation; +import ru.olamedia.olacraft.world.location.ChunkLocation; +import ru.olamedia.olacraft.world.location.RegionLocation; +import ru.olamedia.olacraft.world.location.SectorLocation; + +import com.esotericsoftware.kryo.Kryo; + +public class Network { + public static void registerPackets(Kryo kryo) { + // types + kryo.register(boolean.class); + kryo.register(boolean[].class); + kryo.register(byte.class); + kryo.register(byte[].class); + kryo.register(byte[][].class); + kryo.register(int.class); + kryo.register(int[].class); + kryo.register(float.class); + kryo.register(float[].class); + kryo.register(long.class); + kryo.register(long[].class); + kryo.register(BitSet.class); + kryo.register(HeightMap.class); + kryo.register(WorldInfo.class); + kryo.register(WorldInfoPacket.class); + kryo.register(BlockLocation.class); + kryo.register(ChunkLocation.class); + kryo.register(SectorLocation.class); + kryo.register(RegionLocation.class); + kryo.register(ChunkData.class); + kryo.register(ChunkData[].class); + kryo.register(SectorData.class); + kryo.register(SectorData[].class); + kryo.register(SectorData[][].class); + 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); + } +} diff --git a/src/ru/olamedia/olacraft/network/PlayerConnection.java b/src/ru/olamedia/olacraft/network/PlayerConnection.java new file mode 100644 index 0000000..3120b4d --- /dev/null +++ b/src/ru/olamedia/olacraft/network/PlayerConnection.java @@ -0,0 +1,9 @@ +package ru.olamedia.olacraft.network; + +import ru.olamedia.liveEntity.LiveEntity; + +import com.esotericsoftware.kryonet.Connection; + +public class PlayerConnection extends Connection{ + public LiveEntity entity; +} diff --git a/src/ru/olamedia/olacraft/network/discovery/DiscoveryClient.java b/src/ru/olamedia/olacraft/network/discovery/DiscoveryClient.java new file mode 100644 index 0000000..629e6e3 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/discovery/DiscoveryClient.java @@ -0,0 +1,143 @@ +package ru.olamedia.olacraft.network.discovery; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.InterfaceAddress; +import java.net.NetworkInterface; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +import ru.olamedia.tasks.Task; + +public class DiscoveryClient extends Task { + private static DatagramSocket c; + public static List<InetAddress> list = new ArrayList<InetAddress>(); + private static List<DiscoveryListener> listeners = new ArrayList<DiscoveryListener>(); + + public void addHostListener(DiscoveryListener listener) { + listeners.add(listener); + } + + public static void discovery() { + list.clear(); + try { + list.add(InetAddress.getByName("127.0.0.1")); + } catch (UnknownHostException e1) { + e1.printStackTrace(); + } + // Find the server using UDP broadcast + try { + // Open a random port to send the package + c = new DatagramSocket(); + c.setBroadcast(true); + c.setSoTimeout(3000); + + byte[] sendData = "DISCOVER_OLACRAFTSERVER_REQUEST".getBytes(); + + // Try the 255.255.255.255 first + try { + DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, + InetAddress.getByName("255.255.255.255"), DiscoveryThread.port); + c.send(sendPacket); + System.out.println(DiscoveryClient.class.getName() + + ">>> Request packet sent to: 255.255.255.255 (DEFAULT)"); + } catch (Exception e) { + } + + // Broadcast the message over all the network interfaces + @SuppressWarnings("rawtypes") + Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); + while (interfaces.hasMoreElements()) { + NetworkInterface networkInterface = (NetworkInterface) interfaces.nextElement(); + + if (networkInterface.isLoopback() || !networkInterface.isUp()) { + continue; // Don't want to broadcast to the loopback + // interface + } + + for (InterfaceAddress interfaceAddress : networkInterface.getInterfaceAddresses()) { + InetAddress broadcast = interfaceAddress.getBroadcast(); + if (broadcast == null) { + continue; + } + + // Send the broadcast package! + try { + DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, broadcast, 8888); + c.send(sendPacket); + } catch (Exception e) { + } + + System.out.println(DiscoveryClient.class.getName() + ">>> Request packet sent to: " + + broadcast.getHostAddress() + "; Interface: " + networkInterface.getDisplayName()); + } + } + + System.out.println(DiscoveryClient.class.getName() + + ">>> Done looping over all network interfaces. Now waiting for a reply!"); + while (true) { + // Wait for a response + byte[] recvBuf = new byte[15000]; + DatagramPacket receivePacket = new DatagramPacket(recvBuf, recvBuf.length); + c.receive(receivePacket); + + // We have a response + System.out.println(DiscoveryClient.class.getName() + ">>> Broadcast response from server: " + + receivePacket.getAddress().getHostAddress()); + + // Check if the message is correct + String message = new String(receivePacket.getData()).trim(); + if (message.equals("DISCOVER_OLACRAFTSERVER_RESPONSE")) { + list.add(receivePacket.getAddress()); + for (DiscoveryListener l : listeners) { + l.onHost(receivePacket.getAddress()); + } + // DO SOMETHING WITH THE SERVER'S IP (for example, store it + // in + // your controller) + // Controller_Base.setServerIp(receivePacket.getAddress()); + } + } + } catch (SocketTimeoutException ex) { + // no hosts were discovered + } catch (IOException ex) { + // no hosts were discovered + } finally { + // Close the port! + if (null != c) { + c.close(); + } + for (DiscoveryListener l : listeners) { + l.onHost(null); // end of list marker + } + } + } + + @Override + public void run() { +// while (!shouldStop()) { + discovery(); + // try { + // wait(3000); + // } catch (InterruptedException e) { + // e.printStackTrace(); + // } + // } + } + + public void refresh() { + } + + public static DiscoveryClient getInstance() { + return DiscoveryThreadHolder.INSTANCE; + } + + private static class DiscoveryThreadHolder { + private static final DiscoveryClient INSTANCE = new DiscoveryClient(); + } +} diff --git a/src/ru/olamedia/olacraft/network/discovery/DiscoveryListener.java b/src/ru/olamedia/olacraft/network/discovery/DiscoveryListener.java new file mode 100644 index 0000000..81c1019 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/discovery/DiscoveryListener.java @@ -0,0 +1,9 @@ +package ru.olamedia.olacraft.network.discovery; + +import java.net.InetAddress; + +public class DiscoveryListener { + public void onHost(InetAddress address){ + + } +} diff --git a/src/ru/olamedia/olacraft/network/discovery/DiscoveryThread.java b/src/ru/olamedia/olacraft/network/discovery/DiscoveryThread.java new file mode 100644 index 0000000..a6302fa --- /dev/null +++ b/src/ru/olamedia/olacraft/network/discovery/DiscoveryThread.java @@ -0,0 +1,91 @@ +package ru.olamedia.olacraft.network.discovery; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; + +public class DiscoveryThread extends Thread { + public DiscoveryThread() { + super(); + try { + socket = new DatagramSocket(port, InetAddress.getByName("0.0.0.0")); + socket.setBroadcast(true); + socket.setSoTimeout(1000); + } catch (SocketException e) { + e.printStackTrace(); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + } + + public DiscoveryThread(String name) { + this(); + setName(name); + } + + private DatagramSocket socket; + public static int port = 26003; + + @Override + public void run() { + try { + System.out.println(getClass().getName() + ">>>Ready to receive broadcast packets!"); + while (true) { + + // Receive a packet + byte[] recvBuf = new byte[15000]; + DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length); + try { + socket.receive(packet); + + // Packet received + System.out.println(getClass().getName() + ">>>Discovery packet received from: " + + packet.getAddress().getHostAddress()); + System.out.println(getClass().getName() + ">>>Packet received; data: " + + new String(packet.getData())); + + // See if the packet holds the right command (message) + String message = new String(packet.getData()).trim(); + if (message.equals("DISCOVER_OLACRAFTSERVER_REQUEST")) { + byte[] sendData = "DISCOVER_OLACRAFTSERVER_RESPONSE".getBytes(); + + // Send a response + DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, packet.getAddress(), + packet.getPort()); + socket.send(sendPacket); + + System.out.println(getClass().getName() + ">>>Sent packet to: " + + sendPacket.getAddress().getHostAddress()); + } + } catch (SocketTimeoutException ex) { + + } + try { + Thread.sleep(100); + } catch (IllegalMonitorStateException ex) { + ex.printStackTrace(); + } catch (InterruptedException ex) { + socket.close(); + Thread.currentThread().interrupt(); // very important + break; + } + } + } catch (IOException ex) { + socket.close(); + } + } + + public static DiscoveryThread getInstance() { + return DiscoveryThreadHolder.INSTANCE; + } + + private static class DiscoveryThreadHolder { + + private static final DiscoveryThread INSTANCE = new DiscoveryThread(); + } + +} diff --git a/src/ru/olamedia/olacraft/network/discovery/package-info.java b/src/ru/olamedia/olacraft/network/discovery/package-info.java new file mode 100644 index 0000000..cb376c8 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/discovery/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.network.discovery;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/network/package-info.java b/src/ru/olamedia/olacraft/network/package-info.java new file mode 100644 index 0000000..dfbaec9 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/package-info.java @@ -0,0 +1,9 @@ +/** + * + */ +/** + * Used KryoNet library (Which is under BSD License) + * @author olamedia + * + */ +package ru.olamedia.olacraft.network;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/network/packet/ChatMessagePacket.java b/src/ru/olamedia/olacraft/network/packet/ChatMessagePacket.java new file mode 100644 index 0000000..332c9dd --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/ChatMessagePacket.java @@ -0,0 +1,5 @@ +package ru.olamedia.olacraft.network.packet; + +public class ChatMessagePacket implements IPacket { + public String message; +} diff --git a/src/ru/olamedia/olacraft/network/packet/ChunkDataPacket.java b/src/ru/olamedia/olacraft/network/packet/ChunkDataPacket.java new file mode 100644 index 0000000..1bf92c4 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/ChunkDataPacket.java @@ -0,0 +1,10 @@ +package ru.olamedia.olacraft.network.packet; + +import ru.olamedia.olacraft.world.data.ChunkData; + +public class ChunkDataPacket implements IPacket { + public int chunkX; + public int chunkY; + public int chunkZ; + public ChunkData data; +} diff --git a/src/ru/olamedia/olacraft/network/packet/ConnectionPacket.java b/src/ru/olamedia/olacraft/network/packet/ConnectionPacket.java new file mode 100644 index 0000000..ced43d5 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/ConnectionPacket.java @@ -0,0 +1,11 @@ +package ru.olamedia.olacraft.network.packet; + +/** + * Server sends connection packet with assigned connection ID on client connect + * + * @author olamedia + * + */ +public class ConnectionPacket implements IPacket{ + public int connectionId; +} diff --git a/src/ru/olamedia/olacraft/network/packet/ConnectionRequestPacket.java b/src/ru/olamedia/olacraft/network/packet/ConnectionRequestPacket.java new file mode 100644 index 0000000..419f339 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/ConnectionRequestPacket.java @@ -0,0 +1,5 @@ +package ru.olamedia.olacraft.network.packet; + +public class ConnectionRequestPacket implements IPacket{ + +} diff --git a/src/ru/olamedia/olacraft/network/packet/GetChunkDataPacket.java b/src/ru/olamedia/olacraft/network/packet/GetChunkDataPacket.java new file mode 100644 index 0000000..492ce15 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/GetChunkDataPacket.java @@ -0,0 +1,7 @@ +package ru.olamedia.olacraft.network.packet; + +public class GetChunkDataPacket implements IPacket{ + public int chunkX; + public int chunkY; + public int chunkZ; +} diff --git a/src/ru/olamedia/olacraft/network/packet/GetRegionPacket.java b/src/ru/olamedia/olacraft/network/packet/GetRegionPacket.java new file mode 100644 index 0000000..2c57057 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/GetRegionPacket.java @@ -0,0 +1,15 @@ +package ru.olamedia.olacraft.network.packet; + +import ru.olamedia.olacraft.world.location.RegionLocation; + +public class GetRegionPacket implements IPacket { + public RegionLocation location; + + public GetRegionPacket() { + + } + + public GetRegionPacket(RegionLocation location) { + this.location = location; + } +} diff --git a/src/ru/olamedia/olacraft/network/packet/IPacket.java b/src/ru/olamedia/olacraft/network/packet/IPacket.java new file mode 100644 index 0000000..adfa3c7 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/IPacket.java @@ -0,0 +1,5 @@ +package ru.olamedia.olacraft.network.packet; + +public interface IPacket { + +} diff --git a/src/ru/olamedia/olacraft/network/packet/IPacketListener.java b/src/ru/olamedia/olacraft/network/packet/IPacketListener.java new file mode 100644 index 0000000..2a17cd4 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/IPacketListener.java @@ -0,0 +1,7 @@ +package ru.olamedia.olacraft.network.packet; + +import com.esotericsoftware.kryonet.Connection; + +public interface IPacketListener { + public void onPacket(Connection connection, IPacket p); +} diff --git a/src/ru/olamedia/olacraft/network/packet/LiveEntityLocationUpdatePacket.java b/src/ru/olamedia/olacraft/network/packet/LiveEntityLocationUpdatePacket.java new file mode 100644 index 0000000..15edfd9 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/LiveEntityLocationUpdatePacket.java @@ -0,0 +1,15 @@ +package ru.olamedia.olacraft.network.packet; + +/** + * Client sends this packet every time location changed + * Server fills connectionId and sends back to every connection + * + * @author olamedia + * + */ +public class LiveEntityLocationUpdatePacket implements IPacket { + public float x; + public float y; + public float z; + public int connectionId; // filled by server only +} diff --git a/src/ru/olamedia/olacraft/network/packet/RegionDataPacket.java b/src/ru/olamedia/olacraft/network/packet/RegionDataPacket.java new file mode 100644 index 0000000..3a60230 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/RegionDataPacket.java @@ -0,0 +1,7 @@ +package ru.olamedia.olacraft.network.packet; + +import ru.olamedia.olacraft.world.data.RegionData; + +public class RegionDataPacket implements IPacket { + public RegionData data; +} diff --git a/src/ru/olamedia/olacraft/network/packet/SpawnPacket.java b/src/ru/olamedia/olacraft/network/packet/SpawnPacket.java new file mode 100644 index 0000000..d25a692 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/SpawnPacket.java @@ -0,0 +1,15 @@ +package ru.olamedia.olacraft.network.packet; + +/** + * Client sends SpawnRequestPacket on connect + * Server fills location, connectionId and sends SpawnPacket to every connection + * + * @author olamedia + * + */ +public class SpawnPacket implements IPacket { + public float x; + public float y; + public float z; + public int connectionId; // filled by server only +} diff --git a/src/ru/olamedia/olacraft/network/packet/SpawnRequestPacket.java b/src/ru/olamedia/olacraft/network/packet/SpawnRequestPacket.java new file mode 100644 index 0000000..0628272 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/SpawnRequestPacket.java @@ -0,0 +1,4 @@ +package ru.olamedia.olacraft.network.packet; + +public class SpawnRequestPacket implements IPacket { +} diff --git a/src/ru/olamedia/olacraft/network/packet/WorldInfoPacket.java b/src/ru/olamedia/olacraft/network/packet/WorldInfoPacket.java new file mode 100644 index 0000000..9c8e1c7 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/WorldInfoPacket.java @@ -0,0 +1,15 @@ +package ru.olamedia.olacraft.network.packet; + +import ru.olamedia.olacraft.world.WorldInfo; +import ru.olamedia.olacraft.world.provider.WorldProvider; + +public class WorldInfoPacket implements IPacket { + public WorldInfoPacket(){ + + } + public WorldInfoPacket(WorldProvider worldProvider) { + info = worldProvider.getInfo(); + } + + public WorldInfo info; +} diff --git a/src/ru/olamedia/olacraft/network/packet/package-info.java b/src/ru/olamedia/olacraft/network/packet/package-info.java new file mode 100644 index 0000000..a1da5fd --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.network.packet;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/package-info.java b/src/ru/olamedia/olacraft/package-info.java new file mode 100644 index 0000000..0049efb --- /dev/null +++ b/src/ru/olamedia/olacraft/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft; diff --git a/src/ru/olamedia/olacraft/physics/GamePhysicsWorld.java b/src/ru/olamedia/olacraft/physics/GamePhysicsWorld.java new file mode 100644 index 0000000..dd66ef0 --- /dev/null +++ b/src/ru/olamedia/olacraft/physics/GamePhysicsWorld.java @@ -0,0 +1,27 @@ +package ru.olamedia.olacraft.physics; + +import org.ode4j.ode.DBody; +import org.ode4j.ode.DRay; +import org.ode4j.ode.DWorld; +import org.ode4j.ode.OdeHelper; + +public class GamePhysicsWorld { + private DWorld world; + + public GamePhysicsWorld() { + world = OdeHelper.createWorld(); + world.setGravity(0, -0.98, 0); + } + + public DWorld getWorld() { + return world; + } + + public DBody createBody(){ + return OdeHelper.createBody(world); + } + + public DRay createRay(int length){ + return OdeHelper.createRay(length); + } +} diff --git a/src/ru/olamedia/olacraft/physics/package-info.java b/src/ru/olamedia/olacraft/physics/package-info.java new file mode 100644 index 0000000..6eaba10 --- /dev/null +++ b/src/ru/olamedia/olacraft/physics/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.physics;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/picker/joglBlockPicker.java b/src/ru/olamedia/olacraft/picker/joglBlockPicker.java new file mode 100644 index 0000000..6eb279c --- /dev/null +++ b/src/ru/olamedia/olacraft/picker/joglBlockPicker.java @@ -0,0 +1,27 @@ +package ru.olamedia.olacraft.picker; + +import java.nio.FloatBuffer; + +import javax.media.opengl.GL2; +import javax.media.opengl.GLAutoDrawable; + +import ru.olamedia.olacraft.world.block.Block; +import ru.olamedia.olacraft.world.provider.ChunkProvider; + +public class joglBlockPicker { + ChunkProvider provider; + + public void setChunkProvider(ChunkProvider provider) { + this.provider = provider; + } + + public Block pickBlock(GLAutoDrawable drawable) { + GL2 gl = drawable.getGL().getGL2(); + FloatBuffer projMatrix = FloatBuffer.allocate(16); + FloatBuffer modelMatrix = FloatBuffer.allocate(16); + gl.glGetFloatv(GL2.GL_PROJECTION, projMatrix); + gl.glGetFloatv(GL2.GL_MODELVIEW, modelMatrix); + + return null; + } +} diff --git a/src/ru/olamedia/olacraft/picker/package-info.java b/src/ru/olamedia/olacraft/picker/package-info.java new file mode 100644 index 0000000..b254232 --- /dev/null +++ b/src/ru/olamedia/olacraft/picker/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.picker;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/render/jogl/BlockRenderer.java b/src/ru/olamedia/olacraft/render/jogl/BlockRenderer.java new file mode 100644 index 0000000..6d96403 --- /dev/null +++ b/src/ru/olamedia/olacraft/render/jogl/BlockRenderer.java @@ -0,0 +1,87 @@ +package ru.olamedia.olacraft.render.jogl; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2; +import javax.media.opengl.GLAutoDrawable; + +import com.jogamp.opengl.util.texture.Texture; +import com.jogamp.opengl.util.texture.TextureCoords; + +import ru.olamedia.geom.SimpleQuadMesh; +import ru.olamedia.olacraft.world.chunk.BlockSlice; +import ru.olamedia.texture.TextureManager; + +public class BlockRenderer { + private BlockSlice slice; + private SimpleQuadMesh mesh; + + public BlockRenderer(BlockSlice slice) { + this.slice = slice; + } + + public SimpleQuadMesh getMesh(GL glx) { + GL2 gl = glx.getGL2(); + // 14739 + SimpleQuadMesh mesh = new SimpleQuadMesh(999999); + mesh.useColor(); + mesh.useTexture(); + + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, + GL.GL_NEAREST_MIPMAP_NEAREST); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, + GL.GL_NEAREST_MIPMAP_NEAREST); + gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL2.GL_FASTEST); + gl.glHint(GL2.GL_LINE_SMOOTH_HINT, GL2.GL_NICEST); + Texture grass = TextureManager.get("texture/grass.png"); + int tex = grass.getTextureObject(gl); + + TextureCoords tc = grass.getImageTexCoords(); + // mesh.setTextureSize(tc.right(), tc.top()); + System.out.println(grass.getWidth() + " " + grass.getHeight() + " | " + + tc.left() + " " + tc.right() + " " + tc.top() + " " + + tc.bottom()); + mesh.setTextureSize(grass.getWidth(), grass.getHeight()); + for (int x = 0; x < slice.getWidth(); x++) { + for (int y = 0; y < slice.getHeight(); y++) { + for (int z = 0; z < slice.getDepth(); z++) { + mesh.setTranslation(x, y, z); + // mesh.setColor4f(0, 1, 0, 1); + mesh.setColor4f((float) Math.random(), + (float) Math.random(), (float) Math.random(), 1); + mesh.setGLTexture(tex); + if (y == 0) { + mesh.addBottomQuad(); + } + if (y == 3) { + // Math.random(); + mesh.addTopQuad(); + } + if (y < 4) { + if (x == 0) { + mesh.addLeftQuad(); + } + if (x == slice.getWidth() - 1) { + mesh.addRightQuad(); + } + if (z == 0) { + mesh.addBackQuad(); + } + if (z == slice.getDepth() - 1) { + mesh.addFrontQuad(); + } + } + } + } + } + mesh.endMesh(); + return mesh; + } + + public void render(GL glx) { + if (null == mesh) { + mesh = getMesh(glx); + } + mesh.joglRender(glx); + } + +} diff --git a/src/ru/olamedia/olacraft/render/jogl/BlockStackRenderer.java b/src/ru/olamedia/olacraft/render/jogl/BlockStackRenderer.java new file mode 100644 index 0000000..28f07fd --- /dev/null +++ b/src/ru/olamedia/olacraft/render/jogl/BlockStackRenderer.java @@ -0,0 +1,9 @@ +package ru.olamedia.olacraft.render.jogl; + +import javax.media.opengl.GLAutoDrawable; + +public class BlockStackRenderer { + public void render(GLAutoDrawable drawable) { + + } +} diff --git a/src/ru/olamedia/olacraft/render/jogl/ChunkRenderer.java b/src/ru/olamedia/olacraft/render/jogl/ChunkRenderer.java new file mode 100644 index 0000000..e24e8e9 --- /dev/null +++ b/src/ru/olamedia/olacraft/render/jogl/ChunkRenderer.java @@ -0,0 +1,146 @@ +package ru.olamedia.olacraft.render.jogl; + +import javax.media.opengl.GL; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLContext; + +import ru.olamedia.math.Box; +import ru.olamedia.math.Classifier; +import ru.olamedia.olacraft.game.Game; +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; + +public class ChunkRenderer { + private BlockSlice slice; + + public ChunkRenderer(BlockSlice slice) { + this.slice = slice; + } + + public int visibleTop = 0; + public int visibleBottom = 0; + public int visibleLeft = 0; + public int visibleRight = 0; + public int visibleFront = 0; + public int visibleBack = 0; + + public int frustumCulledChunks = 0; + 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; + * } + */ + // 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()); + if (Game.instance.camera.frustum.quickClassify(box) == Classifier.OUTSIDE) { + frustumCulledChunks++; + return skipnew; + } + + // // boolean inside = true; + // if (Game.camera.frustum != null) { + // if (Game.camera.frustum.quickClassify(box) == + // Classifier.Classification.OUTSIDE) { + // frustumCulledChunks++; + // return; + // } + // } + // } else if (Game.camera.frustum.test(box) == Classifier.INTERSECT) { + // inside = false; + // frustumIntersectChunks++; + // } else { + // frustumCulledChunks++; + // return; + // } + if (!chunk.isMeshCostructed) { + if (skipnew) { + return skipnew; + } + } + if (!chunk.isMeshCostructed) { + ChunkMeshBulder.instance.add(chunk); + if (ChunkMeshBulder.instance.isFull()) { + skipnew = true; + } + return skipnew; + } + if (null == chunk.getMesh()) { + } else { + chunk.getMesh().joglRender(gl); + } + return skipnew; + } + + public void render(GLAutoDrawable drawable) { + + if (!ChunkMeshBulder.instance.isAlive()) { + ChunkMeshBulder.instance.start(); + } + + visibleTop = 0; + visibleBottom = 0; + visibleLeft = 0; + visibleRight = 0; + visibleFront = 0; + visibleBack = 0; + frustumCulledChunks = 0; + boolean skipnew = false; + ChunkSlice cs = slice.getChunkSlice(); + // 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); + } + 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); + } + } + } + // System.out.println("visible top " + visibleTop); + } +} diff --git a/src/ru/olamedia/olacraft/render/jogl/DefaultRenderer.java b/src/ru/olamedia/olacraft/render/jogl/DefaultRenderer.java new file mode 100644 index 0000000..12c12e0 --- /dev/null +++ b/src/ru/olamedia/olacraft/render/jogl/DefaultRenderer.java @@ -0,0 +1,75 @@ +package ru.olamedia.olacraft.render.jogl; + +import com.jogamp.newt.event.KeyEvent; + +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.glu.GLU; + +import ru.olamedia.input.KeyListener; +import ru.olamedia.input.Keyboard; +import ru.olamedia.input.MouseJail; +import ru.olamedia.input.MouseListener; +import ru.olamedia.olacraft.game.Game; + +public class DefaultRenderer implements IRenderer, KeyListener, MouseListener { + private boolean isHUDEnabled = true; + GLU glu = new GLU(); + // private static Color BLACK_TRANSPARENT = new Color(0, 0, 0, 0); + long lastHUD = System.nanoTime(); + + public DefaultRenderer() { + Keyboard.attach(this); + MouseJail.attach(this); + } + + @Override + public void render(GLAutoDrawable drawable) { + Game.client.getScene().tick(); + Game.client.getScene().render(drawable); + } + + @Override + public void onKeyPressed(String name, KeyEvent e) { + + } + + @Override + public void onKeyReleased(String name, KeyEvent e) { + // System.out.println(name); + if (name == "toggleHUD") { + isHUDEnabled = !isHUDEnabled; + } + if (name == "captureMouse") { + MouseJail.setActive(true); + } + if (name == "releaseMouse") { + MouseJail.setActive(false); + } + if (name == "toggleFrustum") { + Game.instance.camera.isFrustumVisible = !Game.instance.camera.isFrustumVisible; + } + if (name == "toggleRenderDistance") { + int renderDistance = Game.client.getScene().getRenderDistance(); + renderDistance *= 2; + if (renderDistance > 256) { + renderDistance = 32; + } + Game.client.getScene().setRenderDistance(renderDistance); + } + } + + @Override + public void onMouseMove(float dx, float dy) { + Game.instance.camera.mouseMoved(dx, dy); + } + + @Override + public void onMouseClick() { + Game.instance.player.onMouseClick(); + } + + @Override + public void init(GLAutoDrawable drawable) { + + } +} diff --git a/src/ru/olamedia/olacraft/render/jogl/IRenderer.java b/src/ru/olamedia/olacraft/render/jogl/IRenderer.java new file mode 100644 index 0000000..1ba581a --- /dev/null +++ b/src/ru/olamedia/olacraft/render/jogl/IRenderer.java @@ -0,0 +1,8 @@ +package ru.olamedia.olacraft.render.jogl; + +import javax.media.opengl.GLAutoDrawable; + +public interface IRenderer { + public void render(GLAutoDrawable drawable); + public void init(GLAutoDrawable drawable); +} diff --git a/src/ru/olamedia/olacraft/render/jogl/InventoryRenderer.java b/src/ru/olamedia/olacraft/render/jogl/InventoryRenderer.java new file mode 100644 index 0000000..46daa4a --- /dev/null +++ b/src/ru/olamedia/olacraft/render/jogl/InventoryRenderer.java @@ -0,0 +1,87 @@ +package ru.olamedia.olacraft.render.jogl; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2; +import javax.media.opengl.GLAutoDrawable; + +import com.jogamp.opengl.util.texture.Texture; + +import ru.olamedia.olacraft.inventory.Inventory; +import ru.olamedia.olacraft.world.blockStack.BlockStack; +import ru.olamedia.olacraft.world.blockTypes.EmptyBlockType; +import ru.olamedia.texture.TextureManager; + +public class InventoryRenderer { + private Inventory inventory; + private BlockStackRenderer stackRenderer; + + int stackSize = 32; + int spacing = 2; + int padding = 2; + int x; + int y; + + public InventoryRenderer(Inventory inventory) { + this.inventory = inventory; + stackRenderer = new BlockStackRenderer(); + } + + public void render(GLAutoDrawable drawable) { + GL2 gl = drawable.getGL().getGL2(); + gl.glPushAttrib(GL2.GL_ALL_ATTRIB_BITS); + int vWidth = drawable.getWidth(); + int vHeight = drawable.getHeight(); + // Draw GUI + + int width = stackSize * Inventory.BIND_NUM + spacing * (Inventory.BIND_NUM - 1) + padding * 2; + int height = stackSize + padding * 2; + x = (vWidth - width) / 2; + y = (vHeight - height) - 10; + gl.glRecti(x, y, x + width, y + height); + // Draw stacks + gl.glEnable(GL2.GL_TEXTURE_2D); + for (int i = 0; i < Inventory.BIND_NUM; i++) { + renderStack(i, drawable); + } + gl.glPopAttrib(); + } + + public void renderStack(int i, GLAutoDrawable drawable) { + GL2 gl = drawable.getGL().getGL2(); + BlockStack stack = inventory.binded[i]; + int sx = x + padding + stackSize * i + spacing * i; + int sy = y + padding; + if (null != stack && !(stack.block.getType() instanceof EmptyBlockType)) { + Texture tex = TextureManager.get(stack.block.getType().getStackTextureFile()); + if (null != tex) { + tex.bind(gl); + 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.glColor3f(1, 1, 1); + int x1 = sx; + int x2 = sx + stackSize; + int y1 = sy; + int y2 = sy + stackSize; + gl.glBegin(GL2.GL_QUADS); + { + gl.glTexCoord2f(0, 0); + gl.glVertex2f(x1, y1); + gl.glTexCoord2f(0, 1); + gl.glVertex2f(x1, y2); + gl.glTexCoord2f(1, 1); + gl.glVertex2f(x2, y2); + gl.glTexCoord2f(1, 0); + gl.glVertex2f(x2, y1); + } + gl.glEnd(); + // gl.glRecti(sx, sy, sx + stackSize, sy + stackSize); + } + } else { + gl.glDisable(GL2.GL_TEXTURE_2D); + float gray = 0.5f; + gl.glColor3f(gray, gray, gray); + gl.glRecti(sx, sy, sx + stackSize, sy + stackSize); + gl.glEnable(GL2.GL_TEXTURE_2D); + } + } +} diff --git a/src/ru/olamedia/olacraft/render/jogl/PlaneRenderer.java b/src/ru/olamedia/olacraft/render/jogl/PlaneRenderer.java new file mode 100644 index 0000000..754a093 --- /dev/null +++ b/src/ru/olamedia/olacraft/render/jogl/PlaneRenderer.java @@ -0,0 +1,102 @@ +package ru.olamedia.olacraft.render.jogl; + +import javax.media.opengl.GL2; +import javax.media.opengl.GLAutoDrawable; + +import ru.olamedia.math.Plane; + +public class PlaneRenderer { + private static float getZ(Plane p, float x, float y) { + return -(p.n.x * x + p.n.y * y + p.d) / p.n.z; + } + + private static float getY(Plane p, float x, float z) { + return -(p.n.x * x + p.n.z * z + p.d) / p.n.y; + } + + private static float getX(Plane p, float y, float z) { + return -(p.n.y * y + p.n.z * z + p.d) / p.n.x; + } + + public static void render(Plane p, GLAutoDrawable drawable) { + GL2 gl = drawable.getGL().getGL2(); + float size = 100; + float step = size / 5; + for (float x = -size; x <= size; x += step) { + for (float y = -size; y <= size; y += step) { + // nx * x + ny * y + nz * z + d = 0 + // (z = nx * x + ny * y + d) / nz + float z = getZ(p, x, y); + float x2 = x + step; + float y2 = y; + float z2 = getZ(p, x2, y2); + float x3 = x + step; + float y3 = y + step; + float z3 = getZ(p, x3, y3); + float x4 = x; + float y4 = y + step; + float z4 = getZ(p, x4, y4); + gl.glPolygonMode(GL2.GL_FRONT_AND_BACK, GL2.GL_LINE); + gl.glBegin(GL2.GL_QUADS); + { + gl.glVertex3f(x, y, z); + gl.glVertex3f(x2, y2, z2); + gl.glVertex3f(x3, y3, z3); + gl.glVertex3f(x4, y4, z4); + } + gl.glEnd(); + } + } + for (float x = -size; x <= size; x += step) { + for (float z = -size; z <= size; z += step) { + // nx * x + ny * y + nz * z + d = 0 + // (z = nx * x + ny * y + d) / nz + float y = getY(p, x, z); + float x2 = x + step; + float z2 = z; + float y2 = getY(p, x2, z2); + float x3 = x + step; + float z3 = z + step; + float y3 = getY(p, x3, z3); + float x4 = x; + float z4 = z + step; + float y4 = getY(p, x4, z4); + gl.glPolygonMode(GL2.GL_FRONT_AND_BACK, GL2.GL_LINE); + gl.glBegin(GL2.GL_QUADS); + { + gl.glVertex3f(x, y, z); + gl.glVertex3f(x2, y2, z2); + gl.glVertex3f(x3, y3, z3); + gl.glVertex3f(x4, y4, z4); + } + gl.glEnd(); + } + } + + for (float y = -size; y <= size; y += step) { + for (float z = -size; z <= size; z += step) { + // nx * x + ny * y + nz * z + d = 0 + // (z = nx * x + ny * y + d) / nz + float x = getX(p, y, z); + float y2 = y + step; + float z2 = z; + float x2 = getX(p, y2, z2); + float y3 = y + step; + float z3 = z + step; + float x3 = getX(p, y3, z3); + float y4 = y; + float z4 = z + step; + float x4 = getX(p, y4, z4); + gl.glPolygonMode(GL2.GL_FRONT_AND_BACK, GL2.GL_LINE); + gl.glBegin(GL2.GL_QUADS); + { + gl.glVertex3f(x, y, z); + gl.glVertex3f(x2, y2, z2); + gl.glVertex3f(x3, y3, z3); + gl.glVertex3f(x4, y4, z4); + } + gl.glEnd(); + } + } + } +} diff --git a/src/ru/olamedia/olacraft/render/jogl/VectorRenderer.java b/src/ru/olamedia/olacraft/render/jogl/VectorRenderer.java new file mode 100644 index 0000000..180ec2a --- /dev/null +++ b/src/ru/olamedia/olacraft/render/jogl/VectorRenderer.java @@ -0,0 +1,20 @@ +package ru.olamedia.olacraft.render.jogl; + +import javax.media.opengl.GL2; +import javax.media.opengl.GLAutoDrawable; + +import ru.olamedia.math.Vector3f; + +public class VectorRenderer { + public static void render(Vector3f point, Vector3f v, GLAutoDrawable drawable) { + GL2 gl = drawable.getGL().getGL2(); + gl.glDisable(GL2.GL_TEXTURE_2D); + gl.glColor3f(1, 0, 0); + gl.glBegin(GL2.GL_LINES); + { + gl.glVertex3f(point.x, point.y, point.z); + gl.glVertex3f(point.x + v.x, point.y + v.y, point.z + v.z); + } + gl.glEnd(); + } +} diff --git a/src/ru/olamedia/olacraft/render/jogl/joglViewport.java b/src/ru/olamedia/olacraft/render/jogl/joglViewport.java new file mode 100644 index 0000000..b3da2ce --- /dev/null +++ b/src/ru/olamedia/olacraft/render/jogl/joglViewport.java @@ -0,0 +1,24 @@ +package ru.olamedia.olacraft.render.jogl; + +import java.awt.Font; + +import javax.media.opengl.GLAutoDrawable; + +import com.jogamp.opengl.util.awt.TextRenderer; + +public class joglViewport { + private GLAutoDrawable drawable; + private TextRenderer sans11; + + public joglViewport(GLAutoDrawable drawable) { + this.drawable = drawable; + sans11 = new TextRenderer(new Font("SansSerif", Font.PLAIN, 11)); + } + + public void drawText(String text, int x, int y) { + sans11.setColor(1, 1, 1, 0.7f); + sans11.beginRendering(drawable.getWidth(), drawable.getHeight()); + sans11.draw(text, x, y); + sans11.endRendering(); + } +} diff --git a/src/ru/olamedia/olacraft/render/jogl/package-info.java b/src/ru/olamedia/olacraft/render/jogl/package-info.java new file mode 100644 index 0000000..73b0ace --- /dev/null +++ b/src/ru/olamedia/olacraft/render/jogl/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.render.jogl;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/scene/GameScene.java b/src/ru/olamedia/olacraft/scene/GameScene.java new file mode 100644 index 0000000..618e270 --- /dev/null +++ b/src/ru/olamedia/olacraft/scene/GameScene.java @@ -0,0 +1,252 @@ +package ru.olamedia.olacraft.scene; + +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryUsage; +import java.util.HashMap; + +import javax.media.opengl.GL2; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.glu.GLU; +import javax.media.opengl.glu.GLUquadric; + +import org.ode4j.ode.DBody; + +import com.jogamp.opengl.util.PMVMatrix; + +import ru.olamedia.Options; +import ru.olamedia.liveEntity.LiveEntity; +import ru.olamedia.olacraft.game.Game; +import ru.olamedia.olacraft.physics.GamePhysicsWorld; +import ru.olamedia.olacraft.render.jogl.ChunkRenderer; +import ru.olamedia.olacraft.render.jogl.InventoryRenderer; +import ru.olamedia.olacraft.render.jogl.joglViewport; +import ru.olamedia.olacraft.weapon.Bullet; +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.provider.WorldProvider; +import ru.olamedia.player.Player; +import ru.olamedia.vbo.VBO; + +public class GameScene { + + private PMVMatrix matrix; + + private HashMap<Integer, LiveEntity> liveEntities = new HashMap<Integer, LiveEntity>(); + WorldProvider provider; + private int renderDistance = Options.renderDistance; + private joglViewport viewport; + private BulletScene bullets = new BulletScene(); + private GamePhysicsWorld physics = new GamePhysicsWorld(); + + private VBO testObject; + + private boolean isInitialized = false; + BlockSlice viewSlice; + + public GameScene(WorldProvider provider) { + this.provider = provider; + setRenderDistance(renderDistance); + } + + public void addBullet(Bullet b) { + bullets.add(b); + DBody body = physics.createBody(); + body.setPosition(b.location.x, b.location.y, b.location.z); + body.setLinearVel(b.velocity.x, b.velocity.y, b.velocity.z); + /* + * DMass mass = OdeHelper.createMass(); + * mass.setMass(10); + * mass.setI(OdeHelper.c); + * body.setMass(mass); + */ + b.body = body; + } + + public int getBulletsCount() { + return bullets.getCount(); + } + + public void init(GLAutoDrawable drawable) { + if (isInitialized) { + return; + } + isInitialized = true; + registerTextures(); + viewport = new joglViewport(drawable); + testObject = new VBO(drawable); + } + + private void registerTextures() { + AbstractBlockType t; + t = new GrassBlockType(); + t.register(); + } + + /** + * @return the renderDistance + */ + public int getRenderDistance() { + return renderDistance; + } + + /** + * @param renderDistance + * the renderDistance to set + */ + public void setRenderDistance(int renderDistance) { + this.renderDistance = renderDistance; + viewSlice = new BlockSlice(provider, renderDistance, renderDistance * 2, renderDistance); + blockRenderer = new ChunkRenderer(viewSlice); + } + + ChunkRenderer blockRenderer = new ChunkRenderer(viewSlice); + GLU glu = new GLU(); + + public void registerLiveEntity(LiveEntity entity) { + // liveEntityIncrement++; + // entity.setId(liveEntityIncrement); + liveEntities.put(entity.getConnectionId(), entity); + } + + private InventoryRenderer inventoryRenderer; + + private Player player; + + public void registerPlayer(LiveEntity player) { + inventoryRenderer = new InventoryRenderer(player.getInventory()); + this.player = (Player) player; + } + + public LiveEntity getLiveEntity(int connectionId) { + if (liveEntities.containsKey(connectionId)) { + return liveEntities.get(connectionId); + } + return null; + } + + public HashMap<Integer, LiveEntity> getLiveEntities() { + return liveEntities; + } + + public void tick() { + Game.instance.tick(); + float aspect = Game.Display.getAspect(); + Game.instance.camera.setAspect(aspect); + // bullets.update(Game.instance.getDelta()); + physics.getWorld().step(Game.instance.getDelta()); + } + + public void render(GLAutoDrawable drawable) { + if (!Game.instance.isRunning()) { + // not running, just clear screen + GL2 gl = drawable.getGL().getGL2(); + gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT); + gl.glClearColor(49f / 255f, 49f / 255f, 49f / 255f, 1); + return; + } + init(drawable); + GL2 gl = drawable.getGL().getGL2(); + gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT); + gl.glClearColor(49f / 255f, 119f / 255f, 243f / 255f, 1); + // GOING 3D + gl.glPushMatrix(); + 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.glPushAttrib(GL2.GL_ALL_ATTRIB_BITS); + gl.glColor4f(0f, 1f, 0, 1); + gl.glEnable(GL2.GL_DEPTH_TEST); + gl.glShadeModel(GL2.GL_FLAT); + gl.glCullFace(GL2.GL_BACK); + // gl.glEnable(GL2.GL_FOG); + // gl.glFogf(GL2.GL_FOG_MODE, GL2.GL_LINEAR); + // gl.glFogf(GL2.GL_FOG_MODE, GL2.GL_EXP); + // gl.glFogf(GL2.GL_FOG_START, renderDistance / 2 - renderDistance / + // 10); + // gl.glFogf(GL2.GL_FOG_END, renderDistance / 2); + // gl.glFogf(GL2.GL_FOG_DENSITY, 0.002f); + // new float[] { 49f / 255f, 119f / 255f, 243f / 255f } + // gl.glFogfv(GL2.GL_FOG_COLOR, new float[] { 1, 1, 1, 0.2f }, 0); + blockRenderer.render(drawable); + gl.glPopAttrib(); + // RENDER ANYTHING ELSE + gl.glPushAttrib(GL2.GL_ALL_ATTRIB_BITS); + GLUquadric qobj0 = glu.gluNewQuadric(); + glu.gluQuadricDrawStyle(qobj0, GLU.GLU_FILL); + glu.gluQuadricNormals(qobj0, GLU.GLU_SMOOTH); + for (LiveEntity entity : liveEntities.values()) { + gl.glPushMatrix(); + gl.glTranslatef(entity.getX(), entity.getCameraY(), entity.getZ()); + glu.gluSphere(qobj0, 0.5f, 10, 10); + gl.glPopMatrix(); + } + gl.glPopAttrib(); + // bullets.render(drawable); + gl.glPopMatrix(); + + testObject.render(); + + // GOIND 2D + gl.glMatrixMode(GL2.GL_PROJECTION); + gl.glLoadIdentity(); + int width = Game.Display.getWidth(); + int height = Game.Display.getHeight(); + glu.gluOrtho2D(0, width, height, 0); + gl.glMatrixMode(GL2.GL_MODELVIEW); + gl.glPushMatrix(); + // renderHUD(); + // MAP++ + gl.glPushAttrib(GL2.GL_ALL_ATTRIB_BITS); + gl.glPolygonMode(GL2.GL_FRONT_AND_BACK, GL2.GL_FILL); + int msz = 100; + gl.glColor4f(0.3f, 0.3f, 0.3f, 0.7f); + gl.glRectf(width - msz - 12, 8, width - 8, msz + 12); + gl.glColor4f(0.9f, 0.9f, 0.9f, 1); + gl.glRectf(width - msz - 10, 10, width - 10, msz + 10); + gl.glColor4f(0.0f, 0.0f, 0.0f, 0.9f); + /* + * for (int mx = 0; mx < msz; mx++) { + * for (int mz = 0; mz < msz; mz++) { + * float h = (float) viewSlice + * .getHighest((int) (mx - msz / 2 + player.getX()), (int) (mz - msz / 2 + * + player.getZ())); + * gl.glColor4f(h / 128, h / 128, h / 128, 1f); + * gl.glRectf(width - msz - 10 + mx, 10 + mz, width - msz - 10 + mx + 1, + * 10 + mz + 1); + * } + * } + */ + // MAP-- + // crosshair + gl.glColor4f(1f, 1f, 1f, 0.7f); + gl.glRectf(width / 2 - 1, height / 2 - 10, width / 2 + 1, height / 2 + 10); // vertical + gl.glRectf(width / 2 - 10, height / 2 - 1, width / 2 + 10, height / 2 + 1); // horizontal + + // inventoryprivate PMVMatrix matrix; + if (null != inventoryRenderer) { + inventoryRenderer.render(drawable); + } + + viewport.drawText("avg fps: " + (int) Game.timer.getAvgFps(), 10, height - 20); + viewport.drawText("fps: " + (int) Game.timer.getFps(), 10, height - 35); + MemoryUsage heap = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); + viewport.drawText("mem: " + (heap.getUsed() / (1024 * 1024)) + "/" + (heap.getMax() / (1024 * 1024)), 10, + height - 50); + + viewport.drawText("y: " + Game.instance.player.getY(), width - msz - 10, height - msz - 25); + viewport.drawText("x: " + Game.instance.player.getX(), width - msz - 10, height - msz - 40); + viewport.drawText("z: " + Game.instance.player.getZ(), width - msz - 10, height - msz - 55); + viewport.drawText("players: " + liveEntities.size(), width - msz - 10, height - msz - 70); + viewport.drawText("bullets: " + getBulletsCount(), width - msz - 10, height - msz - 95); + 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); + gl.glPopAttrib(); + gl.glPopMatrix(); + gl.glFlush(); + } +} diff --git a/src/ru/olamedia/olacraft/scene/package-info.java b/src/ru/olamedia/olacraft/scene/package-info.java new file mode 100644 index 0000000..660e324 --- /dev/null +++ b/src/ru/olamedia/olacraft/scene/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.scene;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/weapon/Bullet.java b/src/ru/olamedia/olacraft/weapon/Bullet.java new file mode 100644 index 0000000..6292bf2 --- /dev/null +++ b/src/ru/olamedia/olacraft/weapon/Bullet.java @@ -0,0 +1,51 @@ +package ru.olamedia.olacraft.weapon; + +import javax.media.opengl.GL2; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.glu.GLU; +import javax.media.opengl.glu.GLUquadric; +import javax.vecmath.Point3f; +import javax.vecmath.Vector3f; + +import org.ode4j.ode.DBody; + +public class Bullet { + public Point3f location = new Point3f(); + public Vector3f velocity = new Vector3f(); + public Vector3f acceleration = new Vector3f(0, -0.98f, 0); + public DBody body; + public float width = 0.05f; + public float height = 0.05f; + public float depth = 0.25f; + public boolean toRemove = false; + private static GLU glu = new GLU(); + + public void update(float deltams) { + // acceleration.set(velocity); + // acceleration.negate(); + // acceleration.scale(0.1f); + // acceleration.y += -0.98f; + // velocity.x += acceleration.x * deltams; + // velocity.y += acceleration.y * deltams; + // velocity.z += acceleration.z * deltams; + // float step = deltams; + // location.x += velocity.x * deltams; + // location.y += velocity.y * deltams; + // location.z += velocity.z * deltams; + if (body.getPosition().get1() < 0 || body.getPosition().get1() > 100) { + // FIXME + toRemove = true; + } + } + + public void render(GLAutoDrawable drawable) { + GL2 gl = drawable.getGL().getGL2(); + gl.glPushMatrix(); + gl.glTranslated(body.getPosition().get0(), body.getPosition().get1(), body.getPosition().get2()); + GLUquadric bulletGeom = glu.gluNewQuadric(); + glu.gluQuadricDrawStyle(bulletGeom, GLU.GLU_FILL); + glu.gluQuadricNormals(bulletGeom, GLU.GLU_SMOOTH); + glu.gluDisk(bulletGeom, 0.3, 0.4, 5, 5); + gl.glPopMatrix(); + } +} diff --git a/src/ru/olamedia/olacraft/weapon/BulletScene.java b/src/ru/olamedia/olacraft/weapon/BulletScene.java new file mode 100644 index 0000000..1e5ea05 --- /dev/null +++ b/src/ru/olamedia/olacraft/weapon/BulletScene.java @@ -0,0 +1,35 @@ +package ru.olamedia.olacraft.weapon; + +import java.util.ArrayList; +import java.util.List; + +import javax.media.opengl.GLAutoDrawable; + +public class BulletScene { + private List<Bullet> bullets = new ArrayList<Bullet>(); + + public void add(Bullet b) { + bullets.add(b); + } + + public int getCount(){ + return bullets.size(); + } + + public void update(float deltas) { + for (int i = 0; i < bullets.size(); i++) { + Bullet b = bullets.get(i); + b.update(deltas); + if (b.toRemove) { + bullets.remove(b); + i--; + } + } + } + + public void render(GLAutoDrawable drawable) { + for (Bullet b : bullets) { + b.render(drawable); + } + } +} diff --git a/src/ru/olamedia/olacraft/weapon/package-info.java b/src/ru/olamedia/olacraft/weapon/package-info.java new file mode 100644 index 0000000..89ca87c --- /dev/null +++ b/src/ru/olamedia/olacraft/weapon/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.weapon;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/World.java b/src/ru/olamedia/olacraft/world/World.java new file mode 100644 index 0000000..e3d25f2 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/World.java @@ -0,0 +1,12 @@ +package ru.olamedia.olacraft.world; + +import ru.olamedia.olacraft.world.block.BlockRegistry; +import ru.olamedia.olacraft.world.blockTypes.GrassBlockType; + +public class World { + private BlockRegistry blockRegistry; + public void setup() { + blockRegistry = new BlockRegistry(); + blockRegistry.registerBlockType(GrassBlockType.class); + } +} diff --git a/src/ru/olamedia/olacraft/world/WorldInfo.java b/src/ru/olamedia/olacraft/world/WorldInfo.java new file mode 100644 index 0000000..797339f --- /dev/null +++ b/src/ru/olamedia/olacraft/world/WorldInfo.java @@ -0,0 +1,11 @@ +package ru.olamedia.olacraft.world; + +import java.io.Serializable; + +public class WorldInfo implements Serializable { + private static final long serialVersionUID = -3669317489158639456L; + public String name = "world"; + public int minHeight = -128; + public int maxHeight = 127; + public float gravity = 9.81f; +} diff --git a/src/ru/olamedia/olacraft/world/block/Block.java b/src/ru/olamedia/olacraft/world/block/Block.java new file mode 100644 index 0000000..a48c9df --- /dev/null +++ b/src/ru/olamedia/olacraft/world/block/Block.java @@ -0,0 +1,111 @@ +package ru.olamedia.olacraft.world.block; + +import ru.olamedia.olacraft.world.blockTypes.BlockType; +import ru.olamedia.olacraft.world.blockTypes.EmptyBlockType; +import ru.olamedia.olacraft.world.provider.WorldProvider; + +public class Block { + private WorldProvider provider; + private int x; + private int y; + private int z; + + /** + * Inventory block + */ + public Block() { + this.provider = null; + this.x = 0; + this.y = 0; + this.z = 0; + } + + public void putIntoWorld(WorldProvider worldProvider, int x, int y, int z) { + this.provider = worldProvider; + this.x = x; + this.y = y; + this.z = z; + } + + public Block(WorldProvider worldProvider, int x, int y, int z) { + putIntoWorld(worldProvider, x, y, z); + } + + /** + * @return the x + */ + public int getX() { + return x; + } + + /** + * @param x + * the x to set + */ + public void setX(int x) { + this.x = x; + } + + /** + * @return the y + */ + public int getY() { + return y; + } + + /** + * @param y + * the y to set + */ + public void setY(int y) { + this.y = y; + } + + /** + * @return the z + */ + public int getZ() { + return z; + } + + /** + * @param z + * the z to set + */ + public void setZ(int z) { + this.z = z; + } + + public boolean isEmpty() { + return provider.isEmptyBlock(x, y, z); + } + + public Block getNeighbor(int dx, int dy, int dz) { + return new Block(provider, x + dx, y + dy, z + dz); + } + + public Block[] getNeighbors() { + return new Block[] { + // + getNeighbor(1, 0, 0),// + getNeighbor(0, 1, 0),// + getNeighbor(0, 0, 1),// + getNeighbor(-1, 0, 0),// + getNeighbor(0, -1, 0),// + getNeighbor(0, 0, -1),// + }; + } + + private BlockType type; + + public void setType(BlockType type) { + this.type = type; + } + + public BlockType getType() { + if (null == type) { + type = new EmptyBlockType(); + } + return type; + } +} diff --git a/src/ru/olamedia/olacraft/world/block/BlockRegistry.java b/src/ru/olamedia/olacraft/world/block/BlockRegistry.java new file mode 100644 index 0000000..19ccc94 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/block/BlockRegistry.java @@ -0,0 +1,46 @@ +package ru.olamedia.olacraft.world.block; + +import java.util.HashMap; + +import ru.olamedia.olacraft.world.blockTypes.BlockType; + +public class BlockRegistry { + + private HashMap<Integer, String> names = new HashMap<Integer, String>(); + private HashMap<Integer, BlockType> types = new HashMap<Integer, BlockType>(); + private int autoincrement = 0; + + private BlockRegistry worldRegistry; + + public BlockRegistry() { + } + + public BlockType getBlockType(int id) { + return types.get(id); + } + + public String getBlockHumanId(int id) { + return names.get(id); + } + + public int registerBlockType(@SuppressWarnings("rawtypes") Class type) { + if (type.isInstance(BlockType.class)) { + autoincrement++; + int id = autoincrement; + String classId = type.getName(); + names.put(id, classId); + // types.put(id, type); + return autoincrement; + } + return 0; + } + + public BlockRegistry getWorldRegistry() { + return worldRegistry; + } + + public void setWorldRegistry(BlockRegistry worldRegistry) { + this.worldRegistry = worldRegistry; + } + +} diff --git a/src/ru/olamedia/olacraft/world/block/package-info.java b/src/ru/olamedia/olacraft/world/block/package-info.java new file mode 100644 index 0000000..0924926 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/block/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.block;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/blockStack/BlockStack.java b/src/ru/olamedia/olacraft/world/blockStack/BlockStack.java new file mode 100644 index 0000000..57258ef --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockStack/BlockStack.java @@ -0,0 +1,63 @@ +package ru.olamedia.olacraft.world.blockStack; + +import ru.olamedia.olacraft.world.block.Block; + +public class BlockStack { + public Block block; + public int count; + + public BlockStack(Block block, int count) { + this.block = block; + this.count = count; + } + + public BlockStack get() { + return get(1); + } + + public BlockStack get(int getcount) { + int c = 0; + if (count >= getcount) { + c = getcount; + count -= getcount; + } else { + c = count; + count = 0; + } + return new BlockStack(block, c); + } + + public BlockStack getAll() { + int c = count; + count = 0; + return new BlockStack(block, c); + } + + /** + * + * @return Remaining BlockStack + */ + public BlockStack putStack(BlockStack stack) { + + if (block.getType() == stack.block.getType()) { + int max = block.getType().getMaxStack(); + // Stack + int total = count + stack.count; + if (total < max) { + count = total; + return new BlockStack(block, 0); + } else { + BlockStack remains = new BlockStack(block, total - max); + count = max; + return remains; + } + } else { + // Replace + BlockStack remains = new BlockStack(block, count); + block = stack.block; + count = stack.count; + return remains; + } + } + +} diff --git a/src/ru/olamedia/olacraft/world/blockStack/package-info.java b/src/ru/olamedia/olacraft/world/blockStack/package-info.java new file mode 100644 index 0000000..933dc87 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockStack/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.blockStack;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/blockTypes/AbstractBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/AbstractBlockType.java new file mode 100644 index 0000000..6e2a86f --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/AbstractBlockType.java @@ -0,0 +1,86 @@ +package ru.olamedia.olacraft.world.blockTypes; + +import com.jogamp.opengl.util.texture.Texture; + +import ru.olamedia.texture.TextureManager; + +public abstract class AbstractBlockType implements BlockType { + + @Override + abstract public String getName(); + + @Override + public int getMaxStack() { + return 64; + } + + @Override + abstract public String getStackTextureFile(); + + @Override + abstract public String getTopTextureFile(); + + @Override + public String getBottomTextureFile() { + return this.getTopTextureFile(); + } + + @Override + public String getLeftTextureFile() { + return this.getFrontTextureFile(); + } + + @Override + public String getRightTextureFile() { + return this.getFrontTextureFile(); + } + + @Override + public String getFrontTextureFile() { + return this.getTopTextureFile(); + } + + @Override + public String getBackTextureFile() { + return this.getFrontTextureFile(); + } + + @Override + public Texture getTopTexture() { + return TextureManager.get(this.getTopTextureFile()); + } + + @Override + public Texture getBottomTexture() { + return TextureManager.get(this.getBottomTextureFile()); + } + + @Override + public Texture getLeftTexture() { + return TextureManager.get(this.getLeftTextureFile()); + } + + @Override + public Texture getRightTexture() { + return TextureManager.get(this.getRightTextureFile()); + } + + @Override + public Texture getFrontTexture() { + return TextureManager.get(this.getFrontTextureFile()); + } + + @Override + public Texture getBackTexture() { + return TextureManager.get(this.getBackTextureFile()); + } + + public void register(){ + getBackTexture(); + getBottomTexture(); + getFrontTexture(); + getLeftTexture(); + getRightTexture(); + getTopTexture(); + } +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/BlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/BlockType.java new file mode 100644 index 0000000..0bda2eb --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/BlockType.java @@ -0,0 +1,21 @@ +package ru.olamedia.olacraft.world.blockTypes; + +import com.jogamp.opengl.util.texture.Texture; + +public interface BlockType { + public String getName(); + public int getMaxStack(); + public String getStackTextureFile(); + public String getTopTextureFile(); + public String getBottomTextureFile(); + public String getLeftTextureFile(); + public String getRightTextureFile(); + public String getFrontTextureFile(); + public String getBackTextureFile(); + public Texture getTopTexture(); + public Texture getBottomTexture(); + public Texture getLeftTexture(); + public Texture getRightTexture(); + public Texture getFrontTexture(); + public Texture getBackTexture(); +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/EmptyBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/EmptyBlockType.java new file mode 100644 index 0000000..4073356 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/EmptyBlockType.java @@ -0,0 +1,23 @@ +package ru.olamedia.olacraft.world.blockTypes; + +public class EmptyBlockType extends AbstractBlockType { + @Override + public String getName() { + return ""; + } + + @Override + public int getMaxStack() { + return 64; + } + + @Override + public String getStackTextureFile() { + return "texture/empty.png"; + } + + @Override + public String getTopTextureFile() { + return "texture/empty.png"; + } +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/GrassBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/GrassBlockType.java new file mode 100644 index 0000000..816b283 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/GrassBlockType.java @@ -0,0 +1,28 @@ +package ru.olamedia.olacraft.world.blockTypes; + +public class GrassBlockType extends AbstractBlockType { + @Override + public String getName() { + return "Grass"; + } + + @Override + public int getMaxStack() { + return 64; + } + + @Override + public String getStackTextureFile() { + return "texture/terrain-grassdarkgreen.png"; + } + + @Override + public String getTopTextureFile() { + return "texture/terrain-grassdarkgreen.png"; + } + + @Override + public String getFrontTextureFile() { + return "texture/terrain-glong-darkgreen-dirt.png"; + } +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/GravelBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/GravelBlockType.java new file mode 100644 index 0000000..354d383 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/GravelBlockType.java @@ -0,0 +1,23 @@ +package ru.olamedia.olacraft.world.blockTypes; + +public class GravelBlockType extends AbstractBlockType { + @Override + public String getName() { + return "Gravel"; + } + + @Override + public int getMaxStack() { + return 64; + } + + @Override + public String getStackTextureFile() { + return "texture/gravel.png"; + } + + @Override + public String getTopTextureFile() { + return "texture/gravel.png"; + } +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/package-info.java b/src/ru/olamedia/olacraft/world/blockTypes/package-info.java new file mode 100644 index 0000000..a49dda8 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.blockTypes;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/chunk/BlockSlice.java b/src/ru/olamedia/olacraft/world/chunk/BlockSlice.java new file mode 100644 index 0000000..ca4c92a --- /dev/null +++ b/src/ru/olamedia/olacraft/world/chunk/BlockSlice.java @@ -0,0 +1,164 @@ +package ru.olamedia.olacraft.world.chunk; + +import ru.olamedia.olacraft.world.provider.WorldProvider; + +public class BlockSlice { + protected WorldProvider provider; + protected int leftX; + protected int bottomY; + protected int backZ; + 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 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; + }*/ + + /** + * + * @param provider + * @param width + * (blocks) + * @param height + * (blocks) + * @param depth + * (blocks) + */ + public BlockSlice(WorldProvider provider, int width, int height, int depth) { + this.provider = provider; + this.width = width; + this.height = height; + this.depth = depth; + } + + public ChunkSlice getChunkSlice() { + 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); + return chunkSlice; + } + + public int getTotalBlocks() { + return getWidth() * getHeight() * getDepth(); + } + + /** + * @return the width (blocks) + */ + public int getWidth() { + return width; + } + + /** + * @param width + * (blocks) + */ + public void setWidth(int width) { + this.width = width; + } + + /** + * @return the height (blocks) + */ + public int getHeight() { + return height; + } + + /** + * @param height + * (blocks) + */ + public void setHeight(int height) { + this.height = height; + } + + /** + * @return the depth (blocks) + */ + public int getDepth() { + return depth; + } + + /** + * @param depth + * (blocks) + */ + public void setDepth(int depth) { + this.depth = depth; + } + + /** + * + * @param x + * (blocks) + * @param y + * (blocks) + * @param z + * (blocks) + */ + public void setLocation(int x, int y, int z) { + if (x != leftX || y != bottomY || z != backZ){ + invalidateCache(); + } + leftX = x; + bottomY = y; + backZ = z; + } + + /** + * + * @param x + * (blocks) + * @param y + * (blocks) + * @param z + * (blocks) + */ + public void setCenter(int x, int y, int z) { + setLocation(x - width / 2, y - height / 2, z - depth / 2); + } + + /** + * @return the left x (blocks) + */ + public int getX() { + return leftX; + } + + /** + * @return the bottom y (blocks) + */ + public int getY() { + return bottomY; + } + + /** + * @return the back z (blocks) + */ + public int getZ() { + return backZ; + } +} diff --git a/src/ru/olamedia/olacraft/world/chunk/Chunk.java b/src/ru/olamedia/olacraft/world/chunk/Chunk.java new file mode 100644 index 0000000..ca2d4bf --- /dev/null +++ b/src/ru/olamedia/olacraft/world/chunk/Chunk.java @@ -0,0 +1,290 @@ +package ru.olamedia.olacraft.world.chunk; + +import ru.olamedia.geom.SimpleQuadMesh; +import ru.olamedia.olacraft.world.blockTypes.GrassBlockType; +import ru.olamedia.olacraft.world.location.BlockLocation; +import ru.olamedia.olacraft.world.location.ChunkLocation; +import ru.olamedia.olacraft.world.provider.WorldProvider; + +public class Chunk extends BlockSlice { + public boolean isMeshCostructed = false; + public SimpleQuadMesh mesh; + + public int visibleTop = 0; + public int visibleBottom = 0; + public int visibleLeft = 0; + public int visibleRight = 0; + public int visibleFront = 0; + public int visibleBack = 0; + + public Chunk(WorldProvider provider) { + super(provider, 16, 16, 16); + } + + /** + * Convert block coordinate into chunk coordinate + * + * @param v + * block coordinate along one axis + * @return + */ + public static int v(int v) { + if (v >= 0) { + return v / 16; + } else { + return (v + 1) / 16 - 1; + } + } + + /** + * Convert block coordinate into block position inside of chunk + * + * @param v + * block coordinate along one axis + * @return + */ + public static int in(int v) { + int tmp = v - v(v) * 16; + return tmp >= 0 ? tmp : 16 + tmp; // block location minus chunk base + // location + // (lower-left-back corner) + // if (v >= 0) { + // return v % 16; + // } else { + // int in = v + 1; // shift up so -1 will be 0 + // in %= 16; // get remaining -15..0 + // in += 15; // revert 0..15 + // return in; + // } + } + + public void setMeshColor(SimpleQuadMesh mesh, int x, int y, int z, boolean isSide) { + float level = 1f;// ((float) getProvider().getBlockLightLevel(x, y, z) - + // (isSide ? 2 : 0)) / 15.0f; + mesh.setColor4f(level, level, level, 1); + if (y < 0) { + mesh.setColor4f(0, 0, 1, 1); + } else if (y > 30) { + mesh.setColor4f(1, 1, 1, 1); + } else { + mesh.setColor4f(1, 1, 0, 1); + } + } + + /** + * @return the mesh + */ + public SimpleQuadMesh getMesh() { + if (isMeshCostructed) { + return mesh; + } + if (getY() > provider.getInfo().maxHeight) { + isMeshCostructed = true; + return null; + } + if (getY() < provider.getInfo().minHeight) { + isMeshCostructed = true; + return null; + } + if (null == mesh) { + mesh = new SimpleQuadMesh(14739); // unindexed + // 17x17x17 + // vertices + mesh.useColor(); + mesh.useTexture(); + // 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++) { + // + + if (!isEmptyBlock(x, y, z)) { + mesh.setTranslation(x, y, z); + // mesh.setColor4f(0, 1, 0, 1); + float cbase = (float) (y / 200.0) * (float) (7.0 / 10.0); + if (cbase > 9 / 10) { + cbase = (float) (9.0 / 10.0); + } + // cbase = (float) (9.0 / 10.0); + float cred, cgreen, cblue; + // cbase; + cred = cgreen = cblue = getLightLevel256(x, y, z); + if (x == 1) { + mesh.setColor4f(1, 0, 0, 1); + // red to the right + } + if (x == 0 || z == 0) { + if (y == 6) { + mesh.setColor4f(1, 0, 0, 1); + } else if (y % 2 == 0) { + mesh.setColor4f(1, 0, 1, 1); + } else { + mesh.setColor4f(1, 1, 0, 1); + } + } + if (z == 1) { + mesh.setColor4f(0, 0, 1, 1); + // blue to the bottom + } + if (renderBottom(x, y, z)) { + setMeshColor(mesh, x, y - 1, z, false); + mesh.setTexture(grass.getBottomTexture()); + mesh.addBottomQuad(); + visibleBottom++; + } + if (renderTop(x, y, z)) { + if (x == 15 || z == 15) { + // debug: show through.. + } else { + setMeshColor(mesh, x, y + 1, z, false); + mesh.setTexture(grass.getTopTexture()); + mesh.addTopQuad(); + } + visibleTop++; + } + if (renderLeft(x, y, z)) { + setMeshColor(mesh, x - 1, y, z, true); + mesh.setTexture(grass.getLeftTexture()); + mesh.addLeftQuad(); + visibleLeft++; + } + if (renderRight(x, y, z)) { + setMeshColor(mesh, x + 1, y, z, true); + mesh.setTexture(grass.getRightTexture()); + mesh.addRightQuad(); + visibleRight++; + } + if (renderBack(x, y, z)) { + setMeshColor(mesh, x, y, z - 1, true); + mesh.setTexture(grass.getBackTexture()); + mesh.addBackQuad(); + visibleBack++; + } + if (renderFront(x, y, z)) { + setMeshColor(mesh, x, y, z + 1, true); + mesh.setTexture(grass.getFrontTexture()); + mesh.addFrontQuad(); + visibleFront++; + } + } + } + } + } + mesh.endMesh(); + isMeshCostructed = true; + return null; + } + return mesh; + } + + /** + * @param mesh + * the mesh to set + */ + public void setMesh(SimpleQuadMesh mesh) { + this.mesh = mesh; + } + + public boolean isEmpty() { + // MUST BE LOADED + return provider.getChunk(getBlockLocation().getChunkLocation()).isEmpty(); + } + + private BlockLocation getBlockLocation() { + return new BlockLocation(getX(), getY(), getZ()); + } + + public boolean isAvailable() { + return provider.isChunkAvailable(getBlockLocation().getChunkLocation()); + } + + public boolean isNeighborsAvailable() { + int x = Chunk.v(getX()); + int y = Chunk.v(getY()); + int z = Chunk.v(getZ()); + 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)) + && provider.isChunkAvailable(new ChunkLocation(x, y + 1, z)) + && provider.isChunkAvailable(new ChunkLocation(x, y, z - 1)) + && provider.isChunkAvailable(new ChunkLocation(x, y, z + 1)); + } + + public void requestNeighbors() { + int x = Chunk.v(getX()); + int y = Chunk.v(getY()); + int z = Chunk.v(getZ()); + if (!provider.isChunkAvailable(new ChunkLocation(x - 1, y, z))) { + provider.loadChunk(new ChunkLocation(x - 1, y, z)); + } + if (!provider.isChunkAvailable(new ChunkLocation(x + 1, y, z))) { + provider.loadChunk(new ChunkLocation(x + 1, y, z)); + } + if (!provider.isChunkAvailable(new ChunkLocation(x, y - 1, z))) { + provider.loadChunk(new ChunkLocation(x, y - 1, z)); + } + if (!provider.isChunkAvailable(new ChunkLocation(x, y + 1, z))) { + provider.loadChunk(new ChunkLocation(x, y + 1, z)); + } + if (!provider.isChunkAvailable(new ChunkLocation(x, y, z - 1))) { + provider.loadChunk(new ChunkLocation(x, y, z - 1)); + } + if (!provider.isChunkAvailable(new ChunkLocation(x, y, z + 1))) { + provider.loadChunk(new ChunkLocation(x, y, z + 1)); + } + } + + public void request() { + BlockLocation blockLocation = new BlockLocation(getX(), getY(), getZ()); + // System.out.println("provider.requestChunk(" + + // blockLocation.getRegionLocation() + blockLocation.getChunkLocation() + // + ")"); + provider.loadChunk(blockLocation.getChunkLocation()); + } + + // public BlockType getBlockType(int x, int y, int z) { + // return provider.getBlockType(int x, int y, int z); + // } + + public boolean isEmptyBlock(int x, int y, int z) { + return provider.isEmptyBlock(x, y, z); + } + + public float getLightLevel256(int x, int y, int z) { + return ((float) getLightLevel(x, y, z)) / 15.0f;// * 255.0f + } + + public int getLightLevel(int x, int y, int z) { + return 15; + } + + public boolean renderBottom(int x, int y, int z) { + return provider.renderBottom(x, y, z); + } + + public boolean renderTop(int x, int y, int z) { + return provider.renderTop(x, y, z); + } + + public boolean renderLeft(int x, int y, int z) { + return provider.renderLeft(x, y, z); + } + + public boolean renderRight(int x, int y, int z) { + return provider.renderRight(x, y, z); + } + + public boolean renderFront(int x, int y, int z) { + return provider.renderFront(x, y, z); + } + + public boolean renderBack(int x, int y, int z) { + return provider.renderBack(x, y, z); + } + + public WorldProvider getProvider() { + return provider; + } +} diff --git a/src/ru/olamedia/olacraft/world/chunk/ChunkMeshBulder.java b/src/ru/olamedia/olacraft/world/chunk/ChunkMeshBulder.java new file mode 100644 index 0000000..d362199 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/chunk/ChunkMeshBulder.java @@ -0,0 +1,47 @@ +package ru.olamedia.olacraft.world.chunk; + +import java.util.concurrent.ArrayBlockingQueue; + +public class ChunkMeshBulder extends Thread { + public static ChunkMeshBulder instance = new ChunkMeshBulder("Mesh builder"); + private ArrayBlockingQueue<Chunk> chunks = new ArrayBlockingQueue<Chunk>(16); + + public ChunkMeshBulder(String name) { + super(name); + } + + public boolean isFull() { + return chunks.remainingCapacity() == 0; + } + + public void add(Chunk chunk) { + chunks.offer(chunk); + } + + public void clear() { + chunks.clear(); + } + + public void tick() throws InterruptedException { + if (!chunks.isEmpty()) { + Chunk chunk = chunks.take(); + chunk.getMesh(); + } + } + + @Override + public void run() { + // glc.makeCurrent(); + while (true) { + // main loop + try { + tick(); + // Thread.sleep(10); // or wait/join etc + } catch (InterruptedException ex) { + // cleanup here + Thread.currentThread().interrupt(); // for nested loops + break; + } + } + } +} diff --git a/src/ru/olamedia/olacraft/world/chunk/ChunkSlice.java b/src/ru/olamedia/olacraft/world/chunk/ChunkSlice.java new file mode 100644 index 0000000..e440740 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/chunk/ChunkSlice.java @@ -0,0 +1,114 @@ +package ru.olamedia.olacraft.world.chunk; + +import java.util.HashMap; + +import ru.olamedia.olacraft.world.provider.WorldProvider; + +public class ChunkSlice { + private WorldProvider provider; + private int leftX; + private int bottomY; + private int backZ; + private int width; + private int height; + private int depth; + + public ChunkSlice(WorldProvider provider, int width, int height, int depth) { + this.provider = provider; + this.width = width; + this.height = height; + this.depth = depth; + } + + protected HashMap<String, Chunk> chunks = new HashMap<String, Chunk>(); + + public Chunk getChunk(int x, int y, int 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); + chunks.put(key, chunk); + return chunk; + } + } + + /** + * @return the width + */ + public int getWidth() { + return width; + } + + /** + * @param width + * the width to set + */ + public void setWidth(int width) { + this.width = width; + } + + /** + * @return the height + */ + public int getHeight() { + return height; + } + + /** + * @param height + * the height to set + */ + public void setHeight(int height) { + this.height = height; + } + + /** + * @return the depth + */ + public int getDepth() { + return depth; + } + + /** + * @param depth + * the depth to set + */ + public void setDepth(int depth) { + 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; + } + + /** + * @return the leftX + */ + public int getX() { + return leftX; + } + + /** + * @return the bottomY + */ + public int getY() { + return bottomY; + } + + /** + * @return the backZ + */ + public int getZ() { + return backZ; + } +} diff --git a/src/ru/olamedia/olacraft/world/chunk/package-info.java b/src/ru/olamedia/olacraft/world/chunk/package-info.java new file mode 100644 index 0000000..314ea35 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/chunk/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.chunk;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/data/ChunkData.java b/src/ru/olamedia/olacraft/world/data/ChunkData.java new file mode 100644 index 0000000..a1abc9e --- /dev/null +++ b/src/ru/olamedia/olacraft/world/data/ChunkData.java @@ -0,0 +1,86 @@ +package ru.olamedia.olacraft.world.data; + +import java.io.Serializable; +import java.util.BitSet; + +import ru.olamedia.olacraft.world.chunk.Chunk; +import ru.olamedia.olacraft.world.location.BlockLocation; +import ru.olamedia.olacraft.world.location.ChunkLocation; + +public class ChunkData implements Serializable { + private static final long serialVersionUID = -5704237444737895501L; + public ChunkLocation location; + public static transient int SIZE = 4096; + // private boolean[] notEmpty = new boolean[SIZE]; + private BitSet emptyBlocks = new BitSet(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) { + 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) { + return true; + } + int id = getId(Chunk.in(blockLocation.x), Chunk.in(blockLocation.y), Chunk.in(blockLocation.z)); + return isEmpty(id); + // return !notEmpty[id]; + } + + public boolean isEmpty(int id) { + if (notEmptyCount == 0) { + return true; + } + return emptyBlocks.get(id); + } + + public void setEmpty(int id, boolean isEmpty) { + if (isEmpty(id) != isEmpty) { + if (!isEmpty) { + notEmptyCount++; + } else { + notEmptyCount--; + } + } + emptyBlocks.set(id, isEmpty); + } + + public boolean isEmpty() { + return notEmptyCount == 0; + } +} diff --git a/src/ru/olamedia/olacraft/world/data/ChunkLightData.java b/src/ru/olamedia/olacraft/world/data/ChunkLightData.java new file mode 100644 index 0000000..f574420 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/data/ChunkLightData.java @@ -0,0 +1,102 @@ +package ru.olamedia.olacraft.world.data; + +import ru.olamedia.olacraft.world.dataProvider.AbstractChunkDataProvider; + +/** + * The daylight calculated as sum of sunlight + emitted light + * The nightlight calculated as sum of emitted light + * + * The light at some time of a day calculated as part of daylight + part of + * nightlight (ex 30% of night + 70% of daylight) - sum of two array's elements + */ +public class ChunkLightData { + public static int SIZE = 4096; + /** + * Constant sunlight level + */ + public byte[] sunLevel = new byte[SIZE]; + /** + * Constant sunlight level + */ + public byte[] emittedLevel = new byte[SIZE]; + /** + * Constant light level during middle of a day + */ + public byte[] daytimeLevel = new byte[SIZE]; + /** + * Constant light level during midnight + */ + public byte[] nighttimeLevel = new byte[SIZE]; + public boolean isCalculated = false; + public boolean isSunlevelCalculated = false; + public byte[] level = new byte[SIZE]; + + 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; + } + + private static byte sunlight = 15; + + public void fillSunlight() { + // simplify: straight from top to bottom, utility to fill top layer + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + sunLevel[getId(x, 15, z)] = sunlight; + } + } + } + + public void copySunlightFromAbove(ChunkLightData above) { + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + sunLevel[getId(x, 15, z)] = above.sunLevel[getId(x, 0, z)]; + } + } + System.out.print("Copy sunlight"); + } + + /** + * Sunlight falling down until meets nonempty block from data + * + * @param data + */ + public void falldownSunlight(ChunkData data) { + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + for (int y = 14; y >= 0; y--) { + if (!data.isEmpty(getId(x, y, z))) { + break; + } else { + sunLevel[getId(x, y, z)] = sunLevel[getId(x, y + 1, z)]; + } + } + } + } + } + + public void receiveNeighborLight(AbstractChunkDataProvider abstractChunkDataProvider) { + + } + +} diff --git a/src/ru/olamedia/olacraft/world/data/HeightMap.java b/src/ru/olamedia/olacraft/world/data/HeightMap.java new file mode 100644 index 0000000..b2c0a63 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/data/HeightMap.java @@ -0,0 +1,42 @@ +package ru.olamedia.olacraft.world.data; + +import java.io.Serializable; + +/** + * Heightmap + * Useful when looking for spawn location, calculating light + * + * @author olamedia + * + */ +public class HeightMap implements Serializable { + private static final long serialVersionUID = -6777972159522169977L; + public byte[][] map; // -128..127 + public HeightMap(){ + + } + public HeightMap(int width, int height) { + map = new byte[width][height]; + } + + public void setHeight(int x, int y, int height) { + map[x][y] = (byte) height; + } + + public int getHeight(int x, int y) { + return map[x][y]; + } + + @Override + public String toString() { + StringBuilder b = new StringBuilder(); + for (int x = 0; x < map.length; x++){ + for (int z = 0; z < map[x].length; z++){ + b.append(map[x][z]); + b.append(","); + } + b.append("\n"); + } + return b.toString(); + } +} diff --git a/src/ru/olamedia/olacraft/world/data/RegionData.java b/src/ru/olamedia/olacraft/world/data/RegionData.java new file mode 100644 index 0000000..fa292d2 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/data/RegionData.java @@ -0,0 +1,57 @@ +package ru.olamedia.olacraft.world.data; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.io.Serializable; + +import ru.olamedia.olacraft.world.chunk.Chunk; +import ru.olamedia.olacraft.world.location.ChunkLocation; +import ru.olamedia.olacraft.world.location.RegionLocation; +import ru.olamedia.olacraft.world.location.SectorLocation; + +/** + * Region is a 16x16 range of sectors. (256x256x256 blocks) + * + * @author olamedia + * + */ +public class RegionData implements Serializable { + private static final long serialVersionUID = 7449677895073874520L; + public RegionLocation location; + public HeightMap heightMap = new HeightMap(256, 256); + public SectorData[][] sectorData = new SectorData[16][16]; + + public void writeTo(OutputStream stream) throws IOException { + ObjectOutputStream out = new ObjectOutputStream(stream); + out.writeObject(this); + out.close(); + } + + public static RegionData loadFrom(InputStream stream) throws IOException, ClassNotFoundException { + ObjectInputStream in = new ObjectInputStream(stream); + RegionData data = (RegionData) in.readObject(); + in.close(); + return data; + } + + public static RegionData createEmpty(RegionLocation location) { + RegionData data = new RegionData(); + data.location = location; + return data; + } + + public ChunkData getChunkData(ChunkLocation chunkLocation) { + SectorData sector = getSectorData(chunkLocation.getSectorLocation()); + int y = Chunk.in(chunkLocation.y + 128); // minHeight = -128 + return sector.chunkData[y]; + } + + public SectorData getSectorData(SectorLocation sectorLocation) { + int x = Chunk.in(sectorLocation.x); + int z = Chunk.in(sectorLocation.z); + return sectorData[x][z]; + } +} diff --git a/src/ru/olamedia/olacraft/world/data/SectorData.java b/src/ru/olamedia/olacraft/world/data/SectorData.java new file mode 100644 index 0000000..12a97cd --- /dev/null +++ b/src/ru/olamedia/olacraft/world/data/SectorData.java @@ -0,0 +1,33 @@ +package ru.olamedia.olacraft.world.data; + +import java.io.Serializable; + +import ru.olamedia.olacraft.world.location.SectorLocation; + +/** + * Sector: set of all chunks by one x,z vertical + * + * @author olamedia + * + */ +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 SectorLocation location; + + public static int yIndex(int y) { + return (y + 128) / 16; + // 1: (-128 + 128) / 16 = 0 + // ...... + // 15: (-114 + 128) / 16 = 14/16 = 0 + // 16: (-113 + 128) / 16 = 15/16 = 0 + // 17: (-112 + 128) / 16 = 16/16 = 1 + } + 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/data/UnavailableDataException.java b/src/ru/olamedia/olacraft/world/data/UnavailableDataException.java new file mode 100644 index 0000000..a75a42e --- /dev/null +++ b/src/ru/olamedia/olacraft/world/data/UnavailableDataException.java @@ -0,0 +1,23 @@ +package ru.olamedia.olacraft.world.data; + +public class UnavailableDataException extends Exception { + + public UnavailableDataException() { + super(); + } + + public UnavailableDataException(String message, Throwable cause) { + super(message, cause); + } + + public UnavailableDataException(String message) { + super(message); + } + + public UnavailableDataException(Throwable cause) { + super(cause); + } + + private static final long serialVersionUID = -8955947061088863309L; + +} diff --git a/src/ru/olamedia/olacraft/world/data/package-info.java b/src/ru/olamedia/olacraft/world/data/package-info.java new file mode 100644 index 0000000..2a171a6 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/data/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.data;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/dataProvider/AbstractChunkDataProvider.java b/src/ru/olamedia/olacraft/world/dataProvider/AbstractChunkDataProvider.java new file mode 100644 index 0000000..1670ef3 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/dataProvider/AbstractChunkDataProvider.java @@ -0,0 +1,60 @@ +package ru.olamedia.olacraft.world.dataProvider; + +import ru.olamedia.olacraft.world.data.ChunkData; +import ru.olamedia.olacraft.world.data.RegionData; +import ru.olamedia.olacraft.world.data.SectorData; +import ru.olamedia.olacraft.world.location.ChunkLocation; +import ru.olamedia.olacraft.world.location.RegionLocation; +import ru.olamedia.olacraft.world.location.SectorLocation; + +abstract public class AbstractChunkDataProvider { + /** + * is data already available or we should wait + * + * @param RegionLocation + * @return + */ + public boolean isChunkAvailable(ChunkLocation chunkLocation) { + return this.isRegionAvailable(chunkLocation.getRegionLocation()); + } + + public boolean isSectorAvailable(SectorLocation sectorLocation) { + return this.isRegionAvailable(sectorLocation.getRegionLocation()); + } + + abstract public boolean isRegionAvailable(RegionLocation regionLocation); + + /** + * we need this chunk now, send request to server or preload + * + * @param RegionLocation + */ + public void loadChunk(ChunkLocation chunkLocation) { + //System.out.println("loadChunk(" + chunkLocation + ")"); + this.loadRegion(chunkLocation.getRegionLocation()); + //System.out.println("loadChunk(" + chunkLocation + ")--"); + } + + public void loadSector(SectorLocation sectorLocation) { + this.loadRegion(sectorLocation.getRegionLocation()); + } + + abstract public void loadRegion(RegionLocation regionLocation); + + /** + * Get data if already available + * + * @param RegionLocation + * @return + */ + public ChunkData getChunk(ChunkLocation chunkLocation) { + return this.getRegion(chunkLocation.getRegionLocation()).getChunkData(chunkLocation); + } + + public SectorData getSector(SectorLocation sectorLocation) { + return this.getRegion(sectorLocation.getRegionLocation()).getSectorData(sectorLocation); + } + + abstract public RegionData getRegion(RegionLocation regionLocation); + +} diff --git a/src/ru/olamedia/olacraft/world/dataProvider/CachedChunkDataProvider.java b/src/ru/olamedia/olacraft/world/dataProvider/CachedChunkDataProvider.java new file mode 100644 index 0000000..23270a7 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/dataProvider/CachedChunkDataProvider.java @@ -0,0 +1,70 @@ +package ru.olamedia.olacraft.world.dataProvider; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import ru.olamedia.olacraft.world.data.RegionData; +import ru.olamedia.olacraft.world.location.RegionLocation; + +public class CachedChunkDataProvider extends AbstractChunkDataProvider { + private AbstractChunkDataProvider provider; + private HashMap<String, RegionData> regionMap = new HashMap<String, RegionData>(); + private List<String> loading = new ArrayList<String>(); + + public CachedChunkDataProvider(AbstractChunkDataProvider provider) { + this.provider = provider; + } + + private static boolean DEBUG = true; + + private void debug(String s) { + if (DEBUG) { + System.out.println("[CachedChunkDataProvider] " + s); + } + } + + @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 + ")"); + if (!regionMap.containsKey(key)) { + if (!loading.contains(key)) { + debug("load()"); + loading.add(key); + provider.loadRegion(regionLocation); + }else{ + //debug("loadRegion(" + regionLocation + ") already in loading"); + } + }else{ + debug("error: loadRegion(" + regionLocation + ") already in regionMap"); + } + } + + @Override + public RegionData getRegion(RegionLocation regionLocation) { + String key = regionLocation.toString(); + if (regionMap.containsKey(key)) { + return regionMap.get(key); + } 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 new file mode 100644 index 0000000..514081f --- /dev/null +++ b/src/ru/olamedia/olacraft/world/dataProvider/LocalChunkDataProvider.java @@ -0,0 +1,218 @@ +package ru.olamedia.olacraft.world.dataProvider; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +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; + +public class LocalChunkDataProvider extends AbstractChunkDataProvider { + private String worldName; + private String path; + + private static boolean DEBUG = true; + + private void debug(String s) { + if (DEBUG) { + System.out.println("[LocalChunkDataProvider] " + s); + } + } + + public LocalChunkDataProvider(String worldName) { + this.worldName = worldName; + path = "data" + File.separator + this.worldName; + File worldDir = new File(path); + if (!worldDir.isDirectory()) { + worldDir.mkdirs(); + } + } + + private int[] seed; + + private int[] getSeed() throws IOException { + if (null == seed) { + String filename = path + File.separator + "world.seed"; + File seedFile = new File(filename); + // md5 - 32x0-f = 16 bytes or 8 short int + seed = new int[8]; + if (seedFile.exists()) { + InputStream in = null; + DataInputStream din = null; + in = new FileInputStream(seedFile); + din = new DataInputStream(in); + for (int i = 0; i < 8; i++) { + seed[i] = din.readShort(); + } + din.close(); + in.close(); + } else { + OutputStream out = new FileOutputStream(seedFile); + DataOutputStream dout = new DataOutputStream(out); + for (int i = 0; i < 8; i++) { + seed[i] = (int) (Integer.MAX_VALUE * Math.random()); + dout.writeShort(seed[i]); + } + dout.close(); + out.close(); + } + } + return seed; + } + + @Override + public boolean isRegionAvailable(RegionLocation regionLocation) { + return true; + } + + @Override + public void loadRegion(RegionLocation regionLocation) { + // do nothing... + 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; + } + + @Override + public RegionData getRegion(RegionLocation regionLocation) { + String filename = path + File.separator + regionLocation.getFilename(); + RegionData data = null; + // TODO READ/WRITE FILE + File chunkFile = new File(filename); + if (chunkFile.exists()) { + InputStream in; + try { + in = new FileInputStream(chunkFile); + data = RegionData.loadFrom(in); + in.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } else { + data = generateRegion(regionLocation); + try { + chunkFile.createNewFile(); + FileOutputStream out = new FileOutputStream(chunkFile); + data.writeTo(out); + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return data; + } + + public RegionData generateRegion(RegionLocation regionLocation) { + RegionData data = new RegionData(); + data.location = regionLocation; + // TODO FILL HERE + RegionGenerator generator = new RegionGenerator(); + try { + generator.setSeed(getSeed()); + } catch (IOException e) { + e.printStackTrace(); + } + generator.generate(data); + 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/LocalRegionDataProvider.java b/src/ru/olamedia/olacraft/world/dataProvider/LocalRegionDataProvider.java new file mode 100644 index 0000000..447bcc3 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/dataProvider/LocalRegionDataProvider.java @@ -0,0 +1,57 @@ +package ru.olamedia.olacraft.world.dataProvider; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public class LocalRegionDataProvider { + private String worldName; + private String path; + + public LocalRegionDataProvider(String worldName) { + this.worldName = worldName; + path = "data" + File.separator + this.worldName; + File worldDir = new File(path); + if (!worldDir.isDirectory()) { + worldDir.mkdirs(); + } + } + + private int[] seed; + + private int[] getSeed() throws IOException { + if (null == seed) { + String filename = path + File.separator + "world.seed"; + File seedFile = new File(filename); + // md5 - 32x0-f = 16 bytes or 8 short int + seed = new int[8]; + if (seedFile.exists()) { + InputStream in = null; + DataInputStream din = null; + in = new FileInputStream(seedFile); + din = new DataInputStream(in); + for (int i = 0; i < 8; i++) { + seed[i] = din.readShort(); + } + din.close(); + in.close(); + } else { + OutputStream out = new FileOutputStream(seedFile); + DataOutputStream dout = new DataOutputStream(out); + for (int i = 0; i < 8; i++) { + seed[i] = (int) (Integer.MAX_VALUE * Math.random()); + dout.writeShort(seed[i]); + } + dout.close(); + out.close(); + } + } + return seed; + } + +} diff --git a/src/ru/olamedia/olacraft/world/dataProvider/RemoteChunkDataProvider.java b/src/ru/olamedia/olacraft/world/dataProvider/RemoteChunkDataProvider.java new file mode 100644 index 0000000..8284ff9 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/dataProvider/RemoteChunkDataProvider.java @@ -0,0 +1,75 @@ +package ru.olamedia.olacraft.world.dataProvider; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import com.esotericsoftware.kryonet.Connection; + +import ru.olamedia.olacraft.network.GameClient; +import ru.olamedia.olacraft.network.packet.GetRegionPacket; +import ru.olamedia.olacraft.network.packet.IPacket; +import ru.olamedia.olacraft.network.packet.IPacketListener; +import ru.olamedia.olacraft.network.packet.RegionDataPacket; +import ru.olamedia.olacraft.world.data.RegionData; +import ru.olamedia.olacraft.world.location.RegionLocation; + +public class RemoteChunkDataProvider extends AbstractChunkDataProvider implements IPacketListener { + + private GameClient client; + private HashMap<String, RegionData> map = new HashMap<String, RegionData>(); + private List<String> loading = new ArrayList<String>(); + + public RemoteChunkDataProvider(GameClient client) { + this.client = client; + this.client.addPacketListener(this); + } + + private static boolean DEBUG = true; + + private void debug(String s) { + if (DEBUG) { + System.out.println("[RemoteChunkDataProvider] " + s); + } + } + + @Override + public void loadRegion(RegionLocation regionLocation) { + String key = regionLocation.toString(); + debug("loadRegion(" + key + ")"); + if (!loading.contains(key)) { + loading.add(key); + client.send(new GetRegionPacket(regionLocation)); + debug("sent packet: GetRegionPacket"); + } + } + + @Override + public boolean isRegionAvailable(RegionLocation regionLocation) { + String key = regionLocation.toString(); + if (loading.contains(key)) { + return false; + } + return map.containsKey(key); + } + + @Override + public RegionData getRegion(RegionLocation regionLocation) { + String key = regionLocation.toString(); + RegionData data = map.get(key); + map.remove(key); + return data; + } + + @Override + public void onPacket(Connection connection, IPacket p) { + if (p instanceof RegionDataPacket) { + debug("received packet [conn " + connection.getID() + "]: ChunkDataPacket"); + RegionData data = ((RegionDataPacket) p).data; + String key = data.location.toString(); + map.put(key, data); + loading.remove(key); + } + } + +} diff --git a/src/ru/olamedia/olacraft/world/dataProvider/package-info.java b/src/ru/olamedia/olacraft/world/dataProvider/package-info.java new file mode 100644 index 0000000..6a411e6 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/dataProvider/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.dataProvider;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/generator/HeightMapGenerator.java b/src/ru/olamedia/olacraft/world/generator/HeightMapGenerator.java new file mode 100644 index 0000000..c3e32b5 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/generator/HeightMapGenerator.java @@ -0,0 +1,157 @@ +package ru.olamedia.olacraft.world.generator; + +import ru.olamedia.olacraft.world.chunk.Chunk; +import ru.olamedia.olacraft.world.data.HeightMap; +import ru.olamedia.olacraft.world.location.RegionLocation; +import libnoiseforjava.NoiseGen.NoiseQuality; +import libnoiseforjava.exception.ExceptionInvalidParam; +import libnoiseforjava.module.Billow; +import libnoiseforjava.module.Blend; +import libnoiseforjava.module.Max; +import libnoiseforjava.module.Perlin; +import libnoiseforjava.module.RidgedMulti; +import libnoiseforjava.module.ScaleBias; +import libnoiseforjava.module.Select; +import libnoiseforjava.module.Turbulence; +import libnoiseforjava.util.NoiseMap; +import libnoiseforjava.util.NoiseMapBuilderPlane; + +public class HeightMapGenerator { + public static int minValue; + public static int maxValue; + + public static int seed = (int) (Integer.MAX_VALUE * Math.random()); + + private static Billow plainsNoise; + private static ScaleBias plains; + private static RidgedMulti hillsNoise; + private static ScaleBias hills; + private static RidgedMulti mountainsNoise; + private static ScaleBias mountains; + private static Perlin terrainType; + private static Blend blendedTerrain; + private static Select selectedTerrain; + private static Max maxTerrain; + private static Turbulence turbulence; + private static ScaleBias finalTerrain; + + private static boolean isInitialized = false; + + public static void init() { + if (isInitialized) { + return; + } + isInitialized = true; + try { + // PLAINS + plainsNoise = new Billow(); + plainsNoise.setFrequency(0.01); + plains = new ScaleBias(plainsNoise); + plains.setScale(0.05); + plains.setBias(-0.75); + // HILLS + hillsNoise = new RidgedMulti(); + hillsNoise.setFrequency(0.01); + hills = new ScaleBias(hillsNoise); + hills.setScale(0.5); + hills.setBias(-0.75); + // MOUNTAINS + mountainsNoise = new RidgedMulti(); + mountainsNoise.setFrequency(0.04); + mountainsNoise.setOctaveCount(6); + turbulence = new Turbulence(mountainsNoise); + turbulence.setFrequency(0.2); + turbulence.setPower(1); + mountains = new ScaleBias(turbulence); + mountains.setScale(1.0); + mountains.setBias(-1.25); + terrainType = new Perlin(); + terrainType.setOctaveCount(6); + terrainType.setFrequency(0.06); + terrainType.setPersistence(0.25); + terrainType.setNoiseQuality(NoiseQuality.QUALITY_BEST); + selectedTerrain = new Select(plains, mountains, terrainType); + selectedTerrain.setBounds(0, 1); + selectedTerrain.setEdgeFalloff(0.125); + blendedTerrain = new Blend(plains, mountains, terrainType); + maxTerrain = new Max(plains, turbulence); + finalTerrain = new ScaleBias(maxTerrain); + finalTerrain.setBias(2); + setSeed(seed); + } catch (ExceptionInvalidParam e) { + e.printStackTrace(); + } + } + + public static void setSeed(int newseed) { + seed = newseed; + plainsNoise.setSeed(seed); + hillsNoise.setSeed(seed); + mountainsNoise.setSeed(seed); + terrainType.setSeed(seed); + } + + public static int[][] getChunkHeightMap(int chunkX, int chunkZ) { + init(); + try { + NoiseMapBuilderPlane builder = new NoiseMapBuilderPlane(16, 16); + // builder.enableSeamless(true); + // Perlin plains = new Perlin(); + + // Select finalTerrain = new Select(plains, mountains, null); + // finalTerrain.setControlModule(terrainType); + // finalTerrain.setBounds(0.0, 1000); + // finalTerrain.setEdgeFalloff(1.25); + + NoiseMap heightMap = new NoiseMap(16, 16); + builder.setSourceModule(maxTerrain); + builder.setDestNoiseMap(heightMap); + double bx = chunkX; + double bz = chunkZ; + builder.setDestSize(16, 16); + builder.setBounds(bx, bx + 1, bz, bz + 1); + builder.build(); + double[][] heights = heightMap.getNoiseMap(); + int[][] ints = new int[16][16]; + // System.out.print("heightmap:"); + 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); + } + } + // System.out.println(""); + return ints; + } catch (ExceptionInvalidParam e) { + e.printStackTrace(); + } + return null; + } + + public static HeightMap getHeightMap(RegionLocation location) { + init(); + HeightMap map = new HeightMap(256, 256); + try { + NoiseMapBuilderPlane builder = new NoiseMapBuilderPlane(256, 256); + NoiseMap heightMap = new NoiseMap(256, 256); + 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); + 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) + } + } + return map; + } catch (ExceptionInvalidParam e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/src/ru/olamedia/olacraft/world/generator/ImprovedNoise.java b/src/ru/olamedia/olacraft/world/generator/ImprovedNoise.java new file mode 100644 index 0000000..365aa12 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/generator/ImprovedNoise.java @@ -0,0 +1,61 @@ +package ru.olamedia.olacraft.world.generator; + +//JAVA REFERENCE IMPLEMENTATION OF IMPROVED NOISE - COPYRIGHT 2002 KEN PERLIN. + +public final class ImprovedNoise { + static public double noise(double x, double y, double z) { + int X = (int) Math.floor(x) & 255, // FIND UNIT CUBE THAT + Y = (int) Math.floor(y) & 255, // CONTAINS POINT. + Z = (int) Math.floor(z) & 255; + x -= Math.floor(x); // FIND RELATIVE X,Y,Z + y -= Math.floor(y); // OF POINT IN CUBE. + z -= Math.floor(z); + double u = fade(x), // COMPUTE FADE CURVES + v = fade(y), // FOR EACH OF X,Y,Z. + w = fade(z); + int A = p[X] + Y, AA = p[A] + Z, AB = p[A + 1] + Z, // HASH COORDINATES + // OF + B = p[X + 1] + Y, BA = p[B] + Z, BB = p[B + 1] + Z; // THE 8 CUBE + // CORNERS, + + return lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z), // AND ADD + grad(p[BA], x - 1, y, z)), // BLENDED + lerp(u, grad(p[AB], x, y - 1, z), // RESULTS + grad(p[BB], x - 1, y - 1, z))),// FROM 8 + lerp(v, lerp(u, grad(p[AA + 1], x, y, z - 1), // CORNERS + grad(p[BA + 1], x - 1, y, z - 1)), // OF CUBE + lerp(u, grad(p[AB + 1], x, y - 1, z - 1), grad(p[BB + 1], x - 1, y - 1, z - 1)))); + } + + static double fade(double t) { + return t * t * t * (t * (t * 6 - 15) + 10); + } + + static double lerp(double t, double a, double b) { + return a + t * (b - a); + } + + static double grad(int hash, double x, double y, double z) { + int h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE + double u = h < 8 ? x : y, // INTO 12 GRADIENT DIRECTIONS. + v = h < 4 ? y : h == 12 || h == 14 ? x : z; + return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); + } + + static final int p[] = new int[512], permutation[] = { 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, + 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, + 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, + 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, + 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, + 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, + 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, + 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129, + 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, + 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, + 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, + 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 }; + static { + for (int i = 0; i < 256; i++) + p[256 + i] = p[i] = permutation[i]; + } +} diff --git a/src/ru/olamedia/olacraft/world/generator/Lerp.java b/src/ru/olamedia/olacraft/world/generator/Lerp.java new file mode 100644 index 0000000..cc009fe --- /dev/null +++ b/src/ru/olamedia/olacraft/world/generator/Lerp.java @@ -0,0 +1,27 @@ +package ru.olamedia.olacraft.world.generator; + +public class Lerp { + public static float lerp(float x, float x1, float x2, float q00, float q01) { + return ((x2 - x) / (x2 - x1)) * q00 + ((x - x1) / (x2 - x1)) * q01; + } + + public static float biLerp(float x, float y, float q11, float q12, float q21, float q22, float x1, float x2, + float y1, float y2) { + float r1 = lerp(x, x1, x2, q11, q21); + float r2 = lerp(x, x1, x2, q12, q22); + + return lerp(y, y1, y2, r1, r2); + } + + public static float triLerp(float x, float y, float z, float q000, float q001, float q010, float q011, float q100, + float q101, float q110, float q111, float x1, float x2, float y1, float y2, float z1, float z2) { + float x00 = lerp(x, x1, x2, q000, q100); + float x10 = lerp(x, x1, x2, q010, q110); + float x01 = lerp(x, x1, x2, q001, q101); + float x11 = lerp(x, x1, x2, q011, q111); + float r0 = lerp(y, y1, y2, x00, x01); + float r1 = lerp(y, y1, y2, x10, x11); + + return lerp(z, z1, z2, r0, r1); + } +} diff --git a/src/ru/olamedia/olacraft/world/generator/RegionGenerator.java b/src/ru/olamedia/olacraft/world/generator/RegionGenerator.java new file mode 100644 index 0000000..9657e32 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/generator/RegionGenerator.java @@ -0,0 +1,71 @@ +package ru.olamedia.olacraft.world.generator; + +import ru.olamedia.olacraft.world.data.ChunkData; +import ru.olamedia.olacraft.world.data.HeightMap; +import ru.olamedia.olacraft.world.data.RegionData; +import ru.olamedia.olacraft.world.data.SectorData; +import ru.olamedia.olacraft.world.location.BlockLocation; +import ru.olamedia.olacraft.world.location.ChunkLocation; +import ru.olamedia.olacraft.world.location.SectorLocation; + +public class RegionGenerator { + private int[] seed; + + public void setSeed(int[] seed) { + this.seed = seed; + } + + public void debug(String s) { + System.out.println("[RegionGenerator] " + s); + } + + public void generate(RegionData data) { + HeightMapGenerator.minValue = -5; + HeightMapGenerator.maxValue = 100; + HeightMapGenerator.init(); + HeightMapGenerator.seed = seed[0]; + BlockLocation offset = data.location.getBlockLocation(); + // 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()); + 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.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; + 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); + sector.heightMap.setHeight(inChunkX, inChunkZ, height); + 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); + } else { + //System.out.println("not empty, height: " + height); + chunk.setEmpty(id, false); + } + } + } + } + chunk.compact(); + sector.chunkData[y] = chunk; + } + data.sectorData[x][z] = sector; + } + } + } +} diff --git a/src/ru/olamedia/olacraft/world/generator/package-info.java b/src/ru/olamedia/olacraft/world/generator/package-info.java new file mode 100644 index 0000000..2f62117 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/generator/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.generator;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/location/BlockLocation.java b/src/ru/olamedia/olacraft/world/location/BlockLocation.java new file mode 100644 index 0000000..b104bad --- /dev/null +++ b/src/ru/olamedia/olacraft/world/location/BlockLocation.java @@ -0,0 +1,37 @@ +package ru.olamedia.olacraft.world.location; + +import java.io.Serializable; + +import ru.olamedia.olacraft.world.chunk.Chunk; + +public class BlockLocation implements Serializable { + private static final long serialVersionUID = -4987461467575474762L; + public int x; + public int y; + public int z; + + public BlockLocation() { + } + + public BlockLocation(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + public ChunkLocation getChunkLocation() { + return new ChunkLocation(Chunk.v(x), Chunk.v(y + 128), Chunk.v(z)); + } + + public RegionLocation getRegionLocation() { + return new RegionLocation(Chunk.v(Chunk.v(x)), Chunk.v(Chunk.v(z))); + } + + public SectorLocation getSectorLocation() { + return new SectorLocation(Chunk.v(x), Chunk.v(z)); + } + + public String toString() { + return "blockLocation[" + x + "," + y + "," + z + "]"; + } +} diff --git a/src/ru/olamedia/olacraft/world/location/ChunkLocation.java b/src/ru/olamedia/olacraft/world/location/ChunkLocation.java new file mode 100644 index 0000000..57acc52 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/location/ChunkLocation.java @@ -0,0 +1,40 @@ +package ru.olamedia.olacraft.world.location; + +import java.io.Serializable; + +import ru.olamedia.olacraft.world.chunk.Chunk; + +public class ChunkLocation implements Serializable { + private static final long serialVersionUID = -3620722885522274470L; + + public ChunkLocation() { + + } + + public ChunkLocation(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + public int x; + public int y; + public int z; + + public SectorLocation getSectorLocation() { + return new SectorLocation(x, z); + } + + public RegionLocation getRegionLocation() { + return new RegionLocation(Chunk.v(x), Chunk.v(z)); + } + + public String toString() { + return "chunkLocation[" + x + "," + y + "," + z + "]"; + } + /* + * public BlockSlice getSlice(){ + * + * } + */ +} diff --git a/src/ru/olamedia/olacraft/world/location/RegionLocation.java b/src/ru/olamedia/olacraft/world/location/RegionLocation.java new file mode 100644 index 0000000..59a57ec --- /dev/null +++ b/src/ru/olamedia/olacraft/world/location/RegionLocation.java @@ -0,0 +1,29 @@ +package ru.olamedia.olacraft.world.location; + +import java.io.Serializable; + +public class RegionLocation implements Serializable { + private static final long serialVersionUID = -141619138379029773L; + public int x; + public int z; + + public RegionLocation() { + } + + public RegionLocation(int x, int z) { + this.x = x; + this.z = z; + } + + public String toString() { + return "regionLocation[" + x + "," + z + "]"; + } + + public String getFilename() { + return "" + x + "_" + z + ".region"; + } + + public BlockLocation getBlockLocation() { + return new BlockLocation(x * 256, 0, z * 256); + } +} diff --git a/src/ru/olamedia/olacraft/world/location/SectorLocation.java b/src/ru/olamedia/olacraft/world/location/SectorLocation.java new file mode 100644 index 0000000..59390b8 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/location/SectorLocation.java @@ -0,0 +1,29 @@ +package ru.olamedia.olacraft.world.location; + +import java.io.Serializable; + +import ru.olamedia.olacraft.world.chunk.Chunk; + +public class SectorLocation implements Serializable { + private static final long serialVersionUID = 4500216114186249375L; + + public SectorLocation() { + + } + + public SectorLocation(int x, int z) { + this.x = x; + this.z = z; + } + + public int x; + public int z; + + public RegionLocation getRegionLocation() { + return new RegionLocation(Chunk.v(x), Chunk.v(z)); + } + + public String toString() { + return "sectorLocation[" + x + "," + z + "]"; + } +} diff --git a/src/ru/olamedia/olacraft/world/location/package-info.java b/src/ru/olamedia/olacraft/world/location/package-info.java new file mode 100644 index 0000000..37f205d --- /dev/null +++ b/src/ru/olamedia/olacraft/world/location/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.location;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/package-info.java b/src/ru/olamedia/olacraft/world/package-info.java new file mode 100644 index 0000000..914d8d2 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/provider/IChunkProvider.java b/src/ru/olamedia/olacraft/world/provider/IChunkProvider.java new file mode 100644 index 0000000..5076c75 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/provider/IChunkProvider.java @@ -0,0 +1,8 @@ +package ru.olamedia.olacraft.world.provider; + +import ru.olamedia.olacraft.world.block.Block; + +public interface IChunkProvider { + public boolean isEmptyBlock(int x, int y, int z); + public Block getBlock(int x, int y, int z); +} diff --git a/src/ru/olamedia/olacraft/world/provider/WorldProvider.java b/src/ru/olamedia/olacraft/world/provider/WorldProvider.java new file mode 100644 index 0000000..8dacce9 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/provider/WorldProvider.java @@ -0,0 +1,130 @@ +package ru.olamedia.olacraft.world.provider; + +import ru.olamedia.olacraft.game.SpawnLocation; +import ru.olamedia.olacraft.world.WorldInfo; +import ru.olamedia.olacraft.world.block.Block; +import ru.olamedia.olacraft.world.chunk.Chunk; +import ru.olamedia.olacraft.world.data.ChunkData; +import ru.olamedia.olacraft.world.data.RegionData; +import ru.olamedia.olacraft.world.dataProvider.AbstractChunkDataProvider; +import ru.olamedia.olacraft.world.location.BlockLocation; +import ru.olamedia.olacraft.world.location.ChunkLocation; +import ru.olamedia.olacraft.world.location.RegionLocation; + +public class WorldProvider { + private WorldInfo info = new WorldInfo(); + private AbstractChunkDataProvider dataProvider; + + public WorldInfo getInfo() { + return info; + } + + public void setInfo(WorldInfo worldInfo) { + info = worldInfo; + } + + /* + * public AbstractChunkDataProvider getChunkDataProvider() { + * return dataProvider; + * } + */ + + public void setChunkDataProvider(AbstractChunkDataProvider provider) { + dataProvider = provider; + } + + public SpawnLocation getSpawnLocation(int connectionId) { + SpawnLocation l = new SpawnLocation(); + int maxShift = 10; + l.x = (int) (maxShift - Math.random() * 2 * maxShift); + l.z = (int) (maxShift - Math.random() * 2 * maxShift); + System.out.print("Searching spawn Y"); + BlockLocation spawnLocation = new BlockLocation(l.x, 0, l.z); + for (int y = info.maxHeight; y > info.minHeight; y--) { + // search for floor block + 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) { + // found + l.y = y + 1; + System.out.println("found: " + y); + return l; + } + } + System.out.println("not found "); + // not found + l.y = info.maxHeight; + return l; + } + + public boolean renderBottom(int x, int y, int z) { + return (!isEmptyBlock(x, y, z)) && (isEmptyBlock(x, y - 1, z)); + } + + public boolean renderTop(int x, int y, int z) { + return (!isEmptyBlock(x, y, z)) && (isEmptyBlock(x, y + 1, z)); + } + + public boolean renderLeft(int x, int y, int z) { + return (!isEmptyBlock(x, y, z)) && (isEmptyBlock(x - 1, y, z)); + } + + public boolean renderRight(int x, int y, int z) { + return (!isEmptyBlock(x, y, z)) && (isEmptyBlock(x + 1, y, z)); + } + + public boolean renderBack(int x, int y, int z) { + return (!isEmptyBlock(x, y, z)) && (isEmptyBlock(x, y, z - 1)); + } + + public boolean renderFront(int x, int y, int z) { + return (!isEmptyBlock(x, y, z)) && (isEmptyBlock(x, y, z + 1)); + } + + public boolean isEmptyBlock(int x, int y, int z) { + BlockLocation blockLocation = new BlockLocation(x, y, z); + + if (isChunkAvailable(blockLocation.getChunkLocation())) { + ChunkData data = dataProvider.getChunk(blockLocation.getChunkLocation()); + if (null != data) { + return data.isEmpty(blockLocation); + } + } + return false; + } + + public void requestChunk(int chunkX, int chunkY, int chunkZ) { + ChunkLocation chunkLocation = new ChunkLocation(chunkX, chunkY, chunkZ); + // getChunkDataProvider().loadRegion(chunkLocation.getRegionLocation()); + loadChunk(chunkLocation); + } + + public boolean isChunkAvailable(ChunkLocation chunkLocation) { + return dataProvider.isChunkAvailable(chunkLocation); + } + + public boolean isAvailableBlock(int x, int y, int z) { + BlockLocation blockLocation = new BlockLocation(x, y, z); + return dataProvider.isChunkAvailable(blockLocation.getChunkLocation()); + } + + public void loadChunk(ChunkLocation chunkLocation) { + dataProvider.loadChunk(chunkLocation); + } + + public RegionData getRegion(RegionLocation regionLocation) { + return dataProvider.getRegion(regionLocation); + } + + public Block getBlock(int x, int y, int z) { + BlockLocation blockLocation = new BlockLocation(x, y, z); + return new Block(this, x, y, z); + } + + public ChunkData getChunk(ChunkLocation chunkLocation) { + return dataProvider.getChunk(chunkLocation); + } +} diff --git a/src/ru/olamedia/olacraft/world/provider/blockData/BlockData.java b/src/ru/olamedia/olacraft/world/provider/blockData/BlockData.java new file mode 100644 index 0000000..94be4d7 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/provider/blockData/BlockData.java @@ -0,0 +1,5 @@ +package ru.olamedia.olacraft.world.provider.blockData; + +public class BlockData { + +} diff --git a/src/ru/olamedia/olacraft/world/provider/blockData/EmptyBlockData.java b/src/ru/olamedia/olacraft/world/provider/blockData/EmptyBlockData.java new file mode 100644 index 0000000..ab17107 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/provider/blockData/EmptyBlockData.java @@ -0,0 +1,5 @@ +package ru.olamedia.olacraft.world.provider.blockData; + +public class EmptyBlockData implements IBlockData{ + public boolean notEmpty = false; +} diff --git a/src/ru/olamedia/olacraft/world/provider/blockData/IBlockData.java b/src/ru/olamedia/olacraft/world/provider/blockData/IBlockData.java new file mode 100644 index 0000000..95dfb35 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/provider/blockData/IBlockData.java @@ -0,0 +1,5 @@ +package ru.olamedia.olacraft.world.provider.blockData; + +public interface IBlockData { + public boolean notEmpty = false; +} diff --git a/src/ru/olamedia/olacraft/world/provider/blockData/package-info.java b/src/ru/olamedia/olacraft/world/provider/blockData/package-info.java new file mode 100644 index 0000000..0fa952a --- /dev/null +++ b/src/ru/olamedia/olacraft/world/provider/blockData/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.provider.blockData;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/provider/package-info.java b/src/ru/olamedia/olacraft/world/provider/package-info.java new file mode 100644 index 0000000..c43643a --- /dev/null +++ b/src/ru/olamedia/olacraft/world/provider/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.provider;
\ No newline at end of file diff --git a/src/ru/olamedia/player/Player.java b/src/ru/olamedia/player/Player.java new file mode 100644 index 0000000..08811b5 --- /dev/null +++ b/src/ru/olamedia/player/Player.java @@ -0,0 +1,31 @@ +package ru.olamedia.player; + +import ru.olamedia.liveEntity.LiveEntity; +import ru.olamedia.olacraft.game.Game; +import ru.olamedia.olacraft.network.packet.LiveEntityLocationUpdatePacket; +import ru.olamedia.olacraft.weapon.Bullet; + +public class Player extends LiveEntity { + + @Override + public void notifyLocationUpdate() { + LiveEntityLocationUpdatePacket p = new LiveEntityLocationUpdatePacket(); + p.x = getX(); + p.y = getY(); + p.z = getZ(); + Game.client.send(p); + } + + public Player() { + + } + + public void onMouseClick() { + Bullet b = new Bullet(); + b.velocity.set(Game.instance.camera.getLook()); + b.velocity.negate(); + b.velocity.scale(100); + b.location.set(getX(), getCameraY(), getZ()); + Game.client.getScene().addBullet(b); + } +} diff --git a/src/ru/olamedia/tasks/Task.java b/src/ru/olamedia/tasks/Task.java new file mode 100644 index 0000000..1886265 --- /dev/null +++ b/src/ru/olamedia/tasks/Task.java @@ -0,0 +1,24 @@ +package ru.olamedia.tasks; + +public abstract class Task implements Runnable { + + public Task(){ + TaskManager.add(this); + } + + protected volatile boolean stopped = false; + + public void setStopped(boolean s){ + this.stopped = s; + } + + public void stop() { + this.stopped = true; + } + + protected boolean shouldStop() { + return this.stopped; + } + + public abstract void run(); +} diff --git a/src/ru/olamedia/tasks/TaskManager.java b/src/ru/olamedia/tasks/TaskManager.java new file mode 100644 index 0000000..e1a637e --- /dev/null +++ b/src/ru/olamedia/tasks/TaskManager.java @@ -0,0 +1,18 @@ +package ru.olamedia.tasks; + +import java.util.ArrayList; +import java.util.List; + +public class TaskManager { + private static List<Task> tasks = new ArrayList<Task>(); + + public static void add(Task task) { + tasks.add(task); + } + + public static void stopAll() { + for (Task task : tasks) { + task.stop(); + } + } +} diff --git a/src/ru/olamedia/tasks/package-info.java b/src/ru/olamedia/tasks/package-info.java new file mode 100644 index 0000000..88dffa7 --- /dev/null +++ b/src/ru/olamedia/tasks/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.tasks;
\ No newline at end of file diff --git a/src/ru/olamedia/texture/ResourceUtil.java b/src/ru/olamedia/texture/ResourceUtil.java new file mode 100644 index 0000000..656e3a8 --- /dev/null +++ b/src/ru/olamedia/texture/ResourceUtil.java @@ -0,0 +1,126 @@ +package ru.olamedia.texture; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; + +public class ResourceUtil { + + private static URL baseURL; + + private static ResourceUtil instance; + + public static ResourceUtil getInstance() { + if (null == instance) { + instance = new ResourceUtil(); + } + return instance; + } + + public static URL getInternalBaseURL() { + if (null == baseURL) { + URL url = getInstance().getClass().getResource("ResourceUtil.class"); + // URL back = null; + // try { + // back = new URL(url, ".."); + // } catch (MalformedURLException e1) { + // e1.printStackTrace(); + // } + // System.out.println("Back:" + back); + // System.out.println("Class:" + url); + int p = url.toString().indexOf("jar!"); + if (p > 0) { + // in local jar: + // jar:file:/E:/com/mindprod/thepackage/thepackage.jar!/com/mindprod/thepackage/images/blueball.gif + // in remote jar: + // jar:http://mindprod.com/thepackage.jar!/com/mindprod/thepackage/images/blueball.gif + try { + baseURL = new URL(url.toString().substring(0, p + 4)); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + } else { + // in local file: + // file:/E:/com/mindprod/thepackage/images/blueball.gif + // in remote file: + // http://mindprod.com/com/mindprod/the...s/blueball.gif + int l = url.toString().length() - (ResourceUtil.class.toString()).length(); + try { + baseURL = new URL(url.toString().substring(0, l)); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + } + } + return baseURL; + } + + public static String getInternalFilename(String fn) { + return getInternalBaseURL() + fn; + } + + public static URL getInternalResource(String internalPath) throws MalformedURLException { + URL url = ResourceUtil.class.getClassLoader().getResource(internalPath); + if (url == null) { + System.out.println(internalPath + " not found"); + } else { + System.out.println(url.toString()); + } + return url; + // return new URL(getInternalBaseURL(), internalPath); + } + + public static URL getURL(String internalPath) { + try { + return new URL(getInternalBaseURL(), internalPath); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + return null; + } + + public static String getFilename(String internalPath) { + try { + URL url = new URL(getInternalBaseURL(), internalPath); + return url.getFile(); + } catch (MalformedURLException e) { + System.err.println("Problems with " + internalPath); + e.printStackTrace(); + } + return null; + } + + public static InputStream getInternalInputStream(String internalPath) { + try { + return getInternalResource(internalPath).openStream(); + } catch (MalformedURLException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + public static File getFile(String fn) { + URL url = null; + try { + url = new URL(getInternalFilename(fn)); + } catch (MalformedURLException e1) { + e1.printStackTrace(); + } + System.out.println("Fn:" + fn); + System.out.println("Base:" + getInternalBaseURL()); + System.out.println("Internal:" + getInternalFilename(fn)); + System.out.println("Url:" + url); + File f; + try { + f = new File(url.toURI()); + } catch (URISyntaxException e) { + f = new File(url.getPath()); + } + return f; + } +} diff --git a/src/ru/olamedia/texture/TextureManager.java b/src/ru/olamedia/texture/TextureManager.java new file mode 100644 index 0000000..c790cee --- /dev/null +++ b/src/ru/olamedia/texture/TextureManager.java @@ -0,0 +1,42 @@ +package ru.olamedia.texture; + +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; + +import ru.olamedia.asset.AssetManager; +import ru.olamedia.asset.AssetNotFoundException; + +import com.jogamp.opengl.util.texture.Texture; +import com.jogamp.opengl.util.texture.TextureIO; + +public class TextureManager { + private static HashMap<String, Texture> list = new HashMap<String, Texture>(); + + public static Texture get(String filename) { + if (!list.containsKey(filename)) { + try { + return get(filename, AssetManager.getAsset(filename).getInputStream()); + } catch (IOException e) { + e.printStackTrace(); + return null; + } catch (AssetNotFoundException e) { + e.printStackTrace(); + return null; + } + } + return list.get(filename); + } + + public static Texture get(String key, InputStream stream) { + if (!list.containsKey(key)) { + try { + list.put(key, TextureIO.newTexture(stream, true, "PNG")); + } catch (IOException e) { + list.put(key, null); + e.printStackTrace(); + } + } + return list.get(key); + } +} diff --git a/src/ru/olamedia/texture/package-info.java b/src/ru/olamedia/texture/package-info.java new file mode 100644 index 0000000..fb1a5d4 --- /dev/null +++ b/src/ru/olamedia/texture/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.texture;
\ No newline at end of file diff --git a/src/ru/olamedia/util/BufferUtils.java b/src/ru/olamedia/util/BufferUtils.java new file mode 100644 index 0000000..10d9f36 --- /dev/null +++ b/src/ru/olamedia/util/BufferUtils.java @@ -0,0 +1,16 @@ +package ru.olamedia.util; + +import java.nio.FloatBuffer; +import java.nio.ShortBuffer; + +public class BufferUtils { + + public static ShortBuffer createShortBuffer(int capacity) { + return ShortBuffer.allocate(capacity); + } + + public static FloatBuffer createFloatBuffer(int capacity) { + return FloatBuffer.allocate(capacity); + } + +} diff --git a/src/ru/olamedia/vbo/VBO.java b/src/ru/olamedia/vbo/VBO.java new file mode 100644 index 0000000..6f6c508 --- /dev/null +++ b/src/ru/olamedia/vbo/VBO.java @@ -0,0 +1,29 @@ +package ru.olamedia.vbo; + +import javax.media.opengl.GL2ES2; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLUniformData; + +import com.jogamp.opengl.util.PMVMatrix; + +public class VBO { + private GLAutoDrawable drawable; + private PMVMatrix pmvMatrix; + private GLUniformData pmvMatrixUniform; + private GLUniformData colorUniform; + private int[] vboIda = new int[10]; + + public VBO(GLAutoDrawable drawable) { + this.drawable = drawable; + GL2ES2 gl = drawable.getGL().getGL2ES2(); + // gl.glGenBuffersARB(1, vboIda, 0); + } + + public void setDrawable(GLAutoDrawable drawable) { + this.drawable = drawable; + } + + public void render() { + + } +} diff --git a/src/ru/olamedia/vbo/package-info.java b/src/ru/olamedia/vbo/package-info.java new file mode 100644 index 0000000..325d96f --- /dev/null +++ b/src/ru/olamedia/vbo/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.vbo;
\ No newline at end of file |