Newer
Older
pixi.js / packages / core / src / shader / generateUniformsSync.js
@Matt Karl Matt Karl on 31 Oct 2017 5 KB Next Restructure for v5 (#4387)
// cv = CachedValue
// v = value
// ud = uniformData
// uv = uniformValue
// l = loaction
const GLSL_TO_SINGLE_SETTERS_CACHED = {

    float: `
    if(cv !== v)
    {
        cv.v = v;
        gl.uniform1f(location, v)
    }`,

    vec2: `
    if(cv[0] !== v[0] || cv[1] !== v[1])
    {
        cv[0] = v[0];
        cv[1] = v[1];
        gl.uniform2f(location, v[0], v[1])
    }`,

    vec3: `
    if(cv[0] !== v[0] || cv[1] !== v[1] || cv[2] !== v[2])
    {
        cv[0] = v[0];
        cv[1] = v[1];
        cv[2] = v[2];

        gl.uniform3f(location, v[0], v[1], v[2])
    }`,

    vec4:     'gl.uniform4f(location, v[0], v[1], v[2], v[3])',

    int:      'gl.uniform1i(location, v)',
    ivec2:    'gl.uniform2i(location, v[0], v[1])',
    ivec3:    'gl.uniform3i(location, v[0], v[1], v[2])',
    ivec4:    'gl.uniform4i(location, v[0], v[1], v[2], v[3])',

    bool:     'gl.uniform1i(location, v)',
    bvec2:    'gl.uniform2i(location, v[0], v[1])',
    bvec3:    'gl.uniform3i(location, v[0], v[1], v[2])',
    bvec4:    'gl.uniform4i(location, v[0], v[1], v[2], v[3])',

    mat2:     'gl.uniformMatrix2fv(location, false, v)',
    mat3:     'gl.uniformMatrix3fv(location, false, v)',
    mat4:     'gl.uniformMatrix4fv(location, false, v)',

    sampler2D:      'gl.uniform1i(location, v)',
    samplerCube:    'gl.uniform1i(location, v)',
    sampler2DArray: 'gl.uniform1i(location, v)',
};

const GLSL_TO_ARRAY_SETTERS = {

    float:    `gl.uniform1fv(location, v)`,

    vec2:     `gl.uniform2fv(location, v)`,
    vec3:     `gl.uniform3fv(location, v)`,
    vec4:     'gl.uniform4fv(location, v)',

    mat4:     'gl.uniformMatrix4fv(location, false, v)',
    mat3:     'gl.uniformMatrix3fv(location, false, v)',
    mat2:     'gl.uniformMatrix2fv(location, false, v)',

    int:      'gl.uniform1iv(location, v)',
    ivec2:    'gl.uniform2iv(location, v)',
    ivec3:    'gl.uniform3iv(location, v)',
    ivec4:    'gl.uniform4iv(location, v)',

    bool:     'gl.uniform1iv(location, v)',
    bvec2:    'gl.uniform2iv(location, v)',
    bvec3:    'gl.uniform3iv(location, v)',
    bvec4:    'gl.uniform4iv(location, v)',

    sampler2D:      'gl.uniform1iv(location, v)',
    samplerCube:    'gl.uniform1iv(location, v)',
    sampler2DArray: 'gl.uniform1iv(location, v)',
};

export default function generateUniformsSync(group, uniformData)
{
    let textureCount = 0;
    let func = `var v = null;
    var cv = null
    var gl = renderer.gl`;

    for (const i in group.uniforms)
    {
        const data = uniformData[i];

        if (!data)
        {
            if (group.uniforms[i].group)
            {
                func += `
                    renderer.shader.syncUniformGroup(uv.${i});
                `;
            }

            continue;
        }

        // TODO && uniformData[i].value !== 0 <-- do we still need this?
        if (data.type === 'float' && data.size === 1)
        {
            func += `
            if(uv.${i} !== ud.${i}.value)
            {
                ud.${i}.value = uv.${i}
                gl.uniform1f(ud.${i}.location, uv.${i})
            }\n`;
        }
        /* eslint-disable max-len */
        else if ((data.type === 'sampler2D' || data.type === 'samplerCube' || data.type === 'sampler2DArray') && data.size === 1 && !data.isArray)
        /* eslint-disable max-len */
        {
            func += `
            renderer.texture.bind(uv.${i}, ${textureCount});

            if(ud.${i}.value !== ${textureCount})
            {
                ud.${i}.value = ${textureCount};
                gl.uniform1i(ud.${i}.location, ${textureCount});\n; // eslint-disable-line max-len
            }\n`;

            textureCount++;
        }
        else if (data.type === 'mat3' && data.size === 1)
        {
            if (group.uniforms[i].a !== undefined)
            {
                // TODO and some smart caching dirty ids here!
                func += `
                gl.uniformMatrix3fv(ud.${i}.location, false, uv.${i}.toArray(true));
                \n`;
            }
            else
            {
                func += `
                gl.uniformMatrix3fv(ud.${i}.location, false, uv.${i});
                \n`;
            }
        }
        else if (data.type === 'vec2' && data.size === 1)
        {
            // TODO - do we need both here?
            // maybe we can get away with only using points?
            if (group.uniforms[i].x !== undefined)
            {
                func += `
                cv = ud.${i}.value;
                v = uv.${i};

                if(cv[0] !== v.x || cv[1] !== v.y)
                {
                    cv[0] = v.x;
                    cv[1] = v.y;
                    gl.uniform2f(ud.${i}.location, v.x, v.y);
                }\n`;
            }
            else
            {
                func += `
                cv = ud.${i}.value;
                v = uv.${i};

                if(cv[0] !== v[0] || cv[1] !== v[1])
                {
                    cv[0] = v[0];
                    cv[1] = v[1];
                    gl.uniform2f(ud.${i}.location, v[0], v[1]);
                }
                \n`;
            }
        }
        else
        {
            const templateType = (data.size === 1) ? GLSL_TO_SINGLE_SETTERS_CACHED : GLSL_TO_ARRAY_SETTERS;

            const template =  templateType[data.type].replace('location', `ud.${i}.location`);

            func += `
            cv = ud.${i}.value;
            v = uv.${i};
            ${template};\n`;
        }
    }

    // console.log(' --------------- ')
    // console.log(func);

    return new Function('ud', 'uv', 'renderer', func); // eslint-disable-line no-new-func
}