@erik9994857/cag 2.0.0 → 2.0.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@erik9994857/cag",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "CaG — A code library and custom language for building 3D worlds with .cagc files, .bbmodel support, and auto UV mapping",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -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
- return { geometry, uvMappings };
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;
@@ -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(" " + result.errors[j]);
96
+ this.printError(result.errors[j]);
102
97
  }
103
98
  }
99
+ }
104
100
 
105
- if (result.outputs && result.outputs.length > 0) {
106
- for (let j = 0; j < result.outputs.length; j++) {
107
- this.printLine(" > " + result.outputs[j]);
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 pkg = {
29
- name: "cag-runner",
30
- version: "1.0.0",
31
- main: "main.js",
32
- dependencies: {}
33
- };
34
- fs.writeFileSync(path.join(this.tempDir, "package.json"), JSON.stringify(pkg, null, 2));
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 vec3 aColor;",
152
+ "attribute vec2 aUV;",
151
153
  "attribute vec3 aNormal;",
152
154
  "uniform mat4 uProj;",
153
155
  "uniform mat4 uView;",
154
- "varying vec3 vColor;",
156
+ "varying vec2 vUV;",
155
157
  "varying vec3 vNormal;",
156
158
  "varying vec3 vWorldPos;",
157
159
  "void main() {",
158
- " vColor = aColor;",
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 vec3 vColor;",
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 = vColor * (uAmbient + uSunColor * diff);",
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, 1.0);",
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,62 @@ ElectronRunner.prototype.getRendererSource = function () {
225
256
  js.push("");
226
257
 
227
258
  // Face helper
228
- js.push("function addFace(pos, col, nrm, v0, v1, v2, v3, color, normal) {");
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
+
238
299
  // Build mesh for a chunk
239
300
  js.push("function buildChunkMesh(blocks, blockMap) {");
240
- js.push(" var pos = [], col = [], nrm = [];");
241
- js.push(" var topC = [0.36, 0.63, 0.21];");
242
- js.push(" var sideC = [0.50, 0.38, 0.22];");
243
- js.push(" var botC = [0.45, 0.32, 0.17];");
301
+ js.push(" var pos = [], uvArr = [], nrm = [];");
302
+ js.push(" var uv = getModelUVs('Grass');");
244
303
  js.push(" for (var i = 0; i < blocks.length; i++) {");
245
304
  js.push(" var b = blocks[i];");
246
305
  js.push(" var x = b.x, y = b.y, z = b.z;");
247
306
  js.push(" var k = function(bx,by,bz) { return bx+','+by+','+bz; };");
248
- js.push(" if (!blockMap[k(x,y+1,z)]) addFace(pos,col,nrm, [x,y+1,z],[x+1,y+1,z],[x+1,y+1,z+1],[x,y+1,z+1], topC, [0,1,0]);");
249
- js.push(" if (!blockMap[k(x,y-1,z)]) addFace(pos,col,nrm, [x,y,z+1],[x+1,y,z+1],[x+1,y,z],[x,y,z], botC, [0,-1,0]);");
250
- js.push(" if (!blockMap[k(x,y,z-1)]) addFace(pos,col,nrm, [x,y,z],[x+1,y,z],[x+1,y+1,z],[x,y+1,z], sideC, [0,0,-1]);");
251
- js.push(" if (!blockMap[k(x,y,z+1)]) addFace(pos,col,nrm, [x+1,y,z+1],[x,y,z+1],[x,y+1,z+1],[x+1,y+1,z+1], sideC, [0,0,1]);");
252
- js.push(" if (!blockMap[k(x-1,y,z)]) addFace(pos,col,nrm, [x,y,z+1],[x,y,z],[x,y+1,z],[x,y+1,z+1], sideC, [-1,0,0]);");
253
- js.push(" if (!blockMap[k(x+1,y,z)]) addFace(pos,col,nrm, [x+1,y,z],[x+1,y,z+1],[x+1,y+1,z+1],[x+1,y+1,z], sideC, [1,0,0]);");
307
+ 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]);");
308
+ 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]);");
309
+ 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], uv.north, [0,0,-1]);");
310
+ 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], uv.south, [0,0,1]);");
311
+ 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], uv.east, [1,0,0]);");
312
+ 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], uv.west, [-1,0,0]);");
254
313
  js.push(" }");
255
- js.push(" return { positions: pos, colors: col, normals: nrm };");
314
+ js.push(" return { positions: pos, uvs: uvArr, normals: nrm };");
256
315
  js.push("}");
257
316
  js.push("");
258
317
 
