Newer
Older
pixi.js / src / core / renderers / webgl / managers / NewTextureManager.js
import WebGLManager from './WebGLManager';
import { GLFramebuffer, GLTexture } from 'pixi-gl-core';

/**
 * @class
 * @extends PIXI.WebGLManager
 * @memberof PIXI
 */
export default class TextureManager extends WebGLManager
{
    /**
     * @param {PIXI.WebGLRenderer} renderer - The renderer this manager works for.
     */
    constructor(renderer)
    {
        super(renderer);
        this.boundTextures = [
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null
        ];

    }

    /**
     * Sets up the renderer context and necessary buffers.
     *
     * @private
     */
    onContextChange()
    {
        const gl = this.gl = this.renderer.gl;
        this.CONTEXT_UID = this.renderer.CONTEXT_UID;

        // TODO move this.. to a nice make empty textures class..
        this.emptyTextures = {}

        this.emptyTextures[gl.TEXTURE_2D] = new GLTexture.fromData(this.gl, null, 1, 1);
        this.emptyTextures[gl.TEXTURE_CUBE_MAP] = new GLTexture(this.gl);

        gl.bindTexture(gl.TEXTURE_CUBE_MAP, this.emptyTextures[gl.TEXTURE_CUBE_MAP].texture);

        for (var i = 0; i < 6; i++)
        {
            gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, gl.RGBA,  1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
        }

        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    }

    bindTexture(texture, location)
    {
        const gl = this.gl;

        location = location || 0;

        gl.activeTexture(gl.TEXTURE0 + location);

        if(texture && texture.valid)
        {
            const glTexture = texture.glTextures[this.CONTEXT_UID] || this.initTexture(texture);

            gl.bindTexture(texture.type, glTexture.texture);

            if(glTexture.dirtyId !== texture.dirtyId)
            {
                glTexture.dirtyId = texture.dirtyId;
                this.updateTexture(texture);
            }

            this.boundTextures[location] = texture;
        }
        else
        {
            gl.bindTexture(texture.type, this.emptyTextures[texture.type].texture);
            this.boundTextures[location] = null;
        }
    }

    unbindTexture(texture)
    {
        const gl = this.gl;

        for (var i = 0; i <  this.boundTextures.length; i++) {

            if(this.boundTextures[i] === texture)
            {
                gl.activeTexture(gl.TEXTURE0 + i);
                gl.bindTexture(gl.TEXTURE_2D, this.emptyGLTexture.texture);
                this.boundTextures[i] = null;
            }
        }
    }

    initTexture(texture)
    {
        const gl = this.gl;

        var glTexture = new GLTexture(this.gl);

        // guarentee an update..
        glTexture.dirtyId = -1;

        texture.glTextures[this.CONTEXT_UID] = glTexture;

        return glTexture;
    }

    updateTexture(texture)
    {
        const glTexture = texture.glTextures[this.CONTEXT_UID];
        const gl = this.gl;

        // TODO there are only 3 textures as far as im aware?
        // Cube / 2D and later 3d. (the latter is WebGL2, we will get to that soon!)
        if(texture.type === gl.TEXTURE_CUBE_MAP)
        {

            for (var i = 0; i < texture.sides.length; i++)
            {
                // TODO - we should only upload what changed..
                // but im sure this is not  going to be a problem just yet!
                var texturePart = texture.sides[i];

                if(texturePart.resource)
                {
                    gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + texturePart.side, 0, glTexture.format, glTexture.format, glTexture.type, texturePart.resource.source);
                }
                else
                {
                    gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + texturePart.side, 0, gl.RGBA,  texture.width, texture.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
                }
            }
        }
        else
        {
            if(texture.resource)
            {
                glTexture.upload(texture.resource.source);
            }
            else
            {
                glTexture.uploadData(null, texture.width, texture.height);
            }
        }

        // lets only update what changes..
        this.setStyle(texture);
    }

    setStyle(texture)
    {
        const gl = this.gl;
        const style = texture.style;

        gl.texParameteri(texture.type, gl.TEXTURE_WRAP_S, style.wrapMode);
        gl.texParameteri(texture.type, gl.TEXTURE_WRAP_T, style.wrapMode);

        if(texture.mipmap)
        {
            gl.texParameteri(texture.type, gl.TEXTURE_MIN_FILTER, style.scaleMode ? gl.LINEAR_MIPMAP_LINEAR : gl.NEAREST_MIPMAP_NEAREST);
        }
        else
        {
            gl.texParameteri(texture.type, gl.TEXTURE_MIN_FILTER, style.scaleMode ? gl.LINEAR : gl.NEAREST);
        }

        gl.texParameteri(texture.type, gl.TEXTURE_MAG_FILTER, style.scaleMode ? gl.LINEAR : gl.NEAREST);
    }
}