1////////////////////////////////////////////////
2//
3// model shaders
4//
5////////////////////////////////////////////////
6
7// skeletal animation with dual quaternions
8
9qtangentdecode = [
10    ? $arg1 [
11        vec4 qxyz = mquat.xxyy*mquat.yzyz, qxzw = vec4(mquat.xzw, -mquat.w);
12        vec3 mtangent = (qxzw.yzw*mquat.zzy + qxyz.zxy)*vec3(-2.0, 2.0, 2.0) + vec3(1.0, 0.0, 0.0);
13        vec3 mnormal = (qxzw.zwx*mquat.yxx + qxyz.ywz)*vec3(2.0, 2.0, -2.0) + vec3(0.0, 0.0, 1.0);
14        // vec3 mtangent = cross(mquat.xyz, vec3(mquat.wz, -mquat.y))*2.0 + vec3(1.0, 0.0, 0.0);
15        // vec3 mnormal = cross(mquat.xyz, vec3(mquat.y, -mquat.x, mquat.w))*2.0 + vec3(0.0, 0.0, 1.0);
16    ] [
17        vec3 mnormal = cross(mquat.xyz, vec3(mquat.y, -mquat.x, mquat.w))*2.0 + vec3(0.0, 0.0, 1.0);
18    ]
19]
20
21skelanimdefs = [
22    result [
23        attribute vec4 vboneweight, vboneindex;
24        #pragma CUBE2_uniform animdata
25        uniform vec4 animdata[@@(min $maxvsuniforms $maxskelanimdata)];
26    ]
27]
28
29skelanim = [
30    result [
31        int index = int(vboneindex.x);
32        @(if (= $arg1 1) [result [
33            vec4 dqreal = animdata[index];
34            vec4 dqdual = animdata[index+1];
35        ]] [result [
36            vec4 dqreal = animdata[index] * vboneweight.x;
37            vec4 dqdual = animdata[index+1] * vboneweight.x;
38            index = int(vboneindex.y);
39            dqreal += animdata[index] * vboneweight.y;
40            dqdual += animdata[index+1] * vboneweight.y;
41            @(if (>= $arg1 3) [result [
42                index = int(vboneindex.z);
43                dqreal += animdata[index] * vboneweight.z;
44                dqdual += animdata[index+1] * vboneweight.z;
45            ]])
46            @(if (>= $arg1 4) [result [
47                index = int(vboneindex.w);
48                dqreal += animdata[index] * vboneweight.w;
49                dqdual += animdata[index+1] * vboneweight.w;
50            ]])
51            float len = length(dqreal);
52            dqreal /= len;
53            dqdual /= len;
54        ]])
55
56        vec4 mpos = vec4((cross(dqreal.xyz, cross(dqreal.xyz, vvertex.xyz) + vvertex.xyz*dqreal.w + dqdual.xyz) + dqdual.xyz*dqreal.w - dqreal.xyz*dqdual.w)*2.0 + vvertex.xyz, vvertex.w);
57
58        @(if (>= $numargs 2) [result [
59            vec4 mquat = vec4(cross(dqreal.xyz, vtangent.xyz) + dqreal.xyz*vtangent.w + vtangent.xyz*dqreal.w, dqreal.w*vtangent.w - dot(dqreal.xyz, vtangent.xyz));
60            @(qtangentdecode $arg2)
61        ]])
62    ]
63]
64
65// mdltype:
66//    a -> alpha test
67//    b -> dual-quat skeletal animation
68
69mdlopt = [ >= (strstr $modeltype $arg1) 0 ]
70
71shadowmodelvertexshader = [
72    local modeltype
73    modeltype = $arg1
74    result [
75        attribute vec4 vvertex;
76        @(if (mdlopt "b") [skelanimdefs $arg2])
77        uniform mat4 modelmatrix;
78        @(? (mdlopt "a") [
79            attribute vec2 vtexcoord0;
80            uniform vec2 texscroll;
81            varying vec2 texcoord0;
82        ])
83        void main(void)
84        {
85            @(if (mdlopt "b") [
86                skelanim $arg2
87            ] [result [
88                #define mpos vvertex
89            ]])
90
91            gl_Position = modelmatrix * mpos;
92
93            @(? (mdlopt "a") [
94                texcoord0 = vtexcoord0 + texscroll;
95            ])
96        }
97    ]
98]
99
100shadowmodelfragmentshader = [
101    local modeltype
102    modeltype = $arg1
103    result [
104        @(? (mdlopt "a") [
105            uniform sampler2D tex0;
106            uniform float alphatest;
107            varying vec2 texcoord0;
108        ])
109        void main(void)
110        {
111            @(? (mdlopt "a") [
112                vec4 color = texture2D(tex0, texcoord0);
113                if(color.a <= alphatest)
114                    discard;
115            ])
116        }
117    ]
118]
119
120shadowmodelshader = [
121    defershader 0 $arg1 [
122        shader 0 @arg1 (shadowmodelvertexshader @arg2) (shadowmodelfragmentshader @arg2)
123        loop+ i 1 4 [
124            variantshader 0 @@arg1 0 (shadowmodelvertexshader @@(concatword $arg2 "b") $i) []
125        ]
126    ]
127]
128
129shadowmodelshader "shadowmodel" ""
130shadowmodelshader "alphashadowmodel" "a"
131
132// mdltype:
133//    a -> alpha test
134//    e -> envmap
135//    n -> normalmap
136//    m -> masks
137//    d -> decal
138//    D -> alpha decal
139//    b -> dual-quat skeletal animation
140//    c -> disable cullface
141//    t -> transparent
142
143modelvertexshader = [
144    local modeltype
145    modeltype = $arg1
146    result [
147        attribute vec4 vvertex, vtangent;
148        attribute vec2 vtexcoord0;
149        @(if (mdlopt "b") [skelanimdefs $arg2 (mdlopt "n")])
150        uniform mat4 modelmatrix;
151        uniform mat3 modelworld;
152        uniform vec3 modelcamera;
153        uniform vec2 texscroll;
154        @(? (mdlopt "n") [
155            varying mat3 world;
156        ] [
157            varying vec3 nvec;
158        ])
159        @(? (mdlopt "e") [
160            varying vec3 camvec;
161        ])
162        @(msaainterpvert)
163        varying vec2 texcoord0;
164
165        void main(void)
166        {
167            @(if (mdlopt "b") [
168                skelanim $arg2 (mdlopt "n")
169            ] [result [
170                #define mpos vvertex
171                #define mquat vtangent
172                @(qtangentdecode (mdlopt "n"))
173            ]])
174
175            gl_Position = modelmatrix * mpos;
176
177            texcoord0 = vtexcoord0 + texscroll;
178
179            @(msaapackvert)
180
181            @(? (mdlopt "e") [
182                camvec = modelworld * normalize(modelcamera - mpos.xyz);
183            ])
184
185            @(? (mdlopt "n") [
186                // composition of tangent -> object and object -> world transforms
187                //   becomes tangent -> world
188                vec3 wnormal = modelworld * mnormal;
189                vec3 wtangent = modelworld * mtangent;
190                vec3 wbitangent = cross(wnormal, wtangent) * (vtangent.w < 0.0 ? -1.0 : 1.0);
191                world = mat3(wtangent, wbitangent, wnormal);
192            ] [
193                nvec = modelworld * mnormal;
194            ])
195        }
196    ]
197]
198
199modelfragmentshader = [
200    local modeltype
201    modeltype = $arg1
202    result [
203        @(? (mdlopt "n") [
204            varying mat3 world;
205        ] [
206            varying vec3 nvec;
207        ])
208        @(? (mdlopt "e") [
209            uniform vec2 envmapscale;
210            varying vec3 camvec;
211        ])
212        uniform vec4 colorscale;
213        uniform vec2 fullbright;
214        uniform vec2 maskscale;
215        @(? (mdlopt "a") [uniform float alphatest;])
216        uniform sampler2D tex0;
217        @(? (mdlopt "m") [uniform sampler2D tex1;])
218        @(? (mdlopt "e") [uniform samplerCube tex2;])
219        @(? (mdlopt "n") [uniform sampler2D tex3;])
220        @(? (|| (mdlopt "d") [mdlopt "D"]) [uniform sampler2D tex4;])
221        @(msaainterpfrag)
222        varying vec2 texcoord0;
223        uniform float aamask;
224
225        void main(void)
226        {
227            vec4 diffuse = texture2D(tex0, texcoord0);
228
229            @(? (mdlopt "a") [
230                if(diffuse.a <= alphatest)
231                    discard;
232            ])
233
234            gcolor.rgb = diffuse.rgb*colorscale.rgb;
235
236            @(? (|| (mdlopt "d") [mdlopt "D"]) [
237                vec4 decal = texture2D(tex4, texcoord0);
238                @(? (mdlopt "D") [
239                    gcolor.rgb = mix(gcolor.rgb, decal.rgb, decal.a);
240                ] [
241                    gcolor.rgb += decal.rgb;
242                ])
243            ])
244
245            @(if (mdlopt "n") [result [
246                vec3 normal = texture2D(tex3, texcoord0).rgb - 0.5;
247                @(? (mdlopt "c") [
248                    if(!gl_FrontFacing) normal.z = -normal.z;
249                ])
250                normal = normalize(world * normal);
251            ]] [result [
252                vec3 normal = normalize(nvec);
253                @(? (mdlopt "c") [
254                    if(!gl_FrontFacing) normal = -normal;
255                ])
256            ]])
257
258            float spec = maskscale.x;
259            @(if (mdlopt "m") [result [
260                vec3 masks = texture2D(tex1, texcoord0).rgb;
261                spec *= masks.r; // specmap in red channel
262
263                @(? (mdlopt "e") [
264                    vec3 camn = normalize(camvec);
265                    float invfresnel = dot(camn, normal);
266                    vec3 rvec = 2.0*invfresnel*normal - camn;
267                    float rmod = envmapscale.x*clamp(invfresnel, 0.0, 1.0) + envmapscale.y;
268                    vec3 reflect = textureCube(tex2, rvec).rgb;
269                    gcolor.rgb = mix(gcolor.rgb, reflect, rmod*masks.b); // envmap mask in blue channel
270                ])
271            ]])
272            gcolor.a = 0.5*spec;
273
274            @(? (mdlopt "m") [
275                float glowk = max(maskscale.y*masks.g, fullbright.y), colork = max(fullbright.x-glowk, 0.0); // glow mask in green channel
276            ] [
277                float glowk = fullbright.y, colork = fullbright.x-fullbright.y;
278            ])
279
280            @(if (mdlopt "t") [result [
281                gglow.rgb = gcolor.rgb*glowk;
282                gcolor.rgb *= colork;
283                #define packnorm colorscale.a
284            ]] [gglowpack "" packnorm])
285
286            @(gnormpackdef normal packnorm)
287
288            @(msaapackfrag aamask)
289        }
290    ]
291]
292
293modelshader = [
294    shadername = (concatword "model" $arg1)
295    maxvariants = 9
296    shader 0 $shadername (modelvertexshader $arg1) (modelfragmentshader $arg1)
297    loop+ i 1 4 [
298        variantshader 0 $shadername 0 (modelvertexshader (concatword $arg1 "b") $i) [] $maxvariants
299    ]
300    variantshader 0 $shadername 1 [] (modelfragmentshader (concatword $arg1 "t")) $maxvariants
301    loop i 4 [
302        variantshader 0 $shadername 1 [0 , @i] 1 $maxvariants
303    ]
304]
305
306rsmmodelvertexshader = [
307    local modeltype
308    modeltype = $arg1
309    result [
310        attribute vec4 vvertex, vtangent;
311        attribute vec2 vtexcoord0;
312        @(if (mdlopt "b") [skelanimdefs $arg2 (mdlopt "n")])
313        uniform mat4 modelmatrix;
314        uniform mat3 modelworld;
315        uniform vec2 texscroll;
316        varying vec2 texcoord0;
317        varying vec3 nvec;
318        void main(void)
319        {
320            @(if (mdlopt "b") [
321                skelanim $arg2 (mdlopt "n")
322            ] [result [
323                #define mpos vvertex
324                #define mquat vtangent
325                @(qtangentdecode (mdlopt "n"))
326            ]])
327
328            gl_Position = modelmatrix * mpos;
329
330            texcoord0 = vtexcoord0 + texscroll;
331
332            nvec = modelworld * mnormal;
333        }
334    ]
335]
336
337rsmmodelfragmentshader = [
338    local modeltype
339    modeltype = $arg1
340    result [
341        varying vec2 texcoord0;
342        varying vec3 nvec;
343        uniform vec4 colorscale;
344        @(? (mdlopt "a") [uniform float alphatest;])
345        uniform vec3 rsmdir;
346        uniform sampler2D tex0;
347        fragdata(0, gcolor, vec4)
348        fragdata(1, gnormal, vec4)
349        void main(void)
350        {
351            vec4 diffuse = texture2D(tex0, texcoord0);
352            @(? (mdlopt "a") [
353                if(diffuse.a <= alphatest)
354                    discard;
355            ])
356            vec3 normal = normalize(nvec);
357            @(? (mdlopt "c") [
358                if(!gl_FrontFacing) normal = -normal;
359            ])
360            gcolor = vec4(dot(normal, rsmdir)*diffuse.rgb*colorscale.rgb, 1.0);
361            gnormal = vec4(normal*0.5+0.5, 0.0);
362        }
363    ]
364]
365
366rsmmodelshader = [
367    shadername = (concatword "rsmmodel" $arg1)
368    shader 0 $shadername (rsmmodelvertexshader $arg1) (rsmmodelfragmentshader $arg1)
369    loop+ i 1 4 [
370        variantshader 0 $shadername 0 (rsmmodelvertexshader (concatword $arg1 "b") $i) []
371    ]
372]
373
374