Skip to content

Commit ddc7480

Browse files
committed
initial rendering test
0 parents  commit ddc7480

File tree

12 files changed

+545
-0
lines changed

12 files changed

+545
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*.iml
2+
.idea

index.html

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<html lang="en">
2+
<head>
3+
<title>Minecraft</title>
4+
<link rel="stylesheet" href="style.css"/>
5+
</head>
6+
7+
<body>
8+
<div id="canvas-container"></div>
9+
<span id="pre-status">Loading page...</span>
10+
</body>
11+
12+
<script src="src/start.js"></script>
13+
14+
</html>
15+
16+

libraries/three.min.js

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
window.GameWindow = class {
2+
3+
constructor(renderer, canvasWrapperId) {
4+
this.renderer = renderer;
5+
this.canvasWrapperId = canvasWrapperId;
6+
7+
// Add web renderer canvas to wrapper
8+
document.getElementById(this.canvasWrapperId).appendChild(renderer.canvasElement);
9+
10+
// Init
11+
this.initialize();
12+
13+
// On resize
14+
let scope = this;
15+
window.addEventListener('resize', _ => scope.initialize(), false);
16+
}
17+
18+
19+
initialize() {
20+
// Get canvas size
21+
let canvasElement = document.getElementById(this.canvasWrapperId);
22+
this.canvasWidth = canvasElement.offsetWidth;
23+
this.canvasHeight = canvasElement.offsetHeight;
24+
25+
// Adjust camera
26+
this.renderer.camera.aspect = this.canvasWidth / this.canvasHeight;
27+
this.renderer.camera.updateProjectionMatrix();
28+
this.renderer.webRenderer.setSize(this.canvasWidth, this.canvasHeight);
29+
}
30+
}

