@next2d/texture-packer 2.0.0 → 3.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/README.md
CHANGED
|
@@ -1,11 +1,244 @@
|
|
|
1
|
-
@next2d/texture-packer
|
|
2
|
-
=============
|
|
1
|
+
# @next2d/texture-packer
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
**重要**: `@next2d/texture-packer` は他の packages の import を禁止しています。このパッケージは基盤モジュールであり、循環依存を避けるために独立を維持する必要があります。
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
**Important**: `@next2d/texture-packer` prohibits importing other packages. This package is a foundational module that must remain independent to avoid circular dependencies.
|
|
6
|
+
|
|
7
|
+
## 概要 / Overview
|
|
8
|
+
|
|
9
|
+
`@next2d/texture-packer` は、GPU テクスチャ割り当てに最適化された二分木ベースのパッキングアルゴリズムを実装した、高性能なテクスチャアトラス管理ライブラリです。このパッケージは、固定サイズのアトラス内でテクスチャの配置と削除を効率的に管理し、テクスチャメモリの断片化を最小限に抑え、スペース利用率を最大化します。
|
|
10
|
+
|
|
11
|
+
`@next2d/texture-packer` is a high-performance texture atlas management library that implements a binary tree-based packing algorithm optimized for GPU texture allocation. This package efficiently manages the placement and removal of textures within a fixed-size atlas, minimizing texture memory fragmentation and maximizing space utilization.
|
|
12
|
+
|
|
13
|
+
## 主な機能 / Key Features
|
|
14
|
+
|
|
15
|
+
- **二分木アルゴリズム**: 最適なテクスチャ配置のための再帰的な二分空間分割アプローチを使用
|
|
16
|
+
- Uses a recursive binary space partitioning approach for optimal texture placement
|
|
17
|
+
- **動的な割り当て/解放**: 実行時のテクスチャの挿入と破棄をサポート
|
|
18
|
+
- Supports runtime insertion and disposal of textures
|
|
19
|
+
- **メモリプール最適化**: オブジェクトプーリングを採用し、ガベージコレクションのオーバーヘッドを削減
|
|
20
|
+
- Employs object pooling to reduce garbage collection overhead
|
|
21
|
+
- **GPU 最適化**: WebGL/GPU テクスチャアトラス管理専用に設計
|
|
22
|
+
- Designed specifically for WebGL/GPU texture atlas management
|
|
23
|
+
- **TypeScript サポート**: 完全な型定義による優れた開発者体験
|
|
24
|
+
- Fully typed for enhanced developer experience
|
|
25
|
+
|
|
26
|
+
## インストール / Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
7
29
|
npm install @next2d/texture-packer
|
|
8
30
|
```
|
|
9
31
|
|
|
10
|
-
##
|
|
11
|
-
|
|
32
|
+
## ディレクトリ構造 / Directory Structure
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
texture-packer/
|
|
36
|
+
├── src/
|
|
37
|
+
│ ├── TexturePacker.ts # メインのテクスチャパッカークラス / Main texture packer class
|
|
38
|
+
│ ├── Node.ts # 二分木ノードクラス / Binary tree node class
|
|
39
|
+
│ ├── Node/
|
|
40
|
+
│ │ └── service/
|
|
41
|
+
│ │ ├── NodeInsertService.ts # テクスチャ挿入アルゴリズム / Texture insertion algorithm
|
|
42
|
+
│ │ └── NodeDisposeService.ts # テクスチャ破棄アルゴリズム / Texture disposal algorithm
|
|
43
|
+
│ └── index.ts # パッケージエントリーポイント / Package entry point
|
|
44
|
+
└── README.md
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### ファイル説明 / File Descriptions
|
|
48
|
+
|
|
49
|
+
- **TexturePacker.ts**: ルートノードを管理し、insert/dispose メソッドを提供するパブリック API / Public API that manages the root node and provides insert/dispose methods
|
|
50
|
+
- **Node.ts**: 左右の子ノードとオブジェクトプーリングを持つ二分木ノードの実装 / Binary tree node implementation with left/right children and object pooling
|
|
51
|
+
- **NodeInsertService.ts**: 新しいテクスチャのためのスペースを見つけて割り当てるコアアルゴリズム / Core algorithm for finding and allocating space for new textures
|
|
52
|
+
- **NodeDisposeService.ts**: 割り当てられたテクスチャスペースを解放し、ノードをマージするコアアルゴリズム / Core algorithm for releasing allocated texture space and merging nodes
|
|
53
|
+
|
|
54
|
+
## 二分木構造 / Binary Tree Structure
|
|
55
|
+
|
|
56
|
+
テクスチャパッカーは二分木構造を使用し、各ノードはテクスチャアトラス内の矩形領域を表します。テクスチャが挿入されると、ツリーは動的に分割されます。
|
|
57
|
+
|
|
58
|
+
The texture packer uses a binary tree structure where each node represents a rectangular region in the texture atlas. The tree dynamically splits as textures are inserted.
|
|
59
|
+
|
|
60
|
+
```mermaid
|
|
61
|
+
graph TD
|
|
62
|
+
A[Root Node / ルートノード<br/>1024x1024<br/>used: true] --> B[Left Child / 左の子<br/>256x1024<br/>used: true]
|
|
63
|
+
A --> C[Right Child / 右の子<br/>767x1024<br/>used: false]
|
|
64
|
+
B --> D[Left Child / 左の子<br/>256x256<br/>used: true<br/>TEXTURE A]
|
|
65
|
+
B --> E[Right Child / 右の子<br/>256x767<br/>used: false]
|
|
66
|
+
|
|
67
|
+
style A fill:#e1f5ff
|
|
68
|
+
style B fill:#e1f5ff
|
|
69
|
+
style C fill:#f0f0f0
|
|
70
|
+
style D fill:#90ee90
|
|
71
|
+
style E fill:#f0f0f0
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### ノードのプロパティ / Node Properties
|
|
75
|
+
|
|
76
|
+
各ノードには以下が含まれます / Each node contains:
|
|
77
|
+
- `x, y`: アトラス内の位置 / Position in the atlas
|
|
78
|
+
- `w, h`: 領域の幅と高さ / Width and height of the region
|
|
79
|
+
- `index`: アトラステクスチャのインデックス / Atlas texture index
|
|
80
|
+
- `left, right`: 子ノード(リーフの場合は null) / Child nodes (null if leaf)
|
|
81
|
+
- `used`: このスペースが割り当てられているか / Whether this space is allocated
|
|
82
|
+
|
|
83
|
+
## アルゴリズム / Algorithms
|
|
84
|
+
|
|
85
|
+
### 挿入アルゴリズム / Insert Algorithm
|
|
86
|
+
|
|
87
|
+
挿入アルゴリズムは、利用可能なスペースを見つけるために二分木を再帰的に検索します。
|
|
88
|
+
|
|
89
|
+
The insertion algorithm recursively searches the binary tree for available space.
|
|
90
|
+
|
|
91
|
+
```mermaid
|
|
92
|
+
flowchart TD
|
|
93
|
+
Start([Insert width, height<br/>width, height を挿入]) --> Check1{Is node used?<br/>ノードは使用中?}
|
|
94
|
+
Check1 -->|Yes / はい| Recurse[Try left child then right child<br/>左の子を試行、次に右の子]
|
|
95
|
+
Recurse --> ReturnResult([Return result<br/>結果を返す])
|
|
96
|
+
|
|
97
|
+
Check1 -->|No / いいえ| Check2{Fits in this node?<br/>このノードに収まる?}
|
|
98
|
+
Check2 -->|No / いいえ| ReturnNull([Return null<br/>null を返す])
|
|
99
|
+
|
|
100
|
+
Check2 -->|Yes / はい| Check3{Exact match?<br/>完全に一致?}
|
|
101
|
+
Check3 -->|Yes / はい| MarkUsed[Mark node as used<br/>ノードを使用中に設定]
|
|
102
|
+
MarkUsed --> ReturnNode([Return this node<br/>このノードを返す])
|
|
103
|
+
|
|
104
|
+
Check3 -->|No / いいえ| CalcDelta[Calculate / 差分を計算<br/>dw = node.w - width<br/>dh = node.h - height]
|
|
105
|
+
CalcDelta --> Split{dw > dh?}
|
|
106
|
+
|
|
107
|
+
Split -->|Yes / はい| SplitVertical[Vertical Split / 垂直分割<br/>left: width × h<br/>right: dw × h]
|
|
108
|
+
Split -->|No / いいえ| SplitHorizontal[Horizontal Split / 水平分割<br/>left: w × height<br/>right: w × dh]
|
|
109
|
+
|
|
110
|
+
SplitVertical --> MarkUsed2[Mark node as used<br/>ノードを使用中に設定]
|
|
111
|
+
SplitHorizontal --> MarkUsed2
|
|
112
|
+
MarkUsed2 --> InsertLeft[Insert into left child<br/>左の子に挿入]
|
|
113
|
+
InsertLeft --> ReturnResult2([Return result<br/>結果を返す])
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**アルゴリズムのステップ / Algorithm Steps:**
|
|
117
|
+
|
|
118
|
+
1. **使用状態の確認 / Check if used**: ノードが既に使用中の場合、左の子、次に右の子を再帰的に試行 / If the node is already used, recursively try left then right children
|
|
119
|
+
2. **サイズ検証 / Size validation**: テクスチャが収まらない場合は null を返す / Return null if the texture doesn't fit
|
|
120
|
+
3. **完全一致 / Exact match**: サイズが完全に一致する場合、使用中に設定して返す / If dimensions match exactly, mark as used and return
|
|
121
|
+
4. **分割方向の決定 / Split decision**: 残りのスペース(dw vs dh)を比較して分割方向を決定 / Compare remaining space (dw vs dh) to decide split direction
|
|
122
|
+
- `dw > dh` の場合: 垂直分割 / Split vertically (better for wider remaining space)
|
|
123
|
+
- それ以外: 水平分割 / Otherwise: Split horizontally (better for taller remaining space)
|
|
124
|
+
5. **子ノードの作成 / Create children**: 左の子は正確なサイズ、右の子は残りのスペースで作成 / Create left child with exact size, right child with remaining space
|
|
125
|
+
6. **再帰的挿入 / Recursive insert**: 左の子に挿入(確実に収まる) / Insert into the left child (guaranteed to fit)
|
|
126
|
+
|
|
127
|
+
**パディング / Padding**: アルゴリズムはテクスチャのにじみを防ぐために 1 ピクセルのパディング(`requiredWidth = width + 1`)を追加します。 / The algorithm adds 1-pixel padding (`requiredWidth = width + 1`) to prevent texture bleeding.
|
|
128
|
+
|
|
129
|
+
### 破棄アルゴリズム / Dispose Algorithm
|
|
130
|
+
|
|
131
|
+
破棄アルゴリズムはテクスチャを削除し、隣接する空きスペースをマージします。
|
|
132
|
+
|
|
133
|
+
The disposal algorithm removes a texture and merges adjacent free space.
|
|
134
|
+
|
|
135
|
+
```mermaid
|
|
136
|
+
flowchart TD
|
|
137
|
+
Start([Dispose x, y, w, h<br/>x, y, w, h を破棄]) --> TryLeft{Left child dispose succeeds?<br/>左の子の破棄が成功?}
|
|
138
|
+
|
|
139
|
+
TryLeft -->|Yes / はい| CheckMergeL{Both children not used?<br/>両方の子が未使用?}
|
|
140
|
+
CheckMergeL -->|Yes / はい| MergeL[Release both children<br/>Set left=right=null<br/>Mark this node unused<br/>両方の子を解放し未使用に設定]
|
|
141
|
+
CheckMergeL -->|No / いいえ| ReturnTrueL([Return true<br/>true を返す])
|
|
142
|
+
MergeL --> ReturnTrueL
|
|
143
|
+
|
|
144
|
+
TryLeft -->|No / いいえ| TryRight{Right child dispose succeeds?<br/>右の子の破棄が成功?}
|
|
145
|
+
|
|
146
|
+
TryRight -->|Yes / はい| CheckMergeR{Both children not used?<br/>両方の子が未使用?}
|
|
147
|
+
CheckMergeR -->|Yes / はい| MergeR[Release both children<br/>Set left=right=null<br/>Mark this node unused<br/>両方の子を解放し未使用に設定]
|
|
148
|
+
CheckMergeR -->|No / いいえ| ReturnTrueR([Return true<br/>true を返す])
|
|
149
|
+
MergeR --> ReturnTrueR
|
|
150
|
+
|
|
151
|
+
TryRight -->|No / いいえ| CheckMatch{Exact position and size match?<br/>位置とサイズが完全一致?}
|
|
152
|
+
CheckMatch -->|Yes / はい| MarkUnused[Mark node unused<br/>ノードを未使用に設定]
|
|
153
|
+
MarkUnused --> ReturnTrue([Return true<br/>true を返す])
|
|
154
|
+
CheckMatch -->|No / いいえ| ReturnFalse([Return false<br/>false を返す])
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**アルゴリズムのステップ / Algorithm Steps:**
|
|
158
|
+
|
|
159
|
+
1. **再帰的検索 / Recursive search**: 左の子、次に右の子で破棄を試行 / Try to dispose in left child, then right child
|
|
160
|
+
2. **一致確認 / Match check**: 見つかった場合、正確な位置とサイズが一致することを確認 / If found, verify exact position and dimensions match
|
|
161
|
+
3. **未使用に設定 / Mark unused**: ノードの `used` フラグを false に設定 / Set the node's `used` flag to false
|
|
162
|
+
4. **マージ最適化 / Merge optimization**: 両方の子が未使用の場合、それらをオブジェクトプールに解放してマージ / If both children are unused, release them to the object pool and merge
|
|
163
|
+
5. **伝播 / Propagation**: マージチェックはツリーを上方向に伝播し、利用可能な連続スペースを最大化 / The merge check propagates up the tree, maximizing available contiguous space
|
|
164
|
+
|
|
165
|
+
**メモリ管理 / Memory Management**: 解放されたノードはオブジェクトプールに返却され、再利用されることで割り当てのオーバーヘッドを削減します。 / Released nodes are returned to the object pool for reuse, reducing allocation overhead.
|
|
166
|
+
|
|
167
|
+
## 使用例 / Usage Example
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
import { TexturePacker } from '@next2d/texture-packer';
|
|
171
|
+
|
|
172
|
+
// 1024x1024 のテクスチャアトラスを作成(インデックス 0)
|
|
173
|
+
// Create a 1024x1024 texture atlas (index 0)
|
|
174
|
+
const packer = new TexturePacker(0, 1024, 1024);
|
|
175
|
+
|
|
176
|
+
// 256x256 のテクスチャを挿入 / Insert a 256x256 texture
|
|
177
|
+
const node1 = packer.insert(256, 256);
|
|
178
|
+
if (node1) {
|
|
179
|
+
console.log(`テクスチャは (${node1.x}, ${node1.y}) に割り当てられました`);
|
|
180
|
+
// Texture allocated at (${node1.x}, ${node1.y})
|
|
181
|
+
// UV 座標に node1.x, node1.y を使用 / Use node1.x, node1.y for UV coordinates
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// 別のテクスチャを挿入 / Insert another texture
|
|
185
|
+
const node2 = packer.insert(128, 128);
|
|
186
|
+
|
|
187
|
+
// 不要になったテクスチャを破棄 / Dispose a texture when no longer needed
|
|
188
|
+
if (node1) {
|
|
189
|
+
const success = packer.dispose(node1.x, node1.y, node1.w, node1.h);
|
|
190
|
+
console.log(`破棄に${success ? '成功' : '失敗'}しました`);
|
|
191
|
+
// Disposal ${success ? 'succeeded' : 'failed'}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// node1 のスペースは再利用可能になりました
|
|
195
|
+
// The space from node1 can now be reused
|
|
196
|
+
const node3 = packer.insert(200, 200);
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## API リファレンス / API Reference
|
|
200
|
+
|
|
201
|
+
### TexturePacker
|
|
202
|
+
|
|
203
|
+
#### `constructor(index: number, width: number, height: number)`
|
|
204
|
+
|
|
205
|
+
指定されたアトラスサイズで新しいテクスチャパッカーを作成します。
|
|
206
|
+
|
|
207
|
+
Creates a new texture packer with the specified atlas dimensions.
|
|
208
|
+
|
|
209
|
+
- `index`: アトラステクスチャのインデックス / Atlas texture index
|
|
210
|
+
- `width`: アトラスの幅(ピクセル) / Atlas width in pixels
|
|
211
|
+
- `height`: アトラスの高さ(ピクセル) / Atlas height in pixels
|
|
212
|
+
|
|
213
|
+
#### `insert(width: number, height: number): Node | null`
|
|
214
|
+
|
|
215
|
+
指定されたサイズのテクスチャを挿入しようと試みます。
|
|
216
|
+
|
|
217
|
+
Attempts to insert a texture with the given dimensions.
|
|
218
|
+
|
|
219
|
+
- 戻り値 / Returns: 成功した場合は位置を持つ `Node`、スペースがない場合は `null` / `Node` with position if successful, `null` if no space available
|
|
220
|
+
|
|
221
|
+
#### `dispose(x: number, y: number, width: number, height: number): boolean`
|
|
222
|
+
|
|
223
|
+
指定された位置とサイズのテクスチャを解放します。
|
|
224
|
+
|
|
225
|
+
Releases the texture at the specified position and dimensions.
|
|
226
|
+
|
|
227
|
+
- 戻り値 / Returns: 破棄に成功した場合は `true`、それ以外は `false` / `true` if disposal succeeded, `false` otherwise
|
|
228
|
+
|
|
229
|
+
### Node
|
|
230
|
+
|
|
231
|
+
#### プロパティ / Properties
|
|
232
|
+
|
|
233
|
+
- `index: number` - アトラステクスチャのインデックス / Atlas texture index
|
|
234
|
+
- `x: number` - アトラス内の X 座標 / X coordinate in atlas
|
|
235
|
+
- `y: number` - アトラス内の Y 座標 / Y coordinate in atlas
|
|
236
|
+
- `w: number` - 割り当てられた領域の幅 / Width of allocated region
|
|
237
|
+
- `h: number` - 割り当てられた領域の高さ / Height of allocated region
|
|
238
|
+
- `left: Node | null` - 左の子ノード / Left child node
|
|
239
|
+
- `right: Node | null` - 右の子ノード / Right child node
|
|
240
|
+
- `used: boolean` - スペースが割り当てられているか / Whether space is allocated
|
|
241
|
+
|
|
242
|
+
## ライセンス / License
|
|
243
|
+
|
|
244
|
+
This project is licensed under the [MIT License](https://opensource.org/licenses/MIT) - see the LICENSE file for details.
|
package/package.json
CHANGED
|
@@ -14,6 +14,13 @@
|
|
|
14
14
|
export const execute = (node, x, y, width, height) => {
|
|
15
15
|
if (node.left?.dispose(x, y, width, height)) {
|
|
16
16
|
if (!node.left.used && !node.right?.used) {
|
|
17
|
+
// 子ノードをプールに返却
|
|
18
|
+
if (node.left) {
|
|
19
|
+
node.left.release();
|
|
20
|
+
}
|
|
21
|
+
if (node.right) {
|
|
22
|
+
node.right.release();
|
|
23
|
+
}
|
|
17
24
|
node.left = node.right = null;
|
|
18
25
|
node.used = false;
|
|
19
26
|
}
|
|
@@ -21,6 +28,13 @@ export const execute = (node, x, y, width, height) => {
|
|
|
21
28
|
}
|
|
22
29
|
if (node.right?.dispose(x, y, width, height)) {
|
|
23
30
|
if (!node.right.used && !node.left?.used) {
|
|
31
|
+
// 子ノードをプールに返却
|
|
32
|
+
if (node.left) {
|
|
33
|
+
node.left.release();
|
|
34
|
+
}
|
|
35
|
+
if (node.right) {
|
|
36
|
+
node.right.release();
|
|
37
|
+
}
|
|
24
38
|
node.left = node.right = null;
|
|
25
39
|
node.used = false;
|
|
26
40
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Node } from "../../Node";
|
|
2
1
|
/**
|
|
3
2
|
* @description ノード挿入ロジック
|
|
4
3
|
* Node insertion logic
|
|
@@ -22,15 +21,17 @@ export const execute = (node, width, height) => {
|
|
|
22
21
|
node.used = true;
|
|
23
22
|
return node;
|
|
24
23
|
}
|
|
25
|
-
const
|
|
26
|
-
const
|
|
24
|
+
const requiredWidth = width + 1;
|
|
25
|
+
const requiredHeight = height + 1;
|
|
26
|
+
const dw = node.w - requiredWidth;
|
|
27
|
+
const dh = node.h - requiredHeight;
|
|
27
28
|
if (dw > dh) {
|
|
28
|
-
node.left =
|
|
29
|
-
node.right =
|
|
29
|
+
node.left = node.create(node.index, node.x, node.y, width, node.h);
|
|
30
|
+
node.right = node.create(node.index, node.x + requiredWidth, node.y, dw, node.h);
|
|
30
31
|
}
|
|
31
32
|
else {
|
|
32
|
-
node.left =
|
|
33
|
-
node.right =
|
|
33
|
+
node.left = node.create(node.index, node.x, node.y, node.w, height);
|
|
34
|
+
node.right = node.create(node.index, node.x, node.y + requiredHeight, node.w, dh);
|
|
34
35
|
}
|
|
35
36
|
node.used = true;
|
|
36
37
|
return node.left.insert(width, height);
|
package/src/Node.d.ts
CHANGED
|
@@ -99,4 +99,27 @@ export declare class Node {
|
|
|
99
99
|
* @public
|
|
100
100
|
*/
|
|
101
101
|
dispose(x: number, y: number, width: number, height: number): boolean;
|
|
102
|
+
/**
|
|
103
|
+
* @description 新規ノードを生成(プールから取得または新規作成)
|
|
104
|
+
* Create a new node (get from pool or create new)
|
|
105
|
+
*
|
|
106
|
+
* @param {number} index
|
|
107
|
+
* @param {number} x
|
|
108
|
+
* @param {number} y
|
|
109
|
+
* @param {number} w
|
|
110
|
+
* @param {number} h
|
|
111
|
+
* @return {Node}
|
|
112
|
+
* @method
|
|
113
|
+
* @public
|
|
114
|
+
*/
|
|
115
|
+
create(index: number, x: number, y: number, w: number, h: number): Node;
|
|
116
|
+
/**
|
|
117
|
+
* @description ノードをプールに返却(メモリ再利用)
|
|
118
|
+
* Return node to pool (memory reuse)
|
|
119
|
+
*
|
|
120
|
+
* @return {void}
|
|
121
|
+
* @method
|
|
122
|
+
* @public
|
|
123
|
+
*/
|
|
124
|
+
release(): void;
|
|
102
125
|
}
|
package/src/Node.js
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { execute as nodeInsertService } from "./Node/service/NodeInsertService";
|
|
2
2
|
import { execute as nodeDisposeService } from "./Node/service/NodeDisposeService";
|
|
3
|
+
/**
|
|
4
|
+
* @description ノードオブジェクトプール(パフォーマンス最適化)
|
|
5
|
+
* Node object pool (performance optimization)
|
|
6
|
+
*
|
|
7
|
+
* @type {Node[]}
|
|
8
|
+
* @private
|
|
9
|
+
*/
|
|
10
|
+
const $nodePool = [];
|
|
3
11
|
/**
|
|
4
12
|
* @description テクスチャパッキングのノードクラス
|
|
5
13
|
* Node class for texture
|
|
@@ -154,4 +162,51 @@ export class Node {
|
|
|
154
162
|
dispose(x, y, width, height) {
|
|
155
163
|
return nodeDisposeService(this, x, y, width, height);
|
|
156
164
|
}
|
|
165
|
+
/**
|
|
166
|
+
* @description 新規ノードを生成(プールから取得または新規作成)
|
|
167
|
+
* Create a new node (get from pool or create new)
|
|
168
|
+
*
|
|
169
|
+
* @param {number} index
|
|
170
|
+
* @param {number} x
|
|
171
|
+
* @param {number} y
|
|
172
|
+
* @param {number} w
|
|
173
|
+
* @param {number} h
|
|
174
|
+
* @return {Node}
|
|
175
|
+
* @method
|
|
176
|
+
* @public
|
|
177
|
+
*/
|
|
178
|
+
create(index, x, y, w, h) {
|
|
179
|
+
const node = $nodePool.length
|
|
180
|
+
? $nodePool.pop()
|
|
181
|
+
: new Node(index, 0, 0, 0, 0);
|
|
182
|
+
node.index = index;
|
|
183
|
+
node.x = x;
|
|
184
|
+
node.y = y;
|
|
185
|
+
node.w = w;
|
|
186
|
+
node.h = h;
|
|
187
|
+
node.left = null;
|
|
188
|
+
node.right = null;
|
|
189
|
+
node.used = false;
|
|
190
|
+
return node;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* @description ノードをプールに返却(メモリ再利用)
|
|
194
|
+
* Return node to pool (memory reuse)
|
|
195
|
+
*
|
|
196
|
+
* @return {void}
|
|
197
|
+
* @method
|
|
198
|
+
* @public
|
|
199
|
+
*/
|
|
200
|
+
release() {
|
|
201
|
+
if (this.left) {
|
|
202
|
+
this.left.release();
|
|
203
|
+
this.left = null;
|
|
204
|
+
}
|
|
205
|
+
if (this.right) {
|
|
206
|
+
this.right.release();
|
|
207
|
+
this.right = null;
|
|
208
|
+
}
|
|
209
|
+
this.used = false;
|
|
210
|
+
$nodePool.push(this);
|
|
211
|
+
}
|
|
157
212
|
}
|