@erik9994857/cag 2.0.0 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/api/model-api.js +36 -2
- package/src/cli/cag-cli.js +21 -11
- package/src/runtime/electron-runner.js +164 -99
package/package.json
CHANGED
package/src/api/model-api.js
CHANGED
|
@@ -72,14 +72,26 @@ class ModelAPI {
|
|
|
72
72
|
valid: false
|
|
73
73
|
};
|
|
74
74
|
|
|
75
|
+
let embeddedTextures = [];
|
|
76
|
+
|
|
75
77
|
if (resource.model) {
|
|
76
78
|
const modelData = this.parseBBModel(resource.model);
|
|
77
79
|
result.geometry = modelData.geometry;
|
|
78
80
|
result.uvMappings = modelData.uvMappings;
|
|
81
|
+
embeddedTextures = modelData.embeddedTextures || [];
|
|
79
82
|
}
|
|
80
83
|
|
|
81
84
|
if (resource.texture) {
|
|
82
85
|
result.texture = this.loadTexture(resource.texture);
|
|
86
|
+
} else if (embeddedTextures.length > 0) {
|
|
87
|
+
result.texture = {
|
|
88
|
+
path: null,
|
|
89
|
+
width: result.geometry ? result.geometry.resolution.width : 16,
|
|
90
|
+
height: result.geometry ? result.geometry.resolution.height : 16,
|
|
91
|
+
format: "png",
|
|
92
|
+
size: 0,
|
|
93
|
+
dataURL: embeddedTextures[0].source
|
|
94
|
+
};
|
|
83
95
|
}
|
|
84
96
|
|
|
85
97
|
if (result.geometry && result.texture && result.uvMappings) {
|
|
@@ -148,7 +160,21 @@ class ModelAPI {
|
|
|
148
160
|
geometry.bones = this.parseOutliner(data.outliner);
|
|
149
161
|
}
|
|
150
162
|
|
|
151
|
-
|
|
163
|
+
const embeddedTextures = [];
|
|
164
|
+
if (data.textures && Array.isArray(data.textures)) {
|
|
165
|
+
for (let i = 0; i < data.textures.length; i++) {
|
|
166
|
+
const tex = data.textures[i];
|
|
167
|
+
if (tex.source) {
|
|
168
|
+
embeddedTextures.push({
|
|
169
|
+
index: tex.id !== undefined ? tex.id : i,
|
|
170
|
+
name: tex.name || "texture_" + i,
|
|
171
|
+
source: tex.source
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return { geometry, uvMappings, embeddedTextures };
|
|
152
178
|
}
|
|
153
179
|
|
|
154
180
|
parseOutliner(outliner) {
|
|
@@ -191,12 +217,16 @@ class ModelAPI {
|
|
|
191
217
|
}
|
|
192
218
|
}
|
|
193
219
|
|
|
220
|
+
const base64 = buffer.toString("base64");
|
|
221
|
+
const mime = ext === ".png" ? "image/png" : (ext === ".jpg" || ext === ".jpeg") ? "image/jpeg" : "image/" + ext.substring(1);
|
|
222
|
+
|
|
194
223
|
return {
|
|
195
224
|
path: filePath,
|
|
196
225
|
width: width,
|
|
197
226
|
height: height,
|
|
198
227
|
format: ext.substring(1),
|
|
199
|
-
size: buffer.length
|
|
228
|
+
size: buffer.length,
|
|
229
|
+
dataURL: "data:" + mime + ";base64," + base64
|
|
200
230
|
};
|
|
201
231
|
}
|
|
202
232
|
|
|
@@ -269,6 +299,10 @@ class ModelAPI {
|
|
|
269
299
|
isModelLoaded(name) {
|
|
270
300
|
return this.loadedModels[name] !== undefined;
|
|
271
301
|
}
|
|
302
|
+
|
|
303
|
+
getLoadedModels() {
|
|
304
|
+
return this.loadedModels;
|
|
305
|
+
}
|
|
272
306
|
}
|
|
273
307
|
|
|
274
308
|
module.exports = ModelAPI;
|
package/src/cli/cag-cli.js
CHANGED
|
@@ -72,9 +72,6 @@ class CagCLI {
|
|
|
72
72
|
|
|
73
73
|
this.printLine("Project: " + engine.getInfo().ID);
|
|
74
74
|
this.printLine("Version: " + engine.getInfo().version);
|
|
75
|
-
this.printLine("Dependencies: " + engine.getDependencies().join(", "));
|
|
76
|
-
this.printLine("Code files: " + engine.getCodeFiles().length);
|
|
77
|
-
this.printLine("Resources: " + Object.keys(engine.getResourceMap()).length);
|
|
78
75
|
this.printLine("");
|
|
79
76
|
|
|
80
77
|
const CagcParser = require("../parser/cagc-parser");
|
|
@@ -91,26 +88,39 @@ class CagCLI {
|
|
|
91
88
|
const fileName = path.basename(filePath);
|
|
92
89
|
const content = fs.readFileSync(filePath, "utf-8");
|
|
93
90
|
|
|
94
|
-
this.printLine("Executing: " + fileName);
|
|
95
|
-
|
|
96
91
|
const parsed = cagcParser.parse(content, fileName);
|
|
97
92
|
const result = executor.execute(parsed);
|
|
98
93
|
|
|
99
94
|
if (result.errors && result.errors.length > 0) {
|
|
100
95
|
for (let j = 0; j < result.errors.length; j++) {
|
|
101
|
-
this.printError(
|
|
96
|
+
this.printError(result.errors[j]);
|
|
102
97
|
}
|
|
103
98
|
}
|
|
99
|
+
}
|
|
104
100
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
101
|
+
const registry = executor.getRegistry();
|
|
102
|
+
if (registry.has("Model.API")) {
|
|
103
|
+
const modelAPI = registry.get("Model.API");
|
|
104
|
+
const loadedModels = modelAPI.getLoadedModels();
|
|
105
|
+
const modelNames = Object.keys(loadedModels);
|
|
106
|
+
if (modelNames.length > 0) {
|
|
107
|
+
this.printLine("Reading UV mapping...");
|
|
108
|
+
for (let i = 0; i < modelNames.length; i++) {
|
|
109
|
+
const name = modelNames[i];
|
|
110
|
+
const model = loadedModels[name];
|
|
111
|
+
if (model && model.valid && model.texture) {
|
|
112
|
+
this.printSuccess("Auto Mapped Custom UV for " + name);
|
|
113
|
+
} else if (model && model.valid) {
|
|
114
|
+
this.printLine(" " + name + " (no texture paired)");
|
|
115
|
+
} else {
|
|
116
|
+
this.printError("Failed to map UV for " + name);
|
|
117
|
+
}
|
|
108
118
|
}
|
|
119
|
+
this.printLine("");
|
|
109
120
|
}
|
|
110
121
|
}
|
|
111
122
|
|
|
112
|
-
this.printLine("");
|
|
113
|
-
this.printSuccess("Execution complete. Launching game...");
|
|
123
|
+
this.printLine("Launching game...");
|
|
114
124
|
this.printLine("");
|
|
115
125
|
|
|
116
126
|
const settings = ElectronRunner.extractSettings(executor);
|
|
@@ -18,35 +18,37 @@ ElectronRunner.prototype.run = function () {
|
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
ElectronRunner.prototype.ensureDirectories = function () {
|
|
21
|
-
if (fs.existsSync(this.tempDir)) {
|
|
22
|
-
this.removeDirectory(this.tempDir);
|
|
23
|
-
}
|
|
24
21
|
fs.mkdirSync(this.tempDir, { recursive: true });
|
|
25
22
|
};
|
|
26
23
|
|
|
27
24
|
ElectronRunner.prototype.generateApp = function () {
|
|
28
|
-
var
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
25
|
+
var pkgPath = path.join(this.tempDir, "package.json");
|
|
26
|
+
if (!fs.existsSync(pkgPath)) {
|
|
27
|
+
var pkg = {
|
|
28
|
+
name: "cag-runner",
|
|
29
|
+
version: "1.0.0",
|
|
30
|
+
main: "main.js",
|
|
31
|
+
dependencies: {}
|
|
32
|
+
};
|
|
33
|
+
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
|
|
34
|
+
}
|
|
35
35
|
fs.writeFileSync(path.join(this.tempDir, "main.js"), this.getMainProcessSource());
|
|
36
36
|
fs.writeFileSync(path.join(this.tempDir, "index.html"), this.getRendererSource());
|
|
37
37
|
};
|
|
38
38
|
|
|
39
39
|
ElectronRunner.prototype.installAndLaunch = function () {
|
|
40
|
-
childProcess.execSync("npm install electron@latest --save --no-audit --no-fund", {
|
|
41
|
-
cwd: this.tempDir,
|
|
42
|
-
stdio: "inherit"
|
|
43
|
-
});
|
|
44
|
-
|
|
45
40
|
var electronBin = path.join(this.tempDir, "node_modules", ".bin", "electron");
|
|
46
41
|
if (process.platform === "win32") {
|
|
47
42
|
electronBin = electronBin + ".cmd";
|
|
48
43
|
}
|
|
49
44
|
|
|
45
|
+
if (!fs.existsSync(electronBin)) {
|
|
46
|
+
childProcess.execSync("npm install electron --save --no-audit --no-fund", {
|
|
47
|
+
cwd: this.tempDir,
|
|
48
|
+
stdio: "inherit"
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
50
52
|
childProcess.execSync("\"" + electronBin + "\" .", {
|
|
51
53
|
cwd: this.tempDir,
|
|
52
54
|
stdio: "inherit",
|
|
@@ -147,15 +149,15 @@ ElectronRunner.prototype.getRendererSource = function () {
|
|
|
147
149
|
|
|
148
150
|
var vsSrc = [
|
|
149
151
|
"attribute vec3 aPos;",
|
|
150
|
-
"attribute
|
|
152
|
+
"attribute vec2 aUV;",
|
|
151
153
|
"attribute vec3 aNormal;",
|
|
152
154
|
"uniform mat4 uProj;",
|
|
153
155
|
"uniform mat4 uView;",
|
|
154
|
-
"varying
|
|
156
|
+
"varying vec2 vUV;",
|
|
155
157
|
"varying vec3 vNormal;",
|
|
156
158
|
"varying vec3 vWorldPos;",
|
|
157
159
|
"void main() {",
|
|
158
|
-
"
|
|
160
|
+
" vUV = aUV;",
|
|
159
161
|
" vNormal = aNormal;",
|
|
160
162
|
" vWorldPos = aPos;",
|
|
161
163
|
" gl_Position = uProj * uView * vec4(aPos, 1.0);",
|
|
@@ -164,9 +166,10 @@ ElectronRunner.prototype.getRendererSource = function () {
|
|
|
164
166
|
|
|
165
167
|
var fsSrc = [
|
|
166
168
|
"precision mediump float;",
|
|
167
|
-
"varying
|
|
169
|
+
"varying vec2 vUV;",
|
|
168
170
|
"varying vec3 vNormal;",
|
|
169
171
|
"varying vec3 vWorldPos;",
|
|
172
|
+
"uniform sampler2D uTexture;",
|
|
170
173
|
"uniform vec3 uSunDir;",
|
|
171
174
|
"uniform vec3 uSunColor;",
|
|
172
175
|
"uniform vec3 uAmbient;",
|
|
@@ -175,13 +178,14 @@ ElectronRunner.prototype.getRendererSource = function () {
|
|
|
175
178
|
"uniform float uFogFar;",
|
|
176
179
|
"uniform vec3 uCamPos;",
|
|
177
180
|
"void main() {",
|
|
181
|
+
" vec4 texColor = texture2D(uTexture, vUV);",
|
|
178
182
|
" vec3 norm = normalize(vNormal);",
|
|
179
183
|
" float diff = max(dot(norm, normalize(uSunDir)), 0.0);",
|
|
180
|
-
" vec3 lit =
|
|
184
|
+
" vec3 lit = texColor.rgb * (uAmbient + uSunColor * diff);",
|
|
181
185
|
" float dist = length(vWorldPos - uCamPos);",
|
|
182
186
|
" float fog = clamp((dist - uFogNear) / (uFogFar - uFogNear), 0.0, 1.0);",
|
|
183
187
|
" vec3 final = mix(lit, uFogColor, fog);",
|
|
184
|
-
" gl_FragColor = vec4(final,
|
|
188
|
+
" gl_FragColor = vec4(final, texColor.a);",
|
|
185
189
|
"}"
|
|
186
190
|
].join("\\n");
|
|
187
191
|
|
|
@@ -193,6 +197,33 @@ ElectronRunner.prototype.getRendererSource = function () {
|
|
|
193
197
|
js.push("var VS_SRC = \"" + vsSrc + "\";");
|
|
194
198
|
js.push("var FS_SRC = \"" + fsSrc + "\";");
|
|
195
199
|
js.push("");
|
|
200
|
+
|
|
201
|
+
var modelDataForRenderer = {};
|
|
202
|
+
if (s.models) {
|
|
203
|
+
var sModelNames = Object.keys(s.models);
|
|
204
|
+
for (var mi = 0; mi < sModelNames.length; mi++) {
|
|
205
|
+
var smName = sModelNames[mi];
|
|
206
|
+
var smData = s.models[smName];
|
|
207
|
+
var faceUVMap = {};
|
|
208
|
+
if (smData.uvMappings) {
|
|
209
|
+
for (var ui = 0; ui < smData.uvMappings.length; ui++) {
|
|
210
|
+
var mapping = smData.uvMappings[ui];
|
|
211
|
+
if (!faceUVMap[mapping.face]) {
|
|
212
|
+
faceUVMap[mapping.face] = mapping.uv;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
modelDataForRenderer[smName] = {
|
|
217
|
+
textureDataURL: smData.textureDataURL || null,
|
|
218
|
+
resW: smData.resolution ? smData.resolution.width : 16,
|
|
219
|
+
resH: smData.resolution ? smData.resolution.height : 16,
|
|
220
|
+
faceUV: faceUVMap
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
js.push("var MODELS = " + JSON.stringify(modelDataForRenderer) + ";");
|
|
225
|
+
js.push("");
|
|
226
|
+
|
|
196
227
|
js.push("var game = {");
|
|
197
228
|
js.push(" gl: null, canvas: null, program: null,");
|
|
198
229
|
js.push(" camX: " + spX + ", camY: " + spY + ", camZ: " + spZ + ",");
|
|
@@ -225,34 +256,67 @@ ElectronRunner.prototype.getRendererSource = function () {
|
|
|
225
256
|
js.push("");
|
|
226
257
|
|
|
227
258
|
// Face helper
|
|
228
|
-
js.push("function addFace(pos,
|
|
259
|
+
js.push("function addFace(pos, uvArr, nrm, v0, v1, v2, v3, fuv, normal) {");
|
|
229
260
|
js.push(" pos.push(v0[0],v0[1],v0[2], v1[0],v1[1],v1[2], v2[0],v2[1],v2[2]);");
|
|
230
261
|
js.push(" pos.push(v0[0],v0[1],v0[2], v2[0],v2[1],v2[2], v3[0],v3[1],v3[2]);");
|
|
262
|
+
js.push(" uvArr.push(fuv[0],fuv[1], fuv[2],fuv[1], fuv[2],fuv[3]);");
|
|
263
|
+
js.push(" uvArr.push(fuv[0],fuv[1], fuv[2],fuv[3], fuv[0],fuv[3]);");
|
|
231
264
|
js.push(" for (var i = 0; i < 6; i++) {");
|
|
232
|
-
js.push(" col.push(color[0], color[1], color[2]);");
|
|
233
265
|
js.push(" nrm.push(normal[0], normal[1], normal[2]);");
|
|
234
266
|
js.push(" }");
|
|
235
267
|
js.push("}");
|
|
236
268
|
js.push("");
|
|
237
269
|
|
|
270
|
+
// UV normalization helper
|
|
271
|
+
js.push("function normUV(faceUV, resW, resH) {");
|
|
272
|
+
js.push(" if (!faceUV) return [0, 1, 1, 0];");
|
|
273
|
+
js.push(" return [faceUV[0]/resW, 1.0-faceUV[1]/resH, faceUV[2]/resW, 1.0-faceUV[3]/resH];");
|
|
274
|
+
js.push("}");
|
|
275
|
+
js.push("");
|
|
276
|
+
|
|
277
|
+
// Get UV coordinates for a model by name (case-insensitive)
|
|
278
|
+
js.push("function getModelUVs(name) {");
|
|
279
|
+
js.push(" var ln = name.toLowerCase();");
|
|
280
|
+
js.push(" var keys = Object.keys(MODELS);");
|
|
281
|
+
js.push(" for (var i = 0; i < keys.length; i++) {");
|
|
282
|
+
js.push(" if (keys[i].toLowerCase() === ln) {");
|
|
283
|
+
js.push(" var m = MODELS[keys[i]];");
|
|
284
|
+
js.push(" var f = m.faceUV || {};");
|
|
285
|
+
js.push(" return {");
|
|
286
|
+
js.push(" up: normUV(f.up, m.resW, m.resH),");
|
|
287
|
+
js.push(" down: normUV(f.down, m.resW, m.resH),");
|
|
288
|
+
js.push(" north: normUV(f.north, m.resW, m.resH),");
|
|
289
|
+
js.push(" south: normUV(f.south, m.resW, m.resH),");
|
|
290
|
+
js.push(" east: normUV(f.east, m.resW, m.resH),");
|
|
291
|
+
js.push(" west: normUV(f.west, m.resW, m.resH)");
|
|
292
|
+
js.push(" };");
|
|
293
|
+
js.push(" }");
|
|
294
|
+
js.push(" }");
|
|
295
|
+
js.push(" return { up:[0,1,1,0], down:[0,1,1,0], north:[0,1,1,0], south:[0,1,1,0], east:[0,1,1,0], west:[0,1,1,0] };");
|
|
296
|
+
js.push("}");
|
|
297
|
+
js.push("");
|
|
298
|
+
|
|
299
|
+
// Flip UV V-axis for side faces (v0/v1 are bottom vertices but addFace assigns fuv[1] to them)
|
|
300
|
+
js.push("function flipV(uv) { return [uv[0], uv[3], uv[2], uv[1]]; }");
|
|
301
|
+
js.push("");
|
|
302
|
+
|
|
238
303
|
// Build mesh for a chunk
|
|
239
304
|
js.push("function buildChunkMesh(blocks, blockMap) {");
|
|
240
|
-
js.push(" var pos = [],
|
|
241
|
-
js.push(" var
|
|
242
|
-
js.push(" var
|
|
243
|
-
js.push(" var botC = [0.45, 0.32, 0.17];");
|
|
305
|
+
js.push(" var pos = [], uvArr = [], nrm = [];");
|
|
306
|
+
js.push(" var uv = getModelUVs('Grass');");
|
|
307
|
+
js.push(" var sN = flipV(uv.north), sS = flipV(uv.south), sE = flipV(uv.east), sW = flipV(uv.west);");
|
|
244
308
|
js.push(" for (var i = 0; i < blocks.length; i++) {");
|
|
245
309
|
js.push(" var b = blocks[i];");
|
|
246
310
|
js.push(" var x = b.x, y = b.y, z = b.z;");
|
|
247
311
|
js.push(" var k = function(bx,by,bz) { return bx+','+by+','+bz; };");
|
|
248
|
-
js.push(" if (!blockMap[k(x,y+1,z)]) addFace(pos,
|
|
249
|
-
js.push(" if (!blockMap[k(x,y-1,z)]) addFace(pos,
|
|
250
|
-
js.push(" if (!blockMap[k(x,y,z-1)]) addFace(pos,
|
|
251
|
-
js.push(" if (!blockMap[k(x,y,z+1)]) addFace(pos,
|
|
252
|
-
js.push(" if (!blockMap[k(x
|
|
253
|
-
js.push(" if (!blockMap[k(x
|
|
312
|
+
js.push(" if (!blockMap[k(x,y+1,z)]) addFace(pos,uvArr,nrm, [x,y+1,z],[x+1,y+1,z],[x+1,y+1,z+1],[x,y+1,z+1], uv.up, [0,1,0]);");
|
|
313
|
+
js.push(" if (!blockMap[k(x,y-1,z)]) addFace(pos,uvArr,nrm, [x,y,z+1],[x+1,y,z+1],[x+1,y,z],[x,y,z], uv.down, [0,-1,0]);");
|
|
314
|
+
js.push(" if (!blockMap[k(x,y,z-1)]) addFace(pos,uvArr,nrm, [x,y,z],[x+1,y,z],[x+1,y+1,z],[x,y+1,z], sN, [0,0,-1]);");
|
|
315
|
+
js.push(" if (!blockMap[k(x,y,z+1)]) addFace(pos,uvArr,nrm, [x+1,y,z+1],[x,y,z+1],[x,y+1,z+1],[x+1,y+1,z+1], sS, [0,0,1]);");
|
|
316
|
+
js.push(" if (!blockMap[k(x+1,y,z)]) addFace(pos,uvArr,nrm, [x+1,y,z],[x+1,y,z+1],[x+1,y+1,z+1],[x+1,y+1,z], sE, [1,0,0]);");
|
|
317
|
+
js.push(" if (!blockMap[k(x-1,y,z)]) addFace(pos,uvArr,nrm, [x,y,z+1],[x,y,z],[x,y+1,z],[x,y+1,z+1], sW, [-1,0,0]);");
|
|
254
318
|
js.push(" }");
|
|
255
|
-
js.push(" return { positions: pos,
|
|
319
|
+
js.push(" return { positions: pos, uvs: uvArr, normals: nrm };");
|
|
256
320
|
js.push("}");
|
|
257
321
|
js.push("");
|
|
258
322
|
|
|
@@ -286,17 +350,16 @@ ElectronRunner.prototype.getRendererSource = function () {
|
|
|
286
350
|
js.push(" var vertCount = mesh.positions.length / 3;");
|
|
287
351
|
js.push(" var gl = game.gl;");
|
|
288
352
|
js.push(" var vbo = gl.createBuffer();");
|
|
289
|
-
js.push(" var data = new Float32Array(vertCount *
|
|
353
|
+
js.push(" var data = new Float32Array(vertCount * 8);");
|
|
290
354
|
js.push(" for (var v = 0; v < vertCount; v++) {");
|
|
291
|
-
js.push(" data[v*
|
|
292
|
-
js.push(" data[v*
|
|
293
|
-
js.push(" data[v*
|
|
294
|
-
js.push(" data[v*
|
|
295
|
-
js.push(" data[v*
|
|
296
|
-
js.push(" data[v*
|
|
297
|
-
js.push(" data[v*
|
|
298
|
-
js.push(" data[v*
|
|
299
|
-
js.push(" data[v*9+8] = mesh.normals[v*3+2];");
|
|
355
|
+
js.push(" data[v*8+0] = mesh.positions[v*3+0];");
|
|
356
|
+
js.push(" data[v*8+1] = mesh.positions[v*3+1];");
|
|
357
|
+
js.push(" data[v*8+2] = mesh.positions[v*3+2];");
|
|
358
|
+
js.push(" data[v*8+3] = mesh.uvs[v*2+0];");
|
|
359
|
+
js.push(" data[v*8+4] = mesh.uvs[v*2+1];");
|
|
360
|
+
js.push(" data[v*8+5] = mesh.normals[v*3+0];");
|
|
361
|
+
js.push(" data[v*8+6] = mesh.normals[v*3+1];");
|
|
362
|
+
js.push(" data[v*8+7] = mesh.normals[v*3+2];");
|
|
300
363
|
js.push(" }");
|
|
301
364
|
js.push(" gl.bindBuffer(gl.ARRAY_BUFFER, vbo);");
|
|
302
365
|
js.push(" gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);");
|
|
@@ -359,7 +422,7 @@ ElectronRunner.prototype.getRendererSource = function () {
|
|
|
359
422
|
js.push(" gl.attachShader(this.program, vs);");
|
|
360
423
|
js.push(" gl.attachShader(this.program, fsh);");
|
|
361
424
|
js.push(" gl.bindAttribLocation(this.program, 0, 'aPos');");
|
|
362
|
-
js.push(" gl.bindAttribLocation(this.program, 1, '
|
|
425
|
+
js.push(" gl.bindAttribLocation(this.program, 1, 'aUV');");
|
|
363
426
|
js.push(" gl.bindAttribLocation(this.program, 2, 'aNormal');");
|
|
364
427
|
js.push(" gl.linkProgram(this.program);");
|
|
365
428
|
js.push(" gl.useProgram(this.program);");
|
|
@@ -373,6 +436,7 @@ ElectronRunner.prototype.getRendererSource = function () {
|
|
|
373
436
|
js.push(" this.uFogNear = gl.getUniformLocation(this.program, 'uFogNear');");
|
|
374
437
|
js.push(" this.uFogFar = gl.getUniformLocation(this.program, 'uFogFar');");
|
|
375
438
|
js.push(" this.uCamPos = gl.getUniformLocation(this.program, 'uCamPos');");
|
|
439
|
+
js.push(" this.uTexture = gl.getUniformLocation(this.program, 'uTexture');");
|
|
376
440
|
js.push("");
|
|
377
441
|
js.push(" gl.uniform3f(this.uSunDir, " + sunD.x + ", " + sunD.y + ", " + sunD.z + ");");
|
|
378
442
|
js.push(" gl.uniform3f(this.uSunColor, 1.0, 0.95, 0.8);");
|
|
@@ -381,6 +445,24 @@ ElectronRunner.prototype.getRendererSource = function () {
|
|
|
381
445
|
js.push(" gl.uniform1f(this.uFogNear, " + fogNear + ");");
|
|
382
446
|
js.push(" gl.uniform1f(this.uFogFar, " + fogFar + ");");
|
|
383
447
|
js.push("");
|
|
448
|
+
js.push(" this.blockTexture = gl.createTexture();");
|
|
449
|
+
js.push(" gl.bindTexture(gl.TEXTURE_2D, this.blockTexture);");
|
|
450
|
+
js.push(" gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([128,128,128,255]));");
|
|
451
|
+
js.push(" var texKeys = Object.keys(MODELS);");
|
|
452
|
+
js.push(" if (texKeys.length > 0 && MODELS[texKeys[0]].textureDataURL) {");
|
|
453
|
+
js.push(" var texImg = new Image();");
|
|
454
|
+
js.push(" texImg.onload = function() {");
|
|
455
|
+
js.push(" var g = game.gl;");
|
|
456
|
+
js.push(" g.bindTexture(g.TEXTURE_2D, game.blockTexture);");
|
|
457
|
+
js.push(" g.texImage2D(g.TEXTURE_2D, 0, g.RGBA, g.RGBA, g.UNSIGNED_BYTE, texImg);");
|
|
458
|
+
js.push(" g.texParameteri(g.TEXTURE_2D, g.TEXTURE_MIN_FILTER, g.NEAREST);");
|
|
459
|
+
js.push(" g.texParameteri(g.TEXTURE_2D, g.TEXTURE_MAG_FILTER, g.NEAREST);");
|
|
460
|
+
js.push(" g.texParameteri(g.TEXTURE_2D, g.TEXTURE_WRAP_S, g.CLAMP_TO_EDGE);");
|
|
461
|
+
js.push(" g.texParameteri(g.TEXTURE_2D, g.TEXTURE_WRAP_T, g.CLAMP_TO_EDGE);");
|
|
462
|
+
js.push(" };");
|
|
463
|
+
js.push(" texImg.src = MODELS[texKeys[0]].textureDataURL;");
|
|
464
|
+
js.push(" }");
|
|
465
|
+
js.push("");
|
|
384
466
|
js.push(" gl.enable(gl.DEPTH_TEST);");
|
|
385
467
|
js.push(" gl.enable(gl.CULL_FACE);");
|
|
386
468
|
js.push(" gl.cullFace(gl.BACK);");
|
|
@@ -407,16 +489,8 @@ ElectronRunner.prototype.getRendererSource = function () {
|
|
|
407
489
|
js.push("");
|
|
408
490
|
js.push(" setInterval(function () { game.fps = game.frames; game.frames = 0; }, 1000);");
|
|
409
491
|
js.push("");
|
|
410
|
-
js.push("
|
|
411
|
-
js.push("
|
|
412
|
-
js.push(" var overlayEl = document.getElementById('click-overlay');");
|
|
413
|
-
js.push(" overlayEl.style.display = 'flex';");
|
|
414
|
-
js.push(" overlayEl.addEventListener('click', function () {");
|
|
415
|
-
js.push(" overlayEl.style.display = 'none';");
|
|
416
|
-
js.push(" game.canvas.requestPointerLock();");
|
|
417
|
-
js.push(" game.started = true;");
|
|
418
|
-
js.push(" game.loop();");
|
|
419
|
-
js.push(" });");
|
|
492
|
+
js.push(" game.started = true;");
|
|
493
|
+
js.push(" game.loop();");
|
|
420
494
|
js.push("};");
|
|
421
495
|
js.push("");
|
|
422
496
|
|
|
@@ -495,7 +569,11 @@ ElectronRunner.prototype.getRendererSource = function () {
|
|
|
495
569
|
js.push(" gl.uniformMatrix4fv(this.uView, false, view);");
|
|
496
570
|
js.push(" gl.uniform3f(this.uCamPos, this.camX, this.camY, this.camZ);");
|
|
497
571
|
js.push("");
|
|
498
|
-
js.push("
|
|
572
|
+
js.push(" gl.activeTexture(gl.TEXTURE0);");
|
|
573
|
+
js.push(" gl.bindTexture(gl.TEXTURE_2D, this.blockTexture);");
|
|
574
|
+
js.push(" gl.uniform1i(this.uTexture, 0);");
|
|
575
|
+
js.push("");
|
|
576
|
+
js.push(" var stride = 8 * 4;");
|
|
499
577
|
js.push(" var keys = Object.keys(this.chunks);");
|
|
500
578
|
js.push(" for (var i = 0; i < keys.length; i++) {");
|
|
501
579
|
js.push(" var chunk = this.chunks[keys[i]];");
|
|
@@ -505,35 +583,13 @@ ElectronRunner.prototype.getRendererSource = function () {
|
|
|
505
583
|
js.push(" gl.enableVertexAttribArray(1);");
|
|
506
584
|
js.push(" gl.enableVertexAttribArray(2);");
|
|
507
585
|
js.push(" gl.vertexAttribPointer(0, 3, gl.FLOAT, false, stride, 0);");
|
|
508
|
-
js.push(" gl.vertexAttribPointer(1,
|
|
509
|
-
js.push(" gl.vertexAttribPointer(2, 3, gl.FLOAT, false, stride,
|
|
586
|
+
js.push(" gl.vertexAttribPointer(1, 2, gl.FLOAT, false, stride, 12);");
|
|
587
|
+
js.push(" gl.vertexAttribPointer(2, 3, gl.FLOAT, false, stride, 20);");
|
|
510
588
|
js.push(" gl.drawArrays(gl.TRIANGLES, 0, chunk.vertCount);");
|
|
511
589
|
js.push(" }");
|
|
512
590
|
js.push("};");
|
|
513
591
|
js.push("");
|
|
514
592
|
|
|
515
|
-
// HUD
|
|
516
|
-
js.push("game.updateHUD = function () {");
|
|
517
|
-
js.push(" var pcx = Math.floor(this.camX / CHUNK_SIZE);");
|
|
518
|
-
js.push(" var pcz = Math.floor(this.camZ / CHUNK_SIZE);");
|
|
519
|
-
js.push(" var loadedCount = Object.keys(this.chunks).length;");
|
|
520
|
-
js.push(" var sprint = this.keys['ShiftLeft'] || this.keys['ShiftRight'];");
|
|
521
|
-
js.push(" var html = '<div class=\"hud-title\">' + INFO_ID + '</div>';");
|
|
522
|
-
js.push(" html += '<div>v' + INFO_VERSION + '</div>';");
|
|
523
|
-
js.push(" html += '<div class=\"hud-sep\"></div>';");
|
|
524
|
-
js.push(" html += '<div>FPS: ' + this.fps + '</div>';");
|
|
525
|
-
js.push(" html += '<div>Triangles: ' + Math.floor(this.totalVerts / 3) + '</div>';");
|
|
526
|
-
js.push(" html += '<div>Blocks: ' + this.totalBlocks + '</div>';");
|
|
527
|
-
js.push(" html += '<div>Chunks: ' + loadedCount + '</div>';");
|
|
528
|
-
js.push(" html += '<div class=\"hud-sep\"></div>';");
|
|
529
|
-
js.push(" html += '<div>X: ' + this.camX.toFixed(1) + '</div>';");
|
|
530
|
-
js.push(" html += '<div>Y: ' + this.camY.toFixed(1) + '</div>';");
|
|
531
|
-
js.push(" html += '<div>Z: ' + this.camZ.toFixed(1) + '</div>';");
|
|
532
|
-
js.push(" html += '<div>Chunk: ' + pcx + ', ' + pcz + '</div>';");
|
|
533
|
-
js.push(" html += '<div class=\"hud-sep\"></div>';");
|
|
534
|
-
js.push(" html += '<div>Sprint: ' + (sprint ? 'ON' : 'OFF') + '</div>';");
|
|
535
|
-
js.push(" document.getElementById('hud-info').innerHTML = html;");
|
|
536
|
-
js.push("};");
|
|
537
593
|
js.push("");
|
|
538
594
|
|
|
539
595
|
// Game loop
|
|
@@ -543,35 +599,18 @@ ElectronRunner.prototype.getRendererSource = function () {
|
|
|
543
599
|
js.push(" game.update();");
|
|
544
600
|
js.push(" updateChunks();");
|
|
545
601
|
js.push(" game.render();");
|
|
546
|
-
js.push(" game.updateHUD();");
|
|
547
602
|
js.push("};");
|
|
548
603
|
js.push("");
|
|
549
604
|
|
|
550
|
-
|
|
551
|
-
js.push("var bar = document.getElementById('bar-inner');");
|
|
552
|
-
js.push("var status = document.getElementById('load-status');");
|
|
553
|
-
js.push("setTimeout(function () { bar.style.width = '25%'; status.textContent = 'Compiling shaders...'; }, 200);");
|
|
554
|
-
js.push("setTimeout(function () { bar.style.width = '50%'; status.textContent = 'Generating chunks...'; }, 600);");
|
|
555
|
-
js.push("setTimeout(function () { bar.style.width = '75%'; status.textContent = 'Building meshes...'; }, 1000);");
|
|
556
|
-
js.push("setTimeout(function () { bar.style.width = '100%'; status.textContent = 'Ready!'; status.style.color = '#4ecca3'; }, 1400);");
|
|
557
|
-
js.push("setTimeout(function () { game.init(); }, 1800);");
|
|
605
|
+
js.push("game.init();");
|
|
558
606
|
|
|
559
607
|
var html = "<!DOCTYPE html>\n<html>\n<head>\n";
|
|
560
608
|
html += "<meta charset='utf-8'>\n";
|
|
561
609
|
html += "<title>" + windowTitle + " - CaG Engine</title>\n";
|
|
562
610
|
html += "<style>\n" + css + "\n</style>\n";
|
|
563
611
|
html += "</head>\n<body>\n";
|
|
564
|
-
html += "<div id='loading'>\n";
|
|
565
|
-
html += " <h1>CaG</h1>\n";
|
|
566
|
-
html += " <h2>" + infoID + "</h2>\n";
|
|
567
|
-
html += " <div id='load-status'>Starting...</div>\n";
|
|
568
|
-
html += " <div id='bar-outer'><div id='bar-inner'></div></div>\n";
|
|
569
|
-
html += " <div class='version-tag'>v" + infoVer + "</div>\n";
|
|
570
|
-
html += "</div>\n";
|
|
571
|
-
html += "<div id='click-overlay' style='display:none'><div class='play-icon'><div class='play-triangle'></div></div><span>CLICK TO PLAY</span></div>\n";
|
|
572
612
|
html += "<div id='crosshair' style='display:none'></div>\n";
|
|
573
|
-
html += "
|
|
574
|
-
html += "<div id='controls-hint'><b>WASD</b> Move <b>Mouse</b> Look <b>Space</b> Jump <b>Shift</b> Sprint <b>F11</b> Fullscreen <b>Esc</b> Release</div>\n";
|
|
613
|
+
html += "";
|
|
575
614
|
html += "<canvas id='cag-canvas'></canvas>\n";
|
|
576
615
|
html += "<script>\n" + js.join("\n") + "\n</script>\n";
|
|
577
616
|
html += "</body>\n</html>";
|
|
@@ -638,6 +677,32 @@ ElectronRunner.extractSettings = function (executor) {
|
|
|
638
677
|
settings.renderDistance = chunkAPI.renderDistance;
|
|
639
678
|
}
|
|
640
679
|
|
|
680
|
+
if (registry.has("Model.API")) {
|
|
681
|
+
var modelAPI = registry.get("Model.API");
|
|
682
|
+
var loadedModels = modelAPI.getLoadedModels();
|
|
683
|
+
settings.models = {};
|
|
684
|
+
if (loadedModels) {
|
|
685
|
+
var modelNames = Object.keys(loadedModels);
|
|
686
|
+
for (var mi = 0; mi < modelNames.length; mi++) {
|
|
687
|
+
var mName = modelNames[mi];
|
|
688
|
+
var model = loadedModels[mName];
|
|
689
|
+
if (model && model.valid) {
|
|
690
|
+
var texW = model.texture ? model.texture.width : 0;
|
|
691
|
+
var texH = model.texture ? model.texture.height : 0;
|
|
692
|
+
if (!texW || !texH) {
|
|
693
|
+
texW = model.geometry ? model.geometry.resolution.width : 16;
|
|
694
|
+
texH = model.geometry ? model.geometry.resolution.height : 16;
|
|
695
|
+
}
|
|
696
|
+
settings.models[mName] = {
|
|
697
|
+
uvMappings: model.uvMappings || [],
|
|
698
|
+
resolution: { width: texW, height: texH },
|
|
699
|
+
textureDataURL: model.texture && model.texture.dataURL ? model.texture.dataURL : null
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
|
|
641
706
|
return settings;
|
|
642
707
|
};
|
|
643
708
|
|