diff --git a/src/net/minecraft/client/GameWindow.js b/src/js/net/minecraft/client/GameWindow.js similarity index 100% rename from src/net/minecraft/client/GameWindow.js rename to src/js/net/minecraft/client/GameWindow.js diff --git a/src/net/minecraft/client/Minecraft.js b/src/js/net/minecraft/client/Minecraft.js similarity index 100% rename from src/net/minecraft/client/Minecraft.js rename to src/js/net/minecraft/client/Minecraft.js diff --git a/src/net/minecraft/client/entity/Player.js b/src/js/net/minecraft/client/entity/Player.js similarity index 99% rename from src/net/minecraft/client/entity/Player.js rename to src/js/net/minecraft/client/entity/Player.js index e05a57f..86a4f95 100644 --- a/src/net/minecraft/client/entity/Player.js +++ b/src/js/net/minecraft/client/entity/Player.js @@ -47,7 +47,8 @@ window.Player = class { } resetPos() { - this.setPos(0, 15, 0); + this.setPos(0, 2, 0); + this.pitch = -90; } setPos(x, y, z) { diff --git a/src/js/net/minecraft/client/render/BlockRenderer.js b/src/js/net/minecraft/client/render/BlockRenderer.js new file mode 100644 index 0000000..695e6ef --- /dev/null +++ b/src/js/net/minecraft/client/render/BlockRenderer.js @@ -0,0 +1,81 @@ +window.BlockRenderer = class { + + constructor(worldRenderer) { + this.worldRenderer = worldRenderer; + this.tessellator = new Tessellator(); + this.tessellator.bindTexture(worldRenderer.terrainTexture); + } + + renderBlock(world, group, typeId, x, y, z) { + let boundingBox = new BoundingBox(0.0, 0.0, 0.0, 1.0, 1.0, 1.0); + + for (let face = 0; face < 6; face++) { + this.tessellator.startDrawing(); + this.renderFace(world, typeId, boundingBox, face, x, y, z); + this.tessellator.draw(group); + } + } + + renderFace(world, typeId, boundingBox, face, x, y, z) { + // Vertex mappings + let minX = x + boundingBox.minX; + let minY = y + boundingBox.minY; + let minZ = z + boundingBox.minZ; + let maxX = x + boundingBox.maxX; + let maxY = y + boundingBox.maxY; + let maxZ = z + boundingBox.maxZ; + + // UV Mapping + let textureIndex = typeId; + let minU = (textureIndex % 16) / 16.0; + let maxU = minU + (16 / 256); + let minV = parseInt(textureIndex / 16); // TODO Math.round + let maxV = minV + (16 / 256); + + // Flip V + minV = 1 - minV; + maxV = 1 - maxV; + + if (face === 0) { + this.addBlockCorner(world, face, minX, minY, maxZ, minU, maxV); + this.addBlockCorner(world, face, minX, minY, minZ, minU, minV); + this.addBlockCorner(world, face, maxX, minY, minZ, maxU, minV); + this.addBlockCorner(world, face, maxX, minY, maxZ, maxU, maxV); + } + if (face === 1) { + this.addBlockCorner(world, face, maxX, maxY, maxZ, maxU, maxV); + this.addBlockCorner(world, face, maxX, maxY, minZ, maxU, minV); + this.addBlockCorner(world, face, minX, maxY, minZ, minU, minV); + this.addBlockCorner(world, face, minX, maxY, maxZ, minU, maxV); + } + if (face === 2) { + this.addBlockCorner(world, face, minX, maxY, minZ, maxU, minV); + this.addBlockCorner(world, face, maxX, maxY, minZ, minU, minV); + this.addBlockCorner(world, face, maxX, minY, minZ, minU, maxV); + this.addBlockCorner(world, face, minX, minY, minZ, maxU, maxV); + } + if (face === 3) { + this.addBlockCorner(world, face, minX, maxY, maxZ, minU, minV); + this.addBlockCorner(world, face, minX, minY, maxZ, minU, maxV); + this.addBlockCorner(world, face, maxX, minY, maxZ, maxU, maxV); + this.addBlockCorner(world, face, maxX, maxY, maxZ, maxU, minV); + } + if (face === 4) { + this.addBlockCorner(world, face, minX, maxY, maxZ, maxU, minV); + this.addBlockCorner(world, face, minX, maxY, minZ, minU, minV); + this.addBlockCorner(world, face, minX, minY, minZ, minU, maxV); + this.addBlockCorner(world, face, minX, minY, maxZ, maxU, maxV); + } + if (face === 5) { + this.addBlockCorner(world, face, maxX, minY, maxZ, minU, maxV); + this.addBlockCorner(world, face, maxX, minY, minZ, maxU, maxV); + this.addBlockCorner(world, face, maxX, maxY, minZ, maxU, minV); + this.addBlockCorner(world, face, maxX, maxY, maxZ, minU, minV); + } + } + + addBlockCorner(world, face, x, y, z, u, v) { + this.tessellator.addVertexWithUV(x, y, z, u, v); + } + +} \ No newline at end of file diff --git a/src/js/net/minecraft/client/render/Tessellator.js b/src/js/net/minecraft/client/render/Tessellator.js new file mode 100644 index 0000000..dfb3046 --- /dev/null +++ b/src/js/net/minecraft/client/render/Tessellator.js @@ -0,0 +1,38 @@ +window.Tessellator = class { + + constructor() { + this.material = new THREE.MeshBasicMaterial({ + color: 0xffffff, + side: THREE.BackSide + }); + } + + bindTexture(texture) { + this.material.map = texture; + } + + startDrawing() { + this.verticies = []; + this.uv = []; + } + + addVertexWithUV(x, y, z, u, v) { + this.verticies.push(x); + this.verticies.push(y); + this.verticies.push(z); + + this.uv.push(u); + this.uv.push(v); + } + + draw(group) { + let geometry = new THREE.BufferGeometry(); + geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(this.verticies), 3)); + geometry.setAttribute('uv', new THREE.BufferAttribute(new Float32Array(this.uv), 2)); + geometry.setIndex(new THREE.BufferAttribute(new Uint32Array([0, 2, 1, 0, 3, 2]), 1)); + + let mesh = new THREE.Mesh(geometry, this.material); + group.add(mesh); + } + +} \ No newline at end of file diff --git a/src/net/minecraft/client/render/WorldRenderer.js b/src/js/net/minecraft/client/render/WorldRenderer.js similarity index 84% rename from src/net/minecraft/client/render/WorldRenderer.js rename to src/js/net/minecraft/client/render/WorldRenderer.js index 0656c61..60baeed 100644 --- a/src/net/minecraft/client/render/WorldRenderer.js +++ b/src/js/net/minecraft/client/render/WorldRenderer.js @@ -25,14 +25,24 @@ window.WorldRenderer = class { antialias: true }); + // Settings this.webRenderer.shadowMap.enabled = true; this.webRenderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap this.webRenderer.autoClear = false; this.webRenderer.setClearColor(0x000000, 0); this.webRenderer.clear(); + // Add lights const nightLight = new THREE.AmbientLight(0x888888, 1.0); this.scene.add(nightLight); + + // Load terrain + this.terrainTexture = new THREE.TextureLoader().load( 'src/resources/terrain.png' ); + this.terrainTexture.magFilter = THREE.NearestFilter; + this.terrainTexture.minFilter = THREE.LinearFilter; + + // Block Renderer + this.blockRenderer = new BlockRenderer(this); } render(partialTicks) { @@ -40,7 +50,7 @@ window.WorldRenderer = class { this.orientCamera(partialTicks); // Render chunks - this.renderChunks(partialTicks); + this.renderChunks(this, partialTicks); // Render window this.webRenderer.render(this.scene, this.camera); @@ -64,7 +74,7 @@ window.WorldRenderer = class { this.camera.updateProjectionMatrix(); } - renderChunks(partialTicks) { + renderChunks(renderer, partialTicks) { let world = this.minecraft.world; const xKeys = Object.keys(world.chunks) @@ -80,7 +90,7 @@ window.WorldRenderer = class { let section = chunk.sections[y]; if (section.dirty) { - section.rebuild(); + section.rebuild(renderer); } } } diff --git a/src/net/minecraft/client/world/Chunk.js b/src/js/net/minecraft/client/world/Chunk.js similarity index 75% rename from src/net/minecraft/client/world/Chunk.js rename to src/js/net/minecraft/client/world/Chunk.js index b718579..bdd88f8 100644 --- a/src/net/minecraft/client/world/Chunk.js +++ b/src/js/net/minecraft/client/world/Chunk.js @@ -1,15 +1,16 @@ window.Chunk = class { - constructor(x, z) { - this.group = new THREE.Object3D(); - + constructor(world, x, z) { + this.world = world; this.x = x; this.z = z; + this.group = new THREE.Object3D(); + // Initialize sections this.sections = []; for (let y = 0; y < 16; y++) { - let section = new ChunkSection(x, y, z); + let section = new ChunkSection(world, x, y, z); this.sections[y] = section; this.group.add(section.group); @@ -20,9 +21,9 @@ window.Chunk = class { return this.sections[y]; } - rebuild() { + rebuild(renderer) { for (let y = 0; y < this.sections.length; y++) { - this.sections[y].rebuild(); + this.sections[y].rebuild(renderer); } } diff --git a/src/net/minecraft/client/world/ChunkSection.js b/src/js/net/minecraft/client/world/ChunkSection.js similarity index 71% rename from src/net/minecraft/client/world/ChunkSection.js rename to src/js/net/minecraft/client/world/ChunkSection.js index aabb776..d049675 100644 --- a/src/net/minecraft/client/world/ChunkSection.js +++ b/src/js/net/minecraft/client/world/ChunkSection.js @@ -4,7 +4,8 @@ window.ChunkSection = class { return 16; } - constructor(x, y, z) { + constructor(world, x, y, z) { + this.world = world; this.x = x; this.y = y; this.z = z; @@ -22,10 +23,11 @@ window.ChunkSection = class { } } - rebuild() { + rebuild(renderer) { this.dirty = false; this.group.clear(); + for (let x = 0; x < ChunkSection.SIZE; x++) { for (let y = 0; y < ChunkSection.SIZE; y++) { for (let z = 0; z < ChunkSection.SIZE; z++) { @@ -36,18 +38,7 @@ window.ChunkSection = class { let absoluteY = this.y * ChunkSection.SIZE + y; let absoluteZ = this.z * ChunkSection.SIZE + z; - // Debug stuff - let color = 0x888888 | (Math.random() * 223); - - let geometry = new THREE.BoxGeometry(1, 1, 1); - let material = new THREE.MeshBasicMaterial({ - color: color - }); - - let cube = new THREE.Mesh(geometry, material); - cube.position.set(absoluteX + 0.5, absoluteY + 0.5, absoluteZ + 0.5); - - this.group.add(cube); + renderer.blockRenderer.renderBlock(this.world, this.group, typeId, absoluteX, absoluteY, absoluteZ); } } } diff --git a/src/net/minecraft/client/world/World.js b/src/js/net/minecraft/client/world/World.js similarity index 98% rename from src/net/minecraft/client/world/World.js rename to src/js/net/minecraft/client/world/World.js index e3d31f9..5229e89 100644 --- a/src/net/minecraft/client/world/World.js +++ b/src/js/net/minecraft/client/world/World.js @@ -70,7 +70,7 @@ window.World = class { let chunk = zArray[z]; if (typeof chunk === 'undefined') { - chunk = new Chunk(x, z); + chunk = new Chunk(this, x, z); this.chunks[x][z] = chunk; this.group.add(chunk.group); } diff --git a/src/net/minecraft/util/BoundingBox.js b/src/js/net/minecraft/util/BoundingBox.js similarity index 100% rename from src/net/minecraft/util/BoundingBox.js rename to src/js/net/minecraft/util/BoundingBox.js diff --git a/src/net/minecraft/util/Keyboard.js b/src/js/net/minecraft/util/Keyboard.js similarity index 100% rename from src/net/minecraft/util/Keyboard.js rename to src/js/net/minecraft/util/Keyboard.js diff --git a/src/net/minecraft/util/MathHelper.js b/src/js/net/minecraft/util/MathHelper.js similarity index 100% rename from src/net/minecraft/util/MathHelper.js rename to src/js/net/minecraft/util/MathHelper.js diff --git a/src/net/minecraft/util/Timer.js b/src/js/net/minecraft/util/Timer.js similarity index 100% rename from src/net/minecraft/util/Timer.js rename to src/js/net/minecraft/util/Timer.js diff --git a/src/resources/terrain.png b/src/resources/terrain.png new file mode 100644 index 0000000..e0e796f Binary files /dev/null and b/src/resources/terrain.png differ diff --git a/src/start.js b/src/start.js index dad6e6d..7875963 100644 --- a/src/start.js +++ b/src/start.js @@ -47,17 +47,19 @@ loadScripts([ "libraries/three.min.js", // Minecraft Source - "src/net/minecraft/util/Timer.js", - "src/net/minecraft/util/MathHelper.js", - "src/net/minecraft/util/BoundingBox.js", - "src/net/minecraft/util/Keyboard.js", - "src/net/minecraft/client/GameWindow.js", - "src/net/minecraft/client/world/ChunkSection.js", - "src/net/minecraft/client/world/Chunk.js", - "src/net/minecraft/client/world/World.js", - "src/net/minecraft/client/entity/Player.js", - "src/net/minecraft/client/Minecraft.js", - "src/net/minecraft/client/render/WorldRenderer.js" + "src/js/net/minecraft/util/Timer.js", + "src/js/net/minecraft/util/MathHelper.js", + "src/js/net/minecraft/util/BoundingBox.js", + "src/js/net/minecraft/util/Keyboard.js", + "src/js/net/minecraft/client/GameWindow.js", + "src/js/net/minecraft/client/world/ChunkSection.js", + "src/js/net/minecraft/client/world/Chunk.js", + "src/js/net/minecraft/client/world/World.js", + "src/js/net/minecraft/client/entity/Player.js", + "src/js/net/minecraft/client/Minecraft.js", + "src/js/net/minecraft/client/render/Tessellator.js", + "src/js/net/minecraft/client/render/WorldRenderer.js", + "src/js/net/minecraft/client/render/BlockRenderer.js" ]).then(() => { // Remove pre status document.getElementById("pre-status").remove();