Skip to content

Instantly share code, notes, and snippets.

@eXponenta
Created April 12, 2020 14:57
Show Gist options
  • Save eXponenta/88985b2338ba63d45e984d52c984b685 to your computer and use it in GitHub Desktop.
Save eXponenta/88985b2338ba63d45e984d52c984b685 to your computer and use it in GitHub Desktop.
Generate Texture atlass from entity and cache it
/**
* This is the default playground.
* You should see a bunny spinning in the right preview pane.
* Feel free to use this as a starting point for you own playground!
*/
class CachedTexture extends PIXI.RenderTexture {
constructor(base, frame){
super(base, frame);
/**
* @type {string}
*/
this.id = undefined;
/**
* @type {number}
*/
this.index = 0;
/**
* @type {boolean}
*/
this.used = false;
this.rtId = -1;
/**
* @type {CacheManager}
*/
this._manager = undefined;
}
destroy() {
this._manager.release(this);
}
}
const tempMatrix = new PIXI.Matrix();
const clear = new PIXI.Sprite(PIXI.Texture.WHITE);
class CacheManager extends PIXI.utils.EventEmitter {
/**
* @param {PIXI.Renderer} renderer
* @param {PIXI.ISize} frame - basic frame size
* @param {number} [count] - frame cell by pallete
*/
constructor(renderer, frame, count = 100) {
super();
this.maxSize = 2048;
this.pad = 2;
this._renderer = renderer;
this._frame = frame;
/**
* @type {PIXI.BaseRenderTexture[]}
*/
this._rts = [];
this._nextCellIndex = 0;
this._cellsPerRt = 0;
this._used = false;
/**
* @type {Map<string, CachedTexture>}
*/
this._items = new Map();
/**
* @type {CachedTexture[]}
*/
this._free = [];
}
init() {
if(this._used) {
this.destroy();
}
const cellPerRt =
(this.maxSize / (this.pad + this._frame.height) | 0) *
(this.maxSize / (this.pad + this._frame.width) | 0) ;
if(!cellPerRt) {
throw new Error('Frame is large, it sould be less that 2048x2048');
}
if(cellPerRt < 4) {
console.warn(`Cached frames ${cellPerRt} <= 4, there are not reason cache it`);
}
this._cellsPerRt = cellPerRt;
this.emit('init');
}
/**
*
* @param {string} id
* @param {PIXI.Container} object
* @param {boolean} update - update existed cache cell
* @returns {CachedTexture}
*/
set(id, object, update = false) {
if(!this._cellsPerRt){
this.init();
}
let texture = this._items.get(id);
if(texture && !update) {
return texture;
}
texture = texture || this._free.shift() || this.createNext();
texture.id = id;
texture.used = true;
this._gen(object, texture);
this._items.set(id, texture);
return texture;
}
/**
*
* @param {PIXI.BaseRenderTexture} rt
* @param {PIXI.Rectangle} frame
* @returns {CachedTexture}
*/
createNext() {
const rtId =(this._nextCellIndex / this._cellsPerRt) | 0;
const frameId = this._nextCellIndex - rtId * this._cellsPerRt;
const colls = this.maxSize / (this.pad + this._frame.width) | 0;
const rt = this._rts[rtId] || new PIXI.BaseRenderTexture({
width: this.maxSize,
height: this.maxSize,
resolution: this._renderer.resolution});
this._rts[rtId] = rt;
const frame = new PIXI.Rectangle(
(frameId % colls) * (this.pad + this._frame.width),
(frameId / colls | 0) * (this.pad + this._frame.height),
this._frame.width, this._frame.height
);
const tex = new CachedTexture(rt,frame);
tex._manager = this;
tex.index = this._nextCellIndex;
tex.used = true;
this._nextCellIndex ++;
return tex;
}
/**
*
* @param {CachedTexture} texture
*/
release(texture) {
if(!texture || !texture.id) {
return;
}
const id = texture.id;
const item = this._items.get(id);
if(item !== texture) {
throw new Error('Item not from pool!');
}
item.id = "";
item.used = false;
this._items.delete(id);
this._free.push(item);
clear.blendMode = PIXI.BLEND_MODES.ERASE;
this._gen(clear, item);
}
/**
*
* @param {string} id
* @returns {PIXI.Texture}
*/
get(id) {
return this._items.get(id);
}
/**
*
* @param {PIXI.Container} obj
* @param {PIXI.RenderTexture} target
* @param {PIXI.Rectangle} frame
*/
_gen(obj, target) {
const bounds = obj.getLocalBounds(undefined);
const frame = target.frame;
tempMatrix.identity();
tempMatrix.scale(frame.width / bounds.width, frame.height / bounds.height);
tempMatrix.translate(-bounds.x + frame.x, -bounds.y + frame.y);
this._renderer.render(obj, target, false, tempMatrix, true);
}
destroy() {
this._rts.forEach((e) => e.destroy());
this._rts = [];
this.emit('destroy');
this._used = false;
this._cellsPerRt = 0;
this._free = [];
this._items.clear()
}
}
// Create our application instance
var app = new PIXI.Application({
width: window.innerWidth,
height: window.innerHeight,
backgroundColor: 0x2c3e50
});
document.body.appendChild(app.view);
// Load the bunny texture
app.loader.add('bunny', 'https://pixijs.io/examples/examples/assets/bunny.png')
.load(startup);
function startup()
{
var bunny = new PIXI.Sprite(app.loader.resources.bunny.texture);
const m = new CacheManager(app.renderer, {
width: 200, height: 200
});
m.maxSize = 2048;
for(let i = 0; i < 100; i ++){
bunny.tint = Math.random() * 0xffffff;
m.set("bunny" + i, bunny);
}
for(let i = 0; i < 50; i ++){
m.get("bunny" + i).destroy();
}
for(let i = 0; i < 6; i ++){
bunny.tint = 0xff00ff;
m.set("bunny" + i, bunny);
}
console.log(m);
bunny.texture = m.get("bunny" + Math.random() * 100 | 0);
// Center the sprite's anchor point
bunny.anchor.set(0.5);
// Move the sprite to the center of the screen
bunny.x = app.renderer.width / 2;
bunny.y = app.renderer.height / 2;
const g = new PIXI.Graphics();
g.lineStyle(10, 0xff0000);
for(let i = 0; i < m._rts.length; i++) {
const t = new PIXI.Texture(m._rts[i]);
g.beginTextureFill({texture:t});
g.drawRect(i * m.maxSize, 0, m.maxSize, m.maxSize);
}
g.scale.set(0.2)
app.stage.addChild(bunny, g);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment