-
Notifications
You must be signed in to change notification settings - Fork 2
/
mesh-plugin.js
127 lines (104 loc) · 3.8 KB
/
mesh-plugin.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
'use strict';
var createVoxelMesh = require('./mesh-buffer.js');
var inherits = require('inherits');
var EventEmitter = require('events').EventEmitter;
var ndarray = require('ndarray');
var ops = require('ndarray-ops');
var parseBlockModel = require("block-models");
var createBuffer = require("gl-buffer");
var createVAO = require("gl-vao");
module.exports = function(game, opts) {
return new MesherPlugin(game, opts);
};
module.exports.pluginInfo = {
loadAfter: ['voxel-registry', 'voxel-stitch'],
clientOnly: true
};
function MesherPlugin(game, opts) {
this.game = game;
this.shell = game.shell;
this.registry = game.plugins.get('voxel-registry');
if (!this.registry) throw new Error('voxel-mesher requires voxel-registry plugin');
this.stitcher = game.plugins.get('voxel-stitch');
if (!this.stitcher) throw new Error('voxel-mesher requires voxel-stitch plugin');
this.isTransparent = undefined;
this.hasBlockModel = undefined;
var s = game.chunkSize + (game.chunkPad|0)
this.solidVoxels = ndarray(new game.arrayType(s*s*s), [s,s,s]);
};
inherits(MesherPlugin, EventEmitter);
MesherPlugin.prototype.createVoxelMesh = function(gl, voxels, voxelSideTextureIDs, voxelSideTextureSizes, position, pad) {
var porousMesh = this.splitVoxelArray(voxels);
var mesh = createVoxelMesh(gl, this.solidVoxels, voxelSideTextureIDs, voxelSideTextureSizes, position, pad, this);
mesh.vertexArrayObjects.porous = porousMesh;
return mesh;
}
// mesh custom voxel
MesherPlugin.prototype.meshCustomBlock = function(value,x,y,z) {
var modelDefn = this.registry.blockProps[value].blockModel;
var stitcher = this.stitcher;
// parse JSON to vertices and UV
var model = parseBlockModel(
modelDefn,
//getTextureUV:
function(name) {
return stitcher.getTextureUV(name); // only available when textures are ready
},
x,y,z
);
return model;
};
// populates solidVoxels array, returns porousMesh
MesherPlugin.prototype.splitVoxelArray = function(voxels) {
if (!this.isTransparent) {
// cache list of transparent voxels TODO: refresh cache when changes
this.isTransparent = this.registry.getBlockPropsAll('transparent');
this.isTransparent.unshift(true); // air (0) is transparent
}
if (!this.hasBlockModel) {
this.hasBlockModel = this.registry.getBlockPropsAll('blockModel');
this.hasBlockModel.unshift(undefined);
}
// phase 1: solid voxels = opaque, transparent (terrain blocks, glass, greedily meshed)
var solidVoxels = this.solidVoxels;
var isTransparent = this.isTransparent;
ops.assign(solidVoxels, voxels);
// phase 2: porous voxels = translucent, custom block models (stained glass, slabs, stairs)
var hasBlockModel = this.hasBlockModel;
var porousMeshes = this.porousMeshes = [];
var length = solidVoxels.data.length;
var vertices = [];
var uv = [];
for (var i = 0; i < length; ++i) {
var value = solidVoxels.data[i];
if (hasBlockModel[value]) {
solidVoxels.data[i] = 0;
// extract coordinate from ndarray index (sorry)
var o = i;
var z = (o % 36)-2; o = Math.floor(o / 36);
var y = (o % 36)-2; o = Math.floor(o / 36);
var x = o-2;
// accumulate mesh vertices and uv
var model = this.meshCustomBlock(value,x,y,z);
vertices = vertices.concat(model.vertices);
uv = uv.concat(model.uv);
} else if (!isTransparent[value]) {
solidVoxels.data[i] = value | (1<<15); // opaque bit
}
}
// load combined porous mesh into GL
var gl = this.shell.gl;
var verticesBuf = createBuffer(gl, new Float32Array(vertices));
var uvBuf = createBuffer(gl, new Float32Array(uv));
var porousMesh = createVAO(gl, [
{ buffer: verticesBuf,
size: 3
},
{
buffer: uvBuf,
size: 2
}
]);
porousMesh.length = vertices.length/3;
return porousMesh;
};