Created
April 12, 2020 14:57
-
-
Save eXponenta/88985b2338ba63d45e984d52c984b685 to your computer and use it in GitHub Desktop.
Generate Texture atlass from entity and cache it
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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