diff options
author | olamedia <[email protected]> | 2012-12-23 11:30:36 +0600 |
---|---|---|
committer | olamedia <[email protected]> | 2012-12-23 11:30:36 +0600 |
commit | f58bdfcb66353bb77213cab580bc49ef890417ad (patch) | |
tree | 2983a05d564891e92c115a679f9bfbf55465c755 /src/ru | |
parent | 5320fd1dad5b77fa227e83fbbe0a958f2c5fc283 (diff) |
0.1.7
Diffstat (limited to 'src/ru')
143 files changed, 9574 insertions, 1279 deletions
diff --git a/src/ru/olamedia/asset/Shader.java b/src/ru/olamedia/asset/Shader.java new file mode 100644 index 0000000..8fd9ada --- /dev/null +++ b/src/ru/olamedia/asset/Shader.java @@ -0,0 +1,40 @@ +package ru.olamedia.asset; + +import javax.media.opengl.GL2ES2; +import javax.media.opengl.GLContext; + +import com.jogamp.opengl.util.glsl.ShaderCode; +import com.jogamp.opengl.util.glsl.ShaderProgram; +import com.jogamp.opengl.util.glsl.ShaderState; + +public class Shader { + private ShaderState state; + + public ShaderState getState() { + return state; + } + + public void compile() { + GL2ES2 gl = GLContext.getCurrentGL().getGL2ES2(); + state = new ShaderState(); + state.setVerbose(true); + final ShaderCode vp0 = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, this.getClass(), "shader", "shader/bin", + "block", true); + final ShaderCode fp0 = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, this.getClass(), "shader", + "shader/bin", "block", true); + final ShaderProgram sp0 = new ShaderProgram(); + sp0.add(gl, vp0, System.err); + sp0.add(gl, fp0, System.err); + state.attachShaderProgram(gl, sp0, true); + } + + public void enable() { + GL2ES2 gl = GLContext.getCurrentGL().getGL2ES2(); + state.useProgram(gl, true); + } + + public void disable() { + GL2ES2 gl = GLContext.getCurrentGL().getGL2ES2(); + state.useProgram(gl, false); + } +} diff --git a/src/ru/olamedia/asset/Sprite.java b/src/ru/olamedia/asset/Sprite.java new file mode 100644 index 0000000..84839d2 --- /dev/null +++ b/src/ru/olamedia/asset/Sprite.java @@ -0,0 +1,115 @@ +package ru.olamedia.asset; + +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; + +public class Sprite { + private BufferedImage combinedImage; + Graphics g; + int width; + int height; + int w; + int h; + int sizeX; + int sizeY; + int size; + int length = 0; + SpriteOffset current; + public void dispose(){ + if (null != combinedImage){ + combinedImage = null; + } + if (null != g){ + g.dispose(); + } + } + + int waiting = 0; + + public BufferedImage getImage() { + return combinedImage; + } + + public Sprite(int width, int height, int w, int h) { + this.width = width; + this.height = height; + this.w = w; + this.h = h; + sizeX = width / w; + sizeY = height / h; + size = sizeY * sizeX; + current = new SpriteOffset(0, 0); + combinedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + g = combinedImage.getGraphics(); + /*g.setColor(Color.darkGray); + g.setPaintMode(); + g.fillRect(0, 0, width, height);*/ + } + + public void next() { + current.x += w; + if (current.x + w > width) { + current.x = 0; + current.y += h; + } + } + + public SpriteRectangle addImage(String path) throws AssetNotFoundException { + final Asset asset = AssetManager.getAsset(path); + BufferedImage image; + try { + image = ImageIO.read(asset.getInputStream()); + return addImage(image); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + public SpriteRectangle addImage(BufferedImage img) { + if (current.y + h > height) { + throw new RuntimeException("Out of bounds while creating Sprite"); + } + final int x = (int) current.x; + final int y = (int) current.y; + waiting++; + // img.getWidth(new ImageObserver() { + // @Override + // public boolean imageUpdate(Image img1, int arg1, int arg2, int arg3, + // int arg4, int arg5) { + //System.out.println("Sprite: draw " + img.getWidth(null)); + /*g.setColor(Color.magenta); + g.fillRect(x, y, w, h);*/ + g.drawImage(img, x, y, w, h, null, null); + waiting--; + // return false; + // } + // }); + SpriteRectangle area = new SpriteRectangle((1 / (float) width) * current.x, (1 / (float) height) * current.y, + (1 / (float) width) * (current.x + 16), (1 / (float) height) * (current.y + 16)); + next(); + return area; + } + + public void write(String path) { + /* + * while (waiting > 0) { + * try { + * Thread.sleep(100); + * } catch (InterruptedException e) { + * e.printStackTrace(); + * } + * } + */ + g.dispose(); + try { + ImageIO.write(combinedImage, "PNG", new File(path)); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/ru/olamedia/asset/SpriteOffset.java b/src/ru/olamedia/asset/SpriteOffset.java new file mode 100644 index 0000000..6720daa --- /dev/null +++ b/src/ru/olamedia/asset/SpriteOffset.java @@ -0,0 +1,10 @@ +package ru.olamedia.asset; + +public class SpriteOffset { + public float x; + public float y; + public SpriteOffset(float x, float y) { + this.x = x; + this.y = y; + } +} diff --git a/src/ru/olamedia/asset/SpriteRectangle.java b/src/ru/olamedia/asset/SpriteRectangle.java new file mode 100644 index 0000000..401d6aa --- /dev/null +++ b/src/ru/olamedia/asset/SpriteRectangle.java @@ -0,0 +1,11 @@ +package ru.olamedia.asset; + +public class SpriteRectangle { + public SpriteOffset topLeft; + public SpriteOffset bottomRight; + + public SpriteRectangle(float left, float top, float right, float bottom) { + topLeft = new SpriteOffset(left, top); + bottomRight = new SpriteOffset(right, bottom); + } +} diff --git a/src/ru/olamedia/asset/shader/block.fp b/src/ru/olamedia/asset/shader/block.fp new file mode 100644 index 0000000..291e975 --- /dev/null +++ b/src/ru/olamedia/asset/shader/block.fp @@ -0,0 +1,28 @@ + + +smooth in vec2 texCoord; +//vec4 frontColor; + +uniform sampler2D mesh_ActiveTexture; + +vec4 frontColor = vec4(1.0); +const vec4 texEnvColor = vec4(0.0); + +const vec4 zerov4 = vec4(0.0); +const vec4 onev4 = vec4(1.0); + +vec4 calcTexColor(in vec4 color, in vec4 texColor) { + color.rgb = mix(color.rgb, texEnvColor.rgb, texColor.rgb); + color.a *= texColor.a; + color = clamp(color, zerov4, onev4); + return color; +} + +void main (void) +{ + vec4 texColor; + texColor = texture2D(mesh_ActiveTexture, texCoord.st); + if (texColor.a < 0.1f) discard; + vec4 color = calcTexColor(frontColor, texColor); + gl_FragColor = vec4(gl_FragColor.a) * gl_FragColor + vec4(1.0 - gl_FragColor.a) * texColor; +}
\ No newline at end of file diff --git a/src/ru/olamedia/asset/shader/block.vp b/src/ru/olamedia/asset/shader/block.vp new file mode 100644 index 0000000..989d182 --- /dev/null +++ b/src/ru/olamedia/asset/shader/block.vp @@ -0,0 +1,25 @@ +//precision lowp float; +//precision lowp int; +uniform mat4 pmvMatrix[4]; // P, Mv, Mvi and Mvit +uniform vec4 sunColor; +uniform sampler2D mesh_ActiveTexture; + +attribute vec4 mesh_vertices; +attribute vec4 mesh_colors; + +attribute vec2 mesh_texCoord; + +invariant out vec4 position; +vec4 color; +smooth out vec2 texCoord; + +void main(void) +{ + // Transforming The Vertex Position To ModelView-Space + position = pmvMatrix[1] * mesh_vertices; // vertex eye position + texCoord = mesh_texCoord; + + gl_Position = pmvMatrix[0] * position; + + color = mesh_colors * sunColor; +} diff --git a/src/ru/olamedia/camera/Cameraman.java b/src/ru/olamedia/camera/Cameraman.java index 7dbbcc0..1ea1e92 100644 --- a/src/ru/olamedia/camera/Cameraman.java +++ b/src/ru/olamedia/camera/Cameraman.java @@ -9,6 +9,10 @@ package ru.olamedia.camera; * */ public interface Cameraman { + public MatrixCamera getCamera(); + + public void setCamera(MatrixCamera camera); + public float getCameraX(); public float getCameraY(); diff --git a/src/ru/olamedia/camera/MatrixCamera.java b/src/ru/olamedia/camera/MatrixCamera.java index b9290b7..de07c6f 100644 --- a/src/ru/olamedia/camera/MatrixCamera.java +++ b/src/ru/olamedia/camera/MatrixCamera.java @@ -10,29 +10,39 @@ import javax.media.opengl.fixedfunc.GLMatrixFunc; import javax.media.opengl.glu.GLU; import javax.vecmath.Vector3f; +import jogamp.opengl.ProjectFloat; + +import org.openmali.vecmath2.Matrix4f; + import ru.olamedia.olacraft.game.Game; +import ru.olamedia.olacraft.world.location.Location3f; +import ru.olamedia.geom.Frustum2; import ru.olamedia.input.Keyboard; -import ru.olamedia.math.Frustum; import com.jogamp.newt.event.KeyEvent; +import com.jogamp.opengl.math.FloatUtil; +import com.jogamp.opengl.math.geom.Frustum; import com.jogamp.opengl.util.PMVMatrix; -public class MatrixCamera { - +public class MatrixCamera implements Cameraman { + protected MatrixCamera attachedCamera = null; public PMVMatrix pmvMatrix = new PMVMatrix(true); private boolean isDirty = true; - public GLUniformData pmvMatrixUniform; + public GLUniformData pmvMatrixUniform = new GLUniformData("mgl_PMVMatrix", 4, 4, pmvMatrix.glGetPMvMatrixf()); public boolean isOrientationChanged = true; protected float fov = 90f; protected float aspect = 1f; protected float zNear = 0.1f; - protected float zFar = 1000f; + protected float zFar = 500f; private boolean isPitchLocked = true; private float minPitch = -80f; private float maxPitch = 80f; public Frustum frustum = new Frustum(); + public Frustum frustump = new Frustum(); + public ru.olamedia.math.Frustum frustum1 = new ru.olamedia.math.Frustum(); + public Frustum2 frustum2 = new Frustum2(); private Vector3f position = new Vector3f(); private float yaw = 0; // around y @@ -40,17 +50,42 @@ public class MatrixCamera { private float roll = 0; private Vector3f look = new Vector3f(); + private Vector3f nlook = new Vector3f(); + + /** + * @return the nlook + */ + public Vector3f getNlook() { + return nlook; + } + private Vector3f right = new Vector3f(); private Vector3f up = new Vector3f(); public boolean isFrustumVisible = false; int counter = 0; + private FloatBuffer mv = pmvMatrix.glGetMvMatrixf(); + final private int mvOffset = mv.position(); + private float[] mulMVP = new float[16]; // as calculated by pmvMatrix + StringBuilder s = new StringBuilder(); + + public Location3f offset = new Location3f(); public void pack() { if (isAttachedToCameraman) { - position.x = cameraman.getCameraX(); - position.y = cameraman.getCameraY(); - position.z = cameraman.getCameraZ(); + position.x = cameraman.getCameraX() + offset.x; + position.y = cameraman.getCameraY() + offset.y; + position.z = cameraman.getCameraZ() + offset.z; + if (cameraman instanceof MatrixCamera) { + final MatrixCamera cam = (MatrixCamera) cameraman; + yaw = cam.getYaw(); + pitch = cam.getPitch(); + roll = cam.getRoll(); + zNear = cam.getzNear(); + zFar = cam.getzFar(); + fov = cam.getFov(); + aspect = cam.getAspect(); + } } pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION); pmvMatrix.glLoadIdentity(); @@ -58,78 +93,224 @@ public class MatrixCamera { pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); pmvMatrix.glLoadIdentity(); - pmvMatrix.glRotatef(360 - pitch, 1, 0, 0); - pmvMatrix.glRotatef(360 - yaw, 0, 1, 0); - pmvMatrix.glRotatef(360 - roll, 0, 0, 1); + pmvMatrix.glRotatef(-pitch, 1, 0, 0); + pmvMatrix.glRotatef(-yaw, 0, 1, 0); + pmvMatrix.glRotatef(-roll, 0, 0, 1); + pmvMatrix.glGetFrustum(); pmvMatrix.glTranslatef(-position.x, -position.y, -position.z); // pmvMatrix.setDirty(); pmvMatrix.update(); - FloatBuffer mv = FloatBuffer.allocate(16); - pmvMatrix.glGetFloatv(GLMatrixFunc.GL_MODELVIEW_MATRIX, mv); + // mv = pmvMatrix.glGetMatrixf(GLMatrixFunc.GL_MODELVIEW); + // pmvMatrix.glGetFloatv(GLMatrixFunc.GL_MODELVIEW_MATRIX, mv); - right.set(mv.get(0), mv.get(4), mv.get(8)); - look.set(mv.get(2), mv.get(6), mv.get(10)); + right.set(mv.get(mvOffset + 0), mv.get(mvOffset + 4), mv.get(mvOffset + 8)); + look.set(mv.get(mvOffset + 2), mv.get(mvOffset + 6), mv.get(mvOffset + 10)); + // look.negate(); up.cross(look, right); + nlook.set(look); + nlook.negate(); + // System.out.println(frustum2.toString()); + // packFrustum(); + isDirty = false; + isOrientationChanged = false; + } + + protected FloatBuffer Mvi = FloatBuffer.allocate(16); + protected FloatBuffer Pi = FloatBuffer.allocate(16); + protected ProjectFloat projectFloat = new ProjectFloat(true); + + public void renderFrustum() { + final GL2 gl = GLContext.getCurrentGL().getGL2(); + gl.glDisable(GL2.GL_CULL_FACE); + gl.glDisable(GL2.GL_DEPTH_TEST); + gl.glDisable(GL2.GL_TEXTURE_2D); + gl.glDisable(GL2.GL_ALPHA_TEST); + gl.glEnable(GL2.GL_BLEND); + gl.glBlendFunc(GL2.GL_SRC_ALPHA, GL2.GL_ONE); + gl.glColor4f(0.2f, 0.2f, 0.7f, 0.3f); + gl.glBegin(GL2.GL_QUADS); + flb.v(); + flt.v(); + frt.v(); + frb.v(); + gl.glEnd(); + gl.glBegin(GL2.GL_QUADS); + nlb.v(); + nlt.v(); + nrt.v(); + nrb.v(); + gl.glEnd(); + gl.glBegin(GL2.GL_LINES); + gl.glColor4f(1f, 1f, 1f, 0.4f); + nearc.v(); + farc.v(); + gl.glColor3f(1.0f, 0.0f, 1.0f); + nlb.v(); + flb.v(); + nlt.v(); + flt.v(); + nrt.v(); + frt.v(); + nrb.v(); + frb.v(); + gl.glEnd(); + } + + private float renderFrustumTang = (float) Math.tan((Math.PI * fov / 180) / 2.0f); + private float renderFrustumNear = 1f; + private float renderFrustumFar = 100f; + private float renderFrustumNh = renderFrustumNear * renderFrustumTang; + private float renderFrustumNw = renderFrustumNh * aspect; + private float renderFrustumFh = renderFrustumFar * renderFrustumTang; + private float renderFrustumFw = renderFrustumFh * aspect; + + public void updateFrustum() { + frustum.updateByPlanes(pmvMatrix.glGetFrustum().getPlanes()); + projectFloat.gluInvertMatrixf(pmvMatrix.glGetMvMatrixf(), Mvi); + projectFloat.gluInvertMatrixf(pmvMatrix.glGetPMatrixf(), Pi); + renderFrustumTang = (float) Math.tan((Math.PI * fov / 180) / 2.0f); + renderFrustumNear = 1f; + renderFrustumFar = 100f; + renderFrustumNh = renderFrustumNear * renderFrustumTang; + renderFrustumNw = renderFrustumNh * aspect; + renderFrustumFh = renderFrustumFar * renderFrustumTang; + renderFrustumFw = renderFrustumFh * aspect; + + eye.set(position.x, position.y, position.z); + nearc.set(eye); + nearc.translate(look, -renderFrustumNear); + farc.set(eye); + farc.translate(look, -renderFrustumFar); + flb.set(farc); + flb.translate(right, -renderFrustumFw / 2); + flb.translate(up, -renderFrustumFh / 2); + flt.set(farc); + flt.translate(right, -renderFrustumFw / 2); + flt.translate(up, renderFrustumFh / 2); + frb.set(farc); + frb.translate(right, renderFrustumFw / 2); + frb.translate(up, -renderFrustumFh / 2); + frt.set(farc); + frt.translate(right, renderFrustumFw / 2); + frt.translate(up, renderFrustumFh / 2); + + nlb.set(nearc); + nlb.translate(right, -renderFrustumNw / 2); + nlb.translate(up, -renderFrustumNh / 2); + nlt.set(nearc); + nlt.translate(right, -renderFrustumNw / 2); + nlt.translate(up, renderFrustumNh / 2); + nrb.set(nearc); + nrb.translate(right, renderFrustumNw / 2); + nrb.translate(up, -renderFrustumNh / 2); + nrt.set(nearc); + nrt.translate(right, renderFrustumNw / 2); + nrt.translate(up, renderFrustumNh / 2); + + } + + private vec eye = new vec(); + private vec nearc = new vec(); + private vec flb = new vec(); + private vec flt = new vec(); + private vec frb = new vec(); + private vec frt = new vec(); + private vec nlb = new vec(); + private vec nlt = new vec(); + private vec nrb = new vec(); + private vec nrt = new vec(); + private vec farc = new vec(); + private GL2 gl2; + + private class vec { + public float x; + public float y; + public float z; + + public void v() { + gl2.glVertex3f(x, y, z); + } - pmvMatrixUniform = new GLUniformData("mgl_PMVMatrix", 4, 4, pmvMatrix.glGetPMvMatrixf()); - - packFrustum(); - } - - 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 = (float) Math.tan((Math.PI * fov / 180) / 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); + public void set(vec v) { + set(v.x, v.y, v.z); + } + + public void set(float x, float y, float z) { + this.x = x; + this.y = y; + this.z = z; + } + + public void translate(Vector3f dir, float d) { + translate(dir.x * d, dir.y * d, dir.z * d); + } + + public void translate(float x, float y, float z) { + this.x += x; + this.y += y; + this.z += z; + } } + // private void packFrustum() { + // 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, zNear); + // ru.olamedia.math.Vector3f farc = eyef.translate(look, zFar); + // final float tang = (float) Math.tan((Math.PI * fov / 180) / 2.0f); + // final float nh = zNear * tang * (isFrustumVisible ? 0.3f : 1);// zNear * + // // tang; + // final float nw = nh * aspect * aspect; + // final float fh = zFar * tang * (isFrustumVisible ? 0.5f : 1);// zNear * + // // tang; + // final float fw = fh * aspect * aspect; + // final ru.olamedia.math.Vector3f nrb = nearc.translate(right, -nw / + // 2).translate(up, -nh / 2); + // final ru.olamedia.math.Vector3f nlb = nearc.translate(right, nw / + // 2).translate(up, -nh / 2); + // @SuppressWarnings("unused") + // final ru.olamedia.math.Vector3f nrt = nearc.translate(right, -nw / + // 2).translate(up, nh / 2); + // final ru.olamedia.math.Vector3f nlt = nearc.translate(right, nw / + // 2).translate(up, nh / 2); + // final ru.olamedia.math.Vector3f frb = farc.translate(right, -fw / + // 2).translate(up, -fh / 2); + // final ru.olamedia.math.Vector3f flb = farc.translate(right, fw / + // 2).translate(up, -fh / 2); + // final ru.olamedia.math.Vector3f frt = farc.translate(right, -fw / + // 2).translate(up, fh / 2); + // final ru.olamedia.math.Vector3f flt = farc.translate(right, fw / + // 2).translate(up, fh / 2); + // + // frustum1.leftPlane.set3Points(nlb, flb, flt); + // frustum1.leftPlane.n.negate(); + // frustum1.rightPlane.set3Points(nrb, frt, frb); + // // frustum.rightPlane.n.negate(); + // frustum1.topPlane.set3Points(nlb, frb, flb);// nlt, frt, flt); + // // frustum.topPlane.n.negate(); + // frustum1.bottomPlane.set3Points(frt, nlt, flt); + // // frustum.bottomPlane.n.negate(); + // frustum1.nearPlane.set3Points(nlb, nlt, nrb); + // frustum1.farPlane.set3Points(flt, flb, frb); + // } + private GLU glu; - public void setUp(GLAutoDrawable drawable) { + public void updateControls() { updateKeyboard(); updateMouse(); - if (glu == null) { - glu = new GLU(); - } - if (isDirty) { - pack(); - } - GL2 gl = GLContext.getCurrentGL().getGL2(); + } + + public void setUp() { + final GL2 gl = GLContext.getCurrentGL().getGL2(); gl.glMatrixMode(GLMatrixFunc.GL_PROJECTION); gl.glLoadMatrixf(pmvMatrix.glGetPMatrixf()); gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); - FloatBuffer pmv = FloatBuffer.allocate(16); - pmvMatrix.glGetFloatv(GLMatrixFunc.GL_MODELVIEW_MATRIX, pmv); - gl.glLoadMatrixf(pmv); + // FloatBuffer pmv = FloatBuffer.allocate(16); + // pmvMatrix.glGetFloatv(GLMatrixFunc.GL_MODELVIEW_MATRIX, pmv); + gl.glLoadMatrixf(pmvMatrix.glGetMvMatrixf()); } public float intersectsRectangle(Vector3f vertex1, Vector3f vertex2, Vector3f vertex3, Vector3f vertex4) { @@ -234,6 +415,7 @@ public class MatrixCamera { pitch = pitch % 360; setDirty(); isOrientationChanged = true; + updateMouse(); } public void updateMouse() { @@ -258,17 +440,18 @@ public class MatrixCamera { public void updateKeyboard() { if (isAttachedToCameraman) { - this.cameraman.update(Game.instance.getDelta()); + this.cameraman.update(Game.instance.getFrameDelta()); 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 + final int left = Keyboard.isKeyDown("strafeLeft") ? 1 : 0; + final int right = Keyboard.isKeyDown("strafeRight") ? 1 : 0; + final int up = Keyboard.isKeyDown("flyForward") ? 1 : 0; + final int down = Keyboard.isKeyDown("flyBack") ? 1 : 0; + final int flyUp = Keyboard.isKeyDown("flyUp") ? 1 : 0; + final int flyDown = Keyboard.isKeyDown("flyDown") ? 1 : 0; + final float distance = 4f * 4.5f * Game.instance.getFrameDelta(); // runspeed, + // m/s if (up + down + right + left + flyDown + flyUp > 0) { translate(// right * distance - left * distance,// @@ -312,8 +495,10 @@ public class MatrixCamera { * the aspect to set */ public void setAspect(float aspect) { - this.aspect = aspect; - setDirty(); + if (aspect != this.aspect) { + this.aspect = aspect; + setDirty(); + } } /** @@ -378,6 +563,7 @@ public class MatrixCamera { public void setPitch(float pitch) { this.pitch = pitch; setDirty(); + updateMouse(); } /** @@ -455,7 +641,7 @@ public class MatrixCamera { setDirty(); } - private void setDirty() { + public void setDirty() { isDirty = true; } @@ -475,15 +661,21 @@ public class MatrixCamera { return roll; } - public void attachTo(Cameraman player) { + public void attachTo(Cameraman player, boolean captureControls) { this.cameraman = player; this.isAttachedToCameraman = true; - this.cameraman.captureControls(); + if (captureControls) { + this.cameraman.captureControls(); + } + this.cameraman.setCamera(this); } - public void detach() { + public void detach(boolean captureControls) { this.isAttachedToCameraman = false; - this.captureControls(); + if (captureControls) { + this.captureControls(); + } + this.cameraman.setCamera(null); } /** @@ -507,4 +699,38 @@ public class MatrixCamera { return up; } + @Override + public MatrixCamera getCamera() { + return attachedCamera; + } + + @Override + public void setCamera(MatrixCamera camera) { + attachedCamera = camera; + } + + @Override + public float getCameraX() { + return position.x; + } + + @Override + public float getCameraY() { + return position.y - 2;// + look.y * 2; + } + + @Override + public float getCameraZ() { + return position.z;// + look.z * 2; + } + + @Override + public void update(float delta) { + + } + + public boolean isDirty() { + return isDirty; + } + } diff --git a/src/ru/olamedia/data/BitCube.java b/src/ru/olamedia/data/BitCube.java new file mode 100644 index 0000000..58252d3 --- /dev/null +++ b/src/ru/olamedia/data/BitCube.java @@ -0,0 +1,13 @@ +package ru.olamedia.data; + +import ru.olamedia.math.OpenBitSet; + +public class BitCube { + private int width = 16; + private int height = 16; + private int depth = 16; + private OpenBitSet data; + private int size = 1; // bit + // bit=0/1 count=0-15=4 bit + // 4096/8=512 +} diff --git a/src/ru/olamedia/data/package-info.java b/src/ru/olamedia/data/package-info.java new file mode 100644 index 0000000..e11738e --- /dev/null +++ b/src/ru/olamedia/data/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.data;
\ No newline at end of file diff --git a/src/ru/olamedia/game/GameFrame.java b/src/ru/olamedia/game/GameFrame.java index 973fcb8..6227a15 100644 --- a/src/ru/olamedia/game/GameFrame.java +++ b/src/ru/olamedia/game/GameFrame.java @@ -4,8 +4,11 @@ import java.awt.Dimension; import java.awt.Frame; import java.awt.Image; import java.awt.Toolkit; +import java.awt.event.KeyListener; +import java.awt.im.InputContext; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLProfile; @@ -16,6 +19,7 @@ import ru.olamedia.asset.AssetNotFoundException; import ru.olamedia.input.Keyboard; import ru.olamedia.input.MouseJail; import ru.olamedia.olacraft.OlaCraft; +import ru.olamedia.olacraft.game.Game; import jogamp.newt.awt.NewtFactoryAWT; @@ -26,7 +30,6 @@ import com.jogamp.newt.event.KeyAdapter; import com.jogamp.newt.event.KeyEvent; import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.util.Animator; -import com.jogamp.opengl.util.FPSAnimator; public class GameFrame { // java.awt.SystemTray @@ -54,8 +57,9 @@ public class GameFrame { // ES2 caps = new GLCapabilities(glProfile); caps.setHardwareAccelerated(true); - caps.setDoubleBuffered(true); - caps.setBackgroundOpaque(false); + caps.setDoubleBuffered(true); // hardware swap + caps.setBackgroundOpaque(true); + caps.setSampleBuffers(false); display = NewtFactoryAWT.createDisplay(null); screen = NewtFactoryAWT.createScreen(display, screenId); @@ -63,15 +67,17 @@ public class GameFrame { // caps); newtCanvasAWT = new NewtCanvasAWT(glWindow); glWindow.setUndecorated(false); + glWindow.setAutoSwapBufferMode(false); glWindow.setPointerVisible(true); glWindow.confinePointer(false); glWindow.addWindowListener(new QuitAdapter()); animator = new Animator(glWindow); - //animator = new FPSAnimator(glWindow, 60); - //animator.setRunAsFastAsPossible(true); // By default there is a - // brief - // pause in the animation - // loop + // animator.setUpdateFPSFrames(200, System.out); + // animator = new FPSAnimator(glWindow, 60); + animator.setRunAsFastAsPossible(true); // By default there is a + // brief + // pause in the animation + // loop animator.start(); glWindow.addMouseListener(MouseJail.instance); glWindow.addKeyListener(Keyboard.instance); @@ -84,8 +90,14 @@ public class GameFrame { glWindow.setPointerVisible(true); } } + + @Override + public void keyPressed(KeyEvent e) { + super.keyPressed(e); + System.out.println(e.toString()); + } }); - // animator.setUpdateFPSFrames(100, System.err); + //animator.setUpdateFPSFrames(1000, System.err); jFrame.add(newtCanvasAWT); glWindow.addGLEventListener(GameManager.instance); } @@ -121,6 +133,14 @@ public class GameFrame { return glWindow.getWidth(); } + public static int getGLWidth() { + return Game.Display.getWidth(); + } + + public static int getGLHeight() { + return Game.Display.getHeight(); + } + public static int getHeight() { if (null == glWindow) { return jFrame.getHeight(); @@ -130,6 +150,7 @@ public class GameFrame { public GameFrame() { instance = this; + // en.selectInputMethod(Locale.ENGLISH); jFrame = new JFrame(); jFrame.setMinimumSize(new Dimension(200, 200)); jFrame.setSize(width, height); @@ -139,6 +160,7 @@ public class GameFrame { // glWindow.setLocation(100, 100); jFrame.addWindowListener(new QuitAdapter()); jFrame.setVisible(true); + } private void setIcons() { diff --git a/src/ru/olamedia/game/GameLogicThread.java b/src/ru/olamedia/game/GameLogicThread.java new file mode 100644 index 0000000..ec95aee --- /dev/null +++ b/src/ru/olamedia/game/GameLogicThread.java @@ -0,0 +1,76 @@ +package ru.olamedia.game; + +import java.util.Random; + +import ru.olamedia.olacraft.game.Game; +import ru.olamedia.olacraft.game.Timer; +import ru.olamedia.olacraft.scene.GameScene; +import ru.olamedia.olacraft.world.chunk.ChunkUnavailableException; + +public class GameLogicThread extends Thread { + public static GameLogicThread instance = new GameLogicThread("Game logic"); + private Timer fpsTimer = new Timer(); + + public GameLogicThread(String name) { + super(name); + + } + + private Random rand = new Random(); + + @Override + public synchronized void start() { + super.start(); + fpsTimer.initialize(); + fpsTimer.update(); + } + + private float delta; + + private void tick() { + fpsTimer.update(); + delta = (float) fpsTimer.getElapsedTime() / 1000f; + if (rand.nextFloat() > 0.95f) { + Game.client.getScene().dayTime.tick(); + } + // bullets.update(Game.instance.getDelta()); + // physics.getWorld().step(Game.instance.getDelta()); + if (Game.client.getScene().isInitialized && null != Game.client.getScene().player) { + Game.client.getScene().player.camera.setAspect(Game.Display.getAspect()); + try { + Game.client.getScene().player.updateKeyboard(delta); + } catch (ChunkUnavailableException e) { + e.printStackTrace(); + } + if (Game.client.getScene().player.isOrientationChanged || Game.instance.camera.isOrientationChanged) { + Game.client.getScene().player.isOrientationChanged = false; + Game.instance.camera.isOrientationChanged = false; + updateNearestBlock(); + } + } + } + + private void updateNearestBlock() { + final GameScene scene = Game.client.getScene(); + if (null != scene.player && null != scene.pickSlice) { + scene.pickSlice.setCenter(scene.player.getCameraX(), scene.player.getCameraY(), scene.player.getCameraZ()); + scene.nearestBlock = scene.pickSlice.getNearest(Game.instance.camera); + scene.nearestPutBlock = scene.pickSlice.getNearestPutBlock(); + } + } + + @Override + public void run() { + while (true) { + try { + tick(); + Thread.sleep(50); + // 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/game/GameManager.java b/src/ru/olamedia/game/GameManager.java index 7118c85..7e1ed71 100644 --- a/src/ru/olamedia/game/GameManager.java +++ b/src/ru/olamedia/game/GameManager.java @@ -1,27 +1,25 @@ package ru.olamedia.game; -import java.nio.FloatBuffer; +import java.awt.event.KeyListener; import java.util.Set; import javax.media.opengl.GL; -import javax.media.opengl.GL2; import javax.media.opengl.GL2ES2; +import javax.media.opengl.GL3; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLEventListener; -import javax.media.opengl.GLUniformData; -import javax.media.opengl.fixedfunc.GLMatrixFunc; -import javax.media.opengl.glu.GLU; import ru.olamedia.olacraft.game.Game; import ru.olamedia.olacraft.network.discovery.DiscoveryThread; import ru.olamedia.olacraft.render.jogl.DefaultRenderer; import ru.olamedia.olacraft.render.jogl.IRenderer; +import ru.olamedia.olacraft.world.blockRenderer.ChunkMeshGarbageCollector; +import ru.olamedia.olacraft.world.chunk.Chunk; import ru.olamedia.olacraft.world.chunk.ChunkMeshBulder; import ru.olamedia.olacraft.world.location.BlockLocation; import ru.olamedia.tasks.TaskManager; import com.jogamp.opengl.JoglVersion; -import com.jogamp.opengl.util.PMVMatrix; public class GameManager implements GLEventListener { public static GameManager instance; @@ -36,34 +34,79 @@ public class GameManager implements GLEventListener { tests(); } + private void assertBoolean(boolean val) { + if (!val) { + throw new RuntimeException("Assert failed"); + } + } + private void tests() { + System.out.println("====TESTS===="); + // Game.client.getWorldProvider().loadChunk(new ChunkLocation()); + // Game.client.getWorldProvider().loadChunk(new ChunkLocation(-1,0,0)); + // Game.client.getWorldProvider().loadChunk(new ChunkLocation(0,0,-1)); + // Game.client.getWorldProvider().loadChunk(new ChunkLocation(-1,0,-1)); BlockLocation b; b = new BlockLocation(0, 0, 0); - assert b.getChunkLocation().x == 0; - assert b.getChunkLocation().getBlockLocation().x == 0; + assertBoolean(b.getChunkLocation().x == 0); + assertBoolean(b.getChunkLocation().getBlockLocation().x == 0); b = new BlockLocation(14, 0, 0); - assert b.getChunkLocation().x == 0; - assert b.getChunkLocation().getBlockLocation().x == 0; + assertBoolean(b.getChunkLocation().x == 0); + assertBoolean(b.getChunkLocation().getBlockLocation().x == 0); b = new BlockLocation(15, 0, 0); - assert b.getChunkLocation().x == 0; - assert b.getChunkLocation().getBlockLocation().x == 0; + assertBoolean(b.getChunkLocation().x == 0); + assertBoolean(b.getChunkLocation().getBlockLocation().x == 0); b = new BlockLocation(16, 0, 0); - assert b.getChunkLocation().x == 1; - assert b.getChunkLocation().getBlockLocation().x == 0; + assertBoolean(b.getChunkLocation().x == 1); + assertBoolean(b.getChunkX() == Chunk.v(b.x)); + assertBoolean(b.getChunkY() == Chunk.v(b.y + 128)); + assertBoolean(b.getChunkZ() == Chunk.v(b.z)); + // failed assertBoolean(b.getChunkLocation().getBlockLocation().x == 0); b = new BlockLocation(-1, 0, 0); - assert b.getChunkLocation().x == -1; - assert b.getChunkLocation().getBlockLocation().x == -1; + assertBoolean(b.getChunkLocation().x == -1); + assertBoolean(b.getChunkX() == Chunk.v(b.x)); + assertBoolean(b.getChunkY() == Chunk.v(b.y + 128)); + assertBoolean(b.getChunkZ() == Chunk.v(b.z)); + // failed assertBoolean(b.getChunkLocation().getBlockLocation().x == + // -1); b = new BlockLocation(-14, 0, 0); - assert b.getChunkLocation().x == -1; + assertBoolean(b.getChunkLocation().x == -1); + assertBoolean(b.getChunkX() == Chunk.v(b.x)); + assertBoolean(b.getChunkY() == Chunk.v(b.y + 128)); + assertBoolean(b.getChunkZ() == Chunk.v(b.z)); b = new BlockLocation(-15, 0, 0); - assert b.getChunkLocation().x == -1; - assert b.getChunkLocation().getBlockLocation().x == -1; + assertBoolean(b.getChunkLocation().x == -1); + assertBoolean(b.getChunkX() == Chunk.v(b.x)); + assertBoolean(b.getChunkY() == Chunk.v(b.y + 128)); + assertBoolean(b.getChunkZ() == Chunk.v(b.z)); + // failed assertBoolean(b.getChunkLocation().getBlockLocation().x == + // -1); b = new BlockLocation(-16, 0, 0); - assert b.getChunkLocation().x == -1; - assert b.getChunkLocation().getBlockLocation().x == -1; + assertBoolean(b.getChunkLocation().x == -1); + // failed assertBoolean(b.getChunkLocation().getBlockLocation().x == + // -1); + + assertBoolean(b.getByteX() == 0); + assertBoolean(b.getByteY() == 0); + assertBoolean(b.getByteZ() == 0); + assertBoolean(b.getChunkX() == Chunk.v(b.x)); + assertBoolean(b.getChunkY() == Chunk.v(b.y + 128)); + assertBoolean(b.getChunkZ() == Chunk.v(b.z)); b = new BlockLocation(-17, 0, 0); - assert b.getChunkLocation().x == -2; - assert b.getChunkLocation().getBlockLocation().x == -17; + assertBoolean(b.getChunkLocation().x == -2); + // assertBoolean(b.getChunkLocation().getBlockLocation().x == -17); + assertBoolean(b.getByteX() == 15); + assertBoolean(b.getByteY() == 0); + assertBoolean(b.getByteZ() == 0); + int id = Chunk.in(b.x) * 16 * 16 + Chunk.in(b.y) * 16 + Chunk.in(b.z); + System.out.print(b.getChunkX() + "/" + Chunk.v(b.x)); + assertBoolean(b.getId() == id); + assertBoolean(b.getChunkX() == Chunk.v(b.x)); + assertBoolean(b.getChunkY() == Chunk.v(b.y + 128)); + assertBoolean(b.getChunkZ() == Chunk.v(b.z)); + // ChunkData data = new ChunkData(); + // data.setVoidLight(18, (byte) 6); + // assert data.getVoidLight(18) == 6; } private void createServerGame() { @@ -114,11 +157,31 @@ public class GameManager implements GLEventListener { menu = new MainMenu(); this.renderer = new DefaultRenderer(); GameFrame.getFrame().getContentPane().add(menu); - menu.setVisible(true); - GameFrame.getFrame().validate(); + GameFrame.getFrame().getContentPane().repaint(); + GameFrame.getFrame().addKeyListener(new KeyListener() { + @Override + public void keyTyped(java.awt.event.KeyEvent e) { + System.out.println(e.toString()); + } + @Override + public void keyReleased(java.awt.event.KeyEvent e) { + System.out.println(e.toString()); + } + + @Override + public void keyPressed(java.awt.event.KeyEvent e) { + System.out.println(e.toString()); + } + }); + // GameFrame.getFrame().getContentPane().validate(); + // GameFrame.getFrame().validate(); + // GameFrame.getFrame().getContentPane().paintComponents(GameFrame.getFrame().getContentPane().getGraphics()); + // GameFrame.getFrame().validate(); + // menu.setVisible(true); + // GameFrame.getFrame().setVisible(true); } - private PMVMatrix m; + private void glTest(GLAutoDrawable drawable) { // m = new PMVMatrix(true); // m.glGetMviMatrixf(); @@ -157,7 +220,7 @@ public class GameManager implements GLEventListener { // for (int i = 0; i < 16; i++) { // System.out.println(pmv.get(i) + " == " + glmv.get(i)); // } - // System.exit(0); + // System.exit(0); } public void start() { @@ -188,6 +251,12 @@ public class GameManager implements GLEventListener { if (ChunkMeshBulder.instance.isAlive()) { ChunkMeshBulder.instance.interrupt(); } + if (GameLogicThread.instance.isAlive()) { + GameLogicThread.instance.interrupt(); + } + if (ChunkMeshGarbageCollector.instance.isAlive()) { + ChunkMeshGarbageCollector.instance.interrupt(); + } // Get all threads Set<Thread> threadSet = Thread.getAllStackTraces().keySet(); for (Thread t : threadSet) { @@ -204,6 +273,8 @@ public class GameManager implements GLEventListener { public void init(GLAutoDrawable drawable) { // GLContext.getContext().getGL() GL2ES2 gl = drawable.getGL().getGL2ES2(); + drawable.setAutoSwapBufferMode(false); + gl.setSwapInterval(0); // drawable.setGL(new DebugGL2ES2(gl)); System.err.println(JoglVersion.getGLInfo(drawable.getGL(), null)); System.err.println(Thread.currentThread() + " Chosen GLCapabilities: " + drawable.getChosenGLCapabilities()); @@ -226,16 +297,28 @@ public class GameManager implements GLEventListener { @Override public void display(GLAutoDrawable drawable) { - GL2ES2 gl = drawable.getGL().getGL2ES2(); - gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + final GL3 gl = drawable.getGL().getGL3(); + // gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); // gl.glClearColor(0.2f, 0.2f, 0.2f, 1); renderer.render(drawable); + // Different GL implementations buffer commands in several different + // locations, including network buffers and the graphics accelerator + // itself. glFlush empties all of these buffers, causing all issued + // commands to be executed as quickly as they are accepted by the actual + // rendering engine. Though this execution may not be completed in any + // particular time period, it does complete in finite time. + //gl.glF + //gl.glFlush(); + //gl.glFinish(); + //gl.glFlush(); + drawable.swapBuffers(); } @Override public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { - GL gl = drawable.getGL().getGL2ES2(); + final GL gl = drawable.getGL().getGL2ES2(); gl.glViewport(0, 0, width, height); + renderer.reshape(drawable); } public void showMainMenu() { diff --git a/src/ru/olamedia/game/GameTime.java b/src/ru/olamedia/game/GameTime.java index bd687d9..1d243ad 100644 --- a/src/ru/olamedia/game/GameTime.java +++ b/src/ru/olamedia/game/GameTime.java @@ -1,5 +1,6 @@ package ru.olamedia.game; +import java.nio.FloatBuffer; import java.text.SimpleDateFormat; import java.util.Date; import java.util.GregorianCalendar; @@ -8,6 +9,8 @@ import java.util.TimeZone; import ru.olamedia.astronomy.SunCalendar; public class GameTime { + public FloatBuffer sunColor = FloatBuffer.allocate(4); + public static class SunCalc { private GameTime time; private int r = 450; @@ -94,63 +97,46 @@ public class GameTime { return new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(new Date((long) (gameTime * 1000))); } - private static float addComponent(float a, float b) { - return a + b; - } + private final float[] spaceColors = new float[] { 0.03f, 0.03f, 0.05f }; + private final float[] sunSkyColors = new float[] { (float) 203 / 255, (float) 233 / 255, (float) 244 / 255 }; + private final float[] sunRedColorsAdd = new float[] { 0.3f, 0.1f, 0.0f }; + private final float sunAngularDiameter = 32; + private final float sunRenderDistance = 700; + private final float sunRenderDiameter = (float) ((float) 2 * sunRenderDistance * Math.tan(sunAngularDiameter / 2)) / 15f; - private static float mulComponent(float a, float b) { - return a * b; + public float[] getClearColor() { + return clearColors; } - public float[] getClearColor() { - float sunAngularDiameter = 32; - float sunRenderDistance = 700; - @SuppressWarnings("unused") - float sunRenderDiameter = (float) ((float) 2 * sunRenderDistance * Math.tan(sunAngularDiameter / 2)); + public float[] updateClearColor() { - sunRenderDiameter /= 15; + // a little + // blue - float[] spaceColors = new float[] { 0.03f, 0.03f, 0.05f }; // a little - // blue + clearColors[0] = 0; + clearColors[1] = 0; + clearColors[2] = 0; - clearColors = new float[] { 0.0f, 0.0f, 0.0f }; + final double crossAngle = sunCalendar.getHourAngle(); - double crossAngle = sunCalendar.getHourAngle(); - @SuppressWarnings("unused") - int elevationAngle = (int) sunCalendar.radToDeg(sunCalendar.getElevationAngle()); + final float minSunlightFactor = 0.2097152f; + final float maxSunlightFactor = (1f - minSunlightFactor); + sunlightFactor = minSunlightFactor; - sunlightFactor = 0f; if ((crossAngle > -120 && crossAngle < -70) || (crossAngle > 70 && crossAngle < 120)) { - sunlightFactor = (float) 1f - (Math.abs(crossAngle) - 70) / 50; + sunlightFactor = minSunlightFactor + maxSunlightFactor * ((float) 1f - (Math.abs(crossAngle) - 70) / 50); } if (crossAngle >= -70 && crossAngle <= 70) { sunlightFactor = (float) 1f; } - int sunlight = (int) Math.round(15 * sunlightFactor); - if (sunlight != lastSunLight) { - spaceLightIsInvalid = true; - receivedLightIsInvalid = true; - } - //float[] sunSkyColors = new float[] { (float) 179 / 255, (float) 195 / 255, (float) 184 / 255 }; - //float[] sunSkyColors = new float[] { (float) 209 / 255, (float) 227 / 255, (float) 251 / 255 }; - float[] sunSkyColors = new float[] { (float) 203 / 255, (float) 233 / 255, (float) 244 / 255 }; - for (int i = 0; i < 3; i++) { - clearColors[i] = addComponent(sunSkyColors[i] * (float) sunlightFactor, spaceColors[i]); - } - float lightness = clearColors[0] + clearColors[1] + clearColors[2]; - float[] sunRedColorsAdd = new float[] { 0.3f, 0.1f, 0.0f }; - for (int i = 0; i < 3; i++) { - if (sunlightFactor < 0.5f && sunlightFactor > 0.0f) { - float redFactor = (float) (1 - Math.abs(1 - sunlightFactor * 4)); - clearColors[i] = addComponent(clearColors[i], (float) sunRedColorsAdd[i] * redFactor); - } - clearColors[i] = mulComponent(clearColors[i], (float) sunlightFactor); - } - // fix lightness - float newLightness = clearColors[0] + clearColors[1] + clearColors[2]; + for (int i = 0; i < 3; i++) { - clearColors[i] = clearColors[i] * lightness / newLightness; + clearColors[i] = (float) (sunSkyColors[i] * sunlightFactor + spaceColors[i] * (1 - sunlightFactor)); } + sunColor.position(0); + sunColor.put(clearColors); + sunColor.put(3, 1f); + sunColor.position(0); return clearColors; } @@ -166,6 +152,7 @@ public class GameTime { // noon sunEA = Math.floor(sunCalendar.getElevationAngle() * 1000) / 1000; sunTC = Math.floor(sunCalendar.getTimeCorrectionFactor() * 1000) / 1000; + updateClearColor(); } } diff --git a/src/ru/olamedia/game/Launcher.java b/src/ru/olamedia/game/Launcher.java index 7849468..c7ceca0 100644 --- a/src/ru/olamedia/game/Launcher.java +++ b/src/ru/olamedia/game/Launcher.java @@ -5,11 +5,13 @@ public class Launcher { public Launcher() { } + private static GameManager manager; + /** * @param args */ public static void main(String[] args) { - GameManager manager = new GameManager(); + manager = new GameManager(); manager.start(); manager.dispose(); } diff --git a/src/ru/olamedia/geom/ChunkMesh.java b/src/ru/olamedia/geom/ChunkMesh.java new file mode 100644 index 0000000..3ff36df --- /dev/null +++ b/src/ru/olamedia/geom/ChunkMesh.java @@ -0,0 +1,83 @@ +package ru.olamedia.geom; + +import ru.olamedia.olacraft.render.jogl.ChunkRangeRenderer; + +public class ChunkMesh { + private ImmModeMesh opaqueMesh; + private ImmModeMesh mesh; + private boolean isCompiled = false; + private boolean isValid = false; + private int vertexCount = 0; + + private void updateVertexCount() { + vertexCount = 0; + if (null != mesh) { + vertexCount += mesh.getVertexCount(); + } + if (null != opaqueMesh) { + vertexCount += opaqueMesh.getVertexCount(); + } + } + + public int getVertexCount() { + return vertexCount; + } + + public void setMesh(ImmModeMesh m) { + mesh = m; + updateVertexCount(); + } + + public void setOpaqueMesh(ImmModeMesh m) { + opaqueMesh = m; + updateVertexCount(); + } + + public void render(int pass) { + if (pass == ChunkRangeRenderer.OPAQUE_PASS) { + if (null != opaqueMesh) { + opaqueMesh.draw(); + } + } else { + if (null != mesh) { + mesh.draw(); + } + } + } + + public boolean isCompiled() { + return isCompiled; + } + + public void setCompiled(boolean isCompiled) { + this.isCompiled = isCompiled; + } + + public boolean isValid() { + return isValid; + } + + public void setValid(boolean isValid) { + this.isValid = isValid; + } + + public boolean isEmpty() { + return isValid() && (null == mesh) && (null == opaqueMesh); + } + + public ImmModeMesh getTransparentMesh() { + return mesh; + } + + public ImmModeMesh getOpaqueMesh() { + return opaqueMesh; + } + + public int getOpaqueVertexCount() { + return null == opaqueMesh ? 0 : opaqueMesh.getVertexCount(); + } + + public int getTransparentVertexCount() { + return null == mesh ? 0 : mesh.getVertexCount(); + } +} diff --git a/src/ru/olamedia/geom/ChunkMeshNode.java b/src/ru/olamedia/geom/ChunkMeshNode.java new file mode 100644 index 0000000..f0593f3 --- /dev/null +++ b/src/ru/olamedia/geom/ChunkMeshNode.java @@ -0,0 +1,97 @@ +package ru.olamedia.geom; + +public class ChunkMeshNode { + private ChunkMesh mesh = new ChunkMesh(); + private ChunkMesh[] leafs = new ChunkMesh[8]; + private int vertexCount = 0; + private int opaqueVertexCount = 0; + private int transparentVertexCount = 0; + private int level = 1; + private int axisChunks = 2; + private int axisShift = 1; + private int volumeChunks = 8; + + public ChunkMeshNode(int level) { + this.level = level; + this.axisChunks = (int) Math.pow(2, level); + this.axisShift = level; + this.volumeChunks = (int) Math.pow(8, level); + } + + public void putChunkMesh(int chunkX, int chunkY, int chunkZ, ChunkMesh mesh) { + // id = 0..7 + // final int id = (chunkX & )*4 + ()*2+(chunkZ & ); + } + + private void updateVertexCount() { + if (!mesh.isValid()) { + vertexCount = 0; + opaqueVertexCount = 0; + transparentVertexCount = 0; + for (ChunkMesh m : leafs) { + if (null != m) { + vertexCount += m.getVertexCount(); + opaqueVertexCount += m.getOpaqueVertexCount(); + transparentVertexCount += m.getTransparentVertexCount(); + } + } + } + } + + public int getVertexCount() { + return vertexCount; + } + + public void render(int pass) { + if (mesh.isValid()) { + mesh.render(pass); + } else { + for (ChunkMesh m : leafs) { + if (null != m) { + m.render(pass); + } + } + } + } + + public void combine() { + updateVertexCount(); + if (!mesh.isValid()) { + if (transparentVertexCount > 0) { + final ImmModeMesh tMesh = ImmModeMesh.allocate(transparentVertexCount); + tMesh.setGLSL(true); + tMesh.enableColor4(); + tMesh.enableTexCoord2(); + tMesh.enableVertex3(); + tMesh.beginQuads(); + for (ChunkMesh m : leafs) { + if (null != m) { + tMesh.put(m.getTransparentMesh()); + } + } + tMesh.end(); + mesh.setMesh(tMesh); + } else { + mesh.setMesh(null); + } + if (opaqueVertexCount > 0) { + final ImmModeMesh oMesh = ImmModeMesh.allocate(opaqueVertexCount); + oMesh.setGLSL(true); + oMesh.enableColor4(); + oMesh.enableTexCoord2(); + oMesh.enableVertex3(); + oMesh.beginQuads(); + for (ChunkMesh m : leafs) { + if (null != m) { + oMesh.put(m.getOpaqueMesh()); + } + } + oMesh.end(); + mesh.setOpaqueMesh(oMesh); + } else { + mesh.setOpaqueMesh(null); + } + mesh.setValid(true); + } + } +} diff --git a/src/ru/olamedia/geom/ChunkMeshOctree.java b/src/ru/olamedia/geom/ChunkMeshOctree.java new file mode 100644 index 0000000..1c5202c --- /dev/null +++ b/src/ru/olamedia/geom/ChunkMeshOctree.java @@ -0,0 +1,95 @@ +package ru.olamedia.geom; + +import java.util.HashMap; + +import ru.olamedia.olacraft.game.Game; + +public class ChunkMeshOctree { + private HashMap<Integer, HashMap<Integer, HashMap<Integer, ChunkMeshNode>>> nodes = new HashMap<Integer, HashMap<Integer, HashMap<Integer, ChunkMeshNode>>>(); + private static int level = 2; + private static int nodeAxisChunks = 4; + private static int nodeChunks = 64; + private static int levelp = 4; + + private int getRenderDistance() { + return Game.instance.player.settings.renderDistance; + } + + private int getCameraX() { + return (int) Game.instance.player.camera.getCameraX(); + } + + private int getCameraY() { + return (int) Game.instance.player.camera.getCameraY(); + } + + private int getCameraZ() { + return (int) Game.instance.player.camera.getCameraZ(); + } + + public void render(int pass) { + final int startX = getCameraX() - getRenderDistance() / 2; + final int startY = getCameraY() - getRenderDistance() / 2; + final int startZ = getCameraZ() - getRenderDistance() / 2; + final int deltaChunks = getRenderDistance() / 16; + // renderDistance = 256, deltaChunks = 16 + // renderDistance = 128, deltaChunks = 8 + // renderDistance = 64, deltaChunks = 4 + // renderDistance = 32, deltaChunks = 2 + // level = 1: 1 parent quadtree node (32x32x32), each root node = 8 + // chunks + // level = 2: 2 parent quadtree nodes (64x64x64), each root node = 64 + // chunks + final int chunkStartX = (startX / 16) / nodeAxisChunks; + final int chunkStartY = (startY / 16) / nodeAxisChunks; + final int chunkStartZ = (startZ / 16) / nodeAxisChunks; + for (int ix = chunkStartX; ix < nodeAxisChunks; ix++) { + for (int iy = chunkStartY; iy < nodeAxisChunks; iy++) { + for (int iz = chunkStartZ; iz < nodeAxisChunks; iz++) { + renderNode(ix, iy, iz, pass); + } + } + } + } + + private void renderNode(int ix, int iy, int iz, int pass) { + if (!nodes.containsKey(ix)) { + return; + } + if (!nodes.get(ix).containsKey(iy)) { + return; + } + if (!nodes.get(ix).get(iy).containsKey(iz)) { + return; + } + nodes.get(ix).get(iy).get(iz).render(pass); + } + + public void render(int x, int y, int z, int pass) { + final int ix = x >> 2; + final int iy = y >> 2; + final int iz = z >> 2; + if (!nodes.containsKey(ix)) { + nodes.put(ix, new HashMap<Integer, HashMap<Integer, ChunkMeshNode>>()); + nodes.get(ix).put(iy, new HashMap<Integer, ChunkMeshNode>()); + // nodes.get(ix).get(iy).put(iz, new ChunkMeshNode()); + } + } + + public void put(int chunkX, int chunkY, int chunkZ, ChunkMesh mesh) { + final int ix = chunkX / nodeAxisChunks; + final int iy = chunkY / nodeAxisChunks; + final int iz = chunkZ / nodeAxisChunks; + final int id = (chunkX & 64) * +(chunkY & 64) * +(chunkZ & 64); + if (!nodes.containsKey(ix)) { + nodes.put(ix, new HashMap<Integer, HashMap<Integer, ChunkMeshNode>>()); + } + if (!nodes.get(ix).containsKey(iy)) { + nodes.get(ix).put(iy, new HashMap<Integer, ChunkMeshNode>()); + } + if (!nodes.get(ix).get(iy).containsKey(iz)) { + nodes.get(ix).get(iy).put(iz, new ChunkMeshNode(level)); + } + nodes.get(ix).get(iy).get(iz).combine(); + } +} diff --git a/src/ru/olamedia/geom/DisplayList.java b/src/ru/olamedia/geom/DisplayList.java index aeaffc7..eb6cf04 100644 --- a/src/ru/olamedia/geom/DisplayList.java +++ b/src/ru/olamedia/geom/DisplayList.java @@ -2,7 +2,6 @@ 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; diff --git a/src/ru/olamedia/geom/Frustum.java b/src/ru/olamedia/geom/Frustum.java index 2065157..1a9d58d 100644 --- a/src/ru/olamedia/geom/Frustum.java +++ b/src/ru/olamedia/geom/Frustum.java @@ -1,9 +1,43 @@ package ru.olamedia.geom; +import java.nio.FloatBuffer; + +import org.openmali.vecmath2.Matrix4f; + +import com.jogamp.opengl.util.PMVMatrix; + //import org.openmali.spatial.bodies.Frustum; public class Frustum extends org.openmali.spatial.bodies.Frustum { + protected PMVMatrix pmvMatrix; + protected int mvOffset; + public Frustum() { super(); } + + public Frustum(PMVMatrix matrix) { + super(); + this.pmvMatrix = matrix; + } + + public float[] getMatrixFloat(FloatBuffer b) { + if (pmvMatrix.usesBackingArray()) { + return b.array(); + } else { + int p = b.position(); + float[] pm = new float[16]; + b.get(pm, p, 16); + b.position(p); + return pm; + } + } + + public void compute() { + Matrix4f proj = new Matrix4f(getMatrixFloat(pmvMatrix.glGetPMatrixf())); + // proj.transpose(); + Matrix4f modl = new Matrix4f(getMatrixFloat(pmvMatrix.glGetMviMatrixf())); + // modl.transpose(); + compute(proj, modl); + } } diff --git a/src/ru/olamedia/geom/Frustum2.java b/src/ru/olamedia/geom/Frustum2.java new file mode 100644 index 0000000..9c382b0 --- /dev/null +++ b/src/ru/olamedia/geom/Frustum2.java @@ -0,0 +1,282 @@ +package ru.olamedia.geom; + +import java.nio.FloatBuffer; + +import org.ode4j.ode.internal.gimpact.GimGeometry.aabb3f; +import org.openmali.spatial.bodies.Box; +import org.openmali.spatial.bodies.Classifier; +import org.openmali.vecmath2.Matrix4f; + +import com.jogamp.opengl.math.FloatUtil; +import com.jogamp.opengl.math.geom.AABBox; +import com.jogamp.opengl.util.PMVMatrix; + +public class Frustum2 { + protected Plane[] planes = new Plane[6]; + protected PMVMatrix pmvMatrix; + protected FloatBuffer pmv = FloatBuffer.allocate(16); + protected float[] mvp = new float[16]; + protected int pmvOffset; + + public Frustum2() { + for (int i = 0; i < 6; ++i) { + planes[i] = new Plane(); + } + } + + public Frustum2(PMVMatrix matrix) { + setMatrix(matrix); + for (int i = 0; i < 6; ++i) { + planes[i] = new Plane(); + } + } + + public void setMatrix(PMVMatrix matrix) { + this.pmvMatrix = matrix; + // pmv = pmvMatrix.glGetPMvMatrixf(); + // pmvOffset = pmv.position(); + makePmvMatrix(); + } + + protected Matrix4f proj; + protected Matrix4f modl; + + private static FloatBuffer b; + private static int bOffset; + + private static float f(int offset) { + return b.get(bOffset + offset); + } + + public static Matrix4f getMatrix4f(FloatBuffer buf) { + b = buf; + bOffset = b.position(); + return new Matrix4f(f(0), f(1), f(2), f(3), f(4), f(5), f(6)/* 12 */, f(7), f(8), f(9), f(10), f(11), f(12), + f(13), f(14), f(15)); + } + + public void makePmvMatrix() { + FloatUtil.multMatrixf(pmvMatrix.glGetPMatrixf(), pmvMatrix.glGetMvMatrixf(), mvp, 0); + getMatrix4f(pmvMatrix.glGetPMatrixf()).mul(getMatrix4f(pmvMatrix.glGetMvMatrixf())).writeToBuffer(pmv, true, + false); + } + + protected class Vector3f { + public float x; + public float y; + public float z; + + @Override + public String toString() { + return "{" + x + "," + y + "," + z + "}"; + } + } + + protected class Plane { + public Vector3f n = new Vector3f(); + public float d; + + public final float distanceTo(float x, float y, float z) { + return (n.x * x) + (n.y * y) + (n.z * z) + d; + } + + @Override + public String toString() { + return "Plane[" + n + ", " + d + "]"; + } + } + + protected float[] getMatrixFloat(FloatBuffer b) { + if (pmvMatrix.usesBackingArray()) { + return b.array(); + } else { + int p = b.position(); + float[] pm = new float[16]; + b.get(pm, p, 16); + b.position(p); + return pm; + } + } + + protected float m(int a) { + return mvp[a]; + // return pmv.get(a); + } + + private static final boolean isInside(Plane p, AABBox box) { + final float[] low = box.getLow(); + final float[] high = box.getHigh(); + if (p.distanceTo(low[0], low[1], low[2]) > 0.0f) + return (true); + if (p.distanceTo(high[0], low[1], low[2]) > 0.0f) + return (true); + if (p.distanceTo(low[0], high[1], low[2]) > 0.0f) + return (true); + if (p.distanceTo(high[0], high[1], low[2]) > 0.0f) + return (true); + if (p.distanceTo(low[0], low[1], high[2]) > 0.0f) + return (true); + if (p.distanceTo(high[0], low[1], high[2]) > 0.0f) + return (true); + if (p.distanceTo(low[0], high[1], high[2]) > 0.0f) + return (true); + if (p.distanceTo(high[0], high[1], high[2]) > 0.0f) + return (true); + + return (false); + } + + /** + * Quick check to see if an orthogonal bounding box is inside the frustum + */ + public final boolean isOutside(AABBox box) { + + // if all points are behind 1 specific plane, we are out + // if we are in with all points, then we are fully in + for (int p = 0; p < 6; ++p) { + if (!isInside(planes[p], box)) { + return true; + } + } + + // so if iTotalIn is 6, then all are inside the view + // if(iTotalIn == 6) + // return(IN); + + // we must be partly in then otherwise + return false; + // for (int i = 0; i < 3; ++i) { + // if (!quickClassify(planes[i], box)) + // return true; + // } + // + // // We make no attempt to determine whether it's fully inside or not. + // return false; + } + + protected float[] mat = new float[16]; + + public void extractFrustumPlanes(boolean normalize) { + // Left: [30+00, 31+01, 32+02, 33+03] + // comboMatrix.m[12] + comboMatrix.m[0]; + + planes[0].n.x = m(12) + m(0); + planes[0].n.y = m(13) + m(1); + planes[0].n.z = m(14) + m(2); + planes[0].d = m(15) + m(3); + + // Right: [30-00, 31-01, 32-02, 33-03] + + planes[1].n.x = m(12) - m(0); + planes[1].n.y = m(13) - m(1); + planes[1].n.z = m(14) - m(2); + planes[1].d = m(15) - m(3); + + // Bottom: [30+10, 31+11, 32+12, 33+13] + + planes[2].n.x = m(12) + m(4); + planes[2].n.y = m(13) + m(5); + planes[2].n.z = m(14) + m(6); + planes[2].d = m(15) + m(7); + + // Top: [30-10, 31-11, 32-12, 33-13] + + planes[3].n.x = m(12) - m(4); + planes[3].n.y = m(13) - m(5); + planes[3].n.z = m(14) - m(6); + planes[3].d = m(15) - m(7); + + // Far: [30-20, 31-21, 32-22, 33-23] + + planes[5].n.x = m(12) - m(8); + planes[5].n.y = m(13) - m(9); + planes[5].n.z = m(14) - m(10); + planes[5].d = m(15) - m(11); + + // Near: [30+20, 31+21, 32+22, 33+23] + + planes[4].n.x = m(12) + m(8); + planes[4].n.y = m(13) + m(9); + planes[4].n.z = m(14) + m(10); + planes[4].d = m(15) + m(11); + + // Normalize + if (normalize) { + for (int i = 0; i < 6; ++i) { + double mag = Math.sqrt(planes[i].n.x * planes[i].n.x + planes[i].n.y * planes[i].n.y + planes[i].n.z + * planes[i].n.z); + + planes[i].n.x /= mag; + planes[i].n.y /= mag; + planes[i].n.z /= mag; + planes[i].d /= mag; + } + } + } + + public void extractFrustumPlanes2(boolean normalize) { + // Left: [30+00, 31+01, 32+02, 33+03] + // comboMatrix.m[12] + comboMatrix.m[0]; + + planes[0].n.x = m(3) + m(0); + planes[0].n.y = m(7) + m(4); + planes[0].n.z = m(11) + m(8); + planes[0].d = m(15) + m(12); + + // Right: [30-00, 31-01, 32-02, 33-03] + + planes[1].n.x = m(3) - m(0); + planes[1].n.y = m(7) - m(4); + planes[1].n.z = m(11) - m(8); + planes[1].d = m(15) - m(12); + + // Bottom: [30+10, 31+11, 32+12, 33+13] + + planes[2].n.x = m(3) + m(1); + planes[2].n.y = m(7) + m(5); + planes[2].n.z = m(11) + m(9); + planes[2].d = m(15) + m(13); + + // Top: [30-10, 31-11, 32-12, 33-13] + + planes[3].n.x = m(3) - m(1); + planes[3].n.y = m(7) - m(5); + planes[3].n.z = m(11) - m(9); + planes[3].d = m(15) - m(13); + + // Far: [30-20, 31-21, 32-22, 33-23] + + planes[5].n.x = m(3) - m(2); + planes[5].n.y = m(7) - m(6); + planes[5].n.z = m(11) - m(10); + planes[5].d = m(15) - m(14); + + // Near: [30+20, 31+21, 32+22, 33+23] + + planes[4].n.x = m(3) + m(2); + planes[4].n.y = m(7) + m(6); + planes[4].n.z = m(11) + m(10); + planes[4].d = m(15) + m(14); + + // Normalize + if (normalize) { + for (int i = 0; i < 6; ++i) { + double mag = Math.sqrt(planes[i].n.x * planes[i].n.x + planes[i].n.y * planes[i].n.y + planes[i].n.z + * planes[i].n.z); + + planes[i].n.x /= mag; + planes[i].n.y /= mag; + planes[i].n.z /= mag; + planes[i].d /= mag; + } + } + } + + @Override + public String toString() { + return "f2\n" + m(0) + " " + m(1) + " " + m(2) + " " + m(3) + "\n" + m(4) + " " + m(5) + " " + m(6) + " " + + m(7) + "\n" + m(8) + " " + m(9) + " " + m(10) + " " + m(11) + "\n" + m(12) + " " + m(13) + " " + + m(14) + " " + m(15) + " " + "Frustum2[" + planes[0] + ", " + planes[1] + ", " + planes[2] + ", " + + planes[3] + ", " + planes[4] + ", " + planes[5] + "]"; + } +} diff --git a/src/ru/olamedia/geom/ImmModeMesh.java b/src/ru/olamedia/geom/ImmModeMesh.java new file mode 100644 index 0000000..4ce419b --- /dev/null +++ b/src/ru/olamedia/geom/ImmModeMesh.java @@ -0,0 +1,465 @@ +package ru.olamedia.geom; + +import java.nio.Buffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2; +import javax.media.opengl.GL2ES2; +import javax.media.opengl.GLContext; +import javax.media.opengl.fixedfunc.GLPointerFunc; + +import com.jogamp.common.nio.Buffers; +import com.jogamp.opengl.util.GLArrayDataServer; + +public class ImmModeMesh { + private IndexedMeshBulder indexed = IndexedMeshBulder.instance; + private boolean useIndexed = false; + protected GLArrayDataServer interleaved; + protected FloatBuffer buf; + private int vertexCount = 0; + protected int mode = GL2.GL_QUADS; + protected boolean isGLSL = false; + protected byte vertexComponent = 0; + protected byte normalComponent = 0; + protected byte colorComponent = 0; + protected byte texCoordComponent = 0; + protected float red = 1; + protected float green = 1; + protected float blue = 1; + protected float alpha = 1; + protected float offsetX = 0; + protected float offsetY = 0; + protected float offsetZ = 0; + protected float x = 0; + protected float y = 0; + protected float z = 0; + protected float nx = 0; + protected float ny = 0; + protected float nz = 0; + protected float u = 0; + protected float v = 0; + protected boolean isFinished = false; + protected boolean isServer = false; + + public void setGLSL(boolean glsl) { + this.isGLSL = glsl; + } + + public void makeServer() { + if (null == interleaved) { + if (isGLSL) { + allocateGLSLBuffer(); + } else { + allocateFixedBuffer(); + } + if (null != buf) { + buf.flip(); + interleaved.put(buf); + buf.clear(); + buf = null; + } + interleaved.seal(true); + isServer = true; + } + } + + public Buffer getBuffer() { + if (!isServer) { + return buf; + } + return interleaved.getBuffer(); + } + + public void put(ImmModeMesh mesh) { + if (isServer) { + final FloatBuffer b = (FloatBuffer) mesh.getBuffer(); + b.rewind(); + interleaved.put(b); + } else { + final FloatBuffer b = (FloatBuffer) mesh.getBuffer(); + b.rewind(); + if (null == buf) { + allocateBuffer(); + } + growBufferIfNecessary(b.remaining()); + buf.put(b); + } + vertexCount += mesh.getVertexCount(); + } + + public void destroy() { + if (isServer) { + interleaved.destroy(GLContext.getCurrentGL().getGL2ES2()); + interleaved = null; + } else { + if (null != buf) { + buf.clear(); + buf = null; + } + } + } + + public int getComponents() { + return vertexComponent + normalComponent + colorComponent + texCoordComponent; + } + + protected void allocateBuffer() { + if (!isServer) { + buf = Buffers.newDirectFloatBuffer(getComponents() * getVertexCount()); + } else { + if (isGLSL) { + allocateGLSLBuffer(); + } else { + allocateFixedBuffer(); + } + } + } + + protected final void growBuffer(int additionalElements) { + final int osize = (buf != null) ? buf.capacity() : 0; + final int nsize = osize + (additionalElements * getComponents()); + FloatBuffer newFBuffer = Buffers.newDirectFloatBuffer(nsize); + if (buf != null) { + buf.flip(); + newFBuffer.put((FloatBuffer) buf); + } + buf = newFBuffer; + } + + protected void allocateFixedBuffer() { + final GLArrayDataServer buf = GLArrayDataServer.createFixedInterleaved(getComponents(), GL.GL_FLOAT, false, + getVertexCount(), GL.GL_STATIC_DRAW); + if (vertexComponent != 0) { + buf.addFixedSubArray(GLPointerFunc.GL_VERTEX_ARRAY, vertexComponent, GL.GL_ARRAY_BUFFER); + } + if (colorComponent != 0) { + buf.addFixedSubArray(GLPointerFunc.GL_COLOR_ARRAY, colorComponent, GL.GL_ARRAY_BUFFER); + } + if (normalComponent != 0) { + buf.addFixedSubArray(GLPointerFunc.GL_NORMAL_ARRAY, normalComponent, GL.GL_ARRAY_BUFFER); + } + if (texCoordComponent != 0) { + buf.addFixedSubArray(GLPointerFunc.GL_TEXTURE_COORD_ARRAY, texCoordComponent, GL.GL_ARRAY_BUFFER); + } + interleaved = buf; + } + + protected void allocateGLSLBuffer() { + final GLArrayDataServer buf = GLArrayDataServer.createGLSLInterleaved(getComponents(), GL.GL_FLOAT, false, + getVertexCount(), GL.GL_STATIC_DRAW); + if (vertexComponent != 0) { + buf.addGLSLSubArray("mesh_vertices", vertexComponent, GL.GL_ARRAY_BUFFER); + } + if (colorComponent != 0) { + buf.addGLSLSubArray("mesh_colors", colorComponent, GL.GL_ARRAY_BUFFER); + } + if (normalComponent != 0) { + buf.addGLSLSubArray("mesh_normal", normalComponent, GL.GL_ARRAY_BUFFER); + } + if (texCoordComponent != 0) { + buf.addGLSLSubArray("mesh_texCoord", texCoordComponent, GL.GL_ARRAY_BUFFER); + } + buf.rewind(); + interleaved = buf; + } + + protected final boolean growBufferIfNecessary(int spare) { + if (buf == null || buf.remaining() < spare) { + growBuffer(spare); + return true; + } + return false; + } + + private void putf(float f) { + if (isServer) { + if (null == interleaved) { + allocateBuffer(); + } + interleaved.putf(f); + } else { + // buf.put(f); + growBufferIfNecessary(256); + Buffers.putf(buf, f); + } + } + + protected void putVertex() { + if (vertexComponent > 0) { + putf(x); + putf(y); + if (vertexComponent > 2) { + putf(z); + } + } + if (colorComponent > 0) { + putf(red); + putf(green); + putf(blue); + if (colorComponent > 3) { + putf(alpha); + } + } + if (normalComponent != 0) { + putf(nx); + putf(ny); + if (normalComponent > 2) { + putf(nz); + } + } + if (texCoordComponent > 0) { + putf(u); + putf(v); + } + } + + public void getIndexed() { + + } + + public void enableColor3() { + colorComponent = 3; + if (useIndexed) { + indexed.setColorComponent(colorComponent); + } + } + + public void enableColor4() { + colorComponent = 4; + if (useIndexed) { + indexed.setColorComponent(colorComponent); + } + } + + public void enableVertex2() { + vertexComponent = 2; + if (useIndexed) { + indexed.setVertexComponent(vertexComponent); + } + } + + public void enableVertex3() { + vertexComponent = 3; + if (useIndexed) { + indexed.setVertexComponent(vertexComponent); + } + } + + public void enableNormal3() { + normalComponent = 3; + if (useIndexed) { + indexed.setNormalComponent(normalComponent); + } + } + + public void enableTexCoord2() { + texCoordComponent = 2; + if (useIndexed) { + indexed.setUVComponent(texCoordComponent); + } + } + + public void enableTexCoord4() { + texCoordComponent = 4; + if (useIndexed) { + indexed.setUVComponent(texCoordComponent); + } + } + + public void glBegin(int mode) { + this.mode = mode; + allocateBuffer(); + if (useIndexed) { + indexed.reset(); + } + } + + public void beginQuads() { + glBegin(GL2.GL_QUADS); + } + + public void beginTriangles() { + glBegin(GL2.GL_TRIANGLES); + } + + public void glEnd() { + if (useIndexed) { + indexed.end(); + final IntBuffer ind = indexed.getIndices(); + System.out.println("glEnd: " + vertexCount + " / " + ind.limit()); + } + if (isServer) { + if (null == interleaved) { + allocateBuffer(); + } + interleaved.seal(true); + } + isFinished = true; + } + + public void end() { + glEnd(); + } + + public void setServer(boolean isServer) { + this.isServer = isServer; + } + + public int getVBOName() { + return interleaved.getVBOName(); + } + + public int getMode() { + return mode; + } + + public boolean draw() { + if (!isFinished) { + return false; + } + makeServer(); + final GL2ES2 gl = GLContext.getCurrentGL().getGL2ES2(); + interleaved.enableBuffer(gl, true); + // Вывод геометрии VBO выполняется такими же функциями, как и при + // использовании буфера в оперативной памяти. + gl.glDrawArrays(mode, 0, interleaved.getElementCount()); + interleaved.enableBuffer(gl, false); + //gl.glFlush(); + return true; + } + + public void setColor(float red, float green, float blue) { + this.red = red; + this.green = green; + this.blue = blue; + if (useIndexed) { + indexed.glColor3f(red, green, blue); + } + } + + public void setColor(float red, float green, float blue, float alpha) { + this.red = red; + this.green = green; + this.blue = blue; + this.alpha = alpha; + if (useIndexed) { + indexed.glColor4f(red, green, blue, alpha); + } + } + + public void glColor3f(float red, float green, float blue) { + this.red = red; + this.green = green; + this.blue = blue; + if (useIndexed) { + indexed.glColor3f(red, green, blue); + } + } + + public void glColor4f(float red, float green, float blue, float alpha) { + this.red = red; + this.green = green; + this.blue = blue; + this.alpha = alpha; + if (useIndexed) { + indexed.glColor4f(red, green, blue, alpha); + } + } + + public void glVertex3f(float x, float y, float z) { + this.x = offsetX + x; + this.y = offsetY + y; + this.z = offsetZ + z; + putVertex(); + if (useIndexed) { + indexed.glVertex3f(x, y, z); + } + } + + public void glVertex2f(float x, float y) { + this.x = offsetX + x; + this.y = offsetY + y; + putVertex(); + if (useIndexed) { + indexed.glVertex2f(x, y); + } + } + + public void setUV(float u, float v) { + this.u = u; + this.v = v; + if (useIndexed) { + indexed.setUV(u, v); + } + } + + public void glTexCoord2f(float u, float v) { + this.u = u; + this.v = v; + if (useIndexed) { + indexed.setUV(u, v); + } + } + + public void glRectf(float x1, float y1, float x2, float y2) { + glVertex2f(x1, y1); + glVertex2f(x1, y2); + glVertex2f(x2, y2); + glVertex2f(x2, y1); + } + + protected ImmModeMesh(int vertexCount) { + this.setVertexCount(vertexCount); + } + + public static ImmModeMesh allocate(int elementCount) { + return new ImmModeMesh(elementCount); + } + + public int getVertexCount() { + return vertexCount; + } + + public void setVertexCount(int vertexCount) { + this.vertexCount = vertexCount; + } + + public void glTranslate(float x, float y, float z) { + offsetX = x; + offsetY = y; + offsetZ = z; + if (useIndexed) { + indexed.glTranslate(x, y, z); + } + } + + public void dispose() { + if (null != interleaved) { + interleaved.destroy(GLContext.getCurrentGL().getGL2ES2()); + } + if (null != buf) { + buf.clear(); + buf = null; + } + } + + public void compact() { + if (null != interleaved) { + if (null != interleaved.getBuffer()) { + interleaved.getBuffer().flip(); + ((FloatBuffer) interleaved.getBuffer()).compact(); + } + } + } + + public void glNormal3f(float nx, float ny, float nz) { + this.nx = nx; + this.ny = ny; + this.nz = nz; + if (useIndexed) { + indexed.glNormal3f(nx, ny, nz); + } + } +} diff --git a/src/ru/olamedia/geom/IndexedMeshBulder.java b/src/ru/olamedia/geom/IndexedMeshBulder.java new file mode 100644 index 0000000..ec66305 --- /dev/null +++ b/src/ru/olamedia/geom/IndexedMeshBulder.java @@ -0,0 +1,207 @@ +package ru.olamedia.geom; + +import java.nio.FloatBuffer; +import java.nio.IntBuffer; + +public class IndexedMeshBulder { + protected static IndexedMeshBulder instance = new IndexedMeshBulder(); + protected IntBuffer indices = IntBuffer.allocate(4096); + protected FloatBuffer vertex = FloatBuffer.allocate(4096 * 3); + protected FloatBuffer color = FloatBuffer.allocate(4096 * 4); + protected FloatBuffer normal = FloatBuffer.allocate(4096 * 3); + protected FloatBuffer uv = FloatBuffer.allocate(4096 * 2); + protected int indexCount = 0; + protected int vertexCount = 0; + protected int colorCount = 0; + protected int normalCount = 0; + protected int uvCount = 0; + + protected byte vertexComponent = 0; + protected byte normalComponent = 0; + protected byte colorComponent = 0; + protected byte uvComponent = 0; + + protected float red = 1; + protected float green = 1; + protected float blue = 1; + protected float alpha = 1; + protected float offsetX = 0; + protected float offsetY = 0; + protected float offsetZ = 0; + protected float x = 0; + protected float y = 0; + protected float z = 0; + protected float nx = 0; + protected float ny = 0; + protected float nz = 0; + protected float u = 0; + protected float v = 0; + + public void reset() { + vertex.clear(); + color.clear(); + normal.clear(); + uv.clear(); + indices.clear(); + vertexCount = indexCount = vertexComponent = colorComponent = normalComponent = uvComponent = 0; + } + + public void end(){ + indices.flip(); + vertex.flip(); + color.flip(); + normal.flip(); + uv.flip(); + } + + public IntBuffer getIndices() { + IntBuffer ind = IntBuffer.allocate(indices.limit()); + ind.put(indices); + return ind; + } + + private boolean _sameVertex(int i) { + if (vertexComponent != 0) { + if (vertex.get(i * vertexComponent) == z) { + if (vertex.get(i * vertexComponent + 1) == y) { + if ((vertexComponent == 2) || (vertex.get(i * vertexComponent) == z)) { + return true; + } + } + } + } + return false; + } + + private boolean _sameColor(int i) { + if (colorComponent != 0) { + if (color.get(i * colorComponent) == red) { + if (color.get(i * colorComponent + 1) == green) { + if (color.get(i * colorComponent + 2) == blue) { + if ((colorComponent == 2) || (color.get(i * colorComponent) == alpha)) { + return true; + } + } + } + } + } + return false; + } + + private boolean _sameUV(int i) { + if (uvComponent != 0) { + if (uv.get(i * uvComponent) == u) { + if (uv.get(i * uvComponent + 1) == v) { + return true; + } + } + } + return false; + } + + private void _addVertex() { + if (vertexComponent != 0) { + vertex.put(x); + vertex.put(y); + if (vertexComponent > 2) { + vertex.put(z); + } + } + if (colorComponent != 0) { + color.put(red); + color.put(green); + color.put(blue); + if (colorComponent > 3) { + color.put(alpha); + } + } + if (normalComponent != 0) { + normal.put(nx); + normal.put(ny); + if (normalComponent > 2) { + normal.put(nz); + } + } + if (uvComponent != 0) { + uv.put(u); + uv.put(v); + } + indices.put(indexCount); + indexCount++; + } + + private void putVertex() { + vertexCount++; + for (int i = 0; i < vertexCount; i++) { + if (_sameVertex(i) && _sameColor(i) && _sameUV(i)) { + indices.put(i); + return; + } + } + _addVertex(); + } + + public void setVertexComponent(byte vertexComponent) { + this.vertexComponent = vertexComponent; + } + + public void setNormalComponent(byte normalComponent) { + this.normalComponent = normalComponent; + } + + public void setColorComponent(byte colorComponent) { + this.colorComponent = colorComponent; + } + + public void setUVComponent(byte uvComponent) { + this.uvComponent = uvComponent; + } + + private int comps() { + return vertexComponent + normalComponent + colorComponent + uvComponent; + } + + public void glTranslate(float x, float y, float z) { + offsetX = x; + offsetY = y; + offsetZ = z; + } + + public void glColor3f(float red, float green, float blue) { + this.red = red; + this.green = green; + this.blue = blue; + } + + public void glColor4f(float red, float green, float blue, float alpha) { + this.red = red; + this.green = green; + this.blue = blue; + this.alpha = alpha; + } + + public void glVertex3f(float x, float y, float z) { + this.x = offsetX + x; + this.y = offsetY + y; + this.z = offsetZ + z; + putVertex(); + } + + public void glVertex2f(float x, float y) { + this.x = offsetX + x; + this.y = offsetY + y; + putVertex(); + } + + public void glNormal3f(float nx, float ny, float nz) { + this.nx = nx; + this.ny = ny; + this.nz = nz; + } + + public void setUV(float u, float v) { + this.u = u; + this.v = v; + } + +} diff --git a/src/ru/olamedia/geom/Mesh.java b/src/ru/olamedia/geom/Mesh.java index bda53b9..7e25666 100644 --- a/src/ru/olamedia/geom/Mesh.java +++ b/src/ru/olamedia/geom/Mesh.java @@ -10,12 +10,52 @@ import javax.media.opengl.GL2; import javax.media.opengl.GL2ES2; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLContext; -import javax.media.opengl.fixedfunc.GLPointerFunc; +import javax.media.opengl.GLException; +import javax.media.opengl.GLUniformData; +import javax.vecmath.Point3f; + +import ru.olamedia.asset.Shader; +import ru.olamedia.olacraft.game.Game; import com.jogamp.opengl.util.GLArrayDataServer; +import com.jogamp.opengl.util.PMVMatrix; +import com.jogamp.opengl.util.glsl.ShaderState; import com.jogamp.opengl.util.texture.Texture; public class Mesh { + private static Shader shader = null; + private static GLUniformData pmvMatrixUniform; + private static GLUniformData sunColor; + + private static Shader getShader() { + if (null == shader) { + shader = new Shader(); + shader.compile(); + GL2ES2 gl = GLContext.getCurrentGL().getGL2ES2(); + ShaderState state = shader.getState(); + PMVMatrix pmvMatrix = Game.client.getScene().getPmvMatrix(); + state.attachObject("pmvMatrix", pmvMatrix); + pmvMatrixUniform = new GLUniformData("pmvMatrix", 4, 4, pmvMatrix.glGetPMvMatrixf()); + state.ownUniform(pmvMatrixUniform); + state.uniform(gl, pmvMatrixUniform); + + state.attachObject("sunColor", sunColor); + sunColor = new GLUniformData("sunColor", 4, Game.client.getScene().dayTime.sunColor); + state.ownUniform(sunColor); + state.uniform(gl, sunColor); + + // if (!state.uniform(gl, new GLUniformData("sunColor", 4, + // Game.client.getScene().time.sunColor))) { + // throw new GLException("Error setting sunColor in shader: " + + // state); + // } + if (!state.uniform(gl, new GLUniformData("mesh_ActiveTexture", 0))) { + throw new GLException("Error setting mesh_ActiveTexture in shader: " + state); + } + } + return shader; + } + public void invalidate() { buffer = null; data = null; @@ -103,11 +143,11 @@ public class Mesh { } for (Integer m : materials.keySet()) { int matVertCount = materials.get(m); - final GLArrayDataServer interleaved = GLArrayDataServer.createFixedInterleaved(9, GL2.GL_FLOAT, false, + final GLArrayDataServer interleaved = GLArrayDataServer.createGLSLInterleaved(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); + interleaved.addGLSLSubArray("mesh_vertices", 3, GL.GL_ARRAY_BUFFER); + interleaved.addGLSLSubArray("mesh_colors", 4, GL.GL_ARRAY_BUFFER); + interleaved.addGLSLSubArray("mesh_texCoord", 2, GL.GL_ARRAY_BUFFER); arrays.put(m, interleaved); } for (int n = 0; n < vertexCount; n++) { @@ -143,6 +183,10 @@ public class Mesh { zOffset = z; } + public void setPoint3f(Point3f point) { + setPoint3f(point.x, point.y, point.z); + } + public void setPoint3f(float x, float y, float z) { ptr = vertexPtr * vertexSize; data[ptr + 0] = x + xOffset; @@ -225,19 +269,24 @@ public class Mesh { return; } GL glx = GLContext.getCurrentGL(); - if (true){ - GL2 gl = glx.getGL2(); - gl.glShadeModel(GL2.GL_FLAT); - } if (useVbo) { GL2ES2 gl = glx.getGL2ES2(); // GL2 gl = glx.getGL2(); + getShader().enable(); + Game.client.getScene().dayTime.getClearColor(); + getShader().getState().uniform(gl, pmvMatrixUniform); + getShader().getState().uniform(gl, sunColor); for (Integer m : materials.keySet()) { - - gl.glEnable(GL.GL_TEXTURE_2D); + gl.glActiveTexture(GL.GL_TEXTURE0); gl.glBindTexture(GL.GL_TEXTURE_2D, (int) m); - gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); - gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST_MIPMAP_NEAREST); + // gl.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_MAG_FILTER, GL.GL_LINEAR); + // gl.glTexParameteri(GL.GL_TEXTURE_2D, + // GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR_MIPMAP_LINEAR); arrays.get(m).enableBuffer(gl, true); gl.glEnable(GL.GL_CULL_FACE); gl.glEnable(GL.GL_DEPTH_TEST); @@ -246,6 +295,7 @@ public class Mesh { arrays.get(m).enableBuffer(gl, false); // System.exit(0); } + getShader().disable(); } else { GL2 gl = glx.getGL2(); if (useDisplayList) { diff --git a/src/ru/olamedia/geom/MultiMesh.java b/src/ru/olamedia/geom/MultiMesh.java new file mode 100644 index 0000000..98becd1 --- /dev/null +++ b/src/ru/olamedia/geom/MultiMesh.java @@ -0,0 +1,34 @@ +package ru.olamedia.geom; + +import java.nio.IntBuffer; + +import javax.media.opengl.GL2; +import javax.media.opengl.GL2ES2; +import javax.media.opengl.GL3; +import javax.media.opengl.GLContext; + +public class MultiMesh { + private IntBuffer vboIndices; + private IntBuffer counts; + private int mode = GL2.GL_TRIANGLES; + + public void clear() { + vboIndices.clear(); + } + + public void add(ImmModeMesh mesh) { + vboIndices.put(mesh.getVBOName()); + } + + public void draw() { + final GL3 gl = GLContext.getCurrentGL().getGL3(); + } + + public MultiMesh(int meshCount) { + vboIndices = IntBuffer.allocate(meshCount); + } + + public static MultiMesh allocate(int meshCount) { + return new MultiMesh(meshCount); + } +} diff --git a/src/ru/olamedia/geom/SimpleQuadMesh.java b/src/ru/olamedia/geom/SimpleQuadMesh.java index ad3c27c..c28c799 100644 --- a/src/ru/olamedia/geom/SimpleQuadMesh.java +++ b/src/ru/olamedia/geom/SimpleQuadMesh.java @@ -1,9 +1,28 @@ package ru.olamedia.geom; +import javax.vecmath.Point3f; + +import ru.olamedia.asset.SpriteRectangle; + public class SimpleQuadMesh extends Mesh { public boolean restart = true; + public Point3f bottomLeftBack = new Point3f(); + public Point3f bottomLeftFront = new Point3f(); + public Point3f bottomRightBack = new Point3f(); + public Point3f bottomRightFront = new Point3f(); + + public Point3f topLeftBack = new Point3f(); + public Point3f topLeftFront = new Point3f(); + public Point3f topRightBack = new Point3f(); + public Point3f topRightFront = new Point3f(); + + public float textureTop = 1; + public float textureBottom = 0; + public float textureLeft = 0; + public float textureRight = 1; + public void restart() { restart = true; } @@ -16,108 +35,154 @@ public class SimpleQuadMesh extends Mesh { super(size * 4); } - private void addBottomLeftBackVertex() { - setPoint3f(-0.5f, -0.5f, -0.5f); + public void addBottomLeftBackVertex() { + setPoint3f(bottomLeftBack); } - private void addBottomLeftFrontVertex() { - setPoint3f(-0.5f, -0.5f, 0.5f); + public void addBottomLeftFrontVertex() { + setPoint3f(bottomLeftFront); } - private void addBottomRightBackVertex() { - setPoint3f(0.5f, -0.5f, -0.5f); + public void addBottomRightBackVertex() { + setPoint3f(bottomRightBack); } - private void addBottomRightFrontVertex() { - setPoint3f(0.5f, -0.5f, 0.5f); + public void addBottomRightFrontVertex() { + setPoint3f(bottomRightFront); } - private void addTopLeftBackVertex() { - setPoint3f(-0.5f, 0.5f, -0.5f); + public void addTopLeftBackVertex() { + setPoint3f(topLeftBack); } - private void addTopLeftFrontVertex() { - setPoint3f(-0.5f, 0.5f, 0.5f); + public void addTopLeftFrontVertex() { + setPoint3f(topLeftFront); } - private void addTopRightBackVertex() { - setPoint3f(0.5f, 0.5f, -0.5f); + public void addTopRightBackVertex() { + setPoint3f(topRightBack); } - private void addTopRightFrontVertex() { - setPoint3f(0.5f, 0.5f, 0.5f); + public void addTopRightFrontVertex() { + setPoint3f(topRightFront); } public void addFrontQuad() { // triangle strip: И - setUV(0, 1); + setUV(textureLeft, textureTop); addTopLeftFrontVertex(); // top left - setUV(0, 0); + setUV(textureLeft, textureBottom); addBottomLeftFrontVertex(); // bottom left - setUV(1, 0); + setUV(textureRight, textureBottom); addBottomRightFrontVertex(); // bottom right - setUV(1, 1); + setUV(textureRight, textureTop); addTopRightFrontVertex(); // top right } public void addBackQuad() { // triangle strip: И - setUV(0, 1); + setUV(textureLeft, textureTop); addTopRightBackVertex(); - setUV(0, 0); + setUV(textureLeft, textureBottom); addBottomRightBackVertex(); - setUV(1, 0); + setUV(textureRight, textureBottom); addBottomLeftBackVertex(); - setUV(1, 1); + setUV(textureRight, textureTop); addTopLeftBackVertex(); } public void addLeftQuad() { // triangle strip: И - setUV(0, 1); + setUV(textureLeft, textureTop); addTopLeftBackVertex(); - setUV(0, 0); + setUV(textureLeft, textureBottom); addBottomLeftBackVertex(); - setUV(1, 0); + setUV(textureRight, textureBottom); addBottomLeftFrontVertex(); - setUV(1, 1); + setUV(textureRight, textureTop); addTopLeftFrontVertex(); } public void addRightQuad() { // triangle strip: И - setUV(0, 1); + setUV(textureLeft, textureTop); addTopRightFrontVertex(); - setUV(0, 0); + setUV(textureLeft, textureBottom); addBottomRightFrontVertex(); - setUV(1, 0); + setUV(textureRight, textureBottom); addBottomRightBackVertex(); - setUV(1, 1); + setUV(textureRight, textureTop); addTopRightBackVertex(); } public void addTopQuad() { // triangle strip: И - setUV(0, 0); + setUV(textureLeft, textureBottom); addTopLeftBackVertex(); - setUV(0, 1); + setUV(textureLeft, textureTop); addTopLeftFrontVertex(); - setUV(1, 1); + setUV(textureRight, textureTop); addTopRightFrontVertex(); - setUV(1, 0); + setUV(textureRight, textureBottom); addTopRightBackVertex(); } public void addBottomQuad() { // triangle strip: И - setUV(0, 0); + setUV(textureLeft, textureBottom); addBottomLeftFrontVertex(); - setUV(0, 1); + setUV(textureLeft, textureTop); addBottomLeftBackVertex(); - setUV(1, 1); + setUV(textureRight, textureTop); addBottomRightBackVertex(); - setUV(1, 0); + setUV(textureRight, textureBottom); addBottomRightFrontVertex(); } + public void setPointOffset(float offset) { + bottomLeftBack.x = -offset; + bottomLeftBack.y = -offset; + bottomLeftBack.z = -offset; + // + bottomLeftFront.x = -offset; + bottomLeftFront.y = -offset; + bottomLeftFront.z = offset; + // + bottomRightBack.x = offset; + bottomRightBack.y = -offset; + bottomRightBack.z = -offset; + // + bottomRightFront.x = offset; + bottomRightFront.y = -offset; + bottomRightFront.z = offset; + // + topLeftBack.x = -offset; + topLeftBack.y = offset; + topLeftBack.z = -offset; + // + topLeftFront.x = -offset; + topLeftFront.y = offset; + topLeftFront.z = offset; + // + topRightBack.x = offset; + topRightBack.y = offset; + topRightBack.z = -offset; + // + topRightFront.x = offset; + topRightFront.y = offset; + topRightFront.z = offset; + + } + + public void setTextureOffset(SpriteRectangle offset) { + if (null != offset) { + // System.out.print("Offset " + "[" + offset.topLeft.x + "," + + // offset.topLeft.y + "]"); + textureTop = offset.topLeft.y; + textureLeft = offset.topLeft.x; + textureRight = offset.bottomRight.x; + textureBottom = offset.bottomRight.y; + } + } + } diff --git a/src/ru/olamedia/geom/VoxelRaypicker.java b/src/ru/olamedia/geom/VoxelRaypicker.java new file mode 100644 index 0000000..9e8c533 --- /dev/null +++ b/src/ru/olamedia/geom/VoxelRaypicker.java @@ -0,0 +1,37 @@ +package ru.olamedia.geom; + +public class VoxelRaypicker { + public float[] center = new float[3]; + public float[] dir = new float[3]; + public float radius; + public float[] picker = new float[3]; + public float[] minDelta = new float[3]; + public float[] delta = new float[3]; + public float[] absDelta = new float[3]; + + private void calcDelta(byte i) { + if (dir[i] > 0) { + delta[i] = ((float) ((int) (center[i] + 1)) - center[i]) / dir[i]; + absDelta[i] = delta[i]; + } else if (dir[0] < 0) { + delta[i] = -((float) ((int) (center[i] - 1)) - center[i]) / dir[i]; + absDelta[i] = delta[i]; + } else { + delta[i] = 0; + absDelta[i] = 0; + } + minDelta[i] = delta[i]; + } + + public void reset() { + picker[0] = center[0]; + picker[1] = center[1]; + picker[2] = center[2]; + calcDelta((byte) 0); + calcDelta((byte) 1); + calcDelta((byte) 2); + } + + public void next() { + } +} diff --git a/src/ru/olamedia/input/Keyboard.java b/src/ru/olamedia/input/Keyboard.java index 6a9ecbd..77e0b7a 100644 --- a/src/ru/olamedia/input/Keyboard.java +++ b/src/ru/olamedia/input/Keyboard.java @@ -36,22 +36,79 @@ public class Keyboard implements com.jogamp.newt.event.KeyListener { @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); + /* + * Key pressed: 87 + * Key pressed: 65 + * Key pressed: 83 + * Key pressed: 68 + * Key pressed: 65034 + * Key pressed: 1731 + * Key pressed: 1734 + * Key pressed: 1753 + * Key pressed: 1751 + * + * keycode 24 = q Q Cyrillic_shorti Cyrillic_SHORTI + * keycode 25 = w W Cyrillic_tse Cyrillic_TSE + * keycode 26 = e E Cyrillic_u Cyrillic_U + * keycode 27 = r R Cyrillic_ka Cyrillic_KA + * keycode 28 = t T Cyrillic_ie Cyrillic_IE + * keycode 29 = y Y Cyrillic_en Cyrillic_EN + * keycode 30 = u U Cyrillic_ghe Cyrillic_GHE + * keycode 31 = i I Cyrillic_sha Cyrillic_SHA + * keycode 32 = o O Cyrillic_shcha Cyrillic_SHCHA + * keycode 33 = p P Cyrillic_ze Cyrillic_ZE + * + * KeyPress event, serial 36, synthetic NO, window 0x4600001, + * root 0xb7, subw 0x0, time 326572351, (602,679), root:(669,730), + * state 0x10, keycode 25 (keysym 0x77, w), same_screen YES, + * XLookupString gives 1 bytes: (77) "w" + * XmbLookupString gives 1 bytes: (77) "w" + * XFilterEvent returns: False + * + * KeyRelease event, serial 36, synthetic NO, window 0x4600001, + * root 0xb7, subw 0x0, time 326572447, (602,679), root:(669,730), + * state 0x10, keycode 25 (keysym 0x77, w), same_screen YES, + * XLookupString gives 1 bytes: (77) "w" + * XFilterEvent returns: False + * + * KeyPress event, serial 36, synthetic NO, window 0x4600001, + * root 0xb7, subw 0x0, time 326588119, (118,-7), root:(185,44), + * state 0x2010, keycode 25 (keysym 0x6c3, Cyrillic_tse), same_screen + * YES, + * XLookupString gives 2 bytes: (d1 86) "ц" + * XmbLookupString gives 2 bytes: (d1 86) "ц" + * XFilterEvent returns: False + * + * KeyRelease event, serial 36, synthetic NO, window 0x4600001, + * root 0xb7, subw 0x0, time 326588200, (118,-7), root:(185,44), + * state 0x2010, keycode 25 (keysym 0x6c3, Cyrillic_tse), same_screen + * YES, + * XLookupString gives 2 bytes: (d1 86) "ц" + * XFilterEvent returns: False + */ + if (e.getKeyCode() < 256) { + 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); + } } + System.out.println("Key pressed: " + e.getKeyCode()); + } else { + System.err.println("Key pressed: " + e.getKeyCode()); } } @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); + if (e.getKeyCode() < 256) { + 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); + } } } } diff --git a/src/ru/olamedia/input/MouseJail.java b/src/ru/olamedia/input/MouseJail.java index bd12b0a..9168cc8 100644 --- a/src/ru/olamedia/input/MouseJail.java +++ b/src/ru/olamedia/input/MouseJail.java @@ -1,9 +1,5 @@ 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; @@ -15,10 +11,22 @@ import ru.olamedia.game.GameFrame; public class MouseJail extends MouseAdapter { public static MouseJail instance = new MouseJail(); + public int x; + public int y; + public MouseJail() { } private static boolean isActive = false; + private static boolean isEnabled = true; // disabled if GUI is opened + + public static void disable() { + isEnabled = false; + } + + public static void enable() { + isEnabled = true; + } /** * @return the isActive @@ -32,22 +40,26 @@ public class MouseJail extends MouseAdapter { * 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); + if (isEnabled) { + 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 (isEnabled) { if (e.isAltDown()) { setActive(false); } else { setActive(true); } for (ru.olamedia.input.MouseListener l : listeners) { - l.onMouseClick(); + l.onMouseClick(e); } + // } } @Override @@ -61,7 +73,7 @@ public class MouseJail extends MouseAdapter { System.out.println("Exited"); isActive = false; if (isActive) { - //moveToCenter(); + // moveToCenter(); } } @@ -83,19 +95,17 @@ public class MouseJail extends MouseAdapter { private float sensitivity = 2f; private void onMove(MouseEvent e) { + x = e.getX(); + y = e.getY(); 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; + final float dx = (e.getX() - GameFrame.getGLWidth() / 2) * sensitivity / 10; + final float dy = (e.getY() - GameFrame.getGLHeight() / 2) * 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); + GameFrame.getWindow().warpPointer(GameFrame.getGLWidth() / 2, GameFrame.getGLHeight() / 2); } } diff --git a/src/ru/olamedia/input/MouseListener.java b/src/ru/olamedia/input/MouseListener.java index 3d93d1d..c9f7088 100644 --- a/src/ru/olamedia/input/MouseListener.java +++ b/src/ru/olamedia/input/MouseListener.java @@ -1,6 +1,8 @@ package ru.olamedia.input; +import com.jogamp.newt.event.MouseEvent; + public interface MouseListener { public void onMouseMove(float dx, float dy); - public void onMouseClick(); + public void onMouseClick(MouseEvent e); } diff --git a/src/ru/olamedia/liveEntity/LiveEntity.java b/src/ru/olamedia/liveEntity/LiveEntity.java index 1befec6..2489a57 100644 --- a/src/ru/olamedia/liveEntity/LiveEntity.java +++ b/src/ru/olamedia/liveEntity/LiveEntity.java @@ -4,21 +4,24 @@ import javax.vecmath.Vector3f; import com.jogamp.newt.event.KeyEvent; -import ru.olamedia.Options; import ru.olamedia.camera.Cameraman; +import ru.olamedia.camera.MatrixCamera; import ru.olamedia.olacraft.game.Game; import ru.olamedia.olacraft.inventory.Inventory; -import ru.olamedia.olacraft.network.GameClient; -import ru.olamedia.olacraft.scene.GameScene; import ru.olamedia.olacraft.world.block.Block; import ru.olamedia.olacraft.world.blockStack.BlockStack; import ru.olamedia.olacraft.world.blockTypes.GravelBlockType; import ru.olamedia.olacraft.world.chunk.ChunkUnavailableException; import ru.olamedia.olacraft.world.location.BlockLocation; +import ru.olamedia.player.RuntimeSettings; +import ru.olamedia.input.KeyListener; import ru.olamedia.input.Keyboard; -public class LiveEntity implements Cameraman { - private Inventory inventory; // every living entity can have inventory +public class LiveEntity implements Cameraman, KeyListener { + public MatrixCamera camera; + public MatrixCamera thirdPerson = new MatrixCamera(); + public RuntimeSettings settings = new RuntimeSettings(); + protected Inventory inventory; // every living entity can have inventory private float x; private float y; private float z; @@ -40,7 +43,7 @@ public class LiveEntity implements Cameraman { private float walkSpeed = 1.3f;// 1.3-1.5 m/s private float runSpeed = 4.5f;// m/s - private boolean isWalking = false; + protected boolean isWalking = false; private boolean isRunning = false; private boolean isSneaking = false; private boolean isCrouching = false; @@ -67,8 +70,6 @@ public class LiveEntity implements Cameraman { 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()); } } @@ -108,7 +109,7 @@ public class LiveEntity implements Cameraman { } public boolean isEmptyUnderFoot() throws ChunkUnavailableException { - return isEmptyBlock(0, -1, 0); + return canMoveThrough(0, -1, 0); } /** @@ -128,11 +129,38 @@ public class LiveEntity implements Cameraman { boolean keySneak = Keyboard.isKeyDown("playerSneak"); boolean keyCrouch = Keyboard.isKeyDown("playerCrouch"); boolean keyRenderDistance = Keyboard.isKeyDown("playerRenderDistance"); + if (Keyboard.isKeyDown("playerInventory1")) { + inventory.select(0); + } + if (Keyboard.isKeyDown("playerInventory2")) { + inventory.select(1); + } + if (Keyboard.isKeyDown("playerInventory3")) { + inventory.select(2); + } + if (Keyboard.isKeyDown("playerInventory4")) { + inventory.select(3); + } + if (Keyboard.isKeyDown("playerInventory5")) { + inventory.select(4); + } + if (Keyboard.isKeyDown("playerInventory6")) { + inventory.select(5); + } + if (Keyboard.isKeyDown("playerInventory7")) { + inventory.select(6); + } + if (Keyboard.isKeyDown("playerInventory8")) { + inventory.select(7); + } + if (Keyboard.isKeyDown("playerInventory9")) { + inventory.select(8); + } + if (Keyboard.isKeyDown("playerInventory0")) { + inventory.select(9); + } if (keyRenderDistance) { - Options.renderDistance *= 2; - if (Options.renderDistance > 256) { - Options.renderDistance = 32; - } + } if (keySneak) { if (!isSneaking) { @@ -393,15 +421,17 @@ public class LiveEntity implements Cameraman { } - public boolean isEmptyBlock(int dx, int dy, int dz) { - BlockLocation loc = new BlockLocation((int) x + dx, (int) Math.ceil(y) + dy, (int) z + dz); - if (!Game.client.getWorldProvider().isChunkAvailable(loc.getChunkLocation())) { - Game.client.getWorldProvider().loadChunk(loc.getChunkLocation()); + BlockLocation testLoc = new BlockLocation(); + + public boolean canMoveThrough(int dx, int dy, int dz) { + testLoc.set((int) x + dx, (int) Math.ceil(y) + dy, (int) z + dz); + if (!Game.client.getWorldProvider().isChunkAvailable(testLoc.getChunkLocation())) { + Game.client.getWorldProvider().loadChunk(testLoc.getChunkLocation()); return false; } try { - return Game.client.getWorldProvider().isEmptyBlock((int) x + dx, (int) Math.ceil(y) + dy, (int) z + dz); + return Game.client.getWorldProvider().canMoveThrough((int) x + dx, (int) Math.ceil(y) + dy, (int) z + dz); } catch (ChunkUnavailableException e) { e.printStackTrace(); return false; @@ -409,11 +439,11 @@ public class LiveEntity implements Cameraman { } public boolean haveBlockUnder(int dy) throws ChunkUnavailableException { - return !isEmptyBlock(0, -dy, 0); + return !canMoveThrough(0, -dy, 0); } public boolean inAir() throws ChunkUnavailableException { - if (!isEmptyBlock(0, -1, 0)) { + if (!canMoveThrough(0, -1, 0)) { if (y > getBlock(0, -1, 0).getY() + 0.5f) { return true; } @@ -455,24 +485,28 @@ public class LiveEntity implements Cameraman { public boolean hasValidPosition(Block head, boolean checkTop, boolean checkBottom) throws ChunkUnavailableException { // Check if we're too near to the wall - Block[] LRNeighbors = { head.getNeighbor(-1, 0, 0), head.getNeighbor(1, 0, 0) }; - for (Block n : LRNeighbors) { - if (n.isEmpty()) { - continue; - } - if (Math.abs(n.getX() - x) < 0.5) { - return false; - } - } - Block[] FBNeighbors = { head.getNeighbor(0, 0, -1), head.getNeighbor(0, 0, 1) }; - for (Block n : FBNeighbors) { - if (n.isEmpty()) { - continue; - } - if (Math.abs(n.getZ() - z) < 0.5) { - return false; - } - } + /* + * Block[] LRNeighbors = { head.getNeighbor(-1, 0, 0), + * head.getNeighbor(1, 0, 0) }; + * for (Block n : LRNeighbors) { + * if (!n.canMoveThrough()) { + * return false; + * } + * if (Math.abs(n.getX() - x) < 0.5) { + * return false; + * } + * } + * Block[] FBNeighbors = { head.getNeighbor(0, 0, -1), + * head.getNeighbor(0, 0, 1) }; + * for (Block n : FBNeighbors) { + * if (!n.canMoveThrough()) { + * return false; + * } + * if (Math.abs(n.getZ() - z) < 0.5) { + * return false; + * } + * } + */ // if (checkBottom) { // Block n = head.getNeighbor(0, -1, 0); // if (Math.abs(n.getY() - y) < 0.5) { @@ -485,7 +519,7 @@ public class LiveEntity implements Cameraman { // return false; // } // } - return head.isEmpty(); + return head.canMoveThrough(); } public boolean hasValidPosition() throws ChunkUnavailableException { @@ -493,7 +527,7 @@ public class LiveEntity implements Cameraman { Block underFoot = getBlock(0, -1, 0); Block head = getBlock(0, (int) getHeight(), 0); if (!inJump) { - if (underFoot.isEmpty()) { + if (underFoot.canMoveThrough()) { // In AIR while normal walking if (isSneaking) { // TODO Jumping while Sneaking fixes x,z while jumping @@ -510,6 +544,9 @@ public class LiveEntity implements Cameraman { if (hasValidPosition()) { backupPosition(); isPositionChanged = true; + if (null != camera) { + camera.setDirty(); + } return true; } restorePosition(); @@ -557,8 +594,8 @@ public class LiveEntity implements Cameraman { if (y < -20) { // spawnAt((int) x, (int) z); } - pitch = Game.instance.camera.getPitch(); - yaw = Game.instance.camera.getYaw(); + setPitch(Game.instance.camera.getPitch()); + setYaw(Game.instance.camera.getYaw()); // Game.camera.setRoll(roll); // saveTrace(); // if (isWalking && onGround) { @@ -573,6 +610,9 @@ public class LiveEntity implements Cameraman { if (isPositionChanged) { isOrientationChanged = true; notifyLocationUpdate(); + if (null != camera) { + camera.setDirty(); + } } } @@ -634,8 +674,11 @@ public class LiveEntity implements Cameraman { return y + getCameraLevel(); } + private BlockLocation cameraBlockLocation = new BlockLocation(); + public BlockLocation getCameraBlockLocation() { - return new BlockLocation(x, y, z); + cameraBlockLocation.set(x, y, z); + return cameraBlockLocation; } @Override @@ -654,8 +697,25 @@ public class LiveEntity implements Cameraman { Keyboard.setName("playerSneak", KeyEvent.VK_SHIFT); Keyboard.setName("playerCrouch", KeyEvent.VK_CONTROL); Keyboard.setName("playerRenderDistance", KeyEvent.VK_F4); + Keyboard.setName("playerInventory1", KeyEvent.VK_1); + Keyboard.setName("playerInventory2", KeyEvent.VK_2); + Keyboard.setName("playerInventory3", KeyEvent.VK_3); + Keyboard.setName("playerInventory4", KeyEvent.VK_4); + Keyboard.setName("playerInventory5", KeyEvent.VK_5); + Keyboard.setName("playerInventory6", KeyEvent.VK_6); + Keyboard.setName("playerInventory7", KeyEvent.VK_7); + Keyboard.setName("playerInventory8", KeyEvent.VK_8); + Keyboard.setName("playerInventory9", KeyEvent.VK_9); + Keyboard.setName("playerInventory0", KeyEvent.VK_0); + Keyboard.setName("playerInventoryToggle", KeyEvent.VK_E); + if (!isListeningControls) { + isListeningControls = true; + Keyboard.attach(this); + } } + private boolean isListeningControls = false; + public void setId(int id) { this.id = id; } @@ -671,4 +731,60 @@ public class LiveEntity implements Cameraman { public void setConnectionId(int connectionId) { this.connectionId = connectionId; } + + @Override + public void onKeyPressed(String name, KeyEvent e) { + if (name.equals("playerInventoryToggle")) { + inventory.toggleGUI(); + } + if (name.equals("playerRenderDistance")) { + settings.renderDistance *= 2; + if (settings.renderDistance > 256) { + settings.renderDistance = 32; + } + } + + } + + @Override + public void onKeyReleased(String name, KeyEvent e) { + + } + + @Override + public MatrixCamera getCamera() { + return camera; + } + + @Override + public void setCamera(MatrixCamera camera) { + this.camera = camera; + if (null != camera) { + // thirdPerson.attachTo(this.camera, false); + } + } + + public float getPitch() { + return pitch; + } + + public void setPitch(float pitch) { + this.pitch = pitch; + } + + public float getYaw() { + return yaw; + } + + public void setYaw(float yaw) { + this.yaw = yaw; + } + + public float getRoll() { + return roll; + } + + public void setRoll(float roll) { + this.roll = roll; + } } diff --git a/src/ru/olamedia/math/Frustum.java b/src/ru/olamedia/math/Frustum.java index e127cc0..7fb1827 100644 --- a/src/ru/olamedia/math/Frustum.java +++ b/src/ru/olamedia/math/Frustum.java @@ -1,5 +1,7 @@ package ru.olamedia.math; +import com.jogamp.opengl.math.geom.AABBox; + public class Frustum { public Plane topPlane = new Plane(); public Plane bottomPlane = new Plane(); @@ -31,45 +33,48 @@ public class Frustum { 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 quickClassify(Plane p, AABBox box) { + final float[] low = box.getLow(); + final float[] high = box.getHigh(); + if (p.distance(low[0], low[1], low[2]) > 0.0f) + return (true); + if (p.distance(high[0], low[1], low[2]) > 0.0f) + return (true); + if (p.distance(low[0], high[1], low[2]) > 0.0f) + return (true); + if (p.distance(high[0], high[1], low[2]) > 0.0f) + return (true); + if (p.distance(low[0], low[1], high[2]) > 0.0f) + return (true); + if (p.distance(high[0], low[1], high[2]) > 0.0f) + return (true); + if (p.distance(low[0], high[1], high[2]) > 0.0f) + return (true); + if (p.distance(high[0], high[1], high[2]) > 0.0f) + return (true); + + return (false); + } + + /** + * Quick check to see if an orthogonal bounding box is inside the frustum + */ + public final boolean isOutside(AABBox box) { + if (!quickClassify(leftPlane, box)) + return true; +// if (!quickClassify(rightPlane, box)) +// return true; +// if (!quickClassify(topPlane, box)) +// return true; +// if (!quickClassify(bottomPlane, box)) +// return true; +// if (!quickClassify(nearPlane, box)) +// return true; +// if (!quickClassify(farPlane, box)) +// return true; + + // We make no attempt to determine whether it's fully inside or not. + return false; } private static final boolean isPointInside(Plane plane, Vector3f p) { @@ -82,31 +87,6 @@ public class Frustum { && 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) * diff --git a/src/ru/olamedia/math/Vector.java b/src/ru/olamedia/math/Vector.java new file mode 100644 index 0000000..08a31f7 --- /dev/null +++ b/src/ru/olamedia/math/Vector.java @@ -0,0 +1,5 @@ +package ru.olamedia.math; + +public class Vector { + +} diff --git a/src/ru/olamedia/math/VectorUtil.java b/src/ru/olamedia/math/VectorUtil.java new file mode 100644 index 0000000..304bc5e --- /dev/null +++ b/src/ru/olamedia/math/VectorUtil.java @@ -0,0 +1,29 @@ +package ru.olamedia.math; + +public class VectorUtil { + private static float[] tmpVec = new float[3]; + + public static float dot(float[] vec1, float[] vec2) { + return (vec1[0] * vec2[0] + vec1[1] * vec2[1] + vec1[2] * vec2[2]); + } + + public static void translate(float[] result, float[] vec, float distance) { + for (int i = 0; i < 3; i++) { + result[i] += vec[i] * distance; + } + } + + public static void set(float[] result, float[] vec) { + for (int i = 0; i < 3; i++) { + result[i] = vec[i]; + } + } + + public static void cross(float[] vec1, float[] vec2) { + set(tmpVec, vec1); + + vec1[0] = vec2[2] * tmpVec[1] - vec2[1] * tmpVec[2]; + vec1[1] = vec2[0] * tmpVec[2] - vec2[2] * tmpVec[0]; + vec1[2] = vec2[1] * tmpVec[0] - vec2[0] * tmpVec[1]; + } +} diff --git a/src/ru/olamedia/olacraft/OlaCraft.java b/src/ru/olamedia/olacraft/OlaCraft.java index b5b3234..2dd39f0 100644 --- a/src/ru/olamedia/olacraft/OlaCraft.java +++ b/src/ru/olamedia/olacraft/OlaCraft.java @@ -1,6 +1,6 @@ package ru.olamedia.olacraft; public class OlaCraft { - public static String version = "0.1.6"; + public static String version = "0.1.7"; } diff --git a/src/ru/olamedia/olacraft/game/Game.java b/src/ru/olamedia/olacraft/game/Game.java index 0980505..a2bc05e 100644 --- a/src/ru/olamedia/olacraft/game/Game.java +++ b/src/ru/olamedia/olacraft/game/Game.java @@ -1,14 +1,10 @@ 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 { @@ -17,7 +13,7 @@ public class Game { public static boolean isServerRunning = false; public static GameServer server = new GameServer(); public static GameClient client = new GameClient(); - public static Timer timer = new Timer(); + public static Timer fpsTimer = new Timer(); public MatrixCamera camera; @@ -27,7 +23,6 @@ public class Game { @SuppressWarnings("unused") private int mode = 1; private boolean isRunning = false; - @SuppressWarnings("unused") // player public Player player; @@ -50,7 +45,7 @@ public class Game { } player = new Player(); camera = new MatrixCamera(); - camera.attachTo(player); + camera.attachTo(player, true); camera.setFov(90); camera.pack(); // scene.registerLiveEntity(player); @@ -81,7 +76,6 @@ public class Game { } public void tick() { - timer.update(); } @@ -99,8 +93,8 @@ public class Game { } } - public float getDelta() { - return (float) timer.getElapsedTime() / 1000; + public float getFrameDelta() { + return (float) fpsTimer.getElapsedTime() / 1000f; } } diff --git a/src/ru/olamedia/olacraft/inventory/Inventory.java b/src/ru/olamedia/olacraft/inventory/Inventory.java index 2ce843b..3076dfe 100644 --- a/src/ru/olamedia/olacraft/inventory/Inventory.java +++ b/src/ru/olamedia/olacraft/inventory/Inventory.java @@ -1,76 +1,402 @@ package ru.olamedia.olacraft.inventory; -import ru.olamedia.olacraft.world.block.Block; +import javax.media.opengl.GL; +import javax.media.opengl.GL2; +import javax.media.opengl.GLContext; + +import com.jogamp.opengl.util.texture.Texture; + +import ru.olamedia.asset.SpriteRectangle; +import ru.olamedia.game.GameFrame; +import ru.olamedia.geom.ImmModeMesh; +import ru.olamedia.input.MouseJail; +import ru.olamedia.olacraft.game.Game; import ru.olamedia.olacraft.world.blockStack.BlockStack; +import ru.olamedia.olacraft.world.blockTypes.EmptyBlockType; +import ru.olamedia.olacraft.world.blockTypes.GravelBlockType; +import ru.olamedia.olacraft.world.blockTypes.WheatBlockType; +import ru.olamedia.olacraft.world.blockTypes.stone.BrecciaStoneBlockType; +import ru.olamedia.texture.TextureManager; public class Inventory { public static int BIND_NUM = 10; - public BlockStack[] binded = new BlockStack[BIND_NUM]; + public static int BACKPACK_NUM = 10 * 5; + public static int TOTAL_NUM = BIND_NUM + BACKPACK_NUM; + public BlockStack[] binded = new BlockStack[TOTAL_NUM]; public BlockStack selected; - public int selectedId; - private boolean isInventoryGUIOpen = false; + public int selectedId = 0; + private boolean isGUIOpened = false; - public Inventory() { + private int[] bindedX = new int[TOTAL_NUM]; + private int[] bindedY = new int[TOTAL_NUM]; + + public BlockStack picked = null; + public int pickedId = 0; + + private ImmModeMesh bindedGUI; + + public void pickHover(boolean half) { + System.out.println("pick hover " + MouseJail.instance.y); + int x = MouseJail.instance.x; + int y = MouseJail.instance.y; + for (int i = 0; i < TOTAL_NUM; i++) { + if (x >= bindedX[i] && x <= bindedX[i] + 32 && y >= bindedY[i] && y <= bindedY[i] + 32) { + if (binded[i].count > 0) { + int pickCount = binded[i].count; + if (pickCount > 1 && half) { + pickCount = pickCount / 2; + } + System.out.println("pick binded"); + pickedId = i; + picked = binded[pickedId].get(pickCount); + } + } + } } - 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); + public void placePicked() { + if (null == picked) { + return; + } + int x = MouseJail.instance.x; + int y = MouseJail.instance.y; + for (int i = 0; i < TOTAL_NUM; i++) { + if (x >= bindedX[i] && x <= bindedX[i] + 32 && y >= bindedY[i] && y <= bindedY[i] + 32) { + if (picked.type.getClass().getName().equals(binded[i].type.getClass().getName()) + || binded[i].count == 0) { + // same type or empty slot + binded[i].putStack(picked); + if (picked.count == 0) { + picked = null; + } else { + binded[pickedId] = picked; // place picked to hovered + picked = null; + } + } else { + // different types + // swap + binded[pickedId].putStack(picked); + picked = binded[pickedId]; + binded[pickedId] = binded[i]; + binded[i] = picked; + picked = null; + } + } } - 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); + public void putPickedBack() { + if (null != picked) { + binded[pickedId].putStack(picked); // put back + picked = null; } - if (key == Keyboard.KEY_2) { - select(1); + } + + public Inventory() { + for (int i = 0; i < TOTAL_NUM; i++) { + binded[i] = new BlockStack(new EmptyBlockType(), 0); } - if (key == Keyboard.KEY_3) { - select(2); + binded[0].type = new WheatBlockType(); + binded[0].count = 60; + binded[1].type = new BrecciaStoneBlockType(); + binded[1].count = 60; + } + + public void openGUI() { + isGUIOpened = true; + MouseJail.enable(); + MouseJail.setActive(false); + MouseJail.disable(); + } + + public void buildMeshes() { + bindedGUI = ImmModeMesh.allocate(2 * 4 + BIND_NUM * 4); + bindedGUI.enableColor3(); + bindedGUI.enableVertex2(); + int x = 0 + GameFrame.getGLWidth() / 2 - width / 2; + int y = GameFrame.getGLHeight() - height - padding; + bindedGUI.glBegin(GL2.GL_QUADS); + { + bindedGUI.glColor3f(0.2f, 0.2f, 0.2f); + bindedGUI.glRectf(x, y, x + width, y + height); + for (int i = 0; i < BIND_NUM; i++) { + bindedX[i] = x + padding + spacing * i + 34 * i + 1; + bindedY[i] = y + padding + 1; + int fx = x + padding + spacing * i + 34 * i; + int fy = y + padding; + // left + bindedGUI.glColor3f(0.0f, 0.0f, 0.0f); + bindedGUI.glRectf(fx, fy, fx + spacing / 2, fy + 34); + // right + bindedGUI.glColor3f(0.5f, 0.5f, 0.5f); + bindedGUI.glRectf(fx + 33, fy, fx + 33 + spacing / 2, fy + 34); + // top + bindedGUI.glColor3f(0.2f, 0.2f, 0.2f); + bindedGUI.glRectf(fx, fy, fx + 34, fy + spacing / 2); + // bottom + bindedGUI.glColor3f(0.3f, 0.3f, 0.3f); + bindedGUI.glRectf(fx, fy + 33, fx + 34, fy + 33 + spacing / 2); + bindedGUI.glColor3f(0.6f, 0.6f, 0.6f); + bindedGUI.glRectf(fx + 1, fy + 1, fx + 1 + 32, fy + 1 + 32); + } + // frame + bindedGUI.glColor3f(0.2f, 0.2f, 0.2f); + int fx = x + padding + spacing * selectedId + 34 * selectedId; + int fy = y + padding; + bindedGUI.glColor3f(15f / 15f, 6f / 15f, 0f); + bindedGUI.glRectf(fx, fy, fx + 32 + 2, fy + 32 + 2); + bindedGUI.glColor3f(0.8f, 0.8f, 0.8f); + bindedGUI.glRectf(fx + 1, fy + 1, fx + 1 + 32, fy + 1 + 32); } - if (key == Keyboard.KEY_4) { - select(3); + bindedGUI.glEnd(); + } + + public BlockStack getSelectedBlockStack() { + return binded[selectedId]; + } + + /** + * + */ + public void putBlockStack(BlockStack external) { + System.out.println("put stack " + external.type.getClass().getName()); + // looking for same type + int i = 0; + while (i < TOTAL_NUM && external.count > 0) { + if (binded[i].type.getClass().getName() == external.type.getClass().getName()) { + System.out.println("append stack"); + binded[i].putStack(external); + } + i++; } - if (key == Keyboard.KEY_5) { - select(4); + i = 0; + // looking for empty slot + while (i < TOTAL_NUM && external.count > 0) { + if (binded[i].count == 0) { // empty + System.out.println("replace stack"); + binded[i].putStack(external); + } + i++; } - if (key == Keyboard.KEY_6) { - select(5); + } + + public void closeGUI() { + isGUIOpened = false; + MouseJail.enable(); + MouseJail.setActive(true); + if (null != picked) { + putPickedBack(); } - if (key == Keyboard.KEY_7) { - select(6); + } + + private int spacing = 2; + private int padding = spacing / 2 + 1; + private int width = 34 * BIND_NUM + padding * 2 + spacing * (BIND_NUM - 1); + private int height = 34 + padding * 2; + + public void renderGUIClosed() { + // render bottom line + GL2 gl = GLContext.getCurrentGL().getGL2(); + + int x = 0 + GameFrame.getGLWidth() / 2 - width / 2; + int y = GameFrame.getGLHeight() - height - padding; + /* + * gl.glColor3f(0.8f, 0.8f, 0.8f); + * gl.glRecti(x, y, x + width, y + height); + * for (int i = 0; i < BIND_NUM; i++) { + * bindedX[i] = x + padding + spacing * i + 32 * i + 1; + * bindedY[i] = y + padding + 1; + * int fx = x + padding + spacing * i + 32 * i; + * int fy = y + padding; + * // left + * gl.glColor3f(0.6f, 0.6f, 0.6f); + * gl.glRecti(fx, fy, fx + spacing / 2, fy + 32); + * // right + * gl.glColor3f(0.5f, 0.5f, 0.5f); + * gl.glRecti(fx, fy, fx + spacing / 2, fy + 32); + * // top + * gl.glColor3f(0.4f, 0.4f, 0.4f); + * gl.glRecti(fx, fy, fx + 32, fy + spacing / 2); + * // bottom + * gl.glColor3f(0.3f, 0.3f, 0.3f); + * gl.glRecti(fx, fy, fx + 32, fy + spacing / 2); + * } + */ + if (null != bindedGUI) { + bindedGUI.draw(); } - if (key == Keyboard.KEY_8) { - select(7); + + gl.glEnable(GL2.GL_TEXTURE_2D); + for (int i = 0; i < BIND_NUM; i++) { + BlockStack stack = binded[i]; + if (null != stack && !(stack.type instanceof EmptyBlockType) && stack.count > 0 && !stack.hidden) { + Texture tex = TextureManager.getSprite(stack.type.getStackTextureFile()); + SpriteRectangle uv = TextureManager.getSpriteOffset(stack.type.getStackTextureFile()); + 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 sx = x + padding + spacing * i + 34 * i + 1; + int sy = y + padding + 1; + gl.glTexCoord4f(uv.topLeft.x, uv.topLeft.y, uv.bottomRight.x, uv.bottomRight.y); + gl.glBegin(GL2.GL_QUADS); + { + gl.glTexCoord2f(uv.topLeft.x, uv.topLeft.y); + gl.glVertex2f(sx, sy); + gl.glTexCoord2f(uv.topLeft.x, uv.bottomRight.y); + gl.glVertex2f(sx, sy + 32); + gl.glTexCoord2f(uv.bottomRight.x, uv.bottomRight.y); + gl.glVertex2f(sx + 32, sy + 32); + gl.glTexCoord2f(uv.bottomRight.x, uv.topLeft.y); + gl.glVertex2f(sx + 32, sy); + } + gl.glEnd(); + // if (stack.count > 0) { + gl.glColor4f(1, 1, 1, 1); + Game.client.getScene().viewport.drawText("" + stack.count, sx, GameFrame.getGLHeight() - sy - 10); + // } + } } - if (key == Keyboard.KEY_9) { - select(8); + if (null != picked) { + // draw picked + BlockStack stack = picked; + if (null != stack && !(stack.type instanceof EmptyBlockType) && stack.count > 0) { + Texture tex = TextureManager.getSprite(stack.type.getStackTextureFile()); + SpriteRectangle uv = TextureManager.getSpriteOffset(stack.type.getStackTextureFile()); + 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 sx = MouseJail.instance.x - 16; + int sy = MouseJail.instance.y - 16; + gl.glTexCoord4f(uv.topLeft.x, uv.topLeft.y, uv.bottomRight.x, uv.bottomRight.y); + gl.glBegin(GL2.GL_QUADS); + { + gl.glTexCoord2f(uv.topLeft.x, uv.topLeft.y); + gl.glVertex2f(sx, sy); + gl.glTexCoord2f(uv.topLeft.x, uv.bottomRight.y); + gl.glVertex2f(sx, sy + 32); + gl.glTexCoord2f(uv.bottomRight.x, uv.bottomRight.y); + gl.glVertex2f(sx + 32, sy + 32); + gl.glTexCoord2f(uv.bottomRight.x, uv.topLeft.y); + gl.glVertex2f(sx + 32, sy); + } + gl.glEnd(); + // if (stack.count > 0) { + gl.glColor4f(1, 1, 1, 1); + Game.client.getScene().viewport.drawText("" + stack.count, sx, GameFrame.getGLHeight() - sy - 10); + // } + } } - if (key == Keyboard.KEY_0) { - select(9); + gl.glDisable(GL2.GL_TEXTURE_2D); + } + + public void renderGUIOpened() { + GL2 gl = GLContext.getCurrentGL().getGL2(); + + int oHeight = 300; + int x = 0 + GameFrame.getGLWidth() / 2 - width / 2; + int y = GameFrame.getGLHeight() - oHeight - height - padding - 32; + gl.glColor3f(0.8f, 0.8f, 0.8f); + gl.glRecti(x, y, x + width, y + oHeight); + for (int ni = BIND_NUM; ni < BIND_NUM + BACKPACK_NUM; ni++) { + int dy = ni / 10; + int dx = ni - dy * 10; + bindedX[ni] = x + padding + spacing * dx + 32 * dx + 1; + bindedY[ni] = y + padding + spacing * dy + 32 * dy + 1; + int fx = x + padding + spacing * dx + 32 * dx; + int fy = y + padding + spacing * dy + 32 * dy; + // left + gl.glColor3f(0.6f, 0.6f, 0.6f); + gl.glRecti(fx, fy, fx + spacing / 2, fy + 32); + // right + gl.glColor3f(0.5f, 0.5f, 0.5f); + gl.glRecti(fx, fy, fx + spacing / 2, fy + 32); + // top + gl.glColor3f(0.4f, 0.4f, 0.4f); + gl.glRecti(fx, fy, fx + 32, fy + spacing / 2); + // bottom + gl.glColor3f(0.3f, 0.3f, 0.3f); + gl.glRecti(fx, fy, fx + 32, fy + spacing / 2); } - if (key == Keyboard.KEY_E) { - isInventoryGUIOpen = !isInventoryGUIOpen; + gl.glColor3f(0.2f, 0.2f, 0.2f); + int fx = x + padding + spacing * selectedId + 32 * selectedId; + int fy = y + padding; + gl.glRecti(fx, fy, fx + 32 + 2, fy + 32 + 2); + gl.glEnable(GL2.GL_TEXTURE_2D); + for (int ni = BIND_NUM; ni < BIND_NUM + BACKPACK_NUM; ni++) { + int dy = ni / 10; + int dx = ni - dy * 10; + bindedX[ni] = x + padding + spacing * dx + 32 * dx + 1; + bindedY[ni] = y + padding + spacing * dy + 32 * dy + 1; + int sx = x + padding + spacing * dx + 32 * dx + 1; + int sy = y + padding + spacing * dy + 32 * dy + 1; + BlockStack stack = binded[ni]; + if (null != stack && !(stack.type instanceof EmptyBlockType) && stack.count > 0 && !stack.hidden) { + Texture tex = TextureManager.getSprite(stack.type.getStackTextureFile()); + SpriteRectangle uv = TextureManager.getSpriteOffset(stack.type.getStackTextureFile()); + 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); + gl.glTexCoord4f(uv.topLeft.x, uv.topLeft.y, uv.bottomRight.x, uv.bottomRight.y); + gl.glBegin(GL2.GL_QUADS); + { + gl.glTexCoord2f(uv.topLeft.x, uv.topLeft.y); + gl.glVertex2f(sx, sy); + gl.glTexCoord2f(uv.topLeft.x, uv.bottomRight.y); + gl.glVertex2f(sx, sy + 32); + gl.glTexCoord2f(uv.bottomRight.x, uv.bottomRight.y); + gl.glVertex2f(sx + 32, sy + 32); + gl.glTexCoord2f(uv.bottomRight.x, uv.topLeft.y); + gl.glVertex2f(sx + 32, sy); + } + gl.glEnd(); + // if (stack.count > 0) { + gl.glColor4f(1, 1, 1, 1); + Game.client.getScene().viewport.drawText("" + stack.count, sx, GameFrame.getGLHeight() - sy - 10); + // } + } } + gl.glDisable(GL2.GL_TEXTURE_2D); + } + public void renderGUI() { + if (isGUIOpened) { + renderGUIOpened(); + } else { + if (null != picked) { + putPickedBack(); + } + } + renderGUIClosed(); } public void select(int i) { + selectedId = i; selected = binded[i]; + buildMeshes(); + } + + public void toggleGUI() { + if (isGUIOpened) { + closeGUI(); + } else { + openGUI(); + } + buildMeshes(); + } + + public boolean isGUIOpened() { + return isGUIOpened; + } + + public void click(boolean half) { + if (null == picked) { + pickHover(half); + } else { + placePicked(); + } + buildMeshes(); } } diff --git a/src/ru/olamedia/olacraft/modelAnimator/Arm.java b/src/ru/olamedia/olacraft/modelAnimator/Arm.java new file mode 100644 index 0000000..eeeea77 --- /dev/null +++ b/src/ru/olamedia/olacraft/modelAnimator/Arm.java @@ -0,0 +1,27 @@ +package ru.olamedia.olacraft.modelAnimator; + +public class Arm extends BoneSet { + // 左腕 - левая рука + // 左ひじ - левый локоть + // 左手首 - левое запястье + // 左袖 - левый рукав + public Bone top; + public Bone elbow; + public Bone wrist; + + public Arm() { + super(3); + top = new Bone(); + elbow = new Bone(); + wrist = new Bone(); + setChild(0, top); + setChild(1, elbow); + setChild(2, wrist); + } + + public void setNamePrefix(String prefix) { + top.setName(prefix + top.getName()); + elbow.setName(prefix + elbow.getName()); + wrist.setName(prefix + wrist.getName()); + } +} diff --git a/src/ru/olamedia/olacraft/modelAnimator/Bone.java b/src/ru/olamedia/olacraft/modelAnimator/Bone.java new file mode 100644 index 0000000..0bda33d --- /dev/null +++ b/src/ru/olamedia/olacraft/modelAnimator/Bone.java @@ -0,0 +1,215 @@ +package ru.olamedia.olacraft.modelAnimator; + +import java.util.Random; + +public class Bone implements ISkeletonNode { + private String name; + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + + private float speed = 1f; + private float yaw; + private float pitch; + private float roll; + private float yawCorrection = 0; + private float pitchCorrection = 0; + private float rollCorrection = 0; + @SuppressWarnings("unused") + private boolean isAnglesModified = false; + private boolean isMatrixModified = false; + + @Override + public int getChildrenCount() { + return 0; + } + + @Override + public Bone getChild(int i) { + return null; + } + + private void updateAngles() { + if (isMatrixModified) { + + } + } + + /* + * private void updateMatrix() { + * if (isAnglesModified) { + * + * } + * } + */ + + public float getSpeed() { + return speed; + } + + /* + * (non-Javadoc) + * + * @see ru.olamedia.olacraft.modelAnimator.ISkeletonNode#setSpeed(float) + */ + @Override + public void setSpeed(float speed) { + this.speed = speed; + } + + /* + * (non-Javadoc) + * + * @see + * ru.olamedia.olacraft.modelAnimator.ISkeletonNode#copyOrientation(ru.olamedia + * .olacraft.modelAnimator.Bone) + */ + @Override + public void copyOrientation(ISkeletonNode node) { + final Bone b = (Bone) node; + setPitch(b.getPitch()); + setPitchCorrection(b.getPitchCorrection()); + setYaw(b.getYaw()); + setYawCorrection(b.getYawCorrection()); + setRoll(b.getRoll()); + setRollCorrection(b.getRollCorrection()); + } + + /* + * (non-Javadoc) + * + * @see + * ru.olamedia.olacraft.modelAnimator.ISkeletonNode#setDelta(ru.olamedia + * .olacraft.modelAnimator.Bone, ru.olamedia.olacraft.modelAnimator.Bone, + * float) + */ + @Override + public void setDelta(ISkeletonNode firstNode, ISkeletonNode secondNode, float delta) { + final Bone first = (Bone) firstNode; + final Bone second = (Bone) secondNode; + final float dPitch = second.getPitch() - first.getPitch(); + setPitch(first.getPitch() + dPitch * getSpeed() * delta); + final float dYaw = second.getYaw() - first.getYaw(); + setYaw(first.getYaw() + dYaw * getSpeed() * delta); + final float dRoll = second.getRoll() - first.getRoll(); + setRoll(first.getRoll() + dRoll * getSpeed() * delta); + } + + public float getYaw() { + updateAngles(); + return yaw; + } + + public float getCorrectedYaw() { + return getYawCorrection() + getYaw(); + } + + public void setYaw(float yaw) { + this.yaw = yaw; + isAnglesModified = true; + } + + public float getPitch() { + updateAngles(); + return pitch; + } + + public float getCorrectedPitch() { + return getPitchCorrection() + getPitch(); + } + + public void setPitch(float pitch) { + this.pitch = pitch; + isAnglesModified = true; + } + + public float getRoll() { + updateAngles(); + return roll; + } + + public float getCorrectedRoll() { + return getRollCorrection() + getRoll(); + } + + public void setRoll(float roll) { + this.roll = roll; + isAnglesModified = true; + } + + private final float yawRand = 5f; + private final float pitchRand = 1f; + private final float rollRand = 5f; + + /* + * (non-Javadoc) + * + * @see ru.olamedia.olacraft.modelAnimator.ISkeletonNode#reset() + */ + @Override + public void reset() { + yaw = 0; + pitch = 0; + roll = 0; + } + + private float nextFloatDelta(Random rand, Random prev, float delta) { + final float first = prev.nextFloat(); + final float second = rand.nextFloat(); + return first + (second - first) * delta; + } + + /* + * (non-Javadoc) + * + * @see + * ru.olamedia.olacraft.modelAnimator.ISkeletonNode#randomize(java.util. + * Random, java.util.Random, float) + */ + @Override + public void randomize(Random rand, Random prev, float delta) { + // delta = 1; + setYaw(yaw + (nextFloatDelta(rand, prev, delta) - 0.5f) * yawRand); + setPitch(pitch + (nextFloatDelta(rand, prev, delta) - 0.5f) * pitchRand); + setRoll(roll + (nextFloatDelta(rand, prev, delta) - 0.5f) * rollRand); + } + + public float getYawCorrection() { + return yawCorrection; + } + + public void setYawCorrection(float yawCorrection) { + this.yawCorrection = yawCorrection; + } + + public float getPitchCorrection() { + return pitchCorrection; + } + + public void setPitchCorrection(float pitchCorrection) { + this.pitchCorrection = pitchCorrection; + } + + public float getRollCorrection() { + return rollCorrection; + } + + public void setRollCorrection(float rollCorrection) { + this.rollCorrection = rollCorrection; + } + + @Override + public void setChild(int i, ISkeletonNode b) { + + } +} diff --git a/src/ru/olamedia/olacraft/modelAnimator/BoneSet.java b/src/ru/olamedia/olacraft/modelAnimator/BoneSet.java new file mode 100644 index 0000000..0e3ce2c --- /dev/null +++ b/src/ru/olamedia/olacraft/modelAnimator/BoneSet.java @@ -0,0 +1,163 @@ +package ru.olamedia.olacraft.modelAnimator; + +import java.util.Iterator; +import java.util.Random; + +public class BoneSet implements ISkeletonNode, Iterable<Bone> { + + private class BonesIterator implements Iterator<Bone> { + private BoneSet set; + private Iterator<Bone> childIterator = null; + private int current = 0; + + public BonesIterator(BoneSet boneSet) { + set = boneSet; + } + + @Override + public boolean hasNext() { + if (null == childIterator) { + return current < set.getChildrenCount(); + } else { + return childIterator.hasNext() || current < set.getChildrenCount(); + } + } + + private boolean nextIsChild; + + @Override + public Bone next() { + if (null == childIterator) { + ISkeletonNode node = set.getChild(current); + if (node instanceof Bone) { + Bone b = (Bone) node; + current++; + return b; + } else if (node instanceof BoneSet) { + childIterator = ((BoneSet) node).iterator(); + current++; + } + } + if (null != childIterator) { + nextIsChild = childIterator.hasNext(); + if (nextIsChild) { + Bone b = childIterator.next(); + return b; + } + if (!nextIsChild) { + childIterator = null; + } + } + if (current < set.getChildrenCount()) { + return next(); + } + return null; + } + + @Override + public void remove() { + + } + + } + + public BoneSet(int bonesCount) { + nodes = new ISkeletonNode[bonesCount]; + for (int i = 0; i < bonesCount; i++) { + // bones[i] = new Bone(); + } + } + + private ISkeletonNode[] nodes; + private String name; + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @param name + * the name to set + */ + public void setName(String name) { + this.name = name; + } + + @Override + public int getChildrenCount() { + return nodes.length; + } + + public ISkeletonNode getChild(int i) { + return nodes[i]; + } + + @Override + public void setSpeed(float speed) { + for (ISkeletonNode b : nodes) { + b.setSpeed(speed); + } + } + + @Override + public void copyOrientation(ISkeletonNode bs) { + for (int i = 0; i < nodes.length; i++) { + nodes[i].copyOrientation(bs.getChild(i)); + } + } + + @Override + public void setDelta(ISkeletonNode first, ISkeletonNode second, float delta) { + for (int i = 0; i < nodes.length; i++) { + nodes[i].setDelta(first.getChild(i), second.getChild(i), delta); + } + } + + @Override + public void reset() { + for (int i = 0; i < nodes.length; i++) { + nodes[i].reset(); + } + } + + @Override + public void randomize(Random rand, Random prev, float delta) { + for (int i = 0; i < nodes.length; i++) { + nodes[i].randomize(rand, prev, delta); + } + } + + @Override + public void setChild(int i, ISkeletonNode node) { + nodes[i] = node; + } + + @Override + public Iterator<Bone> iterator() { + return new BonesIterator(this); + } + + public int getBoneCount() { + int n = 0; + Iterator<Bone> it = iterator(); + while (it.hasNext()) { + it.next(); + n++; + } + return n; + } + + public Bone getBone(int i) { + int j = 0; + Iterator<Bone> it = iterator(); + Bone b = null; + while (it.hasNext() && j <= i) { + b = it.next(); + j++; + } + return b; + } +} diff --git a/src/ru/olamedia/olacraft/modelAnimator/ISkeletonNode.java b/src/ru/olamedia/olacraft/modelAnimator/ISkeletonNode.java new file mode 100644 index 0000000..2b1b28a --- /dev/null +++ b/src/ru/olamedia/olacraft/modelAnimator/ISkeletonNode.java @@ -0,0 +1,26 @@ +package ru.olamedia.olacraft.modelAnimator; + +import java.util.Random; + +public interface ISkeletonNode { + public void setName(String name); + + public String getName(); + + public ISkeletonNode getChild(int i); + + public void setChild(int i, ISkeletonNode b); + + public int getChildrenCount(); + + public abstract void setSpeed(float speed); + + public abstract void copyOrientation(ISkeletonNode b); + + public abstract void setDelta(ISkeletonNode first, ISkeletonNode second, float delta); + + public abstract void reset(); + + public abstract void randomize(Random rand, Random prev, float delta); + +}
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/modelAnimator/Leg.java b/src/ru/olamedia/olacraft/modelAnimator/Leg.java new file mode 100644 index 0000000..0f9000d --- /dev/null +++ b/src/ru/olamedia/olacraft/modelAnimator/Leg.java @@ -0,0 +1,27 @@ +package ru.olamedia.olacraft.modelAnimator; + +public class Leg extends BoneSet { + + public Bone top; + public Bone knee; + public Bone foot; + + public Leg() { + super(3); + top = new Bone(); + knee = new Bone(); + foot = new Bone(); + setChild(0, top); + setChild(1, knee); + setChild(2, foot); + top.setName("Top"); + knee.setName("Knee"); + foot.setName("Foot"); + } + + public void setNamePrefix(String prefix) { + top.setName(prefix + top.getName()); + knee.setName(prefix + knee.getName()); + foot.setName(prefix + foot.getName()); + } +} diff --git a/src/ru/olamedia/olacraft/modelAnimator/ModelAnimator.java b/src/ru/olamedia/olacraft/modelAnimator/ModelAnimator.java new file mode 100644 index 0000000..712cbd1 --- /dev/null +++ b/src/ru/olamedia/olacraft/modelAnimator/ModelAnimator.java @@ -0,0 +1,324 @@ +package ru.olamedia.olacraft.modelAnimator; + +public class ModelAnimator { + private boolean isWalking = false; + private boolean isCrawling = false; + private boolean isCrouching = false; + private boolean isJumping = false; + private boolean isFalling = false; + private boolean isStrafingLeft = false; + private boolean isStrafingRight = false; + private boolean isMovingForward = false; + private boolean isMovingBackward = false; + private float delta; + + private Skeleton currentOrientation = new Skeleton(); + public Skeleton finalOrientation = new Skeleton(); + public Skeleton deltaOrientation = new Skeleton(); + + public ModelAnimator() { + generateFrames(); + } + + public boolean isWalking() { + return isWalking; + } + + public void setWalking(boolean isWalking) { + this.isWalking = isWalking; + } + + public boolean isCrawling() { + return isCrawling; + } + + public void setCrawling(boolean isCrawling) { + this.isCrawling = isCrawling; + } + + public boolean isCrouching() { + return isCrouching; + } + + public void setCrouching(boolean isCrouching) { + this.isCrouching = isCrouching; + } + + public boolean isJumping() { + return isJumping; + } + + public void setJumping(boolean isJumping) { + this.isJumping = isJumping; + } + + public boolean isFalling() { + return isFalling; + } + + public void setFalling(boolean isFalling) { + this.isFalling = isFalling; + } + + public boolean isStrafingLeft() { + return isStrafingLeft; + } + + public void setStrafingLeft(boolean isStrafingLeft) { + this.isStrafingLeft = isStrafingLeft; + } + + public boolean isStrafingRight() { + return isStrafingRight; + } + + public void setStrafingRight(boolean isStrafingRight) { + this.isStrafingRight = isStrafingRight; + } + + public boolean isMovingForward() { + return isMovingForward; + } + + public void setMovingForward(boolean isMovingForward) { + this.isMovingForward = isMovingForward; + } + + public boolean isMovingBackward() { + return isMovingBackward; + } + + public void setMovingBackward(boolean isMovingBackward) { + this.isMovingBackward = isMovingBackward; + } + + public float getDelta() { + return delta; + } + + public void setDelta(float delta) { + this.delta = delta; + } + + // Frames + private Skeleton walkLeftLegForward = new Skeleton(); + private Skeleton walkRightLegForward = new Skeleton(); + private Skeleton standLeftLegApart = new Skeleton(); + private Skeleton standRightLegApart = new Skeleton(); + + private void generateFrames() { + // walkLeftLegForward.leftLeg.top.setYaw(-5); + walkLeftLegForward.skirtFrontLeft.setPitch(30); + walkLeftLegForward.skirtFrontLeft.setYaw(30); + walkLeftLegForward.skirtFrontRight.setPitch(-5); + walkRightLegForward.skirtFrontRight.setPitch(30); + walkRightLegForward.skirtFrontRight.setYaw(-30); + walkRightLegForward.skirtFrontLeft.setPitch(-5); + // walkLeftLegForward.skirtFrontLeft.setYaw(40); + // walkLeftLegForward.skirtFrontLeft.setRoll(40); + // walkLeftLegForward.rightLeg.top.setYaw(5); + walkLeftLegForward.leftLeg.top.setPitch(35); + walkLeftLegForward.leftLeg.knee.setPitch(-30); + walkLeftLegForward.leftLeg.foot.setPitch(25); + walkLeftLegForward.leftLeg.top.setYaw(-10); + walkLeftLegForward.leftLeg.knee.setYaw(-10); + walkLeftLegForward.rightLeg.top.setYaw(-10); + walkLeftLegForward.rightLeg.knee.setYaw(-10); + walkLeftLegForward.rightLeg.top.setPitch(-10); + walkLeftLegForward.rightLeg.knee.setPitch(-15); + walkLeftLegForward.rightLeg.foot.setPitch(8); + /*walkLeftLegForward.leftLeg.top.setPitch(59); + walkLeftLegForward.leftLeg.top.setYaw(-9); + walkLeftLegForward.leftLeg.top.setRoll(10); + walkLeftLegForward.leftLeg.knee.setPitch(-100); + walkLeftLegForward.leftLeg.knee.setYaw(-9);*/ + walkRightLegForward.leftLeg.copyOrientation(walkLeftLegForward.rightLeg); + walkRightLegForward.rightLeg.copyOrientation(walkLeftLegForward.leftLeg); + walkRightLegForward.rightLeg.top.setYaw(10); + walkRightLegForward.rightLeg.knee.setYaw(10); + walkRightLegForward.leftLeg.top.setYaw(10); + walkRightLegForward.leftLeg.knee.setYaw(10); + + walkLeftLegForward.waist.setYaw(18); + walkRightLegForward.waist.setYaw(-18); + walkLeftLegForward.shoulders.setYaw(-10); + walkLeftLegForward.shoulders.setRoll(-4); + walkRightLegForward.shoulders.setYaw(10); + walkRightLegForward.shoulders.setRoll(4); + // ARMS + walkLeftLegForward.rightArm.top.setPitch(15); + walkLeftLegForward.rightArm.top.setRoll(-7); + walkLeftLegForward.rightArm.elbow.setYaw(-90); + walkLeftLegForward.rightArm.wrist.setYaw(0); + walkLeftLegForward.rightArm.wrist.setPitch(0); + walkLeftLegForward.rightArm.wrist.setRoll(50); + walkLeftLegForward.leftArm.wrist.setRoll(30); + walkLeftLegForward.leftArm.top.setPitch(-14); + walkLeftLegForward.leftArm.top.setYaw(-2); + walkLeftLegForward.leftArm.top.setRoll(17); + // walkRightLegForward.leftArm.elbow.setRoll(90); + walkRightLegForward.leftArm.top.setPitch(15); + walkRightLegForward.leftArm.top.setRoll(7); + walkRightLegForward.leftArm.elbow.setYaw(90); + walkRightLegForward.leftArm.wrist.setYaw(0); + walkRightLegForward.leftArm.wrist.setPitch(0); + walkRightLegForward.leftArm.wrist.setRoll(-50); + walkRightLegForward.rightArm.wrist.setRoll(-30); + walkRightLegForward.rightArm.top.setPitch(-14); + walkRightLegForward.rightArm.top.setYaw(2); + walkRightLegForward.rightArm.top.setRoll(-17); + + standLeftLegApart.leftLeg.top.setRoll(-10); + standLeftLegApart.leftLeg.foot.setYaw(-10); + standRightLegApart.rightLeg.top.setRoll(10); + standRightLegApart.rightLeg.foot.setYaw(10); + } + + private boolean areLegsApart = false; + private boolean areLegsTogether = true; + private boolean isLeftLegAhead = false; + private boolean isLegReturning = false; + private float walkStepTimer = 0; + private float walkStepTime = 0.25f; + private float standTimer = 0; + private float standTime = 3f; + private boolean isStandLeftLegApart = true; + + private void standTick() { + standTimer += getDelta(); + if (standTimer >= standTime) { + // Switch legs + standTimer -= standTime; + isStandLeftLegApart = !isStandLeftLegApart; + } + } + + private void setLegsStanding() { + if (isStandLeftLegApart) { + finalOrientation.leftLeg.copyOrientation(standLeftLegApart.leftLeg); + finalOrientation.rightLeg.copyOrientation(standLeftLegApart.rightLeg); + } else { + finalOrientation.leftLeg.copyOrientation(standRightLegApart.leftLeg); + finalOrientation.rightLeg.copyOrientation(standRightLegApart.rightLeg); + } + } + + private void walkTick() { + walkStepTimer += getDelta(); + if (walkStepTimer >= walkStepTime) { + // Switch step, legs + walkStepTimer -= walkStepTime; + if (areLegsTogether) { + areLegsTogether = false; + areLegsApart = true; + isLeftLegAhead = !isLeftLegAhead; + isLegReturning = false; + } else { + areLegsTogether = true; + areLegsApart = false; + isLegReturning = true; + } + } + } + + private void setLegsWalking() { + if (isLeftLegAhead) { + finalOrientation.leftLeg.copyOrientation(walkLeftLegForward.leftLeg); + finalOrientation.rightLeg.copyOrientation(walkLeftLegForward.rightLeg); + finalOrientation.waist.copyOrientation(walkLeftLegForward.waist); + finalOrientation.shoulders.copyOrientation(walkLeftLegForward.shoulders); + finalOrientation.leftArm.copyOrientation(walkLeftLegForward.leftArm); + finalOrientation.rightArm.copyOrientation(walkLeftLegForward.rightArm); + finalOrientation.skirtFrontLeft.copyOrientation(walkLeftLegForward.skirtFrontLeft); + finalOrientation.skirtFrontRight.copyOrientation(walkLeftLegForward.skirtFrontRight); + } else { + finalOrientation.leftLeg.copyOrientation(walkRightLegForward.leftLeg); + finalOrientation.rightLeg.copyOrientation(walkRightLegForward.rightLeg); + finalOrientation.waist.copyOrientation(walkRightLegForward.waist); + finalOrientation.shoulders.copyOrientation(walkRightLegForward.shoulders); + finalOrientation.leftArm.copyOrientation(walkRightLegForward.leftArm); + finalOrientation.rightArm.copyOrientation(walkRightLegForward.rightArm); + finalOrientation.skirtFrontLeft.copyOrientation(walkRightLegForward.skirtFrontLeft); + finalOrientation.skirtFrontRight.copyOrientation(walkRightLegForward.skirtFrontRight); + } + } + + private Randomizer leftLegRandomizer = new Randomizer(0.5f, 7f); + private Randomizer rightLegRandomizer = new Randomizer(0.5f, 7f); + + private void randomize() { + rightLegRandomizer.setPaused(!leftLegRandomizer.isPaused()); + rightLegRandomizer.tick(delta); + leftLegRandomizer.tick(delta); + leftLegRandomizer.randomize(finalOrientation.leftLeg); + rightLegRandomizer.randomize(finalOrientation.rightLeg); + } + + private void fixClothOrientation() { + + } + + public void tick() { + if (!demoMode) { + finalOrientation.reset(); + } + if (!demoMode) { + // deltaOrientation.reset(); + if (isJumping()) { + // air motion + while (!areLegsApart) { + walkTick(); + setLegsWalking(); + } + } else { + // on-ground motion + if (isWalking()) { + walkTick(); + if (isCrawling()) { + + } else if (isCrouching()) { + + } else { + // standing + setLegsWalking(); + } + } else { + // make legs together, switch forward leg + while (!areLegsTogether) { + walkTick(); + standTick(); + setLegsWalking(); + setLegsStanding(); + } + } + } + randomize(); + // System.err.println("[leg] " + + // finalOrientation.leftLeg.top.getPitch()); + fixClothOrientation(); + deltaOrientation.leftArm.top.setRollCorrection(-50f); + deltaOrientation.rightArm.top.setRollCorrection(-deltaOrientation.leftArm.top.getRollCorrection()); + deltaOrientation.setSpeed(4f); + deltaOrientation.skirtFrontLeft.setSpeed(1f); + deltaOrientation.skirtFrontRight.setSpeed(1f); + if (isLeftLegAhead && !isLegReturning) { + deltaOrientation.skirtFrontLeft.setSpeed(4f); + } + if (!isLeftLegAhead && !isLegReturning) { + deltaOrientation.skirtFrontRight.setSpeed(4f); + } + }else{ + deltaOrientation.setSpeed(4f); + } + deltaOrientation.setDelta(currentOrientation, finalOrientation, getDelta()); + // deltaOrientation.copyOrientation(finalOrientation); + currentOrientation.copyOrientation(deltaOrientation); + } + + private boolean demoMode = false; + + public void setPause(boolean boneMode) { + demoMode = boneMode; + } + +} diff --git a/src/ru/olamedia/olacraft/modelAnimator/Randomizer.java b/src/ru/olamedia/olacraft/modelAnimator/Randomizer.java new file mode 100644 index 0000000..1e66c87 --- /dev/null +++ b/src/ru/olamedia/olacraft/modelAnimator/Randomizer.java @@ -0,0 +1,92 @@ +package ru.olamedia.olacraft.modelAnimator; + +import java.util.Random; + +public class Randomizer { + + public Randomizer(float minTimeout, float maxTimeout) { + super(); + this.minTimeout = minTimeout; + this.maxTimeout = maxTimeout; + } + + private float minTimeout = 1f; + private float maxTimeout = 1f; + private long seed; + private long prevSeed = 0; + private float seedTimeout = 0; + private float seedTime = 0; + private float delta; + private boolean isPaused = false; + private boolean isForcePaused = false; + + /** + * @return the isPaused + */ + public boolean isPaused() { + return isPaused; + } + + /** + * @param isPaused + * the isPaused to set + */ + public void setPaused(boolean isPaused) { + this.isForcePaused = isPaused; + } + + private Random rand = new Random(); + private Random prev = new Random(); + + public void tick(float delta) { + if (!isForcePaused) { + seedTimeout -= delta; + } + if (seedTimeout <= 0) { + if (!isPaused) { + prevSeed = seed; + } + Random srand = new Random(); + seed = srand.nextLong(); + seedTime = seedTimeout = minTimeout + srand.nextFloat() * (maxTimeout - minTimeout); + } + prev.setSeed(prevSeed); + rand.setSeed(seed); + prev.nextBoolean(); + isPaused = rand.nextBoolean(); + if (isPaused) { + this.delta = 0; + } else { + this.delta = (seedTime - seedTimeout) / seedTime; + } + } + + public float getMinTimeout() { + return minTimeout; + } + + public void setMinTimeout(float minTimeout) { + this.minTimeout = minTimeout; + } + + public float getMaxTimeout() { + return maxTimeout; + } + + public void setMaxTimeout(float maxTimeout) { + this.maxTimeout = maxTimeout; + } + + public void randomize(Skeleton skel) { + skel.randomize(rand, prev, delta); + } + + public void randomize(Leg leg) { + leg.randomize(rand, prev, delta); + } + + public void randomize(ISkeletonNode b) { + b.randomize(rand, prev, delta); + } + +} diff --git a/src/ru/olamedia/olacraft/modelAnimator/Skeleton.java b/src/ru/olamedia/olacraft/modelAnimator/Skeleton.java new file mode 100644 index 0000000..5cae422 --- /dev/null +++ b/src/ru/olamedia/olacraft/modelAnimator/Skeleton.java @@ -0,0 +1,47 @@ +package ru.olamedia.olacraft.modelAnimator; + +public class Skeleton extends BoneSet { + + public Bone neck; // 首 - шея + public Bone shoulders; // 上半身 - верхняя часть тела + public Bone waist; // 下半身 - нижняя часть корпуса + public Bone skirtFrontLeft; + public Bone skirtFrontRight; + + public Arm leftArm; + public Arm rightArm; + + public Leg leftLeg; + public Leg rightLeg; + + public Skeleton() { + super(9); + neck = new Bone(); + neck.setName("Neck"); + waist = new Bone(); + waist.setName("Waist"); + shoulders = new Bone(); + shoulders.setName("Shoulders"); + skirtFrontLeft = new Bone(); + skirtFrontLeft.setName("Skirt Front Left"); + skirtFrontRight = new Bone(); + skirtFrontRight.setName("Skirt Front Right"); + leftArm = new Arm(); + rightArm = new Arm(); + leftLeg = new Leg(); + rightLeg = new Leg(); + leftArm.setNamePrefix("Left arm "); + rightArm.setNamePrefix("Right arm "); + leftLeg.setNamePrefix("Left leg "); + rightLeg.setNamePrefix("Right leg "); + setChild(0, neck); + setChild(1, waist); + setChild(2, shoulders); + setChild(3, skirtFrontLeft); + setChild(4, skirtFrontRight); + setChild(5, leftArm); + setChild(6, rightArm); + setChild(7, leftLeg); + setChild(8, rightLeg); + } +} diff --git a/src/ru/olamedia/olacraft/modelAnimator/package-info.java b/src/ru/olamedia/olacraft/modelAnimator/package-info.java new file mode 100644 index 0000000..7bc19b6 --- /dev/null +++ b/src/ru/olamedia/olacraft/modelAnimator/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.modelAnimator;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/network/GameClient.java b/src/ru/olamedia/olacraft/network/GameClient.java index f74340a..ee9ce32 100644 --- a/src/ru/olamedia/olacraft/network/GameClient.java +++ b/src/ru/olamedia/olacraft/network/GameClient.java @@ -25,6 +25,7 @@ import ru.olamedia.olacraft.network.packet.WorldInfoPacket; import ru.olamedia.olacraft.scene.GameScene; import ru.olamedia.olacraft.world.WorldInfo; import ru.olamedia.olacraft.world.dataProvider.CachedChunkDataProvider; +import ru.olamedia.olacraft.world.dataProvider.LocalChunkDataProvider; import ru.olamedia.olacraft.world.dataProvider.RemoteChunkDataProvider; import ru.olamedia.olacraft.world.provider.WorldProvider; @@ -63,9 +64,12 @@ public class GameClient extends ConnectionStateListener implements IPacketListen public GameClient() { // INIT WORLD worldProvider = new WorldProvider(); - worldProvider.setChunkDataProvider(new CachedChunkDataProvider(new RemoteChunkDataProvider(this))); // worldProvider.setChunkDataProvider(new CachedChunkDataProvider(new - // LocalChunkDataProvider(worldProvider.getInfo().name))); + // RemoteChunkDataProvider(this))); + // worldProvider.setChunkDataProvider(new + // LocalChunkDataProvider(worldProvider.getInfo().name)); + worldProvider.setChunkDataProvider(new CachedChunkDataProvider(new LocalChunkDataProvider(worldProvider + .getInfo().name))); // CREATE SCENE scene = new GameScene(worldProvider); Kryo kryo = client.getKryo(); diff --git a/src/ru/olamedia/olacraft/network/GameServer.java b/src/ru/olamedia/olacraft/network/GameServer.java index 717b40b..13b70c4 100644 --- a/src/ru/olamedia/olacraft/network/GameServer.java +++ b/src/ru/olamedia/olacraft/network/GameServer.java @@ -32,6 +32,20 @@ import com.esotericsoftware.kryonet.Server; public class GameServer { private WorldProvider worldProvider; + /** + * @return the worldProvider + */ + public WorldProvider getWorldProvider() { + return worldProvider; + } + + /** + * @param worldProvider the worldProvider to set + */ + public void setWorldProvider(WorldProvider worldProvider) { + this.worldProvider = worldProvider; + } + private ExecutorService threadPool = Executors.newFixedThreadPool(1); public static Server server = new Server(30 * 1024 * 1024, 1024 * 1024) { @Override diff --git a/src/ru/olamedia/olacraft/network/Network.java b/src/ru/olamedia/olacraft/network/Network.java index 22434f1..2c44850 100644 --- a/src/ru/olamedia/olacraft/network/Network.java +++ b/src/ru/olamedia/olacraft/network/Network.java @@ -21,8 +21,11 @@ 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.drop.DroppedEntity; import ru.olamedia.olacraft.world.location.BlockLocation; import ru.olamedia.olacraft.world.location.ChunkLocation; +import ru.olamedia.olacraft.world.location.Location3f; +import ru.olamedia.olacraft.world.location.Location3i; import ru.olamedia.olacraft.world.location.RegionLocation; import ru.olamedia.olacraft.world.location.SectorLocation; @@ -53,10 +56,13 @@ public class Network { kryo.register(HeightMap.class); kryo.register(WorldInfo.class); kryo.register(WorldInfoPacket.class); + kryo.register(Location3f.class); + kryo.register(Location3i.class); kryo.register(BlockLocation.class); kryo.register(ChunkLocation.class); kryo.register(SectorLocation.class); kryo.register(RegionLocation.class); + kryo.register(DroppedEntity.class); kryo.register(ChunkData.class); kryo.register(ChunkData[].class); kryo.register(SectorData.class); diff --git a/src/ru/olamedia/olacraft/network/packet/SectorDataPacket.java b/src/ru/olamedia/olacraft/network/packet/SectorDataPacket.java new file mode 100644 index 0000000..d592a10 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/SectorDataPacket.java @@ -0,0 +1,14 @@ +package ru.olamedia.olacraft.network.packet; + +import ru.olamedia.olacraft.world.data.SectorData; + +public class SectorDataPacket implements IPacket { + public SectorDataPacket() { + } + + public SectorDataPacket(SectorData data) { + this.data = data; + } + + public SectorData data; +} diff --git a/src/ru/olamedia/olacraft/network/provider/CacheProvider.java b/src/ru/olamedia/olacraft/network/provider/CacheProvider.java new file mode 100644 index 0000000..267edb0 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/provider/CacheProvider.java @@ -0,0 +1,29 @@ +package ru.olamedia.olacraft.network.provider; + +public class CacheProvider<T> implements IProvider<T> { + public CacheProvider(IProvider<T> parent) { + this.parent = parent; + } + + private T obj; + private IProvider<T> parent; + + public boolean has() { + return null != obj || parent.has(); + } + + public void request() { + parent.request(); + } + + public T get() { + if (null == obj) { + obj = parent.get(); + } + return obj; + } + + public void put(T obj) { + this.obj = obj; + } +} diff --git a/src/ru/olamedia/olacraft/network/provider/IProvider.java b/src/ru/olamedia/olacraft/network/provider/IProvider.java new file mode 100644 index 0000000..d73b55e --- /dev/null +++ b/src/ru/olamedia/olacraft/network/provider/IProvider.java @@ -0,0 +1,11 @@ +package ru.olamedia.olacraft.network.provider; + +public interface IProvider<T> { + public boolean has(); + + public void request(); + + public T get(); + + public void put(T obj); +} diff --git a/src/ru/olamedia/olacraft/network/provider/LocalProvider.java b/src/ru/olamedia/olacraft/network/provider/LocalProvider.java new file mode 100644 index 0000000..da9b82c --- /dev/null +++ b/src/ru/olamedia/olacraft/network/provider/LocalProvider.java @@ -0,0 +1,21 @@ +package ru.olamedia.olacraft.network.provider; + +public class LocalProvider<T> implements IProvider<T> { + private T obj; + + public boolean has() { + return true; + } + + public void request() { + + } + + public T get() { + return obj; + } + + public void put(T obj) { + this.obj = obj; + } +} diff --git a/src/ru/olamedia/olacraft/network/provider/RemoteProvider.java b/src/ru/olamedia/olacraft/network/provider/RemoteProvider.java new file mode 100644 index 0000000..854293c --- /dev/null +++ b/src/ru/olamedia/olacraft/network/provider/RemoteProvider.java @@ -0,0 +1,19 @@ +package ru.olamedia.olacraft.network.provider; + +abstract public class RemoteProvider<T> implements IProvider<T> { + private T obj; + + public boolean has() { + return null != obj; + } + + abstract public void request(); + + public T get() { + return obj; + } + + public void put(T obj) { + this.obj = obj; + } +} diff --git a/src/ru/olamedia/olacraft/network/provider/package-info.java b/src/ru/olamedia/olacraft/network/provider/package-info.java new file mode 100644 index 0000000..f444cac --- /dev/null +++ b/src/ru/olamedia/olacraft/network/provider/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.network.provider;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/render/jogl/ChunkRangeRenderer.java b/src/ru/olamedia/olacraft/render/jogl/ChunkRangeRenderer.java new file mode 100644 index 0000000..cd84c99 --- /dev/null +++ b/src/ru/olamedia/olacraft/render/jogl/ChunkRangeRenderer.java @@ -0,0 +1,254 @@ +package ru.olamedia.olacraft.render.jogl; + +import java.util.ArrayList; +import java.util.HashMap; + +import javax.media.opengl.GL2; +import javax.media.opengl.GLContext; + +import com.jogamp.opengl.math.geom.AABBox; + +import ru.olamedia.geom.ImmModeMesh; +import ru.olamedia.olacraft.game.Game; +import ru.olamedia.olacraft.world.blockRenderer.ChunkRenderer; +import ru.olamedia.olacraft.world.blockTypes.BlockType; +import ru.olamedia.olacraft.world.blockTypes.GrassBlockType; +import ru.olamedia.olacraft.world.chunk.BlockSlice; +import ru.olamedia.olacraft.world.chunk.Chunk; +import ru.olamedia.olacraft.world.chunk.ChunkMeshBulder; +import ru.olamedia.olacraft.world.chunk.ChunkSlice; +import ru.olamedia.olacraft.world.location.BlockLocation; +import ru.olamedia.olacraft.world.location.ChunkLocation; +import ru.olamedia.player.Player; + +public class ChunkRangeRenderer { + + private class Point { + public int x; + public int y; + public int z; + } + + private ArrayList<ArrayList<Point>> ranges = new ArrayList<ArrayList<Point>>(); + private ArrayList<ArrayList<Point>> visibleRanges = new ArrayList<ArrayList<Point>>(); + + public ImmModeMesh big; + private boolean makeBig = false; + private boolean isBigInvalid = true; + + private void precalcRange() { + for (int d = 0; d < 32; d++) { + ranges.add(new ArrayList<ChunkRangeRenderer.Point>()); + } + for (int d = 0; d < 32; d++) { + visibleRanges.add(new ArrayList<ChunkRangeRenderer.Point>()); + } + for (int dx = -15; dx <= 15; dx++) { + for (int dy = -15; dy <= 15; dy++) { + for (int dz = -15; dz <= 15; dz++) { + final Point p = new Point(); + p.x = dx; + p.y = dy; + p.z = dz; + final int d = (int) Math.floor(Math.sqrt(dx * dx + dy * dy + dz * dz)); + ranges.get(d).add(p); + } + } + } + } + + private int vertexTmpCount; + private int components = 0; + + public void updateFrustumCulling() { + if (null == chunkSlice) { + return; + } + final Player player = Game.client.getScene().getPlayer(); + cameraBlock = player.getCameraBlockLocation(); + cameraChunk = cameraBlock.getChunkLocation(); + final float x = player.camera.getX(); + final float y = player.camera.getY(); + final float z = player.camera.getZ(); + renderDistance = player.settings.renderDistance; + vertexTmpCount = 0; + for (int d = 0; d < renderDistance / 16; d++) { + visibleRanges.get(d).clear(); + for (Point delta : ranges.get(d)) { + renderLoc.x = cameraChunk.x + delta.x; + renderLoc.y = cameraChunk.y + delta.y; + renderLoc.z = cameraChunk.z + delta.z; + final Chunk chunk = chunkSlice.getChunk(renderLoc); + center[0] = (float) (chunk.getOffset().x + 8); + center[1] = (float) (chunk.getOffset().y + 8); + center[2] = (float) (chunk.getOffset().z + 8); + if (!Game.instance.camera.frustum.isSphereOutside(center, radius)) { + if (chunk.mesh.isValid() && chunk.mesh.isEmpty()) { + + } else { + visibleRanges.get(d).add(delta); + vertexTmpCount += chunk.mesh.getVertexCount(); + if ((0 == components) && (null != chunk.mesh.getOpaqueMesh())) { + components = chunk.mesh.getOpaqueMesh().getComponents(); + } + } + } + } + } + if (null != big) { + big.destroy(); + big = null; + } + if (makeBig) { + big = ImmModeMesh.allocate(vertexTmpCount * components); + big.setGLSL(true); + big.enableVertex3(); + big.enableColor4(); + big.enableTexCoord2(); + big.setServer(true); + big.beginQuads(); + for (distance = 0; distance <= renderDistance / 16; distance++) { + for (Point offset : visibleRanges.get(distance)) { + renderLoc.x = cameraChunk.x + offset.x; + renderLoc.y = cameraChunk.y + offset.y; + renderLoc.z = cameraChunk.z + offset.z; + final Chunk chunk = chunkSlice.getChunk(renderLoc); + if (chunk.inWorldRange()) { + if (chunk.mesh.isValid() && chunk.mesh.isEmpty()) { + + } else { + if (null != chunk.mesh.getOpaqueMesh()) { + big.put(chunk.mesh.getOpaqueMesh()); + } + if (!chunk.mesh.isValid()) { + if (!ChunkMeshBulder.instance.isFull()) { + ChunkMeshBulder.instance.add(chunk); + } + } + } + } + } + } + big.end(); + } + } + + private boolean useShaders = true; + + public ChunkRangeRenderer(BlockSlice slice) { + precalcRange(); + } + + private BlockType blockType = new GrassBlockType(); + + public int testedChunks = 0; + public int testedChunksVertices = 0; + + 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 int visibleBlocks = 0; + public int vertexCount = 0; + + public static int lightTick = 0; + + public static int OPAQUE_PASS = 0; + public static int ALPHA_PASS = 1; + private AABBox box = new AABBox(); + private float d; + final float radius = (float) Math.sqrt(8 * 8 + 8 * 8 + 8 * 8); + final float radius2 = (float) Math.sqrt(0.5 * 0.5 + 0.5 * 0.5 + 0.5 * 0.5); + private float[] center = new float[3]; + + public boolean renderChunk(Chunk chunk, boolean skipnew, int pass) { + testedChunks++; + if (!chunk.inWorldRange()) { + return skipnew; + } + // center[0] = (float) (chunk.getOffset().x + 8); + // center[1] = (float) (chunk.getOffset().y + 8); + // center[2] = (float) (chunk.getOffset().z + 8); + chunk.render(pass); + + vertexCount += chunk.mesh.getVertexCount(); + if (!chunk.mesh.isValid()) { + if (!skipnew) { + ChunkMeshBulder.instance.add(chunk); + if (ChunkMeshBulder.instance.isFull()) { + skipnew = true; + } + } + } + return skipnew; + } + + Chunk lastInvalidChunk = null; + BlockLocation cameraBlock; + ChunkLocation cameraChunk; + int distance; + private int renderDistance; + public ChunkSlice chunkSlice; + + private boolean allChunksRendered = false; + private boolean allChunksValid = false; + private ChunkLocation renderLoc = new ChunkLocation(); + + public void render(int pass) { + final GL2 gl = GLContext.getCurrentGL().getGL2(); + visibleBlocks = 0; + vertexCount = 0; + allChunksRendered = true; + allChunksValid = true; + renderDistance = Game.client.getScene().getPlayer().settings.renderDistance; + if (!ChunkMeshBulder.instance.isAlive() && !ChunkMeshBulder.instance.isInterrupted()) { + ChunkMeshBulder.instance.start(); + } + if (null == chunkSlice) { + ChunkSlice.rendererInstance = chunkSlice = new ChunkSlice(Game.client.getWorldProvider(), 1, 1, 1);// slice.getChunkSlice(); + } + /* + * if (!ChunkMeshGarbageCollector.instance.isAlive() && + * !ChunkMeshGarbageCollector.instance.isInterrupted()) { + * ChunkMeshGarbageCollector.instance.start(); + * } + */ + // chunkSlice = new ChunkSlice(Game.client.getWorldProvider(), 1, 1, 1); + testedChunks = 0; + visibleTop = 0; + visibleBottom = 0; + visibleLeft = 0; + visibleRight = 0; + visibleFront = 0; + visibleBack = 0; + frustumCulledChunks = 0; + + cameraBlock = Game.client.getScene().getPlayer().getCameraBlockLocation(); + cameraChunk = cameraBlock.getChunkLocation(); + + boolean skipnew = false; + if (null != big) { + big.draw(); + } else { + for (distance = 0; distance <= renderDistance / 16; distance++) { + if (distance > 0) { + for (Point offset : visibleRanges.get(distance)) { + renderLoc.x = cameraChunk.x + offset.x; + renderLoc.y = cameraChunk.y + offset.y; + renderLoc.z = cameraChunk.z + offset.z; + skipnew = renderChunk(chunkSlice.getChunk(renderLoc), skipnew, pass); + } + } else { + renderLoc.set(cameraChunk); + skipnew = renderChunk(chunkSlice.getChunk(renderLoc), skipnew, pass); + } + } + } + } +} diff --git a/src/ru/olamedia/olacraft/render/jogl/DefaultRenderer.java b/src/ru/olamedia/olacraft/render/jogl/DefaultRenderer.java index 12c12e0..60475cf 100644 --- a/src/ru/olamedia/olacraft/render/jogl/DefaultRenderer.java +++ b/src/ru/olamedia/olacraft/render/jogl/DefaultRenderer.java @@ -1,6 +1,9 @@ package ru.olamedia.olacraft.render.jogl; +import java.util.Random; + import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.event.MouseEvent; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.glu.GLU; @@ -22,9 +25,14 @@ public class DefaultRenderer implements IRenderer, KeyListener, MouseListener { MouseJail.attach(this); } + private Random rand = new Random(); + @Override public void render(GLAutoDrawable drawable) { + Game.instance.fpsTimer.update(); + // if (rand.nextFloat() > 0.8f) { Game.client.getScene().tick(); + // } Game.client.getScene().render(drawable); } @@ -48,14 +56,6 @@ public class DefaultRenderer implements IRenderer, KeyListener, MouseListener { 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 @@ -64,12 +64,19 @@ public class DefaultRenderer implements IRenderer, KeyListener, MouseListener { } @Override - public void onMouseClick() { - Game.instance.player.onMouseClick(); + public void onMouseClick(MouseEvent e) { + if (null != Game.instance.player) { + Game.instance.player.onMouseClick(e); + } } @Override public void init(GLAutoDrawable drawable) { - + + } + + @Override + public void reshape(GLAutoDrawable drawable) { + Game.client.getScene().reshape(drawable); } } diff --git a/src/ru/olamedia/olacraft/render/jogl/IRenderer.java b/src/ru/olamedia/olacraft/render/jogl/IRenderer.java index 1ba581a..492e046 100644 --- a/src/ru/olamedia/olacraft/render/jogl/IRenderer.java +++ b/src/ru/olamedia/olacraft/render/jogl/IRenderer.java @@ -5,4 +5,5 @@ import javax.media.opengl.GLAutoDrawable; public interface IRenderer { public void render(GLAutoDrawable drawable); public void init(GLAutoDrawable drawable); + public void reshape(GLAutoDrawable drawable); } diff --git a/src/ru/olamedia/olacraft/render/jogl/InventoryRenderer.java b/src/ru/olamedia/olacraft/render/jogl/InventoryRenderer.java index 46daa4a..d2d103b 100644 --- a/src/ru/olamedia/olacraft/render/jogl/InventoryRenderer.java +++ b/src/ru/olamedia/olacraft/render/jogl/InventoryRenderer.java @@ -51,8 +51,8 @@ public class InventoryRenderer { 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 != stack && !(stack.type instanceof EmptyBlockType)) { + Texture tex = TextureManager.get(stack.type.getStackTextureFile()); if (null != tex) { tex.bind(gl); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); diff --git a/src/ru/olamedia/olacraft/render/jogl/joglViewport.java b/src/ru/olamedia/olacraft/render/jogl/joglViewport.java index ef59352..3a62835 100644 --- a/src/ru/olamedia/olacraft/render/jogl/joglViewport.java +++ b/src/ru/olamedia/olacraft/render/jogl/joglViewport.java @@ -8,19 +8,41 @@ import com.jogamp.opengl.util.awt.TextRenderer; public class joglViewport { private GLAutoDrawable drawable; - private TextRenderer sans11; + private TextRenderer sans11Black; + private TextRenderer sans11White; + + // private TextRenderer sans12; public joglViewport(GLAutoDrawable drawable) { this.drawable = drawable; - sans11 = new TextRenderer(new Font("SansSerif", Font.PLAIN, 11)); + //sans11Black = new TextRenderer(new Font("SansSerif", Font.PLAIN, 11)); + //sans11Black.setColor(0, 0, 0, 1f); + sans11White = new TextRenderer(new Font("SansSerif", Font.PLAIN, 11)); + sans11White.setColor(0, 0, 0, 0.9f); + // sans12 = new TextRenderer(new Font("SansSerif", Font.PLAIN, 11)); + } + + public void beginRendering() { + sans11White.beginRendering(drawable.getWidth(), drawable.getHeight()); + //sans11Black.beginRendering(drawable.getWidth(), drawable.getHeight()); + } + + public void endRendering() { + sans11White.flush(); + sans11White.endRendering(); + //sans11Black.endRendering(); } public void drawText(String text, int x, int y) { - sans11.setColor(0, 0, 0, 0.7f); - sans11.beginRendering(drawable.getWidth(), drawable.getHeight()); - sans11.draw(text, x - 1, y - 1); - // sans11.setColor(1, 1, 1, 0.7f); - // sans11.draw(text, x, y); - sans11.endRendering(); + // sans12.beginRendering(drawable.getWidth(), drawable.getHeight()); + // sans12.setColor(1, 1, 1, 0.9f); + // sans12.draw(text, x, y); + // sans12.endRendering(); + //sans11White.draw(text, x - 1, y); + //sans11White.draw(text, x + 1, y); + //sans11White.draw(text, x, y - 1); + //sans11White.draw(text, x, y + 1); + sans11White.draw(text, x, y); + } } diff --git a/src/ru/olamedia/olacraft/scene/GameScene.java b/src/ru/olamedia/olacraft/scene/GameScene.java index e5655c9..c0a3f86 100644 --- a/src/ru/olamedia/olacraft/scene/GameScene.java +++ b/src/ru/olamedia/olacraft/scene/GameScene.java @@ -3,53 +3,83 @@ package ru.olamedia.olacraft.scene; import java.lang.management.ManagementFactory; import java.lang.management.MemoryUsage; import java.util.HashMap; +import java.util.Random; import javax.media.opengl.GL2; +import javax.media.opengl.GL2ES2; import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLContext; import javax.media.opengl.glu.GLU; import javax.media.opengl.glu.GLUquadric; import org.ode4j.ode.DBody; -import ru.olamedia.Options; +import com.jogamp.newt.event.KeyEvent; +import com.jogamp.opengl.util.PMVMatrix; + +import ru.olamedia.game.GameFrame; +import ru.olamedia.game.GameLogicThread; import ru.olamedia.game.GameTime; +import ru.olamedia.geom.ImmModeMesh; +import ru.olamedia.input.KeyListener; +import ru.olamedia.input.Keyboard; import ru.olamedia.liveEntity.LiveEntity; import ru.olamedia.olacraft.game.Game; +import ru.olamedia.olacraft.modelAnimator.Bone; import ru.olamedia.olacraft.physics.GamePhysicsWorld; -import ru.olamedia.olacraft.render.jogl.ChunkRenderer; +import ru.olamedia.olacraft.render.jogl.ChunkRangeRenderer; 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.block.Block; -import ru.olamedia.olacraft.world.blockTypes.AbstractBlockType; -import ru.olamedia.olacraft.world.blockTypes.DirtBlockType; +import ru.olamedia.olacraft.world.blockRenderer.ChunkRenderer; +import ru.olamedia.olacraft.world.blockTypes.BlockType; import ru.olamedia.olacraft.world.blockTypes.GrassBlockType; -import ru.olamedia.olacraft.world.blockTypes.GravelBlockType; -import ru.olamedia.olacraft.world.blockTypes.StoneBlockType; import ru.olamedia.olacraft.world.chunk.BlockSlice; -import ru.olamedia.olacraft.world.chunk.Chunk; -import ru.olamedia.olacraft.world.chunk.ChunkSlice; -import ru.olamedia.olacraft.world.location.BlockLocation; +import ru.olamedia.olacraft.world.chunk.ChunkUnavailableException; import ru.olamedia.olacraft.world.provider.WorldProvider; import ru.olamedia.player.Player; +import ru.olamedia.texture.TextureManager; -public class GameScene { - +public class GameScene implements KeyListener { + private boolean isHUDEnabled = false; + private boolean thirdPersonMode = true; + public boolean boneMode = false; + private boolean renderFrustum = false; private HashMap<Integer, LiveEntity> liveEntities = new HashMap<Integer, LiveEntity>(); WorldProvider provider; - private int renderDistance = Options.renderDistance; - private joglViewport viewport; + public joglViewport viewport; private BulletScene bullets = new BulletScene(); private GamePhysicsWorld physics = new GamePhysicsWorld(); - private boolean isInitialized = false; + public boolean isInitialized = false; BlockSlice viewSlice; - public GameTime time = new GameTime(); + public GameTime dayTime = new GameTime(); + + private ImmModeMesh crosshair; + + public Bone selectedBone = null; + public int bonesCount = 0; + + private BlockType blockType = new GrassBlockType(); public GameScene(WorldProvider provider) { this.provider = provider; - setRenderDistance(renderDistance); + pickSlice = new BlockSlice(provider, 10, 10, 10); + Keyboard.attach(this); + Keyboard.setName("3_left", KeyEvent.VK_NUMPAD4); + Keyboard.setName("3_right", KeyEvent.VK_NUMPAD6); + Keyboard.setName("3_up", KeyEvent.VK_NUMPAD8); + Keyboard.setName("3_down", KeyEvent.VK_NUMPAD2); + Keyboard.setName("3_in", KeyEvent.VK_NUMPAD7); + Keyboard.setName("3_out", KeyEvent.VK_NUMPAD1); + Keyboard.setName("3_mode", KeyEvent.VK_F6); + Keyboard.setName("hud", KeyEvent.VK_F9); + Keyboard.setName("bone_mode", KeyEvent.VK_B); + Keyboard.setName("next", KeyEvent.VK_N); + Keyboard.setName("rotate_cw", KeyEvent.VK_RIGHT); + Keyboard.setName("rotate_ccw", KeyEvent.VK_LEFT); } public void addBullet(Bullet b) { @@ -70,46 +100,51 @@ public class GameScene { return bullets.getCount(); } + public void buildCrosshair() { + final int width = GameFrame.getGLWidth(); + final int height = GameFrame.getGLHeight(); + final int w = 1; + final int l = 5; + crosshair = ImmModeMesh.allocate(8);// 2 rectangles + // crosshair.setServer(true); + // crosshair.setGLSL(true); + crosshair.enableColor4(); + crosshair.enableVertex2(); + crosshair.setColor(0f, 1f, 1f, 0.7f); + crosshair.beginQuads(); + { + crosshair.glRectf(width / 2 - w, height / 2 - l * 2, width / 2 + w, height / 2 + l * 2); // vertical + crosshair.glRectf(width / 2 - l * 2, height / 2 - w, width / 2 - 1, height / 2 + w); // horizontal + crosshair.glRectf(width / 2 + 1, height / 2 - w, width / 2 + l * 2, height / 2 + w); // horizontal + } + crosshair.end(); + } + public void init(GLAutoDrawable drawable) { if (isInitialized) { return; } - isInitialized = true; - time.init(); + final GL2ES2 gl = GLContext.getCurrentGL().getGL2ES2(); + gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_NEAREST); + gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_NEAREST);// _MIPMAP_NEAREST registerTextures(); + gl.glActiveTexture(GL2.GL_TEXTURE1); + gl.glBindTexture(blockType.getTopTexture().getTarget(), blockType.getTopTexture().getTextureObject(gl)); + gl.glActiveTexture(GL2.GL_TEXTURE0); + isInitialized = true; + dayTime.init(); viewport = new joglViewport(drawable); + buildCrosshair(); + GameLogicThread.instance.start(); } private void registerTextures() { - AbstractBlockType t; - t = new GrassBlockType(); - t.register(provider); - t = new StoneBlockType(); - t.register(provider); - t = new DirtBlockType(); - t.register(provider); - t = new GravelBlockType(); - t.register(provider); - } - - /** - * @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, renderDistance); - blockRenderer = new ChunkRenderer(viewSlice); + provider.registerTextures(); + TextureManager.writeSprite("sprite.png"); + TextureManager.finishSprite(); } - public ChunkRenderer blockRenderer = new ChunkRenderer(viewSlice); + public ChunkRangeRenderer blockRenderer = new ChunkRangeRenderer(viewSlice); GLU glu = new GLU(); public void registerLiveEntity(LiveEntity entity) { @@ -120,11 +155,12 @@ public class GameScene { private InventoryRenderer inventoryRenderer; - private Player player; + public Player player; public void registerPlayer(LiveEntity player) { inventoryRenderer = new InventoryRenderer(player.getInventory()); this.player = (Player) player; + // this.player.getInventory().buildMeshes(); } public LiveEntity getLiveEntity(int connectionId) { @@ -139,221 +175,434 @@ public class GameScene { } public Block nearestBlock = null; + public Block nearestPutBlock = null; + public BlockSlice pickSlice; + private Random rand = new Random(); public void tick() { - time.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()); - BlockSlice pickSlice = new BlockSlice(provider, 10, 10, 10); - if (null != player) { - if (player.isOrientationChanged || Game.instance.camera.isOrientationChanged) { - player.isOrientationChanged = false; - Game.instance.camera.isOrientationChanged = false; - pickSlice.setCenter(player.getCameraX(), player.getCameraY(), player.getCameraZ()); - nearestBlock = pickSlice.getNearest(Game.instance.camera); - } + if (rand.nextFloat() > 0.95f) { + final GL2ES2 gl = GLContext.getCurrentGL().getGL2ES2(); + // ChunkRenderer.getShader().enable(); + dayTime.sunColor.put(0, 1); + dayTime.sunColor.put(1, 1); + dayTime.sunColor.put(2, 1); + // ChunkRenderer.getShader().getState().uniform(gl, + // ChunkRenderer.sunColor); + // ChunkRenderer.getShader().disable(); + final float[] clearColor = dayTime.getClearColor(); + // gl.glClearColor(clearColor[0], clearColor[1], clearColor[2], 1); + gl.glClearColor(0.8f, 0.8f, 0.8f, 1); } } + float dLook = 2; + float dUp = 0; + float dRight = 0; + public void render(GLAutoDrawable drawable) { if (null == player || !Game.instance.isRunning()) { // not running, just clear screen - GL2 gl = drawable.getGL().getGL2(); + final 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); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } return; } init(drawable); - float[] clearColor = time.getClearColor(); - GL2 gl = drawable.getGL().getGL2(); + // final float[] clearColor = time.getClearColor(); + final GL2 gl = drawable.getGL().getGL2(); gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT); - gl.glClearColor(clearColor[0], clearColor[1], clearColor[2], 1); + // gl.glClear(GL2.GL_DEPTH_BUFFER_BIT); + // gl.glClearColor(clearColor[0], clearColor[1], clearColor[2], 1); // gl.glClearColor(49f / 255f, 119f / 255f, 243f / 255f, 1); - // GOING 3D - gl.glPushMatrix(); gl.glPushAttrib(GL2.GL_ALL_ATTRIB_BITS); - Game.instance.camera.setUp(drawable); - // RENDER SUN - // gl.glPushAttrib(GL2.GL_ALL_ATTRIB_BITS); - // gl.glEnable(GL2.GL_BLEND); // Enable Blending - // gl.glBlendFunc(GL2.GL_SRC_ALPHA, GL2.GL_ONE); // Set Blending Mode To - // // Mix Based On SRC - // // Alpha - // GLUquadric sun = glu.gluNewQuadric(); - // glu.gluQuadricDrawStyle(sun, GLU.GLU_FILL); - // glu.gluQuadricNormals(sun, GLU.GLU_SMOOTH); + // GOING 3D + if (player.camera.isDirty()) { + player.camera.offset.x = 0; + player.camera.offset.y = 0; + player.camera.offset.z = 0; + player.camera.pack(); + if (thirdPersonMode) { + player.camera.offset.x = player.camera.getLook().x * dLook + player.camera.getUp().x * dUp + + player.camera.getRight().x * dRight; + player.camera.offset.y = player.camera.getLook().y * dLook + player.camera.getUp().y * dUp + + player.camera.getRight().y * dRight; + player.camera.offset.z = player.camera.getLook().z * dLook + player.camera.getUp().z * dUp + + player.camera.getRight().z * dRight; + player.camera.pack(); + player.camera.updateFrustum(); + blockRenderer.updateFrustumCulling(); + } + ChunkRenderer.getShader().enable(); + ChunkRenderer.getShader().getState().uniform(gl, ChunkRenderer.pmvMatrixUniform); + ChunkRenderer.getShader().disable(); + } + player.camera.setUp(); // gl.glPushMatrix(); - // gl.glTranslatef(time.sun.getX() + player.getCameraX(), - // time.sun.getY(), time.sun.getZ() + player.getCameraZ()); - // gl.glPolygonMode(GL2.GL_FRONT_AND_BACK, GL2.GL_FILL); - // gl.glColor4f(1, 1, 1, 0.02f); - // gl.glColor4f((float) 251 / 255, (float) 255 / 255, (float) 228 / 255, - // 0.02f); - // glu.gluSphere(sun, 100f, 10, 10); - // glu.gluSphere(sun, 90f, 10, 10); - // glu.gluSphere(sun, 80f, 10, 10); - // glu.gluSphere(sun, 70f, 10, 10); - // glu.gluSphere(sun, 60f, 10, 10); - // glu.gluSphere(sun, 50f, 10, 10); - // glu.gluSphere(sun, 40f, 10, 10); - // glu.gluSphere(sun, 35f, 10, 10); - // gl.glColor4f(1, 1, 1, 1f); - // glu.gluSphere(sun, 30f, 10, 10); - // gl.glPopMatrix(); - // gl.glPopAttrib(); + // gl.glPushAttrib(GL2.GL_ALL_ATTRIB_BITS); + + // RENDER SUN + /* + * gl.glPushAttrib(GL2.GL_ALL_ATTRIB_BITS); + * gl.glEnable(GL2.GL_BLEND); // Enable Blending + * gl.glBlendFunc(GL2.GL_SRC_ALPHA, GL2.GL_ONE); // Set Blending Mode To + * // Mix Based On SRC + * // Alpha + * GLUquadric sun = glu.gluNewQuadric(); + * glu.gluQuadricDrawStyle(sun, GLU.GLU_FILL); + * glu.gluQuadricNormals(sun, GLU.GLU_SMOOTH); + * gl.glPushMatrix(); + * gl.glTranslatef(time.sun.getX() + player.getCameraX(), + * time.sun.getY(), time.sun.getZ() + player.getCameraZ()); + * gl.glPolygonMode(GL2.GL_FRONT_AND_BACK, GL2.GL_FILL); + * gl.glColor4f(1, 1, 1, 0.02f); + * gl.glColor4f((float) 251 / 255, (float) 255 / 255, (float) 228 / 255, + * 0.02f); + * glu.gluSphere(sun, 100f, 10, 10); + * glu.gluSphere(sun, 90f, 10, 10); + * glu.gluSphere(sun, 80f, 10, 10); + * glu.gluSphere(sun, 70f, 10, 10); + * glu.gluSphere(sun, 60f, 10, 10); + * glu.gluSphere(sun, 50f, 10, 10); + * glu.gluSphere(sun, 40f, 10, 10); + * glu.gluSphere(sun, 35f, 10, 10); + * gl.glColor4f(1, 1, 1, 1f); + * glu.gluSphere(sun, 30f, 10, 10); + * gl.glPopMatrix(); + * gl.glPopAttrib(); + */ - viewSlice.setCenter((int) Game.instance.camera.getX(), (int) Game.instance.camera.getY(), - (int) Game.instance.camera.getZ()); // RENDER BLOCKS - gl.glPopAttrib(); - gl.glPushAttrib(GL2.GL_ALL_ATTRIB_BITS); - gl.glColor4f(0f, 1f, 0, 1); - gl.glEnable(GL2.GL_DEPTH_TEST); + // gl.glColor4f(0f, 1f, 0, 1); gl.glShadeModel(GL2.GL_FLAT); - gl.glCullFace(GL2.GL_BACK); + gl.glEnable(GL2.GL_DEPTH_TEST); + gl.glEnable(GL2.GL_CULL_FACE); + // gl.glColorMask(false, false, false, false); + // gl.glEnable(GL2.GL_TEXTURE_2D); + gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_NEAREST); + gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_NEAREST);// _MIPMAP_NEAREST + ChunkRenderer.enableShader(); + // ChunkRenderer.getShader().getState().uniform(gl, + // ChunkRenderer.sunColor); + gl.glActiveTexture(GL2.GL_TEXTURE1); + // gl.glBindTexture(blockType.getTopTexture().getTarget(), + // blockType.getTopTexture().getTextureObject(gl)); + gl.glDisable(GL2.GL_BLEND); + blockRenderer.render(ChunkRangeRenderer.OPAQUE_PASS); + gl.glDisable(GL2.GL_BLEND); + // gl.glEnable(GL2.GL_BLEND); + // gl.glBlendFunc(GL2.GL_SRC_ALPHA, GL2.GL_ONE_MINUS_SRC_ALPHA); + // gl.glBlendEquationSeparate(GL2.GL_FUNC_ADD, GL2.GL_FUNC_ADD); // copy + // blockRenderer.render(ChunkRangeRenderer.ALPHA_PASS); + // gl.glDisable(GL2.GL_TEXTURE_2D); + gl.glDisable(GL2.GL_CULL_FACE); + gl.glDisable(GL2.GL_DEPTH_TEST); + gl.glDisable(GL2.GL_BLEND); + // gl.glDisable(GL2.GL_ALPHA_TEST); + ChunkRenderer.disableShader(); + gl.glActiveTexture(GL2.GL_TEXTURE0); + // gl.glPushAttrib(GL2.GL_ALL_ATTRIB_BITS); + // 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_START, player.settings.renderDistance / 2 - + // player.settings.renderDistance / 10); + // gl.glFogf(GL2.GL_FOG_END, player.settings.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(); - gl.glPopAttrib(); + // 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()); - gl.glPolygonMode(GL2.GL_FRONT_AND_BACK, GL2.GL_LINE); - glu.gluSphere(qobj0, 0.1f, 10, 10); - gl.glPopMatrix(); - } - gl.glPopAttrib(); + /* + * 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()); + * gl.glPolygonMode(GL2.GL_FRONT_AND_BACK, GL2.GL_LINE); + * glu.gluSphere(qobj0, 0.03f, 10, 10); + * gl.glPopMatrix(); + * } + * gl.glPopAttrib(); + */ if (nearestBlock != null) { gl.glPushAttrib(GL2.GL_ALL_ATTRIB_BITS); - nearestBlock.renderFrame(); + if (nearestBlock != null) { + nearestBlock.renderFrame(); + } gl.glPopAttrib(); } + if (thirdPersonMode && renderFrustum) { + player.camera.renderFrustum(); + } // bullets.render(drawable); - gl.glPopMatrix(); + // gl.glPushAttrib(GL2.GL_ALL_ATTRIB_BITS); + // player.render(); + // gl.glPopAttrib(); + // gl.glPopMatrix(); // testObject.render(); - + gl.glPopAttrib(); // 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); - } + if (isHUDEnabled) { + gl.glMatrixMode(GL2.GL_PROJECTION); + gl.glLoadIdentity(); + final int width = GameFrame.getGLWidth(); + final int height = GameFrame.getGLHeight(); + glu.gluOrtho2D(0, width, height, 0); + gl.glMatrixMode(GL2.GL_MODELVIEW); + gl.glPushAttrib(GL2.GL_ALL_ATTRIB_BITS); + // 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); + + // MAP-- + // crosshair + if (null != crosshair) { + gl.glDisable(GL2.GL_TEXTURE_2D); + gl.glDisable(GL2.GL_CULL_FACE); + gl.glDisable(GL2.GL_DEPTH_TEST); + gl.glDisable(GL2.GL_BLEND); + gl.glBindTexture(GL2.GL_TEXTURE_2D, 0); + gl.glEnable(GL2.GL_BLEND); + gl.glBlendFunc(GL2.GL_ONE, GL2.GL_ONE); + gl.glBlendEquation(GL2.GL_FUNC_SUBTRACT); + // ChunkRenderer.enableShader(); + crosshair.draw(); + // ChunkRenderer.disableShader(); + gl.glBlendEquation(GL2.GL_FUNC_ADD); + gl.glDisable(GL2.GL_BLEND); + } else { + System.err.println("no 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 + // TODO ENABLE + // inventory + // player.getInventory().renderGUI(); + // inventoryprivate PMVMatrix matrix; + // if (null != inventoryRenderer) { + // // inventoryRenderer.render(drawable); + // } + gl.glPushAttrib(GL2.GL_ALL_ATTRIB_BITS); + viewport.beginRendering(); + gl.glEnable(GL2.GL_BLEND); + // gl.glBlendColor(0, 0, 0, 1); + gl.glBlendFunc(GL2.GL_ZERO, GL2.GL_ONE_MINUS_SRC_ALPHA); + //gl.glBlendFuncSeparate(GL2.GL_DST_COLOR, GL2.GL_ONE_MINUS_SRC_ALPHA, GL2.GL_SRC_ALPHA, + // GL2.GL_ONE_MINUS_DST_COLOR); + gl.glBlendEquation(GL2.GL_FUNC_ADD); + viewport.drawText("⌀ " + player.settings.renderDistance, 10, height - 20); + viewport.drawText("avg fps: " + (int) Game.fpsTimer.getAvgFps(), 10, height - 35); + viewport.drawText("fps: " + (int) Game.fpsTimer.getFps(), 10, height - 50); + final MemoryUsage heap = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); + final MemoryUsage nonheap = ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage(); + viewport.drawText("heap: " + (heap.getUsed() / (1024 * 1024)) + "/" + (heap.getMax() / (1024 * 1024)), 10, + height - 65); + viewport.drawText("non heap: " + (nonheap.getUsed() / (1024 * 1024)) + "/" + + (nonheap.getMax() / (1024 * 1024)), 10, height - 80); + // viewport.drawText("b: " + blockRenderer.visibleBlocks, 10, height + // - + // 80); + if (null != blockRenderer.big) { + viewport.drawText("v: " + blockRenderer.big.getVertexCount(), 10, height - 95); + } + viewport.drawText("c: " + blockRenderer.testedChunks, 10, height - 105); + // + viewport.drawText("y: " + Game.instance.player.getY(), width - 100 - 10, height - 100 - 20); + viewport.drawText("y: " + Game.instance.player.getCameraY() + " (cam)", width - 100 - 10, height - 100 - 30); + viewport.drawText("x: " + Game.instance.player.getX(), width - 100 - 10, height - 100 - 40); + viewport.drawText("z: " + Game.instance.player.getZ(), width - 100 - 10, height - 100 - 50); + if (boneMode) { + viewport.drawText("bones count: " + bonesCount, width - 100 - 10, height - 100 - 80); + } + if (boneMode && null != selectedBone) { + viewport.drawText("bone: " + selectedBone.getName(), width - 100 - 10, height - 100 - 90); + viewport.drawText("pitch: " + selectedBone.getPitch(), width - 100 - 10, height - 100 - 100); + viewport.drawText("__yaw: " + selectedBone.getYaw(), width - 100 - 10, height - 100 - 110); + viewport.drawText("_roll: " + selectedBone.getRoll(), width - 100 - 10, height - 100 - 120); + } + viewport.endRendering(); + gl.glDisable(GL2.GL_BLEND); + gl.glBlendEquation(GL2.GL_FUNC_ADD); + gl.glBlendColor(0, 0, 0, 0); + gl.glPopAttrib(); - viewport.drawText("rad: " + Options.renderDistance, 10, height - 20); - viewport.drawText("avg fps: " + (int) Game.timer.getAvgFps(), 10, height - 35); - viewport.drawText("fps: " + (int) Game.timer.getFps(), 10, height - 50); - MemoryUsage heap = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); - viewport.drawText("mem: " + (heap.getUsed() / (1024 * 1024)) + "/" + (heap.getMax() / (1024 * 1024)), 10, - height - 65); - // - // viewport.drawText("y: " + Game.instance.player.getY(), width - msz - - // 10, height - msz - 20); - // viewport.drawText("y: " + Game.instance.player.getCameraY() + - // " (cam)", width - msz - 10, height - msz - 30); - // 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 - 50); - // viewport.drawText("players: " + liveEntities.size(), width - msz - - // 10, height - msz - 70); - // viewport.drawText("bullets: " + getBulletsCount(), width - msz - 10, - // height - msz - 95); - // viewport.drawText("y velocity: " + player.velocity.y + " y accel: " + - // player.acceleration.y + " inJump: " - // + player.inJump + " onGround: " + player.onGround, width - msz - 350 - // - 10, height - msz - 110); - // viewport.drawText("rdistance: " + Options.renderDistance, width - msz - // - 10, height - msz - 155); - - // ChunkSlice cs = viewSlice.getChunkSlice(); - // viewport.drawText("slice x: " + cs.getX() + ".." + (cs.getX() + - // cs.getWidth() - 1) + " y: " + cs.getY() + ".." - // + (cs.getY() + cs.getHeight() - 1) + " z: " + cs.getZ() + ".." + - // (cs.getZ() + cs.getDepth() - 1), width - // - msz * 2 - 10, height - msz - 170); - // viewport.drawText("time: " + time.getDateTimeString(), width - msz * - // 2 - 10, height - msz - 185); - // if (nearestBlock != null) { - // viewport.drawText("pick: " + nearestBlock.getX() + "," + - // nearestBlock.getY() + "," + nearestBlock.getZ() - // + " d " + nearestBlock.getDistance(Game.instance.camera), width - msz - // * 2 - 10, height - msz - 200); - // viewport.drawText( - // "edge: " + nearestBlock.location.isChunkEdge() + " left " + - // nearestBlock.location.isChunkLeftEdge(), - // width - msz * 2 - 10, height - msz - 210); - // } - - // BlockLocation camloc = player.getCameraBlockLocation(); - // viewport.drawText("cam chunk: " + camloc.getChunkLocation(), width - - // 200 - msz * 2 - 10, height - msz - 225); - // Chunk camc = - // viewSlice.getChunkSlice().getChunk(camloc.getChunkLocation()); - // viewport.drawText("cam chunk: " + camc.isMeshCostructed + " mesh: " + - // camc.mesh, width - 200 - msz * 2 - 10, - // height - msz - 235); - // viewport.drawText( - // "chunk available: " + camc.isAvailable() + " chunk empty: " - // + (camc.isAvailable() ? camc.isEmpty() : "unknown"), width - 200 - - // msz * 2 - 10, height - msz - // - 245); + // viewport.drawText("players: " + liveEntities.size(), width - msz + // - + // 10, height - msz - 70); + // viewport.drawText("bullets: " + getBulletsCount(), width - msz - + // 10, + // height - msz - 95); + // viewport.drawText("y velocity: " + player.velocity.y + + // " y accel: " + + // player.acceleration.y + " inJump: " + // + player.inJump + " onGround: " + player.onGround, width - msz - + // 350 + // - 10, height - msz - 110); + // viewport.drawText("rdistance: " + Options.renderDistance, width - + // msz + // - 10, height - msz - 155); + + // ChunkSlice cs = viewSlice.getChunkSlice(); + // viewport.drawText("slice x: " + cs.getX() + ".." + (cs.getX() + + // cs.getWidth() - 1) + " y: " + cs.getY() + ".." + // + (cs.getY() + cs.getHeight() - 1) + " z: " + cs.getZ() + ".." + + // (cs.getZ() + cs.getDepth() - 1), width + // - msz * 2 - 10, height - msz - 170); + // viewport.drawText("time: " + time.getDateTimeString(), width - + // msz * + // 2 - 10, height - msz - 185); + // if (nearestBlock != null) { + // viewport.drawText("pick: " + nearestBlock.getX() + "," + + // nearestBlock.getY() + "," + nearestBlock.getZ() + // + " d " + nearestBlock.getDistance(Game.instance.camera), width - + // msz + // * 2 - 10, height - msz - 200); + // viewport.drawText( + // "edge: " + nearestBlock.location.isChunkEdge() + " left " + + // nearestBlock.location.isChunkLeftEdge(), + // width - msz * 2 - 10, height - msz - 210); + // } + + // BlockLocation camloc = player.getCameraBlockLocation(); + // viewport.drawText("cam chunk: " + camloc.getChunkLocation(), + // width - + // 200 - msz * 2 - 10, height - msz - 225); + // Chunk camc = + // viewSlice.getChunkSlice().getChunk(camloc.getChunkLocation()); + // viewport.drawText("cam chunk: " + camc.isMeshCostructed + + // " mesh: " + + // camc.mesh, width - 200 - msz * 2 - 10, + // height - msz - 235); + // viewport.drawText( + // "chunk available: " + camc.isAvailable() + " chunk empty: " + // + (camc.isAvailable() ? camc.isEmpty() : "unknown"), width - 200 + // - + // msz * 2 - 10, height - msz + // - 245); + + // gl.glPopAttrib(); + // gl.glPopMatrix(); + // gl.glFlush(); + disposeMeshes(); + gl.glPopAttrib(); + } + } - gl.glPopAttrib(); - gl.glPopMatrix(); - // gl.glFlush(); + public void disposeMeshes() { + // blockRenderer.chunkSlice.disposeMeshes(); } public Player getPlayer() { return player; } + + public PMVMatrix getPmvMatrix() { + return Game.instance.camera.pmvMatrix; + } + + public void reshape(GLAutoDrawable drawable) { + buildCrosshair(); + if (null != player) { + // player.getInventory().buildMeshes(); + } + } + + @Override + public void onKeyPressed(String name, KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_F6) { + thirdPersonMode = !thirdPersonMode; + } + if (e.getKeyCode() == KeyEvent.VK_B) { + boneMode = !boneMode; + } + final boolean thirdPersonControlsEnabled = thirdPersonMode && !boneMode; + if (thirdPersonControlsEnabled) { + final int shiftSpeed = 10; + if (e.getKeyCode() == KeyEvent.VK_NUMPAD4) { + dRight += -0.1 * shiftSpeed; + } + if (e.getKeyCode() == KeyEvent.VK_NUMPAD6) { + dRight += 0.1 * shiftSpeed; + } + if (e.getKeyCode() == KeyEvent.VK_NUMPAD8) { + dUp += 0.1 * shiftSpeed; + } + if (e.getKeyCode() == KeyEvent.VK_NUMPAD2) { + dUp += -0.1 * shiftSpeed; + } + if (e.getKeyCode() == KeyEvent.VK_NUMPAD1) { + dLook += 0.1 * shiftSpeed; + } + if (e.getKeyCode() == KeyEvent.VK_NUMPAD7) { + dLook += -0.1 * shiftSpeed; + } + } + if (boneMode && null != selectedBone) { + if (e.getKeyCode() == KeyEvent.VK_RIGHT) { + player.rotateCW(); + } + if (e.getKeyCode() == KeyEvent.VK_LEFT) { + player.rotateCCW(); + } + if (e.getKeyCode() == KeyEvent.VK_NUMPAD4) { + selectedBone.setRoll(selectedBone.getRoll() + 1); + } + if (e.getKeyCode() == KeyEvent.VK_NUMPAD6) { + selectedBone.setRoll(selectedBone.getRoll() - 1); + } + if (e.getKeyCode() == KeyEvent.VK_NUMPAD8) { + selectedBone.setPitch(selectedBone.getPitch() + 1); + } + if (e.getKeyCode() == KeyEvent.VK_NUMPAD2) { + selectedBone.setPitch(selectedBone.getPitch() - 1); + } + if (e.getKeyCode() == KeyEvent.VK_NUMPAD1) { + selectedBone.setYaw(selectedBone.getYaw() + 1); + } + if (e.getKeyCode() == KeyEvent.VK_NUMPAD7) { + selectedBone.setYaw(selectedBone.getYaw() - 1); + } + if (e.getKeyCode() == KeyEvent.VK_N) { + player.selectNextBone(); + } + } + if (e.getKeyCode() == KeyEvent.VK_F7) { + renderFrustum = !renderFrustum; + } + if (e.getKeyCode() == KeyEvent.VK_F9) { + isHUDEnabled = !isHUDEnabled; + } + if (null != player) { + player.camera.setDirty(); + } + } + + @Override + public void onKeyReleased(String name, KeyEvent e) { + + } } diff --git a/src/ru/olamedia/olacraft/world/biome/Biome.java b/src/ru/olamedia/olacraft/world/biome/Biome.java new file mode 100644 index 0000000..178e799 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/biome/Biome.java @@ -0,0 +1,10 @@ +package ru.olamedia.olacraft.world.biome; + +public class Biome { + public static int ocean = 1; + public static int land = 2; + public static int island = 3; + public static int beach = 4; + public static int desert = 5; + public static int snow = 5; +} diff --git a/src/ru/olamedia/olacraft/world/biome/package-info.java b/src/ru/olamedia/olacraft/world/biome/package-info.java new file mode 100644 index 0000000..b39342c --- /dev/null +++ b/src/ru/olamedia/olacraft/world/biome/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.biome;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/block/Block.java b/src/ru/olamedia/olacraft/world/block/Block.java index 50752f0..1e7175f 100644 --- a/src/ru/olamedia/olacraft/world/block/Block.java +++ b/src/ru/olamedia/olacraft/world/block/Block.java @@ -1,7 +1,6 @@ package ru.olamedia.olacraft.world.block; import javax.media.opengl.GL2; -import javax.media.opengl.GL2ES2; import javax.media.opengl.GLContext; import javax.vecmath.Vector3f; @@ -22,35 +21,16 @@ public class Block { public void removeFromWorld() { ChunkData cdata = provider.getChunk(location.getChunkLocation()); cdata.setEmpty(location, true); - Chunk chunk = Game.client.getScene().blockRenderer.chunkSlice.getChunk(location.getChunkLocation()); - chunk.invalidate(); - if (location.isChunkEdge()) { - if (location.isChunkBackEdge()) { - Chunk neighbor = Game.client.getScene().blockRenderer.chunkSlice.getChunk(location.getChunkLocation() - .getBack()); - neighbor.invalidate(); - } else if (location.isChunkFrontEdge()) { - Chunk neighbor = Game.client.getScene().blockRenderer.chunkSlice.getChunk(location.getChunkLocation() - .getFront()); - neighbor.invalidate(); - } else if (location.isChunkLeftEdge()) { - Chunk neighbor = Game.client.getScene().blockRenderer.chunkSlice.getChunk(location.getChunkLocation() - .getLeft()); - neighbor.invalidate(); - } else if (location.isChunkRightEdge()) { - Chunk neighbor = Game.client.getScene().blockRenderer.chunkSlice.getChunk(location.getChunkLocation() - .getRight()); - neighbor.invalidate(); - } else if (location.isChunkTopEdge()) { - Chunk neighbor = Game.client.getScene().blockRenderer.chunkSlice.getChunk(location.getChunkLocation() - .getTop()); - neighbor.invalidate(); - } else if (location.isChunkBottomEdge()) { - Chunk neighbor = Game.client.getScene().blockRenderer.chunkSlice.getChunk(location.getChunkLocation() - .getBottom()); - neighbor.invalidate(); - } - } + cdata.voidLightPrecomputed = false; + invalidateChunks(); + } + + public void insertToWorld() { + ChunkData cdata = provider.getChunk(location.getChunkLocation()); + cdata.setEmpty(location, false); + cdata.types[ChunkData.ClampID(location.x, location.y, location.z)] = (byte) type.getId(provider); + cdata.voidLightPrecomputed = false; + invalidateChunks(); } /** @@ -63,7 +43,7 @@ public class Block { location.z = 0; } - public void putIntoWorld(WorldProvider worldProvider, int x, int y, int z) { + public void setLocation(WorldProvider worldProvider, int x, int y, int z) { this.provider = worldProvider; location.x = x; location.y = y; @@ -71,7 +51,11 @@ public class Block { } public Block(WorldProvider worldProvider, int x, int y, int z) { - putIntoWorld(worldProvider, x, y, z); + setLocation(worldProvider, x, y, z); + } + + public Block(WorldProvider worldProvider, BlockLocation location) { + setLocation(worldProvider, location.x, location.y, location.z); } /** @@ -152,8 +136,14 @@ public class Block { return type; } + public int nearestX = 0; + public int nearestY = 0; + public int nearestZ = 0; + public float getDistance(MatrixCamera cam) { - String nearest = ""; + nearestX = 0; + nearestY = 0; + nearestZ = 0; float topDistance = cam.intersectsRectangle(getTopLeftBack(), getTopLeftFront(), getTopRightFront(), getTopRightBack()); float bottomDistance = cam.intersectsRectangle(getBottomLeftBack(), getBottomLeftFront(), @@ -171,22 +161,17 @@ public class Block { float frontBack = Math.min(frontDistance, backDistance); float distance = Math.min(Math.min(topBottom, leftRight), frontBack); if (distance == bottomDistance) { - nearest = "BOTTOM"; - } - if (distance == topDistance) { - nearest = "TOP"; - } - if (distance == leftDistance) { - nearest = "LEFT"; - } - if (distance == rightDistance) { - nearest = "RIGHT"; - } - if (distance == frontDistance) { - nearest = "FRONT"; - } - if (distance == backDistance) { - nearest = "BACK"; + nearestY = -1; + } else if (distance == topDistance) { + nearestY = 1; + } else if (distance == leftDistance) { + nearestX = -1; + } else if (distance == rightDistance) { + nearestX = 1; + } else if (distance == frontDistance) { + nearestZ = 1; + } else if (distance == backDistance) { + nearestZ = -1; } return distance; } @@ -243,127 +228,176 @@ public class Block { gl.glBegin(GL2.GL_QUADS); { gl.glColor4f(0, 0, 0, 0.8f); - // top: right - gl.glVertex3f(location.x + min, location.y + min, location.z + min); - gl.glVertex3f(location.x + min, location.y + min, location.z - min); - gl.glVertex3f(location.x + max, location.y + min, location.z - min); - gl.glVertex3f(location.x + max, location.y + min, location.z + min); - // top: left - gl.glVertex3f(location.x - min, location.y + min, location.z + min); - gl.glVertex3f(location.x - min, location.y + min, location.z - min); - gl.glVertex3f(location.x - max, location.y + min, location.z - min); - gl.glVertex3f(location.x - max, location.y + min, location.z + min); - // top: back - gl.glVertex3f(location.x + min, location.y + min, location.z - min); - gl.glVertex3f(location.x - min, location.y + min, location.z - min); - gl.glVertex3f(location.x - min, location.y + min, location.z - max); - gl.glVertex3f(location.x + min, location.y + min, location.z - max); - // top: front - gl.glVertex3f(location.x + min, location.y + min, location.z + min); - gl.glVertex3f(location.x - min, location.y + min, location.z + min); - gl.glVertex3f(location.x - min, location.y + min, location.z + max); - gl.glVertex3f(location.x + min, location.y + min, location.z + max); - // bottom: right - gl.glVertex3f(location.x + min, location.y - min, location.z + min); - gl.glVertex3f(location.x + min, location.y - min, location.z - min); - gl.glVertex3f(location.x + max, location.y - min, location.z - min); - gl.glVertex3f(location.x + max, location.y - min, location.z + min); - // bottom: left - gl.glVertex3f(location.x - min, location.y - min, location.z + min); - gl.glVertex3f(location.x - min, location.y - min, location.z - min); - gl.glVertex3f(location.x - max, location.y - min, location.z - min); - gl.glVertex3f(location.x - max, location.y - min, location.z + min); - // bottom: back - gl.glVertex3f(location.x + min, location.y - min, location.z - min); - gl.glVertex3f(location.x - min, location.y - min, location.z - min); - gl.glVertex3f(location.x - min, location.y - min, location.z - max); - gl.glVertex3f(location.x + min, location.y - min, location.z - max); - // bottom: front - gl.glVertex3f(location.x + min, location.y - min, location.z + min); - gl.glVertex3f(location.x - min, location.y - min, location.z + min); - gl.glVertex3f(location.x - min, location.y - min, location.z + max); - gl.glVertex3f(location.x + min, location.y - min, location.z + max); - // front: right - gl.glVertex3f(location.x + min, location.y + min, location.z + min); - gl.glVertex3f(location.x + min, location.y - min, location.z + min); - gl.glVertex3f(location.x + max, location.y - min, location.z + min); - gl.glVertex3f(location.x + max, location.y + min, location.z + min); - // front: left - gl.glVertex3f(location.x - min, location.y + min, location.z + min); - gl.glVertex3f(location.x - min, location.y - min, location.z + min); - gl.glVertex3f(location.x - max, location.y - min, location.z + min); - gl.glVertex3f(location.x - max, location.y + min, location.z + min); - // front: bottom - gl.glVertex3f(location.x + min, location.y - min, location.z + min); - gl.glVertex3f(location.x - min, location.y - min, location.z + min); - gl.glVertex3f(location.x - min, location.y - max, location.z + min); - gl.glVertex3f(location.x + min, location.y - max, location.z + min); - // front: top - gl.glVertex3f(location.x + min, location.y + min, location.z + min); - gl.glVertex3f(location.x - min, location.y + min, location.z + min); - gl.glVertex3f(location.x - min, location.y + max, location.z + min); - gl.glVertex3f(location.x + min, location.y + max, location.z + min); - // back: right - gl.glVertex3f(location.x + min, location.y + min, location.z - min); - gl.glVertex3f(location.x + min, location.y - min, location.z - min); - gl.glVertex3f(location.x + max, location.y - min, location.z - min); - gl.glVertex3f(location.x + max, location.y + min, location.z - min); - // back: left - gl.glVertex3f(location.x - min, location.y + min, location.z - min); - gl.glVertex3f(location.x - min, location.y - min, location.z - min); - gl.glVertex3f(location.x - max, location.y - min, location.z - min); - gl.glVertex3f(location.x - max, location.y + min, location.z - min); - // back: bottom - gl.glVertex3f(location.x + min, location.y - min, location.z + min); - gl.glVertex3f(location.x - min, location.y - min, location.z + min); - gl.glVertex3f(location.x - min, location.y - max, location.z + min); - gl.glVertex3f(location.x + min, location.y - max, location.z + min); - // back: top - gl.glVertex3f(location.x + min, location.y + min, location.z + min); - gl.glVertex3f(location.x - min, location.y + min, location.z + min); - gl.glVertex3f(location.x - min, location.y + max, location.z + min); - gl.glVertex3f(location.x + min, location.y + max, location.z + min); - // left: back - gl.glVertex3f(location.x - min, location.y + min, location.z - min); - gl.glVertex3f(location.x - min, location.y - min, location.z - min); - gl.glVertex3f(location.x - min, location.y - min, location.z - max); - gl.glVertex3f(location.x - min, location.y + min, location.z - max); - // left: front - gl.glVertex3f(location.x - min, location.y + min, location.z + min); - gl.glVertex3f(location.x - min, location.y - min, location.z + min); - gl.glVertex3f(location.x - min, location.y - min, location.z + max); - gl.glVertex3f(location.x - min, location.y + min, location.z + max); - // left: top - gl.glVertex3f(location.x - min, location.y + min, location.z + min); - gl.glVertex3f(location.x - min, location.y + min, location.z - min); - gl.glVertex3f(location.x - min, location.y + max, location.z - min); - gl.glVertex3f(location.x - min, location.y + max, location.z + min); - // left: bottom - gl.glVertex3f(location.x - min, location.y - min, location.z + min); - gl.glVertex3f(location.x - min, location.y - min, location.z - min); - gl.glVertex3f(location.x - min, location.y - max, location.z - min); - gl.glVertex3f(location.x - min, location.y - max, location.z + min); - // right: back - gl.glVertex3f(location.x + min, location.y + min, location.z - min); - gl.glVertex3f(location.x + min, location.y - min, location.z - min); - gl.glVertex3f(location.x + min, location.y - min, location.z - max); - gl.glVertex3f(location.x + min, location.y + min, location.z - max); - // right: front - gl.glVertex3f(location.x + min, location.y + min, location.z + min); - gl.glVertex3f(location.x + min, location.y - min, location.z + min); - gl.glVertex3f(location.x + min, location.y - min, location.z + max); - gl.glVertex3f(location.x + min, location.y + min, location.z + max); - // right: top - gl.glVertex3f(location.x + min, location.y + min, location.z + min); - gl.glVertex3f(location.x + min, location.y + min, location.z - min); - gl.glVertex3f(location.x + min, location.y + max, location.z - min); - gl.glVertex3f(location.x + min, location.y + max, location.z + min); - // right: bottom - gl.glVertex3f(location.x + min, location.y - min, location.z + min); - gl.glVertex3f(location.x + min, location.y - min, location.z - min); - gl.glVertex3f(location.x + min, location.y - max, location.z - min); - gl.glVertex3f(location.x + min, location.y - max, location.z + min); + if (nearestY == 1) { + // top: right + gl.glVertex3f(location.x + min, location.y + min, location.z + min); + gl.glVertex3f(location.x + min, location.y + min, location.z - min); + gl.glVertex3f(location.x + max, location.y + min, location.z - min); + gl.glVertex3f(location.x + max, location.y + min, location.z + min); + // top: left + gl.glVertex3f(location.x - min, location.y + min, location.z + min); + gl.glVertex3f(location.x - min, location.y + min, location.z - min); + gl.glVertex3f(location.x - max, location.y + min, location.z - min); + gl.glVertex3f(location.x - max, location.y + min, location.z + min); + // top: back + gl.glVertex3f(location.x + min, location.y + min, location.z - min); + gl.glVertex3f(location.x - min, location.y + min, location.z - min); + gl.glVertex3f(location.x - min, location.y + min, location.z - max); + gl.glVertex3f(location.x + min, location.y + min, location.z - max); + // top: front + gl.glVertex3f(location.x + min, location.y + min, location.z + min); + gl.glVertex3f(location.x - min, location.y + min, location.z + min); + gl.glVertex3f(location.x - min, location.y + min, location.z + max); + gl.glVertex3f(location.x + min, location.y + min, location.z + max); + } + if (nearestY == -1) { + // bottom: right + gl.glVertex3f(location.x + min, location.y - min, location.z + min); + gl.glVertex3f(location.x + min, location.y - min, location.z - min); + gl.glVertex3f(location.x + max, location.y - min, location.z - min); + gl.glVertex3f(location.x + max, location.y - min, location.z + min); + // bottom: left + gl.glVertex3f(location.x - min, location.y - min, location.z + min); + gl.glVertex3f(location.x - min, location.y - min, location.z - min); + gl.glVertex3f(location.x - max, location.y - min, location.z - min); + gl.glVertex3f(location.x - max, location.y - min, location.z + min); + // bottom: back + gl.glVertex3f(location.x + min, location.y - min, location.z - min); + gl.glVertex3f(location.x - min, location.y - min, location.z - min); + gl.glVertex3f(location.x - min, location.y - min, location.z - max); + gl.glVertex3f(location.x + min, location.y - min, location.z - max); + // bottom: front + gl.glVertex3f(location.x + min, location.y - min, location.z + min); + gl.glVertex3f(location.x - min, location.y - min, location.z + min); + gl.glVertex3f(location.x - min, location.y - min, location.z + max); + gl.glVertex3f(location.x + min, location.y - min, location.z + max); + } + if (nearestZ == 1) { + // front: right + gl.glVertex3f(location.x + min, location.y + min, location.z + min); + gl.glVertex3f(location.x + min, location.y - min, location.z + min); + gl.glVertex3f(location.x + max, location.y - min, location.z + min); + gl.glVertex3f(location.x + max, location.y + min, location.z + min); + // front: left + gl.glVertex3f(location.x - min, location.y + min, location.z + min); + gl.glVertex3f(location.x - min, location.y - min, location.z + min); + gl.glVertex3f(location.x - max, location.y - min, location.z + min); + gl.glVertex3f(location.x - max, location.y + min, location.z + min); + // front: bottom + gl.glVertex3f(location.x + min, location.y - min, location.z + min); + gl.glVertex3f(location.x - min, location.y - min, location.z + min); + gl.glVertex3f(location.x - min, location.y - max, location.z + min); + gl.glVertex3f(location.x + min, location.y - max, location.z + min); + // front: top + gl.glVertex3f(location.x + min, location.y + min, location.z + min); + gl.glVertex3f(location.x - min, location.y + min, location.z + min); + gl.glVertex3f(location.x - min, location.y + max, location.z + min); + gl.glVertex3f(location.x + min, location.y + max, location.z + min); + } + if (nearestZ == -1) { + // back: right + gl.glVertex3f(location.x + min, location.y + min, location.z - min); + gl.glVertex3f(location.x + min, location.y - min, location.z - min); + gl.glVertex3f(location.x + max, location.y - min, location.z - min); + gl.glVertex3f(location.x + max, location.y + min, location.z - min); + // back: left + gl.glVertex3f(location.x - min, location.y + min, location.z - min); + gl.glVertex3f(location.x - min, location.y - min, location.z - min); + gl.glVertex3f(location.x - max, location.y - min, location.z - min); + gl.glVertex3f(location.x - max, location.y + min, location.z - min); + // back: bottom + gl.glVertex3f(location.x + min, location.y - min, location.z - min); + gl.glVertex3f(location.x - min, location.y - min, location.z - min); + gl.glVertex3f(location.x - min, location.y - max, location.z - min); + gl.glVertex3f(location.x + min, location.y - max, location.z - min); + // back: top + gl.glVertex3f(location.x + min, location.y + min, location.z - min); + gl.glVertex3f(location.x - min, location.y + min, location.z - min); + gl.glVertex3f(location.x - min, location.y + max, location.z - min); + gl.glVertex3f(location.x + min, location.y + max, location.z - min); + } + if (nearestX == -1) { + // left: back + gl.glVertex3f(location.x - min, location.y + min, location.z - min); + gl.glVertex3f(location.x - min, location.y - min, location.z - min); + gl.glVertex3f(location.x - min, location.y - min, location.z - max); + gl.glVertex3f(location.x - min, location.y + min, location.z - max); + // left: front + gl.glVertex3f(location.x - min, location.y + min, location.z + min); + gl.glVertex3f(location.x - min, location.y - min, location.z + min); + gl.glVertex3f(location.x - min, location.y - min, location.z + max); + gl.glVertex3f(location.x - min, location.y + min, location.z + max); + // left: top + gl.glVertex3f(location.x - min, location.y + min, location.z + min); + gl.glVertex3f(location.x - min, location.y + min, location.z - min); + gl.glVertex3f(location.x - min, location.y + max, location.z - min); + gl.glVertex3f(location.x - min, location.y + max, location.z + min); + // left: bottom + gl.glVertex3f(location.x - min, location.y - min, location.z + min); + gl.glVertex3f(location.x - min, location.y - min, location.z - min); + gl.glVertex3f(location.x - min, location.y - max, location.z - min); + gl.glVertex3f(location.x - min, location.y - max, location.z + min); + } + if (nearestX == 1) { + // right: back + gl.glVertex3f(location.x + min, location.y + min, location.z - min); + gl.glVertex3f(location.x + min, location.y - min, location.z - min); + gl.glVertex3f(location.x + min, location.y - min, location.z - max); + gl.glVertex3f(location.x + min, location.y + min, location.z - max); + // right: front + gl.glVertex3f(location.x + min, location.y + min, location.z + min); + gl.glVertex3f(location.x + min, location.y - min, location.z + min); + gl.glVertex3f(location.x + min, location.y - min, location.z + max); + gl.glVertex3f(location.x + min, location.y + min, location.z + max); + // right: top + gl.glVertex3f(location.x + min, location.y + min, location.z + min); + gl.glVertex3f(location.x + min, location.y + min, location.z - min); + gl.glVertex3f(location.x + min, location.y + max, location.z - min); + gl.glVertex3f(location.x + min, location.y + max, location.z + min); + // right: bottom + gl.glVertex3f(location.x + min, location.y - min, location.z + min); + gl.glVertex3f(location.x + min, location.y - min, location.z - min); + gl.glVertex3f(location.x + min, location.y - max, location.z - min); + gl.glVertex3f(location.x + min, location.y - max, location.z + min); + } } gl.glEnd(); } + + public void invalidateChunks() { + // TODO Auto-generated method stub + Chunk chunk = Game.client.getScene().blockRenderer.chunkSlice.getChunk(location.getChunkLocation()); + chunk.invalidate(); + if (location.isChunkEdge()) { + if (location.isChunkBackEdge()) { + Chunk neighbor = Game.client.getScene().blockRenderer.chunkSlice.getChunk(location.getChunkLocation() + .getBack()); + neighbor.invalidate(); + } else if (location.isChunkFrontEdge()) { + Chunk neighbor = Game.client.getScene().blockRenderer.chunkSlice.getChunk(location.getChunkLocation() + .getFront()); + neighbor.invalidate(); + } else if (location.isChunkLeftEdge()) { + Chunk neighbor = Game.client.getScene().blockRenderer.chunkSlice.getChunk(location.getChunkLocation() + .getLeft()); + neighbor.invalidate(); + } else if (location.isChunkRightEdge()) { + Chunk neighbor = Game.client.getScene().blockRenderer.chunkSlice.getChunk(location.getChunkLocation() + .getRight()); + neighbor.invalidate(); + } else if (location.isChunkTopEdge()) { + Chunk neighbor = Game.client.getScene().blockRenderer.chunkSlice.getChunk(location.getChunkLocation() + .getTop()); + neighbor.invalidate(); + } else if (location.isChunkBottomEdge()) { + Chunk neighbor = Game.client.getScene().blockRenderer.chunkSlice.getChunk(location.getChunkLocation() + .getBottom()); + neighbor.invalidate(); + } + } + } + + public boolean canMoveThrough() throws ChunkUnavailableException { + return provider.canMoveThrough(location.x, location.y, location.z); + } } diff --git a/src/ru/olamedia/olacraft/world/block/BlockRegistry.java b/src/ru/olamedia/olacraft/world/block/BlockRegistry.java index ec9f9c1..a6e8d38 100644 --- a/src/ru/olamedia/olacraft/world/block/BlockRegistry.java +++ b/src/ru/olamedia/olacraft/world/block/BlockRegistry.java @@ -2,20 +2,24 @@ package ru.olamedia.olacraft.world.block; import java.util.HashMap; -import ru.olamedia.olacraft.world.blockTypes.BlockType; +import ru.olamedia.olacraft.world.blockTypes.AbstractBlockType; public class BlockRegistry { private HashMap<Integer, String> names = new HashMap<Integer, String>(); - private HashMap<Integer, BlockType> types = new HashMap<Integer, BlockType>(); + private HashMap<Integer, Boolean> opaque = new HashMap<Integer, Boolean>(); + private HashMap<Integer, Boolean> canMoveThrough = new HashMap<Integer, Boolean>(); + private HashMap<Integer, AbstractBlockType> types = new HashMap<Integer, AbstractBlockType>(); + private HashMap<String, Integer> ids = new HashMap<String, Integer>(); private int autoincrement = 0; private BlockRegistry worldRegistry; public BlockRegistry() { + } - public BlockType getBlockType(int id) { + public AbstractBlockType getBlockType(int id) { return types.get(id); } @@ -23,12 +27,19 @@ public class BlockRegistry { return names.get(id); } - public int registerBlockType(BlockType type) { + public boolean isOpaque(int id) { + return opaque.get(id); + } + + public int registerBlockType(AbstractBlockType type) { autoincrement++; int id = autoincrement; - String classId = type.getClass().getName(); - names.put(id, classId); + String className = type.getClass().getName(); + names.put(id, className); types.put(id, type); + opaque.put(id, type.isOpaque()); + canMoveThrough.put(id, type.canMoveThrough()); + ids.put(className, id); return autoincrement; } @@ -40,4 +51,12 @@ public class BlockRegistry { this.worldRegistry = worldRegistry; } + public int getBlockIdByClassName(String className) { + return ids.get(className); + } + + public boolean canMoveThrough(int id) { + return canMoveThrough.get(id); + } + } diff --git a/src/ru/olamedia/olacraft/world/blockRenderer/AbstractBlockRenderer.java b/src/ru/olamedia/olacraft/world/blockRenderer/AbstractBlockRenderer.java new file mode 100644 index 0000000..dfb8e1c --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockRenderer/AbstractBlockRenderer.java @@ -0,0 +1,64 @@ +package ru.olamedia.olacraft.world.blockRenderer; + +import java.nio.FloatBuffer; + +import ru.olamedia.geom.ImmModeMesh; +import ru.olamedia.olacraft.world.blockTypes.BlockType; +import ru.olamedia.olacraft.world.data.ChunkDataNeighbors; +import ru.olamedia.olacraft.world.location.Location3f; +import ru.olamedia.olacraft.world.location.Location3i; + +public abstract class AbstractBlockRenderer implements IBlockRenderer { + + public boolean renderBottom = true; + public boolean renderTop = true; + public boolean renderLeft = true; + public boolean renderRight = true; + public boolean renderFront = true; + public boolean renderBack = true; + public float scale = 1f; + private ChunkDataNeighbors neighbors; + + protected ImmModeMesh mesh = null; + + public void renderAllSides() { + renderBottom = true; + renderTop = true; + renderLeft = true; + renderRight = true; + renderFront = true; + renderBack = true; + } + + abstract public void putMesh(ImmModeMesh mesh, BlockType type, FloatBuffer renderLocation, boolean useShader); + + public ImmModeMesh getMesh(BlockType type, FloatBuffer renderLocation, boolean useShader) { + return mesh; + } + + public ImmModeMesh getMesh(BlockType type, Location3f location, boolean glsl) { + return mesh; + } + + @Override + public void render(BlockType type, Location3f location, boolean glsl) { + getMesh(type, location, glsl).draw(); + } + + @Override + public void render(BlockType type, Location3i location, boolean glsl) { + getMesh(type, new Location3f(location), glsl).draw(); + } + + public void setScale(float f) { + scale = f; + } + + abstract public int getMeshVertexCount(BlockType currentType, FloatBuffer renderLocation, + boolean useShader); + + public void setNeighbors(ChunkDataNeighbors neighbors) { + this.neighbors = neighbors; + } + +} diff --git a/src/ru/olamedia/olacraft/world/blockRenderer/BoxRenderer.java b/src/ru/olamedia/olacraft/world/blockRenderer/BoxRenderer.java new file mode 100644 index 0000000..8482595 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockRenderer/BoxRenderer.java @@ -0,0 +1,282 @@ +package ru.olamedia.olacraft.world.blockRenderer; + +import java.nio.FloatBuffer; + +import javax.vecmath.Point3f; + +import ru.olamedia.asset.SpriteRectangle; +import ru.olamedia.geom.ImmModeMesh; +import ru.olamedia.olacraft.world.blockTypes.BlockType; + +public class BoxRenderer extends AbstractBlockRenderer { + + public static boolean useTriangles = false; + + public Point3f bottomLeftBack = new Point3f(); + public Point3f bottomLeftFront = new Point3f(); + public Point3f bottomRightBack = new Point3f(); + public Point3f bottomRightFront = new Point3f(); + + public Point3f topLeftBack = new Point3f(); + public Point3f topLeftFront = new Point3f(); + public Point3f topRightBack = new Point3f(); + public Point3f topRightFront = new Point3f(); + public float textureTop = 1; + public float textureBottom = 0; + public float textureLeft = 0; + public float textureRight = 1; + + public void setPoint3f(Point3f p) { + mesh.glVertex3f(p.x, p.y, p.z); + } + + public void addBottomLeftBackVertex() { + setPoint3f(bottomLeftBack); + } + + public void addBottomLeftFrontVertex() { + setPoint3f(bottomLeftFront); + } + + public void addBottomRightBackVertex() { + setPoint3f(bottomRightBack); + } + + public void addBottomRightFrontVertex() { + setPoint3f(bottomRightFront); + } + + public void addTopLeftBackVertex() { + setPoint3f(topLeftBack); + } + + public void addTopLeftFrontVertex() { + setPoint3f(topLeftFront); + } + + public void addTopRightBackVertex() { + setPoint3f(topRightBack); + } + + public void addTopRightFrontVertex() { + setPoint3f(topRightFront); + } + + public void addFrontQuad() { + // triangle strip: И + mesh.setUV(textureLeft, textureTop); + addTopLeftFrontVertex(); // top left + mesh.setUV(textureLeft, textureBottom); + addBottomLeftFrontVertex(); // bottom left + if (useTriangles) { + mesh.setUV(textureRight, textureBottom); + addBottomRightFrontVertex(); // bottom right + + mesh.setUV(textureLeft, textureTop); + addTopLeftFrontVertex(); // top left + } + mesh.setUV(textureRight, textureBottom); + addBottomRightFrontVertex(); // bottom right + mesh.setUV(textureRight, textureTop); + addTopRightFrontVertex(); // top right + } + + public void addBackQuad() { + // triangle strip: И + mesh.setUV(textureLeft, textureTop); + addTopRightBackVertex(); + mesh.setUV(textureLeft, textureBottom); + addBottomRightBackVertex(); + if (useTriangles) { + mesh.setUV(textureRight, textureBottom); + addBottomLeftBackVertex(); + + mesh.setUV(textureLeft, textureTop); + addTopRightBackVertex(); + } + mesh.setUV(textureRight, textureBottom); + addBottomLeftBackVertex(); + mesh.setUV(textureRight, textureTop); + addTopLeftBackVertex(); + } + + public void addLeftQuad() { + // triangle strip: И + mesh.setUV(textureLeft, textureTop); + addTopLeftBackVertex(); + mesh.setUV(textureLeft, textureBottom); + addBottomLeftBackVertex(); + if (useTriangles) { + mesh.setUV(textureRight, textureBottom); + addBottomLeftFrontVertex(); + + mesh.setUV(textureLeft, textureTop); + addTopLeftBackVertex(); + } + mesh.setUV(textureRight, textureBottom); + addBottomLeftFrontVertex(); + mesh.setUV(textureRight, textureTop); + addTopLeftFrontVertex(); + } + + public void addRightQuad() { + // triangle strip: И + mesh.setUV(textureLeft, textureTop); + addTopRightFrontVertex(); + mesh.setUV(textureLeft, textureBottom); + addBottomRightFrontVertex(); + if (useTriangles) { + mesh.setUV(textureRight, textureBottom); + addBottomRightBackVertex(); + + mesh.setUV(textureLeft, textureTop); + addTopRightFrontVertex(); + } + mesh.setUV(textureRight, textureBottom); + addBottomRightBackVertex(); + mesh.setUV(textureRight, textureTop); + addTopRightBackVertex(); + } + + public void addTopQuad() { + // triangle strip: И + mesh.setUV(textureLeft, textureBottom); + addTopLeftBackVertex(); + mesh.setUV(textureLeft, textureTop); + addTopLeftFrontVertex(); + if (useTriangles) { + mesh.setUV(textureRight, textureTop); + addTopRightFrontVertex(); + + mesh.setUV(textureLeft, textureBottom); + addTopLeftBackVertex(); + } + mesh.setUV(textureRight, textureTop); + addTopRightFrontVertex(); + mesh.setUV(textureRight, textureBottom); + addTopRightBackVertex(); + } + + public void addBottomQuad() { + // triangle strip: И + mesh.setUV(textureLeft, textureBottom); + addBottomLeftFrontVertex(); + mesh.setUV(textureLeft, textureTop); + addBottomLeftBackVertex(); + if (useTriangles) { + mesh.setUV(textureRight, textureTop); + addBottomRightBackVertex(); + + mesh.setUV(textureLeft, textureBottom); + addBottomLeftFrontVertex(); + } + mesh.setUV(textureRight, textureTop); + addBottomRightBackVertex(); + mesh.setUV(textureRight, textureBottom); + addBottomRightFrontVertex(); + } + + public void setPointOffset(float offset) { + bottomLeftBack.x = -offset; + bottomLeftBack.y = -offset; + bottomLeftBack.z = -offset; + // + bottomLeftFront.x = -offset; + bottomLeftFront.y = -offset; + bottomLeftFront.z = offset; + // + bottomRightBack.x = offset; + bottomRightBack.y = -offset; + bottomRightBack.z = -offset; + // + bottomRightFront.x = offset; + bottomRightFront.y = -offset; + bottomRightFront.z = offset; + // + topLeftBack.x = -offset; + topLeftBack.y = offset; + topLeftBack.z = -offset; + // + topLeftFront.x = -offset; + topLeftFront.y = offset; + topLeftFront.z = offset; + // + topRightBack.x = offset; + topRightBack.y = offset; + topRightBack.z = -offset; + // + topRightFront.x = offset; + topRightFront.y = offset; + topRightFront.z = offset; + + } + + static float tcfix = 0.00001f; + + public void setTextureOffset(SpriteRectangle texRect) { + tcfix = (texRect.bottomRight.x - texRect.topLeft.x) / 512; + textureLeft = texRect.topLeft.x + tcfix; + textureRight = texRect.bottomRight.x - tcfix; + textureTop = texRect.topLeft.y + tcfix; + textureBottom = texRect.bottomRight.y - tcfix; + } + + @Override + public int getMeshVertexCount(BlockType currentType, FloatBuffer renderLocation, boolean useShader) { + return 4 * ((renderBack ? 1 : 0) + (renderFront ? 1 : 0) + (renderLeft ? 1 : 0) + (renderRight ? 1 : 0) + + (renderBottom ? 1 : 0) + (renderTop ? 1 : 0)); + } + + @Override + public void putMesh(ImmModeMesh mesh, BlockType type, FloatBuffer location, boolean useShader) { + this.mesh = mesh; + mesh.enableColor4(); + mesh.enableVertex3(); + mesh.enableTexCoord2(); + // mesh.enableNormal3(); + mesh.glTranslate(location.get(0), location.get(1), location.get(2)); + mesh.glColor4f(1, 1, 1, 1); + setPointOffset(0.5f * scale); + { + if (renderBack) { + setTextureOffset(type.getBackTextureOffset()); + mesh.glNormal3f(0, 0, 1); + addBackQuad(); + } + if (renderFront) { + setTextureOffset(type.getFrontTextureOffset()); + mesh.glNormal3f(0, 0, -1); + addFrontQuad(); + } + if (renderLeft) { + setTextureOffset(type.getLeftTextureOffset()); + mesh.glNormal3f(1, 0, 0); + addLeftQuad(); + } + if (renderRight) { + setTextureOffset(type.getRightTextureOffset()); + mesh.glNormal3f(-1, 0, 1); + addRightQuad(); + } + if (renderBottom) { + setTextureOffset(type.getBottomTextureOffset()); + mesh.glNormal3f(0, -1, 0); + addBottomQuad(); + } + if (renderTop) { + setTextureOffset(type.getTopTextureOffset()); + mesh.glNormal3f(0, 1, 0); + addTopQuad(); + } + } + } + + @Override + public ImmModeMesh getMesh(BlockType type, FloatBuffer location, boolean glsl) { + mesh = ImmModeMesh.allocate(4 * 6); // 6 rectangles + mesh.setGLSL(glsl); + putMesh(mesh, type, location, glsl); + mesh.end(); + return mesh; + } +} diff --git a/src/ru/olamedia/olacraft/world/blockRenderer/ChunkMeshGarbageCollector.java b/src/ru/olamedia/olacraft/world/blockRenderer/ChunkMeshGarbageCollector.java new file mode 100644 index 0000000..ad8bb81 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockRenderer/ChunkMeshGarbageCollector.java @@ -0,0 +1,82 @@ +package ru.olamedia.olacraft.world.blockRenderer; + +import java.util.concurrent.ArrayBlockingQueue; + +import ru.olamedia.olacraft.game.Game; +import ru.olamedia.olacraft.world.chunk.Chunk; +import ru.olamedia.olacraft.world.chunk.ChunkSlice; +import ru.olamedia.olacraft.world.location.BlockLocation; + +public class ChunkMeshGarbageCollector extends Thread { + public static ChunkMeshGarbageCollector instance = new ChunkMeshGarbageCollector("Mesh GC"); + private ArrayBlockingQueue<Chunk> chunks = new ArrayBlockingQueue<Chunk>(32); + + public ChunkMeshGarbageCollector(String name) { + super(name); + } + + BlockLocation cameraBlock; + private int renderDistance; + + public void lookup() { + renderDistance = Game.client.getScene().getPlayer().settings.renderDistance; + cameraBlock = Game.client.getScene().getPlayer().getCameraBlockLocation(); + // FIXME: cuncurrent modification + for (Integer x : ChunkSlice.rendererInstance.iChunks.keySet()) { + for (Integer y : ChunkSlice.rendererInstance.iChunks.get(x).keySet()) { + for (Integer z : ChunkSlice.rendererInstance.iChunks.get(x).get(y).keySet()) { + if (isFull()) { + return; + } + Chunk chunk = ChunkSlice.rendererInstance.iChunks.get(x).get(y).get(z); + float d = (float) Math.sqrt(Math.pow(chunk.getOffset().x + 8 - cameraBlock.x, 2) + + Math.pow(chunk.getOffset().y + 8 - cameraBlock.y, 2) + + Math.pow(chunk.getOffset().z + 8 - cameraBlock.z, 2)); + if (d > renderDistance + renderDistance / 4) { + add(chunk); + } + } + } + } + } + + 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(); + ChunkSlice.rendererInstance.removeChunk(chunk.location); + } else { + lookup(); + } + } + + @Override + public void run() { + // glc.makeCurrent(); + while (true) { + // main loop + try { + tick(); + if (chunks.isEmpty()) { + Thread.sleep(50); + } + // 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/blockRenderer/ChunkRenderer.java b/src/ru/olamedia/olacraft/world/blockRenderer/ChunkRenderer.java new file mode 100644 index 0000000..f27eb76 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockRenderer/ChunkRenderer.java @@ -0,0 +1,356 @@ +package ru.olamedia.olacraft.world.blockRenderer; + +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.util.ArrayList; +import java.util.concurrent.ArrayBlockingQueue; + +import javax.media.opengl.GL2ES2; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLException; +import javax.media.opengl.GLUniformData; + +import com.jogamp.opengl.util.PMVMatrix; +import com.jogamp.opengl.util.glsl.ShaderState; + +import ru.olamedia.asset.Shader; +import ru.olamedia.geom.ChunkMesh; +import ru.olamedia.geom.ImmModeMesh; +import ru.olamedia.olacraft.game.Game; +import ru.olamedia.olacraft.render.jogl.ChunkRangeRenderer; +import ru.olamedia.olacraft.world.blockTypes.BlockType; +import ru.olamedia.olacraft.world.calc.LightCalculator; +import ru.olamedia.olacraft.world.calc.LightData; +import ru.olamedia.olacraft.world.chunk.Chunk; +import ru.olamedia.olacraft.world.chunk.ChunkUnavailableException; +import ru.olamedia.olacraft.world.data.ChunkData; +import ru.olamedia.olacraft.world.data.ChunkDataNeighbors; +import ru.olamedia.olacraft.world.drop.DroppedEntity; +import ru.olamedia.olacraft.world.location.BlockLocation; +import ru.olamedia.olacraft.world.location.IntLocation; +import ru.olamedia.olacraft.world.provider.WorldProvider; + +public class ChunkRenderer { + protected static WorldProvider provider; + protected static Chunk chunk; + protected static ChunkData data; + protected ChunkData top; + protected ChunkData bottom; + protected ChunkData left; + protected ChunkData right; + protected ChunkData front; + protected ChunkData back; + + protected int[] visible; + + public static int visibleCount = 0; + public static int visibleOpaqueCount = 0; + public static int vertexCount = 0; + public static int vertexOpaqueCount = 0; + + public boolean isAvailable = false; + public boolean isCompiling = false; + public boolean isCompiled = false; + public boolean needRecompilation = true; + + protected static ImmModeMesh mesh; + protected ImmModeMesh prevMesh; + protected ImmModeMesh[] meshes; + + protected static ImmModeMesh opaqueMesh; + protected ImmModeMesh prevOpaqueMesh; + protected ImmModeMesh[] opaqueMeshes; + + protected ImmModeMesh[] droppedMeshes; + + protected ArrayBlockingQueue<ImmModeMesh> disposable = new ArrayBlockingQueue<ImmModeMesh>(4096); + int droppedEntityVertexCount = 0; + + private static Shader shader = null; + public static GLUniformData pmvMatrixUniform; + public static GLUniformData sunColor; + + private static boolean useShader = true; + + public static Shader getShader() { + if (null == shader) { + shader = new Shader(); + shader.compile(); + final GL2ES2 gl = GLContext.getCurrentGL().getGL2ES2(); + final ShaderState state = shader.getState(); + final PMVMatrix pmvMatrix = Game.client.getScene().getPmvMatrix(); + state.attachObject("pmvMatrix", pmvMatrix); + pmvMatrixUniform = new GLUniformData("pmvMatrix", 4, 4, pmvMatrix.glGetPMvMatrixf()); + state.ownUniform(pmvMatrixUniform); + state.uniform(gl, pmvMatrixUniform); + + state.attachObject("sunColor", ChunkRenderer.sunColor); + sunColor = new GLUniformData("sunColor", 4, Game.client.getScene().dayTime.sunColor); + state.ownUniform(ChunkRenderer.sunColor); + state.uniform(gl, ChunkRenderer.sunColor); + + // if (!state.uniform(gl, new GLUniformData("sunColor", 4, + // Game.client.getScene().time.sunColor))) { + // throw new GLException("Error setting sunColor in shader: " + + // state); + // } + if (!state.uniform(gl, new GLUniformData("mesh_ActiveTexture", 0))) { + throw new GLException("Error setting mesh_ActiveTexture in shader: " + state); + } + } + return shader; + } + + public ChunkRenderer(Chunk chunk) { + this.chunk = chunk; + this.provider = chunk.getProvider(); + } + + public void invalidate() { + needRecompilation = true; + } + + protected void disposeMesh(ImmModeMesh mesh) { + if (null != mesh) { + disposable.offer(mesh); + } + } + + public void disposeMeshes() { + // while (!disposable.isEmpty()){ + // final ImmModeMesh mesh = disposable.poll(); + // mesh.dispose(); + // } + } + + private static IntBuffer blockLocation = IntBuffer.allocate(3); + private static FloatBuffer renderLocation = FloatBuffer.allocate(3); + + private static short currentId; + private static BlockType currentType; + private static AbstractBlockRenderer currentRenderer; + + private static void prepareRenderer(WorldProvider provider, Chunk chunk, ChunkData data) { + currentType = provider.getTypeRegistry().getBlockType(data.types[currentId]); + if (null == currentType) { + throw new RuntimeException("invalid type: " + currentType + " " + currentId); + } + final int x = currentId / 256; + final int y = (currentId - x * 256) / 16; + final int z = currentId - x * 256 - y * 16; + IntLocation.set(blockLocation, chunk.offset.x + x, chunk.offset.y + y, chunk.offset.z + z); + renderLocation.put(0, blockLocation.get(0)); + renderLocation.put(1, blockLocation.get(1)); + renderLocation.put(2, blockLocation.get(2)); + // final RenderLocation location = new + // RenderLocation(blockLocation); + // System.out.println(chunk.location); + currentRenderer = currentType.getRenderer(); + if (null == currentRenderer) { + throw new RuntimeException("invalid renderer: " + currentType.getClass().getName()); + } + currentRenderer.setScale(1); + currentRenderer.setNeighbors(neighbors); + if (currentType.hideTouchedSides() || currentType.isOpaque()) { + // check each side + try { + currentRenderer.renderBottom = !provider.hideTouchedSides(blockLocation.get(0), + blockLocation.get(1) - 1, blockLocation.get(2), data.types[currentId]); + currentRenderer.renderTop = !provider.hideTouchedSides(blockLocation.get(0), blockLocation.get(1) + 1, + blockLocation.get(2), data.types[currentId]); + currentRenderer.renderLeft = !provider.hideTouchedSides(blockLocation.get(0) - 1, blockLocation.get(1), + blockLocation.get(2), data.types[currentId]); + currentRenderer.renderRight = !provider.hideTouchedSides(blockLocation.get(0) + 1, + blockLocation.get(1), blockLocation.get(2), data.types[currentId]); + currentRenderer.renderFront = !provider.hideTouchedSides(blockLocation.get(0), blockLocation.get(1), + blockLocation.get(2) + 1, data.types[currentId]); + currentRenderer.renderBack = !provider.hideTouchedSides(blockLocation.get(0), blockLocation.get(1), + blockLocation.get(2) - 1, data.types[currentId]); + } catch (ChunkUnavailableException e) { + e.printStackTrace(); + } + } else { + currentRenderer.renderAllSides(); + } + } + + private static ChunkDataNeighbors neighbors = new ChunkDataNeighbors(); + + public static void compile(Chunk chunk) { + final ChunkMesh chunkMesh = chunk.mesh; + chunkMesh.setValid(true); + final WorldProvider provider = chunk.getProvider(); + if (chunk.offset.y >= provider.getInfo().maxHeight) { + chunkMesh.setCompiled(true); + return; + } + if (chunk.offset.y < provider.getInfo().minHeight) { + chunkMesh.setCompiled(true); + return; + } + + if (!chunk.isAvailable()) { + chunk.request(); + return; + } + if (!chunk.isNeighborsAvailable()) { + chunk.requestNeighbors(); + return; + } + final ChunkData data = chunk.getData(); + neighbors.setProvider(provider); + neighbors.setData(data); + neighbors.loadNeighbors(); + neighbors.calcLight(); + neighbors.calcVisibility(); + // data.computeVisibility(provider); + // updateVisibility(); + + // droppedEntityVertexCount = 0; + // if (!data.droppedEntities.isEmpty()) { + // droppedMeshes = new ImmModeMesh[data.droppedEntities.size()]; + // int i = 0; + // for (DroppedEntity entity : data.droppedEntities) { + // droppedMeshes[i] = compileDroppedEntity(entity); + // droppedEntityVertexCount += droppedMeshes[i].getVertexCount(); + // i++; + // } + // } + // + // vertexCount = droppedEntityVertexCount; + vertexCount = 0; + vertexOpaqueCount = 0; + for (currentId = 0; currentId < 4096; currentId++) { + if (neighbors.isVisible(currentId)) { + prepareRenderer(provider, chunk, data); + if (null != currentRenderer) { + if (currentType.isOpaque()) { + vertexOpaqueCount += currentRenderer.getMeshVertexCount(currentType, renderLocation, useShader); + } else { + vertexOpaqueCount += currentRenderer.getMeshVertexCount(currentType, renderLocation, useShader); + //vertexCount += currentRenderer.getMeshVertexCount(currentType, renderLocation, useShader); + } + } + } + } + if (vertexCount > 0) { + mesh = ImmModeMesh.allocate(vertexCount); + // mesh.setServer(true); + mesh.setGLSL(true); + mesh.enableColor4(); + mesh.enableTexCoord2(); + mesh.enableVertex3(); + // mesh.enableNormal3(); + mesh.beginQuads(); + } else { + mesh = null; + } + if (vertexOpaqueCount > 0) { + opaqueMesh = ImmModeMesh.allocate(vertexOpaqueCount); + // opaqueMesh.setServer(true); + opaqueMesh.setGLSL(true); + opaqueMesh.enableColor4(); + opaqueMesh.enableTexCoord2(); + opaqueMesh.enableVertex3(); + // opaqueMesh.enableNormal3(); + opaqueMesh.beginQuads(); + } else { + opaqueMesh = null; + } + for (currentId = 0; currentId < 4096; currentId++) { + if (neighbors.isVisible(currentId)) { + prepareRenderer(provider, chunk, data); + //if (currentType.isOpaque()) { + visibleOpaqueCount++; + if (vertexOpaqueCount > 0) { + currentRenderer.putMesh(opaqueMesh, currentType, renderLocation, useShader); + } + //} else { + // if (vertexCount > 0) { + // currentRenderer.putMesh(mesh, currentType, renderLocation, useShader); + // } + //} + } + } + if (vertexCount > 0) { + mesh.end(); + mesh.compact(); + } + if (vertexOpaqueCount > 0) { + opaqueMesh.end(); + opaqueMesh.compact(); + } + chunkMesh.setMesh(mesh); + chunkMesh.setOpaqueMesh(opaqueMesh); + } + + public ImmModeMesh getOpaqueMesh() { + return opaqueMesh; + } + + public ImmModeMesh getMesh() { + return mesh; + } + + public ImmModeMesh compileDroppedEntity(DroppedEntity entity) { + final BlockType type = entity.stack.type; + final RenderLocation location = new RenderLocation(entity.location); + // int id = location.clampId(); + // System.out.println(chunk.location); + final AbstractBlockRenderer renderer = type.getRenderer(); + renderer.setScale(0.3f); + renderer.renderAllSides(); + return renderer.getMesh(type, location, useShader); + } + + public void render(int pass) { + + if (!isCompiled || isCompiling || !isAvailable) { + // compile(); + return; + } + if (pass == ChunkRangeRenderer.OPAQUE_PASS) { + if (null != opaqueMesh) { + opaqueMesh.draw(); + } else if (null != prevOpaqueMesh) { + prevOpaqueMesh.draw(); + } + } else { + if (null != mesh) { + mesh.draw(); + } else if (null != prevMesh) { + prevMesh.draw(); + } + } + /* + * if (!disposable.isEmpty()) { + * for (ImmModeMesh mesh : disposable) { + * mesh.dispose(); + * } + * disposable.clear(); + * } + */ + } + + public static void disableShader() { + getShader().disable(); + } + + public static void enableShader() { + // GL2ES2 gl = GLContext.getCurrentGL().getGL2ES2(); + getShader().enable(); + // Game.client.getScene().time.getClearColor(); + // getShader().getState().uniform(gl, pmvMatrixUniform); + // getShader().getState().uniform(gl, sunColor); + } + + public void destroy() { + isCompiling = true; + mesh = null; + prevMesh = null; + meshes = null; + needRecompilation = true; + isCompiled = false; + isCompiling = false; + } +} diff --git a/src/ru/olamedia/olacraft/world/blockRenderer/CrossQuadsRenderer.java b/src/ru/olamedia/olacraft/world/blockRenderer/CrossQuadsRenderer.java new file mode 100644 index 0000000..4dc14a6 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockRenderer/CrossQuadsRenderer.java @@ -0,0 +1,115 @@ +package ru.olamedia.olacraft.world.blockRenderer; + +import java.nio.FloatBuffer; +import java.util.HashMap; + +import ru.olamedia.geom.ImmModeMesh; +import ru.olamedia.olacraft.world.blockTypes.BlockType; + +public class CrossQuadsRenderer extends BoxRenderer { + public static boolean useTriangles = false; + private HashMap<Integer, ImmModeMesh> precompiled = new HashMap<Integer, ImmModeMesh>(); + + public void addLeftQuad() { + // triangle strip: И + mesh.setUV(textureLeft, textureTop); + addTopLeftBackVertex(); + mesh.setUV(textureLeft, textureBottom); + addBottomLeftBackVertex(); + if (useTriangles) { + mesh.setUV(textureRight, textureBottom); + addBottomRightFrontVertex(); + + mesh.setUV(textureLeft, textureTop); + addTopLeftBackVertex(); + } + mesh.setUV(textureRight, textureBottom); + addBottomRightFrontVertex(); + mesh.setUV(textureRight, textureTop); + addTopRightFrontVertex(); + // mirror + mesh.setUV(textureLeft, textureTop); + addTopRightFrontVertex(); + mesh.setUV(textureLeft, textureBottom); + addBottomRightFrontVertex(); + if (useTriangles) { + mesh.setUV(textureRight, textureBottom); + addBottomLeftBackVertex(); + + mesh.setUV(textureLeft, textureTop); + addTopRightFrontVertex(); + } + mesh.setUV(textureRight, textureBottom); + addBottomLeftBackVertex(); + mesh.setUV(textureRight, textureTop); + addTopLeftBackVertex(); + } + + public void addRightQuad() { + // triangle strip: И + mesh.setUV(textureLeft, textureTop); + addTopRightBackVertex(); + mesh.setUV(textureLeft, textureBottom); + addBottomRightBackVertex(); + if (useTriangles) { + mesh.setUV(textureLeft, textureTop); + addTopRightBackVertex(); + + mesh.setUV(textureRight, textureBottom); + addBottomLeftFrontVertex(); + } + mesh.setUV(textureRight, textureBottom); + addBottomLeftFrontVertex(); + mesh.setUV(textureRight, textureTop); + addTopLeftFrontVertex(); + // mirror + mesh.setUV(textureLeft, textureTop); + addTopLeftFrontVertex(); + mesh.setUV(textureLeft, textureBottom); + addBottomLeftFrontVertex(); + if (useTriangles) { + mesh.setUV(textureRight, textureBottom); + addBottomRightBackVertex(); + + mesh.setUV(textureLeft, textureTop); + addTopLeftFrontVertex(); + } + mesh.setUV(textureRight, textureBottom); + addBottomRightBackVertex(); + mesh.setUV(textureRight, textureTop); + addTopRightBackVertex(); + } + + @Override + public int getMeshVertexCount(BlockType currentType, FloatBuffer renderLocation, boolean useShader) { + return 4 * 4; + } + + @Override + public void putMesh(ImmModeMesh mesh, BlockType type, FloatBuffer location, boolean useShader) { + this.mesh = mesh; + // mesh.enableNormal3(); + mesh.glNormal3f(1, 0, 0); + mesh.glTranslate(location.get(0), location.get(1), location.get(2)); + mesh.glColor4f(1, 1, 1, 1f); + setPointOffset(0.5f * scale); + { + setTextureOffset(type.getLeftTextureOffset()); + addLeftQuad(); + addRightQuad(); + } + } + + @Override + public ImmModeMesh getMesh(BlockType type, FloatBuffer location, boolean glsl) { + mesh = ImmModeMesh.allocate(4 * 4); // 6 rectangles + mesh.enableColor4(); + mesh.enableVertex3(); + mesh.enableTexCoord2(); + mesh.setGLSL(glsl); + putMesh(mesh, type, location, glsl); + mesh.end(); + return mesh; + } + +} diff --git a/src/ru/olamedia/olacraft/world/blockRenderer/IBlockRenderer.java b/src/ru/olamedia/olacraft/world/blockRenderer/IBlockRenderer.java new file mode 100644 index 0000000..4d2a239 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockRenderer/IBlockRenderer.java @@ -0,0 +1,15 @@ +package ru.olamedia.olacraft.world.blockRenderer; + +import ru.olamedia.geom.ImmModeMesh; +import ru.olamedia.olacraft.world.blockTypes.BlockType; +import ru.olamedia.olacraft.world.location.Location3f; +import ru.olamedia.olacraft.world.location.Location3i; + +public interface IBlockRenderer { + + public void render(BlockType type, Location3i location, boolean glsl); + + public void render(BlockType type, Location3f location, boolean glsl); + + public ImmModeMesh getMesh(BlockType type, Location3f location, boolean glsl); +} diff --git a/src/ru/olamedia/olacraft/world/blockRenderer/RenderLocation.java b/src/ru/olamedia/olacraft/world/blockRenderer/RenderLocation.java new file mode 100644 index 0000000..b396010 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockRenderer/RenderLocation.java @@ -0,0 +1,35 @@ +package ru.olamedia.olacraft.world.blockRenderer; + +import java.nio.IntBuffer; + +import ru.olamedia.olacraft.world.data.ChunkData; +import ru.olamedia.olacraft.world.location.Location3f; +import ru.olamedia.olacraft.world.location.Location3i; + +public class RenderLocation extends Location3f { + public RenderLocation(float x, float y, float z) { + super(x, y, z); + } + + public RenderLocation(Location3i location) { + super(location); + } + + public RenderLocation(Location3f location) { + super(location); + } + + public RenderLocation(IntBuffer location) { + super(location.get(0), location.get(1), location.get(2)); + } + + public void set(float x, float y, float z) { + this.x = x; + this.y = y; + this.z = z; + } + + public int clampId() { + return ChunkData.ClampID((int) x, (int) y, (int) z); + } +} diff --git a/src/ru/olamedia/olacraft/world/blockRenderer/package-info.java b/src/ru/olamedia/olacraft/world/blockRenderer/package-info.java new file mode 100644 index 0000000..65ce990 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockRenderer/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.blockRenderer;
\ 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 index 57258ef..0d6dd7f 100644 --- a/src/ru/olamedia/olacraft/world/blockStack/BlockStack.java +++ b/src/ru/olamedia/olacraft/world/blockStack/BlockStack.java @@ -1,13 +1,15 @@ package ru.olamedia.olacraft.world.blockStack; -import ru.olamedia.olacraft.world.block.Block; +import ru.olamedia.olacraft.world.blockTypes.AbstractBlockType; +import ru.olamedia.olacraft.world.blockTypes.EmptyBlockType; public class BlockStack { - public Block block; - public int count; + public AbstractBlockType type; + public int count = 0; + public boolean hidden = false; // do not render - public BlockStack(Block block, int count) { - this.block = block; + public BlockStack(AbstractBlockType type, int count) { + this.type = type; this.count = count; } @@ -23,40 +25,40 @@ public class BlockStack { } else { c = count; count = 0; + type = new EmptyBlockType(); } - return new BlockStack(block, c); + return new BlockStack(type, c); } public BlockStack getAll() { int c = count; count = 0; - return new BlockStack(block, c); + return new BlockStack(type, 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; - } + public void putStack(BlockStack stack) { + if (!type.getClass().getName().equals(stack.type.getClass().getName())) { + try { + type = stack.type.getClass().newInstance(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } // replace + } + int max = type.getMaxStack(); + // Stack + int total = count + stack.count; + if (total < max) { + count = total; + stack.count = 0; + stack.type = new EmptyBlockType(); } else { - // Replace - BlockStack remains = new BlockStack(block, count); - block = stack.block; - count = stack.count; - return remains; + count = max; + stack.count = total - max; } } diff --git a/src/ru/olamedia/olacraft/world/blockTypes/AbstractBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/AbstractBlockType.java index 717c01f..43e1332 100644 --- a/src/ru/olamedia/olacraft/world/blockTypes/AbstractBlockType.java +++ b/src/ru/olamedia/olacraft/world/blockTypes/AbstractBlockType.java @@ -2,12 +2,26 @@ package ru.olamedia.olacraft.world.blockTypes; import com.jogamp.opengl.util.texture.Texture; -import ru.olamedia.olacraft.world.block.BlockRegistry; +import ru.olamedia.asset.SpriteRectangle; +import ru.olamedia.olacraft.world.blockRenderer.AbstractBlockRenderer; +import ru.olamedia.olacraft.world.blockRenderer.BoxRenderer; +import ru.olamedia.olacraft.world.blockRenderer.RenderLocation; +import ru.olamedia.olacraft.world.location.BlockLocation; import ru.olamedia.olacraft.world.provider.WorldProvider; import ru.olamedia.texture.TextureManager; public abstract class AbstractBlockType implements BlockType { + protected AbstractBlockRenderer renderer = new BoxRenderer(); + + public void dropBlock(WorldProvider provider, BlockLocation location){ + provider.dropBlock(location, this); + } + + public AbstractBlockRenderer getRenderer() { + return this.renderer; + } + @Override abstract public String getName(); @@ -16,6 +30,23 @@ public abstract class AbstractBlockType implements BlockType { return 64; } + public boolean isOpaque() { // solid, non-transparent block + return true; + } + + public boolean isLoose() { + return false; + } + + @Override + public boolean hideTouchedSides() { + return isOpaque(); + } + + public boolean canMoveThrough() { + return false; + } + @Override abstract public String getStackTextureFile(); @@ -49,41 +80,88 @@ public abstract class AbstractBlockType implements BlockType { @Override public Texture getTopTexture() { - return TextureManager.get(this.getTopTextureFile()); + return TextureManager.getSprite(this.getTopTextureFile()); + } + + @Override + public SpriteRectangle getTopTextureOffset() { + return TextureManager.getSpriteOffset(this.getTopTextureFile()); } @Override public Texture getBottomTexture() { - return TextureManager.get(this.getBottomTextureFile()); + return TextureManager.getSprite(this.getBottomTextureFile()); + } + + @Override + public SpriteRectangle getBottomTextureOffset() { + return TextureManager.getSpriteOffset(this.getBottomTextureFile()); } @Override public Texture getLeftTexture() { - return TextureManager.get(this.getLeftTextureFile()); + return TextureManager.getSprite(this.getLeftTextureFile()); + } + + @Override + public SpriteRectangle getLeftTextureOffset() { + return TextureManager.getSpriteOffset(this.getLeftTextureFile()); } @Override public Texture getRightTexture() { - return TextureManager.get(this.getRightTextureFile()); + return TextureManager.getSprite(this.getRightTextureFile()); + } + + @Override + public SpriteRectangle getRightTextureOffset() { + return TextureManager.getSpriteOffset(this.getRightTextureFile()); } @Override public Texture getFrontTexture() { - return TextureManager.get(this.getFrontTextureFile()); + return TextureManager.getSprite(this.getFrontTextureFile()); + } + + @Override + public SpriteRectangle getFrontTextureOffset() { + return TextureManager.getSpriteOffset(this.getFrontTextureFile()); } @Override public Texture getBackTexture() { - return TextureManager.get(this.getBackTextureFile()); + return TextureManager.getSprite(this.getBackTextureFile()); } - - public void register(WorldProvider provider){ - getBackTexture(); - getBottomTexture(); - getFrontTexture(); - getLeftTexture(); - getRightTexture(); - getTopTexture(); - provider.getTypeRegistry().registerBlockType(this); + + @Override + public SpriteRectangle getBackTextureOffset() { + return TextureManager.getSpriteOffset(this.getBackTextureFile()); + } + + public void register(WorldProvider provider, boolean registerTextures) { + if (registerTextures) { + getBackTexture(); + getBottomTexture(); + getFrontTexture(); + getLeftTexture(); + getRightTexture(); + getTopTexture(); + } else { + provider.getTypeRegistry().registerBlockType(this); + } + } + + public int getId(WorldProvider provider) { + return provider.getTypeRegistry().getBlockIdByClassName(this.getClass().getName()); + } + + @Override + public void render(RenderLocation location) { + this.renderer.render(this, location, true); + } + + @Override + public boolean isTimeManaged() { + return false; } } diff --git a/src/ru/olamedia/olacraft/world/blockTypes/BlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/BlockType.java index 0bda2eb..d74dd6b 100644 --- a/src/ru/olamedia/olacraft/world/blockTypes/BlockType.java +++ b/src/ru/olamedia/olacraft/world/blockTypes/BlockType.java @@ -1,21 +1,83 @@ package ru.olamedia.olacraft.world.blockTypes; +import ru.olamedia.asset.SpriteOffset; +import ru.olamedia.asset.SpriteRectangle; +import ru.olamedia.olacraft.world.blockRenderer.AbstractBlockRenderer; +import ru.olamedia.olacraft.world.blockRenderer.IBlockRenderer; +import ru.olamedia.olacraft.world.blockRenderer.RenderLocation; +import ru.olamedia.olacraft.world.location.BlockLocation; +import ru.olamedia.olacraft.world.provider.WorldProvider; + import com.jogamp.opengl.util.texture.Texture; public interface BlockType { public String getName(); + public int getMaxStack(); + + public int getId(WorldProvider provider); + public String getStackTextureFile(); + public String getTopTextureFile(); + + public SpriteRectangle getTopTextureOffset(); + public String getBottomTextureFile(); + + public SpriteRectangle getBottomTextureOffset(); + public String getLeftTextureFile(); + + public SpriteRectangle getLeftTextureOffset(); + public String getRightTextureFile(); + + public SpriteRectangle getRightTextureOffset(); + public String getFrontTextureFile(); + + public SpriteRectangle getFrontTextureOffset(); + public String getBackTextureFile(); + + public SpriteRectangle getBackTextureOffset(); + public Texture getTopTexture(); + public Texture getBottomTexture(); + public Texture getLeftTexture(); + public Texture getRightTexture(); + public Texture getFrontTexture(); + public Texture getBackTexture(); + + /** + * Is block solid and completely non-transparent + */ + public boolean isOpaque(); + + /** + * Is block solid and we can remove sides if touched by another solid block + */ + public boolean hideTouchedSides(); + + /** + * Is block loose + */ + public boolean isLoose(); + + /** + * Can live entities move through this block + */ + public boolean canMoveThrough(); + + public AbstractBlockRenderer getRenderer(); + + public void render(RenderLocation location); + + public boolean isTimeManaged(); } diff --git a/src/ru/olamedia/olacraft/world/blockTypes/DirtBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/DirtBlockType.java index a4e5dd7..b359b08 100644 --- a/src/ru/olamedia/olacraft/world/blockTypes/DirtBlockType.java +++ b/src/ru/olamedia/olacraft/world/blockTypes/DirtBlockType.java @@ -3,7 +3,11 @@ package ru.olamedia.olacraft.world.blockTypes; public class DirtBlockType extends AbstractBlockType { @Override public String getName() { - return "Gravel"; + return "Dirt"; + } + + public boolean isLoose() { + return true; } @Override diff --git a/src/ru/olamedia/olacraft/world/blockTypes/EmptyBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/EmptyBlockType.java index 4073356..595c977 100644 --- a/src/ru/olamedia/olacraft/world/blockTypes/EmptyBlockType.java +++ b/src/ru/olamedia/olacraft/world/blockTypes/EmptyBlockType.java @@ -3,7 +3,7 @@ package ru.olamedia.olacraft.world.blockTypes; public class EmptyBlockType extends AbstractBlockType { @Override public String getName() { - return ""; + return "Empty"; } @Override @@ -20,4 +20,8 @@ public class EmptyBlockType extends AbstractBlockType { public String getTopTextureFile() { return "texture/empty.png"; } + @Override + public boolean isOpaque() { + return false; + } } diff --git a/src/ru/olamedia/olacraft/world/blockTypes/GrassBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/GrassBlockType.java index d863139..6104d13 100644 --- a/src/ru/olamedia/olacraft/world/blockTypes/GrassBlockType.java +++ b/src/ru/olamedia/olacraft/world/blockTypes/GrassBlockType.java @@ -6,6 +6,10 @@ public class GrassBlockType extends AbstractBlockType { return "Grass"; } + public boolean isLoose() { + return true; + } + @Override public int getMaxStack() { return 64; diff --git a/src/ru/olamedia/olacraft/world/blockTypes/GravelBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/GravelBlockType.java index 354d383..e013148 100644 --- a/src/ru/olamedia/olacraft/world/blockTypes/GravelBlockType.java +++ b/src/ru/olamedia/olacraft/world/blockTypes/GravelBlockType.java @@ -6,6 +6,10 @@ public class GravelBlockType extends AbstractBlockType { return "Gravel"; } + public boolean isLoose() { + return true; + } + @Override public int getMaxStack() { return 64; diff --git a/src/ru/olamedia/olacraft/world/blockTypes/IceBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/IceBlockType.java new file mode 100644 index 0000000..a5c6767 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/IceBlockType.java @@ -0,0 +1,32 @@ +package ru.olamedia.olacraft.world.blockTypes; + +public class IceBlockType extends AbstractBlockType { + @Override + public String getName() { + return "Ice"; + } + + public boolean isLoose() { + return true; + } + + @Override + public boolean isOpaque() { + return true; + } + + @Override + public int getMaxStack() { + return 1; + } + + @Override + public String getStackTextureFile() { + return "texture/ice.png"; + } + + @Override + public String getTopTextureFile() { + return "texture/ice.png"; + } +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/SnowBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/SnowBlockType.java new file mode 100644 index 0000000..18697e4 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/SnowBlockType.java @@ -0,0 +1,27 @@ +package ru.olamedia.olacraft.world.blockTypes; + +public class SnowBlockType extends AbstractBlockType { + @Override + public String getName() { + return "Snow"; + } + + public boolean isLoose() { + return true; + } + + @Override + public int getMaxStack() { + return 1; + } + + @Override + public String getStackTextureFile() { + return "texture/snow.png"; + } + + @Override + public String getTopTextureFile() { + return "texture/snow.png"; + } +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/TallGrassBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/TallGrassBlockType.java new file mode 100644 index 0000000..c277d72 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/TallGrassBlockType.java @@ -0,0 +1,58 @@ +package ru.olamedia.olacraft.world.blockTypes; + +import ru.olamedia.olacraft.world.blockRenderer.AbstractBlockRenderer; +import ru.olamedia.olacraft.world.blockRenderer.CrossQuadsRenderer; + +public class TallGrassBlockType extends AbstractBlockType { + + protected AbstractBlockRenderer renderer = new CrossQuadsRenderer(); + + @Override + public AbstractBlockRenderer getRenderer() { + return this.renderer; + } + + @Override + public String getName() { + return "Tall Grass"; + } + + @Override + public boolean canMoveThrough() { + return true; + } + + public boolean isLoose() { + return false; + } + + @Override + public boolean isOpaque() { + return false; + } + + @Override + public int getMaxStack() { + return 64; + } + + @Override + public String getStackTextureFile() { + return "texture/terrain-wheatgrass-lightgreen-med.png"; + } + + @Override + public String getTopTextureFile() { + return "texture/terrain-wheatgrass-lightgreen-med.png"; + } + + @Override + public String getFrontTextureFile() { + return "texture/terrain-wheatgrass-lightgreen-med.png"; + } + + @Override + public boolean isTimeManaged() { + return true; + } +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/WaterBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/WaterBlockType.java new file mode 100644 index 0000000..0ff984f --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/WaterBlockType.java @@ -0,0 +1,42 @@ +package ru.olamedia.olacraft.world.blockTypes; + +public class WaterBlockType extends AbstractBlockType { + @Override + public String getName() { + return "Water"; + } + + public boolean isLoose() { + return true; + } + + @Override + public int getMaxStack() { + return 1; + } + + @Override + public boolean isOpaque() { + return false; + } + + @Override + public boolean hideTouchedSides() { + return true; + } + + @Override + public boolean canMoveThrough() { + return true; + } + + @Override + public String getStackTextureFile() { + return "texture/water.png"; + } + + @Override + public String getTopTextureFile() { + return "texture/water.png"; + } +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/WheatBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/WheatBlockType.java new file mode 100644 index 0000000..583e91a --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/WheatBlockType.java @@ -0,0 +1,58 @@ +package ru.olamedia.olacraft.world.blockTypes; + +import ru.olamedia.olacraft.world.blockRenderer.AbstractBlockRenderer; +import ru.olamedia.olacraft.world.blockRenderer.CrossQuadsRenderer; + +public class WheatBlockType extends AbstractBlockType { + + protected AbstractBlockRenderer renderer = new CrossQuadsRenderer(); + + @Override + public AbstractBlockRenderer getRenderer() { + return this.renderer; + } + + @Override + public String getName() { + return "Wheat"; + } + + @Override + public boolean canMoveThrough() { + return true; + } + + public boolean isLoose() { + return false; + } + + @Override + public boolean isOpaque() { + return false; + } + + @Override + public int getMaxStack() { + return 64; + } + + @Override + public String getStackTextureFile() { + return "texture/wheat.png"; + } + + @Override + public String getTopTextureFile() { + return "texture/wheat.png"; + } + + @Override + public String getFrontTextureFile() { + return "texture/wheat.png"; + } + + @Override + public boolean isTimeManaged() { + return true; + } +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/stone/BrecciaStoneBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/stone/BrecciaStoneBlockType.java new file mode 100644 index 0000000..187938b --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/stone/BrecciaStoneBlockType.java @@ -0,0 +1,25 @@ +package ru.olamedia.olacraft.world.blockTypes.stone; + +import ru.olamedia.olacraft.world.blockTypes.AbstractBlockType; + +public class BrecciaStoneBlockType extends AbstractBlockType { + @Override + public String getName() { + return "Breccia"; + } + + @Override + public int getMaxStack() { + return 64; + } + + @Override + public String getStackTextureFile() { + return "texture/stone/sedimentary/breccia.png"; + } + + @Override + public String getTopTextureFile() { + return "texture/stone/sedimentary/breccia.png"; + } +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/stone/ChertStoneBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/stone/ChertStoneBlockType.java new file mode 100644 index 0000000..706abfc --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/stone/ChertStoneBlockType.java @@ -0,0 +1,25 @@ +package ru.olamedia.olacraft.world.blockTypes.stone; + +import ru.olamedia.olacraft.world.blockTypes.AbstractBlockType; + +public class ChertStoneBlockType extends AbstractBlockType { + @Override + public String getName() { + return "Chert"; + } + + @Override + public int getMaxStack() { + return 64; + } + + @Override + public String getStackTextureFile() { + return "texture/stone/sedimentary/chert.png"; + } + + @Override + public String getTopTextureFile() { + return "texture/stone/sedimentary/chert.png"; + } +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/stone/CoalStoneBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/stone/CoalStoneBlockType.java new file mode 100644 index 0000000..fe06c3d --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/stone/CoalStoneBlockType.java @@ -0,0 +1,25 @@ +package ru.olamedia.olacraft.world.blockTypes.stone; + +import ru.olamedia.olacraft.world.blockTypes.AbstractBlockType; + +public class CoalStoneBlockType extends AbstractBlockType { + @Override + public String getName() { + return "Coal"; + } + + @Override + public int getMaxStack() { + return 64; + } + + @Override + public String getStackTextureFile() { + return "texture/stone/sedimentary/coal.png"; + } + + @Override + public String getTopTextureFile() { + return "texture/stone/sedimentary/coal.png"; + } +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/stone/ConglomerateStoneBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/stone/ConglomerateStoneBlockType.java new file mode 100644 index 0000000..e3829b2 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/stone/ConglomerateStoneBlockType.java @@ -0,0 +1,25 @@ +package ru.olamedia.olacraft.world.blockTypes.stone; + +import ru.olamedia.olacraft.world.blockTypes.AbstractBlockType; + +public class ConglomerateStoneBlockType extends AbstractBlockType { + @Override + public String getName() { + return "Conglomerate"; + } + + @Override + public int getMaxStack() { + return 64; + } + + @Override + public String getStackTextureFile() { + return "texture/stone/sedimentary/conglomerate.png"; + } + + @Override + public String getTopTextureFile() { + return "texture/stone/sedimentary/conglomerate.png"; + } +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/stone/LimestoneStoneBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/stone/LimestoneStoneBlockType.java new file mode 100644 index 0000000..bb49e9c --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/stone/LimestoneStoneBlockType.java @@ -0,0 +1,25 @@ +package ru.olamedia.olacraft.world.blockTypes.stone; + +import ru.olamedia.olacraft.world.blockTypes.AbstractBlockType; + +public class LimestoneStoneBlockType extends AbstractBlockType { + @Override + public String getName() { + return "Limestone"; + } + + @Override + public int getMaxStack() { + return 64; + } + + @Override + public String getStackTextureFile() { + return "texture/stone/sedimentary/limestone.png"; + } + + @Override + public String getTopTextureFile() { + return "texture/stone/sedimentary/limestone.png"; + } +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/stone/SandstoneStoneBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/stone/SandstoneStoneBlockType.java new file mode 100644 index 0000000..c91bdce --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/stone/SandstoneStoneBlockType.java @@ -0,0 +1,25 @@ +package ru.olamedia.olacraft.world.blockTypes.stone; + +import ru.olamedia.olacraft.world.blockTypes.AbstractBlockType; + +public class SandstoneStoneBlockType extends AbstractBlockType { + @Override + public String getName() { + return "Sandstone"; + } + + @Override + public int getMaxStack() { + return 64; + } + + @Override + public String getStackTextureFile() { + return "texture/stone/sedimentary/sandstone.png"; + } + + @Override + public String getTopTextureFile() { + return "texture/stone/sedimentary/sandstone.png"; + } +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/stone/ShaleStoneBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/stone/ShaleStoneBlockType.java new file mode 100644 index 0000000..e099227 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/stone/ShaleStoneBlockType.java @@ -0,0 +1,25 @@ +package ru.olamedia.olacraft.world.blockTypes.stone; + +import ru.olamedia.olacraft.world.blockTypes.AbstractBlockType; + +public class ShaleStoneBlockType extends AbstractBlockType { + @Override + public String getName() { + return "Stone"; + } + + @Override + public int getMaxStack() { + return 64; + } + + @Override + public String getStackTextureFile() { + return "texture/stone/sedimentary/shale.png"; + } + + @Override + public String getTopTextureFile() { + return "texture/stone/sedimentary/shale.png"; + } +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/stone/SiltstoneStoneBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/stone/SiltstoneStoneBlockType.java new file mode 100644 index 0000000..db1a0f3 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/stone/SiltstoneStoneBlockType.java @@ -0,0 +1,25 @@ +package ru.olamedia.olacraft.world.blockTypes.stone; + +import ru.olamedia.olacraft.world.blockTypes.AbstractBlockType; + +public class SiltstoneStoneBlockType extends AbstractBlockType { + @Override + public String getName() { + return "Stone"; + } + + @Override + public int getMaxStack() { + return 64; + } + + @Override + public String getStackTextureFile() { + return "texture/stone/sedimentary/siltstone.png"; + } + + @Override + public String getTopTextureFile() { + return "texture/stone/sedimentary/siltstone.png"; + } +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/stone/package-info.java b/src/ru/olamedia/olacraft/world/blockTypes/stone/package-info.java new file mode 100644 index 0000000..dd284af --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/stone/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.blockTypes.stone;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/calc/LightCalculator.java b/src/ru/olamedia/olacraft/world/calc/LightCalculator.java new file mode 100644 index 0000000..7f55f71 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/calc/LightCalculator.java @@ -0,0 +1,118 @@ +package ru.olamedia.olacraft.world.calc; + +import ru.olamedia.olacraft.world.data.ChunkData; +import ru.olamedia.olacraft.world.data.ChunkDataNeighbors; +import ru.olamedia.olacraft.world.data.ChunkDataWrapper; +import ru.olamedia.olacraft.world.location.IntLocation; + +public class LightCalculator { + + private static final byte fallingLight = 15; + private static boolean exposed = true; + + public static void calculateVoidLightIgnoreNeighbors(ChunkDataWrapper dataWrapper) { + precalculateVoidLight(dataWrapper); + spreadVoidLightIgnoreNeighbors(dataWrapper); + } + + public static void precalculateVoidLight(ChunkDataWrapper dataWrapper) { + final ChunkData data = dataWrapper.getData(); + final LightData light = dataWrapper.getLight(); + for (int x = 0; x <= 15; x++) { + for (int z = 0; z <= 15; z++) { + // FIXME (heightmap) + // falling from top + exposed = true; + for (byte y = 15; y >= 0; y--) { + final short id = IntLocation.id(x, y, z); + if (data.isEmpty(id)) { + if (exposed) { + light.setVoidLight(id, fallingLight); + } else { + light.setVoidLight(id, (byte) 0); + } + } else { + exposed = false; + light.setVoidLight(id, (byte) 0); + } + } + } + } + } + + public static byte max(byte a, byte b, byte c, byte d) { + return max(max(a, b), max(c, d)); + } + + public static byte max(byte a, byte b) { + return a > b ? a : b; + } + + public static void spreadVoidLightIgnoreNeighbors(ChunkDataWrapper dataWrapper) { + final ChunkData data = dataWrapper.getData(); + final LightData light = dataWrapper.getLight(); + for (byte i = 0; i < 15; i++) { + for (byte x = 0; x <= 15; x++) { + for (byte z = 0; z <= 15; z++) { + for (byte y = 0; y <= 15; y++) { + final short id = IntLocation.id(x, y, z); + if (data.isEmpty(id)) { + final byte current = light.getVoidLight(id); + if (current < 15) { + final byte top = (y == 15) ? 0 : (byte) (light + .getVoidLight(IntLocation.id(x, y + 1, z)) - 1); + final byte bottom = (y == 0) ? 0 : (byte) (light.getVoidLight(IntLocation.id(x, y - 1, + z)) - 1); + final byte left = (x == 0) ? 0 : (byte) (light + .getVoidLight(IntLocation.id(x - 1, y, z)) - 1); + final byte right = (x == 15) ? 0 : (byte) (light.getVoidLight(IntLocation.id(x + 1, y, + z)) - 1); + final byte front = (z == 15) ? 0 : (byte) (light.getVoidLight(IntLocation.id(x, y, + z + 1)) - 1); + final byte back = (z == 0) ? 0 : (byte) (light + .getVoidLight(IntLocation.id(x, y, z - 1)) - 1); + light.setVoidLight(id, + max(max(top, bottom, left, right), max(max(front, back), current))); + } + } + } + } + } + } + } + + public static void spreadVoidLight(ChunkDataNeighbors neighbors) { + final LightData light = neighbors.getCenter().getLight(); + for (byte x = 0; x <= 15; x++) { + for (byte z = 0; z <= 15; z++) { + for (byte y = 0; y <= 15; y++) { + final LightData topData = y == 15 ? neighbors.getTop().getLight() : light; + final LightData bottomData = y == 0 ? neighbors.getBottom().getLight() : light; + final LightData leftData = x == 0 ? neighbors.getLeft().getLight() : light; + final LightData rightData = x == 15 ? neighbors.getRight().getLight() : light; + final LightData frontData = z == 15 ? neighbors.getFront().getLight() : light; + final LightData backData = z == 0 ? neighbors.getBack().getLight() : light; + final short id = IntLocation.id(x, y, z); + if (neighbors.getCenterData().isEmpty(id)) { + final byte current = light.getVoidLight(id); + if (current < 15) { + final byte top = (byte) (topData.getVoidLight(IntLocation.id(x, y + 1, z)) - 1); + final byte bottom = (byte) (bottomData.getVoidLight(IntLocation.id(x, y - 1, z)) - 1); + final byte left = (byte) (leftData.getVoidLight(IntLocation.id(x - 1, y, z)) - 1); + final byte right = (byte) (rightData.getVoidLight(IntLocation.id(x + 1, y, z)) - 1); + final byte front = (byte) (frontData.getVoidLight(IntLocation.id(x, y, z + 1)) - 1); + final byte back = (byte) (backData.getVoidLight(IntLocation.id(x, y, z - 1)) - 1); + final byte tb = (top > bottom ? top : bottom); + final byte lr = (left > right ? left : right); + final byte fb = (front > back ? front : back); + final byte tblr = (tb > lr ? tb : lr); + final byte fbc = (fb > current ? fb : current); + light.setVoidLight(id, (tblr > fbc ? tblr : fbc)); + } + } + } + } + } + } + +} diff --git a/src/ru/olamedia/olacraft/world/calc/LightData.java b/src/ru/olamedia/olacraft/world/calc/LightData.java new file mode 100644 index 0000000..62a91fd --- /dev/null +++ b/src/ru/olamedia/olacraft/world/calc/LightData.java @@ -0,0 +1,28 @@ +package ru.olamedia.olacraft.world.calc; + +public class LightData { + private byte[] light = new byte[4096]; + + public byte getVoidLight(short id) { + return (byte) (light[id] & 15); + } + + public void setVoidLight(short id, byte value) { + if (value != getVoidLight(id)) { + // voidLightChanged = true; + } + light[id] = (byte) ((getEmitLight(id) << 4) | value); + } + + public byte getEmitLight(short id) { + return (byte) ((light[id] >> 4) & 15); + } + + public void setEmitLight(short id, byte value) { + light[id] = (byte) ((light[id] & 15) | (value << 4)); + } + + public void reset() { + light = null; + } +} diff --git a/src/ru/olamedia/olacraft/world/calc/VisibilityCalculator.java b/src/ru/olamedia/olacraft/world/calc/VisibilityCalculator.java new file mode 100644 index 0000000..3009697 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/calc/VisibilityCalculator.java @@ -0,0 +1,99 @@ +package ru.olamedia.olacraft.world.calc; + +import ru.olamedia.olacraft.world.data.ChunkData; +import ru.olamedia.olacraft.world.data.ChunkDataNeighbors; +import ru.olamedia.olacraft.world.location.IntLocation; +import ru.olamedia.olacraft.world.provider.WorldProvider; + +public class VisibilityCalculator { + /** + * Compute visibility ("visible" if any side have non-opaque neighbor) + * Leaving side blocks invisible. Use computeVisibility(WorldProvider) to + * compute visibility of side blocks + */ + public static void precomputeVisibility(ChunkDataNeighbors neighbors) { + final VisibilityData v = neighbors.getCenter().getVisibility(); + // first pass, make all blocks invisible, except side blocks + v.setAllInvisible(); + // second pass, make some blocks visible + short id = 0; + for (byte x = 0; x <= 15; x++) { + for (byte y = 0; y <= 15; y++) { + for (byte z = 0; z <= 15; z++) { + if (!neighbors.isOpaque(id)) { + setVisible(v, (byte) (x - 1), y, z); + setVisible(v, (byte) (x + 1), y, z); + setVisible(v, x, (byte) (y - 1), z); + setVisible(v, x, (byte) (y + 1), z); + setVisible(v, x, y, (byte) (z - 1)); + setVisible(v, x, y, (byte) (z + 1)); + } + id++; + } + } + } + } + + public static void computeVisibility(VisibilityData v, WorldProvider provider, ChunkData left, ChunkData right, + ChunkData top, ChunkData bottom, ChunkData front, ChunkData back) { + // compute left/right + byte x, y, z; + short id; + for (y = 0; y <= 15; y++) { + for (z = 0; z <= 15; z++) { + x = 15; + id = IntLocation.id(x, y, z); + if (!left.isOpaque(provider, id)) { + x = 0; + setVisible(v, x, y, z); + } + x = 0; + id = IntLocation.id(x, y, z); + if (!right.isOpaque(provider, id)) { + x = 15; + setVisible(v, x, y, z); + } + } + } + // top/bottom + for (x = 0; x <= 15; x++) { + for (z = 0; z <= 15; z++) { + y = 15; + id = IntLocation.id(x, y, z); + if (!bottom.isOpaque(provider, id)) { + y = 0; + setVisible(v, x, y, z); + } + y = 0; + id = IntLocation.id(x, y, z); + if (!top.isOpaque(provider, id)) { + y = 15; + setVisible(v, x, y, z); + } + } + } + // front/back + for (x = 0; x <= 15; x++) { + for (y = 0; y <= 15; y++) { + z = 15; + id = IntLocation.id(x, y, z); + if (!back.isOpaque(provider, id)) { + z = 0; + setVisible(v, x, y, z); + } + z = 0; + id = IntLocation.id(x, y, z); + if (!front.isOpaque(provider, id)) { + z = 15; + setVisible(v, x, y, z); + } + } + } + } + + private static void setVisible(VisibilityData v, byte x, byte y, byte z) { + if (IntLocation.inRange(x, y, z)) { + v.setVisible(IntLocation.id(x, y, z)); + } + } +} diff --git a/src/ru/olamedia/olacraft/world/calc/VisibilityData.java b/src/ru/olamedia/olacraft/world/calc/VisibilityData.java new file mode 100644 index 0000000..3e61cb3 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/calc/VisibilityData.java @@ -0,0 +1,30 @@ +package ru.olamedia.olacraft.world.calc; + +import ru.olamedia.math.OpenBitSet; + +public class VisibilityData { + private OpenBitSet visibility = new OpenBitSet(4096); + + public void setVisible(short id) { + visibility.set(id); + } + + public void setAllInvisible() { + for (short id = 0; id < 4096; id++) { + visibility.clear(id); + } + } + + public void setInvisible(short id) { + visibility.clear(id); + } + + public boolean isVisible(short id) { + return visibility.get(id); + } + + public void reset() { + visibility = null; + } + +} diff --git a/src/ru/olamedia/olacraft/world/calc/package-info.java b/src/ru/olamedia/olacraft/world/calc/package-info.java new file mode 100644 index 0000000..ce047c7 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/calc/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.calc;
\ 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 index d02999d..3da74f2 100644 --- a/src/ru/olamedia/olacraft/world/chunk/BlockSlice.java +++ b/src/ru/olamedia/olacraft/world/chunk/BlockSlice.java @@ -10,7 +10,7 @@ import ru.olamedia.olacraft.world.provider.WorldProvider; public class BlockSlice implements Iterator<Block> { protected WorldProvider provider; - protected BlockLocation offset; + public BlockLocation offset; protected int width; protected int height; protected int depth; @@ -19,25 +19,31 @@ public class BlockSlice implements Iterator<Block> { private int itY = 0; private int itZ = 0; + private Block nearestPlaceholder = null; + Block nearestBlock = null; + public Block getNearest(MatrixCamera cam) { + nearestPlaceholder = null; + nearestBlock = null; float notEmptyBlockDistance = Float.MAX_VALUE; - Block nearestBlock = null; while (hasNext()) { Block b = next(); try { if (!b.isEmpty()) { - float d = b.getDistance(cam); - //System.out.print("d: " + d + " "); - if (d <= notEmptyBlockDistance) { + final float d = b.getDistance(cam); + if (d < notEmptyBlockDistance) { notEmptyBlockDistance = d; nearestBlock = b; } } } catch (ChunkUnavailableException e) { - //e.printStackTrace(); b.request(); } } + if (null != nearestBlock) { + nearestPlaceholder = new Block(provider, nearestBlock.location.x + nearestBlock.nearestX, + nearestBlock.location.y + +nearestBlock.nearestY, nearestBlock.location.z + +nearestBlock.nearestZ); + } return nearestBlock; } @@ -202,4 +208,8 @@ public class BlockSlice implements Iterator<Block> { public void setCenter(float x, float y, float z) { setCenter((int) x, (int) y, (int) z); } + + public Block getNearestPutBlock() { + return nearestPlaceholder; + } } diff --git a/src/ru/olamedia/olacraft/world/chunk/Chunk.java b/src/ru/olamedia/olacraft/world/chunk/Chunk.java index f390ebc..51b78c5 100644 --- a/src/ru/olamedia/olacraft/world/chunk/Chunk.java +++ b/src/ru/olamedia/olacraft/world/chunk/Chunk.java @@ -1,7 +1,8 @@ package ru.olamedia.olacraft.world.chunk; +import ru.olamedia.geom.ChunkMesh; import ru.olamedia.geom.SimpleQuadMesh; -import ru.olamedia.olacraft.world.blockTypes.BlockType; +import ru.olamedia.olacraft.world.blockRenderer.ChunkRenderer; import ru.olamedia.olacraft.world.data.ChunkData; import ru.olamedia.olacraft.world.location.BlockLocation; import ru.olamedia.olacraft.world.location.ChunkLocation; @@ -9,9 +10,7 @@ import ru.olamedia.olacraft.world.provider.WorldProvider; public class Chunk extends BlockSlice { public boolean isMeshCostructed = false; - public SimpleQuadMesh mesh; public boolean usePrevMesh = false; - public SimpleQuadMesh prevMesh; public int visibleTop = 0; public int visibleBottom = 0; @@ -19,28 +18,21 @@ public class Chunk extends BlockSlice { public int visibleRight = 0; public int visibleFront = 0; public int visibleBack = 0; + public ChunkLocation location; - public void render() { - if (isMeshCostructed) { - mesh.joglRender(); - } else if (usePrevMesh) { - prevMesh.joglRender(); - } + public ChunkMesh mesh = new ChunkMesh(); + + public void render(int pass) { + mesh.render(pass); } public void invalidate() { - if (null != mesh) { - prevMesh = mesh; - usePrevMesh = true; - if (null != mesh) { - mesh.restart(); - } - } - isMeshCostructed = false; + mesh.setValid(false); } - public Chunk(WorldProvider provider) { + public Chunk(WorldProvider provider, ChunkLocation location) { super(provider, 16, 16, 16); + setLocation(location); } /** @@ -98,159 +90,78 @@ public class Chunk extends BlockSlice { // } } + public void setMeshBrightness(ChunkData origin, ChunkData data, short id, boolean side) { + // data.calculateVoidLight(provider); + // float[] sunlight = Game.client.getScene().time.getClearColor(); + // byte lv = data.getVoidLight(id); + // light = lightValues[lv]; + // if (side && lv > 0) { + // light = lightValues[lv - 1]; + // } + // lightR = light;// * sunlight[0]; + // lightG = light;// * sunlight[1]; + // lightB = light;// * sunlight[2]; + } + + public void setMeshBrightness(SimpleQuadMesh mesh, int x, int y, int z, ChunkData data, boolean side) { + if (x < 0) { + setMeshBrightness(data, provider.getChunk(data.location.getLeft()), ChunkData.ClampID(x, y, z), side); + } else if (x > 15) { + setMeshBrightness(data, provider.getChunk(data.location.getRight()), ChunkData.ClampID(x, y, z), side); + } else if (y < 0) { + setMeshBrightness(data, provider.getChunk(data.location.getBottom()), ChunkData.ClampID(x, y, z), side); + } else if (y > 15) { + setMeshBrightness(data, provider.getChunk(data.location.getTop()), ChunkData.ClampID(x, y, z), side); + } else if (z < 0) { + setMeshBrightness(data, provider.getChunk(data.location.getBack()), ChunkData.ClampID(x, y, z), side); + } else if (z > 15) { + setMeshBrightness(data, provider.getChunk(data.location.getFront()), ChunkData.ClampID(x, y, z), side); + } else { + setMeshBrightness(data, data, ChunkData.ID(x, y, z), side); + } + } + + private float light = 0f; + private float lightR = 0f; + private float lightG = 0f; + private float lightB = 0f; + private static float[] lightValues = new float[] {// + 0.035f, // 0.035184372f, 0 + 0.043980465f, // 1 + 0.054975581f, // 2 + 0.068719477f, // 3 + 0.085899346f, // 4 + 0.107374182f, // 5 + 0.134217728f, // 6 + 0.16777216f, // 7 + 0.2097152f, // 8 + 0.262144f, // 9 + 0.32768f, // 10 + 0.4096f, // 11 + 0.512f, // 12 + 0.64f, // 13 + 0.8f, // 14 + 1f // 15 + }; + 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); + mesh.setColor4f(lightR, lightG, lightB, 1); if (y < 0) { - mesh.setColor4f(0, 0, 1, 1); + // mesh.setColor4f(0, 0, 1, 1); } else if (y > 30) { - mesh.setColor4f(1, 1, 1, 1); + // mesh.setColor4f(1, 1, 1, 1); } else { - mesh.setColor4f(1, 1, 0, 1); + // mesh.setColor4f(1, 1, 0, 1); } } /** * @return the mesh */ - public SimpleQuadMesh getMesh() { - if (!isAvailable()) { - return null; - } - if (isMeshCostructed) { - return mesh; - } - if (offset.y >= provider.getInfo().maxHeight) { - isMeshCostructed = true; - return null; + public void getMesh() { + if (!mesh.isCompiled()) { + ChunkRenderer.compile(this); } - if (offset.y < provider.getInfo().minHeight) { - isMeshCostructed = true; - return null; - } - - if (null == mesh || mesh.restart) { - ChunkData data = provider.getChunk(offset.getChunkLocation()); - data.computeVisibility(provider); - // max 14739 - System.out.println(data.visibleCount + " vis"); - mesh = new SimpleQuadMesh(14739); - //mesh = new SimpleQuadMesh(Math.min(data.visibleCount * 6, 14739)); - mesh.start(); - // 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); - BlockType grass; - for (int dx = 0; dx < 16; dx++) { - for (int dy = 0; dy < 16; dy++) { - for (int dz = 0; dz < 16; dz++) { - int x = offset.x + dx; - int y = offset.y + dy; - int z = offset.z + dz; - if (mesh.restart) { - return null; - } - // - try { - int id = dx * 16 * 16 + dy * 16 + dz; - if (data.visible.get(id) && !data.emptyBlocks.get(id)) { - grass = provider.getTypeRegistry().getBlockType( - provider.getChunk((new BlockLocation(x, y, z)).getChunkLocation()).types[id]); - 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++; - } - // System.out.println("mesh not empty"); - } else { - // System.out.println("mesh empty"); - } - } catch (ChunkUnavailableException e) { - e.printStackTrace(); - } - } - } - } - mesh.endMesh(); - data.visible = null; - isMeshCostructed = true; - return null; - } - return mesh; - } - - /** - * @param mesh - * the mesh to set - */ - public void setMesh(SimpleQuadMesh mesh) { - this.mesh = mesh; } public boolean isEmpty() { @@ -352,9 +263,22 @@ public class Chunk extends BlockSlice { public void setLocation(ChunkLocation location) { setLocation(location.getBlockLocation().x, location.getBlockLocation().y, location.getBlockLocation().z); + this.location = new ChunkLocation(location); } public boolean inWorldRange() { return (offset.y + 16 < provider.getInfo().maxHeight) && (offset.y > provider.getInfo().minHeight); } + + public boolean meshInvalid = false; + + public void markMeshInvalid() { + if (isMeshCostructed) { + meshInvalid = true; + } + } + + public ChunkData getData() { + return provider.getChunk(location); + } } diff --git a/src/ru/olamedia/olacraft/world/chunk/ChunkMeshBulder.java b/src/ru/olamedia/olacraft/world/chunk/ChunkMeshBulder.java index e823b2f..3ad2da2 100644 --- a/src/ru/olamedia/olacraft/world/chunk/ChunkMeshBulder.java +++ b/src/ru/olamedia/olacraft/world/chunk/ChunkMeshBulder.java @@ -2,9 +2,11 @@ package ru.olamedia.olacraft.world.chunk; import java.util.concurrent.ArrayBlockingQueue; +import ru.olamedia.olacraft.world.blockRenderer.ChunkRenderer; + public class ChunkMeshBulder extends Thread { public static ChunkMeshBulder instance = new ChunkMeshBulder("Mesh builder"); - private ArrayBlockingQueue<Chunk> chunks = new ArrayBlockingQueue<Chunk>(256); + private ArrayBlockingQueue<Chunk> chunks = new ArrayBlockingQueue<Chunk>(16); public ChunkMeshBulder(String name) { super(name); @@ -24,20 +26,19 @@ public class ChunkMeshBulder extends Thread { public void tick() throws InterruptedException { if (!chunks.isEmpty()) { - Chunk chunk = chunks.take(); - chunk.getMesh(); + ChunkRenderer.compile(chunks.take()); } } @Override public void run() { - // glc.makeCurrent(); while (true) { // main loop try { tick(); - if (chunks.isEmpty()){ + if (chunks.isEmpty()) { Thread.sleep(50); + } else { } // Thread.sleep(10); // or wait/join etc } catch (InterruptedException ex) { diff --git a/src/ru/olamedia/olacraft/world/chunk/ChunkSlice.java b/src/ru/olamedia/olacraft/world/chunk/ChunkSlice.java index 14e2c1f..909f0fe 100644 --- a/src/ru/olamedia/olacraft/world/chunk/ChunkSlice.java +++ b/src/ru/olamedia/olacraft/world/chunk/ChunkSlice.java @@ -12,6 +12,8 @@ public class ChunkSlice { private int height; private int depth; + public static ChunkSlice rendererInstance; + public ChunkSlice(WorldProvider provider, int width, int height, int depth) { this.provider = provider; this.width = width; @@ -20,8 +22,7 @@ public class ChunkSlice { offset = new ChunkLocation(); } - protected HashMap<String, Chunk> chunks = new HashMap<String, Chunk>(); - protected HashMap<Integer, HashMap<Integer, HashMap<Integer, Chunk>>> iChunks = new HashMap<Integer, HashMap<Integer, HashMap<Integer, Chunk>>>(); + public HashMap<Integer, HashMap<Integer, HashMap<Integer, Chunk>>> iChunks = new HashMap<Integer, HashMap<Integer, HashMap<Integer, Chunk>>>(); public Chunk getChunk(ChunkLocation location) { // int x = location.x; @@ -43,8 +44,7 @@ public class ChunkSlice { iChunks.get(location.x).put(location.y, new HashMap<Integer, Chunk>()); } - Chunk chunk = new Chunk(provider); - chunk.setLocation(location); + Chunk chunk = new Chunk(provider, location); // chunks.put(key, chunk); iChunks.get(location.x).get(location.y).put(location.z, chunk); return chunk; @@ -58,6 +58,16 @@ public class ChunkSlice { // } } + public void removeChunk(ChunkLocation location) { + if (iChunks.containsKey(location.x)) { + if (iChunks.get(location.x).containsKey(location.y)) { + if (iChunks.get(location.x).get(location.y).containsKey(location.z)) { + iChunks.get(location.x).get(location.y).remove(location.z); + } + } + } + } + /** * @return the width */ @@ -133,4 +143,5 @@ public class ChunkSlice { public void setLocation(ChunkLocation chunkOffset) { offset = chunkOffset; } + } diff --git a/src/ru/olamedia/olacraft/world/chunk/ChunkUnavailableException.java b/src/ru/olamedia/olacraft/world/chunk/ChunkUnavailableException.java index 9fef715..5fe81f6 100644 --- a/src/ru/olamedia/olacraft/world/chunk/ChunkUnavailableException.java +++ b/src/ru/olamedia/olacraft/world/chunk/ChunkUnavailableException.java @@ -1,6 +1,6 @@ package ru.olamedia.olacraft.world.chunk; -public class ChunkUnavailableException extends Exception { +public class ChunkUnavailableException extends RuntimeException { private static final long serialVersionUID = -5382060550128159125L; diff --git a/src/ru/olamedia/olacraft/world/data/ChunkData.java b/src/ru/olamedia/olacraft/world/data/ChunkData.java index 42f7811..af703c0 100644 --- a/src/ru/olamedia/olacraft/world/data/ChunkData.java +++ b/src/ru/olamedia/olacraft/world/data/ChunkData.java @@ -1,28 +1,155 @@ package ru.olamedia.olacraft.world.data; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; import ru.olamedia.math.OpenBitSet; -import ru.olamedia.olacraft.world.blockTypes.BlockType; +import ru.olamedia.olacraft.world.blockTypes.AbstractBlockType; import ru.olamedia.olacraft.world.chunk.Chunk; +import ru.olamedia.olacraft.world.drop.DroppedEntity; import ru.olamedia.olacraft.world.location.BlockLocation; import ru.olamedia.olacraft.world.location.ChunkLocation; +import ru.olamedia.olacraft.world.location.IntLocation; import ru.olamedia.olacraft.world.provider.WorldProvider; +/** + * 1 bit for opaque + * if non-opaque, some left bits will be used for light, else can be used for + * meta + * + * Opaque blocks: + * stone/cobblestone/gravel/sand(dust) is a state, 2 bits + * dirt/peat + * + * Non-opaque: + * fluids: water, acid, lava + * glass + * + * trees etc is an entities, not the blocks + * + * + * + * @author olamedia + * + */ public class ChunkData implements Serializable { private static final long serialVersionUID = -5704237444737895501L; public ChunkLocation location; - public static transient int SIZE = 4096; + private static transient int SIZE = 4096; // private boolean[] notEmpty = new boolean[SIZE]; - public OpenBitSet emptyBlocks = new OpenBitSet(4096); + private OpenBitSet emptyBlocks = new OpenBitSet(4096); public int visibleCount = 0; public OpenBitSet visible = null; // fast precomputed - // visibility (true if - // any side is open) - //public OpenBitSet sunlight = new OpenBitSet(65536); + // visibility (true if + // any side is open) + // public OpenBitSet sunlight = new OpenBitSet(65536); public byte[] types = new byte[4096]; public int notEmptyCount = 0; public boolean visibilityPrecomputed = false; + public boolean voidLightPrecomputed = false; + public boolean voidLightChanged = false; + private boolean compressionStarted = false; + private boolean isCompressed = false; + private byte[] compressed; + private ChunkDataPointer pointer = new ChunkDataPointer(); + public HashMap<Integer, AbstractBlockType> timeManagedBlocks = new HashMap<Integer, AbstractBlockType>(); + public ArrayList<DroppedEntity> droppedEntities = new ArrayList<DroppedEntity>(); + + public void invalidateComputations() { + visibilityPrecomputed = false; + voidLightPrecomputed = false; + } + + public void detachBlock(short id) { + emptyBlocks.set(id); + types[id] = 0; + } + + public void tick(WorldProvider provider) { + + } + + /** + * After populating with blocks, create entities + * + * @param provider + */ + public void initBlockEntities(WorldProvider provider) { + pointer.reset(); + while (pointer.hasNext()) { + if (!isEmpty(pointer.getId()) && types[pointer.getId()] != 0) { + AbstractBlockType type = provider.getTypeRegistry().getBlockType(types[pointer.getId()]); + // check if entity-managed block + // check if time-managed block + if (type.isTimeManaged()) { + timeManagedBlocks.put(pointer.getId(), type); + } + } + // + pointer.next(); + } + } + + public static short ID(int x, int y, int z) { + return (short) (x * 256 + y * 16 + z); + } + + public static short ClampID(BlockLocation location) { + return location.getId(); + } + + public static short ClampID(int x, int y, int z) { + return ID(x & 15, y & 15, z & 15); + } + + public void compress() { + if (!isCompressed && !compressionStarted) { + compressionStarted = true; + try { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + // GZIPOutputStream gzout = new GZIPOutputStream(bout); + ObjectOutputStream out = new ObjectOutputStream(bout); + out.writeObject(this); + compressed = bout.toByteArray(); + types = null; + emptyBlocks = null; + out.close(); + // gzout.close(); + bout.close(); + isCompressed = true; + } catch (IOException e) { + compressionStarted = false; + e.printStackTrace(); + } + } + } + + public ChunkData decompress() { + if (isCompressed) { + try { + ByteArrayInputStream bin = new ByteArrayInputStream(compressed); + // GZIPInputStream gzin = new GZIPInputStream(new + // BufferedInputStream(bin)); + ObjectInputStream in = new ObjectInputStream(bin); + ChunkData data = (ChunkData) in.readObject(); + in.close(); + // gzin.close(); + bin.close(); + return data; + } catch (IOException e) { + e.printStackTrace(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + return null; + } // public transient int[] type = new int[SIZE]; @@ -30,22 +157,16 @@ public class ChunkData implements Serializable { } private void setVisible(int x, int y, int z) { - if (x < 0 || x > 15 || y < 0 || y > 15 || z < 0 || z > 15) { - return; - } - int id = x * 16 * 16 + y * 16 + z; - if (!visible.get(id)){ + final short id = IntLocation.id(x, y, z); + if (!visible.get(id)) { visibleCount++; } visible.set(id); } private void setInvisible(int x, int y, int z) { - if (x < 0 || x > 15 || y < 0 || y > 15 || z < 0 || z > 15) { - return; - } - int id = x * 16 * 16 + y * 16 + z; - if (visible.get(id)){ + final short id = IntLocation.id(x, y, z); + if (visible.get(id)) { visibleCount--; } visible.clear(id); @@ -54,27 +175,28 @@ public class ChunkData implements Serializable { public void computeVisibility(WorldProvider provider) { visible = new OpenBitSet(4096); visibleCount = 0; - precomputeVisibility(); - computeVisibility(provider.getChunk(location.getLeft()), provider.getChunk(location.getRight()), + precomputeVisibility(provider); + computeVisibility(provider, provider.getChunk(location.getLeft()), provider.getChunk(location.getRight()), provider.getChunk(location.getTop()), provider.getChunk(location.getBottom()), provider.getChunk(location.getFront()), provider.getChunk(location.getBack())); } - public void computeVisibility(ChunkData left, ChunkData right, ChunkData top, ChunkData bottom, ChunkData front, - ChunkData back) { + public void computeVisibility(WorldProvider provider, ChunkData left, ChunkData right, ChunkData top, + ChunkData bottom, ChunkData front, ChunkData back) { // compute left/right - int x, y, z, id; + int x, y, z; + short id; for (y = 0; y <= 15; y++) { for (z = 0; z <= 15; z++) { x = 15; - id = x * 16 * 16 + y * 16 + z; - if (left.emptyBlocks.get(id)) { + id = IntLocation.id(x, y, z); + if (!left.isOpaque(provider, id)) { x = 0; setVisible(x, y, z); } x = 0; - id = x * 16 * 16 + y * 16 + z; - if (right.emptyBlocks.get(id)) { + id = IntLocation.id(x, y, z); + if (!right.isOpaque(provider, id)) { x = 15; setVisible(x, y, z); } @@ -84,14 +206,14 @@ public class ChunkData implements Serializable { for (x = 0; x <= 15; x++) { for (z = 0; z <= 15; z++) { y = 15; - id = x * 16 * 16 + y * 16 + z; - if (bottom.emptyBlocks.get(id)) { + id = IntLocation.id(x, y, z); + if (!bottom.isOpaque(provider, id)) { y = 0; setVisible(x, y, z); } y = 0; - id = x * 16 * 16 + y * 16 + z; - if (top.emptyBlocks.get(id)) { + id = IntLocation.id(x, y, z); + if (!top.isOpaque(provider, id)) { y = 15; setVisible(x, y, z); } @@ -101,14 +223,14 @@ public class ChunkData implements Serializable { for (x = 0; x <= 15; x++) { for (y = 0; y <= 15; y++) { z = 15; - id = x * 16 * 16 + y * 16 + z; - if (back.emptyBlocks.get(id)) { + id = IntLocation.id(x, y, z); + if (!back.isOpaque(provider, id)) { z = 0; setVisible(x, y, z); } z = 0; - id = x * 16 * 16 + y * 16 + z; - if (front.emptyBlocks.get(id)) { + id = IntLocation.id(x, y, z); + if (!front.isOpaque(provider, id)) { z = 15; setVisible(x, y, z); } @@ -118,9 +240,10 @@ public class ChunkData implements Serializable { /** * Compute visibility ("visible" if any side have non-opaque neighbor) - * Leaving side blocks invisible. Use computeVisibility(WorldProvider) to compute visibility of side blocks + * Leaving side blocks invisible. Use computeVisibility(WorldProvider) to + * compute visibility of side blocks */ - public void precomputeVisibility() { + public void precomputeVisibility(WorldProvider provider) { // first pass, make all blocks invisible, except side blocks for (int x = 0; x <= 15; x++) { for (int y = 0; y <= 15; y++) { @@ -140,7 +263,7 @@ public class ChunkData implements Serializable { for (int y = 0; y <= 15; y++) { for (int z = 0; z <= 15; z++) { int id = x * 16 * 16 + y * 16 + z; - if (emptyBlocks.get(id)) { + if (!isOpaque(provider, id)) { setVisible(x - 1, y, z); setVisible(x + 1, y, z); setVisible(x, y - 1, z); @@ -154,13 +277,17 @@ public class ChunkData implements Serializable { visibilityPrecomputed = true; } + public boolean isOpaque(WorldProvider provider, int id) { + return !isEmpty(id) && provider.getTypeRegistry().isOpaque(types[id]); + } + public void compact() { - if (emptyBlocks.cardinality() == 0) { + if (notEmptyCount == 0) { // emptyBlocks = null; } } - public BlockType getType(BlockLocation blockLocation, WorldProvider provider) { + public AbstractBlockType getType(BlockLocation blockLocation, WorldProvider provider) { if (emptyBlocks == null) { return null; } @@ -215,4 +342,14 @@ public class ChunkData implements Serializable { setEmpty(id, isEmpty); } + public void freeRenderData() { + visible = null; + // light = null; + // voidLightPrecomputed = false; + } + + public void addDroppedEntity(DroppedEntity droppedEntity) { + droppedEntities.add(droppedEntity); + } + } diff --git a/src/ru/olamedia/olacraft/world/data/ChunkDataManager.java b/src/ru/olamedia/olacraft/world/data/ChunkDataManager.java new file mode 100644 index 0000000..ba5b50a --- /dev/null +++ b/src/ru/olamedia/olacraft/world/data/ChunkDataManager.java @@ -0,0 +1,22 @@ +package ru.olamedia.olacraft.world.data; + +import ru.olamedia.olacraft.world.provider.WorldProvider; + +public class ChunkDataManager { + private ChunkData data; + private ChunkDataPointer pointer = new ChunkDataPointer(); + private WorldProvider provider; + + public void setProvider(WorldProvider provider){ + this.provider = provider; + } + + public void setData(ChunkData data) { + this.data = data; + pointer.reset(); + } + + private void loadNeighbors(){ + + } +} diff --git a/src/ru/olamedia/olacraft/world/data/ChunkDataNeighbors.java b/src/ru/olamedia/olacraft/world/data/ChunkDataNeighbors.java new file mode 100644 index 0000000..de82b5b --- /dev/null +++ b/src/ru/olamedia/olacraft/world/data/ChunkDataNeighbors.java @@ -0,0 +1,162 @@ +package ru.olamedia.olacraft.world.data; + +import ru.olamedia.olacraft.world.calc.LightCalculator; +import ru.olamedia.olacraft.world.calc.VisibilityCalculator; +import ru.olamedia.olacraft.world.location.ChunkLocation; +import ru.olamedia.olacraft.world.provider.WorldProvider; + +public class ChunkDataNeighbors { + private static byte CENTER = 0; + private static byte LEFT = 1; + private static byte RIGHT = 2; + private static byte TOP = 3; + private static byte BOTTOM = 4; + private static byte FRONT = 5; + private static byte BACK = 6; + private WorldProvider provider; + private ChunkLocation center; + private ChunkDataWrapper data; + private ChunkDataWrapper left; + private ChunkDataWrapper right; + private ChunkDataWrapper top; + private ChunkDataWrapper bottom; + private ChunkDataWrapper front; + private ChunkDataWrapper back; + private ChunkDataWrapper[] chunks; + + public ChunkDataNeighbors() { + chunks = new ChunkDataWrapper[7]; + for (byte i = 0; i < 7; i++) { + chunks[i] = new ChunkDataWrapper(); + } + left = new ChunkDataWrapper(); + right = new ChunkDataWrapper(); + top = new ChunkDataWrapper(); + bottom = new ChunkDataWrapper(); + front = new ChunkDataWrapper(); + back = new ChunkDataWrapper(); + data = new ChunkDataWrapper(); + center = new ChunkLocation(); + } + + public void setProvider(WorldProvider provider) { + this.provider = provider; + } + + public void setData(ChunkData data) { + this.data.setData(data); + center.set(data.location); + chunks[CENTER].setData(data); + } + + public void loadNeighbors() { + top.setData(provider.getChunk(center.getTop())); + bottom.setData(provider.getChunk(center.getBottom())); + left.setData(provider.getChunk(center.getLeft())); + right.setData(provider.getChunk(center.getRight())); + front.setData(provider.getChunk(center.getFront())); + back.setData(provider.getChunk(center.getBack())); + chunks[TOP].setData(top.getData()); + chunks[BOTTOM].setData(bottom.getData()); + chunks[LEFT].setData(left.getData()); + chunks[RIGHT].setData(right.getData()); + chunks[FRONT].setData(front.getData()); + chunks[BACK].setData(back.getData()); + } + + public ChunkDataWrapper getCenter() { + return data; + } + + public ChunkData getCenterData() { + return data.getData(); + } + + public ChunkDataWrapper getTop() { + return top; + } + + public ChunkDataWrapper getBottom() { + return bottom; + } + + public ChunkDataWrapper getLeft() { + return left; + } + + public ChunkDataWrapper getRight() { + return right; + } + + public ChunkDataWrapper getFront() { + return front; + } + + public ChunkDataWrapper getBack() { + return back; + } + + public ChunkData getTopData() { + return top.getData(); + } + + public ChunkData getBottomData() { + return bottom.getData(); + } + + public ChunkData getLeftData() { + return left.getData(); + } + + public ChunkData getRightData() { + return right.getData(); + } + + public ChunkData getFrontData() { + return front.getData(); + } + + public ChunkData getBackData() { + return back.getData(); + } + + public void calcLight() { + LightCalculator.calculateVoidLightIgnoreNeighbors(top); + LightCalculator.calculateVoidLightIgnoreNeighbors(bottom); + LightCalculator.calculateVoidLightIgnoreNeighbors(left); + LightCalculator.calculateVoidLightIgnoreNeighbors(right); + LightCalculator.calculateVoidLightIgnoreNeighbors(front); + LightCalculator.calculateVoidLightIgnoreNeighbors(back); + LightCalculator.precalculateVoidLight(data); + LightCalculator.spreadVoidLight(this); + } + + public void reset() { + provider = null; + data.reset(); + top.reset(); + bottom.reset(); + left.reset(); + right.reset(); + front.reset(); + back.reset(); + } + + public ChunkLocation getLocation() { + return center; + } + + public boolean isOpaque(short id) { + return !data.getData().isEmpty(id) && provider.getTypeRegistry().isOpaque(data.getData().types[id]); + } + + public boolean isVisible(short id) { + return data.getVisibility().isVisible(id) && !data.getData().isEmpty(id) && (0 != data.getData().types[id]); + } + + public void calcVisibility() { + VisibilityCalculator.precomputeVisibility(this); + VisibilityCalculator.computeVisibility(data.getVisibility(), provider, getLeftData(), getRightData(), + getTopData(), getBottomData(), getFrontData(), getBackData()); + } +} diff --git a/src/ru/olamedia/olacraft/world/data/ChunkDataPointer.java b/src/ru/olamedia/olacraft/world/data/ChunkDataPointer.java new file mode 100644 index 0000000..2c0f059 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/data/ChunkDataPointer.java @@ -0,0 +1,82 @@ +package ru.olamedia.olacraft.world.data; + +import ru.olamedia.olacraft.world.chunk.Chunk; + +/** + * pointer.reset() + * while (pointer.hasNext()){ + * int id = pointer.getId() + * ... + * pointer.next() + * } + * @author olamedia + * + */ +public class ChunkDataPointer { + private int x = 0; + private int y = 0; + private int z = 0; + private int id = 0; + + public ChunkDataPointer() { + reset(); + } + + public ChunkDataPointer(int x, int y, int z) { + if (x >= 0 && x < 16) { + if (y >= 0 && y < 16) { + if (z >= 0 && z < 16) { + this.x = x; + this.y = y; + this.z = z; + id = this.x * 16 * 16 + this.y * 16 + this.z; + return; + } + } + } + this.x = Chunk.in(x); + this.y = Chunk.in(y); + this.z = Chunk.in(z); + id = this.x * 16 * 16 + this.y * 16 + this.z; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + public int getZ() { + return z; + } + + public int getId() { + return id; + } + + public void reset() { + x = 0; + y = 0; + z = 0; + id = 0; + } + + public boolean hasNext() { + return id < 4096; + } + + public void next() { + id++; + x++; + if (x > 15) { + x = 0; + y++; + if (y > 15) { + y = 0; + z++; + } + } + } +} diff --git a/src/ru/olamedia/olacraft/world/data/ChunkDataWrapper.java b/src/ru/olamedia/olacraft/world/data/ChunkDataWrapper.java new file mode 100644 index 0000000..ae0f582 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/data/ChunkDataWrapper.java @@ -0,0 +1,40 @@ +package ru.olamedia.olacraft.world.data; + +import ru.olamedia.math.OpenBitSet; +import ru.olamedia.olacraft.world.calc.LightData; +import ru.olamedia.olacraft.world.calc.VisibilityData; + +public class ChunkDataWrapper { + private ChunkData data; + private LightData light; + private VisibilityData visibility; + + public ChunkDataWrapper() { + light = new LightData(); + visibility = new VisibilityData(); + } + + public void setData(ChunkData data) { + this.data = data; + } + + public ChunkData getData() { + return data; + } + + public LightData getLight() { + return light; + } + + public VisibilityData getVisibility() { + return visibility; + } + + public void reset() { + data = null; + light.reset(); + light = null; + visibility.reset(); + visibility = null; + } +} diff --git a/src/ru/olamedia/olacraft/world/data/RegionData.java b/src/ru/olamedia/olacraft/world/data/RegionData.java index f58a424..cdc4497 100644 --- a/src/ru/olamedia/olacraft/world/data/RegionData.java +++ b/src/ru/olamedia/olacraft/world/data/RegionData.java @@ -24,10 +24,18 @@ public class RegionData implements Serializable { public HeightMap heightMap = new HeightMap(256, 256); public SectorData[][] sectorData = new SectorData[16][16]; - public RegionData(){ - + public RegionData() { + + } + + public void compress() { + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + sectorData[x][z].compress(); + } + } } - + public void writeTo(OutputStream stream) throws IOException { ObjectOutputStream out = new ObjectOutputStream(stream); out.writeObject(this); @@ -50,7 +58,7 @@ public class RegionData implements Serializable { public ChunkData getChunkData(ChunkLocation chunkLocation) { SectorData sector = getSectorData(chunkLocation.getSectorLocation()); int y = Chunk.in(chunkLocation.y + 128); // minHeight = -128 - return sector.chunkData[y]; + return sector.get(y); } public SectorData getSectorData(SectorLocation sectorLocation) { @@ -58,4 +66,12 @@ public class RegionData implements Serializable { int z = Chunk.in(sectorLocation.z); return sectorData[x][z]; } + + public void decompress() { + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + sectorData[x][z].decompress(); + } + } + } } diff --git a/src/ru/olamedia/olacraft/world/data/SectorData.java b/src/ru/olamedia/olacraft/world/data/SectorData.java index 31526a7..76414d4 100644 --- a/src/ru/olamedia/olacraft/world/data/SectorData.java +++ b/src/ru/olamedia/olacraft/world/data/SectorData.java @@ -10,26 +10,56 @@ import ru.olamedia.olacraft.world.location.SectorLocation; * @author olamedia * */ -public class SectorData implements Serializable{ +public class SectorData implements Serializable { private static final long serialVersionUID = 5304471397211814748L; - public HeightMap heightMap = new HeightMap(16, 16); // locations of highest nonempty blocks - public ChunkData[] chunkData = new ChunkData[16]; // 256/16 = 16 + public HeightMap heightMap = new HeightMap(16, 16); // locations of highest + // nonempty blocks + protected ChunkData[] chunkData = new ChunkData[16]; // 256/16 = 16 public SectorLocation location; - public SectorData(){ - + public SectorData() { + } - + public static int yIndex(int y) { return (y + 128) / 16; - // 1: (-128 + 128) / 16 = 0 + // 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(){ + + public static SectorData generate() { SectorData data = new SectorData(); return data; } + + public void compress() { + /* + * for (int y = 0; y < 16; y++) { + * chunkData[y].compress(); + * } + */ + } + + public void set(int y, ChunkData data) { + // data.compress(); + chunkData[y] = data; + } + + public ChunkData get(int y) { + /* + * if (chunkData[y].isCompressed){ + * return chunkData[y].decompress(); + * } + */ + return chunkData[y]; + } + + public void decompress() { + for (int y = 0; y < 16; y++) { + // chunkData[y] = chunkData[y].decompress(); + } + } } diff --git a/src/ru/olamedia/olacraft/world/dataProvider/AbstractChunkDataProvider.java b/src/ru/olamedia/olacraft/world/dataProvider/AbstractChunkDataProvider.java index 1670ef3..495fae4 100644 --- a/src/ru/olamedia/olacraft/world/dataProvider/AbstractChunkDataProvider.java +++ b/src/ru/olamedia/olacraft/world/dataProvider/AbstractChunkDataProvider.java @@ -1,5 +1,6 @@ package ru.olamedia.olacraft.world.dataProvider; +import ru.olamedia.olacraft.world.block.BlockRegistry; import ru.olamedia.olacraft.world.data.ChunkData; import ru.olamedia.olacraft.world.data.RegionData; import ru.olamedia.olacraft.world.data.SectorData; @@ -8,6 +9,13 @@ import ru.olamedia.olacraft.world.location.RegionLocation; import ru.olamedia.olacraft.world.location.SectorLocation; abstract public class AbstractChunkDataProvider { + + protected BlockRegistry types; + + public void setTypeRegistry(BlockRegistry types) { + this.types = types; + } + /** * is data already available or we should wait * @@ -30,9 +38,9 @@ abstract public class AbstractChunkDataProvider { * @param RegionLocation */ public void loadChunk(ChunkLocation chunkLocation) { - //System.out.println("loadChunk(" + chunkLocation + ")"); + // System.out.println("loadChunk(" + chunkLocation + ")"); this.loadRegion(chunkLocation.getRegionLocation()); - //System.out.println("loadChunk(" + chunkLocation + ")--"); + // System.out.println("loadChunk(" + chunkLocation + ")--"); } public void loadSector(SectorLocation sectorLocation) { diff --git a/src/ru/olamedia/olacraft/world/dataProvider/CachedChunkDataProvider.java b/src/ru/olamedia/olacraft/world/dataProvider/CachedChunkDataProvider.java index 1e6c0c1..d779a40 100644 --- a/src/ru/olamedia/olacraft/world/dataProvider/CachedChunkDataProvider.java +++ b/src/ru/olamedia/olacraft/world/dataProvider/CachedChunkDataProvider.java @@ -1,62 +1,69 @@ package ru.olamedia.olacraft.world.dataProvider; +import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; +import ru.olamedia.olacraft.game.Game; +import ru.olamedia.olacraft.world.block.BlockRegistry; import ru.olamedia.olacraft.world.data.RegionData; +import ru.olamedia.olacraft.world.location.BlockLocation; +import ru.olamedia.olacraft.world.location.ChunkLocation; 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 ConcurrentHashMap<String, Integer> ticks = new ConcurrentHashMap<String, Integer>(); + private HashMap<RegionLocation, RegionData> regionMap = new HashMap<RegionLocation, RegionData>(); + + private RegionData current; public CachedChunkDataProvider(AbstractChunkDataProvider provider) { this.provider = provider; + this.provider.setTypeRegistry(types); + } + + @Override + public void setTypeRegistry(BlockRegistry types) { + super.setTypeRegistry(types); + this.provider.setTypeRegistry(types); } private static boolean DEBUG = true; private void debug(String s) { if (DEBUG) { - System.out.println("[CachedChunkDataProvider] " + s); + System.err.println("[CachedChunkDataProvider] " + s); } } - @SuppressWarnings("unused") - private void tick(String key) { - ticks.put(key, 0); - gc(); + private boolean containsKey(RegionLocation l) { + return regionMap.containsKey(l); } - private void gc() { - Iterator<String> keys = ticks.keySet().iterator(); - while (keys.hasNext()) { - String key = keys.next(); - ticks.put(key, ticks.get(key) + 1); - if (ticks.get(key) > 30) { - ticks.remove(key); - regionMap.remove(key); - } - } + // private boolean containsKey(int x, int y, int z) { + // return regionMap.containsKey(x) && regionMap.get(x).containsKey(y) && + // regionMap.get(x).get(y).containsKey(z); + // } + + private void put(RegionLocation l, RegionData data) { + regionMap.put(l, data); + } + + private RegionData get(RegionLocation l) { + return regionMap.get(l); } @Override public boolean isRegionAvailable(RegionLocation regionLocation) { - String key = regionLocation.toString();// regionLocation.x + "-" + - if (regionMap.containsKey(key)) { + if (regionMap.containsKey(regionLocation)) { return true; } + debug("regions: " + regionMap.size() + ""); return provider.isRegionAvailable(regionLocation); } @Override public void loadRegion(RegionLocation regionLocation) { - String key = regionLocation.toString(); - // debug("loadRegion(" + regionLocation + ")"); - if (!regionMap.containsKey(key)) { + if (!containsKey(regionLocation)) { provider.loadRegion(regionLocation); } else { debug("error: loadRegion(" + regionLocation + ") already in regionMap"); @@ -65,15 +72,37 @@ public class CachedChunkDataProvider extends AbstractChunkDataProvider { @Override public RegionData getRegion(RegionLocation regionLocation) { - String key = regionLocation.toString(); - // tick(key); - if (regionMap.containsKey(key)) { - return regionMap.get(key); + if (containsKey(regionLocation)) { + return get(regionLocation); } else { - RegionData data = provider.getRegion(regionLocation); - regionMap.put(key, data); - return data; + put(regionLocation, provider.getRegion(regionLocation)); + gc(); + return get(regionLocation); } } + public void unloadRegion(RegionLocation regionLocation) { + regionMap.remove(regionLocation); + } + + private ArrayList<RegionLocation> gcKeys = new ArrayList<RegionLocation>(); + + public void gc() { + if (Game.instance.player != null && regionMap.size() > 4) { + final BlockLocation b = Game.instance.player.getCameraBlockLocation(); + final RegionLocation r = b.getRegionLocation(); + for (RegionLocation l : regionMap.keySet()) { + if ((l.x > r.x + 1) || (l.x < r.x - 1)) { + if ((l.z > r.z + 1) || (l.z < r.z - 1)) { + gcKeys.add(l); + } + } + } + for (RegionLocation l : gcKeys) { + unloadRegion(l); + } + gcKeys.clear(); + regionMap.clear(); + } + } } diff --git a/src/ru/olamedia/olacraft/world/dataProvider/LocalChunkDataProvider.java b/src/ru/olamedia/olacraft/world/dataProvider/LocalChunkDataProvider.java index 887421f..4464b96 100644 --- a/src/ru/olamedia/olacraft/world/dataProvider/LocalChunkDataProvider.java +++ b/src/ru/olamedia/olacraft/world/dataProvider/LocalChunkDataProvider.java @@ -83,48 +83,50 @@ public class LocalChunkDataProvider extends AbstractChunkDataProvider { @SuppressWarnings("unused") @Override public RegionData getRegion(RegionLocation regionLocation) { - String filename = path + File.separator + regionLocation.getFilename(); - RegionData data = null; - if (true) { - return generateRegion(regionLocation); - } - File chunkFile = new File(filename); - if (false && chunkFile.exists()) { - InputStream in; - try { - FileInputStream fIn = new FileInputStream(chunkFile); - in = new GZIPInputStream(fIn); - data = RegionData.loadFrom(in); - in.close(); - fIn.close(); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } - } else { - data = generateRegion(regionLocation); - OutputStream out; - try { - chunkFile.createNewFile(); - FileOutputStream fOut = new FileOutputStream(chunkFile); - out = new GZIPOutputStream(fOut); - data.writeTo(out); - out.close(); - fOut.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - return data; + // String filename = path + File.separator + + // regionLocation.getFilename(); + // RegionData data = null; + return generateRegion(regionLocation); + // File chunkFile = new File(filename); + // if (false && chunkFile.exists()) { + // InputStream in; + // try { + // FileInputStream fIn = new FileInputStream(chunkFile); + // in = new GZIPInputStream(fIn); + // data = RegionData.loadFrom(in); + // in.close(); + // fIn.close(); + // } catch (FileNotFoundException e) { + // e.printStackTrace(); + // } catch (IOException e) { + // e.printStackTrace(); + // } catch (ClassNotFoundException e) { + // e.printStackTrace(); + // } + // } else { + // data = generateRegion(regionLocation); + // OutputStream out; + // try { + // chunkFile.createNewFile(); + // FileOutputStream fOut = new FileOutputStream(chunkFile); + // out = new GZIPOutputStream(fOut); + // data.writeTo(out); + // out.close(); + // fOut.close(); + // } catch (IOException e) { + // e.printStackTrace(); + // } + // } + // return data; } + RegionGenerator generator; + public RegionData generateRegion(RegionLocation regionLocation) { - RegionData data = new RegionData(); + final RegionData data = new RegionData(); data.location = regionLocation; RegionGenerator generator = new RegionGenerator(); + generator.setTypes(types); try { generator.setSeed(getSeed()); } catch (IOException e) { diff --git a/src/ru/olamedia/olacraft/world/dataProvider/RemoteChunkDataProvider.java b/src/ru/olamedia/olacraft/world/dataProvider/RemoteChunkDataProvider.java index 0c52ced..1f860d6 100644 --- a/src/ru/olamedia/olacraft/world/dataProvider/RemoteChunkDataProvider.java +++ b/src/ru/olamedia/olacraft/world/dataProvider/RemoteChunkDataProvider.java @@ -17,7 +17,7 @@ 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 HashMap<RegionLocation, RegionData> map = new HashMap<RegionLocation, RegionData>(); private List<String> loading = new ArrayList<String>(); private List<RegionLocation> queue = new ArrayList<RegionLocation>(); @@ -51,14 +51,13 @@ public class RemoteChunkDataProvider extends AbstractChunkDataProvider implement if (loading.contains(key)) { return false; } - return map.containsKey(key); + return map.containsKey(regionLocation); } @Override public RegionData getRegion(RegionLocation regionLocation) { - String key = regionLocation.toString(); - RegionData data = map.get(key); - map.remove(key); + RegionData data = map.get(regionLocation); + map.remove(regionLocation); return data; } @@ -67,10 +66,10 @@ public class RemoteChunkDataProvider extends AbstractChunkDataProvider implement if (p instanceof RegionDataPacket) { debug("received packet [conn " + connection.getID() + "]: RegionDataPacket"); RegionData data = ((RegionDataPacket) p).data; - System.out.println(data.sectorData[0][0].chunkData[15].isEmpty(0) + ""); - String key = data.location.toString(); - map.put(key, data); - loading.remove(key); + data.decompress(); + //System.out.println(data.sectorData[0][0].get(15).isEmpty(0) + ""); + map.put(data.location, data); + loading.remove(data.location); } } diff --git a/src/ru/olamedia/olacraft/world/drop/DroppedEntity.java b/src/ru/olamedia/olacraft/world/drop/DroppedEntity.java new file mode 100644 index 0000000..0d2fede --- /dev/null +++ b/src/ru/olamedia/olacraft/world/drop/DroppedEntity.java @@ -0,0 +1,17 @@ +package ru.olamedia.olacraft.world.drop; + +import ru.olamedia.olacraft.world.blockStack.BlockStack; +import ru.olamedia.olacraft.world.blockTypes.AbstractBlockType; +import ru.olamedia.olacraft.world.location.BlockLocation; +import ru.olamedia.olacraft.world.location.Location3f; + +public class DroppedEntity { + public DroppedEntity(BlockLocation location, AbstractBlockType type, int count) { + this.location = new Location3f(location); + this.location.addRandomOffset(0.4f); + stack = new BlockStack(type, count); + } + + public Location3f location; + public BlockStack stack; +} diff --git a/src/ru/olamedia/olacraft/world/drop/package-info.java b/src/ru/olamedia/olacraft/world/drop/package-info.java new file mode 100644 index 0000000..d349368 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/drop/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.drop;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/fluid/FluidLevel.java b/src/ru/olamedia/olacraft/world/fluid/FluidLevel.java new file mode 100644 index 0000000..8e90e3c --- /dev/null +++ b/src/ru/olamedia/olacraft/world/fluid/FluidLevel.java @@ -0,0 +1,9 @@ +package ru.olamedia.olacraft.world.fluid; + +import java.util.HashMap; + +public class FluidLevel { + public HashMap<Integer, FluidLine> lines = new HashMap<Integer, FluidLine>(); + public float fluidLevel = 1f; + public int size = 0; +} diff --git a/src/ru/olamedia/olacraft/world/fluid/FluidLine.java b/src/ru/olamedia/olacraft/world/fluid/FluidLine.java new file mode 100644 index 0000000..9dc8d44 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/fluid/FluidLine.java @@ -0,0 +1,56 @@ +package ru.olamedia.olacraft.world.fluid; + +import java.util.ArrayList; + +import ru.olamedia.olacraft.world.data.ChunkData; +import ru.olamedia.olacraft.world.location.BlockLocation; +import ru.olamedia.olacraft.world.provider.WorldProvider; + +public class FluidLine { + public int y; + public int z; + public int start; + public int finish; + public int size; + + public FluidLine(int x, int y, int z) { + this.start = this.finish = x; + this.y = y; + this.z = z; + } + + public FluidLine(BlockLocation location) { + this.start = this.finish = location.x; + this.y = location.y; + this.z = location.z; + } + + public ArrayList<FluidLine> getSideLines(WorldProvider provider) { + ArrayList<FluidLine> sideLines; + sideLines = getSideLines(provider, z + 1); + sideLines.addAll(getSideLines(provider, z - 1)); + return sideLines; + } + + public ArrayList<FluidLine> getSideLines(WorldProvider provider, int z) { + ArrayList<FluidLine> sideLines = new ArrayList<FluidLine>(); + BlockLocation test = new BlockLocation(start, y, z); + boolean found = false; + FluidLine side = null; + while (test.x < finish) { + ChunkData data = provider.getChunk(test.getChunkLocation()); + if (data.isEmpty(test)) { + found = true; + side = new FluidLine(test); + } else { + if (found) { + side.finish = test.x; + sideLines.add(side); + found = false; + } + } + test.x++; + } + return sideLines; + } +} diff --git a/src/ru/olamedia/olacraft/world/fluid/FluidSource.java b/src/ru/olamedia/olacraft/world/fluid/FluidSource.java new file mode 100644 index 0000000..17bffe8 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/fluid/FluidSource.java @@ -0,0 +1,99 @@ +package ru.olamedia.olacraft.world.fluid; + +import java.util.HashMap; +import java.util.List; + +import ru.olamedia.olacraft.world.data.ChunkData; +import ru.olamedia.olacraft.world.location.BlockLocation; +import ru.olamedia.olacraft.world.provider.WorldProvider; + +public class FluidSource { + public HashMap<Integer, FluidLevel> levels = new HashMap<Integer, FluidLevel>(); + int minY = 0; + int maxY = 0; + + public FluidSource(int y) { + minY = y; + maxY = y; + } + + public void flow(WorldProvider provider, BlockLocation location, float amount) { + ChunkData data = provider.getChunk(location.getChunkLocation()); + if (!data.isEmpty(location)) { + return; + } + FluidLevel level = null; + int y = location.y; + while (null == level || amount > 0) { + level = getFluidLevel(provider, location); + if (null == level) { + return; + } + if (level.size < amount) { + level.fluidLevel = 1f; + amount--; + } else { + level.fluidLevel = ((float) level.size) / amount; + } + levels.put(y, level); + y++; + } + } + + private FluidLevel getFluidLevel(WorldProvider provider, BlockLocation location) { + ChunkData data = provider.getChunk(location.getChunkLocation()); + if (!data.isEmpty(location)) { + return null; + } + FluidLevel level = new FluidLevel(); + FluidLine startLine = getFluidLine(provider, location); + + if (location.z > 0) { + BlockLocation test = new BlockLocation(location); + for (test.z = location.z - 1; test.z >= 0; test.z--) { + test.x = startLine.start; + FluidLine nextLine = getFluidLine(provider, test); + if (null != nextLine) { + test.x = nextLine.finish + 2; + if (test.x <= 15) { + // continue + }else{ + // + } + } + } + } + return null; + } + + private FluidLine getFluidLine(WorldProvider provider, BlockLocation location) { + ChunkData data = provider.getChunk(location.getChunkLocation()); + if (!data.isEmpty(location)) { + return null; + } + FluidLine line = new FluidLine(location); + line.start = line.finish = location.x; + BlockLocation test = new BlockLocation(location); + if (location.x > 0) { + for (test.x = location.x - 1; test.x >= 0; test.x--) { + if (!data.isEmpty(test)) { + break; + } + line.start = test.x; + } + } else { + line.start = 0; + } + if (location.x < 15) { + for (test.x = location.x + 1; test.x <= 15; test.x++) { + if (!data.isEmpty(test)) { + break; + } + line.finish = test.x; + } + } else { + line.finish = 15; + } + return line; + } +} diff --git a/src/ru/olamedia/olacraft/world/fluid/package-info.java b/src/ru/olamedia/olacraft/world/fluid/package-info.java new file mode 100644 index 0000000..d2764d9 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/fluid/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.fluid;
\ 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 index 649961f..5d6d0d5 100644 --- a/src/ru/olamedia/olacraft/world/generator/HeightMapGenerator.java +++ b/src/ru/olamedia/olacraft/world/generator/HeightMapGenerator.java @@ -1,6 +1,5 @@ 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; @@ -58,7 +57,7 @@ public class HeightMapGenerator { // MOUNTAINS mountainsNoise = new RidgedMulti(); mountainsNoise.setFrequency(0.04); - mountainsNoise.setOctaveCount(6); + mountainsNoise.setOctaveCount(4); turbulence = new Turbulence(mountainsNoise); turbulence.setFrequency(0.2); turbulence.setPower(1); @@ -105,7 +104,7 @@ public class HeightMapGenerator { // finalTerrain.setEdgeFalloff(1.25); NoiseMap heightMap = new NoiseMap(16, 16); - builder.setSourceModule(maxTerrain); + builder.setSourceModule(blendedTerrain); builder.setDestNoiseMap(heightMap); double bx = chunkX; double bz = chunkZ; @@ -118,7 +117,7 @@ public class HeightMapGenerator { for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { // System.out.print(((float) heights[x][z]) + ";"); - ints[x][z] = (int) (50 + minValue + (maxValue - minValue) * (heights[x][z] + 1) / 2); + ints[x][z] = (int) (minValue + (maxValue - minValue) * (heights[x][z] + 1) / 2); } } // System.out.println(""); @@ -138,8 +137,6 @@ public class HeightMapGenerator { builder.setSourceModule(finalTerrain); builder.setDestNoiseMap(heightMap); builder.setDestSize(256, 256); - float bx = location.getBlockLocation().x; - float bz = location.getBlockLocation().z; float cx = location.getChunkLocation().x; float cz = location.getChunkLocation().z; builder.setBounds(cx, cx + 16, cz, cz + 16); diff --git a/src/ru/olamedia/olacraft/world/generator/HumiditySelectLayer.java b/src/ru/olamedia/olacraft/world/generator/HumiditySelectLayer.java new file mode 100644 index 0000000..63d25c6 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/generator/HumiditySelectLayer.java @@ -0,0 +1,31 @@ +package ru.olamedia.olacraft.world.generator; + +import libnoiseforjava.NoiseGen.NoiseQuality; +import libnoiseforjava.exception.ExceptionInvalidParam; +import libnoiseforjava.module.Perlin; +import libnoiseforjava.module.RidgedMulti; + +public class HumiditySelectLayer { + protected long seed; + + protected Perlin noise = new Perlin(); + //protected RidgedMulti noise = new RidgedMulti(); + + public HumiditySelectLayer() { + noise.setNoiseQuality(NoiseQuality.QUALITY_BEST); + try { + noise.setOctaveCount(5); + noise.setFrequency(0.004); + } catch (ExceptionInvalidParam e) { + e.printStackTrace(); + } + } + + public void setSeed(int seed) { + noise.setSeed(seed); + } + + public double getHumidity(double x, double z) { + return noise.getValue(x, 0, z); + } +} diff --git a/src/ru/olamedia/olacraft/world/generator/IslandSelectLayer.java b/src/ru/olamedia/olacraft/world/generator/IslandSelectLayer.java new file mode 100644 index 0000000..facfc3b --- /dev/null +++ b/src/ru/olamedia/olacraft/world/generator/IslandSelectLayer.java @@ -0,0 +1,31 @@ +package ru.olamedia.olacraft.world.generator; + +import libnoiseforjava.NoiseGen.NoiseQuality; +import libnoiseforjava.exception.ExceptionInvalidParam; +import libnoiseforjava.module.Perlin; +import libnoiseforjava.module.RidgedMulti; + +public class IslandSelectLayer { + protected long seed; + + protected Perlin noise = new Perlin(); + //protected RidgedMulti noise = new RidgedMulti(); + + public IslandSelectLayer() { + noise.setNoiseQuality(NoiseQuality.QUALITY_BEST); + try { + noise.setOctaveCount(5); + noise.setFrequency(0.004); + } catch (ExceptionInvalidParam e) { + e.printStackTrace(); + } + } + + public void setSeed(int seed) { + noise.setSeed(seed); + } + + public double getHeight(double x, double z) { + return noise.getValue(x, 0, z); + } +} diff --git a/src/ru/olamedia/olacraft/world/generator/MountainSelectLayer.java b/src/ru/olamedia/olacraft/world/generator/MountainSelectLayer.java new file mode 100644 index 0000000..5c0390f --- /dev/null +++ b/src/ru/olamedia/olacraft/world/generator/MountainSelectLayer.java @@ -0,0 +1,38 @@ +package ru.olamedia.olacraft.world.generator; + +import libnoiseforjava.NoiseGen.NoiseQuality; +import libnoiseforjava.exception.ExceptionInvalidParam; +import libnoiseforjava.module.Perlin; +import libnoiseforjava.module.RidgedMulti; + +public class MountainSelectLayer { + protected long seed; + + protected Perlin mountainNoise = new Perlin(); + protected Perlin hillNoise = new Perlin(); + + public MountainSelectLayer() { + hillNoise.setNoiseQuality(NoiseQuality.QUALITY_BEST); + mountainNoise.setNoiseQuality(NoiseQuality.QUALITY_BEST); + try { + hillNoise.setOctaveCount(5); + hillNoise.setFrequency(0.004); + mountainNoise.setOctaveCount(7); + mountainNoise.setFrequency(0.004); + } catch (ExceptionInvalidParam e) { + e.printStackTrace(); + } + } + + public void setSeed(int seed) { + hillNoise.setSeed(seed); + mountainNoise.setSeed(seed); + } + + private double val; + + public double getHeight(double x, double z) { + val = mountainNoise.getValue(x, 0, z); + return (val > 0) ? 1 - val : 1 + val; + } +} diff --git a/src/ru/olamedia/olacraft/world/generator/OceanSelectLayer.java b/src/ru/olamedia/olacraft/world/generator/OceanSelectLayer.java new file mode 100644 index 0000000..f0ca567 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/generator/OceanSelectLayer.java @@ -0,0 +1,31 @@ +package ru.olamedia.olacraft.world.generator; + +import libnoiseforjava.NoiseGen.NoiseQuality; +import libnoiseforjava.exception.ExceptionInvalidParam; +import libnoiseforjava.module.Perlin; +import libnoiseforjava.module.RidgedMulti; + +public class OceanSelectLayer { + protected long seed; + + protected Perlin noise = new Perlin(); + //protected RidgedMulti noise = new RidgedMulti(); + + public OceanSelectLayer() { + noise.setNoiseQuality(NoiseQuality.QUALITY_BEST); + try { + noise.setOctaveCount(5); + noise.setFrequency(0.0004); + } catch (ExceptionInvalidParam e) { + e.printStackTrace(); + } + } + + public void setSeed(int seed) { + noise.setSeed(seed); + } + + public double getHeight(double x, double z) { + return noise.getValue(x, 0, z); + } +} diff --git a/src/ru/olamedia/olacraft/world/generator/RegionGenerator.java b/src/ru/olamedia/olacraft/world/generator/RegionGenerator.java index 79ac898..8156b65 100644 --- a/src/ru/olamedia/olacraft/world/generator/RegionGenerator.java +++ b/src/ru/olamedia/olacraft/world/generator/RegionGenerator.java @@ -1,5 +1,18 @@ package ru.olamedia.olacraft.world.generator; +import java.nio.IntBuffer; +import java.util.Random; + +import libnoiseforjava.exception.ExceptionInvalidParam; +import libnoiseforjava.module.Perlin; +import ru.olamedia.olacraft.world.biome.Biome; +import ru.olamedia.olacraft.world.block.BlockRegistry; +import ru.olamedia.olacraft.world.blockTypes.GrassBlockType; +import ru.olamedia.olacraft.world.blockTypes.IceBlockType; +import ru.olamedia.olacraft.world.blockTypes.SnowBlockType; +import ru.olamedia.olacraft.world.blockTypes.TallGrassBlockType; +import ru.olamedia.olacraft.world.blockTypes.WaterBlockType; +import ru.olamedia.olacraft.world.blockTypes.stone.SandstoneStoneBlockType; import ru.olamedia.olacraft.world.chunk.Chunk; import ru.olamedia.olacraft.world.data.ChunkData; import ru.olamedia.olacraft.world.data.HeightMap; @@ -7,10 +20,23 @@ 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.IntLocation; import ru.olamedia.olacraft.world.location.SectorLocation; public class RegionGenerator { private int[] seed; + private Random rand; + + private OceanSelectLayer oceanSelect = new OceanSelectLayer(); + private IslandSelectLayer islandSelect = new IslandSelectLayer(); + private TemperatureSelectLayer tempSelect = new TemperatureSelectLayer(); + private HumiditySelectLayer humSelect = new HumiditySelectLayer(); + private RiverSelectLayer riverSelect = new RiverSelectLayer(); + private MountainSelectLayer mountainSelect = new MountainSelectLayer(); + private BlockRegistry types; + + private byte waterId; + private byte iceId; public void setSeed(int[] seed) { this.seed = seed; @@ -20,13 +46,229 @@ public class RegionGenerator { System.out.println("[RegionGenerator] " + s); } + private int[] heightCache; + private double[] temps; + private double[] hums; + private int[] biome; + private boolean[] initialized; + private boolean[] water; + + protected Perlin erosionNoise = new Perlin(); + + public double avg(double a, double b) { + return (a + b) / 2; + } + + public double blend(double... args) { + double x = 0; + for (int i = 0; i < args.length; i++) { + x += args[i]; + } + return x / args.length; + } + + public int getHeight(int vid, int x, int z) { // vid - vertical id + if (!initialized[vid]) { + double height = 0; + double oceanHeight = Math.min(0, oceanSelect.getHeight(x, z) * 100); + double isleHeight = islandSelect.getHeight(x, z) * 4; + double riverHeight = riverSelect.getHeight(x, z) * 15; + double temp = 10;// tempSelect.getTemperature(x, z) * 40; // -40..40 + double humidity = humSelect.getHumidity(x, z) * 50 + 50; // 0..100 + double mountain = mountainSelect.getHeight(x, z) * 20; + temps[vid] = temp; + hums[vid] = humidity; + height = mountain;// blend(oceanHeight, isleHeight); + if (oceanHeight < 0) { + water[vid] = true; + height = (int) Math.max(-120, oceanHeight); + } else { + water[vid] = false; + // height = (int) Math.max(0, avg(oceanHeight, avg(isleHeight, + // avg(oceanHeight, mountain)))); + } + + biome[vid] = Biome.land; + // + // if (oceanHeight > 0) { + // // materic + // biome[vid] = Biome.land; + // height = isleHeight; + // if (mountain > 1) { + // height = isleHeight; + // } + // if (riverHeight < 0) { + // // RIVERS + // water[vid] = true; + // height = riverHeight; + // } else { + // if (temp > 30) { + // biome[vid] = Biome.desert; + // } + // } + // } else { + // if (isleHeight > 0) { + // // island core + // height = 2; + // biome[vid] = Biome.island; + // } else if (oceanHeight > -3 && isleHeight > -10) { + // // half-island merged + // height = 1; + // biome[vid] = Biome.island; + // } else { + // water[vid] = true; + // height = -2; + // } + // } + + // return (int) height; + heightCache[vid] = (int) height; + initialized[vid] = true; + } + return heightCache[vid]; + } + + public static int clampFloat(float x, float min, float max) { // x in -1..1 + return (int) (min + (max - min) * ((1 + x) / 2)); + } + + // BlockLocation blockOffset = new BlockLocation(); + + private IntBuffer blockLocation = IntLocation.allocate(); + private IntBuffer blockOffset = IntLocation.allocate(); + private IntBuffer chunkLocation = IntLocation.allocate(); + private IntBuffer chunkOffset = IntLocation.allocate(); + + public void generateSector(SectorData sector) { + heightCache = new int[256]; + temps = new double[256]; + hums = new double[256]; + biome = new int[256]; + initialized = new boolean[256]; + water = new boolean[256]; + for (int i = 0; i < 256; i++) { + initialized[i] = false; + water[i] = false; + } + sector.heightMap = new HeightMap(16, 16); + for (int y = 0; y < 16; y++) { + // CREATE CHUNK + final ChunkData chunk = new ChunkData(); + chunk.location = new ChunkLocation(sector.location.x, y, sector.location.z); + IntLocation.set(chunkLocation, sector.location.x, y, sector.location.z); + IntLocation.chunk2block(chunkLocation, chunkOffset); + // final BlockLocation chunkOffset = + // chunk.location.getBlockLocation(); + for (int inChunkX = 0; inChunkX < 16; inChunkX++) { + for (int inChunkZ = 0; inChunkZ < 16; inChunkZ++) { + final int vid = inChunkX * 16 + inChunkZ; + final int height = getHeight(vid, sector.location.x * 16 + inChunkX, sector.location.z * 16 + + inChunkZ); + // int height = 60; + // System.out.println("height: " + height); + sector.heightMap.setHeight(inChunkX, inChunkZ, height); + IntLocation.setXZ(blockOffset, inChunkX, inChunkZ); + for (int inChunkY = 0; inChunkY < 16; inChunkY++) { + IntLocation.setY(blockOffset, inChunkY); + IntLocation.setSum(blockLocation, chunkOffset, blockOffset); + blockID = IntLocation.id(blockLocation); + // height = sector.heightMap.getHeight(inChunkX, + // inChunkZ); + makeBlock(chunk, vid); + + } + } + } + // debug(sector.heightMap.toString()); + chunk.compact(); + sector.set(y, chunk); + } + } + + private int blockHeight; + private int blockY; + private int blockID; + + private void makeBlock(ChunkData chunk, int vid) { + if (null == types) { + throw new RuntimeException("types is null"); + } + blockHeight = getHeight(vid, 0, 0); // coordinates makes no difference + // as + // cached already + blockY = IntLocation.getY(blockLocation); + blockID = IntLocation.id(blockLocation); + /* + * double erosion = erosionNoise.getValue(blockOffset.x, blockOffset.y, + * blockOffset.z); + * if (erosion > 0.99) { + * chunk.setEmpty(blockOffset, true); + * return; + * } + */ + // WATER: + if (blockY <= 0) { + if (water[vid]) { + if (blockY > blockHeight) { + chunk.setEmpty(blockID, false); + chunk.types[blockID] = waterId; + if (temps[vid] < -10) { + chunk.types[blockID] = iceId; + } + return; + } + } + } + if (blockY > blockHeight) { + // AIR + chunk.setEmpty(blockID, true); + if (blockY - 1 == blockHeight) { + // floor level + if (temps[vid] > 15 && temps[vid] < 25 && hums[vid] > 30 && hums[vid] < 70) { + if (rand.nextInt(15) > 2) { + chunk.setEmpty(blockID, false); + chunk.types[blockID] = (byte) (types.getBlockIdByClassName(TallGrassBlockType.class.getName())); // FIXME, + } + } + } + } else { + // LAND + chunk.setEmpty(blockID, false); + if (temps[vid] > 30) { + chunk.types[blockID] = (byte) types.getBlockIdByClassName(SandstoneStoneBlockType.class.getName()); + } else if (temps[vid] < -10 && hums[vid] > 30) { + chunk.types[blockID] = (byte) (types.getBlockIdByClassName(SnowBlockType.class.getName())); // FIXME, + // SNOW + } else { + chunk.types[blockID] = (byte) (types.getBlockIdByClassName(GrassBlockType.class.getName()));// (1 + // + + // Math.random() + // * + // 11); + } + } + } + public void generate(RegionData data) { + final SectorLocation sectorOffset = data.location.getSectorLocation(); HeightMapGenerator.minValue = -5; HeightMapGenerator.maxValue = 60; HeightMapGenerator.init(); HeightMapGenerator.seed = seed[0]; + oceanSelect.setSeed(seed[0]); + islandSelect.setSeed(seed[1]); + tempSelect.setSeed(seed[2]); + humSelect.setSeed(seed[3]); + riverSelect.setSeed(seed[4]); + rand = new Random(seed[6]); + erosionNoise.setFrequency(0.01); + try { + erosionNoise.setOctaveCount(5); + } catch (ExceptionInvalidParam e) { + e.printStackTrace(); + } + erosionNoise.setSeed(seed[5]); // BlockLocation blockOffset = data.location.getBlockLocation(); - SectorLocation sectorOffset = data.location.getSectorLocation(); // int[][] heightMap = // HeightMapGenerator.getHeightMap(data.location.getBlockLocation().x, // data.location.getBlockLocation().z, 256, 256); @@ -37,51 +279,41 @@ public class RegionGenerator { for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { // CREATE SECTOR - SectorData sector = new SectorData(); + final SectorData sector = new SectorData(); sector.location = new SectorLocation(sectorOffset.x + x, sectorOffset.z + z); - sector.heightMap = new HeightMap(16, 16); - sector.chunkData = new ChunkData[16]; - for (int y = 0; y < 16; y++) { - // CREATE CHUNK - ChunkData chunk = new ChunkData(); - chunk.location = new ChunkLocation(sector.location.x, y, sector.location.z); - BlockLocation chunkOffset = chunk.location.getBlockLocation(); - for (int inChunkX = 0; inChunkX < 16; inChunkX++) { - for (int inChunkZ = 0; inChunkZ < 16; inChunkZ++) { - int height = data.heightMap.getHeight(x * 16 + inChunkX, z * 16 + inChunkZ); - // System.out.println("height: " + height); - sector.heightMap.setHeight(inChunkX, inChunkZ, height); - BlockLocation blockOffset = new BlockLocation(); - blockOffset.x = chunkOffset.x + inChunkX; - blockOffset.z = chunkOffset.z + inChunkZ; - for (int inChunkY = 0; inChunkY < 16; inChunkY++) { - blockOffset.y = chunkOffset.y + inChunkY; - // height = sector.heightMap.getHeight(inChunkX, - // inChunkZ); - if (blockOffset.y > height) { - // System.out.println("--- height: " + - // height + " block:" + blockOffset); - chunk.setEmpty(blockOffset, true); - } else { - if (blockOffset.y > 0) { - // System.out.println("+++ height: " + - // height + " block:" + blockOffset); - // System.out.println("not empty, height: " - // + height); - } - int id = Chunk.in(blockOffset.x) * 16 * 16 + Chunk.in(blockOffset.y) * 16 - + Chunk.in(blockOffset.z); - chunk.setEmpty(blockOffset, false); - chunk.types[id] = (byte) (1 + Math.random() * 4); - } - } - } - } - chunk.compact(); - sector.chunkData[y] = chunk; - } + generateSector(sector); data.sectorData[x][z] = sector; } } } + + public void setTypes(BlockRegistry types) { + this.types = types; + waterId = (byte) types.getBlockIdByClassName(WaterBlockType.class.getName()); + iceId = (byte) types.getBlockIdByClassName(IceBlockType.class.getName()); + } + + 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/RiverSelectLayer.java b/src/ru/olamedia/olacraft/world/generator/RiverSelectLayer.java new file mode 100644 index 0000000..a7b7c3e --- /dev/null +++ b/src/ru/olamedia/olacraft/world/generator/RiverSelectLayer.java @@ -0,0 +1,56 @@ +package ru.olamedia.olacraft.world.generator; + +import libnoiseforjava.NoiseGen.NoiseQuality; +import libnoiseforjava.exception.ExceptionInvalidParam; +import libnoiseforjava.module.Perlin; +import libnoiseforjava.module.RidgedMulti; + +public class RiverSelectLayer { + + protected Perlin noise = new Perlin(); + protected Perlin widthNoise = new Perlin(); + protected Perlin deepNoise = new Perlin(); + + // protected RidgedMulti noise = new RidgedMulti(); + + public RiverSelectLayer() { + noise.setNoiseQuality(NoiseQuality.QUALITY_BEST); + widthNoise.setNoiseQuality(NoiseQuality.QUALITY_BEST); + deepNoise.setNoiseQuality(NoiseQuality.QUALITY_BEST); + try { + noise.setOctaveCount(5); + noise.setFrequency(0.000004); + widthNoise.setOctaveCount(6); + widthNoise.setFrequency(0.004); + deepNoise.setOctaveCount(3); + deepNoise.setFrequency(0.004); + } catch (ExceptionInvalidParam e) { + e.printStackTrace(); + } + } + + public void setSeed(int seed) { + noise.setSeed(seed); + widthNoise.setSeed(seed); + deepNoise.setSeed(seed); + } + + static double min = -0.0005; + static double max = 0; + private static double deepFactor = 0; + + public static double scale(double value) { + final double factor = 1 / (max - min); + final double r01 = (value - min) * factor; // 0..1 + final double r3 = r01 > 0.5 ? -r01 : -r01; + return -(1 - Math.abs(1 - r01 * 2)) * deepFactor; + } + + public double getHeight(double x, double z) { + final double widthFactor = widthNoise.getValue(x, 0, z); + deepFactor = (deepNoise.getValue(x, 0, z) + 1.2) / 2.2; + min = -0.000005 * (1 + (1 + widthFactor) * 40); + final double value = noise.getValue(x, 0, z); + return value >= min && value <= max ? scale(value) : 0; + } +} diff --git a/src/ru/olamedia/olacraft/world/generator/TemperatureSelectLayer.java b/src/ru/olamedia/olacraft/world/generator/TemperatureSelectLayer.java new file mode 100644 index 0000000..ca3902f --- /dev/null +++ b/src/ru/olamedia/olacraft/world/generator/TemperatureSelectLayer.java @@ -0,0 +1,31 @@ +package ru.olamedia.olacraft.world.generator; + +import libnoiseforjava.NoiseGen.NoiseQuality; +import libnoiseforjava.exception.ExceptionInvalidParam; +import libnoiseforjava.module.Perlin; +import libnoiseforjava.module.RidgedMulti; + +public class TemperatureSelectLayer { + protected long seed; + + protected Perlin noise = new Perlin(); + //protected RidgedMulti noise = new RidgedMulti(); + + public TemperatureSelectLayer() { + noise.setNoiseQuality(NoiseQuality.QUALITY_BEST); + try { + noise.setOctaveCount(5); + noise.setFrequency(0.004); + } catch (ExceptionInvalidParam e) { + e.printStackTrace(); + } + } + + public void setSeed(int seed) { + noise.setSeed(seed); + } + + public double getTemperature(double x, double z) { + return noise.getValue(x, 0, z); + } +} diff --git a/src/ru/olamedia/olacraft/world/location/BlockLocation.java b/src/ru/olamedia/olacraft/world/location/BlockLocation.java index 9639ac1..371c084 100644 --- a/src/ru/olamedia/olacraft/world/location/BlockLocation.java +++ b/src/ru/olamedia/olacraft/world/location/BlockLocation.java @@ -2,70 +2,110 @@ package ru.olamedia.olacraft.world.location; import java.io.Serializable; -import ru.olamedia.olacraft.world.chunk.Chunk; - -public class BlockLocation implements Serializable { +public class BlockLocation extends Location3i implements Serializable { private static final long serialVersionUID = -4987461467575474762L; - public int x; - public int y; - public int z; + private static int yChunkShift = 128; public BlockLocation() { } + public byte getByteX() { + return (byte) (x & 15); + } + + public int getChunkX() { + return (int) (x >> 4); + } + + public int getRegionX() { + return (int) (x >> 8); + } + + public byte getByteY() { + return (byte) (y & 15); + } + + public int getChunkY() { + return (int) ((y + yChunkShift) >> 4); + } + + public int getRegionY() { + return (int) ((y + yChunkShift) >> 8); + } + + public byte getByteZ() { + return (byte) (z & 15); + } + + public int getChunkZ() { + return (int) (z >> 4); + } + + public int getRegionZ() { + return (int) (z >> 8); + } + + public short getId() { + return IntLocation.id(x, y, z); + } + public boolean isChunkEdge() { - int cx = Chunk.in(x); - int cy = Chunk.in(y); - int cz = Chunk.in(z); + int cx = getByteX(); + int cy = getByteY(); + int cz = getByteZ(); return (cx == 0 || cy == 0 || cz == 0 || cx == 15 || cy == 15 || cz == 15); } public boolean isChunkLeftEdge() { - return Chunk.in(x) == 0; + return getByteX() == 0; } public boolean isChunkRightEdge() { - return Chunk.in(x) == 15; + return getByteX() == 15; } public boolean isChunkTopEdge() { - return Chunk.in(y) == 15; + return getByteY() == 15; } public boolean isChunkBottomEdge() { - return Chunk.in(y) == 0; + return getByteY() == 0; } public boolean isChunkFrontEdge() { - return Chunk.in(z) == 15; + return getByteZ() == 15; } public boolean isChunkBackEdge() { - return Chunk.in(z) == 0; + return getByteZ() == 0; } public BlockLocation(int x, int y, int z) { - this.x = x; - this.y = y; - this.z = z; + super(x, y, z); } public BlockLocation(float x, float y, float z) { - this.x = (int) x; - this.y = (int) y; - this.z = (int) z; + super(x, y, z); + } + + public BlockLocation(Location3i location) { + super(location); + } + + public BlockLocation(Location3f location) { + super(location); } public ChunkLocation getChunkLocation() { - return new ChunkLocation(Chunk.v(x), Chunk.v(y + 128), Chunk.v(z)); + return new ChunkLocation(getChunkX(), getChunkY(), getChunkZ()); } public RegionLocation getRegionLocation() { - return new RegionLocation(Chunk.v(Chunk.v(x)), Chunk.v(Chunk.v(z))); + return new RegionLocation(getRegionX(), getRegionZ()); } public SectorLocation getSectorLocation() { - return new SectorLocation(Chunk.v(x), Chunk.v(z)); + return new SectorLocation(getChunkX(), getChunkZ()); } public String toString() { diff --git a/src/ru/olamedia/olacraft/world/location/ChunkLocation.java b/src/ru/olamedia/olacraft/world/location/ChunkLocation.java index 439b9be..73a9c16 100644 --- a/src/ru/olamedia/olacraft/world/location/ChunkLocation.java +++ b/src/ru/olamedia/olacraft/world/location/ChunkLocation.java @@ -4,28 +4,19 @@ import java.io.Serializable; import ru.olamedia.olacraft.world.chunk.Chunk; -public class ChunkLocation implements Serializable { +public class ChunkLocation extends Location3i 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; + super(x, y, z); } - public ChunkLocation(ChunkLocation loc) { - this.x = loc.x; - this.y = loc.y; - this.z = loc.z; + public ChunkLocation(Location3i cameraChunk) { + super(cameraChunk); } - public int x; - public int y; - public int z; + public ChunkLocation() { + } public SectorLocation getSectorLocation() { return new SectorLocation(x, z); diff --git a/src/ru/olamedia/olacraft/world/location/IntLocation.java b/src/ru/olamedia/olacraft/world/location/IntLocation.java new file mode 100644 index 0000000..3ee7110 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/location/IntLocation.java @@ -0,0 +1,200 @@ +package ru.olamedia.olacraft.world.location; + +import java.nio.IntBuffer; + +public class IntLocation { + private static int yShift = 128; + + public static IntBuffer allocate() { + return IntBuffer.allocate(3); + } + + public static boolean inRange(int x, int y, int z) { + return inRange(x) && inRange(y) && inRange(z); + } + + public static boolean inRange(int val) { + return (val >= 0) && (val <= 15); + } + + public static byte in(int val) { + return (byte) (val & 15); + } + + public static int chunk(int val) { + return val >> 4; + } + + public static int region(int val) { + return val >> 8; + } + + public static int rev(int val) { + return val * 16; + } + + public static int rev2(int val) { + return val * 256; + } + + public static short id(int x, int y, int z) { + return (short) ((x & 15) * 256 + (y & 15) * 16 + (z & 15)); + } + + public static short leftId(int x, int y, int z) { + return id(x - 1, y, z); + } + + public static short rightId(int x, int y, int z) { + return id(x + 1, y, z); + } + + public static short topId(int x, int y, int z) { + return id(x, y + 1, z); + } + + public static short bottomId(int x, int y, int z) { + return id(x, y - 1, z); + } + + public static short backId(int x, int y, int z) { + return id(x, y, z + 1); + } + + public static short frontId(int x, int y, int z) { + return id(x, y, z - 1); + } + + public static int[] block2chunk(int[] b) { + return new int[] { chunk(b[0]), chunk(b[1] + yShift), chunk(b[2]) }; + } + + public static void block2chunk(int[] b, int[] c) { + c[0] = chunk(b[0]); + c[1] = chunk(b[1] + yShift); + c[2] = chunk(b[2]); + } + + public static void block2chunk(IntBuffer b, IntBuffer c) { + c.put(0, chunk(b.get(0))); + c.put(1, chunk(b.get(1) + yShift)); + c.put(2, chunk(b.get(2))); + } + + public static int[] chunk2block(int[] c) { + return new int[] { rev(c[0]), rev(c[1]) - yShift, rev(c[2]) }; + } + + public static void chunk2block(int[] c, int[] b) { + b[0] = rev(c[0]); + b[1] = rev(c[1]) - yShift; + b[2] = rev(c[2]); + } + + public static void chunk2block(IntBuffer c, IntBuffer b) { + b.put(0, rev(c.get(0))); + b.put(1, rev(c.get(1)) - yShift); + b.put(2, rev(c.get(2))); + } + + public static int[] region2chunk(int[] r) { + return new int[] { rev(r[0]), rev(r[1]), rev(r[2]) }; + } + + public static void region2chunk(int[] r, int[] c) { + c[0] = rev(r[0]); + c[1] = rev(r[1]); + c[2] = rev(r[2]); + } + + public static void region2chunk(IntBuffer r, IntBuffer c) { + c.put(0, rev(r.get(0))); + c.put(1, rev(r.get(1))); + c.put(2, rev(r.get(2))); + } + + public static int[] region2block(int[] r) { + return new int[] { rev2(r[0]), rev2(r[1]) - yShift, rev2(r[2]) }; + } + + public static void region2block(int[] r, int[] b) { + b[0] = rev2(r[0]); + b[1] = rev2(r[1]) - yShift; + b[2] = rev2(r[2]); + } + + public static void region2block(IntBuffer r, IntBuffer b) { + b.put(0, rev2(r.get(0))); + b.put(1, rev2(r.get(1)) - yShift); + b.put(2, rev2(r.get(2))); + } + + public static int[] block2region(int[] b) { + return new int[] { chunk(chunk(b[0])), chunk(chunk(b[1] + yShift)), chunk(chunk(b[2])) }; + } + + public static void block2region(int[] b, int[] r) { + r[0] = region(b[0]); + r[1] = region(b[1] + yShift); + r[2] = region(b[2]); + } + + public static void block2region(IntBuffer b, IntBuffer r) { + r.put(0, region(b.get(0))); + r.put(1, region(b.get(1) + yShift)); + r.put(2, region(b.get(2))); + } + + public static int[] chunk2region(int[] c) { + return new int[] { chunk(c[0]), chunk(c[1]), chunk(c[2]) }; + } + + public static void chunk2region(int[] c, int[] r) { + r[0] = chunk(c[0]); + r[1] = chunk(c[1]); + r[2] = chunk(c[2]); + } + + public static void chunk2region(IntBuffer c, IntBuffer r) { + r.put(0, chunk(c.get(0))); + r.put(1, chunk(c.get(1))); + r.put(2, chunk(c.get(2))); + } + + public static void set(IntBuffer b, int x, int y, int z) { + b.put(0, x); + b.put(1, y); + b.put(2, z); + } + + public static void setXZ(IntBuffer b, int x, int z) { + b.put(0, x); + b.put(2, z); + } + + public static void setY(IntBuffer b, int y) { + b.put(1, y); + } + + public static int getX(IntBuffer b) { + return b.get(0); + } + + public static int getY(IntBuffer b) { + return b.get(1); + } + + public static int getZ(IntBuffer b) { + return b.get(2); + } + + public static int id(IntBuffer b) { + return id(b.get(0), b.get(1), b.get(2)); + } + + public static void setSum(IntBuffer target, IntBuffer b1, IntBuffer b2) { + target.put(0, b1.get(0) + b2.get(0)); + target.put(1, b1.get(1) + b2.get(1)); + target.put(2, b1.get(2) + b2.get(2)); + } +} diff --git a/src/ru/olamedia/olacraft/world/location/Location3f.java b/src/ru/olamedia/olacraft/world/location/Location3f.java new file mode 100644 index 0000000..a30c6d7 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/location/Location3f.java @@ -0,0 +1,46 @@ +package ru.olamedia.olacraft.world.location; + +public class Location3f { + public float x; + public float y; + public float z; + + public Location3f() { + x = 0; + y = 0; + z = 0; + } + + public Location3f(float x, float y, float z) { + this.x = x; + this.y = y; + this.z = z; + } + + public Location3f(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + public Location3f(Location3f location) { + x = location.x; + y = location.y; + z = location.z; + } + + public Location3f(Location3i location) { + x = location.x; + y = location.y; + z = location.z; + } + + public String toString() { + return "Location3f[" + x + "," + y + "," + z + "]"; + } + + public void addRandomOffset(float d) { + x += Math.random() * d * 2 - d; + z += Math.random() * d * 2 - d; + } +} diff --git a/src/ru/olamedia/olacraft/world/location/Location3i.java b/src/ru/olamedia/olacraft/world/location/Location3i.java new file mode 100644 index 0000000..347e4bc --- /dev/null +++ b/src/ru/olamedia/olacraft/world/location/Location3i.java @@ -0,0 +1,71 @@ +package ru.olamedia.olacraft.world.location; + +public class Location3i { + public int x; + public int y; + public int z; + + public byte getByteX() { + return (byte) (x & 15); + } + + public byte getByteY() { + return (byte) (y & 15); + } + + public byte getByteZ() { + return (byte) (z & 15); + } + + public Location3i() { + x = 0; + y = 0; + z = 0; + } + + public Location3i(float x, float y, float z) { + this.x = (int) x; + this.y = (int) y; + this.z = (int) z; + } + + public Location3i(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + public Location3i(Location3i location) { + x = location.x; + y = location.y; + z = location.z; + } + + public Location3i(Location3f location) { + x = (int) location.x; + y = (int) location.y; + z = (int) location.z; + } + + public void set(Location3i location) { + this.x = location.x; + this.y = location.y; + this.z = location.z; + } + + public void set(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + public void set(float x, float y, float z) { + this.x = (int) x; + this.y = (int) y; + this.z = (int) z; + } + + public String toString() { + return "Location3i[" + x + "," + y + "," + z + "]"; + } +} diff --git a/src/ru/olamedia/olacraft/world/location/MetaLocation3i.java b/src/ru/olamedia/olacraft/world/location/MetaLocation3i.java new file mode 100644 index 0000000..e440572 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/location/MetaLocation3i.java @@ -0,0 +1,7 @@ +package ru.olamedia.olacraft.world.location; + +import java.nio.IntBuffer; + +public class MetaLocation3i { + private IntBuffer b = IntBuffer.allocate(3); +} diff --git a/src/ru/olamedia/olacraft/world/location/RegionLocation.java b/src/ru/olamedia/olacraft/world/location/RegionLocation.java index a1100c0..c11d3c8 100644 --- a/src/ru/olamedia/olacraft/world/location/RegionLocation.java +++ b/src/ru/olamedia/olacraft/world/location/RegionLocation.java @@ -36,4 +36,40 @@ public class RegionLocation implements Serializable { public BlockLocation getBlockLocation() { return new BlockLocation(Chunk.rev(Chunk.rev(x)), 0, Chunk.rev(Chunk.rev(z))); } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + x; + result = prime * result + z; + return result; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + RegionLocation other = (RegionLocation) obj; + if (x != other.x) + return false; + if (z != other.z) + return false; + return true; + } + } diff --git a/src/ru/olamedia/olacraft/world/provider/IWorldProvider.java b/src/ru/olamedia/olacraft/world/provider/IWorldProvider.java new file mode 100644 index 0000000..5605728 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/provider/IWorldProvider.java @@ -0,0 +1,11 @@ +package ru.olamedia.olacraft.world.provider; + +import ru.olamedia.olacraft.world.WorldInfo; + +public interface IWorldProvider { + public boolean hasInfo(); + + public void requestInfo(); + + public WorldInfo getInfo(); +} diff --git a/src/ru/olamedia/olacraft/world/provider/LocalWorld.java b/src/ru/olamedia/olacraft/world/provider/LocalWorld.java new file mode 100644 index 0000000..1756118 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/provider/LocalWorld.java @@ -0,0 +1,24 @@ +package ru.olamedia.olacraft.world.provider; + +import ru.olamedia.olacraft.network.provider.LocalProvider; +import ru.olamedia.olacraft.world.WorldInfo; + +public class LocalWorld implements IWorldProvider { + private LocalProvider<WorldInfo> info; + + public LocalWorld() { + info.put(new WorldInfo()); + } + + public boolean hasInfo() { + return true; + } + + public void requestInfo() { + // do nothing + } + + public WorldInfo getInfo() { + return info.get(); + } +} diff --git a/src/ru/olamedia/olacraft/world/provider/RemoteWorld.java b/src/ru/olamedia/olacraft/world/provider/RemoteWorld.java new file mode 100644 index 0000000..d086bf1 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/provider/RemoteWorld.java @@ -0,0 +1,32 @@ +package ru.olamedia.olacraft.world.provider; + +import ru.olamedia.olacraft.network.provider.CacheProvider; +import ru.olamedia.olacraft.network.provider.RemoteProvider; +import ru.olamedia.olacraft.world.WorldInfo; + +public class RemoteWorld implements IWorldProvider { + private CacheProvider<WorldInfo> info; + + public RemoteWorld() { + info = new CacheProvider<WorldInfo>(new RemoteProvider<WorldInfo>() { + @Override + public void request() { + + } + }); + } + + public boolean hasInfo() { + return info.has(); + } + + public void requestInfo() { + info.request(); + } + + @Override + public WorldInfo getInfo() { + return info.get(); + } + +} diff --git a/src/ru/olamedia/olacraft/world/provider/WorldProvider.java b/src/ru/olamedia/olacraft/world/provider/WorldProvider.java index 7471b52..decf24d 100644 --- a/src/ru/olamedia/olacraft/world/provider/WorldProvider.java +++ b/src/ru/olamedia/olacraft/world/provider/WorldProvider.java @@ -6,25 +6,86 @@ import ru.olamedia.olacraft.world.block.Block; import ru.olamedia.olacraft.world.block.BlockRegistry; import ru.olamedia.olacraft.world.blockTypes.AbstractBlockType; import ru.olamedia.olacraft.world.blockTypes.BlockType; +import ru.olamedia.olacraft.world.blockTypes.DirtBlockType; +import ru.olamedia.olacraft.world.blockTypes.GrassBlockType; +import ru.olamedia.olacraft.world.blockTypes.GravelBlockType; +import ru.olamedia.olacraft.world.blockTypes.IceBlockType; +import ru.olamedia.olacraft.world.blockTypes.SnowBlockType; +import ru.olamedia.olacraft.world.blockTypes.TallGrassBlockType; +import ru.olamedia.olacraft.world.blockTypes.WaterBlockType; +import ru.olamedia.olacraft.world.blockTypes.WheatBlockType; +import ru.olamedia.olacraft.world.blockTypes.stone.BrecciaStoneBlockType; +import ru.olamedia.olacraft.world.blockTypes.stone.ChertStoneBlockType; +import ru.olamedia.olacraft.world.blockTypes.stone.CoalStoneBlockType; +import ru.olamedia.olacraft.world.blockTypes.stone.ConglomerateStoneBlockType; +import ru.olamedia.olacraft.world.blockTypes.stone.LimestoneStoneBlockType; +import ru.olamedia.olacraft.world.blockTypes.stone.SandstoneStoneBlockType; +import ru.olamedia.olacraft.world.blockTypes.stone.ShaleStoneBlockType; +import ru.olamedia.olacraft.world.blockTypes.stone.SiltstoneStoneBlockType; import ru.olamedia.olacraft.world.chunk.ChunkUnavailableException; 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.drop.DroppedEntity; import ru.olamedia.olacraft.world.location.BlockLocation; import ru.olamedia.olacraft.world.location.ChunkLocation; import ru.olamedia.olacraft.world.location.RegionLocation; +/** + * Provides ALL information about world (world height, block types, chunks, mobs, spawn locations etc) + * + */ public class WorldProvider { private WorldInfo info = new WorldInfo(); - private BlockRegistry typeRegistry = new BlockRegistry(); + private BlockRegistry types = new BlockRegistry(); private AbstractChunkDataProvider dataProvider; + + public WorldProvider() { + registerBlockTypes(false); + } + + public void registerTextures(){ + registerBlockTypes(true); + } + + protected void registerBlockType(AbstractBlockType t, boolean registerTextures){ + if (registerTextures) { + t.getBackTexture(); + t.getBottomTexture(); + t.getFrontTexture(); + t.getLeftTexture(); + t.getRightTexture(); + t.getTopTexture(); + } else { + types.registerBlockType(t); + } + } + + protected void registerBlockTypes(boolean registerTextures) { + registerBlockType(new GrassBlockType(), registerTextures); + registerBlockType(new ConglomerateStoneBlockType(), registerTextures); + registerBlockType(new LimestoneStoneBlockType(), registerTextures); + registerBlockType(new ChertStoneBlockType(), registerTextures); + registerBlockType(new SiltstoneStoneBlockType(), registerTextures); + registerBlockType(new SandstoneStoneBlockType(), registerTextures); + registerBlockType(new ShaleStoneBlockType(), registerTextures); + registerBlockType(new CoalStoneBlockType(), registerTextures); + registerBlockType(new BrecciaStoneBlockType(), registerTextures); + registerBlockType(new DirtBlockType(), registerTextures); + registerBlockType(new GravelBlockType(), registerTextures); + registerBlockType(new WheatBlockType(), registerTextures); + registerBlockType(new WaterBlockType(), registerTextures); + registerBlockType(new IceBlockType(), registerTextures); + registerBlockType(new SnowBlockType(), registerTextures); + registerBlockType(new TallGrassBlockType(), registerTextures); + } public WorldInfo getInfo() { return info; } - - public BlockRegistry getTypeRegistry(){ - return typeRegistry; + + public BlockRegistry getTypeRegistry() { + return types; } public void setInfo(WorldInfo worldInfo) { @@ -39,9 +100,11 @@ public class WorldProvider { public void setChunkDataProvider(AbstractChunkDataProvider provider) { dataProvider = provider; + dataProvider.setTypeRegistry(this.types); } public SpawnLocation getSpawnLocation(int connectionId) { + dataProvider.setTypeRegistry(this.types); SpawnLocation l = new SpawnLocation(); int maxShift = 10; l.x = (int) (maxShift - Math.random() * 2 * maxShift); @@ -140,7 +203,76 @@ public class WorldProvider { return dataProvider.getChunk(chunkLocation); } - public BlockType getBlockTypeById(int id) { - return typeRegistry.getBlockType(id); + public AbstractBlockType getBlockTypeById(int id) { + return types.getBlockType(id); } + + public boolean isOpaque(int x, int y, int z) throws ChunkUnavailableException { + BlockLocation blockLocation = new BlockLocation(x, y, z); + if (isChunkAvailable(blockLocation.getChunkLocation())) { + ChunkData data = dataProvider.getChunk(blockLocation.getChunkLocation()); + if (null != data) { + int id = ChunkData.ClampID(x, y, z); + if (data.isEmpty(id)) { + return false; + } + return types.isOpaque(data.types[id]); + } else { + System.out.println("chunk null " + x + " " + y + " " + z); + } + } else { + throw new ChunkUnavailableException(); + } + return false; + } + + public boolean hideTouchedSides(int x, int y, int z, int typeid) throws ChunkUnavailableException { + BlockLocation blockLocation = new BlockLocation(x, y, z); + if (isChunkAvailable(blockLocation.getChunkLocation())) { + ChunkData data = dataProvider.getChunk(blockLocation.getChunkLocation()); + if (null != data) { + int id = ChunkData.ClampID(x, y, z); + if (data.isEmpty(id)) { + return false; + } + if (data.types[id] == typeid) { + return types.getBlockType(data.types[id]).hideTouchedSides(); + } + return types.isOpaque(data.types[id]); + } else { + System.out.println("chunk null " + x + " " + y + " " + z); + } + } else { + throw new ChunkUnavailableException(); + } + return false; + } + + public boolean canMoveThrough(int x, int y, int z) throws ChunkUnavailableException { + BlockLocation blockLocation = new BlockLocation(x, y, z); + if (isChunkAvailable(blockLocation.getChunkLocation())) { + ChunkData data = dataProvider.getChunk(blockLocation.getChunkLocation()); + if (null != data) { + int id = ChunkData.ClampID(x, y, z); + if (data.isEmpty(id)) { + return true; + } + return types.canMoveThrough(data.types[id]); + } else { + System.out.println("chunk null " + x + " " + y + " " + z); + } + } else { + throw new ChunkUnavailableException(); + } + return false; + } + + public void dropBlock(BlockLocation location, AbstractBlockType type) throws ChunkUnavailableException { + if (!isChunkAvailable(location.getChunkLocation())) { + throw new ChunkUnavailableException(); + } + ChunkData data = dataProvider.getChunk(location.getChunkLocation()); + data.addDroppedEntity(new DroppedEntity(location, type, 1)); + } + } diff --git a/src/ru/olamedia/player/Player.java b/src/ru/olamedia/player/Player.java index bb62201..342175a 100644 --- a/src/ru/olamedia/player/Player.java +++ b/src/ru/olamedia/player/Player.java @@ -1,14 +1,385 @@ package ru.olamedia.player; +import java.io.FileNotFoundException; + +import javax.media.opengl.GL2; +import javax.media.opengl.GLContext; + +import jp.nyatla.nymmd.MmdException; +import jp.nyatla.nymmd.MmdMotionPlayerGL2; +import jp.nyatla.nymmd.MmdPmdModel; +import jp.nyatla.nymmd.MmdVmdMotion; +import jp.nyatla.nymmd.types.MmdVector3; +import jp.nyatla.nymmd.types.MmdVector4; + +import com.jogamp.newt.event.MouseEvent; + +import ru.olamedia.asset.Asset; +import ru.olamedia.asset.AssetManager; +import ru.olamedia.asset.AssetNotFoundException; +import ru.olamedia.game.GameTime; +import ru.olamedia.input.MouseJail; import ru.olamedia.liveEntity.LiveEntity; import ru.olamedia.olacraft.game.Game; +import ru.olamedia.olacraft.modelAnimator.Arm; +import ru.olamedia.olacraft.modelAnimator.Bone; +import ru.olamedia.olacraft.modelAnimator.Leg; +import ru.olamedia.olacraft.modelAnimator.ModelAnimator; +import ru.olamedia.olacraft.modelAnimator.Skeleton; import ru.olamedia.olacraft.network.packet.LiveEntityLocationUpdatePacket; -import ru.olamedia.olacraft.weapon.Bullet; 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.blockStack.BlockStack; +import ru.olamedia.olacraft.world.blockTypes.EmptyBlockType; +import ru.olamedia.olacraft.world.chunk.ChunkUnavailableException; public class Player extends LiveEntity { + private MmdMotionPlayerGL2 gl2player; + private MmdPmdModel model; + private MmdVmdMotion motion; + private boolean reverseModelLook = true; + + private float motionTimer = 0; + private float motionTimerSpeed = 1f; + private float motionTimerFinish = 1; + + private MmdVmdMotion getMotion() { + if (null == motion) { + try { + final Asset motionAsset = AssetManager.getAsset("models/test.vmd"); + motion = new MmdVmdMotion(motionAsset.getFile()); + } catch (AssetNotFoundException e) { + e.printStackTrace(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (MmdException e) { + e.printStackTrace(); + } + } + return motion; + } + + private MmdPmdModel getModel() { + if (null == model) { + try { + // final Asset modelAsset = + // AssetManager.getAsset("models/neru/Rin_Kagamine.pmd"); + final Asset modelAsset = AssetManager.getAsset("models/raisen/raisen.pmd"); + // final Asset modelAsset = + // AssetManager.getAsset("models/marisa/marisa.pmd"); + // final Asset modelAsset = + // AssetManager.getAsset("models/alice/alice.pmd"); + // final Asset modelAsset = + // AssetManager.getAsset("models/lat_miku/Normal.pmd"); + // final Asset modelAsset = + // AssetManager.getAsset("models/rin/rin.pmd"); + model = new MmdPmdModel(modelAsset.getFile()); + } catch (AssetNotFoundException e) { + e.printStackTrace(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (MmdException e) { + e.printStackTrace(); + } + } + return model; + } + + private float motionFrame = 0; + private float bodyYaw = 0; + private float cameraYaw = 0; + private float cameraDeltaYaw = 0; + private float leftWalkFrame; + private float walkFrameHalf1; + private float walkFrameHalf2; + private float rightWalkFrame; + private float rightWalkFrameHalf1; + private float rightWalkFrameHalf2; + + private float clamp360(float value) { + if (value < 0) { + return value + (-(int) value / 360) * 360; + } + if (value > 0) { + return value - ((int) value / 360) * 360; + } + return value; + } + + private MmdMotionPlayerGL2 getPlayerModel() throws MmdException { + if (null == gl2player) { + gl2player = new MmdMotionPlayerGL2(); + gl2player.setPmd(getModel()); + gl2player.setVmd(getMotion()); + bodyYaw = cameraYaw = camera.getYaw(); + } + cameraYaw = camera.getYaw() + (reverseModelLook ? -180 : 0); + final float yawDelta = clamp360(cameraYaw - bodyYaw); + if (yawDelta > 45) { + bodyYaw = cameraYaw - 45; + } else if (yawDelta < -45) { + bodyYaw = cameraYaw + 45; + } else { + bodyYaw += yawDelta * Game.instance.getFrameDelta(); + bodyYaw = clamp360(bodyYaw); + } + cameraDeltaYaw = clamp360(cameraYaw - bodyYaw); + gl2player.lookMeEnable(true); + // gl2player.setLookVector(camera.getLook().x, camera.getLook().y, + // camera.getLook().z); + motionFrame += Game.instance.getFrameDelta(); + if (motionFrame >= getMotion().getMaxFrame() * (100 / 3)) { + motionFrame = 0; + } + + if (null != gl2player.m_centerBone) { + gl2player.m_centerBone.m_vec3Position.x = 0; + gl2player.m_centerBone.m_vec3Position.y = 0; + gl2player.m_centerBone.m_vec3Position.z = 0; + } + + if (null != gl2player.m_pNeckBone) { + final MmdVector3 euler = new MmdVector3((float) Math.toRadians(-camera.getPitch()), + (float) Math.toRadians(cameraDeltaYaw), (float) Math.toRadians(camera.getRoll())); + gl2player.m_pNeckBone.m_vec4Rotate.QuaternionCreateEuler(euler); + // final MmdVector3 yAxis = new MmdVector3(0, 0, 1); + // gl2player.m_pNeckBone.m_vec4Rotate.QuaternionCreateAxis(yAxis, + // (float) Math.toRadians(camera.getYaw()));// .x + // = + // camera.getLook().x; + // gl2player.m_pNeckBone.m_vec4Rotate.y = camera.getLook().y; + // gl2player.m_pNeckBone.m_vec4Rotate.z = camera.getLook().z; + // gl2player.m_pNeckBone.m_vec4Rotate.w = 1; + // .QuaternionCreateEuler(euler); + // gl2player.manualUpdateNeckBone(); + } + gl2player.m_leftEyeDestination.lookAt(new MmdVector3(camera.getNlook().x, 0, camera.getNlook().z)); + final float maxFootOffset = 1f; + final MmdVector3 xAxis = new MmdVector3(1, 0, 0); + final MmdVector3 yAxis = new MmdVector3(0, 1, 0); + + // gl2player.m_leftFootDestinationIK.m_vec3Position.y = maxFootOffset * + // walkFrame; + // gl2player.m_leftKnee.m_vec3Position.y = maxFootOffset * walkFrame; + gl2player.reset(); + /* + * final float hipAngle = 15; + * final float hipLegYaw = 5; + * final float legPitch = 40; + * final float hipLegRoll = -5; + * final float lowerBodyYaw = -(float) Math.toRadians(-hipAngle * + * walkFrameHalf1 + hipAngle * walkFrameHalf2); + * final float leftLegYaw = -(float) Math.toRadians(hipLegYaw * + * walkFrameHalf1); + * final float rightLegYaw = -(float) Math.toRadians(-hipLegYaw * + * walkFrameHalf2); + * final float leftLegRoll = -(float) Math.toRadians(-hipLegRoll * + * walkFrameHalf1 + hipLegRoll * walkFrameHalf2); + * final float rightLegRoll = (float) Math.toRadians(hipLegRoll * + * walkFrameHalf1 - hipLegRoll * walkFrameHalf2); + * final float leftLegPitch = -(float) Math.toRadians(-legPitch * + * walkFrameHalf1 + legPitch * walkFrameHalf2); + * final float rightLegPitch = -(float) Math.toRadians(-legPitch * + * walkFrameHalf2 + legPitch * walkFrameHalf1); + * gl2player.m_lowerBody.m_vec4Rotate.QuaternionCreateAxis(yAxis, + * lowerBodyYaw); + * final MmdVector3 leftLegEuler = new MmdVector3(leftLegPitch, + * leftLegYaw, leftLegRoll); + * final MmdVector3 rightLegEuler = new MmdVector3(rightLegPitch, + * rightLegYaw, rightLegRoll); + * gl2player.m_leftLeg.m_vec4Rotate.QuaternionCreateEuler(leftLegEuler); + * gl2player.m_rightLeg.m_vec4Rotate.QuaternionCreateEuler(rightLegEuler) + * ; + * gl2player.m_leftKnee.m_vec4Rotate.QuaternionCreateAxis(xAxis, + * -(float) Math.toRadians(20 * walkFrameHalf2 + 30 * walkFrameHalf1)); + * gl2player.m_rightKnee.m_vec4Rotate.QuaternionCreateAxis(xAxis, + * -(float) Math.toRadians(30 * walkFrameHalf2 + 20 * walkFrameHalf1)); + * gl2player.m_leftAnkle.m_vec4Rotate.QuaternionCreateAxis(xAxis, + * -(float) Math.toRadians(15 * walkFrameHalf2 - 30 * walkFrameHalf1)); + * gl2player.m_rightAnkle.m_vec4Rotate.QuaternionCreateAxis(xAxis, + * -(float) Math.toRadians(-30 * walkFrameHalf2 + 15 * walkFrameHalf1)); + * gl2player.update(); + * // gl2player.m_leftFootIK.m_vec3Position.z = 0; + * // gl2player.m_leftFootIK.m_vec4Rotate.x = 0; + * // gl2player.m_leftFootIK.m_vec4Rotate.y = 0; + * // gl2player.m_leftFootIK.m_vec4Rotate.z = 0; + * // gl2player.m_leftToe.m_vec3Position.x = 0; + * // gl2player.m_leftToe.m_vec3Position.y = 0; + * // gl2player.m_leftToe.m_vec3Position.z = 0; + * // gl2player.m_leftToe.m_vec4Rotate.x = 0; + * // gl2player.m_leftToe.m_vec4Rotate.y = 0; + * // gl2player.m_leftToe.m_vec4Rotate.z = 0; + * // if (motionTimer > 1) { + * // gl2player.m_leftKnee.m_vec3Position.z = maxFootOffset + + * maxFootOffset + * // * ((1 - (motionTimer - 1) * 2)); + * // if (gl2player.m_leftKnee.m_vec3Position.z < 0) { + * // gl2player.m_leftKnee.m_vec3Position.z = 0; + * // } + * // } + * gl2player.m_rightFootIK.m_vec3Position.x = -maxFootOffset * (1 - + * motionTimer); + * // gl2player.updateMotion(motionFrame * 1000); + */ + return gl2player; + } + + private MmdVector3 createEuler(float pitch, float yaw, float roll) { + return new MmdVector3(pitch, yaw, roll); + } + + private MmdVector3 createEuler(Bone b) { + return new MmdVector3((float) Math.toRadians(b.getCorrectedPitch()), + (float) Math.toRadians(b.getCorrectedYaw()), (float) Math.toRadians(b.getCorrectedRoll())); + } + + private void calcWalkFrames() { + leftWalkFrame = (float) (motionTimer > 0.5 ? (motionTimer - 0.5) * 2 : 1 - motionTimer * 2); + if (motionTimer > 0.5f) { + // Half2 + walkFrameHalf1 = 0; + walkFrameHalf2 = (motionTimer - 0.5f) * 2f; + walkFrameHalf2 = 1f - (float) Math.abs(walkFrameHalf2 * 2f - 1f); + } else { + // Half1 + walkFrameHalf1 = motionTimer * 2f; + walkFrameHalf2 = 0; + walkFrameHalf1 = 1f - (float) Math.abs(walkFrameHalf1 * 2f - 1f); + } + rightWalkFrame = 1 - leftWalkFrame; + } + + private void updateMotionTimer() { + motionTimer += Game.instance.getFrameDelta() * motionTimerSpeed; + if (motionTimer >= motionTimerFinish) { + motionTimer = 0; + } + } + + private ModelAnimator animator = new ModelAnimator(); + + private MmdMotionPlayerGL2 getOrientedModel() { + try { + final MmdMotionPlayerGL2 player = getPlayerModel(); + player.reset(); + final Skeleton skel = animator.deltaOrientation; + final Leg leftLeg = skel.leftLeg; + final Leg rightLeg = skel.rightLeg; + // LEGS + player.m_leftLeg.m_vec4Rotate.QuaternionCreateEuler(createEuler(leftLeg.top)); + player.m_rightLeg.m_vec4Rotate.QuaternionCreateEuler(createEuler(rightLeg.top)); + player.m_leftKnee.m_vec4Rotate.QuaternionCreateEuler(createEuler(leftLeg.knee)); + player.m_rightKnee.m_vec4Rotate.QuaternionCreateEuler(createEuler(rightLeg.knee)); + player.m_leftAnkle.m_vec4Rotate.QuaternionCreateEuler(createEuler(leftLeg.foot)); + player.m_rightAnkle.m_vec4Rotate.QuaternionCreateEuler(createEuler(rightLeg.foot)); + player.m_rightFootIK.m_vec3Position.y = 0; + player.m_leftFootIK.m_vec3Position.y = 0; + // ARMS + final Arm leftArm = skel.leftArm; + final Arm rightArm = skel.rightArm; + player.m_leftArm.m_vec4Rotate.QuaternionCreateEuler(createEuler(leftArm.top)); + player.m_rightArm.m_vec4Rotate.QuaternionCreateEuler(createEuler(rightArm.top)); + player.m_leftElbow.m_vec4Rotate.QuaternionCreateEuler(createEuler(leftArm.elbow)); + player.m_rightElbow.m_vec4Rotate.QuaternionCreateEuler(createEuler(rightArm.elbow)); + player.m_leftWrist.m_vec4Rotate.QuaternionCreateEuler(createEuler(leftArm.wrist)); + player.m_rightWrist.m_vec4Rotate.QuaternionCreateEuler(createEuler(rightArm.wrist)); + + player.m_lowerBody.m_vec4Rotate.QuaternionCreateEuler(createEuler(skel.waist)); + player.m_upperBody.m_vec4Rotate.QuaternionCreateEuler(createEuler(skel.shoulders)); + if (null != player.m_skirtFrontLeft) { + player.m_skirtFrontLeft.m_vec4Rotate.QuaternionCreateEuler(createEuler(skel.skirtFrontLeft)); + player.m_skirtFrontRight.m_vec4Rotate.QuaternionCreateEuler(createEuler(skel.skirtFrontRight)); + } + // player.m_upperBody.m_vec3Position.z = 1; + player.update(); + return player; + } catch (MmdException e) { + e.printStackTrace(); + } + return null; + } + + private int bonesCount = 0; + private int selectedBone = 0; + + private int bodyYawCorrection = 0; + + public void rotateCW() { + bodyYawCorrection++; + if (bodyYawCorrection > 360) { + bodyYawCorrection -= 360; + } + } + + public void rotateCCW() { + bodyYawCorrection--; + if (bodyYawCorrection < 0) { + bodyYawCorrection += 360; + } + } + + public void selectNextBone() { + selectedBone++; + if (selectedBone > bonesCount) { + selectedBone = 0; + } + Game.client.getScene().selectedBone = animator.finalOrientation.getBone(selectedBone); + } + + public void render() { + if (null == Game.client.getScene().selectedBone) { + bonesCount = Game.client.getScene().bonesCount = animator.deltaOrientation.getBoneCount(); + int i = 0; + Game.client.getScene().selectedBone = animator.finalOrientation.getBone(selectedBone); + } + animator.setPause(Game.client.getScene().boneMode); + animator.setJumping(inJump ? true : false); + animator.setWalking(isWalking ? true : false); + animator.setDelta(Game.instance.getFrameDelta()); + animator.tick(); + + /* + * if (inJump) { + * if (walkFrameHalf1 < 0.9f && walkFrameHalf2 < 0.9f) { + * updateMotionTimer(); + * calcWalkFrames(); + * } + * } else if (isWalking) { + * updateMotionTimer(); + * calcWalkFrames(); + * } else { + * motionTimer -= Game.instance.getDelta() * motionTimerSpeed; + * if (motionTimer <= 0) { + * motionTimer = 0; + * } + * leftWalkFrame += Game.instance.getDelta() * (0 - leftWalkFrame) * 5; + * rightWalkFrame += Game.instance.getDelta() * (0 - rightWalkFrame) * + * 5; + * walkFrameHalf1 += Game.instance.getDelta() * (0 - walkFrameHalf1) * + * 5; + * walkFrameHalf2 += Game.instance.getDelta() * (0 - walkFrameHalf2) * + * 5; + * } + */ + + try { + final MmdMotionPlayerGL2 player = getOrientedModel(); + final GL2 gl = GLContext.getCurrentGL().getGL2(); + gl.glPushMatrix(); + gl.glPushAttrib(GL2.GL_ALL_ATTRIB_BITS); + final float scale = getHeight() / player.height; + gl.glTranslatef(getX(), getY(), getZ());// - 2.5f + gl.glScalef(scale, scale, scale); + // gl.glRotatef(getPitch(), 1, 0, 0); + + gl.glRotatef(bodyYaw + bodyYawCorrection, 0, 1, 0); + // gl.glRotatef(getRoll(), 0, 0, 1); + player.render(); + gl.glPopAttrib(); + gl.glPopMatrix(); + } catch (MmdException e) { + e.printStackTrace(); + } + } @Override public void notifyLocationUpdate() { @@ -21,14 +392,63 @@ public class Player extends LiveEntity { public Player() { } - - public void pickBlock(Block b){ + + public void pickBlock(Block b) { + BlockStack stack = new BlockStack(b.provider.getChunk(b.location.getChunkLocation()).getType(b.location, + b.provider), 1); + if (null != stack.type) { + // inventory.putBlockStack(stack); + stack.type.dropBlock(b.provider, b.location); + } b.removeFromWorld(); + try { + if (inAir()) { + System.out.println("in air while picking"); + inJump = true; + onGround = false; + isOrientationChanged = true; + } + } catch (ChunkUnavailableException e) { + e.printStackTrace(); + } + // Game.client.getScene().updateNearestBlock(); } - public void onMouseClick() { - if (null != Game.client.getScene().nearestBlock){ - pickBlock(Game.client.getScene().nearestBlock); + public void putBlock(Block b) { + BlockStack stack = inventory.getSelectedBlockStack(); + if (stack.count > 0) { + b.setType(stack.type); + stack.count--; + if (stack.count == 0) { + stack.type = new EmptyBlockType(); + } + b.setLocation(b.provider, b.location.x, b.location.y, b.location.z); + System.out.println("put block " + b.getType().getClass().getName()); + b.insertToWorld(); + // Game.client.getScene().updateNearestBlock(); + } + } + + public void onMouseClick(MouseEvent e) { + if (null != inventory) { + if (e.getButton() == 1) { + inventory.click(false); + } + if (e.getButton() == 3) { + inventory.click(true); + } + } + if (e.isConfined() && MouseJail.isActive()) { + if (e.getButton() == 1) { + if (null != Game.client.getScene().nearestBlock) { + pickBlock(Game.client.getScene().nearestBlock); + } + } + if (e.getButton() == 3) { + if (null != Game.client.getScene().nearestPutBlock) { + putBlock(Game.client.getScene().nearestPutBlock); + } + } } // Bullet b = new Bullet(); // b.velocity.set(Game.instance.camera.getLook()); diff --git a/src/ru/olamedia/player/RuntimeSettings.java b/src/ru/olamedia/player/RuntimeSettings.java new file mode 100644 index 0000000..d5ce012 --- /dev/null +++ b/src/ru/olamedia/player/RuntimeSettings.java @@ -0,0 +1,5 @@ +package ru.olamedia.player; + +public class RuntimeSettings { + public int renderDistance = 128; +} diff --git a/src/ru/olamedia/texture/TextureManager.java b/src/ru/olamedia/texture/TextureManager.java index c790cee..afe5da3 100644 --- a/src/ru/olamedia/texture/TextureManager.java +++ b/src/ru/olamedia/texture/TextureManager.java @@ -1,17 +1,31 @@ package ru.olamedia.texture; +import java.awt.image.BufferedImage; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; +import javax.media.opengl.GLProfile; + import ru.olamedia.asset.AssetManager; import ru.olamedia.asset.AssetNotFoundException; +import ru.olamedia.asset.Sprite; +import ru.olamedia.asset.SpriteRectangle; import com.jogamp.opengl.util.texture.Texture; import com.jogamp.opengl.util.texture.TextureIO; +import com.jogamp.opengl.util.texture.awt.AWTTextureIO; public class TextureManager { private static HashMap<String, Texture> list = new HashMap<String, Texture>(); + private static HashMap<String, Sprite> currentSpriteList = new HashMap<String, Sprite>(); + private static HashMap<String, SpriteRectangle> offsets = new HashMap<String, SpriteRectangle>(); + private static Sprite currentSprite = new Sprite(256, 256, 32, 32); // 64 + // tiles + + public static void writeSprite(String filename) { + currentSprite.write(filename); + } public static Texture get(String filename) { if (!list.containsKey(filename)) { @@ -39,4 +53,54 @@ public class TextureManager { } return list.get(key); } + + public static Texture get(String key, InputStream stream, String format) { + if (!list.containsKey(key)) { + try { + list.put(key, TextureIO.newTexture(stream, true, format)); + } catch (IOException e) { + list.put(key, null); + e.printStackTrace(); + } + } + return list.get(key); + } + + public static Texture makeTextureFromBufferedImage(BufferedImage b) { + return null; + } + + public static Texture getSprite(String filename) { + if (!list.containsKey(filename)) { + try { + SpriteRectangle offset = currentSprite.addImage(filename); + offsets.put(filename, offset); + currentSpriteList.put(filename, currentSprite); + } catch (AssetNotFoundException e) { + e.printStackTrace(); + } + return get(filename); + } + return list.get(filename); + } + + public static SpriteRectangle getSpriteOffset(String filename) { + if (!offsets.containsKey(filename)) { + getSprite(filename); + if (!offsets.containsKey(filename)) { + return null; + } + } + return offsets.get(filename); + } + + public static void finishSprite() { + GLProfile gp = GLProfile.getGL2ES2(); + Texture texture = AWTTextureIO.newTexture(gp, currentSprite.getImage(), true); + currentSprite.dispose(); + for (String key : currentSpriteList.keySet()) { + list.put(key, texture); + } + currentSpriteList.clear(); + } } |