@ives_xxz/framework 1.4.1 → 1.4.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/FW.d.ts +11 -0
- package/entry/FWEntry.ts +14 -1
- package/manager/FWAssetManager.ts +3 -0
- package/package.json +1 -1
- package/render/FWAssembler.ts +11 -0
- package/render/FWAssembler.ts.meta +10 -0
- package/render/FWRenderAssembler.ts +620 -0
- package/render/FWRenderAssembler.ts.meta +10 -0
- package/render.meta +13 -0
package/FW.d.ts
CHANGED
|
@@ -1899,6 +1899,17 @@ declare namespace FW {
|
|
|
1899
1899
|
message?: string;
|
|
1900
1900
|
};
|
|
1901
1901
|
|
|
1902
|
+
// 颜色分段配置接口
|
|
1903
|
+
type AssemblerLabelColorSegment = {
|
|
1904
|
+
color: cc.Color;
|
|
1905
|
+
position: number;
|
|
1906
|
+
};
|
|
1907
|
+
|
|
1908
|
+
type AssemblerLabelColorConfig = {
|
|
1909
|
+
color: cc.Color;
|
|
1910
|
+
percentages: number;
|
|
1911
|
+
};
|
|
1912
|
+
|
|
1902
1913
|
declare function timeScale(scale: number);
|
|
1903
1914
|
declare let Entry: Entry;
|
|
1904
1915
|
}
|
package/entry/FWEntry.ts
CHANGED
|
@@ -166,7 +166,20 @@ export default class FWEntry implements FW.Entry {
|
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
getDepend(bundleName: string) {
|
|
169
|
-
|
|
169
|
+
const dependencySet = new Set<string>();
|
|
170
|
+
const findDependencies = (name: string) => {
|
|
171
|
+
const directDeps = this.map.get(name)?.depend || [];
|
|
172
|
+
for (const dep of directDeps) {
|
|
173
|
+
if (!dependencySet.has(dep)) {
|
|
174
|
+
dependencySet.add(dep);
|
|
175
|
+
findDependencies(dep);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
findDependencies(bundleName);
|
|
181
|
+
|
|
182
|
+
return Array.from(dependencySet);
|
|
170
183
|
}
|
|
171
184
|
|
|
172
185
|
hasSceneName(sceneName: string) {
|
|
@@ -77,6 +77,9 @@ export class FWAssetManager extends FWManager implements FW.AssetManager {
|
|
|
77
77
|
): Promise<T> {
|
|
78
78
|
return new Promise((resolve, reject) => {
|
|
79
79
|
cc.assetManager.loadRemote(url, { cacheEnabled: true, maxRetryCount: 0 }, (err, asset) => {
|
|
80
|
+
if (err || !asset) {
|
|
81
|
+
reject(err);
|
|
82
|
+
}
|
|
80
83
|
cb?.(asset as T);
|
|
81
84
|
resolve(asset as T);
|
|
82
85
|
});
|
package/package.json
CHANGED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Learn TypeScript:
|
|
2
|
+
// - https://docs.cocos.com/creator/manual/en/scripting/typescript.html
|
|
3
|
+
// Learn Attribute:
|
|
4
|
+
// - https://docs.cocos.com/creator/manual/en/scripting/reference/attributes.html
|
|
5
|
+
// Learn life-cycle callbacks:
|
|
6
|
+
// - https://docs.cocos.com/creator/manual/en/scripting/life-cycle-callbacks.html
|
|
7
|
+
|
|
8
|
+
const { ccclass, property } = cc._decorator;
|
|
9
|
+
|
|
10
|
+
@ccclass
|
|
11
|
+
export default class FWAssembler extends cc['Assembler'] {}
|
|
@@ -0,0 +1,620 @@
|
|
|
1
|
+
import { FWLodash } from '../utils/FWLodash';
|
|
2
|
+
|
|
3
|
+
const { ccclass, property, executeInEditMode, menu } = cc._decorator;
|
|
4
|
+
|
|
5
|
+
@ccclass('AssemblerLabelColorConfig')
|
|
6
|
+
class AssemblerLabelColorConfig implements FW.AssemblerLabelColorConfig {
|
|
7
|
+
@property({ displayName: '颜色' })
|
|
8
|
+
color: cc.Color = cc.Color.WHITE;
|
|
9
|
+
|
|
10
|
+
@property({ type: cc.Float, min: 0, max: 1, displayName: '占比', slide: true })
|
|
11
|
+
percentages: number = 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@ccclass
|
|
15
|
+
@executeInEditMode
|
|
16
|
+
@menu('CustomComponent/FWRenderAssembler')
|
|
17
|
+
export default class FWRenderAssembler extends cc.Component {
|
|
18
|
+
@property({ displayName: '文本自定义渐变色' })
|
|
19
|
+
enableLabelCustomColors: boolean = false;
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
_gradientDirection: number = 0;
|
|
23
|
+
@property({
|
|
24
|
+
type: cc.Enum({ 从左到右: 0, 从上到下: 1 }),
|
|
25
|
+
displayName: '渐变方向',
|
|
26
|
+
visible() {
|
|
27
|
+
return this.enableLabelCustomColors;
|
|
28
|
+
},
|
|
29
|
+
})
|
|
30
|
+
get gradientDirection() {
|
|
31
|
+
return this._gradientDirection;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
set gradientDirection(gradientDirection: number) {
|
|
35
|
+
this._gradientDirection = gradientDirection;
|
|
36
|
+
if (CC_EDITOR) {
|
|
37
|
+
this.adjustLabel();
|
|
38
|
+
this.onPropertyChanged();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
_config: AssemblerLabelColorConfig[] = [];
|
|
44
|
+
|
|
45
|
+
@property({
|
|
46
|
+
type: [AssemblerLabelColorConfig],
|
|
47
|
+
visible() {
|
|
48
|
+
return this.enableLabelCustomColors;
|
|
49
|
+
},
|
|
50
|
+
displayName: '颜色配置',
|
|
51
|
+
})
|
|
52
|
+
get config() {
|
|
53
|
+
return this._config;
|
|
54
|
+
}
|
|
55
|
+
set config(config: AssemblerLabelColorConfig[]) {
|
|
56
|
+
this._config = config;
|
|
57
|
+
if (CC_EDITOR) {
|
|
58
|
+
this.adjustLabel();
|
|
59
|
+
this.onPropertyChanged();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private _horizontalAlign: number;
|
|
64
|
+
private _verticalAlign: number;
|
|
65
|
+
private _originalRenderData: any = null;
|
|
66
|
+
private _originalUpdateRenderData: Function = null;
|
|
67
|
+
private _originalFillBuffers: Function = null;
|
|
68
|
+
private _isPatched: boolean = false;
|
|
69
|
+
private _colors: cc.Color[] = [];
|
|
70
|
+
private _percentages: number[] = [];
|
|
71
|
+
private _isOriginalDataSaved: boolean = false;
|
|
72
|
+
private _cachedProperties: any;
|
|
73
|
+
|
|
74
|
+
protected start(): void {
|
|
75
|
+
this.adjustLabel();
|
|
76
|
+
this.config.forEach((v) => {
|
|
77
|
+
this._colors.push(v.color);
|
|
78
|
+
this._percentages.push(v.percentages);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
if (!CC_EDITOR) {
|
|
82
|
+
cc.director.on(cc.Director.EVENT_AFTER_DRAW, this.onUpdateAssembler, this);
|
|
83
|
+
} else {
|
|
84
|
+
this.node.on(cc.Node.EventType.SIZE_CHANGED, this.onRefreshEditor, this);
|
|
85
|
+
this.node.on(cc.Node.EventType.COLOR_CHANGED, this.onRefreshEditor, this);
|
|
86
|
+
this.node.on(cc.Node.EventType.ANCHOR_CHANGED, this.onRefreshEditor, this);
|
|
87
|
+
setTimeout(() => {
|
|
88
|
+
this.cacheLabelProperties();
|
|
89
|
+
this.onPropertyChanged();
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
onRefreshEditor() {
|
|
95
|
+
if (CC_EDITOR && this.enableLabelCustomColors) {
|
|
96
|
+
this._originalRenderData = null;
|
|
97
|
+
this._isOriginalDataSaved = false;
|
|
98
|
+
this.node.label['_assembler'] = null;
|
|
99
|
+
this.node.active = false;
|
|
100
|
+
this.node.active = true;
|
|
101
|
+
setTimeout(() => {
|
|
102
|
+
this.onPropertyChanged();
|
|
103
|
+
}, 30);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private refreshGradient(): void {
|
|
108
|
+
this._colors = [];
|
|
109
|
+
this._percentages = [];
|
|
110
|
+
this.config.forEach((v) => {
|
|
111
|
+
this._colors.push(v.color);
|
|
112
|
+
this._percentages.push(v.percentages);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
this._isPatched = false;
|
|
116
|
+
this.onUpdateAssembler();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private cacheLabelProperties(): void {
|
|
120
|
+
const label = this.node.label;
|
|
121
|
+
if (!label) {
|
|
122
|
+
this._cachedProperties = null;
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
this._cachedProperties = {
|
|
127
|
+
horizontalAlign: label.horizontalAlign,
|
|
128
|
+
verticalAlign: label.verticalAlign,
|
|
129
|
+
overflow: label.overflow,
|
|
130
|
+
enableWrap: label.enableWrapText,
|
|
131
|
+
fontFamily: label.fontFamily,
|
|
132
|
+
font: label.font ? label.font['_uuid'] : null,
|
|
133
|
+
underlineHeight: label.underlineHeight,
|
|
134
|
+
cacheMode: label.cacheMode,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
private checkLabelPropertiesChanged(): boolean {
|
|
139
|
+
const label = this.node.label;
|
|
140
|
+
if (!label || !this._cachedProperties) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const current = {
|
|
145
|
+
horizontalAlign: label.horizontalAlign,
|
|
146
|
+
verticalAlign: label.verticalAlign,
|
|
147
|
+
overflow: label.overflow,
|
|
148
|
+
enableWrap: label.enableWrapText,
|
|
149
|
+
underlineHeight: label.underlineHeight,
|
|
150
|
+
fontFamily: label.fontFamily,
|
|
151
|
+
cacheMode: label.cacheMode,
|
|
152
|
+
font: label.font ? label.font['_uuid'] : null,
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const keys = Object.keys(current);
|
|
156
|
+
for (let key of keys) {
|
|
157
|
+
if (current[key] !== this._cachedProperties[key]) {
|
|
158
|
+
this._cachedProperties = current;
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
protected onPropertyChanged(): void {
|
|
167
|
+
if (CC_EDITOR && this.enableLabelCustomColors) {
|
|
168
|
+
this.restoreOriginalAssembler();
|
|
169
|
+
this.refreshGradient();
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
protected onDisable(): void {
|
|
174
|
+
this.restoreOriginalAssembler();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
private adjustLabel(): void {
|
|
178
|
+
if (CC_EDITOR && !this.node.label) {
|
|
179
|
+
this.node.label = this.node.getComponent(cc.Label);
|
|
180
|
+
}
|
|
181
|
+
if (this.node.label) {
|
|
182
|
+
if (this.gradientDirection === 1) {
|
|
183
|
+
this.node.label.lineHeight = this.node.label.fontSize * 0.8;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (!this._horizontalAlign) {
|
|
187
|
+
this._horizontalAlign = this.node.label.horizontalAlign;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (!this._verticalAlign) {
|
|
191
|
+
this._verticalAlign = this.node.label.verticalAlign;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
protected update(dt: number): void {
|
|
197
|
+
if (!CC_EDITOR) return;
|
|
198
|
+
if (this.checkLabelPropertiesChanged()) {
|
|
199
|
+
setTimeout(() => {
|
|
200
|
+
this.adjustLabel();
|
|
201
|
+
this.onRefreshEditor();
|
|
202
|
+
}, 100);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
private onUpdateAssembler(): void {
|
|
207
|
+
if (this.enableLabelCustomColors && this.node.label) {
|
|
208
|
+
this.patchAssembler();
|
|
209
|
+
} else {
|
|
210
|
+
this.restoreOriginalAssembler();
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
private patchAssembler(): void {
|
|
215
|
+
const label = this.node.label;
|
|
216
|
+
if (!label || !label['_assembler'] || this._isPatched) return;
|
|
217
|
+
|
|
218
|
+
const assembler = label['_assembler'];
|
|
219
|
+
|
|
220
|
+
if (!this._isOriginalDataSaved) {
|
|
221
|
+
this._originalRenderData = FWLodash.cloneDeep(assembler);
|
|
222
|
+
this._isOriginalDataSaved = true;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const colorSegments = this.createColorSegments();
|
|
226
|
+
if (!colorSegments) return;
|
|
227
|
+
|
|
228
|
+
if (!this._originalUpdateRenderData) {
|
|
229
|
+
this._originalUpdateRenderData = assembler.updateRenderData;
|
|
230
|
+
}
|
|
231
|
+
if (!this._originalFillBuffers) {
|
|
232
|
+
this._originalFillBuffers = assembler.fillBuffers;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
assembler.updateRenderData = () => {
|
|
236
|
+
if (this._originalUpdateRenderData) {
|
|
237
|
+
this._originalUpdateRenderData.call(assembler, label);
|
|
238
|
+
}
|
|
239
|
+
this.applyMultiColorGradient(assembler, colorSegments);
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
assembler.fillBuffers = (renderer: any, node: any) => {
|
|
243
|
+
this.fillGradientBuffers(renderer, node, assembler);
|
|
244
|
+
};
|
|
245
|
+
if (colorSegments.length > 2) {
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
this._isPatched = true;
|
|
249
|
+
assembler.updateRenderData();
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
private restoreOriginalAssembler(): void {
|
|
253
|
+
if (!this.node.label || !this._isOriginalDataSaved) return;
|
|
254
|
+
|
|
255
|
+
const label = this.node.label;
|
|
256
|
+
if (label['_assembler']) {
|
|
257
|
+
const assembler = label['_assembler'];
|
|
258
|
+
|
|
259
|
+
if (this._originalUpdateRenderData) {
|
|
260
|
+
assembler.updateRenderData = this._originalUpdateRenderData;
|
|
261
|
+
}
|
|
262
|
+
if (this._originalFillBuffers) {
|
|
263
|
+
assembler.fillBuffers = this._originalFillBuffers;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (this._originalRenderData) {
|
|
267
|
+
label['_assembler'] = FWLodash.cloneDeep(this._originalRenderData);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
this._isPatched = false;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
private applyMultiColorGradient(
|
|
275
|
+
assembler: any,
|
|
276
|
+
colorSegments: FW.AssemblerLabelColorSegment[],
|
|
277
|
+
): void {
|
|
278
|
+
const renderData = assembler._renderData;
|
|
279
|
+
const originalUintVData = renderData.uintVDatas[0];
|
|
280
|
+
const charsCount = originalUintVData.length / 20;
|
|
281
|
+
const segmentsCount = colorSegments.length - 1;
|
|
282
|
+
const useVertical = this.gradientDirection === 1;
|
|
283
|
+
|
|
284
|
+
const verticesPerChar = segmentsCount * 4;
|
|
285
|
+
const newVertexCount = charsCount * verticesPerChar;
|
|
286
|
+
const newUintVData = new Uint32Array(newVertexCount * 5);
|
|
287
|
+
|
|
288
|
+
let writeIndex = 0;
|
|
289
|
+
|
|
290
|
+
for (let c = 0; c < charsCount; c++) {
|
|
291
|
+
const base = c * 20;
|
|
292
|
+
const vertices = this.getCharacterVertices(originalUintVData, base);
|
|
293
|
+
const bounds = this.calculateBounds(vertices);
|
|
294
|
+
|
|
295
|
+
for (let s = 0; s < segmentsCount; s++) {
|
|
296
|
+
const segment = colorSegments[s];
|
|
297
|
+
const nextSegment = colorSegments[s + 1];
|
|
298
|
+
|
|
299
|
+
if (useVertical) {
|
|
300
|
+
this.createVerticalSegment(
|
|
301
|
+
newUintVData,
|
|
302
|
+
writeIndex,
|
|
303
|
+
vertices,
|
|
304
|
+
bounds,
|
|
305
|
+
segment,
|
|
306
|
+
nextSegment,
|
|
307
|
+
);
|
|
308
|
+
} else {
|
|
309
|
+
this.createHorizontalSegment(
|
|
310
|
+
newUintVData,
|
|
311
|
+
writeIndex,
|
|
312
|
+
vertices,
|
|
313
|
+
bounds,
|
|
314
|
+
segment,
|
|
315
|
+
nextSegment,
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
writeIndex += 4;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
this.updateRenderData(renderData, newUintVData, charsCount, segmentsCount);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
private getCharacterVertices(uintVData: Uint32Array, baseIndex: number): any[] {
|
|
326
|
+
const vertices = [];
|
|
327
|
+
for (let i = 0; i < 4; i++) {
|
|
328
|
+
const idx = baseIndex + i * 5;
|
|
329
|
+
vertices.push({
|
|
330
|
+
x: this.uintToFloat(uintVData[idx]),
|
|
331
|
+
y: this.uintToFloat(uintVData[idx + 1]),
|
|
332
|
+
u: this.uintToFloat(uintVData[idx + 2]),
|
|
333
|
+
v: this.uintToFloat(uintVData[idx + 3]),
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
return vertices;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
private calculateBounds(vertices: any[]): any {
|
|
340
|
+
const xs = vertices.map((v) => v.x);
|
|
341
|
+
const ys = vertices.map((v) => v.y);
|
|
342
|
+
return {
|
|
343
|
+
minX: Math.min(...xs),
|
|
344
|
+
maxX: Math.max(...xs),
|
|
345
|
+
minY: Math.min(...ys),
|
|
346
|
+
maxY: Math.max(...ys),
|
|
347
|
+
width: Math.max(...xs) - Math.min(...xs),
|
|
348
|
+
height: Math.max(...ys) - Math.min(...ys),
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
private createHorizontalSegment(
|
|
353
|
+
newUintVData: Uint32Array,
|
|
354
|
+
writeIndex: number,
|
|
355
|
+
vertices: any[],
|
|
356
|
+
bounds: any,
|
|
357
|
+
segment: any,
|
|
358
|
+
nextSegment: any,
|
|
359
|
+
): void {
|
|
360
|
+
const startX = bounds.minX + bounds.width * segment.position;
|
|
361
|
+
const endX = bounds.minX + bounds.width * nextSegment.position;
|
|
362
|
+
const startU = vertices[0].u + (vertices[1].u - vertices[0].u) * segment.position;
|
|
363
|
+
const endU = vertices[0].u + (vertices[1].u - vertices[0].u) * nextSegment.position;
|
|
364
|
+
|
|
365
|
+
this.setVertexData(
|
|
366
|
+
newUintVData,
|
|
367
|
+
writeIndex,
|
|
368
|
+
startX,
|
|
369
|
+
bounds.minY,
|
|
370
|
+
startU,
|
|
371
|
+
vertices[0].v,
|
|
372
|
+
segment.color._val,
|
|
373
|
+
);
|
|
374
|
+
this.setVertexData(
|
|
375
|
+
newUintVData,
|
|
376
|
+
writeIndex + 1,
|
|
377
|
+
endX,
|
|
378
|
+
bounds.minY,
|
|
379
|
+
endU,
|
|
380
|
+
vertices[1].v,
|
|
381
|
+
nextSegment.color._val,
|
|
382
|
+
);
|
|
383
|
+
this.setVertexData(
|
|
384
|
+
newUintVData,
|
|
385
|
+
writeIndex + 2,
|
|
386
|
+
startX,
|
|
387
|
+
bounds.maxY,
|
|
388
|
+
startU,
|
|
389
|
+
vertices[2].v,
|
|
390
|
+
segment.color._val,
|
|
391
|
+
);
|
|
392
|
+
this.setVertexData(
|
|
393
|
+
newUintVData,
|
|
394
|
+
writeIndex + 3,
|
|
395
|
+
endX,
|
|
396
|
+
bounds.maxY,
|
|
397
|
+
endU,
|
|
398
|
+
vertices[3].v,
|
|
399
|
+
nextSegment.color._val,
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
private createVerticalSegment(
|
|
404
|
+
newUintVData: Uint32Array,
|
|
405
|
+
writeIndex: number,
|
|
406
|
+
vertices: any[],
|
|
407
|
+
bounds: any,
|
|
408
|
+
segment: any,
|
|
409
|
+
nextSegment: any,
|
|
410
|
+
): void {
|
|
411
|
+
const startY = bounds.minY + bounds.height * (1 - segment.position);
|
|
412
|
+
const endY = bounds.minY + bounds.height * (1 - nextSegment.position);
|
|
413
|
+
|
|
414
|
+
const startVL = vertices[0].v + (vertices[2].v - vertices[0].v) * (1 - segment.position);
|
|
415
|
+
const endVL = vertices[0].v + (vertices[2].v - vertices[0].v) * (1 - nextSegment.position);
|
|
416
|
+
const startVR = vertices[1].v + (vertices[3].v - vertices[1].v) * (1 - segment.position);
|
|
417
|
+
const endVR = vertices[1].v + (vertices[3].v - vertices[1].v) * (1 - nextSegment.position);
|
|
418
|
+
|
|
419
|
+
this.setVertexData(
|
|
420
|
+
newUintVData,
|
|
421
|
+
writeIndex,
|
|
422
|
+
bounds.minX,
|
|
423
|
+
startY,
|
|
424
|
+
vertices[0].u,
|
|
425
|
+
startVL,
|
|
426
|
+
segment.color._val,
|
|
427
|
+
);
|
|
428
|
+
this.setVertexData(
|
|
429
|
+
newUintVData,
|
|
430
|
+
writeIndex + 1,
|
|
431
|
+
bounds.maxX,
|
|
432
|
+
startY,
|
|
433
|
+
vertices[1].u,
|
|
434
|
+
startVR,
|
|
435
|
+
segment.color._val,
|
|
436
|
+
);
|
|
437
|
+
this.setVertexData(
|
|
438
|
+
newUintVData,
|
|
439
|
+
writeIndex + 2,
|
|
440
|
+
bounds.minX,
|
|
441
|
+
endY,
|
|
442
|
+
vertices[2].u,
|
|
443
|
+
endVL,
|
|
444
|
+
nextSegment.color._val,
|
|
445
|
+
);
|
|
446
|
+
this.setVertexData(
|
|
447
|
+
newUintVData,
|
|
448
|
+
writeIndex + 3,
|
|
449
|
+
bounds.maxX,
|
|
450
|
+
endY,
|
|
451
|
+
vertices[3].u,
|
|
452
|
+
endVR,
|
|
453
|
+
nextSegment.color._val,
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
private setVertexData(
|
|
458
|
+
data: Uint32Array,
|
|
459
|
+
index: number,
|
|
460
|
+
x: number,
|
|
461
|
+
y: number,
|
|
462
|
+
u: number,
|
|
463
|
+
v: number,
|
|
464
|
+
color: number,
|
|
465
|
+
): void {
|
|
466
|
+
const base = index * 5;
|
|
467
|
+
data[base] = this.floatToUint(x);
|
|
468
|
+
data[base + 1] = this.floatToUint(y);
|
|
469
|
+
data[base + 2] = this.floatToUint(u);
|
|
470
|
+
data[base + 3] = this.floatToUint(v);
|
|
471
|
+
data[base + 4] = color;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
private updateRenderData(
|
|
475
|
+
renderData: any,
|
|
476
|
+
newUintVData: Uint32Array,
|
|
477
|
+
charsCount: number,
|
|
478
|
+
segmentsCount: number,
|
|
479
|
+
): void {
|
|
480
|
+
renderData.uintVDatas[0] = newUintVData;
|
|
481
|
+
renderData.iDatas[0] = this.createQuadMeshIndices(charsCount, segmentsCount);
|
|
482
|
+
renderData.vertexCount = newUintVData.length / 5;
|
|
483
|
+
|
|
484
|
+
const newVData = new Float32Array(renderData.vertexCount * 5);
|
|
485
|
+
for (let i = 0; i < newVData.length; i++) {
|
|
486
|
+
newVData[i] = this.uintToFloat(newUintVData[i]);
|
|
487
|
+
}
|
|
488
|
+
renderData.vDatas[0] = newVData;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
private createQuadMeshIndices(charsCount: number, segmentsCount: number): Uint16Array {
|
|
492
|
+
const indicesPerChar = segmentsCount * 6;
|
|
493
|
+
const totalIndices = charsCount * indicesPerChar;
|
|
494
|
+
const indices = new Uint16Array(totalIndices);
|
|
495
|
+
let idx = 0;
|
|
496
|
+
|
|
497
|
+
for (let charIndex = 0; charIndex < charsCount; charIndex++) {
|
|
498
|
+
const vertexOffset = charIndex * segmentsCount * 4;
|
|
499
|
+
|
|
500
|
+
for (let segIndex = 0; segIndex < segmentsCount; segIndex++) {
|
|
501
|
+
const base = vertexOffset + segIndex * 4;
|
|
502
|
+
indices[idx++] = base;
|
|
503
|
+
indices[idx++] = base + 1;
|
|
504
|
+
indices[idx++] = base + 2;
|
|
505
|
+
indices[idx++] = base + 1;
|
|
506
|
+
indices[idx++] = base + 3;
|
|
507
|
+
indices[idx++] = base + 2;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
return indices;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
private getLabelBounds(uintVData: Uint32Array): any {
|
|
515
|
+
let minX = Number.MAX_VALUE,
|
|
516
|
+
maxX = -Number.MAX_VALUE;
|
|
517
|
+
let minY = Number.MAX_VALUE,
|
|
518
|
+
maxY = -Number.MAX_VALUE;
|
|
519
|
+
|
|
520
|
+
for (let i = 0; i < uintVData.length; i += 5) {
|
|
521
|
+
const x = this.uintToFloat(uintVData[i]);
|
|
522
|
+
const y = this.uintToFloat(uintVData[i + 1]);
|
|
523
|
+
minX = Math.min(minX, x);
|
|
524
|
+
maxX = Math.max(maxX, x);
|
|
525
|
+
minY = Math.min(minY, y);
|
|
526
|
+
maxY = Math.max(maxY, y);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
return {
|
|
530
|
+
minX,
|
|
531
|
+
maxX,
|
|
532
|
+
minY,
|
|
533
|
+
maxY,
|
|
534
|
+
width: Math.max(maxX - minX, 1),
|
|
535
|
+
height: Math.max(maxY - minY, 1),
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
private fillGradientBuffers(renderer: any, node: any, assembler: any): void {
|
|
540
|
+
const renderData = assembler._renderData;
|
|
541
|
+
if (!renderData?.vDatas?.[0] || !renderData?.iDatas?.[0]) return;
|
|
542
|
+
|
|
543
|
+
const buffer = node._buffer;
|
|
544
|
+
const offsetInfo = buffer.request(renderData.vertexCount, renderData.iDatas[0].length);
|
|
545
|
+
|
|
546
|
+
const vertexOffset = offsetInfo.byteOffset >> 2;
|
|
547
|
+
buffer._vData.set(renderData.vDatas[0], vertexOffset);
|
|
548
|
+
|
|
549
|
+
const ibuf = buffer._iData;
|
|
550
|
+
const vertexId = offsetInfo.vertexOffset;
|
|
551
|
+
|
|
552
|
+
renderData.iDatas[0].forEach((index, i) => {
|
|
553
|
+
ibuf[offsetInfo.indiceOffset + i] = vertexId + index;
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
private createColorSegments(): FW.AssemblerLabelColorSegment[] | null {
|
|
558
|
+
if (!this._colors || this._colors.length < 2) return null;
|
|
559
|
+
|
|
560
|
+
const percentages = this.calculatePercentages();
|
|
561
|
+
const segments: FW.AssemblerLabelColorSegment[] = [];
|
|
562
|
+
|
|
563
|
+
for (let i = 0; i < this._colors.length; i++) {
|
|
564
|
+
segments.push({
|
|
565
|
+
color: this.cloneColor(this._colors[i]),
|
|
566
|
+
position: percentages[i],
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
return segments;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
private calculatePercentages(): number[] {
|
|
574
|
+
if (this._percentages?.length === this._colors.length) {
|
|
575
|
+
const percentages = [...this._percentages];
|
|
576
|
+
percentages[0] = 0;
|
|
577
|
+
percentages[percentages.length - 1] = 1;
|
|
578
|
+
|
|
579
|
+
for (let i = 1; i < percentages.length - 1; i++) {
|
|
580
|
+
if (percentages[i] <= percentages[i - 1]) {
|
|
581
|
+
percentages[i] = percentages[i - 1] + 0.001;
|
|
582
|
+
}
|
|
583
|
+
if (percentages[i] >= percentages[i + 1]) {
|
|
584
|
+
percentages[i] = (percentages[i - 1] + percentages[i + 1]) / 2;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
return percentages;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
return Array.from({ length: this._colors.length }, (_, i) => i / (this._colors.length - 1));
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
private cloneColor(color: cc.Color): cc.Color {
|
|
594
|
+
return color.clone ? color.clone() : cc.color(color.r, color.g, color.b, color.a);
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
private interpolateColor(color1: cc.Color, color2: cc.Color, progress: number): cc.Color {
|
|
598
|
+
const r = Math.round(color1.r + (color2.r - color1.r) * progress);
|
|
599
|
+
const g = Math.round(color1.g + (color2.g - color1.g) * progress);
|
|
600
|
+
const b = Math.round(color1.b + (color2.b - color1.b) * progress);
|
|
601
|
+
const a = Math.round(color1.a + (color2.a - color1.a) * progress);
|
|
602
|
+
return cc.color(r, g, b, a);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
private uintToFloat(uintValue: number): number {
|
|
606
|
+
const buffer = new ArrayBuffer(4);
|
|
607
|
+
const uintView = new Uint32Array(buffer);
|
|
608
|
+
const floatView = new Float32Array(buffer);
|
|
609
|
+
uintView[0] = uintValue;
|
|
610
|
+
return floatView[0];
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
private floatToUint(floatValue: number): number {
|
|
614
|
+
const buffer = new ArrayBuffer(4);
|
|
615
|
+
const floatView = new Float32Array(buffer);
|
|
616
|
+
const uintView = new Uint32Array(buffer);
|
|
617
|
+
floatView[0] = floatValue;
|
|
618
|
+
return uintView[0];
|
|
619
|
+
}
|
|
620
|
+
}
|
package/render.meta
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"ver": "1.1.3",
|
|
3
|
+
"uuid": "d49ee3cc-a25e-4c14-8a04-5f22d03b8164",
|
|
4
|
+
"importer": "folder",
|
|
5
|
+
"isBundle": false,
|
|
6
|
+
"bundleName": "",
|
|
7
|
+
"priority": 1,
|
|
8
|
+
"compressionType": {},
|
|
9
|
+
"optimizeHotUpdate": {},
|
|
10
|
+
"inlineSpriteFrames": {},
|
|
11
|
+
"isRemoteBundle": {},
|
|
12
|
+
"subMetas": {}
|
|
13
|
+
}
|