diff options
Diffstat (limited to 'intern/cycles')
-rw-r--r-- | intern/cycles/CMakeLists.txt | 3 | ||||
-rw-r--r-- | intern/cycles/SConscript | 5 | ||||
-rw-r--r-- | intern/cycles/blender/addon/ui.py | 1 | ||||
-rw-r--r-- | intern/cycles/blender/blender_mesh.cpp | 110 | ||||
-rw-r--r-- | intern/cycles/blender/blender_session.cpp | 21 | ||||
-rw-r--r-- | intern/cycles/blender/blender_session.h | 5 | ||||
-rw-r--r-- | intern/cycles/blender/blender_shader.cpp | 12 | ||||
-rw-r--r-- | intern/cycles/kernel/kernel_textures.h | 5 | ||||
-rw-r--r-- | intern/cycles/kernel/kernel_types.h | 1 | ||||
-rw-r--r-- | intern/cycles/kernel/osl/osl_services.cpp | 8 | ||||
-rw-r--r-- | intern/cycles/kernel/svm/svm_image.h | 51 | ||||
-rw-r--r-- | intern/cycles/render/attribute.cpp | 7 | ||||
-rw-r--r-- | intern/cycles/render/image.cpp | 150 | ||||
-rw-r--r-- | intern/cycles/render/image.h | 9 | ||||
-rw-r--r-- | intern/cycles/render/nodes.cpp | 233 | ||||
-rw-r--r-- | intern/cycles/render/nodes.h | 26 | ||||
-rw-r--r-- | intern/cycles/render/scene.h | 3 | ||||
-rw-r--r-- | intern/cycles/util/util_types.h | 2 |
18 files changed, 609 insertions, 43 deletions
diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt index 2ba6af48d0d..a893b9dd12d 100644 --- a/intern/cycles/CMakeLists.txt +++ b/intern/cycles/CMakeLists.txt @@ -129,8 +129,9 @@ if(WITH_CYCLES_STANDALONE_GUI) add_definitions(-DWITH_CYCLES_STANDALONE_GUI) endif() -if(WITH_CYCLES_PTEX) +if(WITH_PTEX) add_definitions(-DWITH_PTEX) + include_directories("../../extern/ptex") endif() if(WITH_CYCLES_OPENSUBDIV) diff --git a/intern/cycles/SConscript b/intern/cycles/SConscript index 9cbdb93ce85..33f1ac87ef9 100644 --- a/intern/cycles/SConscript +++ b/intern/cycles/SConscript @@ -81,8 +81,13 @@ incs.append(env['BF_GLEW_INC']) incs.append('#/intern/glew-mx') incs.append('#/intern/atomic') incs.append('#intern/mikktspace') +if env['WITH_BF_PTEX']: + incs.append('#/extern/ptex') incs.extend('#extern/glew/include #extern/clew/include #extern/cuew/include #intern/mikktspace'.split()) +if env['WITH_BF_PTEX']: + defs.append('WITH_PTEX') + incs.append(cycles['BF_OIIO_INC']) incs.append(cycles['BF_BOOST_INC']) incs.append(cycles['BF_OPENEXR_INC'].split()) diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 651114a12dc..cd8b3c6677a 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -1409,6 +1409,7 @@ def get_panels(): "DATA_PT_context_speaker", "DATA_PT_normals", "DATA_PT_texture_space", + "DATA_PT_ptex", "DATA_PT_curve_texture_space", "DATA_PT_mball_texture_space", "DATA_PT_vertex_groups", diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index a5664fa2800..613d17120dd 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -260,6 +260,83 @@ static void create_mesh_volume_attributes(Scene *scene, BL::Object b_ob, Mesh *m /* Create Mesh */ +static const int quad_split_pattern[2][2][3] = { + /* Note that first pattern is the one used for triangle inputs */ + {{0, 1, 2}, {0, 2, 3}}, + {{0, 1, 3}, {2, 3, 1}} +}; + +static int quad_split_pattern_index(const float3 &a, + const float3 &b, + const float3 &c, + const float3 &d) +{ + if (is_zero(cross(b - a, c - a)) || is_zero(cross(c - a, d - a))) { + return 1; + } + else { + return 0; + } +} + +static void mesh_add_ptex_face_attributes(Mesh *mesh, BL::Mesh b_mesh, + const vector<int> &nverts, + const vector<int> &face_split_pattern) +{ + BL::Mesh::tessfaces_iterator f; + Attribute *face_id_attr = mesh->attributes.add(ATTR_STD_PTEX_UV); + mesh->attributes.reserve(); + + float3 (*dst)[3] = (float3(*)[3])face_id_attr->data_float3(); + size_t cur_tri = 0; + size_t cur_tessface = 0; + + for (b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f) { + BL::PtexTessFace ptex = f->ptex_tess_face(); + if (!ptex) break; + const int num_triangles = (nverts[cur_tessface] == 4) ? 2 : 1; + const int spi = face_split_pattern[cur_tessface]; + + for (int i = 0; i < num_triangles; i++) { + for (int j = 0; j < 3; j++) { + const int ci = quad_split_pattern[spi][i][j]; + + dst[cur_tri][j] = make_float3(ptex.uv()[ci * 2 + 0], + ptex.uv()[ci * 2 + 1], + ptex.id()); + } + cur_tri++; + } + + cur_tessface++; + } +} + +static void mesh_add_ptex_layer_data(Scene *scene, Mesh *mesh, BL::Mesh b_mesh) +{ + BL::Mesh::loop_ptex_iterator l; + for (b_mesh.loop_ptex.begin(l); l != b_mesh.loop_ptex.end(); ++l) { + const ustring layer_name = ustring(l->name()); + if (mesh->need_attribute(scene, layer_name)) { + Attribute *attr = mesh->attributes.add(layer_name, + TypeDesc::TypeFloat, + ATTR_ELEMENT_MESH); + //mesh->attributes.reserve(); + float *slot = attr->data_float(); + bool is_float; + bool is_linear; + // TODO + + BL::Image image = l->image(); + + // Other alternative is: get data, pack new image here + (*slot) = scene->image_manager->add_image + ("TODO", image.ptr.data, false, 1, + is_float, is_linear, INTERPOLATION_LINEAR, true); + } + } +} + static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<uint>& used_shaders) { /* count vertices and faces */ @@ -307,6 +384,7 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector< /* create faces */ vector<int> nverts(numfaces); + vector<int> face_split_pattern(numfaces); int fi = 0, ti = 0; for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f, ++fi) { @@ -338,24 +416,32 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector< } /* create triangles */ + int spi; if(n == 4) { - if(is_zero(cross(mesh->verts[vi[1]] - mesh->verts[vi[0]], mesh->verts[vi[2]] - mesh->verts[vi[0]])) || - is_zero(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]]))) - { - mesh->set_triangle(ti++, vi[0], vi[1], vi[3], shader, smooth); - mesh->set_triangle(ti++, vi[2], vi[3], vi[1], shader, smooth); - } - else { - mesh->set_triangle(ti++, vi[0], vi[1], vi[2], shader, smooth); - mesh->set_triangle(ti++, vi[0], vi[2], vi[3], shader, smooth); - } + spi = quad_split_pattern_index(mesh->verts[vi[0]], + mesh->verts[vi[1]], + mesh->verts[vi[2]], + mesh->verts[vi[3]]); + + } + else { + spi = 0; + } + face_split_pattern[fi] = spi; + + for (int i = 0; i < (n == 4 ? 2 : 1); i++) { + const int *c = quad_split_pattern[spi][i]; + mesh->set_triangle(ti++, vi[c[0]], vi[c[1]], vi[c[2]], + shader, smooth); } - else - mesh->set_triangle(ti++, vi[0], vi[1], vi[2], shader, smooth); nverts[fi] = n; } + /* Add Ptex data if needed */ + mesh_add_ptex_face_attributes(mesh, b_mesh, nverts, face_split_pattern); + mesh_add_ptex_layer_data(scene, mesh, b_mesh); + /* create vertex color attributes */ { BL::Mesh::tessface_vertex_colors_iterator l; diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index eb3f54ae90c..db70bad4e1f 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -101,8 +101,8 @@ void BlenderSession::create_session() scene = new Scene(scene_params, session_params.device); /* setup callbacks for builtin image support */ - scene->image_manager->builtin_image_info_cb = function_bind(&BlenderSession::builtin_image_info, this, _1, _2, _3, _4, _5, _6, _7); - scene->image_manager->builtin_image_pixels_cb = function_bind(&BlenderSession::builtin_image_pixels, this, _1, _2, _3); + scene->image_manager->builtin_image_info_cb = function_bind(&BlenderSession::builtin_image_info, this, _1, _2, _3, _4, _5, _6, _7, _8); + scene->image_manager->builtin_image_pixels_cb = function_bind(&BlenderSession::builtin_image_pixels, this, _1, _2, _3, _4, _5); scene->image_manager->builtin_image_float_pixels_cb = function_bind(&BlenderSession::builtin_image_float_pixels, this, _1, _2, _3); /* create session */ @@ -927,7 +927,7 @@ int BlenderSession::builtin_image_frame(const string &builtin_name) return atoi(builtin_name.substr(last + 1, builtin_name.size() - last - 1).c_str()); } -void BlenderSession::builtin_image_info(const string &builtin_name, void *builtin_data, bool &is_float, int &width, int &height, int &depth, int &channels) +void BlenderSession::builtin_image_info(const string &builtin_name, void *builtin_data, bool &is_float, int &width, int &height, int &depth, int &channels, int &num_ptex_regions) { /* empty image */ is_float = false; @@ -953,6 +953,10 @@ void BlenderSession::builtin_image_info(const string &builtin_name, void *builti height = b_image.size()[1]; depth = 1; channels = b_image.channels(); + + // TODO: ptex + is_float = false; + num_ptex_regions = b_image.ptex_regions().length; } else if(b_id.is_a(&RNA_Object)) { /* smoke volume data */ @@ -981,7 +985,8 @@ void BlenderSession::builtin_image_info(const string &builtin_name, void *builti } } -bool BlenderSession::builtin_image_pixels(const string &builtin_name, void *builtin_data, unsigned char *pixels) +bool BlenderSession::builtin_image_pixels(const string &builtin_name, void *builtin_data, unsigned char *pixels, + PtexRegions ptex_regions, const int num_ptex_regions) { if(!builtin_data) return false; @@ -1019,6 +1024,14 @@ bool BlenderSession::builtin_image_pixels(const string &builtin_name, void *buil } } + { + // TODO + BL::DynamicArray<int> regions = b_image.ptex_regions(); + assert(num_ptex_regions == regions.length); + memcpy(ptex_regions, regions.data, + sizeof(**ptex_regions) * num_ptex_regions); + } + /* premultiply, byte images are always straight for blender */ unsigned char *cp = pixels; for(int i = 0; i < width * height; i++, cp += channels) { diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h index 33da3076b55..0eeabdaade8 100644 --- a/intern/cycles/blender/blender_session.h +++ b/intern/cycles/blender/blender_session.h @@ -104,8 +104,9 @@ protected: void do_write_update_render_tile(RenderTile& rtile, bool do_update_only); int builtin_image_frame(const string &builtin_name); - void builtin_image_info(const string &builtin_name, void *builtin_data, bool &is_float, int &width, int &height, int &depth, int &channels); - bool builtin_image_pixels(const string &builtin_name, void *builtin_data, unsigned char *pixels); + void builtin_image_info(const string &builtin_name, void *builtin_data, bool &is_float, int &width, int &height, int &depth, int &channels, int &num_ptex_regions); + bool builtin_image_pixels(const string &builtin_name, void *builtin_data, unsigned char *pixels, + PtexRegions ptex_regions, int num_ptex_regions); bool builtin_image_float_pixels(const string &builtin_name, void *builtin_data, float *pixels); }; diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index baf79a78987..c141b9eeabd 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -577,6 +577,9 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen image->animated = b_image_node.image_user().use_auto_refresh(); image->use_alpha = b_image.use_alpha(); + // TODO(nicholasbishop) + image->ptex = string_endswith(image->filename, ".ptx"); + /* TODO(sergey): Does not work properly when we change builtin type. */ if (b_image.is_updated()) { scene->image_manager->tag_reload_image(image->filename, @@ -591,6 +594,15 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen get_tex_mapping(&image->tex_mapping, b_image_node.texture_mapping()); node = image; } + else if (b_node.is_a(&RNA_ShaderNodeTexPtex)) { + // TODO + BL::ShaderNodeTexPtex b_image_node(b_node); + PtexTextureNode *image = new PtexTextureNode(); + + image->ptex = true; + image->ptex_layer = b_image_node.layer_name(); + node = image; + } else if (b_node.is_a(&RNA_ShaderNodeTexEnvironment)) { BL::ShaderNodeTexEnvironment b_env_node(b_node); BL::Image b_image(b_env_node.image()); diff --git a/intern/cycles/kernel/kernel_textures.h b/intern/cycles/kernel/kernel_textures.h index 374dc6d1dd9..29cbee7731e 100644 --- a/intern/cycles/kernel/kernel_textures.h +++ b/intern/cycles/kernel/kernel_textures.h @@ -71,6 +71,9 @@ KERNEL_TEX(float, texture_float, __lookup_table) /* sobol */ KERNEL_TEX(uint, texture_uint, __sobol_directions) +/* ptex */ +KERNEL_TEX(uint, texture_uint, __ptex_table) + /* full-float image */ KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float_000) KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float_001) @@ -172,9 +175,9 @@ KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_094) KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_095) KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_096) KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_097) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_098) /* Kepler and above */ +KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_098) KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_099) KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_100) KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_101) diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 680094dcd0e..54aa2f478b9 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -535,6 +535,7 @@ typedef enum AttributeStandard { ATTR_STD_VOLUME_HEAT, ATTR_STD_VOLUME_VELOCITY, ATTR_STD_POINTINESS, + ATTR_STD_PTEX_LAYER, ATTR_STD_NUM, ATTR_STD_NOT_FOUND = ~0 diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp index 1f6015d0d6b..eddf86ca5c5 100644 --- a/intern/cycles/kernel/osl/osl_services.cpp +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -50,7 +50,7 @@ #include "kernel_accumulate.h" #include "kernel_shader.h" -#ifdef WITH_PTEX +#ifdef WITH_PTEX_OSL #include <Ptexture.h> #endif @@ -115,7 +115,7 @@ OSLRenderServices::OSLRenderServices() kernel_globals = NULL; osl_ts = NULL; -#ifdef WITH_PTEX +#ifdef WITH_PTEX_OSL size_t maxmem = 16384 * 1024; ptex_cache = PtexCache::create(0, maxmem); #endif @@ -123,7 +123,7 @@ OSLRenderServices::OSLRenderServices() OSLRenderServices::~OSLRenderServices() { -#ifdef WITH_PTEX +#ifdef WITH_PTEX_OSL ptex_cache->release(); #endif } @@ -848,7 +848,7 @@ bool OSLRenderServices::texture(ustring filename, TextureOpt &options, ShaderData *sd = (ShaderData *)(sg->renderstate); KernelGlobals *kg = sd->osl_globals; -#ifdef WITH_PTEX +#ifdef WITH_PTEX_OSL /* todo: this is just a quick hack, only works with particular files and options */ if(string_endswith(filename.string(), ".ptx")) { float2 uv; diff --git a/intern/cycles/kernel/svm/svm_image.h b/intern/cycles/kernel/svm/svm_image.h index e667fc2033d..f168f69306e 100644 --- a/intern/cycles/kernel/svm/svm_image.h +++ b/intern/cycles/kernel/svm/svm_image.h @@ -251,9 +251,9 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, case 95: r = kernel_tex_image_interp(__tex_image_095, x, y); break; case 96: r = kernel_tex_image_interp(__tex_image_096, x, y); break; case 97: r = kernel_tex_image_interp(__tex_image_097, x, y); break; - case 98: r = kernel_tex_image_interp(__tex_image_098, x, y); break; #if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 300) + case 98: r = kernel_tex_image_interp(__tex_image_098, x, y); break; case 99: r = kernel_tex_image_interp(__tex_image_099, x, y); break; case 100: r = kernel_tex_image_interp(__tex_image_100, x, y); break; case 101: r = kernel_tex_image_interp(__tex_image_101, x, y); break; @@ -377,7 +377,54 @@ ccl_device void svm_node_tex_image(KernelGlobals *kg, ShaderData *sd, float *sta co = texco_remap_square(co); map_to_tube(&co.x, &co.y, co.x, co.y, co.z); } - float4 f = svm_image_texture(kg, id, co.x, co.y, srgb, use_alpha); + + float4 f; + + // TODO + bool err = false; + if (srgb & 4) { + AttributeElement ae; + int image_attr_offset = find_attribute(kg, sd, id, &ae); + if(image_attr_offset == ATTR_STD_NOT_FOUND) { + /* Error */ + err = true; + } + else { + float fid = kernel_tex_fetch(__attributes_float, + image_attr_offset); + id = (int)(fid + 0.5f); + } + } + + if (err) { + f = make_float4(1.0f, 0.0f, 1.0f, 1.0f); + } + else if (srgb & 2) { + // TODO: test hacks for Ptex + uint face_id = (uint)(co.z + 0.5f); + uint offset = kernel_tex_fetch(__ptex_table, id - /* TODO */ 1024); + float2 tex_size = + make_float2((float)kernel_tex_fetch(__ptex_table, offset + 0), + (float)kernel_tex_fetch(__ptex_table, offset + 1)); + offset += 2; + offset += 4 * face_id; + + float2 ptex_origin = + make_float2((float)kernel_tex_fetch(__ptex_table, offset + 0), + (float)kernel_tex_fetch(__ptex_table, offset + 1)); + float2 ptex_res = + make_float2((float)kernel_tex_fetch(__ptex_table, offset + 2), + (float)kernel_tex_fetch(__ptex_table, offset + 3)); + + float2 ptex_uv = ptex_origin + make_float2(co.x, co.y) * ptex_res; + ptex_uv /= tex_size; + + f = svm_image_texture(kg, id, ptex_uv.x, ptex_uv.y, srgb, + use_alpha); + } + else { + f = svm_image_texture(kg, id, co.x, co.y, srgb, use_alpha); + } if(stack_valid(out_offset)) stack_store_float3(stack, out_offset, make_float3(f.x, f.y, f.z)); diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp index 656420f5dbc..22fe2075148 100644 --- a/intern/cycles/render/attribute.cpp +++ b/intern/cycles/render/attribute.cpp @@ -232,6 +232,8 @@ const char *Attribute::standard_name(AttributeStandard std) return "velocity"; case ATTR_STD_POINTINESS: return "pointiness"; + case ATTR_STD_PTEX_LAYER: + return "ptex_layer"; case ATTR_STD_NOT_FOUND: case ATTR_STD_NONE: case ATTR_STD_NUM: @@ -361,7 +363,7 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name) attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_FACE); break; case ATTR_STD_PTEX_UV: - attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX); + attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER); break; case ATTR_STD_GENERATED_TRANSFORM: attr = add(name, TypeDesc::TypeMatrix, ATTR_ELEMENT_MESH); @@ -380,6 +382,9 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name) case ATTR_STD_POINTINESS: attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VERTEX); break; + case ATTR_STD_PTEX_LAYER: + attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_MESH); + break; default: assert(0); break; diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index 61a0a81d51d..144a83714f3 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -27,6 +27,10 @@ #include <OSL/oslexec.h> #endif +#ifdef WITH_PTEX +#include "BPX_ptex.h" +#endif + CCL_NAMESPACE_BEGIN ImageManager::ImageManager() @@ -96,7 +100,8 @@ bool ImageManager::is_float_image(const string& filename, void *builtin_data, bo if(builtin_data) { if(builtin_image_info_cb) { int width, height, depth, channels; - builtin_image_info_cb(filename, builtin_data, is_float, width, height, depth, channels); + int num_ptex_regions; + builtin_image_info_cb(filename, builtin_data, is_float, width, height, depth, channels, num_ptex_regions); } if(is_float) @@ -348,7 +353,88 @@ void ImageManager::tag_reload_image(const string& filename, void *builtin_data, } } -bool ImageManager::file_load_image(Image *img, device_vector<uchar4>& tex_img) +#ifdef WITH_PTEX +// TODO +static PtexRegions ptex_table_reserve(DeviceScene *dscene, + const int texture_slot, + const int texture_width, + const int texture_height, + const int num_ptex_regions) +{ + // Simple encoding (not necessarily a good one): + // + // Two-step lookup: index is image slot, value there is an another + // index into same array. At that index, two ints store + // width/height of the whole texture. Then come 4-tuples of Ptex + // regions (x, y, w, h ints). + if (dscene->ptex_table.size() == 0) { + dscene->ptex_table.resize(TEX_EXTENDED_NUM_IMAGES_CPU); + } + + uint offset = dscene->ptex_table.size(); + uint *table_data = dscene->ptex_table.resize(offset + + 2 + + num_ptex_regions); + table_data[texture_slot] = offset; + table_data[offset] = texture_width; + offset++; + table_data[offset] = texture_height; + offset++; + + return (PtexRegions)(&table_data[offset]); +} + +struct PtexPackUcharContext { + uchar **pixels; + device_vector<uchar4> &tex_img; + DeviceScene *dscene; + int slot; +}; + +static BPXImageBuf *ptex_pack_uchar_cb(const struct BPXPackedLayout *layout, + void *c) +{ + PtexPackUcharContext &context = *static_cast<PtexPackUcharContext*>(c); + const int width = BPX_packed_layout_width(layout); + const int height = BPX_packed_layout_height(layout); + const int depth = 1; + (*context.pixels) = (uchar*)context.tex_img.resize(width, height, depth); + + const int num_regions = BPX_packed_layout_num_regions(layout); + PtexRegions regions = ptex_table_reserve(context.dscene, context.slot, + // TODO: 4 + width, height, num_regions*4); + + for (int i = 0; i < num_regions; i++) { + int x, y, w, h; + if (BPX_packed_layout_item(layout, i, &x, &y, &w, &h)) { + regions[i][0] = x; + regions[i][1] = y; + regions[i][2] = w; + regions[i][3] = h; + } + else { + // TODO + assert(!"TODO"); + } + } + + return BPX_image_buf_wrap(width, height, 4, BPX_TYPE_DESC_UINT8, + *context.pixels); +} +#else +static PtexRegions ptex_table_reserve(DeviceScene *dscene, + const int texture_slot, + const int texture_width, + const int texture_height, + const int num_ptex_regions) +{ + return NULL; +} +#endif + +bool ImageManager::file_load_image(Image *img, device_vector<uchar4>& tex_img, + DeviceScene *dscene, int slot) { if(img->filename == "") return false; @@ -356,6 +442,8 @@ bool ImageManager::file_load_image(Image *img, device_vector<uchar4>& tex_img) ImageInput *in = NULL; int width, height, depth, components; + bool use_ptex_file = false; + int num_ptex_regions = 0; if(!img->builtin_data) { /* load image from file through OIIO */ in = ImageInput::create(img->filename); @@ -374,8 +462,14 @@ bool ImageManager::file_load_image(Image *img, device_vector<uchar4>& tex_img) return false; } - width = spec.width; - height = spec.height; + if (in->format_name() == std::string("ptex")) { + use_ptex_file = true; + } + else { + width = spec.width; + height = spec.height; + } + depth = spec.depth; components = spec.nchannels; } @@ -385,7 +479,7 @@ bool ImageManager::file_load_image(Image *img, device_vector<uchar4>& tex_img) return false; bool is_float; - builtin_image_info_cb(img->filename, img->builtin_data, is_float, width, height, depth, components); + builtin_image_info_cb(img->filename, img->builtin_data, is_float, width, height, depth, components, num_ptex_regions); } /* we only handle certain number of components */ @@ -399,9 +493,33 @@ bool ImageManager::file_load_image(Image *img, device_vector<uchar4>& tex_img) } /* read RGBA pixels */ - uchar *pixels = (uchar*)tex_img.resize(width, height, depth); + uchar *pixels = NULL; bool cmyk = false; + if (use_ptex_file) { +#ifdef WITH_PTEX + BPXImageBuf *packed_buf; + BPXImageInput *bpx_in = reinterpret_cast<BPXImageInput*>(in); + // TODO, subtraction + PtexPackUcharContext context = {&pixels, tex_img, dscene, slot - 1024}; + packed_buf = BPX_image_buf_ptex_pack(bpx_in, ptex_pack_uchar_cb, + &context); + delete in; + + if (!packed_buf) { + return false; + } + + BPX_image_buf_free(packed_buf); + in = NULL; +#else + delete in; + in = NULL; +#endif + } else { + pixels = (uchar*)tex_img.resize(width, height, depth); + } + if(in) { if(depth <= 1) { int scanlinesize = width*components*sizeof(uchar); @@ -421,8 +539,16 @@ bool ImageManager::file_load_image(Image *img, device_vector<uchar4>& tex_img) in->close(); delete in; } - else { - builtin_image_pixels_cb(img->filename, img->builtin_data, pixels); + else if (!use_ptex_file) { + PtexRegions ptex_regions; + thread_scoped_lock device_lock(device_mutex); + + ptex_regions = ptex_table_reserve(dscene, slot - 1024, width, + height, num_ptex_regions); + + + builtin_image_pixels_cb(img->filename, img->builtin_data, pixels, + ptex_regions, num_ptex_regions); } if(cmyk) { @@ -509,7 +635,8 @@ bool ImageManager::file_load_float_image(Image *img, device_vector<float4>& tex_ return false; bool is_float; - builtin_image_info_cb(img->filename, img->builtin_data, is_float, width, height, depth, components); + int num_ptex_regions; + builtin_image_info_cb(img->filename, img->builtin_data, is_float, width, height, depth, components, num_ptex_regions); } if(components < 1 || width == 0 || height == 0) { @@ -675,7 +802,7 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, int sl device->tex_free(tex_img); } - if(!file_load_image(img, tex_img)) { + if(!file_load_image(img, tex_img, dscene, slot)) { /* on failure to load, we set a 1x1 pixels pink image */ uchar *pixels = (uchar*)tex_img.resize(1, 1); @@ -788,6 +915,7 @@ void ImageManager::device_update(Device *device, DeviceScene *dscene, Progress& if(pack_images) device_pack_images(device, dscene, progress); + device->tex_alloc("__ptex_table", dscene->ptex_table); need_update = false; } @@ -864,9 +992,11 @@ void ImageManager::device_free(Device *device, DeviceScene *dscene) device->tex_free(dscene->tex_image_packed); device->tex_free(dscene->tex_image_packed_info); + device->tex_free(dscene->ptex_table); dscene->tex_image_packed.clear(); dscene->tex_image_packed_info.clear(); + dscene->ptex_table.clear(); images.clear(); float_images.clear(); diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index 2f5dcb6efd5..44628621191 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -29,7 +29,7 @@ CCL_NAMESPACE_BEGIN /* generic */ -#define TEX_NUM_IMAGES 94 +#define TEX_NUM_IMAGES 93 #define TEX_IMAGE_BYTE_START TEX_NUM_FLOAT_IMAGES /* extended gpu */ @@ -73,8 +73,8 @@ public: bool need_update; - boost::function<void(const string &filename, void *data, bool &is_float, int &width, int &height, int &depth, int &channels)> builtin_image_info_cb; - boost::function<bool(const string &filename, void *data, unsigned char *pixels)> builtin_image_pixels_cb; + boost::function<void(const string &filename, void *data, bool &is_float, int &width, int &height, int &depth, int &channels, int &num_ptex_regions)> builtin_image_info_cb; + boost::function<bool(const string &filename, void *data, unsigned char *pixels, PtexRegions ptex_regions, int num_ptex_regions)> builtin_image_pixels_cb; boost::function<bool(const string &filename, void *data, float *pixels)> builtin_image_float_pixels_cb; struct Image { @@ -102,7 +102,8 @@ private: void *osl_texture_system; bool pack_images; - bool file_load_image(Image *img, device_vector<uchar4>& tex_img); + bool file_load_image(Image *img, device_vector<uchar4>& tex_img, + DeviceScene *dscene, int slot); bool file_load_float_image(Image *img, device_vector<float4>& tex_img); void device_load_image(Device *device, DeviceScene *dscene, int slot, Progress *progess); diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 46c962b16c3..aaf8d1d09d3 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -200,6 +200,7 @@ ImageTextureNode::ImageTextureNode() interpolation = INTERPOLATION_LINEAR; projection_blend = 0.0f; animated = false; + ptex = false; add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_UV); add_output("Color", SHADER_SOCKET_COLOR); @@ -234,6 +235,10 @@ void ImageTextureNode::attributes(Shader *shader, AttributeRequestSet *attribute } #endif + if (ptex) { + attributes->add(ATTR_STD_PTEX_UV); + } + ShaderNode::attributes(shader, attributes); } @@ -243,6 +248,13 @@ void ImageTextureNode::compile(SVMCompiler& compiler) ShaderOutput *color_out = output("Color"); ShaderOutput *alpha_out = output("Alpha"); + if (ptex) { + int attr = compiler.attribute(ATTR_STD_PTEX_UV); + compiler.stack_assign(vector_in); + compiler.add_node(NODE_ATTR, attr, vector_in->stack_offset, + NODE_ATTR_FLOAT3); + } + image_manager = compiler.image_manager; if(is_float == -1) { bool is_float_bool; @@ -261,6 +273,11 @@ void ImageTextureNode::compile(SVMCompiler& compiler) compiler.stack_assign(vector_in); int srgb = (is_linear || color_space != "Color")? 0: 1; + // TODO(nicholasbishop): clean this up of course + int flags = srgb; + if (ptex || string_endswith(filename, ".ptx")) { + flags |= 2; + } int vector_offset = vector_in->stack_offset; if(!tex_mapping.skip()) { @@ -275,7 +292,7 @@ void ImageTextureNode::compile(SVMCompiler& compiler) vector_offset, color_out->stack_offset, alpha_out->stack_offset, - srgb), + flags), projection_enum[projection]); } else { @@ -285,7 +302,7 @@ void ImageTextureNode::compile(SVMCompiler& compiler) vector_offset, color_out->stack_offset, alpha_out->stack_offset, - srgb), + flags & 1), __float_as_int(projection_blend)); } @@ -364,6 +381,218 @@ void ImageTextureNode::compile(OSLCompiler& compiler) compiler.add(this, "node_image_texture"); } +PtexTextureNode::PtexTextureNode() +: ShaderNode("ptex_texture") +{ + image_manager = NULL; + slot = -1; + is_float = -1; + is_linear = false; + use_alpha = true; + filename = ""; + builtin_data = NULL; + color_space = ustring("Color"); + projection = ustring("Flat"); + interpolation = INTERPOLATION_LINEAR; + projection_blend = 0.0f; + animated = false; + + add_input("Layer", SHADER_SOCKET_FLOAT); + add_input("Vector", SHADER_SOCKET_POINT); + add_output("Color", SHADER_SOCKET_COLOR); + add_output("Alpha", SHADER_SOCKET_FLOAT); +} + +PtexTextureNode::~PtexTextureNode() +{ + // if(image_manager) + // image_manager->remove_image(filename, builtin_data, interpolation); +} + +ShaderNode *PtexTextureNode::clone() const +{ + PtexTextureNode *node = new PtexTextureNode(*this); + node->image_manager = NULL; + node->slot = -1; + node->is_float = -1; + node->is_linear = false; + return node; +} + +void PtexTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes) +{ +#ifdef WITH_PTEX + /* todo: avoid loading other texture coordinates when using ptex, + * and hide texture coordinate socket in the UI */ + if (shader->has_surface && string_endswith(filename, ".ptx")) { + /* ptex */ + attributes->add(ATTR_STD_PTEX_FACE_ID); + attributes->add(ATTR_STD_PTEX_UV); + } +#endif + + attributes->add(ptex_layer); + attributes->add(ATTR_STD_PTEX_UV); + + ShaderNode::attributes(shader, attributes); +} + +static NodeType node_attr_from_bump(const ShaderBump bump) +{ + if(bump == SHADER_BUMP_DX) { + return NODE_ATTR_BUMP_DX; + } + else if(bump == SHADER_BUMP_DY) { + return NODE_ATTR_BUMP_DY; + } + else { + return NODE_ATTR; + } +} + +void PtexTextureNode::compile(SVMCompiler& compiler) +{ + ShaderInput *layer_in = input("Layer"); + ShaderInput *vector_in = input("Vector"); + ShaderOutput *color_out = output("Color"); + ShaderOutput *alpha_out = output("Alpha"); + + const int layer_attr_id = compiler.attribute(ptex_layer); + + { + int attr = compiler.attribute(ATTR_STD_PTEX_UV); + compiler.stack_assign(vector_in); + + compiler.add_node(node_attr_from_bump(bump), attr, + vector_in->stack_offset, NODE_ATTR_FLOAT3); + } + + image_manager = compiler.image_manager; + + if(!color_out->links.empty()) + compiler.stack_assign(color_out); + if(!alpha_out->links.empty()) + compiler.stack_assign(alpha_out); + + // TODO + if (true) + { + //if(slot != -1) { + compiler.stack_assign(layer_in); + compiler.stack_assign(vector_in); + + int srgb = (is_linear || color_space != "Color")? 0: 1; + // TODO(nicholasbishop): clean this up of course + int flags = srgb; + if (ptex || string_endswith(filename, ".ptx")) { + flags |= 2; + } + flags |= 4; + int vector_offset = vector_in->stack_offset; + + // if(!tex_mapping.skip()) { + // vector_offset = compiler.stack_find_offset(SHADER_SOCKET_VECTOR); + // tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset); + // } + + if(projection != "Box") { + compiler.add_node(NODE_TEX_IMAGE, + layer_attr_id, + compiler.encode_uchar4( + vector_offset, + color_out->stack_offset, + alpha_out->stack_offset, + flags), + ImageTextureNode::projection_enum[projection]); + } + else { + compiler.add_node(NODE_TEX_IMAGE_BOX, + slot, + compiler.encode_uchar4( + vector_offset, + color_out->stack_offset, + alpha_out->stack_offset, + flags & 1), + __float_as_int(projection_blend)); + } + + if(vector_offset != vector_in->stack_offset) + compiler.stack_clear_offset(vector_in->type, vector_offset); + } + else { + /* image not found */ + if(!color_out->links.empty()) { + compiler.add_node(NODE_VALUE_V, color_out->stack_offset); + compiler.add_node(NODE_VALUE_V, make_float3(TEX_IMAGE_MISSING_R, + TEX_IMAGE_MISSING_G, + TEX_IMAGE_MISSING_B)); + } + if(!alpha_out->links.empty()) + compiler.add_node(NODE_VALUE_F, __float_as_int(TEX_IMAGE_MISSING_A), alpha_out->stack_offset); + } +} + +void PtexTextureNode::compile(OSLCompiler& compiler) +{ + #if 0 + ShaderOutput *alpha_out = output("Alpha"); + + tex_mapping.compile(compiler); + + image_manager = compiler.image_manager; + if(is_float == -1) { + if(builtin_data == NULL) { + is_float = (int)image_manager->is_float_image(filename, NULL, is_linear); + } + else { + bool is_float_bool; + slot = image_manager->add_image(filename, builtin_data, + animated, 0, is_float_bool, is_linear, + interpolation, use_alpha); + is_float = (int)is_float_bool; + } + } + + if(slot == -1) { + compiler.parameter("filename", filename.c_str()); + } + else { + /* TODO(sergey): It's not so simple to pass custom attribute + * to the texture() function in order to make builtin images + * support more clear. So we use special file name which is + * "@<slot_number>" and check whether file name matches this + * mask in the OSLRenderServices::texture(). + */ + compiler.parameter("filename", string_printf("@%d", slot).c_str()); + } + if(is_linear || color_space != "Color") + compiler.parameter("color_space", "Linear"); + else + compiler.parameter("color_space", "sRGB"); + compiler.parameter("projection", projection); + compiler.parameter("projection_blend", projection_blend); + compiler.parameter("is_float", is_float); + compiler.parameter("use_alpha", !alpha_out->links.empty()); + + switch (interpolation) { + case INTERPOLATION_CLOSEST: + compiler.parameter("interpolation", "closest"); + break; + case INTERPOLATION_CUBIC: + compiler.parameter("interpolation", "cubic"); + break; + case INTERPOLATION_SMART: + compiler.parameter("interpolation", "smart"); + break; + case INTERPOLATION_LINEAR: + default: + compiler.parameter("interpolation", "linear"); + break; + } + compiler.add(this, "node_image_texture"); +#endif +} + /* Environment Texture */ static ShaderEnum env_projection_init() diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 0ec0fce512f..513fb334ff7 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -80,11 +80,37 @@ public: InterpolationType interpolation; float projection_blend; bool animated; + bool ptex; + ustring ptex_layer; static ShaderEnum color_space_enum; static ShaderEnum projection_enum; }; +// TODO +class PtexTextureNode : public ShaderNode { +public: + SHADER_NODE_NO_CLONE_CLASS(PtexTextureNode) + ~PtexTextureNode(); + ShaderNode *clone() const; + void attributes(Shader *shader, AttributeRequestSet *attributes); + + ImageManager *image_manager; + int slot; + int is_float; + bool is_linear; + bool use_alpha; + string filename; + void *builtin_data; + ustring color_space; + ustring projection; + InterpolationType interpolation; + float projection_blend; + bool animated; + bool ptex; + ustring ptex_layer; +}; + class EnvironmentTextureNode : public TextureNode { public: SHADER_NODE_NO_CLONE_CLASS(EnvironmentTextureNode) diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index 53c3a95903c..781d0b4cb7c 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -108,6 +108,9 @@ public: /* integrator */ device_vector<uint> sobol_directions; + /* ptex */ + device_vector<uint> ptex_table; + /* cpu images */ device_vector<uchar4> tex_image[TEX_EXTENDED_NUM_IMAGES_CPU]; device_vector<float4> tex_float_image[TEX_EXTENDED_NUM_FLOAT_IMAGES]; diff --git a/intern/cycles/util/util_types.h b/intern/cycles/util/util_types.h index df61b6ead21..3ec8fd269a1 100644 --- a/intern/cycles/util/util_types.h +++ b/intern/cycles/util/util_types.h @@ -460,6 +460,8 @@ ccl_device_inline int4 make_int4(const float3& f) #endif +typedef uint (*PtexRegions)[4]; + /* Interpolation types for textures * cuda also use texture space to store other objects */ enum InterpolationType { |