aboutsummaryrefslogtreecommitdiff
path: root/js/helper-classes/RDGE/src/core/script/ubershader.js
blob: 5d13d5a80c01653c35c328646b54b21dd503e53e (plain)
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
150
151
152
153
154
155
156
157
158
159
/* <copyright>
 This file contains proprietary software owned by Motorola Mobility, Inc.<br/>
 No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.<br/>
 (c) Copyright 2011 Motorola Mobility, Inc.  All Rights Reserved.
 </copyright> */
 
 /* UBERSHADER */ 
/*
    The ubershader function takes a JSON definition object and creates a jshader 
    that supports all or a subset of ubershader features. The ubershader currently 
    supports up to four per-pixel lights, optional diffuse, normal, specular, and 
    environment map textures. Lights can be directional, point, or spot lights. The 
    resulting shader is very much optimized based on the given use case, so if the 
    configuration changes, such as by adding a light, removing a texture, or even 
    changing the type of a light) then the shader needs to be rebuilt and recompiled 
    to reflect those changes.  
*/
ubershader = function(def) {
    var r = new XMLHttpRequest();
    r.open('GET', "assets/shaders/ub_vshader.glsl", false);
    r.send(null);
    if (r.status == 200) {
        vshader = r.responseText;
    }
    r.open('GET', "assets/shaders/ub_fshader.glsl", false);
    r.send(null);
    if (r.status == 200) {
        fshader = r.responseText;
    }
    var preproc = "";
//    var paramBlock = {};

//    paramBlock['u_uvMatrix'] = { 'type': 'mat4' };

    if (typeof def.material != 'undefined') {
        preproc += '#define MATERIAL\n';
    }
    if (typeof def.lighting != 'undefined') {
        preproc += '#define LIGHTING\n';
        preproc += '#define SPECULAR\n';
        for (i = 0; i < 4; ++i) {
            var light = def.lighting['light' + i];
            var t;
            if (typeof light != 'undefined') {
                switch (light.type) {
                    case 'directional': t = 0; break;
                    case 'point': t = 1; break;
                    case 'spot': t = 2; break;
                }
                preproc += '#define LIGHT_' + i + ' ' + t + '\n';
                preproc += '#define LIGHT_' + i + '_SPECULAR\n';
            }
        }
    }
    if (typeof def.diffuseMap != 'undefined') {
        preproc += '#define DIFFUSE_MAP\n';
    }
    if (typeof def.normalMap != 'undefined') {
        preproc += '#define NORMAL_MAP\n';
    }
    if (typeof def.specularMap != 'undefined') {
        preproc += '#define SPECULAR_MAP\n';
    }
    if (typeof def.environmentMap != 'undefined') {
        preproc += '#define ENVIRONMENT_MAP\n';
    }

    // prefix preprocessor settings
    vshader = preproc + vshader;
    fshader = preproc + fshader;

    // build output jshader    
    uberJShader = new jshader();
    uberJShader.def = {
        'shaders': {
            'defaultVShader': vshader,
            'defaultFShader': fshader
        },
        'techniques': {
            'defaultTechnique': [{
                'vshader': 'defaultVShader',
                'fshader': 'defaultFShader',
                'attributes': {
                    'a_pos': { 'type': 'vec3' },
                    'a_normal': { 'type': 'vec3' },
                    'a_texcoord': { 'type': 'vec2' }
                },
                'params': {
                    specularColor : 'u_specularColor',
                },
                'states': {
                    'depthEnable': true,
                    'blendEnable': false,
                    'culling': true,
                    'cullFace': "FRONT"
                }
            }]
            }
        }
        // initialize the jshader
        uberJShader.init();

        // initialize shader parameters
        var technique = uberJShader.defaultTechnique;
        if (typeof def.material != 'undefined') {
            technique.u_ambientColor.set(def.material.ambientColor);
            technique.u_diffuseColor.set(def.material.diffuseColor);
            if (technique.u_specularColor)
                technique.u_specularColor.set(def.material.specularColor);
            if (technique.u_specularPower)
                technique.u_specularPower.set([def.material.specularPower]);
        }
        if (typeof def.lighting != 'undefined') {
            for (i = 0; i < 4; ++i) {
                var light = def.lighting["light" + i];
                if (typeof light != "undefined") {
                    if (light.type == 'directional') {
                        paramBlock['u_light' + i + 'Dir'] = { 'type': 'vec3' };
                        technique['u_light' + i + 'Dir'].set(light['direction'] || [0, 0, 1]);
                    }
                    else if (light.type == 'spot') {
                        paramBlock['u_light' + i + 'Spot'] = { 'type': 'vec2' };
                        technique['u_light' + i + 'Position'].set(light['position'] || [0, 0, 0]);
                        var deg2Rad = Math.PI / 180;
                        technique['u_light' + i + 'Spot'].set([Math.cos((light['spotInnerCutoff'] || 45.0) * deg2Rad),
                                                        Math.cos((light['spotOuterCutoff'] || 90.0) * deg2Rad)]);
                        technique['u_light' + i + 'Atten'].set(light['attenuation'] || [1, 0, 0]);
                    } else {
                        technique['u_light' + i + 'Position'].set(light['position'] || [0, 0, 0]);
                        technique['u_light' + i + 'Atten'].set(light['attenuation'] || [1, 0, 0]);
                    }
                    technique['u_light' + i + 'Color'].set(light['diffuseColor'] || [1, 1, 1, 1]);
                    technique['u_light' + i + 'Specular'].set(light['specularColor'] || [1, 1, 1, 1]);
                }
            }
        }

        if (technique.u_uvMatrix)
            technique.u_uvMatrix.set(def.uvTransform || mat4.identity());

        renderer = g_Engine.getContext().renderer;
        if (technique.s_diffuseMap && typeof def.diffuseMap != 'undefined') {
            technique.s_diffuseMap.set(renderer.getTextureByName(def.diffuseMap.texture, def.diffuseMap.wrap, def.diffuseMap.mips));
        }
        if (technique.s_normalMap && typeof def.normalMap != 'undefined') {
            technique.s_normalMap.set(renderer.getTextureByName(def.normalMap.texture, def.normalMap.wrap, def.normalMap.mips));
        }
        if (technique.s_specMap && typeof def.specularMap != 'undefined') {
            technique.s_specMap.set(renderer.getTextureByName(def.specularMap.texture, def.specularMap.wrap));
        }
        if (technique.s_envMap && typeof def.environmentMap != 'undefined') {
            technique.s_envMap.set(renderer.getTextureByName(def.environmentMap.texture, def.environmentMap.wrap));
        }
        if (technique.u_envReflection) {
            technique.u_envReflection.set([def.environmentMap.envReflection || 1.0]);
        }
        return uberJShader;
    }