-
Notifications
You must be signed in to change notification settings - Fork 0
/
texture-atlas.ts
149 lines (129 loc) · 3.11 KB
/
texture-atlas.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import * as PIXI from 'pixi.js';
// declare this on server or in tests to save memory
declare var headless: boolean;
export interface TextureAtlasOptions {
texture: PIXI.Texture;
tileWidth?: number;
tileHeight?: number;
cols?: number;
rows?: number;
offset?: number;
count?: number;
scaleMode?: PIXI.SCALE_MODE;
}
/**
* for slicing textures into tileset
*/
export class TextureAtlas {
/**
* texture atlas base texture (required in constructor)
*/
texture: PIXI.Texture;
/**
* calculated from cols/rows or passed in constructor
*/
tileWidth: number;
/**
* calculated from cols/rows or passed in constructor
*/
tileHeight: number;
/**
* get(frame) gets slice of index frame - offset
* if unsure leave at 0
*/
offset: number;
/**
* scale mode for slices
*/
scaleMode: PIXI.SCALE_MODE;
/**
* texture slices
*/
slices: PIXI.Texture[] = [];
/**
* create texture atlas
* @param textureAtlasOptions
*/
constructor({
texture,
tileWidth,
tileHeight,
cols,
rows,
count,
offset = 0,
scaleMode = 'nearest'
}: TextureAtlasOptions) {
this.texture = texture;
if (tileWidth && tileHeight) {
this.tileWidth = tileWidth;
this.tileHeight = tileHeight;
} else if (cols && rows) {
this.tileWidth = this.width / cols;
this.tileHeight = this.height / rows;
} else {
throw new Error('Specify tileWidth/tileHeight or cols/rows.');
}
this.offset = offset;
this.scaleMode = scaleMode;
this.preload(count);
}
/**
* width read from texture
*/
get width(): number {
return this.texture.width;
}
/**
* height read from texture
*/
get height(): number {
return this.texture.height;
}
/**
* get lazy cached slice on index
*/
get(frame: number): PIXI.Texture {
if (typeof headless !== 'undefined') {
return PIXI.Texture.WHITE;
}
if (!this.slices[frame]) {
this.loadSlice(frame);
}
return this.slices[frame];
}
/**
* used internally in get(frame) to load the slice first time
*/
protected loadSlice(frame: number): PIXI.Texture {
if (typeof headless !== 'undefined') {
return PIXI.Texture.WHITE;
}
const cols: number = Math.floor(this.width / this.tileWidth);
const index: number = Math.floor(frame - this.offset);
const x: number = (index % cols) * this.tileWidth;
const y: number = Math.floor(index / cols) * this.tileHeight;
const texture: PIXI.Texture = new PIXI.Texture({
source: this.texture.source,
frame: new PIXI.Rectangle(x, y, this.tileWidth, this.tileHeight)
});
texture.source.scaleMode = this.scaleMode;
return texture;
}
/**
* used internally to preload cached slices
*/
protected preload(
count = Math.floor(
(this.width / this.tileWidth) * (this.height / this.tileHeight)
)
): void {
if (this.slices.length) {
throw new Error("Don't call prepare() twice.");
}
Array.from({ length: count }, (_, frame) => {
const texture = this.loadSlice(frame);
this.slices.push(texture);
});
}
}