Add support for multiple interpolation modes on cycles image textures
authorMartijn Berger <martijn.berger@gmail.com>
Fri, 7 Mar 2014 22:16:09 +0000 (23:16 +0100)
committerMartijn Berger <martijn.berger@gmail.com>
Fri, 7 Mar 2014 22:16:33 +0000 (23:16 +0100)
All textures are sampled bi-linear currently with the exception of OSL there texture sampling is fixed and set to smart bi-cubic.

This patch adds user control to this setting.

Added:
- bits to DNA / RNA in the form of an enum for supporting multiple interpolations types
- changes to the image texture node drawing code ( add enum)
- to ImageManager (this needs to know to allocate second texture when interpolation type is different)
- to node compiler (pass on interpolation type)
- to device tex_alloc this also needs to get the concept of multiple interpolation types
- implementation for doing non interpolated lookup for cuda and cpu
- implementation where we pass this along to osl ( this makes OSL also do linear untill I add smartcubic to the interface / DNA/ RNA)

Reviewers: brecht, dingto

Reviewed By: brecht

CC: dingto, venomgfx
Differential Revision: https://developer.blender.org/D317

20 files changed:
intern/cycles/blender/blender_shader.cpp
intern/cycles/device/device.h
intern/cycles/device/device_cpu.cpp
intern/cycles/device/device_cuda.cpp
intern/cycles/device/device_multi.cpp
intern/cycles/device/device_network.cpp
intern/cycles/device/device_opencl.cpp
intern/cycles/kernel/kernel.cpp
intern/cycles/kernel/kernel.h
intern/cycles/kernel/kernel_compat_cpu.h
intern/cycles/kernel/shaders/node_image_texture.osl
intern/cycles/kernel/svm/svm_image.h
intern/cycles/render/image.cpp
intern/cycles/render/image.h
intern/cycles/render/nodes.cpp
intern/cycles/render/nodes.h
intern/cycles/util/util_types.h
source/blender/editors/space_node/drawnode.c
source/blender/makesdna/DNA_node_types.h
source/blender/makesrna/intern/rna_nodetree.c

index 6175c8ea3993da29f177f52922c52ad516614ea3..1559a96a3d3392120964c7a7ba75f2b202524665 100644 (file)
@@ -549,6 +549,7 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
                }
                image->color_space = ImageTextureNode::color_space_enum[(int)b_image_node.color_space()];
                image->projection = ImageTextureNode::projection_enum[(int)b_image_node.projection()];
+               image->interpolation = (InterpolationType)b_image_node.interpolation();
                image->projection_blend = b_image_node.projection_blend();
                get_tex_mapping(&image->tex_mapping, b_image_node.texture_mapping());
                node = image;
index bd309e357881573812220aacc42922ffd755d3c1..f94075f9aa5ffdb058cc751263d8291ef9a8acf8 100644 (file)
@@ -100,7 +100,7 @@ public:
 
        /* texture memory */
        virtual void tex_alloc(const char *name, device_memory& mem,
-               bool interpolation = false, bool periodic = false) {};
+               InterpolationType interpolation = INTERPOLATION_NONE, bool periodic = false) {};
        virtual void tex_free(device_memory& mem) {};
 
        /* pixel memory */
index 76123fe44d287b7bbbe8b1db151ef1e3b2c25922..de44feb2debb70df4e90d4c135cca28e4123f350 100644 (file)
@@ -103,9 +103,9 @@ public:
                kernel_const_copy(&kernel_globals, name, host, size);
        }
 
-       void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic)
+       void tex_alloc(const char *name, device_memory& mem, InterpolationType interpolation, bool periodic)
        {
-               kernel_tex_copy(&kernel_globals, name, mem.data_pointer, mem.data_width, mem.data_height);
+               kernel_tex_copy(&kernel_globals, name, mem.data_pointer, mem.data_width, mem.data_height, interpolation);
                mem.device_pointer = mem.data_pointer;
 
                stats.mem_alloc(mem.memory_size());
index 932fdc303a5210c87a9dba0bb77cf44bf6f4ca9f..5133a5c9feac8ba90a39830ef771b6bbc36fa764 100644 (file)
@@ -451,7 +451,7 @@ public:
                cuda_pop_context();
        }
 
-       void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic)
+       void tex_alloc(const char *name, device_memory& mem, InterpolationType interpolation, bool periodic)
        {
                /* determine format */
                CUarray_format_enum format;
@@ -479,7 +479,7 @@ public:
                                return;
                        }
 