@@ -286,17 +345,16 @@ ElectronRunner.prototype.getRendererSource = function () {
286
345
  js.push(" var vertCount = mesh.positions.length / 3;");
287
346
  js.push(" var gl = game.gl;");
288
347
  js.push(" var vbo = gl.createBuffer();");
289
- js.push(" var data = new Float32Array(vertCount * 9);");
348
+ js.push(" var data = new Float32Array(vertCount * 8);");
290
349
  js.push(" for (var v = 0; v < vertCount; v++) {");
291
- js.push(" data[v*9+0] = mesh.positions[v*3+0];");
292
- js.push(" data[v*9+1] = mesh.positions[v*3+1];");
293
- js.push(" data[v*9+2] = mesh.positions[v*3+2];");
294
- js.push(" data[v*9+3] = mesh.colors[v*3+0];");
295
- js.push(" data[v*9+4] = mesh.colors[v*3+1];");
296
- js.push(" data[v*9+5] = mesh.colors[v*3+2];");
297
- js.push(" data[v*9+6] = mesh.normals[v*3+0];");
298
- js.push(" data[v*9+7] = mesh.normals[v*3+1];");
299
- js.push(" data[v*9+8] = mesh.normals[v*3+2];");
350
+ js.push(" data[v*8+0] = mesh.positions[v*3+0];");
351
+ js.push(" data[v*8+1] = mesh.positions[v*3+1];");
352
+ js.push(" data[v*8+2] = mesh.positions[v*3+2];");
353
+ js.push(" data[v*8+3] = mesh.uvs[v*2+0];");
354
+ js.push(" data[v*8+4] = mesh.uvs[v*2+1];");
355
+ js.push(" data[v*8+5] = mesh.normals[v*3+0];");
356
+ js.push(" data[v*8+6] = mesh.normals[v*3+1];");
357
+ js.push(" data[v*8+7] = mesh.normals[v*3+2];");
300
358
  js.push(" }");
301
359
  js.push(" gl.bindBuffer(gl.ARRAY_BUFFER, vbo);");
302
360
  js.push(" gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);");
@@ -359,7 +417,7 @@ ElectronRunner.prototype.getRendererSource = function () {
359
417
  js.push(" gl.attachShader(this.program, vs);");
360
418
  js.push(" gl.attachShader(this.program, fsh);");
361
419
  js.push(" gl.bindAttribLocation(this.program, 0, 'aPos');");
362
- js.push(" gl.bindAttribLocation(this.program, 1, 'aColor');");
420
+ js.push(" gl.bindAttribLocation(this.program, 1, 'aUV');");
363
421
  js.push(" gl.bindAttribLocation(this.program, 2, 'aNormal');");
364
422
  js.push(" gl.linkProgram(this.program);");
365
423
  js.push(" gl.useProgram(this.program);");
@@ -373,6 +431,7 @@ ElectronRunner.prototype.getRendererSource = function () {
373
431
  js.push(" this.uFogNear = gl.getUniformLocation(this.program, 'uFogNear');");
374
432
  js.push(" this.uFogFar = gl.getUniformLocation(this.program, 'uFogFar');");
375
433
  js.push(" this.uCamPos = gl.getUniformLocation(this.program, 'uCamPos');");
434
+ js.push(" this.uTexture = gl.getUniformLocation(this.program, 'uTexture');");
376
435
  js.push("");
377
436
  js.push(" gl.uniform3f(this.uSunDir, " + sunD.x + ", " + sunD.y + ", " + sunD.z + ");");
378
437
  js.push(" gl.uniform3f(this.uSunColor, 1.0, 0.95, 0.8);");
@@ -381,6 +440,24 @@ ElectronRunner.prototype.getRendererSource = function () {
381
440
  js.push(" gl.uniform1f(this.uFogNear, " + fogNear + ");");
382
441
  js.push(" gl.uniform1f(this.uFogFar, " + fogFar + ");");
383
442
  js.push("");
443
+ js.push(" this.blockTexture = gl.createTexture();");
444
+ js.push(" gl.bindTexture(gl.TEXTURE_2D, this.blockTexture);");
445
+ js.push(" gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([128,128,128,255]));");
446
+ js.push(" var texKeys = Object.keys(MODELS);");
447
+ js.push(" if (texKeys.length > 0 && MODELS[texKeys[0]].textureDataURL) {");
448
+ js.push(" var texImg = new Image();");
449
+ js.push(" texImg.onload = function() {");
450
+ js.push(" var g = game.gl;");
451
+ js.push(" g.bindTexture(g.TEXTURE_2D, game.blockTexture);");
452
+ js.push(" g.texImage2D(g.TEXTURE_2D, 0, g.RGBA, g.RGBA, g.UNSIGNED_BYTE, texImg);");
453
+ js.push(" g.texParameteri(g.TEXTURE_2D, g.TEXTURE_MIN_FILTER, g.NEAREST);");
454
+ js.push(" g.texParameteri(g.TEXTURE_2D, g.TEXTURE_MAG_FILTER, g.NEAREST);");
455
+ js.push(" g.texParameteri(g.TEXTURE_2D, g.TEXTURE_WRAP_S, g.CLAMP_TO_EDGE);");
456
+ js.push(" g.texParameteri(g.TEXTURE_2D, g.TEXTURE_WRAP_T, g.CLAMP_TO_EDGE);");
457
+ js.push(" };");
458
+ js.push(" texImg.src = MODELS[texKeys[0]].textureDataURL;");
459
+ js.push(" }");
460
+ js.push("");
384
461
  js.push(" gl.enable(gl.DEPTH_TEST);");
385
462
  js.push(" gl.enable(gl.CULL_FACE);");
386
463
  js.push(" gl.cullFace(gl.BACK);");
@@ -407,16 +484,8 @@ ElectronRunner.prototype.getRendererSource = function () {
407
484
  js.push("");
408
485
  js.push(" setInterval(function () { game.fps = game.frames; game.frames = 0; }, 1000);");
409
486
  js.push("");
410
- js.push(" var loadingEl = document.getElementById('loading');");
411
- js.push(" loadingEl.classList.add('fade-out');");
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(" });");
487
+ js.push(" game.started = true;");
488
+ js.push(" game.loop();");
420
489
  js.push("};");
421
490
  js.push("");
422
491
 
@@ -495,7 +564,11 @@ ElectronRunner.prototype.getRendererSource = function () {
495
564
  js.push(" gl.uniformMatrix4fv(this.uView, false, view);");
496
565
  js.push(" gl.uniform3f(this.uCamPos, this.camX, this.camY, this.camZ);");
497
566
  js.push("");
498
- js.push(" var stride = 9 * 4;");
567
+ js.push(" gl.activeTexture(gl.TEXTURE0);");
568
+ js.push(" gl.bindTexture(gl.TEXTURE_2D, this.blockTexture);");
569
+ js.push(" gl.uniform1i(this.uTexture, 0);");
570
+ js.push("");
571
+ js.push(" var stride = 8 * 4;");
499
572
  js.push(" var keys = Object.keys(this.chunks);");
500
573
  js.push(" for (var i = 0; i < keys.length; i++) {");
501
574
  js.push(" var chunk = this.chunks[keys[i]];");
@@ -505,8 +578,8 @@ ElectronRunner.prototype.getRendererSource = function () {
505
578
  js.push(" gl.enableVertexAttribArray(1);");
506
579
  js.push(" gl.enableVertexAttribArray(2);");
507
580
  js.push(" gl.vertexAttribPointer(0, 3, gl.FLOAT, false, stride, 0);");
508
- js.push(" gl.vertexAttribPointer(1, 3, gl.FLOAT, false, stride, 12);");
509
- js.push(" gl.vertexAttribPointer(2, 3, gl.FLOAT, false, stride, 24);");
581
+ js.push(" gl.vertexAttribPointer(1, 2, gl.FLOAT, false, stride, 12);");
582
+ js.push(" gl.vertexAttribPointer(2, 3, gl.FLOAT, false, stride, 20);");
510
583
  js.push(" gl.drawArrays(gl.TRIANGLES, 0, chunk.vertCount);");
511
584
  js.push(" }");
512
585
  js.push("};");
@@ -547,28 +620,13 @@ ElectronRunner.prototype.getRendererSource = function () {
547
620
  js.push("};");
548
621
  js.push("");
549
622
 
550
- // Loading animation
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);");
623
+ js.push("game.init();");
558
624
 
559
625
  var html = "<!DOCTYPE html>\n<html>\n<head>\n";
560
626
  html += "<meta charset='utf-8'>\n";
561
627
  html += "<title>" + windowTitle + " - CaG Engine</title>\n";
562
628
  html += "<style>\n" + css + "\n</style>\n";
563
629
  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
630
  html += "<div id='crosshair' style='display:none'></div>\n";
573
631
  html += "<div id='hud'><div id='hud-box'><div id='hud-info'></div></div></div>\n";
574
632
  html += "<div id='controls-hint'><b>WASD</b> Move &nbsp; <b>Mouse</b> Look &nbsp; <b>Space</b> Jump &nbsp; <b>Shift</b> Sprint &nbsp; <b>F11</b> Fullscreen &nbsp; <b>Esc</b> Release</div>\n";
@@ -638,6 +696,32 @@ ElectronRunner.extractSettings = function (executor) {
638
696
  settings.renderDistance = chunkAPI.renderDistance;
639
697
  }
640
698
 
699
+ if (registry.has("Model.API")) {
700
+ var modelAPI = registry.get("Model.API");
701
+ var loadedModels = modelAPI.getLoadedModels();
702
+ settings.models = {};
703
+ if (loadedModels) {
704
+ var modelNames = Object.keys(loadedModels);
705
+ for (var mi = 0; mi < modelNames.length; mi++) {
706
+ var mName = modelNames[mi];
707
+ var model = loadedModels[mName];
708
+ if (model && model.valid) {
709
+ var texW = model.texture ? model.texture.width : 0;
710
+ var texH = model.texture ? model.texture.height : 0;
711
+ if (!texW || !texH) {
712
+ texW = model.geometry ? model.geometry.resolution.width : 16;
713
+ texH = model.geometry ? model.geometry.resolution.height : 16;
714
+ }
715
+ settings.models[mName] = {
716
+ uvMappings: model.uvMappings || [],
717
+ resolution: { width: texW, height: texH },
718
+ textureDataURL: model.texture && model.texture.dataURL ? model.texture.dataURL : null
719
+ };
720
+ }
721
+ }
722
+ }
723
+ }
724
+
641
725
  return settings;
642
726
  };
643
727