Currently only two mappings are supported by API, which is Repeat (old behavior)
and new Clip behavior. Internally this extension is being converted to periodic
flag which was already supported but wasn't exposed.
There's no support for OpenCL yet because of the way how we pack images into a
single texture.
Those settings are not exposed to UI or anywhere else and there should be no
functional changes so far.
bool animated = false;
volume_data->manager = image_manager;
- volume_data->slot = image_manager->add_image(Attribute::standard_name(std),
- b_ob.ptr.data, animated, frame, is_float, is_linear, INTERPOLATION_LINEAR, true);
+ volume_data->slot = image_manager->add_image(
+ Attribute::standard_name(std),
+ b_ob.ptr.data,
+ animated,
+ frame,
+ is_float,
+ is_linear,
+ INTERPOLATION_LINEAR,
+ EXTENSION_REPEAT,
+ true);
}
static void create_mesh_volume_attributes(Scene *scene, BL::Object b_ob, Mesh *mesh, float frame)
/* TODO(sergey): Does not work properly when we change builtin type. */
if(b_image.is_updated()) {
- scene->image_manager->tag_reload_image(image->filename,
- image->builtin_data,
- (InterpolationType)b_image_node.interpolation());
+ scene->image_manager->tag_reload_image(
+ image->filename,
+ image->builtin_data,
+ (InterpolationType)b_image_node.interpolation(),
+ EXTENSION_REPEAT);
}
}
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->extension = EXTENSION_REPEAT;
image->projection_blend = b_image_node.projection_blend();
get_tex_mapping(&image->tex_mapping, b_image_node.texture_mapping());
node = image;
if(b_image.is_updated()) {
scene->image_manager->tag_reload_image(env->filename,
env->builtin_data,
- INTERPOLATION_LINEAR);
+ INTERPOLATION_LINEAR,
+ EXTENSION_REPEAT);
}
}
env->color_space = EnvironmentTextureNode::color_space_enum[(int)b_env_node.color_space()];
/* TODO(sergey): Use more proper update flag. */
if(true) {
- scene->image_manager->tag_reload_image(point_density->filename,
- point_density->builtin_data,
- point_density->interpolation);
+ scene->image_manager->tag_reload_image(
+ point_density->filename,
+ point_density->builtin_data,
+ point_density->interpolation,
+ EXTENSION_CLIP);
}
node = point_density;
}
kernel_const_copy(&kernel_globals, name, host, size);
}
- void tex_alloc(const char *name, device_memory& mem, InterpolationType interpolation, bool /*periodic*/)
+ void tex_alloc(const char *name,
+ device_memory& mem,
+ InterpolationType interpolation,
+ bool periodic)
{
VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes.";
- kernel_tex_copy(&kernel_globals, name, mem.data_pointer, mem.data_width, mem.data_height, mem.data_depth, interpolation);
+ kernel_tex_copy(&kernel_globals,
+ name,
+ mem.data_pointer,
+ mem.data_width,
+ mem.data_height,
+ mem.data_depth,
+ interpolation,
+ periodic);
mem.device_pointer = mem.data_pointer;
mem.device_size = mem.memory_size();
stats.mem_alloc(mem.device_size);
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, size_t depth, InterpolationType interpolation=INTERPOLATION_LINEAR);
+void kernel_tex_copy(KernelGlobals *kg,
+ const char *name,
+ device_ptr mem,
+ size_t width,
+ size_t height,
+ size_t depth,
+ InterpolationType interpolation=INTERPOLATION_LINEAR,
+ bool periodic = true);
void kernel_cpu_path_trace(KernelGlobals *kg, float *buffer, unsigned int *rng_state,
int sample, int x, int y, int offset, int stride);
return x - (float)i;
}
- ccl_always_inline float4 interp(float x, float y, bool periodic = true)
+ ccl_always_inline float4 interp(float x, float y)
{
if(UNLIKELY(!data))
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
}
}
- ccl_always_inline float4 interp_3d(float x, float y, float z, bool periodic = false)
+ ccl_always_inline float4 interp_3d(float x, float y, float z)
{
- return interp_3d_ex(x, y, z, interpolation, periodic);
+ return interp_3d_ex(x, y, z, interpolation);
}
ccl_always_inline float4 interp_3d_ex(float x, float y, float z,
- int interpolation = INTERPOLATION_LINEAR,
- bool periodic = false)
+ int interpolation = INTERPOLATION_LINEAR)
{
if(UNLIKELY(!data))
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
T *data;
int interpolation;
+ bool periodic;
int width, height, depth;
#undef SET_CUBIC_SPLINE_WEIGHTS
};
assert(0);
}
-void kernel_tex_copy(KernelGlobals *kg, const char *name, device_ptr mem, size_t width, size_t height, size_t depth, InterpolationType interpolation)
+void kernel_tex_copy(KernelGlobals *kg,
+ const char *name,
+ device_ptr mem,
+ size_t width,
+ size_t height,
+ size_t depth,
+ InterpolationType interpolation,
+ bool periodic)
{
if(0) {
}
tex->data = (float4*)mem;
tex->dimensions_set(width, height, depth);
tex->interpolation = interpolation;
+ tex->periodic = periodic;
}
}
else if(strstr(name, "__tex_image")) {
tex->data = (uchar4*)mem;
tex->dimensions_set(width, height, depth);
tex->interpolation = interpolation;
+ tex->periodic = periodic;
}
}
else
return point(u, v, 0.0);
}
-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 image_texture_lookup(string filename,
+ string color_space,
+ float u, float v,
+ output float Alpha,
+ int use_alpha,
+ int is_float,
+ string interpolation,
+ string wrap)
{
- color rgb = (color)texture(filename, u, 1.0 - v, "wrap", "periodic", "interp", interpolation, "alpha", Alpha);
+ color rgb = (color)texture(filename, u, 1.0 - v, "wrap", wrap, "interp", interpolation, "alpha", Alpha);
if (use_alpha) {
rgb = color_unpremultiply(rgb, Alpha);
string color_space = "sRGB",
string projection = "Flat",
string interpolation = "smartcubic",
+ string wrap = "periodic",
float projection_blend = 0.0,
int is_float = 1,
int use_alpha = 1,
p = transform(mapping, p);
if (projection == "Flat") {
- Color = image_texture_lookup(filename, color_space, p[0], p[1], Alpha, use_alpha, is_float, interpolation);
+ Color = image_texture_lookup(filename,
+ color_space,
+ p[0], p[1],
+ Alpha,
+ use_alpha,
+ is_float,
+ interpolation,
+ wrap);
}
else if (projection == "Box") {
/* object space normal */
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, interpolation);
+ Color += weight[0] * image_texture_lookup(filename,
+ color_space,
+ p[1], p[2],
+ tmp_alpha,
+ use_alpha,
+ is_float,
+ interpolation,
+ wrap);
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, interpolation);
+ Color += weight[1] * image_texture_lookup(filename,
+ color_space,
+ p[0], p[2],
+ tmp_alpha,
+ use_alpha,
+ is_float,
+ interpolation,
+ wrap);
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, interpolation);
+ Color += weight[2] * image_texture_lookup(filename,
+ color_space,
+ p[1], p[0],
+ tmp_alpha,
+ use_alpha,
+ is_float,
+ interpolation,
+ wrap);
Alpha += weight[2] * tmp_alpha;
}
}
else if (projection == "Sphere") {
point projected = map_to_sphere(texco_remap_square(p));
- Color = image_texture_lookup(filename, color_space,
+ Color = image_texture_lookup(filename,
+ color_space,
projected[0], projected[1],
- Alpha, use_alpha, is_float, interpolation);
+ Alpha,
+ use_alpha,
+ is_float,
+ interpolation,
+ wrap);
}
else if (projection == "Tube") {
point projected = map_to_tube(texco_remap_square(p));
- Color = image_texture_lookup(filename, color_space,
+ Color = image_texture_lookup(filename,
+ color_space,
projected[0], projected[1],
- Alpha, use_alpha, is_float, interpolation);
+ Alpha,
+ use_alpha,
+ is_float,
+ interpolation,
+ wrap);
}
}
return is_float;
}
-static bool image_equals(ImageManager::Image *image, const string& filename, void *builtin_data, InterpolationType interpolation)
+static bool image_equals(ImageManager::Image *image,
+ const string& filename,
+ void *builtin_data,
+ InterpolationType interpolation,
+ ExtensionType extension)
{
return image->filename == filename &&
image->builtin_data == builtin_data &&
- image->interpolation == interpolation;
+ image->interpolation == interpolation &&
+ image->extension == extension;
}
-int ImageManager::add_image(const string& filename, void *builtin_data, bool animated, float frame,
- bool& is_float, bool& is_linear, InterpolationType interpolation, bool use_alpha)
+int ImageManager::add_image(const string& filename,
+ void *builtin_data,
+ bool animated,
+ float frame,
+ bool& is_float,
+ bool& is_linear,
+ InterpolationType interpolation,
+ ExtensionType extension,
+ bool use_alpha)
{
Image *img;
size_t slot;
/* find existing image */
for(slot = 0; slot < float_images.size(); slot++) {
img = float_images[slot];
- if(img && image_equals(img, filename, builtin_data, interpolation)) {
+ if(img && image_equals(img,
+ filename,
+ builtin_data,
+ interpolation,
+ extension))
+ {
if(img->frame != frame) {
img->frame = frame;
img->need_load = true;
img->animated = animated;
img->frame = frame;
img->interpolation = interpolation;
+ img->extension = extension;
img->users = 1;
img->use_alpha = use_alpha;
else {
for(slot = 0; slot < images.size(); slot++) {
img = images[slot];
- if(img && image_equals(img, filename, builtin_data, interpolation)) {
+ if(img && image_equals(img,
+ filename,
+ builtin_data,
+ interpolation,
+ extension))
+ {
if(img->frame != frame) {
img->frame = frame;
img->need_load = true;
img->animated = animated;
img->frame = frame;
img->interpolation = interpolation;
+ img->extension = extension;
img->users = 1;
img->use_alpha = use_alpha;
}
}
-void ImageManager::remove_image(const string& filename, void *builtin_data, InterpolationType interpolation)
+void ImageManager::remove_image(const string& filename,
+ void *builtin_data,
+ InterpolationType interpolation,
+ ExtensionType extension)
{
size_t slot;
for(slot = 0; slot < images.size(); slot++) {
- if(images[slot] && image_equals(images[slot], filename, builtin_data, interpolation)) {
+ if(images[slot] && image_equals(images[slot],
+ filename,
+ builtin_data,
+ interpolation,
+ extension))
+ {
remove_image(slot+tex_image_byte_start);
break;
}
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] && image_equals(float_images[slot], filename, builtin_data, interpolation)) {
+ if(float_images[slot] && image_equals(float_images[slot],
+ filename,
+ builtin_data,
+ interpolation,
+ extension)) {
remove_image(slot);
break;
}
* without bunch of arguments passing around making code readability even
* more cluttered.
*/
-void ImageManager::tag_reload_image(const string& filename, void *builtin_data, InterpolationType interpolation)
+void ImageManager::tag_reload_image(const string& filename,
+ void *builtin_data,
+ InterpolationType interpolation,
+ ExtensionType extension)
{
size_t slot;
for(slot = 0; slot < images.size(); slot++) {
- if(images[slot] && image_equals(images[slot], filename, builtin_data, interpolation)) {
+ if(images[slot] && image_equals(images[slot],
+ filename,
+ builtin_data,
+ interpolation,
+ extension)) {
images[slot]->need_load = true;
break;
}
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] && image_equals(float_images[slot], filename, builtin_data, interpolation)) {
+ if(float_images[slot] && image_equals(float_images[slot],
+ filename,
+ builtin_data,
+ interpolation,
+ extension)) {
float_images[slot]->need_load = true;
break;
}
if(!pack_images) {
thread_scoped_lock device_lock(device_mutex);
- device->tex_alloc(name.c_str(), tex_img, img->interpolation, true);
+ device->tex_alloc(name.c_str(),
+ tex_img,
+ img->interpolation,
+ img->extension == EXTENSION_REPEAT);
}
}
else {
if(!pack_images) {
thread_scoped_lock device_lock(device_mutex);
- device->tex_alloc(name.c_str(), tex_img, img->interpolation, true);
+ device->tex_alloc(name.c_str(),
+ tex_img,
+ img->interpolation,
+ img->extension == EXTENSION_REPEAT);
}
}
ImageManager();
~ImageManager();
- int add_image(const string& filename, void *builtin_data, bool animated, float frame,
- bool& is_float, bool& is_linear, InterpolationType interpolation, bool use_alpha);
+ int add_image(const string& filename,
+ void *builtin_data,
+ bool animated,
+ float frame,
+ bool& is_float,
+ bool& is_linear,
+ InterpolationType interpolation,
+ ExtensionType extension,
+ bool use_alpha);
void remove_image(int slot);
- void remove_image(const string& filename, void *builtin_data, InterpolationType interpolation);
- void tag_reload_image(const string& filename, void *builtin_data, InterpolationType interpolation);
+ void remove_image(const string& filename,
+ void *builtin_data,
+ InterpolationType interpolation,
+ ExtensionType extension);
+ void tag_reload_image(const string& filename,
+ void *builtin_data,
+ InterpolationType interpolation,
+ ExtensionType extension);
bool is_float_image(const string& filename, void *builtin_data, bool& is_linear);
void device_update(Device *device, DeviceScene *dscene, Progress& progress);
bool animated;
float frame;
InterpolationType interpolation;
+ ExtensionType extension;
int users;
};
color_space = ustring("Color");
projection = ustring("Flat");
interpolation = INTERPOLATION_LINEAR;
+ extension = EXTENSION_REPEAT;
projection_blend = 0.0f;
animated = false;
ImageTextureNode::~ImageTextureNode()
{
- if(image_manager)
- image_manager->remove_image(filename, builtin_data, interpolation);
+ if(image_manager) {
+ image_manager->remove_image(filename,
+ builtin_data,
+ interpolation,
+ extension);
+ }
}
ShaderNode *ImageTextureNode::clone() const
image_manager = compiler.image_manager;
if(is_float == -1) {
bool is_float_bool;
- slot = image_manager->add_image(filename, builtin_data,
- animated, 0, is_float_bool, is_linear,
- interpolation, use_alpha);
+ slot = image_manager->add_image(filename,
+ builtin_data,
+ animated,
+ 0,
+ is_float_bool,
+ is_linear,
+ interpolation,
+ extension,
+ use_alpha);
is_float = (int)is_float_bool;
}
}
else {
bool is_float_bool;
- slot = image_manager->add_image(filename, builtin_data,
- animated, 0, is_float_bool, is_linear,
- interpolation, use_alpha);
+ slot = image_manager->add_image(filename,
+ builtin_data,
+ animated,
+ 0,
+ is_float_bool,
+ is_linear,
+ interpolation,
+ extension,
+ use_alpha);
is_float = (int)is_float_bool;
}
}
compiler.parameter("interpolation", "linear");
break;
}
+
+ if (extension == EXTENSION_REPEAT) {
+ compiler.parameter("wrap", "periodic");
+ }
+ else {
+ compiler.parameter("wrap", "clamp");
+ }
+
compiler.add(this, "node_image_texture");
}
EnvironmentTextureNode::~EnvironmentTextureNode()
{
- if(image_manager)
- image_manager->remove_image(filename, builtin_data, INTERPOLATION_LINEAR);
+ if(image_manager) {
+ image_manager->remove_image(filename,
+ builtin_data,
+ INTERPOLATION_LINEAR,
+ EXTENSION_REPEAT);
+ }
}
ShaderNode *EnvironmentTextureNode::clone() const
image_manager = compiler.image_manager;
if(slot == -1) {
bool is_float_bool;
- slot = image_manager->add_image(filename, builtin_data,
- animated, 0, is_float_bool, is_linear,
- INTERPOLATION_LINEAR, use_alpha);
+ slot = image_manager->add_image(filename,
+ builtin_data,
+ animated,
+ 0,
+ is_float_bool,
+ is_linear,
+ INTERPOLATION_LINEAR,
+ EXTENSION_REPEAT,
+ use_alpha);
is_float = (int)is_float_bool;
}
}
else {
bool is_float_bool;
- slot = image_manager->add_image(filename, builtin_data,
- animated, 0, is_float_bool, is_linear,
- INTERPOLATION_LINEAR, use_alpha);
+ slot = image_manager->add_image(filename,
+ builtin_data,
+ animated,
+ 0,
+ is_float_bool,
+ is_linear,
+ INTERPOLATION_LINEAR,
+ EXTENSION_REPEAT,
+ use_alpha);
is_float = (int)is_float_bool;
}
}
PointDensityTextureNode::~PointDensityTextureNode()
{
- if(image_manager)
- image_manager->remove_image(filename, builtin_data, interpolation);
+ if(image_manager) {
+ image_manager->remove_image(filename,
+ builtin_data,
+ interpolation,
+ EXTENSION_CLIP);
+ }
}
ShaderNode *PointDensityTextureNode::clone() const
false, 0,
is_float, is_linear,
interpolation,
+ EXTENSION_CLIP,
true);
}
false, 0,
is_float, is_linear,
interpolation,
+ EXTENSION_CLIP,
true);
}
ustring color_space;
ustring projection;
InterpolationType interpolation;
+ ExtensionType extension;
float projection_blend;
bool animated;
INTERPOLATION_SMART = 3,
};
+/* Extension types for textures.
+ *
+ * Defines how the image is extrapolated past its original bounds.
+ */
+enum ExtensionType {
+ /* Cause the image to repeat horizontally and vertically. */
+ EXTENSION_REPEAT = 0,
+ /* Clip to image size and set exterior pixels as transparent. */
+ EXTENSION_CLIP = 1,
+};
+
/* macros */
/* hints for branch prediction, only use in code that runs a _lot_ */