Cycles: constant folding for RGB/Vector Curves and Color Ramp.
[blender.git] / intern / cycles / kernel / shaders / node_image_texture.osl
1 /*
2  * Copyright 2011-2013 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "stdosl.h"
18 #include "node_color.h"
19
20 point texco_remap_square(point co)
21 {
22         return (co - point(0.5, 0.5, 0.5)) * 2.0;
23 }
24
25 point map_to_tube(vector dir)
26 {
27         float u, v;
28         v = (dir[2] + 1.0) * 0.5;
29         float len = sqrt(dir[0] * dir[0] + dir[1] * dir[1]);
30         if (len > 0.0) {
31                 u = (1.0 - (atan2(dir[0] / len, dir[1] / len) / M_PI)) * 0.5;
32         }
33         else {
34                 v = u = 0.0; /* To avoid un-initialized variables. */
35         }
36         return point(u, v, 0.0);
37 }
38
39 point map_to_sphere(vector dir)
40 {
41         float len = length(dir);
42         float v, u;
43         if (len > 0.0) {
44                 if (dir[0] == 0.0 && dir[1] == 0.0) {
45                         u = 0.0;  /* Othwise domain error. */
46                 }
47                 else {
48                         u = (1.0 - atan2(dir[0], dir[1]) / M_PI) / 2.0;
49                 }
50                 v = 1.0 - acos(dir[2] / len) / M_PI;
51         }
52         else {
53                 v = u = 0.0;  /* To avoid un-initialized variables. */
54         }
55         return point(u, v, 0.0);
56 }
57
58 color image_texture_lookup(string filename,
59                            string color_space,
60                            float u, float v,
61                            output float Alpha,
62                            int use_alpha,
63                            int is_float,
64                            string interpolation,
65                            string extension)
66 {
67         color rgb = (color)texture(filename, u, 1.0 - v, "wrap", extension, "interp", interpolation, "alpha", Alpha);
68
69         if (use_alpha) {
70                 rgb = color_unpremultiply(rgb, Alpha);
71         
72                 if (!is_float)
73                         rgb = min(rgb, 1.0);
74         }
75
76         if (color_space == "sRGB") {
77                 rgb = color_srgb_to_scene_linear(rgb);
78         }
79
80         return rgb;
81 }
82
83 shader node_image_texture(
84         int use_mapping = 0,
85         matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
86         point Vector = P,
87         string filename = "",
88         string color_space = "sRGB",
89         string projection = "flat",
90         string interpolation = "smartcubic",
91         string extension = "periodic",
92         float projection_blend = 0.0,
93         int is_float = 1,
94         int use_alpha = 1,
95         output color Color = 0.0,
96         output float Alpha = 1.0)
97 {
98         point p = Vector;
99
100         if (use_mapping)
101                 p = transform(mapping, p);
102         
103         if (projection == "flat") {
104                 Color = image_texture_lookup(filename,
105                                              color_space,
106                                              p[0], p[1],
107                                              Alpha,
108                                              use_alpha,
109                                              is_float,
110                                              interpolation,
111                                              extension);
112         }
113         else if (projection == "box") {
114                 /* object space normal */
115                 vector Nob = transform("world", "object", N);
116
117                 /* project from direction vector to barycentric coordinates in triangles */
118                 Nob = vector(fabs(Nob[0]), fabs(Nob[1]), fabs(Nob[2]));
119                 Nob /= (Nob[0] + Nob[1] + Nob[2]);
120
121                 /* basic idea is to think of this as a triangle, each corner representing
122                  * one of the 3 faces of the cube. in the corners we have single textures,
123                  * in between we blend between two textures, and in the middle we a blend
124                  * between three textures.
125                  *
126                  * the Nxyz values are the barycentric coordinates in an equilateral
127                  * triangle, which in case of blending, in the middle has a smaller
128                  * equilateral triangle where 3 textures blend. this divides things into
129                  * 7 zones, with an if () test for each zone */
130
131                 vector weight = vector(0.0, 0.0, 0.0);
132                 float blend = projection_blend;
133                 float limit = 0.5 * (1.0 + blend);
134
135                 /* first test for corners with single texture */
136                 if (Nob[0] > limit * (Nob[0] + Nob[1]) && Nob[0] > limit * (Nob[0] + Nob[2])) {
137                         weight[0] = 1.0;
138                 }
139                 else if (Nob[1] > limit * (Nob[0] + Nob[1]) && Nob[1] > limit * (Nob[1] + Nob[2])) {
140                         weight[1] = 1.0;
141                 }
142                 else if (Nob[2] > limit * (Nob[0] + Nob[2]) && Nob[2] > limit * (Nob[1] + Nob[2])) {
143                         weight[2] = 1.0;
144                 }
145                 else if (blend > 0.0) {
146                         /* in case of blending, test for mixes between two textures */
147                         if (Nob[2] < (1.0 - limit) * (Nob[1] + Nob[0])) {
148                                 weight[0] = Nob[0] / (Nob[0] + Nob[1]);
149                                 weight[0] = clamp((weight[0] - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
150                                 weight[1] = 1.0 - weight[0];
151                         }
152                         else if (Nob[0] < (1.0 - limit) * (Nob[1] + Nob[2])) {
153                                 weight[1] = Nob[1] / (Nob[1] + Nob[2]);
154                                 weight[1] = clamp((weight[1] - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
155                                 weight[2] = 1.0 - weight[1];
156                         }
157                         else if (Nob[1] < (1.0 - limit) * (Nob[0] + Nob[2])) {
158                                 weight[0] = Nob[0] / (Nob[0] + Nob[2]);
159                                 weight[0] = clamp((weight[0] - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
160                                 weight[2] = 1.0 - weight[0];
161                         }
162                         else {
163                                 /* last case, we have a mix between three */
164                                 weight[0] = ((2.0 - limit) * Nob[0] + (limit - 1.0)) / (2.0 * limit - 1.0);
165                                 weight[1] = ((2.0 - limit) * Nob[1] + (limit - 1.0)) / (2.0 * limit - 1.0);
166                                 weight[2] = ((2.0 - limit) * Nob[2] + (limit - 1.0)) / (2.0 * limit - 1.0);
167                         }
168                 }
169                 else {
170                         /* Desperate mode, no valid choice anyway, fallback to one side.*/
171                         weight[0] = 1.0;
172                 }
173
174                 Color = color(0.0, 0.0, 0.0);
175                 Alpha = 0.0;
176
177                 float tmp_alpha;
178
179                 if (weight[0] > 0.0) {
180                         Color += weight[0] * image_texture_lookup(filename,
181                                                                   color_space,
182                                                                   p[1], p[2],
183                                                                   tmp_alpha,
184                                                                   use_alpha,
185                                                                   is_float,
186                                                                   interpolation,
187                                                                   extension);
188                         Alpha += weight[0] * tmp_alpha;
189                 }
190                 if (weight[1] > 0.0) {
191                         Color += weight[1] * image_texture_lookup(filename,
192                                                                   color_space,
193                                                                   p[0], p[2],
194                                                                   tmp_alpha,
195                                                                   use_alpha,
196                                                                   is_float,
197                                                                   interpolation,
198                                                                   extension);
199                         Alpha += weight[1] * tmp_alpha;
200                 }
201                 if (weight[2] > 0.0) {
202                         Color += weight[2] * image_texture_lookup(filename,
203                                                                   color_space,
204                                                                   p[1], p[0],
205                                                                   tmp_alpha,
206                                                                   use_alpha,
207                                                                   is_float,
208                                                                   interpolation,
209                                                                   extension);
210                         Alpha += weight[2] * tmp_alpha;
211                 }
212         }
213         else if (projection == "sphere") {
214                 point projected = map_to_sphere(texco_remap_square(p));
215                 Color = image_texture_lookup(filename,
216                                              color_space,
217                                              projected[0], projected[1],
218                                              Alpha,
219                                              use_alpha,
220                                              is_float,
221                                              interpolation,
222                                              extension);
223         }
224         else if (projection == "tube") {
225                 point projected = map_to_tube(texco_remap_square(p));
226                 Color = image_texture_lookup(filename,
227                                              color_space,
228                                              projected[0], projected[1],
229                                              Alpha,
230                                              use_alpha,
231                                              is_float,
232                                              interpolation,
233                                              extension);
234         }
235 }