@erik9994857/cag 1.0.0
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/bin/cag +10 -0
- package/defaults/info.cag +4 -0
- package/defaults/main.cag +3 -0
- package/defaults/src/code/example.cagc +5 -0
- package/package.json +33 -0
- package/src/api/api-registry.js +144 -0
- package/src/api/model-api.js +274 -0
- package/src/api/pull-api.js +331 -0
- package/src/api/worldgen-api.js +332 -0
- package/src/cli/cag-cli.js +324 -0
- package/src/index.js +214 -0
- package/src/models/bbmodel-parser.js +320 -0
- package/src/models/uv-mapper.js +315 -0
- package/src/parser/cag-parser.js +241 -0
- package/src/parser/cagc-parser.js +255 -0
- package/src/parser/tokenizer.js +233 -0
- package/src/resources/resource-loader.js +257 -0
- package/src/runtime/context.js +163 -0
- package/src/runtime/executor.js +213 -0
- package/src/runtime/scope.js +198 -0
- package/src/utils/file-resolver.js +208 -0
- package/src/utils/id-validator.js +171 -0
- package/src/utils/logger.js +203 -0
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
|
|
4
|
+
class BBModelParser {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.supportedFormatVersions = ["4.0", "4.5", "4.6", "4.7", "4.8", "4.9", "4.10"];
|
|
7
|
+
this.faceNames = ["north", "south", "east", "west", "up", "down"];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
parse(filePath) {
|
|
11
|
+
if (!fs.existsSync(filePath)) {
|
|
12
|
+
throw new Error("BBModel file not found: " + filePath);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
var raw = fs.readFileSync(filePath, "utf-8");
|
|
16
|
+
var data;
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
data = JSON.parse(raw);
|
|
20
|
+
} catch (e) {
|
|
21
|
+
throw new Error("Invalid BBModel JSON: " + filePath);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
var result = {
|
|
25
|
+
filePath: filePath,
|
|
26
|
+
fileName: path.basename(filePath, ".bbmodel"),
|
|
27
|
+
formatVersion: this.extractFormatVersion(data),
|
|
28
|
+
name: data.name || path.basename(filePath, ".bbmodel"),
|
|
29
|
+
resolution: this.extractResolution(data),
|
|
30
|
+
elements: this.extractElements(data),
|
|
31
|
+
textures: this.extractTextures(data),
|
|
32
|
+
outliner: this.extractOutliner(data),
|
|
33
|
+
animations: this.extractAnimations(data),
|
|
34
|
+
uvMappings: [],
|
|
35
|
+
valid: false
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
result.uvMappings = this.extractAllUVMappings(result.elements);
|
|
39
|
+
result.valid = this.validate(result);
|
|
40
|
+
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
extractFormatVersion(data) {
|
|
45
|
+
if (data.meta && data.meta.format_version) {
|
|
46
|
+
return data.meta.format_version;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return "unknown";
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
extractResolution(data) {
|
|
53
|
+
if (data.resolution) {
|
|
54
|
+
return {
|
|
55
|
+
width: data.resolution.width || 16,
|
|
56
|
+
height: data.resolution.height || 16
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return { width: 16, height: 16 };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
extractElements(data) {
|
|
64
|
+
if (!data.elements || !Array.isArray(data.elements)) {
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
var elements = [];
|
|
69
|
+
|
|
70
|
+
for (var i = 0; i < data.elements.length; i++) {
|
|
71
|
+
var el = data.elements[i];
|
|
72
|
+
|
|
73
|
+
var element = {
|
|
74
|
+
name: el.name || "element_" + i,
|
|
75
|
+
type: el.type || "cube",
|
|
76
|
+
from: el.from || [0, 0, 0],
|
|
77
|
+
to: el.to || [1, 1, 1],
|
|
78
|
+
rotation: el.rotation || [0, 0, 0],
|
|
79
|
+
origin: el.origin || [0, 0, 0],
|
|
80
|
+
inflate: el.inflate || 0,
|
|
81
|
+
visibility: el.visibility !== undefined ? el.visibility : true,
|
|
82
|
+
faces: this.extractFaces(el),
|
|
83
|
+
uuid: el.uuid || null
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
elements.push(element);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return elements;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
extractFaces(element) {
|
|
93
|
+
var faces = {};
|
|
94
|
+
|
|
95
|
+
if (!element.faces) {
|
|
96
|
+
for (var i = 0; i < this.faceNames.length; i++) {
|
|
97
|
+
faces[this.faceNames[i]] = {
|
|
98
|
+
uv: [0, 0, 16, 16],
|
|
99
|
+
texture: 0,
|
|
100
|
+
rotation: 0
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return faces;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
for (var j = 0; j < this.faceNames.length; j++) {
|
|
107
|
+
var faceName = this.faceNames[j];
|
|
108
|
+
|
|
109
|
+
if (element.faces[faceName]) {
|
|
110
|
+
var face = element.faces[faceName];
|
|
111
|
+
faces[faceName] = {
|
|
112
|
+
uv: face.uv || [0, 0, 16, 16],
|
|
113
|
+
texture: face.texture !== undefined ? face.texture : 0,
|
|
114
|
+
rotation: face.rotation || 0,
|
|
115
|
+
tint: face.tint || -1
|
|
116
|
+
};
|
|
117
|
+
} else {
|
|
118
|
+
faces[faceName] = {
|
|
119
|
+
uv: [0, 0, 16, 16],
|
|
120
|
+
texture: 0,
|
|
121
|
+
rotation: 0
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return faces;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
extractTextures(data) {
|
|
130
|
+
if (!data.textures || !Array.isArray(data.textures)) {
|
|
131
|
+
return [];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
var textures = [];
|
|
135
|
+
|
|
136
|
+
for (var i = 0; i < data.textures.length; i++) {
|
|
137
|
+
var tex = data.textures[i];
|
|
138
|
+
|
|
139
|
+
textures.push({
|
|
140
|
+
id: tex.id !== undefined ? tex.id : i,
|
|
141
|
+
name: tex.name || "texture_" + i,
|
|
142
|
+
folder: tex.folder || "",
|
|
143
|
+
namespace: tex.namespace || "",
|
|
144
|
+
source: tex.source || null,
|
|
145
|
+
width: tex.width || 0,
|
|
146
|
+
height: tex.height || 0,
|
|
147
|
+
uvWidth: tex.uv_width || 16,
|
|
148
|
+
uvHeight: tex.uv_height || 16
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return textures;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
extractOutliner(data) {
|
|
156
|
+
if (!data.outliner || !Array.isArray(data.outliner)) {
|
|
157
|
+
return [];
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return this.parseOutlinerNodes(data.outliner);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
parseOutlinerNodes(nodes) {
|
|
164
|
+
var result = [];
|
|
165
|
+
|
|
166
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
167
|
+
var node = nodes[i];
|
|
168
|
+
|
|
169
|
+
if (typeof node === "string") {
|
|
170
|
+
result.push({
|
|
171
|
+
type: "element_ref",
|
|
172
|
+
uuid: node
|
|
173
|
+
});
|
|
174
|
+
} else if (typeof node === "object" && node !== null) {
|
|
175
|
+
var bone = {
|
|
176
|
+
type: "group",
|
|
177
|
+
name: node.name || "group_" + i,
|
|
178
|
+
origin: node.origin || [0, 0, 0],
|
|
179
|
+
rotation: node.rotation || [0, 0, 0],
|
|
180
|
+
visibility: node.visibility !== undefined ? node.visibility : true,
|
|
181
|
+
uuid: node.uuid || null,
|
|
182
|
+
children: []
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
if (node.children && Array.isArray(node.children)) {
|
|
186
|
+
bone.children = this.parseOutlinerNodes(node.children);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
result.push(bone);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return result;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
extractAnimations(data) {
|
|
197
|
+
if (!data.animations || !Array.isArray(data.animations)) {
|
|
198
|
+
return [];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
var animations = [];
|
|
202
|
+
|
|
203
|
+
for (var i = 0; i < data.animations.length; i++) {
|
|
204
|
+
var anim = data.animations[i];
|
|
205
|
+
|
|
206
|
+
animations.push({
|
|
207
|
+
name: anim.name || "animation_" + i,
|
|
208
|
+
loop: anim.loop || "once",
|
|
209
|
+
length: anim.length || 0,
|
|
210
|
+
snapping: anim.snapping || 24
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return animations;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
extractAllUVMappings(elements) {
|
|
218
|
+
var mappings = [];
|
|
219
|
+
|
|
220
|
+
for (var i = 0; i < elements.length; i++) {
|
|
221
|
+
var element = elements[i];
|
|
222
|
+
var faceKeys = Object.keys(element.faces);
|
|
223
|
+
|
|
224
|
+
for (var j = 0; j < faceKeys.length; j++) {
|
|
225
|
+
var faceName = faceKeys[j];
|
|
226
|
+
var face = element.faces[faceName];
|
|
227
|
+
|
|
228
|
+
mappings.push({
|
|
229
|
+
element: element.name,
|
|
230
|
+
elementIndex: i,
|
|
231
|
+
face: faceName,
|
|
232
|
+
uv: face.uv.slice(),
|
|
233
|
+
textureIndex: face.texture,
|
|
234
|
+
rotation: face.rotation || 0,
|
|
235
|
+
supported: true
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return mappings;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
validate(result) {
|
|
244
|
+
if (!result.elements || result.elements.length === 0) {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
for (var i = 0; i < result.elements.length; i++) {
|
|
249
|
+
var el = result.elements[i];
|
|
250
|
+
|
|
251
|
+
if (!el.from || el.from.length !== 3) {
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (!el.to || el.to.length !== 3) {
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
for (var j = 0; j < result.uvMappings.length; j++) {
|
|
261
|
+
var mapping = result.uvMappings[j];
|
|
262
|
+
|
|
263
|
+
if (!mapping.uv || mapping.uv.length !== 4) {
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return true;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
getElementByName(parsedModel, name) {
|
|
272
|
+
for (var i = 0; i < parsedModel.elements.length; i++) {
|
|
273
|
+
if (parsedModel.elements[i].name === name) {
|
|
274
|
+
return parsedModel.elements[i];
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
getUVMappingsForElement(parsedModel, elementName) {
|
|
282
|
+
var result = [];
|
|
283
|
+
|
|
284
|
+
for (var i = 0; i < parsedModel.uvMappings.length; i++) {
|
|
285
|
+
if (parsedModel.uvMappings[i].element === elementName) {
|
|
286
|
+
result.push(parsedModel.uvMappings[i]);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return result;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
calculateBounds(parsedModel) {
|
|
294
|
+
if (parsedModel.elements.length === 0) {
|
|
295
|
+
return { min: [0, 0, 0], max: [0, 0, 0], size: [0, 0, 0] };
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
var min = [Infinity, Infinity, Infinity];
|
|
299
|
+
var max = [-Infinity, -Infinity, -Infinity];
|
|
300
|
+
|
|
301
|
+
for (var i = 0; i < parsedModel.elements.length; i++) {
|
|
302
|
+
var el = parsedModel.elements[i];
|
|
303
|
+
|
|
304
|
+
for (var a = 0; a < 3; a++) {
|
|
305
|
+
if (el.from[a] < min[a]) min[a] = el.from[a];
|
|
306
|
+
if (el.to[a] < min[a]) min[a] = el.to[a];
|
|
307
|
+
if (el.from[a] > max[a]) max[a] = el.from[a];
|
|
308
|
+
if (el.to[a] > max[a]) max[a] = el.to[a];
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
return {
|
|
313
|
+
min: min,
|
|
314
|
+
max: max,
|
|
315
|
+
size: [max[0] - min[0], max[1] - min[1], max[2] - min[2]]
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
module.exports = BBModelParser;
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
class UVMapper {
|
|
2
|
+
constructor(resolution) {
|
|
3
|
+
this.resolution = resolution || { width: 16, height: 16 };
|
|
4
|
+
this.mappings = [];
|
|
5
|
+
this.fixLog = [];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
setResolution(width, height) {
|
|
9
|
+
this.resolution = { width: width, height: height };
|
|
10
|
+
return this;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
getResolution() {
|
|
14
|
+
return this.resolution;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
mapFace(elementName, faceName, uv, textureIndex) {
|
|
18
|
+
var mapping = {
|
|
19
|
+
element: elementName,
|
|
20
|
+
face: faceName,
|
|
21
|
+
uv: uv ? uv.slice() : [0, 0, this.resolution.width, this.resolution.height],
|
|
22
|
+
textureIndex: textureIndex !== undefined ? textureIndex : 0,
|
|
23
|
+
normalized: false,
|
|
24
|
+
fixed: false,
|
|
25
|
+
supported: true
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
this.mappings.push(mapping);
|
|
29
|
+
return mapping;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
mapElement(element) {
|
|
33
|
+
var result = [];
|
|
34
|
+
var faceNames = ["north", "south", "east", "west", "up", "down"];
|
|
35
|
+
|
|
36
|
+
for (var i = 0; i < faceNames.length; i++) {
|
|
37
|
+
var faceName = faceNames[i];
|
|
38
|
+
|
|
39
|
+
if (element.faces && element.faces[faceName]) {
|
|
40
|
+
var face = element.faces[faceName];
|
|
41
|
+
var mapping = this.mapFace(
|
|
42
|
+
element.name || "unnamed",
|
|
43
|
+
faceName,
|
|
44
|
+
face.uv,
|
|
45
|
+
face.texture
|
|
46
|
+
);
|
|
47
|
+
result.push(mapping);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
mapAllElements(elements) {
|
|
55
|
+
var allMappings = [];
|
|
56
|
+
|
|
57
|
+
for (var i = 0; i < elements.length; i++) {
|
|
58
|
+
var elementMappings = this.mapElement(elements[i]);
|
|
59
|
+
allMappings = allMappings.concat(elementMappings);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return allMappings;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
normalize(mapping) {
|
|
66
|
+
if (!mapping || !mapping.uv) {
|
|
67
|
+
return mapping;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
var normalized = {
|
|
71
|
+
element: mapping.element,
|
|
72
|
+
face: mapping.face,
|
|
73
|
+
uv: [
|
|
74
|
+
mapping.uv[0] / this.resolution.width,
|
|
75
|
+
mapping.uv[1] / this.resolution.height,
|
|
76
|
+
mapping.uv[2] / this.resolution.width,
|
|
77
|
+
mapping.uv[3] / this.resolution.height
|
|
78
|
+
],
|
|
79
|
+
textureIndex: mapping.textureIndex,
|
|
80
|
+
normalized: true,
|
|
81
|
+
fixed: mapping.fixed,
|
|
82
|
+
supported: mapping.supported
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
return normalized;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
normalizeAll(mappings) {
|
|
89
|
+
var result = [];
|
|
90
|
+
|
|
91
|
+
for (var i = 0; i < mappings.length; i++) {
|
|
92
|
+
result.push(this.normalize(mappings[i]));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
denormalize(mapping) {
|
|
99
|
+
if (!mapping || !mapping.uv || !mapping.normalized) {
|
|
100
|
+
return mapping;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
var denormalized = {
|
|
104
|
+
element: mapping.element,
|
|
105
|
+
face: mapping.face,
|
|
106
|
+
uv: [
|
|
107
|
+
mapping.uv[0] * this.resolution.width,
|
|
108
|
+
mapping.uv[1] * this.resolution.height,
|
|
109
|
+
mapping.uv[2] * this.resolution.width,
|
|
110
|
+
mapping.uv[3] * this.resolution.height
|
|
111
|
+
],
|
|
112
|
+
textureIndex: mapping.textureIndex,
|
|
113
|
+
normalized: false,
|
|
114
|
+
fixed: mapping.fixed,
|
|
115
|
+
supported: mapping.supported
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
return denormalized;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
validate(mapping, textureWidth, textureHeight) {
|
|
122
|
+
if (!mapping || !mapping.uv) {
|
|
123
|
+
return { valid: false, issues: ["Missing UV data"] };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
var issues = [];
|
|
127
|
+
var uv = mapping.uv;
|
|
128
|
+
var tw = textureWidth || this.resolution.width;
|
|
129
|
+
var th = textureHeight || this.resolution.height;
|
|
130
|
+
|
|
131
|
+
if (uv.length !== 4) {
|
|
132
|
+
issues.push("UV array must have exactly 4 values");
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (uv[0] < 0) issues.push("UV x1 is negative: " + uv[0]);
|
|
136
|
+
if (uv[1] < 0) issues.push("UV y1 is negative: " + uv[1]);
|
|
137
|
+
if (uv[2] < 0) issues.push("UV x2 is negative: " + uv[2]);
|
|
138
|
+
if (uv[3] < 0) issues.push("UV y2 is negative: " + uv[3]);
|
|
139
|
+
|
|
140
|
+
if (uv[0] > tw) issues.push("UV x1 exceeds texture width: " + uv[0] + " > " + tw);
|
|
141
|
+
if (uv[1] > th) issues.push("UV y1 exceeds texture height: " + uv[1] + " > " + th);
|
|
142
|
+
if (uv[2] > tw) issues.push("UV x2 exceeds texture width: " + uv[2] + " > " + tw);
|
|
143
|
+
if (uv[3] > th) issues.push("UV y2 exceeds texture height: " + uv[3] + " > " + th);
|
|
144
|
+
|
|
145
|
+
if (uv[0] === uv[2]) issues.push("UV has zero width");
|
|
146
|
+
if (uv[1] === uv[3]) issues.push("UV has zero height");
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
valid: issues.length === 0,
|
|
150
|
+
issues: issues
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
validateAll(mappings, textureWidth, textureHeight) {
|
|
155
|
+
var results = [];
|
|
156
|
+
var allValid = true;
|
|
157
|
+
|
|
158
|
+
for (var i = 0; i < mappings.length; i++) {
|
|
159
|
+
var result = this.validate(mappings[i], textureWidth, textureHeight);
|
|
160
|
+
results.push({
|
|
161
|
+
mapping: mappings[i],
|
|
162
|
+
valid: result.valid,
|
|
163
|
+
issues: result.issues
|
|
164
|
+
});
|
|
165
|
+
if (!result.valid) {
|
|
166
|
+
allValid = false;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
allValid: allValid,
|
|
172
|
+
results: results,
|
|
173
|
+
totalMappings: mappings.length,
|
|
174
|
+
invalidCount: results.filter(function (r) { return !r.valid; }).length
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
fix(mapping, textureWidth, textureHeight) {
|
|
179
|
+
if (!mapping || !mapping.uv) {
|
|
180
|
+
return mapping;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
var tw = textureWidth || this.resolution.width;
|
|
184
|
+
var th = textureHeight || this.resolution.height;
|
|
185
|
+
var uv = mapping.uv.slice();
|
|
186
|
+
var wasFixed = false;
|
|
187
|
+
|
|
188
|
+
for (var i = 0; i < 4; i++) {
|
|
189
|
+
if (uv[i] < 0) {
|
|
190
|
+
uv[i] = 0;
|
|
191
|
+
wasFixed = true;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (uv[0] > tw) { uv[0] = tw; wasFixed = true; }
|
|
196
|
+
if (uv[2] > tw) { uv[2] = tw; wasFixed = true; }
|
|
197
|
+
if (uv[1] > th) { uv[1] = th; wasFixed = true; }
|
|
198
|
+
if (uv[3] > th) { uv[3] = th; wasFixed = true; }
|
|
199
|
+
|
|
200
|
+
if (uv[0] > uv[2]) {
|
|
201
|
+
var temp = uv[0];
|
|
202
|
+
uv[0] = uv[2];
|
|
203
|
+
uv[2] = temp;
|
|
204
|
+
wasFixed = true;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (uv[1] > uv[3]) {
|
|
208
|
+
var temp2 = uv[1];
|
|
209
|
+
uv[1] = uv[3];
|
|
210
|
+
uv[3] = temp2;
|
|
211
|
+
wasFixed = true;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (uv[0] === uv[2]) {
|
|
215
|
+
uv[2] = Math.min(uv[0] + 1, tw);
|
|
216
|
+
wasFixed = true;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (uv[1] === uv[3]) {
|
|
220
|
+
uv[3] = Math.min(uv[1] + 1, th);
|
|
221
|
+
wasFixed = true;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (wasFixed) {
|
|
225
|
+
this.fixLog.push({
|
|
226
|
+
element: mapping.element,
|
|
227
|
+
face: mapping.face,
|
|
228
|
+
originalUV: mapping.uv.slice(),
|
|
229
|
+
fixedUV: uv.slice(),
|
|
230
|
+
timestamp: Date.now()
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
var fixed = {};
|
|
235
|
+
for (var key in mapping) {
|
|
236
|
+
fixed[key] = mapping[key];
|
|
237
|
+
}
|
|
238
|
+
fixed.uv = uv;
|
|
239
|
+
fixed.fixed = wasFixed;
|
|
240
|
+
fixed.supported = true;
|
|
241
|
+
|
|
242
|
+
return fixed;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
fixAll(mappings, textureWidth, textureHeight) {
|
|
246
|
+
var result = [];
|
|
247
|
+
|
|
248
|
+
for (var i = 0; i < mappings.length; i++) {
|
|
249
|
+
result.push(this.fix(mappings[i], textureWidth, textureHeight));
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return result;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
autoMap(elementFrom, elementTo) {
|
|
256
|
+
var sizeX = Math.abs(elementTo[0] - elementFrom[0]);
|
|
257
|
+
var sizeY = Math.abs(elementTo[1] - elementFrom[1]);
|
|
258
|
+
var sizeZ = Math.abs(elementTo[2] - elementFrom[2]);
|
|
259
|
+
|
|
260
|
+
return {
|
|
261
|
+
north: [sizeZ, sizeY + sizeZ, sizeZ + sizeX, sizeY + sizeZ + sizeY],
|
|
262
|
+
south: [sizeZ + sizeX + sizeZ, sizeY + sizeZ, sizeZ + sizeX + sizeZ + sizeX, sizeY + sizeZ + sizeY],
|
|
263
|
+
east: [0, sizeY + sizeZ, sizeZ, sizeY + sizeZ + sizeY],
|
|
264
|
+
west: [sizeZ + sizeX, sizeY + sizeZ, sizeZ + sizeX + sizeZ, sizeY + sizeZ + sizeY],
|
|
265
|
+
up: [sizeZ, 0, sizeZ + sizeX, sizeZ],
|
|
266
|
+
down: [sizeZ + sizeX, 0, sizeZ + sizeX + sizeX, sizeZ]
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
calculateTextureSize(elements) {
|
|
271
|
+
var maxU = 0;
|
|
272
|
+
var maxV = 0;
|
|
273
|
+
|
|
274
|
+
for (var i = 0; i < elements.length; i++) {
|
|
275
|
+
var el = elements[i];
|
|
276
|
+
var faceKeys = Object.keys(el.faces || {});
|
|
277
|
+
|
|
278
|
+
for (var j = 0; j < faceKeys.length; j++) {
|
|
279
|
+
var face = el.faces[faceKeys[j]];
|
|
280
|
+
if (face.uv) {
|
|
281
|
+
if (face.uv[2] > maxU) maxU = face.uv[2];
|
|
282
|
+
if (face.uv[3] > maxV) maxV = face.uv[3];
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
var width = 1;
|
|
288
|
+
while (width < maxU) width *= 2;
|
|
289
|
+
|
|
290
|
+
var height = 1;
|
|
291
|
+
while (height < maxV) height *= 2;
|
|
292
|
+
|
|
293
|
+
return { width: width, height: height };
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
getFixLog() {
|
|
297
|
+
return this.fixLog;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
clearFixLog() {
|
|
301
|
+
this.fixLog = [];
|
|
302
|
+
return this;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
getMappings() {
|
|
306
|
+
return this.mappings;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
clearMappings() {
|
|
310
|
+
this.mappings = [];
|
|
311
|
+
return this;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
module.exports = UVMapper;
|