Skip to content

Commit a2fee5f

Browse files
authored
Fix primitive chunk free area error (#2340)
* fix(text): fix primitive chunk free area error
1 parent 1369f11 commit a2fee5f

File tree

4 files changed

+124
-30
lines changed

4 files changed

+124
-30
lines changed

e2e/case/text-typed.ts

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/**
2+
* @title TypedText
3+
* @category Text
4+
*/
5+
6+
import {
7+
Camera,
8+
Logger,
9+
Script,
10+
TextHorizontalAlignment,
11+
TextRenderer,
12+
TextVerticalAlignment,
13+
Vector3,
14+
WebGLEngine
15+
} from "@galacean/engine";
16+
import { initScreenshot, updateForE2E } from "./.mockForE2E";
17+
18+
Logger.enable();
19+
WebGLEngine.create({ canvas: "canvas" }).then((engine) => {
20+
engine.canvas.resizeByClientSize();
21+
const scene = engine.sceneManager.activeScene;
22+
const rootEntity = scene.createRootEntity();
23+
24+
// camera
25+
const cameraEntity = rootEntity.createChild("camera_node");
26+
cameraEntity.transform.position = new Vector3(0, 0, 10);
27+
const camera = cameraEntity.addComponent(Camera);
28+
29+
const entity = rootEntity.createChild("text");
30+
const textRenderer = entity.addComponent(TextRenderer);
31+
textRenderer.fontSize = 64;
32+
textRenderer.horizontalAlignment = TextHorizontalAlignment.Left;
33+
textRenderer.verticalAlignment = TextVerticalAlignment.Top;
34+
textRenderer.enableWrapping = true;
35+
textRenderer.width = 4;
36+
37+
class TypedText extends Script {
38+
private _renderer: TextRenderer;
39+
private _text: string;
40+
private _index = 0;
41+
private _charCount = 0;
42+
private _showText = "";
43+
private _curTime = 0;
44+
private _totalTime = 0.1;
45+
private _isPlaying = false;
46+
47+
onUpdate(deltaTime: number): void {
48+
if (this._isPlaying) {
49+
if (this._curTime >= this._totalTime) {
50+
if (this._index >= this._charCount) {
51+
this._isPlaying = false;
52+
initScreenshot(engine, camera);
53+
} else {
54+
this._showText += this._text[this._index++];
55+
this._renderer.text = this._showText;
56+
}
57+
this._curTime = 0;
58+
} else {
59+
this._curTime += deltaTime;
60+
}
61+
}
62+
}
63+
64+
play(textRenderer: TextRenderer, text: string = ""): void {
65+
this._renderer = textRenderer;
66+
this._text = text;
67+
this._index = 0;
68+
this._charCount = text.length;
69+
this._showText = "";
70+
this._curTime = this._totalTime;
71+
this._isPlaying = true;
72+
}
73+
}
74+
75+
const typedText = entity.addComponent(TypedText);
76+
typedText.play(textRenderer, "我这一生,走过许多地方的桥儿");
77+
78+
updateForE2E(engine, 100, 100);
79+
});

e2e/config.ts

+7
Original file line numberDiff line numberDiff line change
@@ -212,5 +212,12 @@ export const E2E_CONFIG = {
212212
caseFileName: "postProcess-LDR-bloom-neutral",
213213
threshold: 0.2
214214
}
215+
},
216+
Text: {
217+
TypedText: {
218+
category: "Text",
219+
caseFileName: "text-typed",
220+
threshold: 0.4
221+
}
215222
}
216223
};
Loading

packages/core/src/RenderPipeline/PrimitiveChunk.ts

+35-30
Original file line numberDiff line numberDiff line change
@@ -138,39 +138,44 @@ export class PrimitiveChunk {
138138
}
139139

140140
private _freeArea(area: VertexArea): void {
141-
const areas = this.vertexFreeAreas;
142-
const areaLen = areas.length;
143-
if (areaLen === 0) {
144-
areas.push(area);
145-
return;
146-
}
147-
141+
const { start, size } = area;
142+
const freeAreas = this.vertexFreeAreas;
143+
const end = start + size;
148144
const pool = PrimitiveChunk.areaPool;
149-
let preArea = area;
150-
let notMerge = true;
151-
for (let i = 0; i < areaLen; ++i) {
152-
const curArea = areas[i];
153-
const { start: preStart, size } = preArea;
154-
const { start: curStart } = curArea;
155-
const preEnd = preStart + size;
156-
const curEnd = curStart + curArea.size;
157-
if (preEnd < curStart) {
158-
notMerge && areas.splice(i, 0, preArea);
145+
for (let i = 0, areaLen = freeAreas.length; i < areaLen; ++i) {
146+
const curFreeArea = freeAreas[i];
147+
const curStart = curFreeArea.start;
148+
const curEnd = curStart + curFreeArea.size;
149+
150+
if (end < curStart) {
151+
// The area to be freed is to the left of the current free area and is not connected
152+
freeAreas.splice(i, 0, area);
153+
return;
154+
} else if (end === curStart) {
155+
// The area to be freed is to the left of the current free area and is connected
156+
curFreeArea.start = start;
157+
curFreeArea.size += size;
158+
pool.return(area);
159+
return;
160+
} else if (start === curEnd) {
161+
// The area to be freed is to the right of the current free area and is connected
162+
curFreeArea.size += size;
163+
pool.return(area);
164+
const nextIndex = i + 1;
165+
if (nextIndex < areaLen) {
166+
const nextFreeArea = freeAreas[nextIndex];
167+
if (end === nextFreeArea.start) {
168+
// The cur free area after merge is to the left of the next free area and is connected
169+
curFreeArea.size += nextFreeArea.size;
170+
freeAreas.splice(nextIndex, 1);
171+
pool.return(nextFreeArea);
172+
}
173+
}
159174
return;
160-
} else if (preEnd === curStart) {
161-
curArea.start = preStart;
162-
curArea.size += size;
163-
pool.return(preArea);
164-
preArea = curArea;
165-
notMerge = false;
166-
} else if (preStart === curEnd) {
167-
curArea.size += size;
168-
pool.return(preArea);
169-
preArea = curArea;
170-
notMerge = false;
171-
} else if (preStart > curEnd) {
172-
i + 1 === areaLen && areas.push(preArea);
173175
}
174176
}
177+
178+
// The area to be freed is to the right of the last free area and is not connected or free areas is empty
179+
freeAreas.push(area);
175180
}
176181
}

0 commit comments

Comments
 (0)