Fix T62178 Eevee: Texture Box mapping not matching Cycles if object is scaled
[blender.git] / source / blender / nodes / shader / nodes / node_shader_tex_image.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2005 Blender Foundation.
17  * All rights reserved.
18  */
19
20 #include "../node_shader_util.h"
21
22 /* **************** OUTPUT ******************** */
23
24 static bNodeSocketTemplate sh_node_tex_image_in[] = {
25         {       SOCK_VECTOR, 1, N_("Vector"),           0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
26         {       -1, 0, ""       },
27 };
28
29 static bNodeSocketTemplate sh_node_tex_image_out[] = {
30         {       SOCK_RGBA, 0, N_("Color"),              0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK},
31         {       SOCK_FLOAT, 0, N_("Alpha"),             0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK},
32         {       -1, 0, ""       },
33 };
34
35 static void node_shader_init_tex_image(bNodeTree *UNUSED(ntree), bNode *node)
36 {
37         NodeTexImage *tex = MEM_callocN(sizeof(NodeTexImage), "NodeTexImage");
38         BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
39         BKE_texture_colormapping_default(&tex->base.color_mapping);
40         tex->color_space = SHD_COLORSPACE_COLOR;
41         tex->iuser.frames = 1;
42         tex->iuser.sfra = 1;
43         tex->iuser.ok = 1;
44
45         node->storage = tex;
46 }
47
48 static int node_shader_gpu_tex_image(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
49 {
50         static const char *names[] = {
51             "node_tex_image_linear",
52             "node_tex_image_nearest",
53             "node_tex_image_cubic",
54             "node_tex_image_smart",
55         };
56         static const char *names_box[] = {
57             "tex_box_sample_linear",
58             "tex_box_sample_nearest",
59             "tex_box_sample_cubic",
60             "tex_box_sample_smart",
61         };
62         static const char *names_clip[] = {
63             "tex_clip_linear",
64             "tex_clip_nearest",
65             "tex_clip_cubic",
66             "tex_clip_smart",
67         };
68
69         Image *ima = (Image *)node->id;
70         NodeTexImage *tex = node->storage;
71
72         /* We get the image user from the original node, since GPU image keeps
73          * a pointer to it and the dependency refreshes the original. */
74         bNode *node_original = node->original ? node->original : node;
75         NodeTexImage *tex_original = node_original->storage;
76         ImageUser *iuser = &tex_original->iuser;
77
78         const char *gpu_node_name = (tex->projection == SHD_PROJ_BOX)
79                                      ? names_box[tex->interpolation]
80                                      : names[tex->interpolation];
81         bool do_color_correction = false;
82         bool do_texco_extend = (tex->extension != SHD_IMAGE_EXTENSION_REPEAT);
83         const bool do_texco_clip = (tex->extension == SHD_IMAGE_EXTENSION_CLIP);
84
85         if (do_texco_extend && (tex->projection != SHD_PROJ_BOX) &&
86             ELEM(tex->interpolation, SHD_INTERP_CUBIC, SHD_INTERP_SMART))
87         {
88                 gpu_node_name = "node_tex_image_cubic_extend";
89                 /* We do it inside the sampling function */
90                 do_texco_extend = false;
91         }
92
93         GPUNodeLink *norm, *col1, *col2, *col3, *input_coords;
94
95         int isdata = tex->color_space == SHD_COLORSPACE_NONE;
96         float blend = tex->projection_blend;
97
98         if (!ima)
99                 return GPU_stack_link(mat, node, "node_tex_image_empty", in, out);
100
101         ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
102         if ((tex->color_space == SHD_COLORSPACE_COLOR) &&
103             ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 &&
104             GPU_material_do_color_management(mat))
105         {
106                 do_color_correction = true;
107         }
108         BKE_image_release_ibuf(ima, ibuf, NULL);
109
110         if (!in[0].link)
111                 in[0].link = GPU_attribute(CD_MTFACE, "");
112
113         node_shader_gpu_tex_mapping(mat, node, in, out);
114
115         switch (tex->projection) {
116                 case SHD_PROJ_FLAT:
117                         if (do_texco_clip) {
118                                 GPU_link(mat, "set_rgb", in[0].link, &input_coords);
119                         }
120                         if (do_texco_extend) {
121                                 GPU_link(mat, "point_texco_clamp", in[0].link, GPU_image(ima, iuser, isdata), &in[0].link);
122                         }
123                         GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, isdata));
124                         break;
125                 case SHD_PROJ_BOX:
126                         GPU_link(mat, "mat3_mul", GPU_builtin(GPU_VIEW_NORMAL),
127                                                   GPU_builtin(GPU_INVERSE_NORMAL_MATRIX),
128                                                   &norm);
129                         GPU_link(mat, gpu_node_name, in[0].link,
130                                                      norm,
131                                                      GPU_image(ima, iuser, isdata),
132                                                      &col1,
133                                                      &col2,
134                                                      &col3);
135                         if (do_color_correction) {
136                                 GPU_link(mat, "srgb_to_linearrgb", col1, &col1);
137                                 GPU_link(mat, "srgb_to_linearrgb", col2, &col2);
138                                 GPU_link(mat, "srgb_to_linearrgb", col3, &col3);
139                         }
140                         GPU_link(mat, "node_tex_image_box", in[0].link,
141                                                             norm,
142                                                             col1, col2, col3,
143                                                             GPU_image(ima, iuser, isdata),
144                                                             GPU_uniform(&blend),
145                                                             &out[0].link,
146                                                             &out[1].link);
147                         break;
148                 case SHD_PROJ_SPHERE:
149                         GPU_link(mat, "point_texco_remap_square", in[0].link, &in[0].link);
150                         GPU_link(mat, "point_map_to_sphere", in[0].link, &in[0].link);
151                         if (do_texco_clip) {
152                                 GPU_link(mat, "set_rgb", in[0].link, &input_coords);
153                         }
154                         if (do_texco_extend) {
155                                 GPU_link(mat, "point_texco_clamp", in[0].link, GPU_image(ima, iuser, isdata), &in[0].link);
156                         }
157                         GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, isdata));
158                         break;
159                 case SHD_PROJ_TUBE:
160                         GPU_link(mat, "point_texco_remap_square", in[0].link, &in[0].link);
161                         GPU_link(mat, "point_map_to_tube", in[0].link, &in[0].link);
162                         if (do_texco_clip) {
163                                 GPU_link(mat, "set_rgb", in[0].link, &input_coords);
164                         }
165                         if (do_texco_extend) {
166                                 GPU_link(mat, "point_texco_clamp", in[0].link, GPU_image(ima, iuser, isdata), &in[0].link);
167                         }
168                         GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, isdata));
169                         break;
170         }
171
172         if (do_texco_clip && (tex->projection != SHD_PROJ_BOX)) {
173                 GPU_link(mat, names_clip[tex->interpolation],
174                          input_coords, GPU_image(ima, iuser, isdata), out[0].link,
175                          &out[0].link, &out[1].link);
176         }
177
178         if (do_color_correction && (tex->projection != SHD_PROJ_BOX)) {
179                 GPU_link(mat, "srgb_to_linearrgb", out[0].link, &out[0].link);
180         }
181
182         return true;
183 }
184
185 /* node type definition */
186 void register_node_type_sh_tex_image(void)
187 {
188         static bNodeType ntype;
189
190         sh_node_type_base(&ntype, SH_NODE_TEX_IMAGE, "Image Texture", NODE_CLASS_TEXTURE, 0);
191         node_type_socket_templates(&ntype, sh_node_tex_image_in, sh_node_tex_image_out);
192         node_type_init(&ntype, node_shader_init_tex_image);
193         node_type_storage(&ntype, "NodeTexImage", node_free_standard_storage, node_copy_standard_storage);
194         node_type_gpu(&ntype, node_shader_gpu_tex_image);
195         node_type_label(&ntype, node_image_label);
196         node_type_size_preset(&ntype, NODE_SIZE_LARGE);
197
198         nodeRegisterType(&ntype);
199 }