src/net/minecraft/client/Minecraft.js

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
window.Minecraft = class {
2+
3+
/**
4+
* Create Minecraft instance and render it on a canvas
5+
*/
6+
constructor(canvasWrapperId) {
7+
this.worldRenderer = new WorldRenderer(this);
8+
this.window = new GameWindow(this.worldRenderer, canvasWrapperId);
9+
this.timer = new Timer(20);
10+
11+
this.frames = 0;
12+
this.lastTime = Date.now();
13+
14+
this.world = new World();
15+
this.worldRenderer.scene.add(this.world.group);
16+
17+
this.init();
18+
}
19+
20+
init() {
21+
this.running = true;
22+
this.requestNextFrame();
23+
}
24+
25+
requestNextFrame() {
26+
let scope = this;
27+
requestAnimationFrame(function () {
28+
if (scope.running) {
29+
scope.requestNextFrame();
30+
scope.onRender();
31+
}
32+
});
33+
}
34+
35+
onRender() {
36+
// Update the timer
37+
this.timer.advanceTime();
38+
39+
// Call the tick to reach updates 20 per seconds
40+
for (let i = 0; i < this.timer.ticks; i++) {
41+
this.onTick();
42+
}
43+
44+
// Render the game
45+
this.worldRenderer.render(this.timer.partialTicks);
46+
47+
// Increase rendered frame
48+
this.frames++;
49+
50+
// Loop if a second passed
51+
while (Date.now() >= this.lastTime + 1000) {
52+
console.log(this.frames + " fps");
53+
54+
this.lastTime += 1000;
55+
this.frames = 0;
56+
}
57+
}
58+
59+
onTick() {
60+
61+
}
62+
63+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
window.WorldRenderer = class {
2+
3+
constructor(minecraft) {
4+
this.minecraft = minecraft;
5+
6+
this.supportWebGL = !!WebGLRenderingContext
7+
&& (!!document.createElement('canvas').getContext('experimental-webgl')
8+
|| !!document.createElement('canvas').getContext('webgl'));
9+
10+
// Create cameras
11+
this.camera = new THREE.PerspectiveCamera(85, 1, 1, 10000);
12+
this.camera.position.set(0, 3, 0);
13+
this.camera.up = new THREE.Vector3(0, 0, 1);
14+
15+
// Create scene
16+
this.scene = new THREE.Scene();
17+
18+
// Create web renderer
19+
this.canvasElement = document.createElement('canvas')
20+
this.webRenderer = this.supportWebGL ? new THREE.WebGLRenderer({
21+
canvas: this.canvasElement,
22+
antialias: true
23+
}) : new THREE.CanvasRenderer({
24+
canvas: this.canvasElement,
25+
antialias: true
26+
});
27+
28+
this.webRenderer.shadowMap.enabled = true;
29+
this.webRenderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap
30+
this.webRenderer.autoClear = false;
31+
this.webRenderer.setClearColor(0x000000, 0);
32+
this.webRenderer.clear();
33+
34+
const nightLight = new THREE.AmbientLight(0x888888, 1.0);
35+
this.scene.add(nightLight);
36+
}
37+
38+
render(partialTicks) {
39+
let world = this.minecraft.world;
40+
41+
const xKeys = Object.keys(world.chunks)
42+
for (let x = 0; x < xKeys.length; x++) {
43+
44+
let zArray = world.chunks[xKeys[x]];
45+
const zKeys = Object.keys(zArray)
46+
47+
for (let z = 0; z < zKeys.length; z++) {
48+
let chunk = zArray[zKeys[z]];
49+
50+
for (let y = 0; y < chunk.sections.length; y++) {
51+
let section = chunk.sections[y];
52+
53+
if (section.dirty) {
54+
section.rebuild();
55+
}
56+
}
57+
}
58+
}
59+
60+
// Render window
61+
this.webRenderer.render(this.scene, this.camera);
62+
}
63+
64+
65+
}
+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
window.Chunk = class {
2+
3+
constructor(x, z) {
4+
this.group = new THREE.Object3D();
5+
6+
this.x = x;
7+
this.z = z;
8+
9+
// Initialize sections
10+
this.sections = [];
11+
for (let y = 0; y < 16; y++) {
12+
let section = new ChunkSection(x, y, z);
13+
14+
this.sections[y] = section;
15+
this.group.add(section.group);
16+
}
17+
}
18+
19+
getSection(y) {
20+
return this.sections[y];
21+
}
22+
23+
rebuild() {
24+
for (let y = 0; y < this.sections.length; y++) {
25+
this.sections[y].rebuild();
26+
}
27+
}
28+
29+
queueForRebuild() {
30+
for (let y = 0; y < this.sections.length; y++) {
31+
this.sections[y].queueForRebuild();
32+
}
33+
}
34+
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
window.ChunkSection = class {
2+
3+
static get SIZE() {
4+
return 16;
5+
}
6+
7+
constructor(x, y, z) {
8+
this.x = x;
9+
this.y = y;
10+
this.z = z;
11+
12+
this.group = new THREE.Object3D();
13+
this.dirty = true;
14+
15+
this.blocks = [];
16+
for (let x = 0; x < ChunkSection.SIZE; x++) {
17+
for (let y = 0; y < ChunkSection.SIZE; y++) {
18+
for (let z = 0; z < ChunkSection.SIZE; z++) {
19+
this.setBlockAt(x, y, z, 0);
20+
}
21+
}
22+
}
23+
}
24+
25+
rebuild() {
26+
this.dirty = false;
27+
this.group.clear();
28+
29+
for (let x = 0; x < ChunkSection.SIZE; x++) {
30+
for (let y = 0; y < ChunkSection.SIZE; y++) {
31+
for (let z = 0; z < ChunkSection.SIZE; z++) {
32+
let typeId = this.getBlockAt(x, y, z);
33+
34+
if (typeId !== 0) {
35+
let absoluteX = this.x * ChunkSection.SIZE + x;
36+
let absoluteY = this.y * ChunkSection.SIZE + y;
37+
let absoluteZ = this.z * ChunkSection.SIZE + z;
38+
39+
// Debug stuff
40+
let color = 0x888888 | (Math.random() * 223);
41+
42+
let geometry = new THREE.BoxGeometry(1, 1, 1);
43+
let material = new THREE.MeshBasicMaterial({
44+
color: color
45+
});
46+
47+
let cube = new THREE.Mesh(geometry, material);
48+
cube.position.set(absoluteX - 0.5, absoluteY - 0.5, absoluteZ - 0.5);
49+
50+
this.group.add(cube);
51+
}
52+
}
53+
}
54+
}
55+
}
56+
57+
getBlockAt(x, y, z) {
58+
let index = y << 8 | z << 4 | x;
59+
return this.blocks[index];
60+
}
61+
62+
setBlockAt(x, y, z, typeId) {
63+
let index = y << 8 | z << 4 | x;
64+
this.blocks[index] = typeId;
65+
}
66+
67+
queueForRebuild() {
68+
this.dirty = true;
69+
}
70+
}
+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
window.World = class {
2+
3+
static get TOTAL_HEIGHT() {
4+
return ChunkSection.SIZE * 16 - 1;
5+
}
6+
7+
constructor() {
8+
this.group = new THREE.Object3D();
9+
this.chunks = [];
10+
11+
for (let x = -16; x < 16; x++) {
12+
for (let z = -16; z < 16; z++) {
13+
this.setBlockAt(x, 0, z, 1);
14+
}
15+
}
16+
}
17+
18+
setBlockAt(x, y, z, type) {
19+
let chunkSection = this.getChunkAtBlock(x, y, z);
20+
if (chunkSection != null) {
21+
chunkSection.setBlockAt(x & 15, y & 15, z & 15, type);
22+
}
23+
24+
this.blockChanged(x, y, z);
25+
}
26+
27+
getChunkAt(x, z) {
28+
let zArray = this.chunks[x];
29+
if (typeof zArray === 'undefined') {
30+
zArray = this.chunks[x] = [];
31+
}
32+
33+
let chunk = zArray[z];
34+
if (typeof chunk === 'undefined') {
35+
chunk = new Chunk(x, z);
36+
this.chunks[x][z] = chunk;
37+
this.group.add(chunk.group);
38+
}
39+
return chunk;
40+
}
41+
42+
blockChanged(x, y, z) {
43+
this.setDirty(x - 1, y - 1, z - 1, x + 1, y + 1, z + 1);
44+
}
45+
46+
setDirty(minX, minY, minZ, maxX, maxY, maxZ) {
47+
// To chunk coordinates
48+
minX = minX >> 4;
49+
maxX = maxX >> 4;
50+
minY = minY >> 4;
51+
maxY = maxY >> 4;
52+
minZ = minZ >> 4;
53+
maxZ = maxZ >> 4;
54+
55+
// Minimum and maximum y
56+
minY = Math.max(0, minY);
57+
maxY = Math.min(15, maxY);
58+
59+
for (let x = minX; x <= maxX; x++) {
60+
for (let y = minY; y <= maxY; y++) {
61+
for (let z = minZ; z <= maxZ; z++) {
62+
this.getChunkAt(x, y, z).queueForRebuild();
63+
}
64+
}
65+
}
66+
}
67+
68+
getChunkAtBlock(x, y, z) {
69+
let chunk = this.getChunkAt(x >> 4, z >> 4);
70+
return y < 0 || y > World.TOTAL_HEIGHT ? null : chunk.getSection(y >> 4);
71+
}
72+
73+
74+
}

0 commit comments

Comments
 (0)