-                       if(interpolation) {
+                       if(interpolation != INTERPOLATION_NONE) {
                                CUarray handle = NULL;
                                CUDA_ARRAY_DESCRIPTOR desc;
 
@@ -513,7 +513,15 @@ public:
 
                                cuda_assert(cuTexRefSetArray(texref, handle, CU_TRSA_OVERRIDE_FORMAT))
 
-                               cuda_assert(cuTexRefSetFilterMode(texref, CU_TR_FILTER_MODE_LINEAR))
+                               if(interpolation == INTERPOLATION_CLOSEST) {
+                                       cuda_assert(cuTexRefSetFilterMode(texref, CU_TR_FILTER_MODE_POINT))
+                               }
+                               else if (interpolation == INTERPOLATION_LINEAR){
+                                       cuda_assert(cuTexRefSetFilterMode(texref, CU_TR_FILTER_MODE_LINEAR))
+                               }
+                               else {/* CUBIC and SMART are unsupported for CUDA */
+                                       cuda_assert(cuTexRefSetFilterMode(texref, CU_TR_FILTER_MODE_LINEAR))
+                               }
                                cuda_assert(cuTexRefSetFlags(texref, CU_TRSF_NORMALIZED_COORDINATES))
 
                                mem.device_pointer = (device_ptr)handle;
@@ -570,7 +578,7 @@ public:
                        cuda_pop_context();
                }
 
-               tex_interp_map[mem.device_pointer] = interpolation;
+               tex_interp_map[mem.device_pointer] = (interpolation != INTERPOLATION_NONE);
        }
 
        void tex_free(device_memory& mem)
index 27b9de0769e5c15bc0d0f0f6e7dfcf92a8841dc4..1e9367c845a52af84d4162093462b23614a98cfc 100644 (file)
@@ -168,7 +168,7 @@ public:
                        sub.device->const_copy_to(name, host, size);
        }
 
-       void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic)
+       void tex_alloc(const char *name, device_memory& mem, InterpolationType interpolation, bool periodic)
        {
                foreach(SubDevice& sub, devices) {
                        mem.device_pointer = 0;
index bffd993818fe0728bface42d0cfa11fbac72b779..8f00324c3e17eab19275acd3cd0d24948ce44627 100644 (file)
@@ -162,7 +162,7 @@ public:
                snd.write_buffer(host, size);
        }
 
-       void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic)
+       void tex_alloc(const char *name, device_memory& mem, InterpolationType interpolation, bool periodic)
        {
                thread_scoped_lock lock(rpc_lock);
 
@@ -559,7 +559,7 @@ protected:
                else if(rcv.name == "tex_alloc") {
                        network_device_memory mem;
                        string name;
-                       bool interpolation;
+                       InterpolationType interpolation;
                        bool periodic;
                        device_ptr client_pointer;
 
index 9117b70d7492ad60c9cdbf54424f361499b9c12f..33170e1230dbe5d6954accfc042ab1458ebeac3a 100644 (file)
@@ -881,7 +881,7 @@ public:
                mem_copy_to(*i->second);
        }
 
-       void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic)
+       void tex_alloc(const char *name, device_memory& mem, InterpolationType interpolation, bool periodic)
        {
                mem_alloc(mem, MEM_READ_ONLY);
                mem_copy_to(mem);
index 6cd14d3c51c2075f9f77301ae8517783f7cd3619..5d74feed9f4e668183bbcf1262c954edde612990 100644 (file)
@@ -37,7 +37,7 @@ void kernel_const_copy(KernelGlobals *kg, const char *name, void *host, size_t s
                assert(0);
 }
 
-void kernel_tex_copy(KernelGlobals *kg, const char *name, device_ptr mem, size_t width, size_t height)
+void kernel_tex_copy(KernelGlobals *kg, const char *name, device_ptr mem, size_t width, size_t height, InterpolationType interpolation)
 {
        if(0) {
        }
@@ -63,6 +63,7 @@ void kernel_tex_copy(KernelGlobals *kg, const char *name, device_ptr mem, size_t
                        tex->data = (float4*)mem;
                        tex->width = width;
                        tex->height = height;
+                       tex->interpolation = interpolation;
                }
        }
        else if(strstr(name, "__tex_image")) {
@@ -78,6 +79,7 @@ void kernel_tex_copy(KernelGlobals *kg, const char *name, device_ptr mem, size_t
                        tex->data = (uchar4*)mem;
                        tex->width = width;
                        tex->height = height;
+                       tex->interpolation = interpolation;
                }
        }
        else
index 039dc791b08071737ed210892da40b64a075192b..a4f13e780064a090a2d4000b84cb81b171e1ccef 100644 (file)
@@ -32,7 +32,7 @@ void *kernel_osl_memory(KernelGlobals *kg);
 bool kernel_osl_use(KernelGlobals *kg);
 
 void kernel_const_copy(KernelGlobals *kg, const char *name, void *host, size_t size);
-void kernel_tex_copy(KernelGlobals *kg, const char *name, device_ptr mem, size_t width, size_t height);
+void kernel_tex_copy(KernelGlobals *kg, const char *name, device_ptr mem, size_t width, size_t height, InterpolationType interpolation=INTERPOLATION_LINEAR);
 
 void kernel_cpu_path_trace(KernelGlobals *kg, float *buffer, unsigned int *rng_state,
        int sample, int x, int y, int offset, int stride);
index a9c66ec2d68dfc75a178693185ce4da166193d1e..55f4484ba1f94d815af260b3a6c5e75a61dab9c0 100644 (file)
@@ -117,14 +117,19 @@ template<typename T> struct texture_image  {
                        niy = wrap_clamp(iy+1, height);
                }
 
-               float4 r = (1.0f - ty)*(1.0f - tx)*read(data[ix + iy*width]);
-               r += (1.0f - ty)*tx*read(data[nix + iy*width]);
-               r += ty*(1.0f - tx)*read(data[ix + niy*width]);
-               r += ty*tx*read(data[nix + niy*width]);
-
-               return r;
+               if(interpolation == INTERPOLATION_CLOSEST) {
+                       return read(data[ix + iy*width]);
+               }
+               else {
+                       float4 r = (1.0f - ty)*(1.0f - tx)*read(data[ix + iy*width]);
+                       r += (1.0f - ty)*tx*read(data[nix + iy*width]);
+                       r += ty*(1.0f - tx)*read(data[ix + niy*width]);
+                       r += ty*tx*read(data[nix + niy*width]);
+                       return r;
+               }
        }
 
+       int interpolation;
        T *data;
        int width, height;
 };
@@ -146,7 +151,6 @@ typedef texture_image<uchar4> texture_image_uchar4;
 #define kernel_tex_fetch_m128i(tex, index) (kg->tex.fetch_m128i(index))
 #define kernel_tex_lookup(tex, t, offset, size) (kg->tex.lookup(t, offset, size))
 #define kernel_tex_image_interp(tex, x, y) ((tex < MAX_FLOAT_IMAGES) ? kg->texture_float_images[tex].interp(x, y) : kg->texture_byte_images[tex - MAX_FLOAT_IMAGES].interp(x, y))
-
 #define kernel_data (kg->__data)
 
 CCL_NAMESPACE_END
index caa755636b93f2ce362018241aed98991d8a3b15..7238a1e88628743d67a2bca823f5443bce4a0e6a 100644 (file)
@@ -17,9 +17,9 @@
 #include "stdosl.h"
 #include "node_color.h"
 
-color image_texture_lookup(string filename, string color_space, float u, float v, output float Alpha, int use_alpha, int is_float)
+color image_texture_lookup(string filename, string color_space, float u, float v, output float Alpha, int use_alpha, int is_float, string interpolation)
 {
-       color rgb = (color)texture(filename, u, 1.0 - v, "wrap", "periodic", "alpha", Alpha);
+       color rgb = (color)texture(filename, u, 1.0 - v, "wrap", "periodic", "interp", interpolation, "alpha", Alpha);
 
        if (use_alpha) {
                rgb = color_unpremultiply(rgb, Alpha);
@@ -42,6 +42,7 @@ shader node_image_texture(
        string filename = "",
        string color_space = "sRGB",
        string projection = "Flat",
+       string interpolation = "smartcubic",
        float projection_blend = 0.0,
        int is_float = 1,
        int use_alpha = 1,
@@ -54,7 +55,7 @@ shader node_image_texture(
                p = transform(mapping, p);
        
        if (projection == "Flat") {
-               Color = image_texture_lookup(filename, color_space, p[0], p[1], Alpha, use_alpha, is_float);
+               Color = image_texture_lookup(filename, color_space, p[0], p[1], Alpha, use_alpha, is_float, interpolation);
        }
        else if (projection == "Box") {
                /* object space normal */
@@ -119,15 +120,15 @@ shader node_image_texture(
                float tmp_alpha;
 
                if (weight[0] > 0.0) {
-                       Color += weight[0] * image_texture_lookup(filename, color_space, p[1], p[2], tmp_alpha, use_alpha, is_float);
+                       Color += weight[0] * image_texture_lookup(filename, color_space, p[1], p[2], tmp_alpha, use_alpha, is_float, interpolation);
                        Alpha += weight[0] * tmp_alpha;
                }
                if (weight[1] > 0.0) {
-                       Color += weight[1] * image_texture_lookup(filename, color_space, p[0], p[2], tmp_alpha, use_alpha, is_float);
+                       Color += weight[1] * image_texture_lookup(filename, color_space, p[0], p[2], tmp_alpha, use_alpha, is_float, interpolation);
                        Alpha += weight[1] * tmp_alpha;
                }
                if (weight[2] > 0.0) {
-                       Color += weight[2] * image_texture_lookup(filename, color_space, p[1], p[0], tmp_alpha, use_alpha, is_float);
+                       Color += weight[2] * image_texture_lookup(filename, color_space, p[1], p[0], tmp_alpha, use_alpha, is_float, interpolation);
                        Alpha += weight[2] * tmp_alpha;
                }
        }
index bc76ea1e6622f52afc15fbe074f9f365f50bd600..750af97150ec56d3856bbfed3693ab03cb27d6a9 100644 (file)
@@ -60,7 +60,8 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y,
        uint width = info.x;
        uint height = info.y;
        uint offset = info.z;
-       uint periodic = info.w;
+       uint periodic = (info.w & 0x1);
+       uint interpolation = info.w >> 1;
 
        int ix, iy, nix, niy;
        float tx = svm_image_texture_frac(x*width, &ix);
@@ -81,10 +82,16 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y,
                niy = svm_image_texture_wrap_clamp(iy+1, height);
        }
 
-       float4 r = (1.0f - ty)*(1.0f - tx)*svm_image_texture_read(kg, offset + ix + iy*width);
-       r += (1.0f - ty)*tx*svm_image_texture_read(kg, offset + nix + iy*width);
-       r += ty*(1.0f - tx)*svm_image_texture_read(kg, offset + ix + niy*width);
-       r += ty*tx*svm_image_texture_read(kg, offset + nix + niy*width);
+       float4 r;
+       if (interpolation == INTERPOLATION_CLOSEST){
+               r = svm_image_texture_read(kg, offset + ix + iy*width);
+       }
+       else { /* We default to linear interpolation if it is not closest */
+               r = (1.0f - ty)*(1.0f - tx)*svm_image_texture_read(kg, offset + ix + iy*width);
+               r += (1.0f - ty)*tx*svm_image_texture_read(kg, offset + nix + iy*width);
+               r += ty*(1.0f - tx)*svm_image_texture_read(kg, offset + ix + niy*width);
+               r += ty*tx*svm_image_texture_read(kg, offset + nix + niy*width);
+       }
 
        if(use_alpha && r.w != 1.0f && r.w != 0.0f) {
                float invw = 1.0f/r.w;
index 91aae6f3ec3ad20ae7654392c2a3e19547c8259e..b2559c8c824922305e57d03ae06b9a44c6801d8d 100644 (file)
@@ -145,7 +145,7 @@ bool ImageManager::is_float_image(const string& filename, void *builtin_data, bo
        return is_float;
 }
 
-int ImageManager::add_image(const string& filename, void *builtin_data, bool animated, bool& is_float, bool& is_linear)
+int ImageManager::add_image(const string& filename, void *builtin_data, bool animated, bool& is_float, bool& is_linear, InterpolationType interpolation)
 {
        Image *img;
        size_t slot;
@@ -156,7 +156,7 @@ int ImageManager::add_image(const string& filename, void *builtin_data, bool ani
        if(is_float) {
                /* find existing image */
                for(slot = 0; slot < float_images.size(); slot++) {
-                       if(float_images[slot] && float_images[slot]->filename == filename) {
+                       if(float_images[slot] && float_images[slot]->filename == filename && float_images[slot]->interpolation == interpolation) {
                                float_images[slot]->users++;
                                return slot;
                        }
@@ -185,13 +185,14 @@ int ImageManager::add_image(const string& filename, void *builtin_data, bool ani
                img->builtin_data = builtin_data;
                img->need_load = true;
                img->animated = animated;
+               img->interpolation = interpolation;
                img->users = 1;
 
                float_images[slot] = img;
        }
        else {
                for(slot = 0; slot < images.size(); slot++) {
-                       if(images[slot] && images[slot]->filename == filename) {
+                       if(images[slot] && images[slot]->filename == filename && images[slot]->interpolation == interpolation) {
                                images[slot]->users++;
                                return slot+tex_image_byte_start;
                        }
@@ -220,6 +221,7 @@ int ImageManager::add_image(const string& filename, void *builtin_data, bool ani
                img->builtin_data = builtin_data;
                img->need_load = true;
                img->animated = animated;
+               img->interpolation = interpolation;
                img->users = 1;
 
                images[slot] = img;
@@ -231,12 +233,12 @@ int ImageManager::add_image(const string& filename, void *builtin_data, bool ani
        return slot;
 }
 
-void ImageManager::remove_image(const string& filename, void *builtin_data)
+void ImageManager::remove_image(const string& filename, void *builtin_data, InterpolationType interpolation)
 {
        size_t slot;
 
        for(slot = 0; slot < images.size(); slot++) {
-               if(images[slot] && images[slot]->filename == filename && images[slot]->builtin_data == builtin_data) {
+               if(images[slot] && images[slot]->filename == filename && images[slot]->interpolation == interpolation && images[slot]->builtin_data == builtin_data) {
                        /* decrement user count */
                        images[slot]->users--;
                        assert(images[slot]->users >= 0);
@@ -254,7 +256,9 @@ void ImageManager::remove_image(const string& filename, void *builtin_data)
        if(slot == images.size()) {
                /* see if it's in a float texture slot */
                for(slot = 0; slot < float_images.size(); slot++) {
-                       if(float_images[slot] && float_images[slot]->filename == filename && float_images[slot]->builtin_data == builtin_data) {
+                       if(float_images[slot] && float_images[slot]->filename == filename
+                                                                 && float_images[slot]->interpolation == interpolation
+                                                                 && float_images[slot]->builtin_data == builtin_data) {
                                /* decrement user count */
                                float_images[slot]->users--;
                                assert(float_images[slot]->users >= 0);
@@ -499,7 +503,7 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, int sl
 
                if(!pack_images) {
                        thread_scoped_lock device_lock(device_mutex);
-                       device->tex_alloc(name.c_str(), tex_img, true, true);
+                       device->tex_alloc(name.c_str(), tex_img, img->interpolation, true);
                }
        }
        else {
@@ -530,7 +534,7 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, int sl
 
                if(!pack_images) {
                        thread_scoped_lock device_lock(device_mutex);
-                       device->tex_alloc(name.c_str(), tex_img, true, true);
+                       device->tex_alloc(name.c_str(), tex_img, img->interpolation, true);
                }
        }
 
@@ -653,16 +657,31 @@ void ImageManager::device_pack_images(Device *device, DeviceScene *dscene, Progr
 
                device_vector<uchar4>& tex_img = dscene->tex_image[slot];
 
-               info[slot] = make_uint4(tex_img.data_width, tex_img.data_height, offset, 1);
+
+               /* The image options are packed
+                  bit 0 -> periodic
+                  bit 1 + 2 -> interpolation type */
+               u_int8_t interpolation = (images[slot]->interpolation << 1) + 1;
+               info[slot] = make_uint4(tex_img.data_width, tex_img.data_height, offset, interpolation);
 
                memcpy(pixels+offset, (void*)tex_img.data_pointer, tex_img.memory_size());
                offset += tex_img.size();
        }
 
-       if(dscene->tex_image_packed.size())
+       if(dscene->tex_image_packed.size()) {
+               if(dscene->tex_image_packed.device_pointer) {
+                       thread_scoped_lock device_lock(device_mutex);
+                       device->tex_free(dscene->tex_image_packed);
+               }
                device->tex_alloc("__tex_image_packed", dscene->tex_image_packed);
-       if(dscene->tex_image_packed_info.size())
+       }
+       if(dscene->tex_image_packed_info.size()) {
+               if(dscene->tex_image_packed_info.device_pointer) {
+                       thread_scoped_lock device_lock(device_mutex);
+                       device->tex_free(dscene->tex_image_packed_info);
+               }
                device->tex_alloc("__tex_image_packed_info", dscene->tex_image_packed_info);
+       }
 }
 
 void ImageManager::device_free(Device *device, DeviceScene *dscene)
index 187c5fd0f02b09f41b2ab0ac0e2b2748c166c25d..85b6b512bae2f28740190398724ff25dc13e05fe 100644 (file)
@@ -49,8 +49,8 @@ public:
        ImageManager();
        ~ImageManager();
 
-       int add_image(const string& filename, void *builtin_data, bool animated, bool& is_float, bool& is_linear);
-       void remove_image(const string& filename, void *builtin_data);
+       int add_image(const string& filename, void *builtin_data, bool animated, bool& is_float, bool& is_linear, InterpolationType interpolation);
+       void remove_image(const string& filename, void *builtin_data, InterpolationType interpolation);
        bool is_float_image(const string& filename, void *builtin_data, bool& is_linear);
 
        void device_update(Device *device, DeviceScene *dscene, Progress& progress);
@@ -79,6 +79,8 @@ private:
 
                bool need_load;
                bool animated;
+               InterpolationType interpolation;
+
                int users;
        };
 
index af6fca29ab05f0f4a87d4b541b64cbff0d751f24..e2ee3a949fd43dea3e8781611c084ed77edf520b 100644 (file)
@@ -193,6 +193,7 @@ ImageTextureNode::ImageTextureNode()
        builtin_data = NULL;
        color_space = ustring("Color");
        projection = ustring("Flat");
+       interpolation = INTERPOLATION_LINEAR;
        projection_blend = 0.0f;
        animated = false;
 
@@ -204,7 +205,7 @@ ImageTextureNode::ImageTextureNode()
 ImageTextureNode::~ImageTextureNode()
 {
        if(image_manager)
-               image_manager->remove_image(filename, builtin_data);
+               image_manager->remove_image(filename, builtin_data, interpolation);
 }
 
 ShaderNode *ImageTextureNode::clone() const
@@ -241,7 +242,7 @@ void ImageTextureNode::compile(SVMCompiler& compiler)
        image_manager = compiler.image_manager;
        if(is_float == -1) {
                bool is_float_bool;
-               slot = image_manager->add_image(filename, builtin_data, animated, is_float_bool, is_linear);
+               slot = image_manager->add_image(filename, builtin_data, animated, is_float_bool, is_linear, interpolation);
                is_float = (int)is_float_bool;
        }
 
@@ -315,6 +316,24 @@ void ImageTextureNode::compile(OSLCompiler& compiler)
        compiler.parameter("projection_blend", projection_blend);
        compiler.parameter("is_float", is_float);
        compiler.parameter("use_alpha", !alpha_out->links.empty());
+
+       switch (interpolation){
+               case INTERPOLATION_LINEAR:
+                       compiler.parameter("interpolation", "linear");
+                       break;
+               case INTERPOLATION_CLOSEST:
+                       compiler.parameter("interpolation", "closest");
+                       break;
+               case INTERPOLATION_CUBIC:
+                       compiler.parameter("interpolation", "cubic");
+                       break;
+               case INTERPOLATION_SMART:
+                       compiler.parameter("interpolation", "smart");
+                       break;
+               default:
+                       compiler.parameter("interpolation", "linear");
+                       break;
+       }
        compiler.add(this, "node_image_texture");
 }
 
@@ -354,7 +373,7 @@ EnvironmentTextureNode::EnvironmentTextureNode()
 EnvironmentTextureNode::~EnvironmentTextureNode()
 {
        if(image_manager)
-               image_manager->remove_image(filename, builtin_data);
+               image_manager->remove_image(filename, builtin_data, INTERPOLATION_LINEAR);
 }
 
 ShaderNode *EnvironmentTextureNode::clone() const
@@ -389,7 +408,7 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler)
        image_manager = compiler.image_manager;
        if(slot == -1) {
                bool is_float_bool;
-               slot = image_manager->add_image(filename, builtin_data, animated, is_float_bool, is_linear);
+               slot = image_manager->add_image(filename, builtin_data, animated, is_float_bool, is_linear, INTERPOLATION_LINEAR);
                is_float = (int)is_float_bool;
        }
 
index 86c4f49087508b5e1fc8539828927264bc1f66ad..497a367a2a61db81004531dba8b971882b5233fc 100644 (file)
@@ -76,6 +76,7 @@ public:
        void *builtin_data;
        ustring color_space;
        ustring projection;
+       InterpolationType interpolation;
        float projection_blend;
        bool animated;
 
index 20d575e481c8c6769b2838afdc4c639bc5ba2694..5d2037960fc7ea0e1daffd2710fcb276a57bfe17 100644 (file)
@@ -450,6 +450,16 @@ ccl_device_inline int4 make_int4(const float3& f)
 
 #endif
 
+/* Interpolation types for textures
+ * cuda also use texture space to store other objects */
+enum InterpolationType {
+       INTERPOLATION_NONE = -1,
+       INTERPOLATION_LINEAR = 0,
+       INTERPOLATION_CLOSEST = 1,
+       INTERPOLATION_CUBIC = 2,
+       INTERPOLATION_SMART = 3,
+};
+
 CCL_NAMESPACE_END
 
 #endif /* __UTIL_TYPES_H__ */
index effb8eb7de5157f7eb65d8a6df9a79e9dcd046cf..0cdb17cb2d490ba8669f76ada7a1d8fa607422ba 100644 (file)
@@ -784,6 +784,7 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA
        uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL);
        uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE);
        uiItemR(layout, ptr, "projection", 0, "", ICON_NONE);
+       uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE);
 
        if (RNA_enum_get(ptr, "projection") == SHD_PROJ_BOX) {
                uiItemR(layout, ptr, "projection_blend", 0, "Blend", ICON_NONE);
index cd9595d8185df1d55a77226fecb01491c7523222..1ad713e64e0f8e80b87294e54d1c98ea4243acb9 100644 (file)
@@ -724,7 +724,7 @@ typedef struct NodeTexImage {
        int color_space;
        int projection;
        float projection_blend;
-       int pad;
+       int interpolation;
 } NodeTexImage;
 
 typedef struct NodeTexChecker {
@@ -951,6 +951,12 @@ typedef struct NodeShaderNormalMap {
 #define SHD_PROJ_FLAT                          0
 #define SHD_PROJ_BOX                           1
 
+/* image texture interpolation */
+#define SHD_INTER_LINEAR               0
+#define SHD_INTER_CLOSEST              1
+#define SHD_INTER_CUBIC                        2
+#define SHD_INTER_SMART                        3
+
 /* tangent */
 #define SHD_TANGENT_RADIAL                     0
 #define SHD_TANGENT_UVMAP                      1
index d893a8c21f92a233d1bccd97fc4341665f7d544c..ae7dcdac42387d2aa3c3ae9a7f1b3854f03b0874 100644 (file)
@@ -3428,6 +3428,17 @@ static void def_sh_tex_image(StructRNA *srna)
                {0, NULL, 0, NULL, NULL}
        };
 
+       static const EnumPropertyItem prop_interpolation_items[] = {
+               {SHD_INTER_LINEAR,  "Linear", 0, "Linear",
+                                               "Linear interpolation"},
+               {SHD_INTER_CLOSEST, "Closest", 0, "Closest",
+                                               "No interpolation (sample closest texel"},
+               {SHD_INTER_CUBIC, "Cubic", 0, "Cubic",
+                                               "Cubic interpolation (OSL only)"},
+               {SHD_INTER_SMART, "Smart", 0, "Smart",
+                                               "Bicubic when maxifying, else bilinear (OSL only)"},
+               {0, NULL, 0, NULL, NULL}
+       };
 
        PropertyRNA *prop;
 
@@ -3451,6 +3462,11 @@ static void def_sh_tex_image(StructRNA *srna)
        RNA_def_property_ui_text(prop, "Projection", "Method to project 2D image on object with a 3D texture vector");
        RNA_def_property_update(prop, 0, "rna_Node_update");
 
+       prop = RNA_def_property(srna, "interpolation", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_items(prop, prop_interpolation_items);
+       RNA_def_property_ui_text(prop, "Interpolation", "Texture interpolation");
+       RNA_def_property_update(prop, 0, "rna_Node_update");
+
        prop = RNA_def_property(srna, "projection_blend", PROP_FLOAT, PROP_FACTOR);
        RNA_def_property_ui_text(prop, "Projection Blend", "For box projection, amount of blend to use between sides");
        RNA_def_property_update(prop, 0, "rna_Node_update");