diff options
238 files changed, 11364 insertions, 6853 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b40b9268fc..b558fe14820 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1959,7 +1959,7 @@ elseif(WIN32) set(OPENAL ${LIBDIR}/openal) set(OPENALDIR ${LIBDIR}/openal) set(OPENAL_INCLUDE_DIR ${OPENAL}/include) - if(MSVC12) + if(MSVC) set(OPENAL_LIBRARY openal32) else() set(OPENAL_LIBRARY wrap_oal) diff --git a/build_files/buildbot/slave_compile.py b/build_files/buildbot/slave_compile.py index 5e25d9f3f04..9a874e92c80 100644 --- a/build_files/buildbot/slave_compile.py +++ b/build_files/buildbot/slave_compile.py @@ -75,11 +75,18 @@ if 'cmake' in builder: cmake_extra_options.append('-DCUDA_NVCC_EXECUTABLE=/usr/local/cuda-hack/bin/nvcc') elif builder.startswith('win'): + if builder.endswith('_vc2015'): if builder.startswith('win64'): - cmake_options.append(['-G', '"Visual Studio 12 2013 Win64"']) + cmake_options.extend(['-G', 'Visual Studio 14 2015 Win64']) elif builder.startswith('win32'): bits = 32 - cmake_options.append(['-G', '"Visual Studio 12 2013"']) + cmake_options.extend(['-G', 'Visual Studio 14 2015']) + else: + if builder.startswith('win64'): + cmake_options.extend(['-G', 'Visual Studio 12 2013 Win64']) + elif builder.startswith('win32'): + bits = 32 + cmake_options.extend(['-G', 'Visual Studio 12 2013']) elif builder.startswith('linux'): tokens = builder.split("_") diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index 47fc86c4f20..d34b55e14e0 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -879,8 +879,16 @@ macro(TEST_SHARED_PTR_SUPPORT) # otherwise it's assumed to be defined in std namespace. include(CheckIncludeFileCXX) + include(CheckCXXSourceCompiles) set(SHARED_PTR_FOUND FALSE) - CHECK_INCLUDE_FILE_CXX(memory HAVE_STD_MEMORY_HEADER) + # Workaround for newer GCC (6.x+) where C++11 was enabled by default, which lead us + # to a situation when there is <unordered_map> include but which can't be used uless + # C++11 is enabled. + if(CMAKE_COMPILER_IS_GNUCC AND (NOT "${CMAKE_C_COMPILER_VERSION}" VERSION_LESS "6.0") AND (NOT WITH_CXX11)) + set(HAVE_STD_MEMORY_HEADER False) + else() + CHECK_INCLUDE_FILE_CXX(memory HAVE_STD_MEMORY_HEADER) + endif() if(HAVE_STD_MEMORY_HEADER) # Finding the memory header doesn't mean that shared_ptr is in std # namespace. @@ -888,7 +896,6 @@ macro(TEST_SHARED_PTR_SUPPORT) # In particular, MSVC 2008 has shared_ptr declared in std::tr1. In # order to support this, we do an extra check to see which namespace # should be used. - include(CheckCXXSourceCompiles) CHECK_CXX_SOURCE_COMPILES("#include <memory> int main() { std::shared_ptr<int> int_ptr; diff --git a/extern/Eigen3/README.blender b/extern/Eigen3/README.blender new file mode 100644 index 00000000000..8ccc46ac344 --- /dev/null +++ b/extern/Eigen3/README.blender @@ -0,0 +1,6 @@ +Project: Eigen, template library for linear algebra: matrices, vectors, numerical solvers, and related algorithms +URL: http://eigen.tuxfamily.org/index.php?title=Main_Page +License: GPLv3+ +Upstream version: 3.2.7 +Local modifications: +- OpenMP fix for MSVC2015, see http://eigen.tuxfamily.org/bz/show_bug.cgi?id=1131 diff --git a/extern/binreloc/README.blender b/extern/binreloc/README.blender new file mode 100644 index 00000000000..a90b44216a4 --- /dev/null +++ b/extern/binreloc/README.blender @@ -0,0 +1,6 @@ +Project: AutoPackage +URL: http://autopackage.org/docs/binreloc (original, defunct) + http://alien.cern.ch/cache/autopackage-1.0/site/docs/binreloc/ (cache) +License: Public Domain +Upstream version: Unknown (Last Release) +Local modifications: None diff --git a/extern/carve/README.blender b/extern/carve/README.blender new file mode 100644 index 00000000000..80be40ae558 --- /dev/null +++ b/extern/carve/README.blender @@ -0,0 +1,4 @@ +Project: Carve, CSG library +URL: https://code.google.com/archive/p/carve/ +Upstream version 9a85d733a43d +Local modifications: See patches/ folder diff --git a/extern/libopenjpeg/README.blender b/extern/libopenjpeg/README.blender new file mode 100644 index 00000000000..5aa213c7707 --- /dev/null +++ b/extern/libopenjpeg/README.blender @@ -0,0 +1,5 @@ +Project: OpenJPEG +URL: http://www.openjpeg.org +License: BSD 2-Clause +Upstream version: 1.5.2 +Local modifications: diff --git a/extern/rangetree/README.blender b/extern/rangetree/README.blender new file mode 100644 index 00000000000..cb5967137ac --- /dev/null +++ b/extern/rangetree/README.blender @@ -0,0 +1,5 @@ +Project: RangeTree +URL: https://github.com/nicholasbishop/RangeTree +License: GPLv2+ +Upstream version: c4ecf6bb7dfd +Local modifications: None diff --git a/extern/xdnd/README.blender b/extern/xdnd/README.blender new file mode 100644 index 00000000000..05afe566bba --- /dev/null +++ b/extern/xdnd/README.blender @@ -0,0 +1,8 @@ +Project: X Drag and Drop +URL: http://www.newplanetsoftware.com/xdnd/ (defunct) + https://freedesktop.org/wiki/Specifications/XDND/ (cache) +License: GPLv2+ +Upstream version: 2000-08-08 +Local modifications: +* Fix T33192 + Opening Blender breaks drag-and-drop support on the KDE desktop. diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp index f734d01f71d..9f967a4bde9 100644 --- a/intern/cycles/app/cycles_xml.cpp +++ b/intern/cycles/app/cycles_xml.cpp @@ -31,6 +31,7 @@ #include "mesh.h" #include "nodes.h" #include "object.h" +#include "osl.h" #include "shader.h" #include "scene.h" @@ -214,25 +215,7 @@ static bool xml_equal_string(pugi::xml_node node, const char *name, const char * return false; } -static bool xml_read_enum(ustring *str, ShaderEnum& enm, pugi::xml_node node, const char *name) -{ - pugi::xml_attribute attr = node.attribute(name); - - if(attr) { - ustring ustr(attr.value()); - - if(enm.exists(ustr)) { - *str = ustr; - return true; - } - else - fprintf(stderr, "Unknown value \"%s\" for attribute \"%s\".\n", ustr.c_str(), name); - } - - return false; -} - -static bool xml_read_enum_value(int *value, ShaderEnum& enm, pugi::xml_node node, const char *name) +static bool xml_read_enum_value(int *value, NodeEnum& enm, pugi::xml_node node, const char *name) { pugi::xml_attribute attr = node.attribute(name); @@ -250,77 +233,16 @@ static bool xml_read_enum_value(int *value, ShaderEnum& enm, pugi::xml_node node return false; } -static ShaderSocketType xml_read_socket_type(pugi::xml_node node, const char *name) -{ - pugi::xml_attribute attr = node.attribute(name); - - if(attr) { - string value = attr.value(); - if(string_iequals(value, "float")) - return SHADER_SOCKET_FLOAT; - else if(string_iequals(value, "int")) - return SHADER_SOCKET_INT; - else if(string_iequals(value, "color")) - return SHADER_SOCKET_COLOR; - else if(string_iequals(value, "vector")) - return SHADER_SOCKET_VECTOR; - else if(string_iequals(value, "point")) - return SHADER_SOCKET_POINT; - else if(string_iequals(value, "normal")) - return SHADER_SOCKET_NORMAL; - else if(string_iequals(value, "closure color")) - return SHADER_SOCKET_CLOSURE; - else if(string_iequals(value, "string")) - return SHADER_SOCKET_STRING; - else - fprintf(stderr, "Unknown shader socket type \"%s\" for attribute \"%s\".\n", value.c_str(), name); - } - - return SHADER_SOCKET_UNDEFINED; -} - /* Camera */ -static void xml_read_camera(const XMLReadState& state, pugi::xml_node node) +static void xml_read_camera(XMLReadState& state, pugi::xml_node node) { Camera *cam = state.scene->camera; xml_read_int(&cam->width, node, "width"); xml_read_int(&cam->height, node, "height"); - if(xml_read_float(&cam->fov, node, "fov")) - cam->fov = DEG2RADF(cam->fov); - - xml_read_float(&cam->nearclip, node, "nearclip"); - xml_read_float(&cam->farclip, node, "farclip"); - xml_read_float(&cam->aperturesize, node, "aperturesize"); // 0.5*focallength/fstop - xml_read_float(&cam->focaldistance, node, "focaldistance"); - xml_read_float(&cam->shuttertime, node, "shuttertime"); - xml_read_float(&cam->aperture_ratio, node, "aperture_ratio"); - - if(xml_equal_string(node, "type", "orthographic")) - cam->type = CAMERA_ORTHOGRAPHIC; - else if(xml_equal_string(node, "type", "perspective")) - cam->type = CAMERA_PERSPECTIVE; - else if(xml_equal_string(node, "type", "panorama")) - cam->type = CAMERA_PANORAMA; - - if(xml_equal_string(node, "panorama_type", "equirectangular")) - cam->panorama_type = PANORAMA_EQUIRECTANGULAR; - else if(xml_equal_string(node, "panorama_type", "fisheye_equidistant")) - cam->panorama_type = PANORAMA_FISHEYE_EQUIDISTANT; - else if(xml_equal_string(node, "panorama_type", "fisheye_equisolid")) - cam->panorama_type = PANORAMA_FISHEYE_EQUISOLID; - - xml_read_float(&cam->fisheye_fov, node, "fisheye_fov"); - xml_read_float(&cam->fisheye_lens, node, "fisheye_lens"); - - xml_read_bool(&cam->use_spherical_stereo, node, "use_spherical_stereo"); - xml_read_float(&cam->interocular_distance, node, "interocular_distance"); - xml_read_float(&cam->convergence_distance, node, "convergence_distance"); - - xml_read_float(&cam->sensorwidth, node, "sensorwidth"); - xml_read_float(&cam->sensorheight, node, "sensorheight"); + xml_read_node(state, cam, node); cam->matrix = state.tfm; @@ -345,6 +267,7 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml { xml_read_node(state, shader, graph_node); + ShaderManager *manager = state.scene->shader_manager; ShaderGraph *graph = new ShaderGraph(); map<string, ShaderNode*> nodemap; @@ -364,8 +287,8 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml xml_read_string(&img->filename, node, "src"); img->filename = path_join(state.base, img->filename); - xml_read_enum(&img->color_space, ImageTextureNode::color_space_enum, node, "color_space"); - xml_read_enum(&img->projection, ImageTextureNode::projection_enum, node, "projection"); + xml_read_enum_value((int*)&img->color_space, ImageTextureNode::color_space_enum, node, "color_space"); + xml_read_enum_value((int*)&img->projection, ImageTextureNode::projection_enum, node, "projection"); xml_read_float(&img->projection_blend, node, "projection_blend"); /* ToDo: Interpolation */ @@ -378,56 +301,40 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml xml_read_string(&env->filename, node, "src"); env->filename = path_join(state.base, env->filename); - xml_read_enum(&env->color_space, EnvironmentTextureNode::color_space_enum, node, "color_space"); - xml_read_enum(&env->projection, EnvironmentTextureNode::projection_enum, node, "projection"); + xml_read_enum_value((int*)&env->color_space, EnvironmentTextureNode::color_space_enum, node, "color_space"); + xml_read_enum_value((int*)&env->projection, EnvironmentTextureNode::projection_enum, node, "projection"); snode = env; } +#ifdef WITH_OSL else if(string_iequals(node.name(), "osl_shader")) { - OSLScriptNode *osl = new OSLScriptNode(); + if(manager->use_osl()) { + std::string filepath; - /* Source */ - xml_read_string(&osl->filepath, node, "src"); - if(path_is_relative(osl->filepath)) { - osl->filepath = path_join(state.base, osl->filepath); - } + if(xml_read_string(&filepath, node, "src")) { + if(path_is_relative(filepath)) { + filepath = path_join(state.base, filepath); + } - /* Generate inputs/outputs from node sockets - * - * Note: ShaderInput/ShaderOutput store shallow string copies only! - * So we register them as ustring to ensure the pointer stays valid. */ - /* read input values */ - for(pugi::xml_node param = node.first_child(); param; param = param.next_sibling()) { - if(string_iequals(param.name(), "input")) { - string name; - if(!xml_read_string(&name, param, "name")) - continue; - - ShaderSocketType type = xml_read_socket_type(param, "type"); - if(type == SHADER_SOCKET_UNDEFINED) - continue; - - osl->add_input(ustring(name).c_str(), type); + snode = ((OSLShaderManager*)manager)->osl_node(filepath); + + if(!snode) { + fprintf(stderr, "Failed to create OSL node from \"%s\".\n", filepath.c_str()); + } } - else if(string_iequals(param.name(), "output")) { - string name; - if(!xml_read_string(&name, param, "name")) - continue; - - ShaderSocketType type = xml_read_socket_type(param, "type"); - if(type == SHADER_SOCKET_UNDEFINED) - continue; - - osl->add_output(ustring(name).c_str(), type); + else { + fprintf(stderr, "OSL node missing \"src\" attribute.\n"); } } - - snode = osl; + else { + fprintf(stderr, "OSL node without using --shadingsys osl.\n"); + } } +#endif else if(string_iequals(node.name(), "sky_texture")) { SkyTextureNode *sky = new SkyTextureNode(); - xml_read_enum(&sky->type, SkyTextureNode::type_enum, node, "type"); + xml_read_enum_value((int*)&sky->type, SkyTextureNode::type_enum, node, "type"); xml_read_float3(&sky->sun_direction, node, "sun_direction"); xml_read_float(&sky->turbidity, node, "turbidity"); xml_read_float(&sky->ground_albedo, node, "ground_albedo"); @@ -452,17 +359,17 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml } else if(string_iequals(node.name(), "gradient_texture")) { GradientTextureNode *blend = new GradientTextureNode(); - xml_read_enum(&blend->type, GradientTextureNode::type_enum, node, "type"); + xml_read_enum_value((int*)&blend->type, GradientTextureNode::type_enum, node, "type"); snode = blend; } else if(string_iequals(node.name(), "voronoi_texture")) { VoronoiTextureNode *voronoi = new VoronoiTextureNode(); - xml_read_enum(&voronoi->coloring, VoronoiTextureNode::coloring_enum, node, "coloring"); + xml_read_enum_value((int*)&voronoi->coloring, VoronoiTextureNode::coloring_enum, node, "coloring"); snode = voronoi; } else if(string_iequals(node.name(), "musgrave_texture")) { MusgraveTextureNode *musgrave = new MusgraveTextureNode(); - xml_read_enum(&musgrave->type, MusgraveTextureNode::type_enum, node, "type"); + xml_read_enum_value((int*)&musgrave->type, MusgraveTextureNode::type_enum, node, "type"); snode = musgrave; } else if(string_iequals(node.name(), "magic_texture")) { @@ -472,8 +379,8 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml } else if(string_iequals(node.name(), "wave_texture")) { WaveTextureNode *wave = new WaveTextureNode(); - xml_read_enum(&wave->type, WaveTextureNode::type_enum, node, "type"); - xml_read_enum(&wave->profile, WaveTextureNode::profile_enum, node, "profile"); + xml_read_enum_value((int*)&wave->type, WaveTextureNode::type_enum, node, "type"); + xml_read_enum_value((int*)&wave->profile, WaveTextureNode::profile_enum, node, "profile"); snode = wave; } else if(string_iequals(node.name(), "normal")) { @@ -508,7 +415,7 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml } else if(string_iequals(node.name(), "anisotropic_bsdf")) { AnisotropicBsdfNode *aniso = new AnisotropicBsdfNode(); - xml_read_enum(&aniso->distribution, AnisotropicBsdfNode::distribution_enum, node, "distribution"); + xml_read_enum_value((int*)&aniso->distribution, AnisotropicBsdfNode::distribution_enum, node, "distribution"); snode = aniso; } else if(string_iequals(node.name(), "diffuse_bsdf")) { @@ -525,27 +432,27 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml } else if(string_iequals(node.name(), "toon_bsdf")) { ToonBsdfNode *toon = new ToonBsdfNode(); - xml_read_enum(&toon->component, ToonBsdfNode::component_enum, node, "component"); + xml_read_enum_value((int*)&toon->component, ToonBsdfNode::component_enum, node, "component"); snode = toon; } else if(string_iequals(node.name(), "glossy_bsdf")) { GlossyBsdfNode *glossy = new GlossyBsdfNode(); - xml_read_enum(&glossy->distribution, GlossyBsdfNode::distribution_enum, node, "distribution"); + xml_read_enum_value((int*)&glossy->distribution, GlossyBsdfNode::distribution_enum, node, "distribution"); snode = glossy; } else if(string_iequals(node.name(), "glass_bsdf")) { GlassBsdfNode *diel = new GlassBsdfNode(); - xml_read_enum(&diel->distribution, GlassBsdfNode::distribution_enum, node, "distribution"); + xml_read_enum_value((int*)&diel->distribution, GlassBsdfNode::distribution_enum, node, "distribution"); snode = diel; } else if(string_iequals(node.name(), "refraction_bsdf")) { RefractionBsdfNode *diel = new RefractionBsdfNode(); - xml_read_enum(&diel->distribution, RefractionBsdfNode::distribution_enum, node, "distribution"); + xml_read_enum_value((int*)&diel->distribution, RefractionBsdfNode::distribution_enum, node, "distribution"); snode = diel; } else if(string_iequals(node.name(), "hair_bsdf")) { HairBsdfNode *hair = new HairBsdfNode(); - xml_read_enum(&hair->component, HairBsdfNode::component_enum, node, "component"); + xml_read_enum_value((int*)&hair->component, HairBsdfNode::component_enum, node, "component"); snode = hair; } else if(string_iequals(node.name(), "emission")) { @@ -623,7 +530,7 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml else if(string_iequals(node.name(), "mix")) { /* ToDo: Tag Mix case for optimization */ MixNode *mix = new MixNode(); - xml_read_enum(&mix->type, MixNode::type_enum, node, "type"); + xml_read_enum_value((int*)&mix->type, MixNode::type_enum, node, "type"); xml_read_bool(&mix->use_clamp, node, "use_clamp"); snode = mix; } @@ -687,32 +594,32 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml else if(string_iequals(node.name(), "normal_map")) { NormalMapNode *nmap = new NormalMapNode; xml_read_ustring(&nmap->attribute, node, "attribute"); - xml_read_enum(&nmap->space, NormalMapNode::space_enum, node, "space"); + xml_read_enum_value((int*)&nmap->space, NormalMapNode::space_enum, node, "space"); snode = nmap; } else if(string_iequals(node.name(), "tangent")) { TangentNode *tangent = new TangentNode; xml_read_ustring(&tangent->attribute, node, "attribute"); - xml_read_enum(&tangent->direction_type, TangentNode::direction_type_enum, node, "direction_type"); - xml_read_enum(&tangent->axis, TangentNode::axis_enum, node, "axis"); + xml_read_enum_value((int*)&tangent->direction_type, TangentNode::direction_type_enum, node, "direction_type"); + xml_read_enum_value((int*)&tangent->axis, TangentNode::axis_enum, node, "axis"); snode = tangent; } else if(string_iequals(node.name(), "math")) { MathNode *math = new MathNode(); - xml_read_enum(&math->type, MathNode::type_enum, node, "type"); + xml_read_enum_value((int*)&math->type, MathNode::type_enum, node, "type"); xml_read_bool(&math->use_clamp, node, "use_clamp"); snode = math; } else if(string_iequals(node.name(), "vector_math")) { VectorMathNode *vmath = new VectorMathNode(); - xml_read_enum(&vmath->type, VectorMathNode::type_enum, node, "type"); + xml_read_enum_value((int*)&vmath->type, VectorMathNode::type_enum, node, "type"); snode = vmath; } else if(string_iequals(node.name(), "vector_transform")) { VectorTransformNode *vtransform = new VectorTransformNode(); - xml_read_enum(&vtransform->type, VectorTransformNode::type_enum, node, "type"); - xml_read_enum(&vtransform->convert_from, VectorTransformNode::convert_space_enum, node, "convert_from"); - xml_read_enum(&vtransform->convert_to, VectorTransformNode::convert_space_enum, node, "convert_to"); + xml_read_enum_value((int*)&vtransform->type, VectorTransformNode::type_enum, node, "type"); + xml_read_enum_value((int*)&vtransform->convert_from, VectorTransformNode::convert_space_enum, node, "convert_from"); + xml_read_enum_value((int*)&vtransform->convert_to, VectorTransformNode::convert_space_enum, node, "convert_to"); snode = vtransform; } else if(string_iequals(node.name(), "connect")) { @@ -731,7 +638,7 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml ShaderNode *fromnode = nodemap[from_tokens[0]]; foreach(ShaderOutput *out, fromnode->outputs) - if(string_iequals(xml_socket_name(out->name), from_tokens[1])) + if(string_iequals(xml_socket_name(out->name().c_str()), from_tokens[1])) output = out; if(!output) @@ -744,7 +651,7 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml ShaderNode *tonode = nodemap[to_tokens[0]]; foreach(ShaderInput *in, tonode->inputs) - if(string_iequals(xml_socket_name(in->name), to_tokens[1])) + if(string_iequals(xml_socket_name(in->name().c_str()), to_tokens[1])) input = in; if(!input) @@ -776,20 +683,20 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml /* read input values */ for(pugi::xml_attribute attr = node.first_attribute(); attr; attr = attr.next_attribute()) { foreach(ShaderInput *in, snode->inputs) { - if(string_iequals(in->name, attr.name())) { - switch(in->type) { - case SHADER_SOCKET_FLOAT: - case SHADER_SOCKET_INT: - xml_read_float(&in->value.x, node, attr.name()); + if(string_iequals(in->name().c_str(), attr.name())) { + switch(in->type()) { + case SocketType::FLOAT: + case SocketType::INT: + xml_read_float(&in->value_float(), node, attr.name()); break; - case SHADER_SOCKET_COLOR: - case SHADER_SOCKET_VECTOR: - case SHADER_SOCKET_POINT: - case SHADER_SOCKET_NORMAL: - xml_read_float3(&in->value, node, attr.name()); + case SocketType::COLOR: + case SocketType::VECTOR: + case SocketType::POINT: + case SocketType::NORMAL: + xml_read_float3(&in->value(), node, attr.name()); break; - case SHADER_SOCKET_STRING: - xml_read_ustring( &in->value_string, node, attr.name() ); + case SocketType::STRING: + xml_read_ustring( &in->value_string(), node, attr.name() ); break; default: break; @@ -908,6 +815,11 @@ static void xml_read_mesh(const XMLReadState& state, pugi::xml_node node) /* create vertices */ mesh->verts = P; + size_t num_triangles = 0; + for(size_t i = 0; i < nverts.size(); i++) + num_triangles += nverts[i]-2; + mesh->reserve_mesh(mesh->verts.size(), num_triangles); + /* create triangles */ int index_offset = 0; diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp index 9dec489ce33..f02fc553908 100644 --- a/intern/cycles/blender/blender_camera.cpp +++ b/intern/cycles/blender/blender_camera.cpp @@ -37,7 +37,7 @@ struct BlenderCamera { float lens; float shuttertime; Camera::MotionPosition motion_position; - float shutter_curve[RAMP_TABLE_SIZE]; + array<float> shutter_curve; Camera::RollingShutterType rolling_shutter_type; float rolling_shutter_duration; @@ -108,10 +108,6 @@ static void blender_camera_init(BlenderCamera *bcam, /* render resolution */ bcam->full_width = render_resolution_x(b_render); bcam->full_height = render_resolution_y(b_render); - - /* pixel aspect */ - bcam->pixelaspect.x = b_render.pixel_aspect_x(); - bcam->pixelaspect.y = b_render.pixel_aspect_y(); } static float blender_camera_focal_distance(BL::RenderEngine& b_engine, @@ -464,7 +460,7 @@ static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int cam->rolling_shutter_type = bcam->rolling_shutter_type; cam->rolling_shutter_duration = bcam->rolling_shutter_duration; - memcpy(cam->shutter_curve, bcam->shutter_curve, sizeof(cam->shutter_curve)); + cam->shutter_curve = bcam->shutter_curve; /* border */ cam->border = bcam->border; @@ -563,6 +559,10 @@ void BlenderSync::sync_camera_motion(BL::RenderSettings& b_render, float aspectratio, sensor_size; blender_camera_init(&bcam, b_render); + /* TODO(sergey): Consider making it a part of blender_camera_init(). */ + bcam.pixelaspect.x = b_render.pixel_aspect_x(); + bcam.pixelaspect.y = b_render.pixel_aspect_y(); + blender_camera_from_object(&bcam, b_engine, b_ob); blender_camera_viewplane(&bcam, width, height, diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp index 39521c841d1..7b9d4f2ecdf 100644 --- a/intern/cycles/blender/blender_curves.cpp +++ b/intern/cycles/blender/blender_curves.cpp @@ -134,10 +134,7 @@ void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, } } - mesh->verts.reserve(mesh->verts.size() + numverts); - mesh->triangles.reserve(mesh->triangles.size() + numtris); - mesh->shader.reserve(mesh->shader.size() + numtris); - mesh->smooth.reserve(mesh->smooth.size() + numtris); + mesh->reserve_mesh(mesh->verts.size() + numverts, mesh->num_triangles() + numtris); /* actually export */ for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) { @@ -157,8 +154,8 @@ void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, xbasis = normalize(cross(RotCam - ickey_loc, v1)); float3 ickey_loc_shfl = ickey_loc - radius * xbasis; float3 ickey_loc_shfr = ickey_loc + radius * xbasis; - mesh->verts.push_back(ickey_loc_shfl); - mesh->verts.push_back(ickey_loc_shfr); + mesh->add_vertex(ickey_loc_shfl); + mesh->add_vertex(ickey_loc_shfr); vertexindex += 2; for(int curvekey = CData->curve_firstkey[curve] + 1; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; curvekey++) { @@ -184,8 +181,8 @@ void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, xbasis = normalize(cross(RotCam - ickey_loc, v1)); float3 ickey_loc_shfl = ickey_loc - radius * xbasis; float3 ickey_loc_shfr = ickey_loc + radius * xbasis; - mesh->verts.push_back(ickey_loc_shfl); - mesh->verts.push_back(ickey_loc_shfr); + mesh->add_vertex(ickey_loc_shfl); + mesh->add_vertex(ickey_loc_shfr); mesh->add_triangle(vertexindex-2, vertexindex, vertexindex-1, CData->psys_shader[sys], true); mesh->add_triangle(vertexindex+1, vertexindex-1, vertexindex, CData->psys_shader[sys], true); vertexindex += 2; @@ -193,7 +190,6 @@ void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, } } - mesh->reserve(mesh->verts.size(), mesh->triangles.size(), 0, 0); mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); mesh->attributes.remove(ATTR_STD_FACE_NORMAL); mesh->add_face_normals(); @@ -220,10 +216,7 @@ void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resol } } - mesh->verts.reserve(mesh->verts.size() + numverts); - mesh->triangles.reserve(mesh->triangles.size() + numtris); - mesh->shader.reserve(mesh->shader.size() + numtris); - mesh->smooth.reserve(mesh->smooth.size() + numtris); + mesh->reserve_mesh(mesh->verts.size() + numverts, mesh->num_triangles() + numtris); /* actually export */ for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) { @@ -312,7 +305,7 @@ void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resol float angle = M_2PI_F / (float)resolution; for(int section = 0; section < resolution; section++) { float3 ickey_loc_shf = ickey_loc + radius * (cosf(angle * section) * xbasis + sinf(angle * section) * ybasis); - mesh->verts.push_back(ickey_loc_shf); + mesh->add_vertex(ickey_loc_shf); } if(subv != 0) { @@ -329,7 +322,6 @@ void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resol } } - mesh->reserve(mesh->verts.size(), mesh->triangles.size(), 0, 0); mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); mesh->attributes.remove(ATTR_STD_FACE_NORMAL); mesh->add_face_normals(); @@ -344,7 +336,7 @@ void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData) int num_keys = 0; int num_curves = 0; - if(!(mesh->curves.empty() && mesh->curve_keys.empty())) + if(mesh->num_curves()) return; Attribute *attr_intercept = NULL; @@ -367,8 +359,7 @@ void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData) VLOG(1) << "Exporting curve segments for mesh " << mesh->name; } - mesh->curve_keys.reserve(mesh->curve_keys.size() + num_keys); - mesh->curves.reserve(mesh->curves.size() + num_curves); + mesh->reserve_curves(mesh->num_curves() + num_curves, mesh->curve_keys.size() + num_keys); num_keys = 0; num_curves = 0; @@ -396,18 +387,16 @@ void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData) num_curve_keys++; } - mesh->add_curve(num_keys, num_curve_keys, CData->psys_shader[sys]); + mesh->add_curve(num_keys, CData->psys_shader[sys]); num_keys += num_curve_keys; num_curves++; } } /* check allocation */ - if((mesh->curve_keys.size() != num_keys) || (mesh->curves.size() != num_curves)) { + if((mesh->curve_keys.size() != num_keys) || (mesh->num_curves() != num_curves)) { VLOG(1) << "Allocation failed, clearing data"; - mesh->curve_keys.clear(); - mesh->curves.clear(); - mesh->curve_attributes.clear(); + mesh->clear(); } } @@ -450,13 +439,16 @@ static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int if(CData->psys_closetip[sys] && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)) radius = 0.0f; + /* curve motion keys store both position and radius in float4 */ mP[i] = float3_to_float4(ickey_loc); mP[i].w = radius; /* unlike mesh coordinates, these tend to be slightly different * between frames due to particle transforms into/out of object * space, so we use an epsilon to detect actual changes */ - if(len_squared(mP[i] - mesh->curve_keys[i]) > 1e-5f*1e-5f) + float4 curve_key = float3_to_float4(mesh->curve_keys[i]); + curve_key.w = mesh->curve_radius[i]; + if(len_squared(mP[i] - curve_key) > 1e-5f*1e-5f) have_motion = true; } @@ -480,8 +472,10 @@ static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int for(int step = 0; step < time_index; step++) { float4 *mP = attr_mP->data_float4() + step*numkeys; - for(int key = 0; key < numkeys; key++) - mP[key] = mesh->curve_keys[key]; + for(int key = 0; key < numkeys; key++) { + mP[key] = float3_to_float4(mesh->curve_keys[key]); + mP[key].w = mesh->curve_radius[key]; + } } } } @@ -641,7 +635,9 @@ void BlenderSync::sync_curves(Mesh *mesh, if(!motion) { /* Clear stored curve data */ mesh->curve_keys.clear(); - mesh->curves.clear(); + mesh->curve_radius.clear(); + mesh->curve_first_key.clear(); + mesh->curve_shader.clear(); mesh->curve_attributes.clear(); } @@ -658,7 +654,7 @@ void BlenderSync::sync_curves(Mesh *mesh, int triangle_method = scene->curve_system_manager->triangle_method; int resolution = scene->curve_system_manager->resolution; size_t vert_num = mesh->verts.size(); - size_t tri_num = mesh->triangles.size(); + size_t tri_num = mesh->num_triangles(); int used_res = 1; /* extract particle hair data - should be combined with connecting to mesh later*/ @@ -714,11 +710,10 @@ void BlenderSync::sync_curves(Mesh *mesh, else { Attribute *attr_generated = mesh->curve_attributes.add(ATTR_STD_GENERATED); float3 *generated = attr_generated->data_float3(); - size_t i = 0; - foreach(Mesh::Curve& curve, mesh->curves) { - float3 co = float4_to_float3(mesh->curve_keys[curve.first_key]); - generated[i++] = co*size - loc; + for(size_t i = 0; i < mesh->num_curves(); i++) { + float3 co = mesh->curve_keys[mesh->get_curve(i).first_key]; + generated[i] = co*size - loc; } } } diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index 4a0ad79f3ae..80db51148e6 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -548,13 +548,12 @@ static void create_mesh(Scene *scene, numtris += (vi[3] == 0)? 1: 2; } - /* reserve memory */ - mesh->reserve(numverts, numtris, 0, 0); + /* allocate memory */ + mesh->reserve_mesh(numverts, numtris); /* create vertex coordinates and normals */ - int i = 0; - for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++i) - mesh->verts[i] = get_float3(v->co()); + for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v) + mesh->add_vertex(get_float3(v->co())); Attribute *attr_N = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL); float3 *N = attr_N->data_float3(); @@ -583,7 +582,7 @@ static void create_mesh(Scene *scene, /* create faces */ vector<int> nverts(numfaces); vector<int> face_flags(numfaces, FACE_FLAG_NONE); - int fi = 0, ti = 0; + int fi = 0; for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f, ++fi) { int4 vi = get_int4(f->vertices_raw()); @@ -618,18 +617,18 @@ static void create_mesh(Scene *scene, is_zero(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]]))) { // TODO(mai): order here is probably wrong - mesh->set_triangle(ti++, vi[0], vi[1], vi[3], shader, smooth, true); - mesh->set_triangle(ti++, vi[2], vi[3], vi[1], shader, smooth, true); + mesh->add_triangle(vi[0], vi[1], vi[3], shader, smooth, true); + mesh->add_triangle(vi[2], vi[3], vi[1], shader, smooth, true); face_flags[fi] |= FACE_FLAG_DIVIDE_24; } else { - mesh->set_triangle(ti++, vi[0], vi[1], vi[2], shader, smooth, true); - mesh->set_triangle(ti++, vi[0], vi[2], vi[3], shader, smooth, true); + mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth, true); + mesh->add_triangle(vi[0], vi[2], vi[3], shader, smooth, true); face_flags[fi] |= FACE_FLAG_DIVIDE_13; } } else - mesh->set_triangle(ti++, vi[0], vi[1], vi[2], shader, smooth, false); + mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth, false); nverts[fi] = n; } @@ -759,11 +758,12 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, /* create derived mesh */ PointerRNA cmesh = RNA_pointer_get(&b_ob_data.ptr, "cycles"); - vector<Mesh::Triangle> oldtriangle = mesh->triangles; + array<int> oldtriangle = mesh->triangles; /* compares curve_keys rather than strands in order to handle quick hair * adjustments in dynamic BVH - other methods could probably do this better*/ - vector<float4> oldcurve_keys = mesh->curve_keys; + array<float3> oldcurve_keys = mesh->curve_keys; + array<float> oldcurve_radius = mesh->curve_radius; mesh->clear(); mesh->used_shaders = used_shaders; @@ -827,14 +827,21 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, if(oldtriangle.size() != mesh->triangles.size()) rebuild = true; else if(oldtriangle.size()) { - if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(Mesh::Triangle)*oldtriangle.size()) != 0) + if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(int)*oldtriangle.size()) != 0) rebuild = true; } if(oldcurve_keys.size() != mesh->curve_keys.size()) rebuild = true; else if(oldcurve_keys.size()) { - if(memcmp(&oldcurve_keys[0], &mesh->curve_keys[0], sizeof(float4)*oldcurve_keys.size()) != 0) + if(memcmp(&oldcurve_keys[0], &mesh->curve_keys[0], sizeof(float3)*oldcurve_keys.size()) != 0) + rebuild = true; + } + + if(oldcurve_radius.size() != mesh->curve_radius.size()) + rebuild = true; + else if(oldcurve_radius.size()) { + if(memcmp(&oldcurve_radius[0], &mesh->curve_radius[0], sizeof(float)*oldcurve_radius.size()) != 0) rebuild = true; } @@ -931,8 +938,8 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, Attribute *attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); if(attr_mP) { - float4 *keys = &mesh->curve_keys[0]; - memcpy(attr_mP->data_float4() + time_index*numkeys, keys, sizeof(float4)*numkeys); + float3 *keys = &mesh->curve_keys[0]; + memcpy(attr_mP->data_float3() + time_index*numkeys, keys, sizeof(float3)*numkeys); } } diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index a56c2e75e4e..7a13641a312 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -127,82 +127,57 @@ static float3 get_node_output_vector(BL::Node& b_node, const string& name) return make_float3(value[0], value[1], value[2]); } -static ShaderSocketType convert_socket_type(BL::NodeSocket& b_socket) +static SocketType::Type convert_socket_type(BL::NodeSocket& b_socket) { switch(b_socket.type()) { case BL::NodeSocket::type_VALUE: - return SHADER_SOCKET_FLOAT; + return SocketType::FLOAT; case BL::NodeSocket::type_INT: - return SHADER_SOCKET_INT; + return SocketType::INT; case BL::NodeSocket::type_VECTOR: - return SHADER_SOCKET_VECTOR; + return SocketType::VECTOR; case BL::NodeSocket::type_RGBA: - return SHADER_SOCKET_COLOR; + return SocketType::COLOR; case BL::NodeSocket::type_STRING: - return SHADER_SOCKET_STRING; + return SocketType::STRING; case BL::NodeSocket::type_SHADER: - return SHADER_SOCKET_CLOSURE; + return SocketType::CLOSURE; default: - return SHADER_SOCKET_UNDEFINED; + return SocketType::UNDEFINED; } } -#ifdef WITH_OSL -static ShaderSocketType convert_osl_socket_type(OSL::OSLQuery& query, - BL::NodeSocket& b_socket) -{ - ShaderSocketType socket_type = convert_socket_type(b_socket); - if(socket_type == SHADER_SOCKET_VECTOR) { - /* TODO(sergey): Do we need compatible_name() here? */ - const OSL::OSLQuery::Parameter *param = query.getparam(b_socket.name()); - assert(param != NULL); - if(param != NULL) { - if(param->type.vecsemantics == TypeDesc::POINT) { - socket_type = SHADER_SOCKET_POINT; - } - else if(param->type.vecsemantics == TypeDesc::NORMAL) { - socket_type = SHADER_SOCKET_NORMAL; - } - } - } - - return socket_type; -} -#endif /* WITH_OSL */ - static void set_default_value(ShaderInput *input, BL::NodeSocket& b_sock, BL::BlendData& b_data, BL::ID& b_id) { /* copy values for non linked inputs */ - switch(input->type) { - case SHADER_SOCKET_FLOAT: { + switch(input->type()) { + case SocketType::FLOAT: { input->set(get_float(b_sock.ptr, "default_value")); break; } - case SHADER_SOCKET_INT: { - input->set((float)get_int(b_sock.ptr, "default_value")); + case SocketType::INT: { + input->set(get_int(b_sock.ptr, "default_value")); break; } - case SHADER_SOCKET_COLOR: { + case SocketType::COLOR: { input->set(float4_to_float3(get_float4(b_sock.ptr, "default_value"))); break; } - case SHADER_SOCKET_NORMAL: - case SHADER_SOCKET_POINT: - case SHADER_SOCKET_VECTOR: { + case SocketType::NORMAL: + case SocketType::POINT: + case SocketType::VECTOR: { input->set(get_float3(b_sock.ptr, "default_value")); break; } - case SHADER_SOCKET_STRING: { + case SocketType::STRING: { input->set((ustring)blender_absolute_path(b_data, b_id, get_string(b_sock.ptr, "default_value"))); break; } - - case SHADER_SOCKET_CLOSURE: - case SHADER_SOCKET_UNDEFINED: + default: break; } } @@ -315,7 +290,7 @@ static ShaderNode *add_node(Scene *scene, else if(b_node.is_a(&RNA_ShaderNodeMixRGB)) { BL::ShaderNodeMixRGB b_mix_node(b_node); MixNode *mix = new MixNode(); - mix->type = MixNode::type_enum[b_mix_node.blend_type()]; + mix->type = (NodeMix)b_mix_node.blend_type(); mix->use_clamp = b_mix_node.use_clamp(); node = mix; } @@ -341,27 +316,27 @@ static ShaderNode *add_node(Scene *scene, node = new HSVNode(); } else if(b_node.is_a(&RNA_ShaderNodeRGBToBW)) { - node = new ConvertNode(SHADER_SOCKET_COLOR, SHADER_SOCKET_FLOAT); + node = new RGBToBWNode(); } else if(b_node.is_a(&RNA_ShaderNodeMath)) { BL::ShaderNodeMath b_math_node(b_node); MathNode *math = new MathNode(); - math->type = MathNode::type_enum[b_math_node.operation()]; + math->type = (NodeMath)b_math_node.operation(); math->use_clamp = b_math_node.use_clamp(); node = math; } else if(b_node.is_a(&RNA_ShaderNodeVectorMath)) { BL::ShaderNodeVectorMath b_vector_math_node(b_node); VectorMathNode *vmath = new VectorMathNode(); - vmath->type = VectorMathNode::type_enum[b_vector_math_node.operation()]; + vmath->type = (NodeVectorMath)b_vector_math_node.operation(); node = vmath; } else if(b_node.is_a(&RNA_ShaderNodeVectorTransform)) { BL::ShaderNodeVectorTransform b_vector_transform_node(b_node); VectorTransformNode *vtransform = new VectorTransformNode(); - vtransform->type = VectorTransformNode::type_enum[b_vector_transform_node.vector_type()]; - vtransform->convert_from = VectorTransformNode::convert_space_enum[b_vector_transform_node.convert_from()]; - vtransform->convert_to = VectorTransformNode::convert_space_enum[b_vector_transform_node.convert_to()]; + vtransform->type = (NodeVectorTransformType)b_vector_transform_node.vector_type(); + vtransform->convert_from = (NodeVectorTransformConvertSpace)b_vector_transform_node.convert_from(); + vtransform->convert_to = (NodeVectorTransformConvertSpace)b_vector_transform_node.convert_to(); node = vtransform; } else if(b_node.is_a(&RNA_ShaderNodeNormal)) { @@ -410,13 +385,13 @@ static ShaderNode *add_node(Scene *scene, switch(b_aniso_node.distribution()) { case BL::ShaderNodeBsdfAnisotropic::distribution_BECKMANN: - aniso->distribution = ustring("Beckmann"); + aniso->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID; break; case BL::ShaderNodeBsdfAnisotropic::distribution_GGX: - aniso->distribution = ustring("GGX"); + aniso->distribution = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID; break; case BL::ShaderNodeBsdfAnisotropic::distribution_ASHIKHMIN_SHIRLEY: - aniso->distribution = ustring("Ashikhmin-Shirley"); + aniso->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID; break; } @@ -432,13 +407,13 @@ static ShaderNode *add_node(Scene *scene, switch(b_subsurface_node.falloff()) { case BL::ShaderNodeSubsurfaceScattering::falloff_CUBIC: - subsurface->closure = CLOSURE_BSSRDF_CUBIC_ID; + subsurface->falloff = CLOSURE_BSSRDF_CUBIC_ID; break; case BL::ShaderNodeSubsurfaceScattering::falloff_GAUSSIAN: - subsurface->closure = CLOSURE_BSSRDF_GAUSSIAN_ID; + subsurface->falloff = CLOSURE_BSSRDF_GAUSSIAN_ID; break; case BL::ShaderNodeSubsurfaceScattering::falloff_BURLEY: - subsurface->closure = CLOSURE_BSSRDF_BURLEY_ID; + subsurface->falloff = CLOSURE_BSSRDF_BURLEY_ID; break; } @@ -450,16 +425,16 @@ static ShaderNode *add_node(Scene *scene, switch(b_glossy_node.distribution()) { case BL::ShaderNodeBsdfGlossy::distribution_SHARP: - glossy->distribution = ustring("Sharp"); + glossy->distribution = CLOSURE_BSDF_REFLECTION_ID; break; case BL::ShaderNodeBsdfGlossy::distribution_BECKMANN: - glossy->distribution = ustring("Beckmann"); + glossy->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_ID; break; case BL::ShaderNodeBsdfGlossy::distribution_GGX: - glossy->distribution = ustring("GGX"); + glossy->distribution = CLOSURE_BSDF_MICROFACET_GGX_ID; break; case BL::ShaderNodeBsdfGlossy::distribution_ASHIKHMIN_SHIRLEY: - glossy->distribution = ustring("Ashikhmin-Shirley"); + glossy->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID; break; } node = glossy; @@ -469,13 +444,13 @@ static ShaderNode *add_node(Scene *scene, GlassBsdfNode *glass = new GlassBsdfNode(); switch(b_glass_node.distribution()) { case BL::ShaderNodeBsdfGlass::distribution_SHARP: - glass->distribution = ustring("Sharp"); + glass->distribution = CLOSURE_BSDF_SHARP_GLASS_ID; break; case BL::ShaderNodeBsdfGlass::distribution_BECKMANN: - glass->distribution = ustring("Beckmann"); + glass->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID; break; case BL::ShaderNodeBsdfGlass::distribution_GGX: - glass->distribution = ustring("GGX"); + glass->distribution = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID; break; } node = glass; @@ -485,13 +460,13 @@ static ShaderNode *add_node(Scene *scene, RefractionBsdfNode *refraction = new RefractionBsdfNode(); switch(b_refraction_node.distribution()) { case BL::ShaderNodeBsdfRefraction::distribution_SHARP: - refraction->distribution = ustring("Sharp"); + refraction->distribution = CLOSURE_BSDF_REFRACTION_ID; break; case BL::ShaderNodeBsdfRefraction::distribution_BECKMANN: - refraction->distribution = ustring("Beckmann"); + refraction->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; break; case BL::ShaderNodeBsdfRefraction::distribution_GGX: - refraction->distribution = ustring("GGX"); + refraction->distribution = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; break; } node = refraction; @@ -501,10 +476,10 @@ static ShaderNode *add_node(Scene *scene, ToonBsdfNode *toon = new ToonBsdfNode(); switch(b_toon_node.component()) { case BL::ShaderNodeBsdfToon::component_DIFFUSE: - toon->component = ustring("Diffuse"); + toon->component = CLOSURE_BSDF_DIFFUSE_TOON_ID; break; case BL::ShaderNodeBsdfToon::component_GLOSSY: - toon->component = ustring("Glossy"); + toon->component = CLOSURE_BSDF_GLOSSY_TOON_ID; break; } node = toon; @@ -514,10 +489,10 @@ static ShaderNode *add_node(Scene *scene, HairBsdfNode *hair = new HairBsdfNode(); switch(b_hair_node.component()) { case BL::ShaderNodeBsdfHair::component_Reflection: - hair->component = ustring("Reflection"); + hair->component = CLOSURE_BSDF_HAIR_REFLECTION_ID; break; case BL::ShaderNodeBsdfHair::component_Transmission: - hair->component = ustring("Transmission"); + hair->component = CLOSURE_BSDF_HAIR_TRANSMISSION_ID; break; } node = hair; @@ -584,62 +559,17 @@ static ShaderNode *add_node(Scene *scene, if(scene->shader_manager->use_osl()) { /* create script node */ BL::ShaderNodeScript b_script_node(b_node); - OSLScriptNode *script_node = new OSLScriptNode(); OSLShaderManager *manager = (OSLShaderManager*)scene->shader_manager; string bytecode_hash = b_script_node.bytecode_hash(); - /* Gather additional information from the shader, such as - * input/output type info needed for proper node construction. - */ - OSL::OSLQuery query; - string absolute_filepath; - - if(!bytecode_hash.empty()) { - query.open_bytecode(b_script_node.bytecode()); - } - else { - absolute_filepath = blender_absolute_path(b_data, b_ntree, b_script_node.filepath()); - OSLShaderManager::osl_query(query, absolute_filepath); - } - /* TODO(sergey): Add proper query info error parsing. */ - - /* Generate inputs/outputs from node sockets - * - * Note: the node sockets are generated from OSL parameters, - * so the names match those of the corresponding parameters exactly. - * - * Note 2: ShaderInput/ShaderOutput store shallow string copies only! - * So we register them as ustring to ensure the pointer stays valid. */ - BL::Node::inputs_iterator b_input; - - for(b_script_node.inputs.begin(b_input); b_input != b_script_node.inputs.end(); ++b_input) { - ShaderInput *input = script_node->add_input(ustring(b_input->name()).c_str(), - convert_osl_socket_type(query, *b_input)); - set_default_value(input, *b_input, b_data, b_ntree); - } - - BL::Node::outputs_iterator b_output; - - for(b_script_node.outputs.begin(b_output); b_output != b_script_node.outputs.end(); ++b_output) { - script_node->add_output(ustring(b_output->name()).c_str(), - convert_osl_socket_type(query, *b_output)); - } - - /* load bytecode or filepath */ if(!bytecode_hash.empty()) { - /* loaded bytecode if not already done */ - if(!manager->shader_test_loaded(bytecode_hash)) - manager->shader_load_bytecode(bytecode_hash, b_script_node.bytecode()); - - script_node->bytecode_hash = bytecode_hash; + node = manager->osl_node("", bytecode_hash, b_script_node.bytecode()); } else { - /* set filepath */ - script_node->filepath = absolute_filepath; + string absolute_filepath = blender_absolute_path(b_data, b_ntree, b_script_node.filepath()); + node = manager->osl_node(absolute_filepath, ""); } - - node = script_node; } #else (void)b_data; @@ -692,8 +622,8 @@ static ShaderNode *add_node(Scene *scene, get_image_extension(b_image_node)); } } - image->color_space = ImageTextureNode::color_space_enum[(int)b_image_node.color_space()]; - image->projection = ImageTextureNode::projection_enum[(int)b_image_node.projection()]; + image->color_space = (NodeImageColorSpace)b_image_node.color_space(); + image->projection = (NodeImageProjection)b_image_node.projection(); image->interpolation = get_image_interpolation(b_image_node); image->extension = get_image_extension(b_image_node); image->projection_blend = b_image_node.projection_blend(); @@ -738,9 +668,9 @@ static ShaderNode *add_node(Scene *scene, EXTENSION_REPEAT); } } - env->color_space = EnvironmentTextureNode::color_space_enum[(int)b_env_node.color_space()]; + env->color_space = (NodeImageColorSpace)b_env_node.color_space(); env->interpolation = get_image_interpolation(b_env_node); - env->projection = EnvironmentTextureNode::projection_enum[(int)b_env_node.projection()]; + env->projection = (NodeEnvironmentProjection)b_env_node.projection(); BL::TexMapping b_texture_mapping(b_env_node.texture_mapping()); get_tex_mapping(&env->tex_mapping, b_texture_mapping); node = env; @@ -748,7 +678,7 @@ static ShaderNode *add_node(Scene *scene, else if(b_node.is_a(&RNA_ShaderNodeTexGradient)) { BL::ShaderNodeTexGradient b_gradient_node(b_node); GradientTextureNode *gradient = new GradientTextureNode(); - gradient->type = GradientTextureNode::type_enum[(int)b_gradient_node.gradient_type()]; + gradient->type = (NodeGradientType)b_gradient_node.gradient_type(); BL::TexMapping b_texture_mapping(b_gradient_node.texture_mapping()); get_tex_mapping(&gradient->tex_mapping, b_texture_mapping); node = gradient; @@ -756,7 +686,7 @@ static ShaderNode *add_node(Scene *scene, else if(b_node.is_a(&RNA_ShaderNodeTexVoronoi)) { BL::ShaderNodeTexVoronoi b_voronoi_node(b_node); VoronoiTextureNode *voronoi = new VoronoiTextureNode(); - voronoi->coloring = VoronoiTextureNode::coloring_enum[(int)b_voronoi_node.coloring()]; + voronoi->coloring = (NodeVoronoiColoring)b_voronoi_node.coloring(); BL::TexMapping b_texture_mapping(b_voronoi_node.texture_mapping()); get_tex_mapping(&voronoi->tex_mapping, b_texture_mapping); node = voronoi; @@ -772,8 +702,8 @@ static ShaderNode *add_node(Scene *scene, else if(b_node.is_a(&RNA_ShaderNodeTexWave)) { BL::ShaderNodeTexWave b_wave_node(b_node); WaveTextureNode *wave = new WaveTextureNode(); - wave->type = WaveTextureNode::type_enum[(int)b_wave_node.wave_type()]; - wave->profile = WaveTextureNode::profile_enum[(int)b_wave_node.wave_profile()]; + wave->type = (NodeWaveType)b_wave_node.wave_type(); + wave->profile = (NodeWaveProfile)b_wave_node.wave_profile(); BL::TexMapping b_texture_mapping(b_wave_node.texture_mapping()); get_tex_mapping(&wave->tex_mapping, b_texture_mapping); node = wave; @@ -806,7 +736,7 @@ static ShaderNode *add_node(Scene *scene, else if(b_node.is_a(&RNA_ShaderNodeTexMusgrave)) { BL::ShaderNodeTexMusgrave b_musgrave_node(b_node); MusgraveTextureNode *musgrave = new MusgraveTextureNode(); - musgrave->type = MusgraveTextureNode::type_enum[(int)b_musgrave_node.musgrave_type()]; + musgrave->type = (NodeMusgraveType)b_musgrave_node.musgrave_type(); BL::TexMapping b_texture_mapping(b_musgrave_node.texture_mapping()); get_tex_mapping(&musgrave->tex_mapping, b_texture_mapping); node = musgrave; @@ -824,7 +754,7 @@ static ShaderNode *add_node(Scene *scene, else if(b_node.is_a(&RNA_ShaderNodeTexSky)) { BL::ShaderNodeTexSky b_sky_node(b_node); SkyTextureNode *sky = new SkyTextureNode(); - sky->type = SkyTextureNode::type_enum[(int)b_sky_node.sky_type()]; + sky->type = (NodeSkyType)b_sky_node.sky_type(); sky->sun_direction = normalize(get_float3(b_sky_node.sun_direction())); sky->turbidity = b_sky_node.turbidity(); sky->ground_albedo = b_sky_node.ground_albedo(); @@ -835,15 +765,15 @@ static ShaderNode *add_node(Scene *scene, else if(b_node.is_a(&RNA_ShaderNodeNormalMap)) { BL::ShaderNodeNormalMap b_normal_map_node(b_node); NormalMapNode *nmap = new NormalMapNode(); - nmap->space = NormalMapNode::space_enum[(int)b_normal_map_node.space()]; + nmap->space = (NodeNormalMapSpace)b_normal_map_node.space(); nmap->attribute = b_normal_map_node.uv_map(); node = nmap; } else if(b_node.is_a(&RNA_ShaderNodeTangent)) { BL::ShaderNodeTangent b_tangent_node(b_node); TangentNode *tangent = new TangentNode(); - tangent->direction_type = TangentNode::direction_type_enum[(int)b_tangent_node.direction_type()]; - tangent->axis = TangentNode::axis_enum[(int)b_tangent_node.axis()]; + tangent->direction_type = (NodeTangentDirectionType)b_tangent_node.direction_type(); + tangent->axis = (NodeTangentAxis)b_tangent_node.axis(); tangent->attribute = b_tangent_node.uv_map(); node = tangent; } @@ -858,8 +788,7 @@ static ShaderNode *add_node(Scene *scene, BL::ShaderNodeTexPointDensity b_point_density_node(b_node); PointDensityTextureNode *point_density = new PointDensityTextureNode(); point_density->filename = b_point_density_node.name(); - point_density->space = - PointDensityTextureNode::space_enum[(int)b_point_density_node.space()]; + point_density->space = (NodeTexVoxelSpace)b_point_density_node.space(); point_density->interpolation = get_image_interpolation(b_point_density_node); point_density->builtin_data = b_point_density_node.ptr.data; @@ -1020,7 +949,7 @@ static void add_nodes(Scene *scene, BL::Node::internal_links_iterator b_link; for(b_node->internal_links.begin(b_link); b_link != b_node->internal_links.end(); ++b_link) { BL::NodeSocket to_socket(b_link->to_socket()); - ShaderSocketType to_socket_type = convert_socket_type(to_socket); + SocketType::Type to_socket_type = convert_socket_type(to_socket); ConvertNode *proxy = new ConvertNode(to_socket_type, to_socket_type, true); input_map[b_link->from_socket().ptr.data] = proxy->inputs[0]; @@ -1043,7 +972,7 @@ static void add_nodes(Scene *scene, * so that links have something to connect to and assert won't fail. */ for(b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) { - ShaderSocketType input_type = convert_socket_type(*b_input); + SocketType::Type input_type = convert_socket_type(*b_input); ConvertNode *proxy = new ConvertNode(input_type, input_type, true); graph->add(proxy); @@ -1055,7 +984,7 @@ static void add_nodes(Scene *scene, set_default_value(proxy->inputs[0], *b_input, b_data, b_ntree); } for(b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) { - ShaderSocketType output_type = convert_socket_type(*b_output); + SocketType::Type output_type = convert_socket_type(*b_output); ConvertNode *proxy = new ConvertNode(output_type, output_type, true); graph->add(proxy); @@ -1227,7 +1156,7 @@ void BlenderSync::sync_materials(bool update_all) ShaderNode *closure, *out; closure = graph->add(new DiffuseBsdfNode()); - closure->input("Color")->value = get_float3(b_mat->diffuse_color()); + closure->input("Color")->set(get_float3(b_mat->diffuse_color())); out = graph->output(); graph->connect(closure->output("BSDF"), out->input("Surface")); @@ -1276,7 +1205,7 @@ void BlenderSync::sync_world(bool update_all) ShaderNode *closure, *out; closure = graph->add(new BackgroundNode()); - closure->input("Color")->value = get_float3(b_world.horizon_color()); + closure->input("Color")->set(get_float3(b_world.horizon_color())); out = graph->output(); graph->connect(closure->output("Background"), out->input("Surface")); @@ -1369,8 +1298,8 @@ void BlenderSync::sync_lamps(bool update_all) } closure = graph->add(new EmissionNode()); - closure->input("Color")->value = get_float3(b_lamp->color()); - closure->input("Strength")->value.x = strength; + closure->input("Color")->set(get_float3(b_lamp->color())); + closure->input("Strength")->set(strength); out = graph->output(); graph->connect(closure->output("Emission"), out->input("Surface")); diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index 3e8856c8de6..89a53a1deca 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -98,11 +98,12 @@ static inline void curvemapping_minmax(/*const*/ BL::CurveMapping& cumap, } static inline void curvemapping_to_array(BL::CurveMapping& cumap, - float *data, + array<float>& data, int size) { cumap.update(); BL::CurveMap curve = cumap.curves[0]; + data.resize(size); for(int i = 0; i < size; i++) { float t = (float)i/(float)(size-1); data[i] = curve.evaluate(t); diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp index 5c474c8c3e9..fa2b9ae7279 100644 --- a/intern/cycles/bvh/bvh.cpp +++ b/intern/cycles/bvh/bvh.cpp @@ -128,11 +128,11 @@ void BVH::pack_triangle(int idx, float4 storage[3]) const Mesh *mesh = objects[tob]->mesh; int tidx = pack.prim_index[idx]; - const int *vidx = mesh->triangles[tidx].v; + Mesh::Triangle t = mesh->get_triangle(tidx); const float3* vpos = &mesh->verts[0]; - float3 v0 = vpos[vidx[0]]; - float3 v1 = vpos[vidx[1]]; - float3 v2 = vpos[vidx[2]]; + float3 v0 = vpos[t.v[0]]; + float3 v1 = vpos[t.v[1]]; + float3 v2 = vpos[t.v[2]]; storage[0] = float3_to_float4(v0); storage[1] = float3_to_float4(v1); @@ -506,10 +506,10 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility if(pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) { /* curves */ int str_offset = (params.top_level)? mesh->curve_offset: 0; - const Mesh::Curve& curve = mesh->curves[pidx - str_offset]; + Mesh::Curve curve = mesh->get_curve(pidx - str_offset); int k = PRIMITIVE_UNPACK_SEGMENT(pack.prim_type[prim]); - curve.bounds_grow(k, &mesh->curve_keys[0], bbox); + curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bbox); visibility |= PATH_RAY_CURVE; @@ -520,17 +520,17 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility if(attr) { size_t mesh_size = mesh->curve_keys.size(); size_t steps = mesh->motion_steps - 1; - float4 *key_steps = attr->data_float4(); + float3 *key_steps = attr->data_float3(); for(size_t i = 0; i < steps; i++) - curve.bounds_grow(k, key_steps + i*mesh_size, bbox); + curve.bounds_grow(k, key_steps + i*mesh_size, &mesh->curve_radius[0], bbox); } } } else { /* triangles */ int tri_offset = (params.top_level)? mesh->tri_offset: 0; - const Mesh::Triangle& triangle = mesh->triangles[pidx - tri_offset]; + Mesh::Triangle triangle = mesh->get_triangle(pidx - tri_offset); const float3 *vpos = &mesh->verts[0]; triangle.bounds_grow(vpos, bbox); @@ -770,10 +770,10 @@ void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility) if(pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) { /* Curves. */ int str_offset = (params.top_level)? mesh->curve_offset: 0; - const Mesh::Curve& curve = mesh->curves[pidx - str_offset]; + Mesh::Curve curve = mesh->get_curve(pidx - str_offset); int k = PRIMITIVE_UNPACK_SEGMENT(pack.prim_type[prim]); - curve.bounds_grow(k, &mesh->curve_keys[0], bbox); + curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bbox); visibility |= PATH_RAY_CURVE; @@ -784,17 +784,17 @@ void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility) if(attr) { size_t mesh_size = mesh->curve_keys.size(); size_t steps = mesh->motion_steps - 1; - float4 *key_steps = attr->data_float4(); + float3 *key_steps = attr->data_float3(); for(size_t i = 0; i < steps; i++) - curve.bounds_grow(k, key_steps + i*mesh_size, bbox); + curve.bounds_grow(k, key_steps + i*mesh_size, &mesh->curve_radius[0], bbox); } } } else { /* Triangles. */ int tri_offset = (params.top_level)? mesh->tri_offset: 0; - const Mesh::Triangle& triangle = mesh->triangles[pidx - tri_offset]; + Mesh::Triangle triangle = mesh->get_triangle(pidx - tri_offset); const float3 *vpos = &mesh->verts[0]; triangle.bounds_grow(vpos, bbox); diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index 76a1bfa2bfe..87a889955fe 100644 --- a/intern/cycles/bvh/bvh_build.cpp +++ b/intern/cycles/bvh/bvh_build.cpp @@ -117,8 +117,9 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, if(mesh->has_motion_blur()) attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - for(uint j = 0; j < mesh->triangles.size(); j++) { - Mesh::Triangle t = mesh->triangles[j]; + size_t num_triangles = mesh->num_triangles(); + for(uint j = 0; j < num_triangles; j++) { + Mesh::Triangle t = mesh->get_triangle(j); BoundBox bounds = BoundBox::empty; PrimitiveType type = PRIMITIVE_TRIANGLE; @@ -148,22 +149,23 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, if(mesh->has_motion_blur()) curve_attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - for(uint j = 0; j < mesh->curves.size(); j++) { - Mesh::Curve curve = mesh->curves[j]; + size_t num_curves = mesh->num_curves(); + for(uint j = 0; j < num_curves; j++) { + Mesh::Curve curve = mesh->get_curve(j); PrimitiveType type = PRIMITIVE_CURVE; for(int k = 0; k < curve.num_keys - 1; k++) { BoundBox bounds = BoundBox::empty; - curve.bounds_grow(k, &mesh->curve_keys[0], bounds); + curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bounds); /* motion curve */ if(curve_attr_mP) { size_t mesh_size = mesh->curve_keys.size(); size_t steps = mesh->motion_steps - 1; - float4 *key_steps = curve_attr_mP->data_float4(); + float3 *key_steps = curve_attr_mP->data_float3(); for(size_t i = 0; i < steps; i++) - curve.bounds_grow(k, key_steps + i*mesh_size, bounds); + curve.bounds_grow(k, key_steps + i*mesh_size, &mesh->curve_radius[0], bounds); type = PRIMITIVE_MOTION_CURVE; } @@ -188,10 +190,10 @@ void BVHBuild::add_reference_object(BoundBox& root, BoundBox& center, Object *ob static size_t count_curve_segments(Mesh *mesh) { - size_t num = 0, num_curves = mesh->curves.size(); + size_t num = 0, num_curves = mesh->num_curves(); for(size_t i = 0; i < num_curves; i++) - num += mesh->curves[i].num_keys - 1; + num += mesh->get_curve(i).num_keys - 1; return num; } @@ -204,14 +206,14 @@ void BVHBuild::add_references(BVHRange& root) foreach(Object *ob, objects) { if(params.top_level) { if(!ob->mesh->is_instanced()) { - num_alloc_references += ob->mesh->triangles.size(); + num_alloc_references += ob->mesh->num_triangles(); num_alloc_references += count_curve_segments(ob->mesh); } else num_alloc_references++; } else { - num_alloc_references += ob->mesh->triangles.size(); + num_alloc_references += ob->mesh->num_triangles(); num_alloc_references += count_curve_segments(ob->mesh); } } @@ -326,11 +328,11 @@ BVHNode* BVHBuild::run() VLOG(1) << "BVH build statistics:\n" << " Build time: " << time_dt() - build_start_time << "\n" << " Total number of nodes: " - << rootnode->getSubtreeSize(BVH_STAT_NODE_COUNT) << "\n" + << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_NODE_COUNT)) << "\n" << " Number of inner nodes: " - << rootnode->getSubtreeSize(BVH_STAT_INNER_COUNT) << "\n" + << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_INNER_COUNT)) << "\n" << " Number of leaf nodes: " - << rootnode->getSubtreeSize(BVH_STAT_LEAF_COUNT) << "\n" + << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_LEAF_COUNT)) << "\n" << " Allocation slop factor: " << ((prim_type.capacity() != 0) ? (float)prim_type.size() / prim_type.capacity() diff --git a/intern/cycles/bvh/bvh_split.cpp b/intern/cycles/bvh/bvh_split.cpp index 8084975565e..3665fb42bc2 100644 --- a/intern/cycles/bvh/bvh_split.cpp +++ b/intern/cycles/bvh/bvh_split.cpp @@ -292,13 +292,13 @@ void BVHSpatialSplit::split_triangle_primitive(const Mesh *mesh, BoundBox& left_bounds, BoundBox& right_bounds) { - const int *inds = mesh->triangles[prim_index].v; + Mesh::Triangle t = mesh->get_triangle(prim_index); const float3 *verts = &mesh->verts[0]; - float3 v1 = tfm ? transform_point(tfm, verts[inds[2]]) : verts[inds[2]]; + float3 v1 = tfm ? transform_point(tfm, verts[t.v[2]]) : verts[t.v[2]]; for(int i = 0; i < 3; i++) { float3 v0 = v1; - int vindex = inds[i]; + int vindex = t.v[i]; v1 = tfm ? transform_point(tfm, verts[vindex]) : verts[vindex]; float v0p = v0[dim]; float v1p = v1[dim]; @@ -329,12 +329,11 @@ void BVHSpatialSplit::split_curve_primitive(const Mesh *mesh, BoundBox& right_bounds) { /* curve split: NOTE - Currently ignores curve width and needs to be fixed.*/ - const int k0 = mesh->curves[prim_index].first_key + segment_index; + Mesh::Curve curve = mesh->get_curve(prim_index); + const int k0 = curve.first_key + segment_index; const int k1 = k0 + 1; - const float4& key0 = mesh->curve_keys[k0]; - const float4& key1 = mesh->curve_keys[k1]; - float3 v0 = float4_to_float3(key0); - float3 v1 = float4_to_float3(key1); + float3 v0 = mesh->curve_keys[k0]; + float3 v1 = mesh->curve_keys[k1]; if(tfm != NULL) { v0 = transform_point(tfm, v0); @@ -414,8 +413,8 @@ void BVHSpatialSplit::split_object_reference(const Object *object, left_bounds, right_bounds); } - for(int curve_idx = 0; curve_idx < mesh->curves.size(); ++curve_idx) { - Mesh::Curve &curve = mesh->curves[curve_idx]; + for(int curve_idx = 0; curve_idx < mesh->num_curves(); ++curve_idx) { + Mesh::Curve curve = mesh->get_curve(curve_idx); for(int segment_idx = 0; segment_idx < curve.num_keys - 1; ++segment_idx) diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp index 275ee028eb4..aed86d8d853 100644 --- a/intern/cycles/device/device_cpu.cpp +++ b/intern/cycles/device/device_cpu.cpp @@ -155,7 +155,9 @@ public: InterpolationType interpolation, ExtensionType extension) { - VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes."; + VLOG(1) << "Texture allocate: " << name << ", " + << string_human_readable_number(mem.memory_size()) << " bytes. (" + << string_human_readable_size(mem.memory_size()) << ")"; kernel_tex_copy(&kernel_globals, name, mem.data_pointer, diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index 9a78d055580..d7ed7b4f853 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -493,7 +493,9 @@ public: InterpolationType interpolation, ExtensionType extension) { - VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes."; + VLOG(1) << "Texture allocate: " << name << ", " + << string_human_readable_number(mem.memory_size()) << " bytes. (" + << string_human_readable_size(mem.memory_size()) << ")"; /* Check if we are on sm_30 or above. * We use arrays and bindles textures for storage there */ diff --git a/intern/cycles/device/device_multi.cpp b/intern/cycles/device/device_multi.cpp index 434d0085d39..c4f8d9e16e0 100644 --- a/intern/cycles/device/device_multi.cpp +++ b/intern/cycles/device/device_multi.cpp @@ -175,7 +175,9 @@ public: interpolation, ExtensionType extension) { - VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes."; + VLOG(1) << "Texture allocate: " << name << ", " + << string_human_readable_number(mem.memory_size()) << " bytes. (" + << string_human_readable_size(mem.memory_size()) << ")"; foreach(SubDevice& sub, devices) { mem.device_pointer = 0; diff --git a/intern/cycles/device/device_network.cpp b/intern/cycles/device/device_network.cpp index cf4a05de8fc..3eb5ad2d2db 100644 --- a/intern/cycles/device/device_network.cpp +++ b/intern/cycles/device/device_network.cpp @@ -168,7 +168,9 @@ public: InterpolationType interpolation, ExtensionType extension) { - VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes."; + VLOG(1) << "Texture allocate: " << name << ", " + << string_human_readable_number(mem.memory_size()) << " bytes. (" + << string_human_readable_size(mem.memory_size()) << ")"; thread_scoped_lock lock(rpc_lock); diff --git a/intern/cycles/device/device_opencl.cpp b/intern/cycles/device/device_opencl.cpp index 1b4e5421b5a..afe21c49730 100644 --- a/intern/cycles/device/device_opencl.cpp +++ b/intern/cycles/device/device_opencl.cpp @@ -1187,7 +1187,9 @@ public: InterpolationType /*interpolation*/, ExtensionType /*extension*/) { - VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes."; + VLOG(1) << "Texture allocate: " << name << ", " + << string_human_readable_number(mem.memory_size()) << " bytes. (" + << string_human_readable_size(mem.memory_size()) << ")"; mem_alloc(mem, MEM_READ_ONLY); mem_copy_to(mem); assert(mem_map.find(name) == mem_map.end()); @@ -1222,18 +1224,28 @@ public: CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t), &workgroup_size, NULL); clGetDeviceInfo(cdDevice, CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof(size_t)*3, max_work_items, NULL); - - /* try to divide evenly over 2 dimensions */ + + /* Try to divide evenly over 2 dimensions. */ size_t sqrt_workgroup_size = max((size_t)sqrt((double)workgroup_size), 1); size_t local_size[2] = {sqrt_workgroup_size, sqrt_workgroup_size}; - /* some implementations have max size 1 on 2nd dimension */ + /* Some implementations have max size 1 on 2nd dimension. */ if(local_size[1] > max_work_items[1]) { local_size[0] = workgroup_size/max_work_items[1]; local_size[1] = max_work_items[1]; } - size_t global_size[2] = {global_size_round_up(local_size[0], w), global_size_round_up(local_size[1], h)}; + size_t global_size[2] = {global_size_round_up(local_size[0], w), + global_size_round_up(local_size[1], h)}; + + /* Vertical size of 1 is coming from bake/shade kernels where we should + * not round anything up because otherwise we'll either be doing too + * much work per pixel (if we don't check global ID on Y axis) or will + * be checking for global ID to always have Y of 0. + */ + if (h == 1) { + global_size[h] = 1; + } /* run kernel */ opencl_assert(clEnqueueNDRangeKernel(cqCommandQueue, kernel, 2, NULL, global_size, NULL, 0, NULL, NULL)); @@ -1318,48 +1330,49 @@ public: else kernel = ckShaderKernel; - for(int sample = 0; sample < task.num_samples; sample++) { - - if(task.get_cancel()) - break; - - cl_int d_sample = sample; - - cl_uint start_arg_index = - kernel_set_args(kernel, - 0, - d_data, - d_input, - d_output); + cl_uint start_arg_index = + kernel_set_args(kernel, + 0, + d_data, + d_input, + d_output); - if(task.shader_eval_type < SHADER_EVAL_BAKE) { - start_arg_index += kernel_set_args(kernel, - start_arg_index, - d_output_luma); - } + if(task.shader_eval_type < SHADER_EVAL_BAKE) { + start_arg_index += kernel_set_args(kernel, + start_arg_index, + d_output_luma); + } #define KERNEL_TEX(type, ttype, name) \ - set_kernel_arg_mem(kernel, &start_arg_index, #name); + set_kernel_arg_mem(kernel, &start_arg_index, #name); #include "kernel_textures.h" #undef KERNEL_TEX + start_arg_index += kernel_set_args(kernel, + start_arg_index, + d_shader_eval_type); + if(task.shader_eval_type >= SHADER_EVAL_BAKE) { start_arg_index += kernel_set_args(kernel, start_arg_index, - d_shader_eval_type); - if(task.shader_eval_type >= SHADER_EVAL_BAKE) { - start_arg_index += kernel_set_args(kernel, - start_arg_index, - d_shader_filter); - } - start_arg_index += kernel_set_args(kernel, - start_arg_index, - d_shader_x, - d_shader_w, - d_offset, - d_sample); + d_shader_filter); + } + start_arg_index += kernel_set_args(kernel, + start_arg_index, + d_shader_x, + d_shader_w, + d_offset); + + for(int sample = 0; sample < task.num_samples; sample++) { + + if(task.get_cancel()) + break; + + kernel_set_args(kernel, start_arg_index, sample); enqueue_kernel(kernel, task.shader_w, 1); + clFinish(cqCommandQueue); + task.update_progress(NULL); } } diff --git a/intern/cycles/graph/node.cpp b/intern/cycles/graph/node.cpp index d482577b73b..941a66741c5 100644 --- a/intern/cycles/graph/node.cpp +++ b/intern/cycles/graph/node.cpp @@ -36,12 +36,8 @@ Node::Node(const NodeType *type_, ustring name_) } /* initialize default values */ - typedef unordered_map<ustring, SocketType, ustringHash> map_type; - foreach(const map_type::value_type& it, type->inputs) { - const SocketType& socket = it.second; - const void *src = socket.default_value; - void *dst = ((char*)this) + socket.struct_offset; - memcpy(dst, src, socket.size()); + foreach(const SocketType& socket, type->inputs) { + set_default_value(socket); } } @@ -104,6 +100,11 @@ void Node::set(const SocketType& input, float3 value) get_socket_value<float3>(this, input) = value; } +void Node::set(const SocketType& input, const char *value) +{ + set(input, ustring(value)); +} + void Node::set(const SocketType& input, ustring value) { if(input.type == SocketType::STRING) { @@ -292,7 +293,8 @@ const array<Node*>& Node::get_node_array(const SocketType& input) const return get_socket_value<array<Node*> >(this, input); } -/* default values */ +/* generic value operations */ + bool Node::has_default_value(const SocketType& input) const { const void *src = input.default_value; @@ -300,6 +302,48 @@ bool Node::has_default_value(const SocketType& input) const return memcmp(dst, src, input.size()) == 0; } +void Node::set_default_value(const SocketType& socket) +{ + const void *src = socket.default_value; + void *dst = ((char*)this) + socket.struct_offset; + memcpy(dst, src, socket.size()); +} + +template<typename T> +static void copy_array(const Node *node, const SocketType& socket, const Node *other, const SocketType& other_socket) +{ + const array<T>* src = (const array<T>*)(((char*)other) + other_socket.struct_offset); + array<T>* dst = (array<T>*)(((char*)node) + socket.struct_offset); + *dst = *src; +} + +void Node::copy_value(const SocketType& socket, const Node& other, const SocketType& other_socket) +{ + assert(socket.type == other_socket.type); + + if(socket.is_array()) { + switch(socket.type) { + case SocketType::BOOLEAN_ARRAY: copy_array<bool>(this, socket, &other, other_socket); break; + case SocketType::FLOAT_ARRAY: copy_array<float>(this, socket, &other, other_socket); break; + case SocketType::INT_ARRAY: copy_array<int>(this, socket, &other, other_socket); break; + case SocketType::COLOR_ARRAY: copy_array<float3>(this, socket, &other, other_socket); break; + case SocketType::VECTOR_ARRAY: copy_array<float3>(this, socket, &other, other_socket); break; + case SocketType::POINT_ARRAY: copy_array<float3>(this, socket, &other, other_socket); break; + case SocketType::NORMAL_ARRAY: copy_array<float3>(this, socket, &other, other_socket); break; + case SocketType::POINT2_ARRAY: copy_array<float2>(this, socket, &other, other_socket); break; + case SocketType::STRING_ARRAY: copy_array<ustring>(this, socket, &other, other_socket); break; + case SocketType::TRANSFORM_ARRAY: copy_array<Transform>(this, socket, &other, other_socket); break; + case SocketType::NODE_ARRAY: copy_array<void*>(this, socket, &other, other_socket); break; + default: assert(0); break; + } + } + else { + const void *src = ((char*)&other) + other_socket.struct_offset; + void *dst = ((char*)this) + socket.struct_offset; + memcpy(dst, src, socket.size()); + } +} + template<typename T> static bool is_array_equal(const Node *node, const Node *other, const SocketType& socket) { @@ -308,48 +352,43 @@ static bool is_array_equal(const Node *node, const Node *other, const SocketType return *a == *b; } -/* modified */ -bool Node::modified(const Node& other) +bool Node::equals_value(const Node& other, const SocketType& socket) const +{ + if(socket.is_array()) { + switch(socket.type) { + case SocketType::BOOLEAN_ARRAY: return is_array_equal<bool>(this, &other, socket); + case SocketType::FLOAT_ARRAY: return is_array_equal<float>(this, &other, socket); + case SocketType::INT_ARRAY: return is_array_equal<int>(this, &other, socket); + case SocketType::COLOR_ARRAY: return is_array_equal<float3>(this, &other, socket); + case SocketType::VECTOR_ARRAY: return is_array_equal<float3>(this, &other, socket); + case SocketType::POINT_ARRAY: return is_array_equal<float3>(this, &other, socket); + case SocketType::NORMAL_ARRAY: return is_array_equal<float3>(this, &other, socket); + case SocketType::POINT2_ARRAY: return is_array_equal<float2>(this, &other, socket); + case SocketType::STRING_ARRAY: return is_array_equal<ustring>(this, &other, socket); + case SocketType::TRANSFORM_ARRAY: return is_array_equal<Transform>(this, &other, socket); + case SocketType::NODE_ARRAY: return is_array_equal<void*>(this, &other, socket); + default: assert(0); return true; + } + } + else { + const void *a = ((char*)this) + socket.struct_offset; + const void *b = ((char*)&other) + socket.struct_offset; + return (memcmp(a, b, socket.size()) == 0); + } +} + +/* equals */ + +bool Node::equals(const Node& other) const { assert(type == other.type); - typedef unordered_map<ustring, SocketType, ustringHash> map_type; - foreach(const map_type::value_type& it, type->inputs) { - const SocketType& socket = it.second; - - if(socket.is_array()) { - bool equal = true; - - switch(socket.type) - { - case SocketType::BOOLEAN_ARRAY: equal = is_array_equal<bool>(this, &other, socket); break; - case SocketType::FLOAT_ARRAY: equal = is_array_equal<float>(this, &other, socket); break; - case SocketType::INT_ARRAY: equal = is_array_equal<int>(this, &other, socket); break; - case SocketType::COLOR_ARRAY: equal = is_array_equal<float3>(this, &other, socket); break; - case SocketType::VECTOR_ARRAY: equal = is_array_equal<float3>(this, &other, socket); break; - case SocketType::POINT_ARRAY: equal = is_array_equal<float3>(this, &other, socket); break; - case SocketType::NORMAL_ARRAY: equal = is_array_equal<float3>(this, &other, socket); break; - case SocketType::POINT2_ARRAY: equal = is_array_equal<float2>(this, &other, socket); break; - case SocketType::STRING_ARRAY: equal = is_array_equal<ustring>(this, &other, socket); break; - case SocketType::TRANSFORM_ARRAY: equal = is_array_equal<Transform>(this, &other, socket); break; - case SocketType::NODE_ARRAY: equal = is_array_equal<void*>(this, &other, socket); break; - default: assert(0); break; - } - - if(!equal) { - return true; - } - } - else { - const void *a = ((char*)this) + socket.struct_offset; - const void *b = ((char*)&other) + socket.struct_offset; - if(memcmp(a, b, socket.size()) != 0) { - return true; - } - } + foreach(const SocketType& socket, type->inputs) { + if(!equals_value(other, socket)) + return false; } - return false; + return true; } CCL_NAMESPACE_END diff --git a/intern/cycles/graph/node.h b/intern/cycles/graph/node.h index 33971fa714a..bb84f982fb3 100644 --- a/intern/cycles/graph/node.h +++ b/intern/cycles/graph/node.h @@ -41,6 +41,7 @@ struct Node void set(const SocketType& input, float value); void set(const SocketType& input, float2 value); void set(const SocketType& input, float3 value); + void set(const SocketType& input, const char *value); void set(const SocketType& input, ustring value); void set(const SocketType& input, const Transform& value); void set(const SocketType& input, Node *value); @@ -76,11 +77,14 @@ struct Node const array<Transform>& get_transform_array(const SocketType& input) const; const array<Node*>& get_node_array(const SocketType& input) const; - /* default values */ + /* generic values operations */ bool has_default_value(const SocketType& input) const; + void set_default_value(const SocketType& input); + bool equals_value(const Node& other, const SocketType& input) const; + void copy_value(const SocketType& input, const Node& other, const SocketType& other_input); - /* modified */ - bool modified(const Node& other); + /* equals */ + bool equals(const Node& other) const; ustring name; const NodeType *type; diff --git a/intern/cycles/graph/node_type.cpp b/intern/cycles/graph/node_type.cpp index dc879655d7f..7f68ae9c7c7 100644 --- a/intern/cycles/graph/node_type.cpp +++ b/intern/cycles/graph/node_type.cpp @@ -114,9 +114,15 @@ ustring SocketType::type_name(Type type) return names[(int)type]; } +bool SocketType::is_float3(Type type) +{ + return (type == COLOR || type == VECTOR || type == POINT || type == NORMAL); +} + /* Node Type */ -NodeType::NodeType() +NodeType::NodeType(Type type_) +: type(type_) { } @@ -137,7 +143,7 @@ void NodeType::register_input(ustring name, ustring ui_name, SocketType::Type ty socket.enum_values = enum_values; socket.node_type = node_type; socket.flags = flags | extra_flags; - inputs[name] = socket; + inputs.push_back(socket); } void NodeType::register_output(ustring name, ustring ui_name, SocketType::Type type) @@ -151,7 +157,29 @@ void NodeType::register_output(ustring name, ustring ui_name, SocketType::Type t socket.enum_values = NULL; socket.node_type = NULL; socket.flags = SocketType::LINKABLE; - outputs[name] = socket; + outputs.push_back(socket); +} + +const SocketType *NodeType::find_input(ustring name) const +{ + foreach(const SocketType& socket, inputs) { + if(socket.name == name) { + return &socket; + } + } + + return NULL; +} + +const SocketType *NodeType::find_output(ustring name) const +{ + foreach(const SocketType& socket, outputs) { + if(socket.name == name) { + return &socket; + } + } + + return NULL; } /* Node Type Registry */ @@ -162,7 +190,7 @@ unordered_map<ustring, NodeType, ustringHash>& NodeType::types() return _types; } -NodeType *NodeType::add(const char *name_, CreateFunc create_) +NodeType *NodeType::add(const char *name_, CreateFunc create_, Type type_) { ustring name(name_); @@ -172,7 +200,7 @@ NodeType *NodeType::add(const char *name_, CreateFunc create_) return NULL; } - types()[name] = NodeType(); + types()[name] = NodeType(type_); NodeType *type = &types()[name]; type->name = name; diff --git a/intern/cycles/graph/node_type.h b/intern/cycles/graph/node_type.h index 82ddd29da33..20816f634cd 100644 --- a/intern/cycles/graph/node_type.h +++ b/intern/cycles/graph/node_type.h @@ -21,6 +21,7 @@ #include "util_map.h" #include "util_param.h" #include "util_string.h" +#include "util_vector.h" CCL_NAMESPACE_BEGIN @@ -94,13 +95,19 @@ struct SocketType static size_t max_size(); static ustring type_name(Type type); static void *zero_default_value(); + static bool is_float3(Type type); }; /* Node Type */ struct NodeType { - explicit NodeType(); + enum Type { + NONE, + SHADER + }; + + explicit NodeType(Type type = NONE); ~NodeType(); void register_input(ustring name, ustring ui_name, SocketType::Type type, @@ -110,15 +117,18 @@ struct NodeType int flags = 0, int extra_flags = 0); void register_output(ustring name, ustring ui_name, SocketType::Type type); + const SocketType *find_input(ustring name) const; + const SocketType *find_output(ustring name) const; + typedef Node *(*CreateFunc)(const NodeType *type); - typedef unordered_map<ustring, SocketType, ustringHash> SocketMap; ustring name; - SocketMap inputs; - SocketMap outputs; + Type type; + std::vector<SocketType> inputs; + std::vector<SocketType> outputs; CreateFunc create; - static NodeType *add(const char *name, CreateFunc create); + static NodeType *add(const char *name, CreateFunc create, Type type = NONE); static const NodeType *find(ustring name); static unordered_map<ustring, NodeType, ustringHash>& types(); }; diff --git a/intern/cycles/graph/node_xml.cpp b/intern/cycles/graph/node_xml.cpp index fe06a243998..022de7cf32a 100644 --- a/intern/cycles/graph/node_xml.cpp +++ b/intern/cycles/graph/node_xml.cpp @@ -58,9 +58,7 @@ void xml_read_node(XMLReader& reader, Node *node, pugi::xml_node xml_node) node->name = ustring(name_attr.value()); } - foreach(const NodeType::SocketMap::value_type& it, node->type->inputs) { - const SocketType& socket = it.second; - + foreach(const SocketType& socket, node->type->inputs) { if(socket.type == SocketType::CLOSURE || socket.type == SocketType::UNDEFINED) { continue; } @@ -117,8 +115,9 @@ void xml_read_node(XMLReader& reader, Node *node, pugi::xml_node xml_node) array<int> value; value.resize(tokens.size()); - for(size_t i = 0; i < value.size(); i++) + for(size_t i = 0; i < value.size(); i++) { value[i] = (int)atoi(attr.value()); + } node->set(socket, value); break; } @@ -127,7 +126,7 @@ void xml_read_node(XMLReader& reader, Node *node, pugi::xml_node xml_node) case SocketType::POINT: case SocketType::NORMAL: { - array<float> value; + array<float3> value; xml_read_float_array<3>(value, attr); if(value.size() == 1) { node->set(socket, value[0]); @@ -161,11 +160,21 @@ void xml_read_node(XMLReader& reader, Node *node, pugi::xml_node xml_node) break; } case SocketType::STRING: - case SocketType::ENUM: { node->set(socket, attr.value()); break; } + case SocketType::ENUM: + { + ustring value(attr.value()); + if(socket.enum_values->exists(value)) { + node->set(socket, value); + } + else { + fprintf(stderr, "Unknown value \"%s\" for attribute \"%s\".\n", value.c_str(), socket.name.c_str()); + } + break; + } case SocketType::STRING_ARRAY: { vector<string> tokens; @@ -173,8 +182,9 @@ void xml_read_node(XMLReader& reader, Node *node, pugi::xml_node xml_node) array<ustring> value; value.resize(tokens.size()); - for(size_t i = 0; i < value.size(); i++) + for(size_t i = 0; i < value.size(); i++) { value[i] = ustring(tokens[i]); + } node->set(socket, value); break; } @@ -245,9 +255,7 @@ pugi::xml_node xml_write_node(Node *node, pugi::xml_node xml_root) xml_node.append_attribute("name") = node->name.c_str(); - foreach(const NodeType::SocketMap::value_type& it, node->type->inputs) { - const SocketType& socket = it.second; - + foreach(const SocketType& socket, node->type->inputs) { if(socket.type == SocketType::CLOSURE || socket.type == SocketType::UNDEFINED) { continue; } diff --git a/intern/cycles/kernel/geom/geom_bvh.h b/intern/cycles/kernel/geom/geom_bvh.h index 9eadc97386c..d0eedd3396a 100644 --- a/intern/cycles/kernel/geom/geom_bvh.h +++ b/intern/cycles/kernel/geom/geom_bvh.h @@ -48,6 +48,28 @@ CCL_NAMESPACE_BEGIN #define BVH_FEATURE(f) (((BVH_FUNCTION_FEATURES) & (f)) != 0) +/* Debugging heleprs */ +#ifdef __KERNEL_DEBUG__ +# define BVH_DEBUG_INIT() \ + do { \ + isect->num_traversal_steps = 0; \ + isect->num_traversed_instances = 0; \ + } while(0) +# define BVH_DEBUG_NEXT_STEP() \ + do { \ + ++isect->num_traversal_steps; \ + } while(0) +# define BVH_DEBUG_NEXT_INSTANCE() \ + do { \ + ++isect->num_traversed_instances; \ + } while(0) +#else /* __KERNEL_DEBUG__ */ +# define BVH_DEBUG_INIT() +# define BVH_DEBUG_NEXT_STEP() +# define BVH_DEBUG_NEXT_INSTANCE() +#endif /* __KERNEL_DEBUG__ */ + + /* Common QBVH functions. */ #ifdef __QBVH__ # include "geom_qbvh.h" diff --git a/intern/cycles/kernel/geom/geom_bvh_traversal.h b/intern/cycles/kernel/geom/geom_bvh_traversal.h index 8560612addc..ae919ef3f86 100644 --- a/intern/cycles/kernel/geom/geom_bvh_traversal.h +++ b/intern/cycles/kernel/geom/geom_bvh_traversal.h @@ -74,10 +74,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, isect->prim = PRIM_NONE; isect->object = OBJECT_NONE; -#if defined(__KERNEL_DEBUG__) - isect->num_traversal_steps = 0; - isect->num_traversed_instances = 0; -#endif + BVH_DEBUG_INIT(); #if defined(__KERNEL_SSE2__) const shuffle_swap_t shuf_identity = shuffle_swap_identity(); @@ -241,10 +238,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, --stackPtr; } } - -#if defined(__KERNEL_DEBUG__) - isect->num_traversal_steps++; -#endif + BVH_DEBUG_NEXT_STEP(); } /* if node is leaf, fetch triangle list */ @@ -266,9 +260,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, switch(type & PRIMITIVE_ALL) { case PRIMITIVE_TRIANGLE: { for(; primAddr < primAddr2; primAddr++) { -#if defined(__KERNEL_DEBUG__) - isect->num_traversal_steps++; -#endif + BVH_DEBUG_NEXT_STEP(); kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); if(triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, primAddr)) { /* shadow ray early termination */ @@ -287,9 +279,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, #if BVH_FEATURE(BVH_MOTION) case PRIMITIVE_MOTION_TRIANGLE: { for(; primAddr < primAddr2; primAddr++) { -# if defined(__KERNEL_DEBUG__) - isect->num_traversal_steps++; -# endif + BVH_DEBUG_NEXT_STEP(); kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); if(motion_triangle_intersect(kg, isect, P, dir, ray->time, visibility, object, primAddr)) { /* shadow ray early termination */ @@ -310,9 +300,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, case PRIMITIVE_CURVE: case PRIMITIVE_MOTION_CURVE: { for(; primAddr < primAddr2; primAddr++) { -# if defined(__KERNEL_DEBUG__) - isect->num_traversal_steps++; -# endif + BVH_DEBUG_NEXT_STEP(); kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); bool hit; if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) @@ -364,9 +352,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, nodeAddr = kernel_tex_fetch(__object_node, object); -# if defined(__KERNEL_DEBUG__) - isect->num_traversed_instances++; -# endif + BVH_DEBUG_NEXT_INSTANCE(); } } #endif /* FEATURE(BVH_INSTANCING) */ diff --git a/intern/cycles/kernel/geom/geom_qbvh_traversal.h b/intern/cycles/kernel/geom/geom_qbvh_traversal.h index ce3bbbdf957..738d08ac6fc 100644 --- a/intern/cycles/kernel/geom/geom_qbvh_traversal.h +++ b/intern/cycles/kernel/geom/geom_qbvh_traversal.h @@ -78,10 +78,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, isect->prim = PRIM_NONE; isect->object = OBJECT_NONE; -#if defined(__KERNEL_DEBUG__) - isect->num_traversal_steps = 0; - isect->num_traversed_instances = 0; -#endif + BVH_DEBUG_INIT(); ssef tnear(0.0f), tfar(ray->t); sse3f idir4(ssef(idir.x), ssef(idir.y), ssef(idir.z)); @@ -120,9 +117,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, int traverseChild; ssef dist; -#if defined(__KERNEL_DEBUG__) - isect->num_traversal_steps++; -#endif + BVH_DEBUG_NEXT_STEP(); #if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH) if(difl != 0.0f) { @@ -295,9 +290,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, switch(type & PRIMITIVE_ALL) { case PRIMITIVE_TRIANGLE: { for(; primAddr < primAddr2; primAddr++) { -#if defined(__KERNEL_DEBUG__) - isect->num_traversal_steps++; -#endif + BVH_DEBUG_NEXT_STEP(); kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); if(triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, primAddr)) { tfar = ssef(isect->t); @@ -311,9 +304,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, #if BVH_FEATURE(BVH_MOTION) case PRIMITIVE_MOTION_TRIANGLE: { for(; primAddr < primAddr2; primAddr++) { -# if defined(__KERNEL_DEBUG__) - isect->num_traversal_steps++; -# endif + BVH_DEBUG_NEXT_STEP(); kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); if(motion_triangle_intersect(kg, isect, P, dir, ray->time, visibility, object, primAddr)) { tfar = ssef(isect->t); @@ -329,9 +320,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, case PRIMITIVE_CURVE: case PRIMITIVE_MOTION_CURVE: { for(; primAddr < primAddr2; primAddr++) { -# if defined(__KERNEL_DEBUG__) - isect->num_traversal_steps++; -# endif + BVH_DEBUG_NEXT_STEP(); kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); bool hit; if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) @@ -381,9 +370,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, nodeAddr = kernel_tex_fetch(__object_node, object); -# if defined(__KERNEL_DEBUG__) - isect->num_traversed_instances++; -# endif + BVH_DEBUG_NEXT_INSTANCE(); } } #endif /* FEATURE(BVH_INSTANCING) */ diff --git a/intern/cycles/kernel/kernel_bake.h b/intern/cycles/kernel/kernel_bake.h index 77982ee548a..8d05befe1d4 100644 --- a/intern/cycles/kernel/kernel_bake.h +++ b/intern/cycles/kernel/kernel_bake.h @@ -30,8 +30,8 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian Ray ray; float3 throughput = make_float3(1.0f, 1.0f, 1.0f); - /* emission shader data memory used by various functions */ - ShaderData emission_sd; + /* emission and indirect shader data memory used by various functions */ + ShaderData emission_sd, indirect_sd; ray.P = sd->P + sd->Ng; ray.D = -sd->Ng; @@ -94,6 +94,7 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian &L_sample, &throughput); kernel_path_indirect(kg, + &indirect_sd, &emission_sd, &rng, &ray, @@ -117,7 +118,7 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian state.ray_t = 0.0f; #endif /* compute indirect light */ - kernel_path_indirect(kg, &emission_sd, &rng, &ray, throughput, 1, &state, &L_sample); + kernel_path_indirect(kg, &indirect_sd, &emission_sd, &rng, &ray, throughput, 1, &state, &L_sample); /* sum and reset indirect light pass variables for the next samples */ path_radiance_sum_indirect(&L_sample); @@ -144,7 +145,8 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian /* sample subsurface scattering */ if((pass_filter & BAKE_FILTER_SUBSURFACE) && (sd->flag & SD_BSSRDF)) { /* when mixing BSSRDF and BSDF closures we should skip BSDF lighting if scattering was successful */ - kernel_branched_path_subsurface_scatter(kg, sd, &emission_sd, &L_sample, &state, &rng, &ray, throughput); + kernel_branched_path_subsurface_scatter(kg, sd, &indirect_sd, + &emission_sd, &L_sample, &state, &rng, &ray, throughput); } #endif @@ -161,7 +163,7 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian /* indirect light */ kernel_branched_path_surface_indirect_light(kg, &rng, - sd, &emission_sd, throughput, 1.0f, &state, &L_sample); + sd, &indirect_sd, &emission_sd, throughput, 1.0f, &state, &L_sample); } } #endif @@ -480,12 +482,10 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, } /* write output */ - float output_fac = is_aa_pass(type)? 1.0f/num_samples: 1.0f; + const float output_fac = is_aa_pass(type)? 1.0f/num_samples: 1.0f; + const float4 scaled_result = make_float4(out.x, out.y, out.z, 1.0f) * output_fac; - if(sample == 0) - output[i] = make_float4(out.x, out.y, out.z, 1.0f) * output_fac; - else - output[i] += make_float4(out.x, out.y, out.z, 1.0f) * output_fac; + output[i] = (sample == 0)? scaled_result: output[i] + scaled_result; } #endif /* __BAKING__ */ diff --git a/intern/cycles/kernel/kernel_globals.h b/intern/cycles/kernel/kernel_globals.h index 7e6cdf93fb9..e06c68f2fc9 100644 --- a/intern/cycles/kernel/kernel_globals.h +++ b/intern/cycles/kernel/kernel_globals.h @@ -35,10 +35,10 @@ struct Intersection; struct VolumeStep; typedef struct KernelGlobals { - texture_image_uchar4 texture_byte4_images[TEX_NUM_BYTE4_IMAGES_CPU]; - texture_image_float4 texture_float4_images[TEX_NUM_FLOAT4_IMAGES_CPU]; - texture_image_float texture_float_images[TEX_NUM_FLOAT_IMAGES_CPU]; - texture_image_uchar texture_byte_images[TEX_NUM_BYTE_IMAGES_CPU]; + texture_image_uchar4 texture_byte4_images[TEX_NUM_BYTE4_CPU]; + texture_image_float4 texture_float4_images[TEX_NUM_FLOAT4_CPU]; + texture_image_float texture_float_images[TEX_NUM_FLOAT_CPU]; + texture_image_uchar texture_byte_images[TEX_NUM_BYTE_CPU]; # define KERNEL_TEX(type, ttype, name) ttype name; # define KERNEL_IMAGE_TEX(type, ttype, name) diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index 5527d8aa861..0dded397ffa 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -53,6 +53,7 @@ CCL_NAMESPACE_BEGIN ccl_device void kernel_path_indirect(KernelGlobals *kg, + ShaderData *sd, ShaderData *emission_sd, RNG *rng, Ray *ray, @@ -61,9 +62,6 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, PathState *state, PathRadiance *L) { - /* shader data memory used for both volumes and surfaces, saves stack space */ - ShaderData sd; - /* path iteration */ for(;;) { /* intersect scene */ @@ -121,12 +119,12 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, VolumeSegment volume_segment; shader_setup_from_volume(kg, - &sd, + sd, &volume_ray); kernel_volume_decoupled_record(kg, state, &volume_ray, - &sd, + sd, &volume_segment, heterogeneous); @@ -149,7 +147,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, /* direct light sampling */ kernel_branched_path_volume_connect_light(kg, rng, - &sd, + sd, emission_sd, throughput, state, @@ -167,7 +165,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, result = kernel_volume_decoupled_scatter(kg, state, &volume_ray, - &sd, + sd, &throughput, rphase, rscatter, @@ -182,7 +180,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, if(result == VOLUME_PATH_SCATTERED) { if(kernel_path_volume_bounce(kg, rng, - &sd, + sd, &throughput, state, L, @@ -203,14 +201,14 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, { /* integrate along volume segment with distance sampling */ VolumeIntegrateResult result = kernel_volume_integrate( - kg, state, &sd, &volume_ray, L, &throughput, rng, heterogeneous); + kg, state, sd, &volume_ray, L, &throughput, rng, heterogeneous); # ifdef __VOLUME_SCATTER__ if(result == VOLUME_PATH_SCATTERED) { /* direct lighting */ kernel_path_volume_connect_light(kg, rng, - &sd, + sd, emission_sd, throughput, state, @@ -219,7 +217,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, /* indirect light bounce */ if(kernel_path_volume_bounce(kg, rng, - &sd, + sd, &throughput, state, L, @@ -251,13 +249,13 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, /* setup shading */ shader_setup_from_ray(kg, - &sd, + sd, &isect, ray); float rbsdf = path_state_rng_1D_for_decision(kg, rng, state, PRNG_BSDF); - shader_eval_surface(kg, &sd, state, rbsdf, state->flag, SHADER_CONTEXT_INDIRECT); + shader_eval_surface(kg, sd, state, rbsdf, state->flag, SHADER_CONTEXT_INDIRECT); #ifdef __BRANCHED_PATH__ - shader_merge_closures(&sd); + shader_merge_closures(sd); #endif /* blurring of bsdf after bounces, for rays that have a small likelihood @@ -267,15 +265,15 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, if(blur_pdf < 1.0f) { float blur_roughness = sqrtf(1.0f - blur_pdf)*0.5f; - shader_bsdf_blur(kg, &sd, blur_roughness); + shader_bsdf_blur(kg, sd, blur_roughness); } } #ifdef __EMISSION__ /* emission */ - if(sd.flag & SD_EMISSION) { + if(sd->flag & SD_EMISSION) { float3 emission = indirect_primitive_emission(kg, - &sd, + sd, isect.t, state->flag, state->ray_pdf); @@ -305,30 +303,30 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, #ifdef __AO__ /* ambient occlusion */ - if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) { + if(kernel_data.integrator.use_ambient_occlusion || (sd->flag & SD_AO)) { float bsdf_u, bsdf_v; path_state_rng_2D(kg, rng, state, PRNG_BSDF_U, &bsdf_u, &bsdf_v); float ao_factor = kernel_data.background.ao_factor; float3 ao_N; - float3 ao_bsdf = shader_bsdf_ao(kg, &sd, ao_factor, &ao_N); + float3 ao_bsdf = shader_bsdf_ao(kg, sd, ao_factor, &ao_N); float3 ao_D; float ao_pdf; float3 ao_alpha = make_float3(0.0f, 0.0f, 0.0f); sample_cos_hemisphere(ao_N, bsdf_u, bsdf_v, &ao_D, &ao_pdf); - if(dot(sd.Ng, ao_D) > 0.0f && ao_pdf != 0.0f) { + if(dot(sd->Ng, ao_D) > 0.0f && ao_pdf != 0.0f) { Ray light_ray; float3 ao_shadow; - light_ray.P = ray_offset(sd.P, sd.Ng); + light_ray.P = ray_offset(sd->P, sd->Ng); light_ray.D = ao_D; light_ray.t = kernel_data.background.ao_distance; # ifdef __OBJECT_MOTION__ - light_ray.time = sd.time; + light_ray.time = sd->time; # endif - light_ray.dP = sd.dP; + light_ray.dP = sd->dP; light_ray.dD = differential3_zero(); if(!shadow_blocked(kg, emission_sd, state, &light_ray, &ao_shadow)) { @@ -346,9 +344,9 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, #ifdef __SUBSURFACE__ /* bssrdf scatter to a different location on the same object, replacing * the closures with a diffuse BSDF */ - if(sd.flag & SD_BSSRDF) { + if(sd->flag & SD_BSSRDF) { float bssrdf_probability; - ShaderClosure *sc = subsurface_scatter_pick_closure(kg, &sd, &bssrdf_probability); + ShaderClosure *sc = subsurface_scatter_pick_closure(kg, sd, &bssrdf_probability); /* modify throughput for picking bssrdf or bsdf */ throughput *= bssrdf_probability; @@ -364,7 +362,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, PRNG_BSDF_U, &bssrdf_u, &bssrdf_v); subsurface_scatter_step(kg, - &sd, + sd, state, state->flag, sc, @@ -380,7 +378,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, int all = kernel_data.integrator.sample_all_lights_indirect; kernel_branched_path_surface_connect_light(kg, rng, - &sd, + sd, emission_sd, state, throughput, @@ -390,7 +388,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, } #endif - if(!kernel_path_surface_bounce(kg, rng, &sd, &throughput, state, L, ray)) + if(!kernel_path_surface_bounce(kg, rng, sd, &throughput, state, L, ray)) break; } } diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h index b4dee220aa5..fdba1a7b025 100644 --- a/intern/cycles/kernel/kernel_path_branched.h +++ b/intern/cycles/kernel/kernel_path_branched.h @@ -64,8 +64,8 @@ ccl_device void kernel_branched_path_ao(KernelGlobals *kg, /* bounce off surface and integrate indirect light */ ccl_device_noinline void kernel_branched_path_surface_indirect_light(KernelGlobals *kg, - RNG *rng, ShaderData *sd, ShaderData *emission_sd, float3 throughput, - float num_samples_adjust, PathState *state, PathRadiance *L) + RNG *rng, ShaderData *sd, ShaderData *indirect_sd, ShaderData *emission_sd, + float3 throughput, float num_samples_adjust, PathState *state, PathRadiance *L) { for(int i = 0; i < ccl_fetch(sd, num_closure); i++) { const ShaderClosure *sc = &ccl_fetch(sd, closure)[i]; @@ -112,6 +112,7 @@ ccl_device_noinline void kernel_branched_path_surface_indirect_light(KernelGloba } kernel_path_indirect(kg, + indirect_sd, emission_sd, rng, &bsdf_ray, @@ -131,6 +132,7 @@ ccl_device_noinline void kernel_branched_path_surface_indirect_light(KernelGloba #ifdef __SUBSURFACE__ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg, ShaderData *sd, + ShaderData *indirect_sd, ShaderData *emission_sd, PathRadiance *L, PathState *state, @@ -222,6 +224,7 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg, kg, rng, &bssrdf_sd, + indirect_sd, emission_sd, throughput, num_samples_inv, @@ -244,8 +247,8 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in /* shader data memory used for both volumes and surfaces, saves stack space */ ShaderData sd; - /* shader data used by emission, shadows, volume stacks */ - ShaderData emission_sd; + /* shader data used by emission, shadows, volume stacks, indirect path */ + ShaderData emission_sd, indirect_sd; PathState state; path_state_init(kg, &emission_sd, &state, rng, sample, &ray); @@ -356,6 +359,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in &pray)) { kernel_path_indirect(kg, + &indirect_sd, &emission_sd, rng, &pray, @@ -413,6 +417,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in &pray)) { kernel_path_indirect(kg, + &indirect_sd, &emission_sd, rng, &pray, @@ -522,8 +527,8 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in #ifdef __SUBSURFACE__ /* bssrdf scatter to a different location on the same object */ if(sd.flag & SD_BSSRDF) { - kernel_branched_path_subsurface_scatter(kg, &sd, &emission_sd, &L, &state, - rng, &ray, throughput); + kernel_branched_path_subsurface_scatter(kg, &sd, &indirect_sd, &emission_sd, + &L, &state, rng, &ray, throughput); } #endif @@ -541,7 +546,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in /* indirect light */ kernel_branched_path_surface_indirect_light(kg, rng, - &sd, &emission_sd, throughput, 1.0f, &hit_state, &L); + &sd, &indirect_sd, &emission_sd, throughput, 1.0f, &hit_state, &L); /* continue in case of transparency */ throughput *= shader_bsdf_transparency(kg, &sd); diff --git a/intern/cycles/kernel/kernel_shadow.h b/intern/cycles/kernel/kernel_shadow.h index c8f6503cf58..1abbbb2ddad 100644 --- a/intern/cycles/kernel/kernel_shadow.h +++ b/intern/cycles/kernel/kernel_shadow.h @@ -126,8 +126,6 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, ShaderData *shadow_sd, /* stop if all light is blocked */ if(is_zero(throughput)) { /* free dynamic storage */ - if(hits != hits_stack) - free(hits); return true; } diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index ba50d180acf..1ffcfb94a15 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -121,9 +121,7 @@ CCL_NAMESPACE_BEGIN # define __OBJECT_MOTION__ # define __HAIR__ # define __BAKING__ -# ifdef __KERNEL_EXPERIMENTAL__ -# define __TRANSPARENT_SHADOWS__ -# endif +# define __TRANSPARENT_SHADOWS__ # endif /* __KERNEL_OPENCL_AMD__ */ # ifdef __KERNEL_OPENCL_INTEL_CPU__ diff --git a/intern/cycles/kernel/kernels/cpu/kernel.cpp b/intern/cycles/kernel/kernels/cpu/kernel.cpp index 365ce891354..d8a83f69685 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel.cpp +++ b/intern/cycles/kernel/kernels/cpu/kernel.cpp @@ -95,7 +95,7 @@ void kernel_tex_copy(KernelGlobals *kg, int id = atoi(name + strlen("__tex_image_float4_")); int array_index = id; - if(array_index >= 0 && array_index < TEX_NUM_FLOAT4_IMAGES_CPU) { + if(array_index >= 0 && array_index < TEX_NUM_FLOAT4_CPU) { tex = &kg->texture_float4_images[array_index]; } @@ -109,9 +109,9 @@ void kernel_tex_copy(KernelGlobals *kg, else if(strstr(name, "__tex_image_float")) { texture_image_float *tex = NULL; int id = atoi(name + strlen("__tex_image_float_")); - int array_index = id - TEX_IMAGE_FLOAT_START_CPU; + int array_index = id - TEX_START_FLOAT_CPU; - if(array_index >= 0 && array_index < TEX_NUM_FLOAT_IMAGES_CPU) { + if(array_index >= 0 && array_index < TEX_NUM_FLOAT_CPU) { tex = &kg->texture_float_images[array_index]; } @@ -125,9 +125,9 @@ void kernel_tex_copy(KernelGlobals *kg, else if(strstr(name, "__tex_image_byte4")) { texture_image_uchar4 *tex = NULL; int id = atoi(name + strlen("__tex_image_byte4_")); - int array_index = id - TEX_IMAGE_BYTE4_START_CPU; + int array_index = id - TEX_START_BYTE4_CPU; - if(array_index >= 0 && array_index < TEX_NUM_BYTE4_IMAGES_CPU) { + if(array_index >= 0 && array_index < TEX_NUM_BYTE4_CPU) { tex = &kg->texture_byte4_images[array_index]; } @@ -141,9 +141,9 @@ void kernel_tex_copy(KernelGlobals *kg, else if(strstr(name, "__tex_image_byte")) { texture_image_uchar *tex = NULL; int id = atoi(name + strlen("__tex_image_byte_")); - int array_index = id - TEX_IMAGE_BYTE_START_CPU; + int array_index = id - TEX_START_BYTE_CPU; - if(array_index >= 0 && array_index < TEX_NUM_BYTE_IMAGES_CPU) { + if(array_index >= 0 && array_index < TEX_NUM_BYTE_CPU) { tex = &kg->texture_byte_images[array_index]; } diff --git a/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h b/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h index 4807f96a0df..b10861ab857 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h +++ b/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h @@ -23,24 +23,24 @@ CCL_NAMESPACE_BEGIN ccl_device float4 kernel_tex_image_interp_impl(KernelGlobals *kg, int tex, float x, float y) { - if(tex >= TEX_IMAGE_BYTE_START_CPU) - return kg->texture_byte_images[tex - TEX_IMAGE_BYTE_START_CPU].interp(x, y); - else if(tex >= TEX_IMAGE_FLOAT_START_CPU) - return kg->texture_float_images[tex - TEX_IMAGE_FLOAT_START_CPU].interp(x, y); - else if(tex >= TEX_IMAGE_BYTE4_START_CPU) - return kg->texture_byte4_images[tex - TEX_IMAGE_BYTE4_START_CPU].interp(x, y); + if(tex >= TEX_START_BYTE_CPU) + return kg->texture_byte_images[tex - TEX_START_BYTE_CPU].interp(x, y); + else if(tex >= TEX_START_FLOAT_CPU) + return kg->texture_float_images[tex - TEX_START_FLOAT_CPU].interp(x, y); + else if(tex >= TEX_START_BYTE4_CPU) + return kg->texture_byte4_images[tex - TEX_START_BYTE4_CPU].interp(x, y); else return kg->texture_float4_images[tex].interp(x, y); } ccl_device float4 kernel_tex_image_interp_3d_impl(KernelGlobals *kg, int tex, float x, float y, float z) { - if(tex >= TEX_IMAGE_BYTE_START_CPU) - return kg->texture_byte_images[tex - TEX_IMAGE_BYTE_START_CPU].interp_3d(x, y, z); - else if(tex >= TEX_IMAGE_FLOAT_START_CPU) - return kg->texture_float_images[tex - TEX_IMAGE_FLOAT_START_CPU].interp_3d(x, y, z); - else if(tex >= TEX_IMAGE_BYTE4_START_CPU) - return kg->texture_byte4_images[tex - TEX_IMAGE_BYTE4_START_CPU].interp_3d(x, y, z); + if(tex >= TEX_START_BYTE_CPU) + return kg->texture_byte_images[tex - TEX_START_BYTE_CPU].interp_3d(x, y, z); + else if(tex >= TEX_START_FLOAT_CPU) + return kg->texture_float_images[tex - TEX_START_FLOAT_CPU].interp_3d(x, y, z); + else if(tex >= TEX_START_BYTE4_CPU) + return kg->texture_byte4_images[tex - TEX_START_BYTE4_CPU].interp_3d(x, y, z); else return kg->texture_float4_images[tex].interp_3d(x, y, z); @@ -48,12 +48,12 @@ ccl_device float4 kernel_tex_image_interp_3d_impl(KernelGlobals *kg, int tex, fl ccl_device float4 kernel_tex_image_interp_3d_ex_impl(KernelGlobals *kg, int tex, float x, float y, float z, int interpolation) { - if(tex >= TEX_IMAGE_BYTE_START_CPU) - return kg->texture_byte_images[tex - TEX_IMAGE_BYTE_START_CPU].interp_3d_ex(x, y, z, interpolation); - else if(tex >= TEX_IMAGE_FLOAT_START_CPU) - return kg->texture_float_images[tex - TEX_IMAGE_FLOAT_START_CPU].interp_3d_ex(x, y, z, interpolation); - else if(tex >= TEX_IMAGE_BYTE4_START_CPU) - return kg->texture_byte4_images[tex - TEX_IMAGE_BYTE4_START_CPU].interp_3d_ex(x, y, z, interpolation); + if(tex >= TEX_START_BYTE_CPU) + return kg->texture_byte_images[tex - TEX_START_BYTE_CPU].interp_3d_ex(x, y, z, interpolation); + else if(tex >= TEX_START_FLOAT_CPU) + return kg->texture_float_images[tex - TEX_START_FLOAT_CPU].interp_3d_ex(x, y, z, interpolation); + else if(tex >= TEX_START_BYTE4_CPU) + return kg->texture_byte4_images[tex - TEX_START_BYTE4_CPU].interp_3d_ex(x, y, z, interpolation); else return kg->texture_float4_images[tex].interp_3d_ex(x, y, z, interpolation); } diff --git a/intern/cycles/kernel/shaders/node_brick_texture.osl b/intern/cycles/kernel/shaders/node_brick_texture.osl index 35e01178ba8..d5e0a7d4c8c 100644 --- a/intern/cycles/kernel/shaders/node_brick_texture.osl +++ b/intern/cycles/kernel/shaders/node_brick_texture.osl @@ -59,10 +59,10 @@ float brick(point p, float mortar_size, float bias, shader node_brick_texture( int use_mapping = 0, matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - float Offset = 0.5, - int OffsetFrequency = 2, - float Squash = 1.0, - int SquashFrequency = 1, + float offset = 0.5, + int offset_frequency = 2, + float squash = 1.0, + int squash_frequency = 1, point Vector = P, color Color1 = 0.2, color Color2 = 0.8, @@ -84,7 +84,7 @@ shader node_brick_texture( color Col = Color1; Fac = brick(p * Scale, MortarSize, Bias, BrickWidth, RowHeight, - Offset, OffsetFrequency, Squash, SquashFrequency, tint); + offset, offset_frequency, squash, squash_frequency, tint); if (Fac != 1.0) { float facm = 1.0 - tint; diff --git a/intern/cycles/kernel/shaders/node_convert_from_color.osl b/intern/cycles/kernel/shaders/node_convert_from_color.osl index 44074317f42..e95a17f6fa1 100644 --- a/intern/cycles/kernel/shaders/node_convert_from_color.osl +++ b/intern/cycles/kernel/shaders/node_convert_from_color.osl @@ -17,18 +17,18 @@ #include "stdosl.h" shader node_convert_from_color( - color Color = 0.0, - output string String = "", - output float Val = 0.0, - output int ValInt = 0, - output vector Vector = vector(0.0, 0.0, 0.0), - output point Point = point(0.0, 0.0, 0.0), - output normal Normal = normal(0.0, 0.0, 0.0)) + color value_color = 0.0, + output string value_string = "", + output float value_float = 0.0, + output int value_int = 0, + output vector value_vector = vector(0.0, 0.0, 0.0), + output point value_point = point(0.0, 0.0, 0.0), + output normal value_normal = normal(0.0, 0.0, 0.0)) { - Val = Color[0] * 0.2126 + Color[1] * 0.7152 + Color[2] * 0.0722; - ValInt = (int)(Color[0] * 0.2126 + Color[1] * 0.7152 + Color[2] * 0.0722); - Vector = vector(Color[0], Color[1], Color[2]); - Point = point(Color[0], Color[1], Color[2]); - Normal = normal(Color[0], Color[1], Color[2]); + value_float = value_color[0] * 0.2126 + value_color[1] * 0.7152 + value_color[2] * 0.0722; + value_int = (int)(value_color[0] * 0.2126 + value_color[1] * 0.7152 + value_color[2] * 0.0722); + value_vector = vector(value_color[0], value_color[1], value_color[2]); + value_point = point(value_color[0], value_color[1], value_color[2]); + value_normal = normal(value_color[0], value_color[1], value_color[2]); } diff --git a/intern/cycles/kernel/shaders/node_convert_from_float.osl b/intern/cycles/kernel/shaders/node_convert_from_float.osl index fc5c79c4c64..a5c2e3b26ad 100644 --- a/intern/cycles/kernel/shaders/node_convert_from_float.osl +++ b/intern/cycles/kernel/shaders/node_convert_from_float.osl @@ -17,18 +17,18 @@ #include "stdosl.h" shader node_convert_from_float( - float Val = 0.0, - output string String = "", - output int ValInt = 0, - output color Color = 0.0, - output vector Vector = vector(0.0, 0.0, 0.0), - output point Point = point(0.0, 0.0, 0.0), - output normal Normal = normal(0.0, 0.0, 0.0)) + float value_float = 0.0, + output string value_string = "", + output int value_int = 0, + output color value_color = 0.0, + output vector value_vector = vector(0.0, 0.0, 0.0), + output point value_point = point(0.0, 0.0, 0.0), + output normal value_normal = normal(0.0, 0.0, 0.0)) { - ValInt = (int)Val; - Color = color(Val, Val, Val); - Vector = vector(Val, Val, Val); - Point = point(Val, Val, Val); - Normal = normal(Val, Val, Val); + value_int = (int)value_float; + value_color = color(value_float, value_float, value_float); + value_vector = vector(value_float, value_float, value_float); + value_point = point(value_float, value_float, value_float); + value_normal = normal(value_float, value_float, value_float); } diff --git a/intern/cycles/kernel/shaders/node_convert_from_int.osl b/intern/cycles/kernel/shaders/node_convert_from_int.osl index 3c3785ebc0d..0e6ae711210 100644 --- a/intern/cycles/kernel/shaders/node_convert_from_int.osl +++ b/intern/cycles/kernel/shaders/node_convert_from_int.osl @@ -17,19 +17,19 @@ #include "stdosl.h" shader node_convert_from_int( - int ValInt = 0, - output string String = "", - output float Val = 0.0, - output color Color = 0.0, - output vector Vector = vector(0.0, 0.0, 0.0), - output point Point = point(0.0, 0.0, 0.0), - output normal Normal = normal(0.0, 0.0, 0.0)) + int value_int = 0, + output string value_string = "", + output float value_float = 0.0, + output color value_color = 0.0, + output vector value_vector = vector(0.0, 0.0, 0.0), + output point value_point = point(0.0, 0.0, 0.0), + output normal value_normal = normal(0.0, 0.0, 0.0)) { - float f = (float)ValInt; - Val = f; - Color = color(f, f, f); - Vector = vector(f, f, f); - Point = point(f, f, f); - Normal = normal(f, f, f); + float f = (float)value_int; + value_float = f; + value_color = color(f, f, f); + value_vector = vector(f, f, f); + value_point = point(f, f, f); + value_normal = normal(f, f, f); } diff --git a/intern/cycles/kernel/shaders/node_convert_from_normal.osl b/intern/cycles/kernel/shaders/node_convert_from_normal.osl index 8ecc56ac8ce..7fffa7f6169 100644 --- a/intern/cycles/kernel/shaders/node_convert_from_normal.osl +++ b/intern/cycles/kernel/shaders/node_convert_from_normal.osl @@ -17,18 +17,18 @@ #include "stdosl.h" shader node_convert_from_normal( - normal Normal = normal(0.0, 0.0, 0.0), - output string String = "", - output float Val = 0.0, - output int ValInt = 0, - output vector Vector = vector(0.0, 0.0, 0.0), - output color Color = 0.0, - output point Point = point(0.0, 0.0, 0.0)) + normal value_normal = normal(0.0, 0.0, 0.0), + output string value_string = "", + output float value_float = 0.0, + output int value_int = 0, + output vector value_vector = vector(0.0, 0.0, 0.0), + output color value_color = 0.0, + output point value_point = point(0.0, 0.0, 0.0)) { - Val = (Normal[0] + Normal[1] + Normal[2]) * (1.0 / 3.0); - ValInt = (int)((Normal[0] + Normal[1] + Normal[2]) * (1.0 / 3.0)); - Vector = vector(Normal[0], Normal[1], Normal[2]); - Color = color(Normal[0], Normal[1], Normal[2]); - Point = point(Normal[0], Normal[1], Normal[2]); + value_float = (value_normal[0] + value_normal[1] + value_normal[2]) * (1.0 / 3.0); + value_int = (int)((value_normal[0] + value_normal[1] + value_normal[2]) * (1.0 / 3.0)); + value_vector = vector(value_normal[0], value_normal[1], value_normal[2]); + value_color = color(value_normal[0], value_normal[1], value_normal[2]); + value_point = point(value_normal[0], value_normal[1], value_normal[2]); } diff --git a/intern/cycles/kernel/shaders/node_convert_from_point.osl b/intern/cycles/kernel/shaders/node_convert_from_point.osl index e5913b7a1e4..9e4930296bb 100644 --- a/intern/cycles/kernel/shaders/node_convert_from_point.osl +++ b/intern/cycles/kernel/shaders/node_convert_from_point.osl @@ -17,18 +17,18 @@ #include "stdosl.h" shader node_convert_from_point( - point Point = point(0.0, 0.0, 0.0), - output string String = "", - output float Val = 0.0, - output int ValInt = 0, - output vector Vector = vector(0.0, 0.0, 0.0), - output color Color = 0.0, - output normal Normal = normal(0.0, 0.0, 0.0)) + point value_point = point(0.0, 0.0, 0.0), + output string value_string = "", + output float value_float = 0.0, + output int value_int = 0, + output vector value_vector = vector(0.0, 0.0, 0.0), + output color value_color = 0.0, + output normal value_normal = normal(0.0, 0.0, 0.0)) { - Val = (Point[0] + Point[1] + Point[2]) * (1.0 / 3.0); - ValInt = (int)((Normal[0] + Normal[1] + Normal[2]) * (1.0 / 3.0)); - Vector = vector(Point[0], Point[1], Point[2]); - Color = color(Point[0], Point[1], Point[2]); - Normal = normal(Point[0], Point[1], Point[2]); + value_float = (value_point[0] + value_point[1] + value_point[2]) * (1.0 / 3.0); + value_int = (int)((value_normal[0] + value_normal[1] + value_normal[2]) * (1.0 / 3.0)); + value_vector = vector(value_point[0], value_point[1], value_point[2]); + value_color = color(value_point[0], value_point[1], value_point[2]); + value_normal = normal(value_point[0], value_point[1], value_point[2]); } diff --git a/intern/cycles/kernel/shaders/node_convert_from_string.osl b/intern/cycles/kernel/shaders/node_convert_from_string.osl index 0466734277b..cbc6653eada 100644 --- a/intern/cycles/kernel/shaders/node_convert_from_string.osl +++ b/intern/cycles/kernel/shaders/node_convert_from_string.osl @@ -17,13 +17,13 @@ #include "stdosl.h" shader node_convert_from_string( - string String = "", - output color Color = color(0.0, 0.0, 0.0), - output float Val = 0.0, - output int ValInt = 0, - output vector Vector = vector(0.0, 0.0, 0.0), - output point Point = point(0.0, 0.0, 0.0), - output normal Normal = normal(0.0, 0.0, 0.0)) + string value_string = "", + output color value_color = color(0.0, 0.0, 0.0), + output float value_float = 0.0, + output int value_int = 0, + output vector value_vector = vector(0.0, 0.0, 0.0), + output point value_point = point(0.0, 0.0, 0.0), + output normal value_normal = normal(0.0, 0.0, 0.0)) { } diff --git a/intern/cycles/kernel/shaders/node_convert_from_vector.osl b/intern/cycles/kernel/shaders/node_convert_from_vector.osl index 79c5cb04550..8bdca469b90 100644 --- a/intern/cycles/kernel/shaders/node_convert_from_vector.osl +++ b/intern/cycles/kernel/shaders/node_convert_from_vector.osl @@ -17,18 +17,18 @@ #include "stdosl.h" shader node_convert_from_vector( - vector Vector = vector(0.0, 0.0, 0.0), - output string String = "", - output float Val = 0.0, - output int ValInt = 0, - output color Color = color(0.0, 0.0, 0.0), - output point Point = point(0.0, 0.0, 0.0), - output normal Normal = normal(0.0, 0.0, 0.0)) + vector value_vector = vector(0.0, 0.0, 0.0), + output string value_string = "", + output float value_float = 0.0, + output int value_int = 0, + output color value_color = color(0.0, 0.0, 0.0), + output point value_point = point(0.0, 0.0, 0.0), + output normal value_normal = normal(0.0, 0.0, 0.0)) { - Val = (Vector[0] + Vector[1] + Vector[2]) * (1.0 / 3.0); - ValInt = (int)((Normal[0] + Normal[1] + Normal[2]) * (1.0 / 3.0)); - Color = color(Vector[0], Vector[1], Vector[2]); - Point = point(Vector[0], Vector[1], Vector[2]); - Normal = normal(Vector[0], Vector[1], Vector[2]); + value_float = (value_vector[0] + value_vector[1] + value_vector[2]) * (1.0 / 3.0); + value_int = (int)((value_normal[0] + value_normal[1] + value_normal[2]) * (1.0 / 3.0)); + value_color = color(value_vector[0], value_vector[1], value_vector[2]); + value_point = point(value_vector[0], value_vector[1], value_vector[2]); + value_normal = normal(value_vector[0], value_vector[1], value_vector[2]); } diff --git a/intern/cycles/kernel/shaders/node_gradient_texture.osl b/intern/cycles/kernel/shaders/node_gradient_texture.osl index 52b49688ab3..69e2ee54bdf 100644 --- a/intern/cycles/kernel/shaders/node_gradient_texture.osl +++ b/intern/cycles/kernel/shaders/node_gradient_texture.osl @@ -63,7 +63,7 @@ float gradient(point p, string type) shader node_gradient_texture( int use_mapping = 0, matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - string Type = "Linear", + string type = "Linear", point Vector = P, output float Fac = 0.0, output color Color = 0.0) @@ -73,7 +73,7 @@ shader node_gradient_texture( if (use_mapping) p = transform(mapping, p); - Fac = gradient(p, Type); + Fac = gradient(p, type); Color = color(Fac, Fac, Fac); } diff --git a/intern/cycles/kernel/shaders/node_image_texture.osl b/intern/cycles/kernel/shaders/node_image_texture.osl index d3a347b70db..d09174ff5d3 100644 --- a/intern/cycles/kernel/shaders/node_image_texture.osl +++ b/intern/cycles/kernel/shaders/node_image_texture.osl @@ -62,9 +62,9 @@ color image_texture_lookup(string filename, int use_alpha, int is_float, string interpolation, - string wrap) + string extension) { - color rgb = (color)texture(filename, u, 1.0 - v, "wrap", wrap, "interp", interpolation, "alpha", Alpha); + color rgb = (color)texture(filename, u, 1.0 - v, "wrap", extension, "interp", interpolation, "alpha", Alpha); if (use_alpha) { rgb = color_unpremultiply(rgb, Alpha); diff --git a/intern/cycles/kernel/shaders/node_magic_texture.osl b/intern/cycles/kernel/shaders/node_magic_texture.osl index 55992e3494c..8d6af391e04 100644 --- a/intern/cycles/kernel/shaders/node_magic_texture.osl +++ b/intern/cycles/kernel/shaders/node_magic_texture.osl @@ -93,7 +93,7 @@ color magic(point p, int n, float distortion) shader node_magic_texture( int use_mapping = 0, matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - int Depth = 2, + int depth = 2, float Distortion = 5.0, float Scale = 5.0, point Vector = P, @@ -105,7 +105,7 @@ shader node_magic_texture( if (use_mapping) p = transform(mapping, p); - Color = magic(p * Scale, Depth, Distortion); + Color = magic(p * Scale, depth, Distortion); Fac = (Color[0] + Color[1] + Color[2]) * (1.0 / 3.0); } diff --git a/intern/cycles/kernel/shaders/node_math.osl b/intern/cycles/kernel/shaders/node_math.osl index 7eef97fd7e8..85eac0b97a6 100644 --- a/intern/cycles/kernel/shaders/node_math.osl +++ b/intern/cycles/kernel/shaders/node_math.osl @@ -50,7 +50,7 @@ float safe_log(float a, float b) shader node_math( string type = "Add", - int Clamp = 0, + int use_clamp = 0, float Value1 = 0.0, float Value2 = 0.0, output float Value = 0.0) @@ -96,7 +96,7 @@ shader node_math( else if (type == "Absolute") Value = fabs(Value1); - if (Clamp) + if (use_clamp) Value = clamp(Value, 0.0, 1.0); } diff --git a/intern/cycles/kernel/shaders/node_mix.osl b/intern/cycles/kernel/shaders/node_mix.osl index 9ef58e4cbba..4a66748ed6a 100644 --- a/intern/cycles/kernel/shaders/node_mix.osl +++ b/intern/cycles/kernel/shaders/node_mix.osl @@ -278,7 +278,7 @@ color node_mix_clamp(color col) shader node_mix( string type = "Mix", - int Clamp = 0, + int use_clamp = 0, float Fac = 0.5, color Color1 = 0.0, color Color2 = 0.0, @@ -323,7 +323,7 @@ shader node_mix( if (type == "Linear Light") Color = node_mix_linear(t, Color1, Color2); - if (Clamp) + if (use_clamp) Color = node_mix_clamp(Color); } diff --git a/intern/cycles/kernel/shaders/node_musgrave_texture.osl b/intern/cycles/kernel/shaders/node_musgrave_texture.osl index 4f95dec910a..2f9f62bcfe8 100644 --- a/intern/cycles/kernel/shaders/node_musgrave_texture.osl +++ b/intern/cycles/kernel/shaders/node_musgrave_texture.osl @@ -187,7 +187,7 @@ float noise_musgrave_ridged_multi_fractal(point p, float H, float lacunarity, shader node_musgrave_texture( int use_mapping = 0, matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - string Type = "fBM", + string type = "fBM", float Dimension = 2.0, float Lacunarity = 1.0, float Detail = 2.0, @@ -210,15 +210,15 @@ shader node_musgrave_texture( p = p * Scale; - if (Type == "Multifractal") + if (type == "Multifractal") Fac = intensity * noise_musgrave_multi_fractal(p, dimension, lacunarity, octaves); - else if (Type == "fBM") + else if (type == "fBM") Fac = intensity * noise_musgrave_fBm(p, dimension, lacunarity, octaves); - else if (Type == "Hybrid Multifractal") + else if (type == "Hybrid Multifractal") Fac = intensity * noise_musgrave_hybrid_multi_fractal(p, dimension, lacunarity, octaves, Offset, Gain); - else if (Type == "Ridged Multifractal") + else if (type == "Ridged Multifractal") Fac = intensity * noise_musgrave_ridged_multi_fractal(p, dimension, lacunarity, octaves, Offset, Gain); - else if (Type == "Hetero Terrain") + else if (type == "Hetero Terrain") Fac = intensity * noise_musgrave_hetero_terrain(p, dimension, lacunarity, octaves, Offset); Color = color(Fac, Fac, Fac); diff --git a/intern/cycles/kernel/shaders/node_normal.osl b/intern/cycles/kernel/shaders/node_normal.osl index 2d04978fc72..7307971eddd 100644 --- a/intern/cycles/kernel/shaders/node_normal.osl +++ b/intern/cycles/kernel/shaders/node_normal.osl @@ -17,12 +17,12 @@ #include "stdosl.h" shader node_normal( - normal Direction = normal(0.0, 0.0, 0.0), + normal direction = normal(0.0, 0.0, 0.0), normal NormalIn = normal(0.0, 0.0, 0.0), output normal NormalOut = normal(0.0, 0.0, 0.0), output float Dot = 1.0) { - NormalOut = normalize(Direction); + NormalOut = normalize(direction); Dot = dot(NormalOut, normalize(NormalIn)); } diff --git a/intern/cycles/kernel/shaders/node_rgb_ramp.osl b/intern/cycles/kernel/shaders/node_rgb_ramp.osl index 2ab6b6778b7..c0ae74d6b33 100644 --- a/intern/cycles/kernel/shaders/node_rgb_ramp.osl +++ b/intern/cycles/kernel/shaders/node_rgb_ramp.osl @@ -20,7 +20,7 @@ shader node_rgb_ramp( color ramp_color[] = {0.0}, float ramp_alpha[] = {0.0}, - int ramp_interpolate = 1, + int interpolate = 1, float Fac = 0.0, output color Color = 0.0, @@ -38,7 +38,7 @@ shader node_rgb_ramp( Color = ramp_color[i]; Alpha = ramp_alpha[i]; - if (ramp_interpolate && t > 0.0) { + if (interpolate && t > 0.0) { Color = (1.0 - t) * Color + t * ramp_color[i + 1]; Alpha = (1.0 - t) * Alpha + t * ramp_alpha[i + 1]; } diff --git a/intern/cycles/kernel/shaders/node_subsurface_scattering.osl b/intern/cycles/kernel/shaders/node_subsurface_scattering.osl index a67333c5d4e..1877c7e595f 100644 --- a/intern/cycles/kernel/shaders/node_subsurface_scattering.osl +++ b/intern/cycles/kernel/shaders/node_subsurface_scattering.osl @@ -22,13 +22,13 @@ shader node_subsurface_scattering( vector Radius = vector(0.1, 0.1, 0.1), float TextureBlur = 0.0, float Sharpness = 0.0, - string Falloff = "Cubic", + string falloff = "Cubic", normal Normal = N, output closure color BSSRDF = 0) { - if (Falloff == "Gaussian") + if (falloff == "Gaussian") BSSRDF = Color * bssrdf_gaussian(Normal, Scale * Radius, TextureBlur); - else if (Falloff == "Cubic") + else if (falloff == "Cubic") BSSRDF = Color * bssrdf_cubic(Normal, Scale * Radius, TextureBlur, Sharpness); else BSSRDF = Color * bssrdf_burley(Normal, Scale * Radius, TextureBlur, Color); diff --git a/intern/cycles/kernel/shaders/node_voronoi_texture.osl b/intern/cycles/kernel/shaders/node_voronoi_texture.osl index 29e143ae207..bacdd593c7c 100644 --- a/intern/cycles/kernel/shaders/node_voronoi_texture.osl +++ b/intern/cycles/kernel/shaders/node_voronoi_texture.osl @@ -22,7 +22,7 @@ shader node_voronoi_texture( int use_mapping = 0, matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - string Coloring = "Intensity", + string coloring = "Intensity", float Scale = 5.0, point Vector = P, output float Fac = 0.0, @@ -40,7 +40,7 @@ shader node_voronoi_texture( voronoi(p * Scale, 1.0, da, pa); /* Colored output */ - if (Coloring == "Intensity") { + if (coloring == "Intensity") { Fac = fabs(da[0]); Color = color(Fac); } diff --git a/intern/cycles/kernel/shaders/node_wave_texture.osl b/intern/cycles/kernel/shaders/node_wave_texture.osl index 59f61d3b46a..a07742faefc 100644 --- a/intern/cycles/kernel/shaders/node_wave_texture.osl +++ b/intern/cycles/kernel/shaders/node_wave_texture.osl @@ -48,8 +48,8 @@ float wave(point p, string type, string profile, float detail, float distortion, shader node_wave_texture( int use_mapping = 0, matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - string Type = "Bands", - string Profile = "Sine", + string type = "Bands", + string profile = "Sine", float Scale = 5.0, float Distortion = 0.0, float Detail = 2.0, @@ -63,7 +63,7 @@ shader node_wave_texture( if (use_mapping) p = transform(mapping, p); - Fac = wave(p * Scale, Type, Profile, Detail, Distortion, DetailScale); + Fac = wave(p * Scale, type, profile, Detail, Distortion, DetailScale); Color = Fac; } diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h index 88397005b49..65512a0105c 100644 --- a/intern/cycles/kernel/svm/svm_closure.h +++ b/intern/cycles/kernel/svm/svm_closure.h @@ -365,8 +365,12 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * } break; } - case CLOSURE_BSDF_DIFFUSE_TOON_ID: - case CLOSURE_BSDF_GLOSSY_TOON_ID: { + case CLOSURE_BSDF_GLOSSY_TOON_ID: +#ifdef __CAUSTICS_TRICKS__ + if(!kernel_data.integrator.caustics_reflective && (path_flag & PATH_RAY_DIFFUSE)) + break; +#endif + case CLOSURE_BSDF_DIFFUSE_TOON_ID: { ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight); if(sc) { diff --git a/intern/cycles/kernel/svm/svm_image.h b/intern/cycles/kernel/svm/svm_image.h index 92d2b36bbb1..3d9ab405849 100644 --- a/intern/cycles/kernel/svm/svm_image.h +++ b/intern/cycles/kernel/svm/svm_image.h @@ -18,15 +18,15 @@ CCL_NAMESPACE_BEGIN /* Float4 textures on various devices. */ #if defined(__KERNEL_CPU__) -# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_IMAGES_CPU +# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_CPU #elif defined(__KERNEL_CUDA__) # if __CUDA_ARCH__ < 300 -# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_IMAGES_CUDA +# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_CUDA # else -# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_IMAGES_CUDA_KEPLER +# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_CUDA_KEPLER # endif #else -# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_IMAGES_OPENCL +# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_OPENCL #endif #ifdef __KERNEL_OPENCL__ diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index be87e35326e..e57d22b1b13 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -343,6 +343,11 @@ typedef enum NodeNormalMapSpace { NODE_NORMAL_MAP_BLENDER_WORLD, } NodeNormalMapSpace; +typedef enum NodeImageColorSpace { + NODE_COLOR_SPACE_NONE = 0, + NODE_COLOR_SPACE_COLOR = 1, +} NodeImageColorSpace; + typedef enum NodeImageProjection { NODE_IMAGE_PROJ_FLAT = 0, NODE_IMAGE_PROJ_BOX = 1, @@ -350,6 +355,11 @@ typedef enum NodeImageProjection { NODE_IMAGE_PROJ_TUBE = 3, } NodeImageProjection; +typedef enum NodeEnvironmentProjection { + NODE_ENVIRONMENT_EQUIRECTANGULAR = 0, + NODE_ENVIRONMENT_MIRROR_BALL = 1, +} NodeEnvironmentProjection; + typedef enum NodeBumpOffset { NODE_BUMP_OFFSET_CENTER, NODE_BUMP_OFFSET_DX, diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp index b7de83d89c1..71a3cba6811 100644 --- a/intern/cycles/render/attribute.cpp +++ b/intern/cycles/render/attribute.cpp @@ -51,13 +51,13 @@ void Attribute::set(ustring name_, TypeDesc type_, AttributeElement element_) type == TypeDesc::TypeNormal || type == TypeDesc::TypeMatrix); } -void Attribute::reserve(int numverts, int numtris, int numsteps, int numcurves, int numkeys, bool resize) +void Attribute::resize(int numverts, int numtris, int numsteps, int numcurves, int numkeys, bool reserve_only) { - if(resize) { - buffer.resize(buffer_size(numverts, numtris, numsteps, numcurves, numkeys), 0); + if(reserve_only) { + buffer.reserve(buffer_size(numverts, numtris, numsteps, numcurves, numkeys)); } else { - buffer.reserve(buffer_size(numverts, numtris, numsteps, numcurves, numkeys)); + buffer.resize(buffer_size(numverts, numtris, numsteps, numcurves, numkeys), 0); } } @@ -263,7 +263,7 @@ AttributeSet::~AttributeSet() { } -Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement element, bool resize) +Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement element) { Attribute *attr = find(name); @@ -291,9 +291,9 @@ Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement eleme /* this is weak .. */ if(triangle_mesh) - attr->reserve(triangle_mesh->verts.size(), triangle_mesh->triangles.size(), triangle_mesh->motion_steps, 0, 0, resize); + attr->resize(triangle_mesh->verts.size(), triangle_mesh->num_triangles(), triangle_mesh->motion_steps, 0, 0, false); if(curve_mesh) - attr->reserve(0, 0, curve_mesh->motion_steps, curve_mesh->curves.size(), curve_mesh->curve_keys.size(), resize); + attr->resize(0, 0, curve_mesh->motion_steps, curve_mesh->num_curves(), curve_mesh->curve_keys.size(), false); return attr; } @@ -448,13 +448,13 @@ Attribute *AttributeSet::find(AttributeRequest& req) return find(req.std); } -void AttributeSet::reserve() +void AttributeSet::resize(bool reserve_only) { foreach(Attribute& attr, attributes) { if(triangle_mesh) - attr.reserve(triangle_mesh->verts.size(), triangle_mesh->triangles.size(), triangle_mesh->motion_steps, 0, 0, true); + attr.resize(triangle_mesh->verts.size(), triangle_mesh->num_triangles(), triangle_mesh->motion_steps, 0, 0, reserve_only); if(curve_mesh) - attr.reserve(0, 0, 0, curve_mesh->curves.size(), curve_mesh->curve_keys.size(), true); + attr.resize(0, 0, 0, curve_mesh->num_curves(), curve_mesh->curve_keys.size(), reserve_only); } } diff --git a/intern/cycles/render/attribute.h b/intern/cycles/render/attribute.h index 01102d22aaa..41b3626afd3 100644 --- a/intern/cycles/render/attribute.h +++ b/intern/cycles/render/attribute.h @@ -58,7 +58,7 @@ public: Attribute() {} ~Attribute(); void set(ustring name, TypeDesc type, AttributeElement element); - void reserve(int numverts, int numfaces, int numsteps, int numcurves, int numkeys, bool resize); + void resize(int numverts, int numfaces, int numsteps, int numcurves, int numkeys, bool reserve_only); size_t data_sizeof() const; size_t element_size(int numverts, int numfaces, int numsteps, int numcurves, int numkeys) const; @@ -104,7 +104,7 @@ public: AttributeSet(); ~AttributeSet(); - Attribute *add(ustring name, TypeDesc type, AttributeElement element, bool resize = true); + Attribute *add(ustring name, TypeDesc type, AttributeElement element); Attribute *find(ustring name) const; void remove(ustring name); @@ -114,7 +114,7 @@ public: Attribute *find(AttributeRequest& req); - void reserve(); + void resize(bool reserve_only = false); void clear(); }; diff --git a/intern/cycles/render/background.cpp b/intern/cycles/render/background.cpp index 6f8d1d1d461..20536b74e87 100644 --- a/intern/cycles/render/background.cpp +++ b/intern/cycles/render/background.cpp @@ -116,6 +116,11 @@ void Background::device_free(Device * /*device*/, DeviceScene * /*dscene*/) { } +bool Background::modified(const Background& background) +{ + return !Node::equals(background); +} + void Background::tag_update(Scene *scene) { scene->integrator->tag_update(scene); diff --git a/intern/cycles/render/background.h b/intern/cycles/render/background.h index 843655b00a1..8029c6a9e80 100644 --- a/intern/cycles/render/background.h +++ b/intern/cycles/render/background.h @@ -50,6 +50,7 @@ public: void device_update(Device *device, DeviceScene *dscene, Scene *scene); void device_free(Device *device, DeviceScene *dscene); + bool modified(const Background& background); void tag_update(Scene *scene); }; diff --git a/intern/cycles/render/bake.cpp b/intern/cycles/render/bake.cpp index 5bf5e5113ef..13310a61761 100644 --- a/intern/cycles/render/bake.cpp +++ b/intern/cycles/render/bake.cpp @@ -177,7 +177,7 @@ bool BakeManager::bake(Device *device, DeviceScene *dscene, Scene *scene, Progre device->mem_alloc(d_input, MEM_READ_ONLY); device->mem_copy_to(d_input); - device->mem_alloc(d_output, MEM_WRITE_ONLY); + device->mem_alloc(d_output, MEM_READ_WRITE); DeviceTask task(DeviceTask::SHADER); task.shader_input = d_input.device_pointer; diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp index d992cac5312..2310798be2e 100644 --- a/intern/cycles/render/camera.cpp +++ b/intern/cycles/render/camera.cpp @@ -30,70 +30,126 @@ CCL_NAMESPACE_BEGIN static float shutter_curve_eval(float x, - float shutter_curve[RAMP_TABLE_SIZE]) + array<float>& shutter_curve) { - x *= RAMP_TABLE_SIZE; + if (shutter_curve.size() == 0) + return 1.0f; + + x *= shutter_curve.size(); int index = (int)x; float frac = x - index; - if(index < RAMP_TABLE_SIZE - 1) { + if(index < shutter_curve.size() - 1) { return lerp(shutter_curve[index], shutter_curve[index + 1], frac); } else { - return shutter_curve[RAMP_TABLE_SIZE - 1]; + return shutter_curve[shutter_curve.size() - 1]; } } +NODE_DEFINE(Camera) +{ + NodeType* type = NodeType::add("camera", create); + + SOCKET_FLOAT(shuttertime, "Shutter Time", 1.0f); + + static NodeEnum motion_position_enum; + motion_position_enum.insert("start", MOTION_POSITION_START); + motion_position_enum.insert("center", MOTION_POSITION_CENTER); + motion_position_enum.insert("end", MOTION_POSITION_END); + SOCKET_ENUM(motion_position, "Motion Position", motion_position_enum, MOTION_POSITION_CENTER); + + static NodeEnum rolling_shutter_type_enum; + rolling_shutter_type_enum.insert("none", ROLLING_SHUTTER_NONE); + rolling_shutter_type_enum.insert("top", ROLLING_SHUTTER_TOP); + SOCKET_ENUM(rolling_shutter_type, "Rolling Shutter Type", rolling_shutter_type_enum, ROLLING_SHUTTER_NONE); + SOCKET_FLOAT(rolling_shutter_duration, "Rolling Shutter Duration", 0.1f); + + SOCKET_FLOAT_ARRAY(shutter_curve, "Shutter Curve", array<float>()); + + SOCKET_FLOAT(aperturesize, "Aperture Size", 0.0f); + SOCKET_FLOAT(focaldistance, "Focal Distance", 10.0f); + SOCKET_INT(blades, "Blades", 0); + SOCKET_FLOAT(bladesrotation, "Blades Rotation", 0.0f); + + SOCKET_TRANSFORM(matrix, "Matrix", transform_identity()); + + SOCKET_FLOAT(aperture_ratio, "Aperture Ratio", 1.0f); + + static NodeEnum type_enum; + type_enum.insert("perspective", CAMERA_PERSPECTIVE); + type_enum.insert("orthograph", CAMERA_ORTHOGRAPHIC); + type_enum.insert("panorama", CAMERA_PANORAMA); + SOCKET_ENUM(type, "Type", type_enum, CAMERA_PERSPECTIVE); + + static NodeEnum panorama_type_enum; + panorama_type_enum.insert("equirectangular", PANORAMA_EQUIRECTANGULAR); + panorama_type_enum.insert("mirrorball", PANORAMA_MIRRORBALL); + panorama_type_enum.insert("fisheye_equidistant", PANORAMA_FISHEYE_EQUIDISTANT); + panorama_type_enum.insert("fisheye_equisolid", PANORAMA_FISHEYE_EQUISOLID); + SOCKET_ENUM(panorama_type, "Panorama Type", panorama_type_enum, PANORAMA_EQUIRECTANGULAR); + + SOCKET_FLOAT(fisheye_fov, "Fisheye FOV", M_PI_F); + SOCKET_FLOAT(fisheye_lens, "Fisheye Lens", 10.5f); + SOCKET_FLOAT(latitude_min, "Latitude Min", -M_PI_2_F); + SOCKET_FLOAT(latitude_max, "Latitude Max", M_PI_2_F); + SOCKET_FLOAT(longitude_min, "Longitude Min", -M_PI_F); + SOCKET_FLOAT(longitude_max, "Longitude Max", M_PI_F); + SOCKET_FLOAT(fov, "FOV", M_PI_4_F); + SOCKET_FLOAT(fov_pre, "FOV Pre", M_PI_4_F); + SOCKET_FLOAT(fov_post, "FOV Post", M_PI_4_F); + + static NodeEnum stereo_eye_enum; + stereo_eye_enum.insert("none", STEREO_NONE); + stereo_eye_enum.insert("left", STEREO_LEFT); + stereo_eye_enum.insert("right", STEREO_RIGHT); + SOCKET_ENUM(stereo_eye, "Stereo Eye", stereo_eye_enum, STEREO_NONE); + + SOCKET_FLOAT(interocular_distance, "Interocular Distance", 0.065f); + SOCKET_FLOAT(convergence_distance, "Convergence Distance", 30.0f * 0.065f); + + SOCKET_BOOLEAN(use_pole_merge, "Use Pole Merge", false); + SOCKET_FLOAT(pole_merge_angle_from, "Pole Merge Angle From", 60.0f * M_PI_F / 180.0f); + SOCKET_FLOAT(pole_merge_angle_to, "Pole Merge Angle To", 75.0f * M_PI_F / 180.0f); + + SOCKET_FLOAT(sensorwidth, "Sensor Width", 0.036f); + SOCKET_FLOAT(sensorheight, "Sensor Height", 0.024f); + + SOCKET_FLOAT(nearclip, "Near Clip", 1e-5f); + SOCKET_FLOAT(farclip, "Far Clip", 1e5f); + + SOCKET_FLOAT(viewplane.left, "Viewplane Left", 0); + SOCKET_FLOAT(viewplane.right, "Viewplane Right", 0); + SOCKET_FLOAT(viewplane.bottom, "Viewplane Bottom", 0); + SOCKET_FLOAT(viewplane.top, "Viewplane Top", 0); + + SOCKET_FLOAT(border.left, "Border Left", 0); + SOCKET_FLOAT(border.right, "Border Right", 0); + SOCKET_FLOAT(border.bottom, "Border Bottom", 0); + SOCKET_FLOAT(border.top, "Border Top", 0); + + return type; +} + Camera::Camera() +: Node(node_type) { - shuttertime = 1.0f; - motion_position = MOTION_POSITION_CENTER; shutter_table_offset = TABLE_OFFSET_INVALID; - aperturesize = 0.0f; - focaldistance = 10.0f; - blades = 0; - bladesrotation = 0.0f; - - matrix = transform_identity(); + width = 1024; + height = 512; + resolution = 1; motion.pre = transform_identity(); motion.post = transform_identity(); use_motion = false; use_perspective_motion = false; - aperture_ratio = 1.0f; - - type = CAMERA_PERSPECTIVE; - panorama_type = PANORAMA_EQUIRECTANGULAR; - fisheye_fov = M_PI_F; - fisheye_lens = 10.5f; - latitude_min = -M_PI_2_F; - latitude_max = M_PI_2_F; - longitude_min = -M_PI_F; - longitude_max = M_PI_F; - fov = M_PI_4_F; - fov_pre = fov_post = fov; - stereo_eye = STEREO_NONE; - interocular_distance = 0.065f; - convergence_distance = 30.0f * 0.065f; - use_pole_merge = false; - pole_merge_angle_from = 60.0f * M_PI_F / 180.0f; - pole_merge_angle_to = 75.0f * M_PI_F / 180.0f; - - sensorwidth = 0.036f; - sensorheight = 0.024f; - - nearclip = 1e-5f; - farclip = 1e5f; - - width = 1024; - height = 512; - resolution = 1; + shutter_curve.resize(RAMP_TABLE_SIZE); + for(int i = 0; i < shutter_curve.size(); ++i) { + shutter_curve[i] = 1.0f; + } - viewplane.left = -((float)width/(float)height); - viewplane.right = (float)width/(float)height; - viewplane.bottom = -1.0f; - viewplane.top = 1.0f; + compute_auto_viewplane(); screentoworld = transform_identity(); rastertoworld = transform_identity(); @@ -109,16 +165,6 @@ Camera::Camera() need_device_update = true; need_flags_update = true; previous_need_motion = -1; - - /* Initialize shutter curve. */ - const int num_shutter_points = sizeof(shutter_curve) / sizeof(*shutter_curve); - for(int i = 0; i < num_shutter_points; ++i) { - shutter_curve[i] = 1.0f; - } - - /* Initialize rolling shutter effect. */ - rolling_shutter_type = ROLLING_SHUTTER_NONE; - rolling_shutter_duration = 0.1f; } Camera::~Camera() @@ -438,38 +484,14 @@ void Camera::device_free(Device * /*device*/, bool Camera::modified(const Camera& cam) { - return !((shuttertime == cam.shuttertime) && - (aperturesize == cam.aperturesize) && - (blades == cam.blades) && - (bladesrotation == cam.bladesrotation) && - (focaldistance == cam.focaldistance) && - (type == cam.type) && - (fov == cam.fov) && - (nearclip == cam.nearclip) && - (farclip == cam.farclip) && - (sensorwidth == cam.sensorwidth) && - (sensorheight == cam.sensorheight) && - // modified for progressive render - // (width == cam.width) && - // (height == cam.height) && - (viewplane == cam.viewplane) && - (border == cam.border) && - (matrix == cam.matrix) && - (aperture_ratio == cam.aperture_ratio) && - (panorama_type == cam.panorama_type) && - (fisheye_fov == cam.fisheye_fov) && - (fisheye_lens == cam.fisheye_lens) && - (latitude_min == cam.latitude_min) && - (latitude_max == cam.latitude_max) && - (longitude_min == cam.longitude_min) && - (longitude_max == cam.longitude_max) && - (stereo_eye == cam.stereo_eye)); + return !Node::equals(cam); } bool Camera::motion_modified(const Camera& cam) { return !((motion == cam.motion) && - (use_motion == cam.use_motion)); + (use_motion == cam.use_motion) && + (use_perspective_motion == cam.use_perspective_motion)); } void Camera::tag_update() diff --git a/intern/cycles/render/camera.h b/intern/cycles/render/camera.h index 57b9960e70b..141ef9cccef 100644 --- a/intern/cycles/render/camera.h +++ b/intern/cycles/render/camera.h @@ -19,6 +19,8 @@ #include "kernel_types.h" +#include "node.h" + #include "util_boundbox.h" #include "util_transform.h" #include "util_types.h" @@ -35,8 +37,10 @@ class Scene; * Renderman, and Blender after remapping. */ -class Camera { +class Camera : public Node { public: + NODE_DECLARE; + /* Specifies an offset for the shutter's time interval. */ enum MotionPosition { /* Shutter opens at the current frame. */ @@ -69,7 +73,7 @@ public: /* motion blur */ float shuttertime; MotionPosition motion_position; - float shutter_curve[RAMP_TABLE_SIZE]; + array<float> shutter_curve; size_t shutter_table_offset; /* ** Rolling shutter effect. ** */ diff --git a/intern/cycles/render/curves.h b/intern/cycles/render/curves.h index 3d9b4e1f347..e41967eebf5 100644 --- a/intern/cycles/render/curves.h +++ b/intern/cycles/render/curves.h @@ -63,23 +63,23 @@ public: ParticleCurveData(); ~ParticleCurveData(); - vector<int> psys_firstcurve; - vector<int> psys_curvenum; - vector<int> psys_shader; - - vector<float> psys_rootradius; - vector<float> psys_tipradius; - vector<float> psys_shape; - vector<bool> psys_closetip; - - vector<int> curve_firstkey; - vector<int> curve_keynum; - vector<float> curve_length; - vector<float3> curve_uv; - vector<float3> curve_vcol; - - vector<float3> curvekey_co; - vector<float> curvekey_time; + array<int> psys_firstcurve; + array<int> psys_curvenum; + array<int> psys_shader; + + array<float> psys_rootradius; + array<float> psys_tipradius; + array<float> psys_shape; + array<bool> psys_closetip; + + array<int> curve_firstkey; + array<int> curve_keynum; + array<float> curve_length; + array<float3> curve_uv; + array<float3> curve_vcol; + + array<float3> curvekey_co; + array<float> curvekey_time; }; /* HairSystem Manager */ diff --git a/intern/cycles/render/film.cpp b/intern/cycles/render/film.cpp index 12dce6ad999..e10a938e1eb 100644 --- a/intern/cycles/render/film.cpp +++ b/intern/cycles/render/film.cpp @@ -465,7 +465,7 @@ void Film::device_free(Device * /*device*/, bool Film::modified(const Film& film) { - return Node::modified(film) || !Pass::equals(passes, film.passes); + return !Node::equals(film) || !Pass::equals(passes, film.passes); } void Film::tag_passes_update(Scene *scene, const array<Pass>& passes_) diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp index 24e4c9f33d5..29c0eec9b97 100644 --- a/intern/cycles/render/graph.cpp +++ b/intern/cycles/render/graph.cpp @@ -66,7 +66,7 @@ bool check_node_inputs_equals(const ShaderNode *node_a, *input_b = node_b->inputs[i]; if(input_a->link == NULL && input_b->link == NULL) { /* Unconnected inputs are expected to have the same value. */ - if(input_a->value != input_b->value) { + if(input_a->value() != input_b->value()) { return false; } } @@ -90,23 +90,22 @@ bool check_node_inputs_equals(const ShaderNode *node_a, /* Input and Output */ -ShaderInput::ShaderInput(ShaderNode *parent_, const char *name_, ShaderSocketType type_) +ShaderInput::ShaderInput(ShaderNode *parent_, const char *name, SocketType::Type type) { parent = parent_; - name = name_; - type = type_; + name_ = name; + type_ = type; link = NULL; - value = make_float3(0.0f, 0.0f, 0.0f); + value_ = make_float3(0.0f, 0.0f, 0.0f); stack_offset = SVM_STACK_INVALID; - default_value = NONE; - usage = USE_ALL; + flags_ = 0; } -ShaderOutput::ShaderOutput(ShaderNode *parent_, const char *name_, ShaderSocketType type_) +ShaderOutput::ShaderOutput(ShaderNode *parent_, const char *name, SocketType::Type type) { parent = parent_; - name = name_; - type = type_; + name_ = name; + type_ = type; stack_offset = SVM_STACK_INVALID; } @@ -132,7 +131,7 @@ ShaderNode::~ShaderNode() ShaderInput *ShaderNode::input(const char *name) { foreach(ShaderInput *socket, inputs) { - if(strcmp(socket->name, name) == 0) + if(socket->name() == name) return socket; } @@ -142,39 +141,50 @@ ShaderInput *ShaderNode::input(const char *name) ShaderOutput *ShaderNode::output(const char *name) { foreach(ShaderOutput *socket, outputs) - if(strcmp(socket->name, name) == 0) + if(socket->name() == name) return socket; return NULL; } -ShaderInput *ShaderNode::add_input(const char *name, ShaderSocketType type, float value, int usage) +ShaderInput *ShaderNode::input(ustring name) { - ShaderInput *input = new ShaderInput(this, name, type); - input->value.x = value; - input->usage = usage; - inputs.push_back(input); - return input; + foreach(ShaderInput *socket, inputs) { + if(socket->name() == name) + return socket; + } + + return NULL; } -ShaderInput *ShaderNode::add_input(const char *name, ShaderSocketType type, float3 value, int usage) +ShaderOutput *ShaderNode::output(ustring name) +{ + foreach(ShaderOutput *socket, outputs) + if(socket->name() == name) + return socket; + + return NULL; +} + +ShaderInput *ShaderNode::add_input(const char *name, SocketType::Type type, float value, int flags) { ShaderInput *input = new ShaderInput(this, name, type); - input->value = value; - input->usage = usage; + input->value_.x = value; + input->flags_ = flags; inputs.push_back(input); return input; } -ShaderInput *ShaderNode::add_input(const char *name, ShaderSocketType type, ShaderInput::DefaultValue value, int usage) +ShaderInput *ShaderNode::add_input(const char *name, SocketType::Type type, float3 value, int flags) { - ShaderInput *input = add_input(name, type); - input->default_value = value; - input->usage = usage; + ShaderInput *input = new ShaderInput(this, name, type); + input->value_ = value; + input->flags_ = flags; + inputs.push_back(input); return input; } -ShaderOutput *ShaderNode::add_output(const char *name, ShaderSocketType type) +ShaderOutput *ShaderNode::add_output(const char *name, SocketType::Type type) { ShaderOutput *output = new ShaderOutput(this, name, type); outputs.push_back(output); @@ -185,13 +195,13 @@ void ShaderNode::attributes(Shader *shader, AttributeRequestSet *attributes) { foreach(ShaderInput *input, inputs) { if(!input->link) { - if(input->default_value == ShaderInput::TEXTURE_GENERATED) { + if(input->flags() & SocketType::LINK_TEXTURE_GENERATED) { if(shader->has_surface) attributes->add(ATTR_STD_GENERATED); if(shader->has_volume) attributes->add(ATTR_STD_GENERATED_TRANSFORM); } - else if(input->default_value == ShaderInput::TEXTURE_UV) { + else if(input->flags() & SocketType::LINK_TEXTURE_UV) { if(shader->has_surface) attributes->add(ATTR_STD_UV); } @@ -256,18 +266,18 @@ void ShaderGraph::connect(ShaderOutput *from, ShaderInput *to) return; } - if(from->type != to->type) { + if(from->type() != to->type()) { /* for closures we can't do automatic conversion */ - if(from->type == SHADER_SOCKET_CLOSURE || to->type == SHADER_SOCKET_CLOSURE) { + if(from->type() == SocketType::CLOSURE || to->type() == SocketType::CLOSURE) { fprintf(stderr, "Cycles shader graph connect: can only connect closure to closure " "(%s.%s to %s.%s).\n", - from->parent->name.c_str(), from->name, - to->parent->name.c_str(), to->name); + from->parent->name.c_str(), from->name().c_str(), + to->parent->name.c_str(), to->name().c_str()); return; } /* add automatic conversion node in case of type mismatch */ - ShaderNode *convert = add(new ConvertNode(from->type, to->type, true)); + ShaderNode *convert = add(new ConvertNode(from->type(), to->type(), true)); connect(from, convert->inputs[0]); connect(convert->outputs[0], to); @@ -401,8 +411,8 @@ void ShaderGraph::copy_nodes(ShaderNodeSet& nodes, ShaderNodeMap& nnodemap) /* find new input and output */ ShaderNode *nfrom = nnodemap[input->link->parent]; ShaderNode *nto = nnodemap[input->parent]; - ShaderOutput *noutput = nfrom->output(input->link->name); - ShaderInput *ninput = nto->input(input->name); + ShaderOutput *noutput = nfrom->output(input->link->name()); + ShaderInput *ninput = nto->input(input->name()); /* connect */ connect(noutput, ninput); @@ -447,10 +457,10 @@ void ShaderGraph::remove_proxy_nodes() vector<ShaderInput*> links = tonode->outputs[0]->links; foreach(ShaderInput *autoin, links) { - if(autoin->default_value == ShaderInput::NONE) - all_links_removed = false; - else + if(autoin->flags() & SocketType::DEFAULT_LINK_MASK) disconnect(autoin); + else + all_links_removed = false; } if(all_links_removed) @@ -460,8 +470,8 @@ void ShaderGraph::remove_proxy_nodes() disconnect(to); /* transfer the default input value to the target socket */ - to->set(input->value); - to->set(input->value_string); + to->set(input->value()); + to->set(input->value_string()); } } @@ -527,14 +537,13 @@ void ShaderGraph::constant_fold() } } /* Optimize current node. */ - float3 optimized_value = make_float3(0.0f, 0.0f, 0.0f); - if(node->constant_fold(this, output, &optimized_value)) { - /* Apply optimized value to connected sockets. */ + if(node->constant_fold(this, output, output->links[0])) { + /* Apply optimized value to other connected sockets and disconnect. */ vector<ShaderInput*> links(output->links); - foreach(ShaderInput *input, links) { - /* Assign value and disconnect the optimizedinput. */ - input->value = optimized_value; - disconnect(input); + for(size_t i = 0; i < links.size(); i++) { + if(i > 0) + links[i]->set(links[0]->value()); + disconnect(links[i]); } } } @@ -706,38 +715,38 @@ void ShaderGraph::default_inputs(bool do_osl) foreach(ShaderNode *node, nodes) { foreach(ShaderInput *input, node->inputs) { - if(!input->link && ((input->usage & ShaderInput::USE_SVM) || do_osl)) { - if(input->default_value == ShaderInput::TEXTURE_GENERATED) { + if(!input->link && (!(input->flags() & SocketType::OSL_INTERNAL) || do_osl)) { + if(input->flags() & SocketType::LINK_TEXTURE_GENERATED) { if(!texco) texco = new TextureCoordinateNode(); connect(texco->output("Generated"), input); } - else if(input->default_value == ShaderInput::TEXTURE_UV) { + else if(input->flags() & SocketType::LINK_TEXTURE_UV) { if(!texco) texco = new TextureCoordinateNode(); connect(texco->output("UV"), input); } - else if(input->default_value == ShaderInput::INCOMING) { + else if(input->flags() & SocketType::LINK_INCOMING) { if(!geom) geom = new GeometryNode(); connect(geom->output("Incoming"), input); } - else if(input->default_value == ShaderInput::NORMAL) { + else if(input->flags() & SocketType::LINK_NORMAL) { if(!geom) geom = new GeometryNode(); connect(geom->output("Normal"), input); } - else if(input->default_value == ShaderInput::POSITION) { + else if(input->flags() & SocketType::LINK_POSITION) { if(!geom) geom = new GeometryNode(); connect(geom->output("Position"), input); } - else if(input->default_value == ShaderInput::TANGENT) { + else if(input->flags() & SocketType::LINK_TANGENT) { if(!geom) geom = new GeometryNode(); @@ -785,8 +794,8 @@ void ShaderGraph::refine_bump_nodes() pair.second->bump = SHADER_BUMP_DY; ShaderOutput *out = bump_input->link; - ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name); - ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name); + ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name()); + ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name()); connect(out_dx, node->input("SampleX")); connect(out_dy, node->input("SampleY")); @@ -860,9 +869,9 @@ void ShaderGraph::bump_from_displacement() ShaderNode *bump = add(new BumpNode()); ShaderOutput *out = displacement_in->link; - ShaderOutput *out_center = nodes_center[out->parent]->output(out->name); - ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name); - ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name); + ShaderOutput *out_center = nodes_center[out->parent]->output(out->name()); + ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name()); + ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name()); connect(out_center, bump->input("SampleCenter")); connect(out_dx, bump->input("SampleX")); @@ -882,7 +891,7 @@ void ShaderGraph::bump_from_displacement() continue; } foreach(ShaderInput *input, node->inputs) { - if(!input->link && input->default_value == ShaderInput::NORMAL) + if(!input->link && (input->flags() & SocketType::LINK_NORMAL)) connect(set_normal->output("Normal"), input); } } @@ -925,7 +934,7 @@ void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight if(fin->link) connect(fin->link, fac_in); else - fac_in->value = fin->value; + fac_in->set(fin->value_float()); if(weight_out) connect(weight_out, weight_in); @@ -952,7 +961,7 @@ void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight return; /* already has a weight connected to it? add weights */ - if(weight_in->link || weight_in->value.x != 0.0f) { + if(weight_in->link || weight_in->value_float() != 0.0f) { ShaderNode *math_node = add(new MathNode()); ShaderInput *value1_in = math_node->input("Value1"); ShaderInput *value2_in = math_node->input("Value2"); @@ -960,12 +969,12 @@ void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight if(weight_in->link) connect(weight_in->link, value1_in); else - value1_in->value = weight_in->value; + value1_in->set(weight_in->value_float()); if(weight_out) connect(weight_out, value2_in); else - value2_in->value.x = 1.0f; + value2_in->set(1.0f); weight_out = math_node->output("Value"); if(weight_in->link) @@ -976,7 +985,7 @@ void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight if(weight_out) connect(weight_out, weight_in); else - weight_in->value.x += 1.0f; + weight_in->set(weight_in->value_float() + 1.0f); } } @@ -1024,7 +1033,7 @@ void ShaderGraph::dump_graph(const char *filename) if(socket != node->inputs[0]) { fprintf(fd, "|"); } - fprintf(fd, "<IN_%p>%s", socket, socket->name); + fprintf(fd, "<IN_%p>%s", socket, socket->name().c_str()); } fprintf(fd, "}|"); } @@ -1044,7 +1053,7 @@ void ShaderGraph::dump_graph(const char *filename) if(socket != node->outputs[0]) { fprintf(fd, "|"); } - fprintf(fd, "<OUT_%p>%s", socket, socket->name); + fprintf(fd, "<OUT_%p>%s", socket, socket->name().c_str()); } fprintf(fd, "}"); } @@ -1058,7 +1067,7 @@ void ShaderGraph::dump_graph(const char *filename) "// CONNECTION: OUT_%p->IN_%p (%s:%s)\n", output, input, - output->name, input->name); + output->name().c_str(), input->name().c_str()); fprintf(fd, "\"%p\":\"OUT_%p\":e -> \"%p\":\"IN_%p\":w [label=\"\"]\n", output->parent, diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h index bd3f5ca689a..882e495df20 100644 --- a/intern/cycles/render/graph.h +++ b/intern/cycles/render/graph.h @@ -17,6 +17,8 @@ #ifndef __GRAPH_H__ #define __GRAPH_H__ +#include "node.h" + #include "kernel_types.h" #include "util_list.h" @@ -39,23 +41,6 @@ class SVMCompiler; class OSLCompiler; class OutputNode; -/* Socket Type - * - * Data type for inputs and outputs */ - -enum ShaderSocketType { - SHADER_SOCKET_UNDEFINED, - - SHADER_SOCKET_FLOAT, - SHADER_SOCKET_INT, - SHADER_SOCKET_COLOR, - SHADER_SOCKET_VECTOR, - SHADER_SOCKET_POINT, - SHADER_SOCKET_NORMAL, - SHADER_SOCKET_CLOSURE, - SHADER_SOCKET_STRING -}; - /* Bump * * For bump mapping, a node may be evaluated multiple times, using different @@ -86,30 +71,6 @@ enum ShaderNodeSpecialType { SHADER_SPECIAL_TYPE_BUMP, }; -/* Enum - * - * Utility class for enum values. */ - -class ShaderEnum { -public: - bool empty() const { return left.empty(); } - void insert(const char *x, int y) { - left[ustring(x)] = y; - right[y] = ustring(x); - } - - bool exists(ustring x) { return left.find(x) != left.end(); } - bool exists(int y) { return right.find(y) != right.end(); } - - int operator[](const char *x) { return left[ustring(x)]; } - int operator[](ustring x) { return left[x]; } - ustring operator[](int y) { return right[y]; } - -protected: - map<ustring, int> left; - map<int, ustring> right; -}; - /* Input * * Input socket for a shader node. May be linked to an output or not. If not @@ -118,39 +79,32 @@ protected: class ShaderInput { public: - enum DefaultValue { - TEXTURE_GENERATED, - TEXTURE_UV, - INCOMING, - NORMAL, - POSITION, - TANGENT, - NONE - }; - - enum Usage { - USE_SVM = 1, - USE_OSL = 2, - USE_ALL = USE_SVM|USE_OSL - }; - - ShaderInput(ShaderNode *parent, const char *name, ShaderSocketType type); - void set(const float3& v) { value = v; } - void set(float f) { value = make_float3(f, 0, 0); } - void set(const ustring v) { value_string = v; } - - const char *name; - ShaderSocketType type; + ShaderInput(ShaderNode *parent, const char *name, SocketType::Type type); + + ustring name() { return name_; } + int flags() { return flags_; } + SocketType::Type type() { return type_; } + + void set(float f) { value_.x = f; } + void set(float3 f) { value_ = f; } + void set(int i) { value_.x = (float)i; } + void set(ustring s) { value_string_ = s; } + + float3& value() { return value_; } + float& value_float() { return value_.x; } + ustring& value_string() { return value_string_; } + + ustring name_; + SocketType::Type type_; ShaderNode *parent; ShaderOutput *link; - DefaultValue default_value; - float3 value; - ustring value_string; + float3 value_; + ustring value_string_; int stack_offset; /* for SVM compiler */ - int usage; + int flags_; }; /* Output @@ -159,12 +113,15 @@ public: class ShaderOutput { public: - ShaderOutput(ShaderNode *parent, const char *name, ShaderSocketType type); + ShaderOutput(ShaderNode *parent, const char *name, SocketType::Type type); - const char *name; - ShaderNode *parent; - ShaderSocketType type; + ustring name() { return name_; } + SocketType::Type type() { return type_; } + ustring name_; + SocketType::Type type_; + + ShaderNode *parent; vector<ShaderInput*> links; int stack_offset; /* for SVM compiler */ @@ -182,11 +139,12 @@ public: ShaderInput *input(const char *name); ShaderOutput *output(const char *name); + ShaderInput *input(ustring name); + ShaderOutput *output(ustring name); - ShaderInput *add_input(const char *name, ShaderSocketType type, float value=0.0f, int usage=ShaderInput::USE_ALL); - ShaderInput *add_input(const char *name, ShaderSocketType type, float3 value, int usage=ShaderInput::USE_ALL); - ShaderInput *add_input(const char *name, ShaderSocketType type, ShaderInput::DefaultValue value, int usage=ShaderInput::USE_ALL); - ShaderOutput *add_output(const char *name, ShaderSocketType type); + ShaderInput *add_input(const char *name, SocketType::Type type, float value=0.0f, int flags=0); + ShaderInput *add_input(const char *name, SocketType::Type type, float3 value, int flags=0); + ShaderOutput *add_output(const char *name, SocketType::Type type); virtual ShaderNode *clone() const = 0; virtual void attributes(Shader *shader, AttributeRequestSet *attributes); @@ -195,7 +153,7 @@ public: /* ** Node optimization ** */ /* Check whether the node can be replaced with single constant. */ - virtual bool constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, float3 * /*optimized_value*/) { return false; } + virtual bool constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, ShaderInput * /*optimized*/) { return false; } /* Simplify settings used by artists to the ones which are simpler to * evaluate in the kernel but keep the final result unchanged. diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index 6650c98aa38..71dc85f5f03 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -36,59 +36,58 @@ ImageManager::ImageManager(const DeviceInfo& info) osl_texture_system = NULL; animation_frame = 0; - /* Set image limits */ + /* In case of multiple devices used we need to know type of an actual + * compute device. + * + * NOTE: We assume that all the devices are same type, otherwise we'll + * be screwed on so many levels.. + */ + DeviceType device_type = info.type; + if (device_type == DEVICE_MULTI) { + device_type = info.multi_devices[0].type; + } - /* CPU */ - if(info.type == DEVICE_CPU) { - tex_num_images[IMAGE_DATA_TYPE_BYTE4] = TEX_NUM_BYTE4_IMAGES_CPU; - tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_NUM_FLOAT4_IMAGES_CPU; - tex_num_images[IMAGE_DATA_TYPE_FLOAT] = TEX_NUM_FLOAT_IMAGES_CPU; - tex_num_images[IMAGE_DATA_TYPE_BYTE] = TEX_NUM_BYTE_IMAGES_CPU; - tex_image_byte4_start = TEX_IMAGE_BYTE4_START_CPU; - tex_image_float_start = TEX_IMAGE_FLOAT_START_CPU; - tex_image_byte_start = TEX_IMAGE_BYTE_START_CPU; + /* Set image limits */ +#define SET_TEX_IMAGES_LIMITS(ARCH) \ + { \ + tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_NUM_FLOAT4_ ## ARCH; \ + tex_num_images[IMAGE_DATA_TYPE_BYTE4] = TEX_NUM_BYTE4_ ## ARCH; \ + tex_num_images[IMAGE_DATA_TYPE_FLOAT] = TEX_NUM_FLOAT_ ## ARCH; \ + tex_num_images[IMAGE_DATA_TYPE_BYTE] = TEX_NUM_BYTE_ ## ARCH; \ + tex_start_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_START_FLOAT4_ ## ARCH; \ + tex_start_images[IMAGE_DATA_TYPE_BYTE4] = TEX_START_BYTE4_ ## ARCH; \ + tex_start_images[IMAGE_DATA_TYPE_FLOAT] = TEX_START_FLOAT_ ## ARCH; \ + tex_start_images[IMAGE_DATA_TYPE_BYTE] = TEX_START_BYTE_ ## ARCH; \ } - /* CUDA (Fermi) */ - else if((info.type == DEVICE_CUDA || info.type == DEVICE_MULTI) && !info.has_bindless_textures) { - tex_num_images[IMAGE_DATA_TYPE_BYTE4] = TEX_NUM_BYTE4_IMAGES_CUDA; - tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_NUM_FLOAT4_IMAGES_CUDA; - tex_num_images[IMAGE_DATA_TYPE_FLOAT] = TEX_NUM_FLOAT_IMAGES_CUDA; - tex_num_images[IMAGE_DATA_TYPE_BYTE] = TEX_NUM_BYTE_IMAGES_CUDA; - tex_image_byte4_start = TEX_IMAGE_BYTE4_START_CUDA; - tex_image_float_start = TEX_IMAGE_FLOAT_START_CUDA; - tex_image_byte_start = TEX_IMAGE_BYTE_START_CUDA; + + if(device_type == DEVICE_CPU) { + SET_TEX_IMAGES_LIMITS(CPU); } - /* CUDA (Kepler and above) */ - else if((info.type == DEVICE_CUDA || info.type == DEVICE_MULTI) && info.has_bindless_textures) { - tex_num_images[IMAGE_DATA_TYPE_BYTE4] = TEX_NUM_BYTE4_IMAGES_CUDA_KEPLER; - tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_NUM_FLOAT4_IMAGES_CUDA_KEPLER; - tex_num_images[IMAGE_DATA_TYPE_FLOAT] = TEX_NUM_FLOAT_IMAGES_CUDA_KEPLER; - tex_num_images[IMAGE_DATA_TYPE_BYTE] = TEX_NUM_BYTE_IMAGES_CUDA_KEPLER; - tex_image_byte4_start = TEX_IMAGE_BYTE4_START_CUDA_KEPLER; - tex_image_float_start = TEX_IMAGE_FLOAT_START_CUDA_KEPLER; - tex_image_byte_start = TEX_IMAGE_BYTE_START_CUDA_KEPLER; + else if(device_type == DEVICE_CUDA) { + if(info.has_bindless_textures) { + SET_TEX_IMAGES_LIMITS(CUDA_KEPLER); + } + else { + SET_TEX_IMAGES_LIMITS(CUDA); + } } - /* OpenCL */ - else if(info.pack_images) { - tex_num_images[IMAGE_DATA_TYPE_BYTE4] = TEX_NUM_BYTE4_IMAGES_OPENCL; - tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_NUM_FLOAT4_IMAGES_OPENCL; - tex_num_images[IMAGE_DATA_TYPE_FLOAT] = TEX_NUM_FLOAT_IMAGES_OPENCL; - tex_num_images[IMAGE_DATA_TYPE_BYTE] = TEX_NUM_BYTE_IMAGES_OPENCL; - tex_image_byte4_start = TEX_IMAGE_BYTE4_START_OPENCL; - tex_image_float_start = TEX_IMAGE_FLOAT_START_OPENCL; - tex_image_byte_start = TEX_IMAGE_BYTE_START_OPENCL; + else if(device_type == DEVICE_OPENCL) { + SET_TEX_IMAGES_LIMITS(OPENCL); } - /* Should never happen */ else { - tex_num_images[IMAGE_DATA_TYPE_BYTE4] = 0; + /* Should not happen. */ tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = 0; + tex_num_images[IMAGE_DATA_TYPE_BYTE4] = 0; tex_num_images[IMAGE_DATA_TYPE_FLOAT] = 0; tex_num_images[IMAGE_DATA_TYPE_BYTE] = 0; - tex_image_byte4_start = 0; - tex_image_float_start = 0; - tex_image_byte_start = 0; + tex_start_images[IMAGE_DATA_TYPE_FLOAT4] = 0; + tex_start_images[IMAGE_DATA_TYPE_BYTE4] = 0; + tex_start_images[IMAGE_DATA_TYPE_FLOAT] = 0; + tex_start_images[IMAGE_DATA_TYPE_BYTE] = 0; assert(0); } + +#undef SET_TEX_IMAGES_LIMITS } ImageManager::~ImageManager() @@ -207,34 +206,20 @@ ImageManager::ImageDataType ImageManager::get_image_metadata(const string& filen * to device ones and vice versa. */ int ImageManager::type_index_to_flattened_slot(int slot, ImageDataType type) { - if(type == IMAGE_DATA_TYPE_BYTE4) - return slot + tex_image_byte4_start; - else if(type == IMAGE_DATA_TYPE_FLOAT) - return slot + tex_image_float_start; - else if(type == IMAGE_DATA_TYPE_BYTE) - return slot + tex_image_byte_start; - else - return slot; + return slot + tex_start_images[type]; } int ImageManager::flattened_slot_to_type_index(int flat_slot, ImageDataType *type) { - if(flat_slot >= tex_image_byte_start) { - *type = IMAGE_DATA_TYPE_BYTE; - return flat_slot - tex_image_byte_start; - } - else if(flat_slot >= tex_image_float_start) { - *type = IMAGE_DATA_TYPE_FLOAT; - return flat_slot - tex_image_float_start; - } - else if(flat_slot >= tex_image_byte4_start) { - *type = IMAGE_DATA_TYPE_BYTE4; - return flat_slot - tex_image_byte4_start; - } - else { - *type = IMAGE_DATA_TYPE_FLOAT4; - return flat_slot; + for(int i = IMAGE_DATA_NUM_TYPES - 1; i >= 0; i--) { + if(flat_slot >= tex_start_images[i]) { + *type = (ImageDataType)i; + return flat_slot - tex_start_images[i]; + } } + + /* Should not happen. */ + return flat_slot; } string ImageManager::name_from_type(int type) diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index 2ab16dd8967..8735133fd91 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -96,9 +96,8 @@ public: private: int tex_num_images[IMAGE_DATA_NUM_TYPES]; - int tex_image_byte4_start; - int tex_image_float_start; - int tex_image_byte_start; + int tex_start_images[IMAGE_DATA_NUM_TYPES]; + thread_mutex device_mutex; int animation_frame; diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp index 41e2571dc24..2a10eb474a4 100644 --- a/intern/cycles/render/integrator.cpp +++ b/intern/cycles/render/integrator.cpp @@ -204,6 +204,11 @@ void Integrator::device_free(Device *device, DeviceScene *dscene) dscene->sobol_directions.clear(); } +bool Integrator::modified(const Integrator& integrator) +{ + return !Node::equals(integrator); +} + void Integrator::tag_update(Scene *scene) { foreach(Shader *shader, scene->shaders) { diff --git a/intern/cycles/render/integrator.h b/intern/cycles/render/integrator.h index a5cfb0c7863..39eaaf246d4 100644 --- a/intern/cycles/render/integrator.h +++ b/intern/cycles/render/integrator.h @@ -86,6 +86,7 @@ public: void device_update(Device *device, DeviceScene *dscene, Scene *scene); void device_free(Device *device, DeviceScene *dscene); + bool modified(const Integrator& integrator); void tag_update(Scene *scene); }; diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp index c20bf6b5e9e..9ef35820254 100644 --- a/intern/cycles/render/light.cpp +++ b/intern/cycles/render/light.cpp @@ -247,7 +247,8 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen /* count triangles */ if(have_emission) { - for(size_t i = 0; i < mesh->triangles.size(); i++) { + size_t mesh_num_triangles = mesh->num_triangles(); + for(size_t i = 0; i < mesh_num_triangles; i++) { int shader_index = mesh->shader[i]; Shader *shader = (shader_index < mesh->used_shaders.size()) ? mesh->used_shaders[shader_index] : scene->default_surface; @@ -319,7 +320,8 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen use_light_visibility = true; } - for(size_t i = 0; i < mesh->triangles.size(); i++) { + size_t mesh_num_triangles = mesh->num_triangles(); + for(size_t i = 0; i < mesh_num_triangles; i++) { int shader_index = mesh->shader[i]; Shader *shader = (shader_index < mesh->used_shaders.size()) ? mesh->used_shaders[shader_index] : scene->default_surface; @@ -331,7 +333,7 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen distribution[offset].w = __int_as_float(object_id); offset++; - Mesh::Triangle t = mesh->triangles[i]; + Mesh::Triangle t = mesh->get_triangle(i); float3 p1 = mesh->verts[t.v[0]]; float3 p2 = mesh->verts[t.v[1]]; float3 p3 = mesh->verts[t.v[2]]; diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index d26404035eb..755b16a51c7 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -51,14 +51,14 @@ void Mesh::Triangle::bounds_grow(const float3 *verts, BoundBox& bounds) const /* Curve */ -void Mesh::Curve::bounds_grow(const int k, const float4 *curve_keys, BoundBox& bounds) const +void Mesh::Curve::bounds_grow(const int k, const float3 *curve_keys, const float *curve_radius, BoundBox& bounds) const { float3 P[4]; - P[0] = float4_to_float3(curve_keys[max(first_key + k - 1,first_key)]); - P[1] = float4_to_float3(curve_keys[first_key + k]); - P[2] = float4_to_float3(curve_keys[first_key + k + 1]); - P[3] = float4_to_float3(curve_keys[min(first_key + k + 2, first_key + num_keys - 1)]); + P[0] = curve_keys[max(first_key + k - 1,first_key)]; + P[1] = curve_keys[first_key + k]; + P[2] = curve_keys[first_key + k + 1]; + P[3] = curve_keys[min(first_key + k + 2, first_key + num_keys - 1)]; float3 lower; float3 upper; @@ -67,7 +67,7 @@ void Mesh::Curve::bounds_grow(const int k, const float4 *curve_keys, BoundBox& b curvebounds(&lower.y, &upper.y, P, 1); curvebounds(&lower.z, &upper.z, P, 2); - float mr = max(curve_keys[first_key + k].w, curve_keys[first_key + k + 1].w); + float mr = max(curve_radius[first_key + k], curve_radius[first_key + k + 1]); bounds.grow(lower, mr); bounds.grow(upper, mr); @@ -75,19 +75,42 @@ void Mesh::Curve::bounds_grow(const int k, const float4 *curve_keys, BoundBox& b /* Mesh */ +NODE_DEFINE(Mesh) +{ + NodeType* type = NodeType::add("mesh", create); + + static NodeEnum displacement_method_enum; + displacement_method_enum.insert("bump", DISPLACE_BUMP); + displacement_method_enum.insert("true", DISPLACE_TRUE); + displacement_method_enum.insert("both", DISPLACE_BOTH); + SOCKET_ENUM(displacement_method, "Displacement Method", displacement_method_enum, DISPLACE_BUMP); + + SOCKET_INT(motion_steps, "Motion Steps", 3); + SOCKET_BOOLEAN(use_motion_blur, "Use Motion Blur", false); + + SOCKET_INT_ARRAY(triangles, "Triangles", array<int>()); + SOCKET_POINT_ARRAY(verts, "Vertices", array<float3>()); + SOCKET_INT_ARRAY(shader, "Shader", array<int>()); + SOCKET_BOOLEAN_ARRAY(smooth, "Smooth", array<bool>()); + + SOCKET_POINT_ARRAY(curve_keys, "Curve Keys", array<float3>()); + SOCKET_FLOAT_ARRAY(curve_radius, "Curve Radius", array<float>()); + SOCKET_INT_ARRAY(curve_first_key, "Curve First Key", array<int>()); + SOCKET_INT_ARRAY(curve_shader, "Curve Shader", array<int>()); + + return type; +} + Mesh::Mesh() +: Node(node_type) { need_update = true; need_update_rebuild = false; transform_applied = false; transform_negative_scaled = false; transform_normal = transform_identity(); - displacement_method = DISPLACE_BUMP; bounds = BoundBox::empty; - motion_steps = 3; - use_motion_blur = false; - bvh = NULL; tri_offset = 0; @@ -99,6 +122,8 @@ Mesh::Mesh() attributes.triangle_mesh = this; curve_attributes.curve_mesh = this; + geometry_flags = GEOMETRY_NONE; + has_volume = false; has_surface_bssrdf = false; } @@ -108,21 +133,49 @@ Mesh::~Mesh() delete bvh; } -void Mesh::reserve(int numverts, int numtris, int numcurves, int numcurvekeys) +void Mesh::resize_mesh(int numverts, int numtris) { - /* reserve space to add verts and triangles later */ verts.resize(numverts); - triangles.resize(numtris); + triangles.resize(numtris * 3); shader.resize(numtris); smooth.resize(numtris); forms_quad.resize(numtris); - curve_keys.resize(numcurvekeys); - curves.resize(numcurves); + attributes.resize(); +} + +void Mesh::reserve_mesh(int numverts, int numtris) +{ + /* reserve space to add verts and triangles later */ + verts.reserve(numverts); + triangles.reserve(numtris * 3); + shader.reserve(numtris); + smooth.reserve(numtris); + + forms_quad.reserve(numtris); - attributes.reserve(); - curve_attributes.reserve(); + attributes.resize(true); +} + +void Mesh::resize_curves(int numcurves, int numkeys) +{ + curve_keys.resize(numkeys); + curve_radius.resize(numkeys); + curve_first_key.resize(numcurves); + curve_shader.resize(numcurves); + + curve_attributes.resize(); +} + +void Mesh::reserve_curves(int numcurves, int numkeys) +{ + curve_keys.reserve(numkeys); + curve_radius.reserve(numkeys); + curve_first_key.reserve(numcurves); + curve_shader.reserve(numcurves); + + curve_attributes.resize(true); } void Mesh::clear() @@ -136,7 +189,9 @@ void Mesh::clear() forms_quad.clear(); curve_keys.clear(); - curves.clear(); + curve_radius.clear(); + curve_first_key.clear(); + curve_shader.clear(); attributes.clear(); curve_attributes.clear(); @@ -151,7 +206,7 @@ void Mesh::clear() int Mesh::split_vertex(int vertex) { /* copy vertex location and vertex attributes */ - verts.push_back(verts[vertex]); + add_vertex_slow(verts[vertex]); foreach(Attribute& attr, attributes.attributes) { if(attr.element == ATTR_ELEMENT_VERTEX) { @@ -164,48 +219,36 @@ int Mesh::split_vertex(int vertex) return verts.size() - 1; } -void Mesh::set_triangle(int i, int v0, int v1, int v2, int shader_, bool smooth_, bool forms_quad_) +void Mesh::add_vertex(float3 P) { - Triangle tri; - tri.v[0] = v0; - tri.v[1] = v1; - tri.v[2] = v2; - - triangles[i] = tri; - shader[i] = shader_; - smooth[i] = smooth_; - forms_quad[i] = forms_quad_; + verts.push_back_reserved(P); +} + +void Mesh::add_vertex_slow(float3 P) +{ + verts.push_back_slow(P); } void Mesh::add_triangle(int v0, int v1, int v2, int shader_, bool smooth_, bool forms_quad_) { - Triangle tri; - tri.v[0] = v0; - tri.v[1] = v1; - tri.v[2] = v2; - - triangles.push_back(tri); - shader.push_back(shader_); - smooth.push_back(smooth_); - forms_quad.push_back(forms_quad_); + triangles.push_back_reserved(v0); + triangles.push_back_reserved(v1); + triangles.push_back_reserved(v2); + shader.push_back_reserved(shader_); + smooth.push_back_reserved(smooth_); + forms_quad.push_back_reserved(forms_quad_); } void Mesh::add_curve_key(float3 co, float radius) { - float4 key = float3_to_float4(co); - key.w = radius; - - curve_keys.push_back(key); + curve_keys.push_back_reserved(co); + curve_radius.push_back_reserved(radius); } -void Mesh::add_curve(int first_key, int num_keys, int shader) +void Mesh::add_curve(int first_key, int shader) { - Curve curve; - curve.first_key = first_key; - curve.num_keys = num_keys; - curve.shader = shader; - - curves.push_back(curve); + curve_first_key.push_back_reserved(first_key); + curve_shader.push_back_reserved(shader); } void Mesh::compute_bounds() @@ -219,7 +262,7 @@ void Mesh::compute_bounds() bnds.grow(verts[i]); for(size_t i = 0; i < curve_keys_size; i++) - bnds.grow(float4_to_float3(curve_keys[i]), curve_keys[i].w); + bnds.grow(curve_keys[i], curve_radius[i]); Attribute *attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); if(use_motion_blur && attr) { @@ -247,7 +290,7 @@ void Mesh::compute_bounds() bnds.grow_safe(verts[i]); for(size_t i = 0; i < curve_keys_size; i++) - bnds.grow_safe(float4_to_float3(curve_keys[i]), curve_keys[i].w); + bnds.grow_safe(curve_keys[i], curve_radius[i]); if(use_motion_blur && attr) { size_t steps_size = verts.size() * (motion_steps - 1); @@ -301,15 +344,14 @@ void Mesh::add_face_normals() float3 *fN = attr_fN->data_float3(); /* compute face normals */ - size_t triangles_size = triangles.size(); + size_t triangles_size = num_triangles(); bool flip = transform_negative_scaled; if(triangles_size) { float3 *verts_ptr = &verts[0]; - Triangle *triangles_ptr = &triangles[0]; for(size_t i = 0; i < triangles_size; i++) { - fN[i] = compute_face_normal(triangles_ptr[i], verts_ptr); + fN[i] = compute_face_normal(get_triangle(i), verts_ptr); if(flip) fN[i] = -fN[i]; @@ -329,7 +371,7 @@ void Mesh::add_vertex_normals() { bool flip = transform_negative_scaled; size_t verts_size = verts.size(); - size_t triangles_size = triangles.size(); + size_t triangles_size = num_triangles(); /* static vertex normals */ if(!attributes.find(ATTR_STD_VERTEX_NORMAL)) { @@ -344,11 +386,10 @@ void Mesh::add_vertex_normals() memset(vN, 0, verts.size()*sizeof(float3)); if(triangles_size) { - Triangle *triangles_ptr = &triangles[0]; for(size_t i = 0; i < triangles_size; i++) for(size_t j = 0; j < 3; j++) - vN[triangles_ptr[i].v[j]] += fN[i]; + vN[get_triangle(i).v[j]] += fN[i]; } for(size_t i = 0; i < verts_size; i++) { @@ -374,12 +415,10 @@ void Mesh::add_vertex_normals() memset(mN, 0, verts.size()*sizeof(float3)); if(triangles_size) { - Triangle *triangles_ptr = &triangles[0]; - for(size_t i = 0; i < triangles_size; i++) { for(size_t j = 0; j < 3; j++) { - float3 fN = compute_face_normal(triangles_ptr[i], mP); - mN[triangles_ptr[i].v[j]] += fN; + float3 fN = compute_face_normal(get_triangle(i), mP); + mN[get_triangle(i).v[j]] += fN; } } } @@ -402,8 +441,8 @@ void Mesh::pack_normals(Scene *scene, uint *tri_shader, float4 *vnormal) uint last_shader = -1; bool last_smooth = false; - size_t triangles_size = triangles.size(); - uint *shader_ptr = (shader.size())? &shader[0]: NULL; + size_t triangles_size = num_triangles(); + int *shader_ptr = (shader.size())? &shader[0]: NULL; bool do_transform = transform_applied; Transform ntfm = transform_normal; @@ -446,13 +485,11 @@ void Mesh::pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset) } } - size_t triangles_size = triangles.size(); + size_t triangles_size = num_triangles(); if(triangles_size) { - Triangle *triangles_ptr = &triangles[0]; - for(size_t i = 0; i < triangles_size; i++) { - Triangle t = triangles_ptr[i]; + Triangle t = get_triangle(i); tri_vindex[i] = make_float4( __int_as_float(t.v[0] + vert_offset), @@ -466,27 +503,25 @@ void Mesh::pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset) void Mesh::pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset) { size_t curve_keys_size = curve_keys.size(); - float4 *keys_ptr = NULL; /* pack curve keys */ if(curve_keys_size) { - keys_ptr = &curve_keys[0]; + float3 *keys_ptr = &curve_keys[0]; + float *radius_ptr = &curve_radius[0]; for(size_t i = 0; i < curve_keys_size; i++) - curve_key_co[i] = keys_ptr[i]; + curve_key_co[i] = make_float4(keys_ptr[i].x, keys_ptr[i].y, keys_ptr[i].z, radius_ptr[i]); } /* pack curve segments */ - size_t curve_num = curves.size(); + size_t curve_num = num_curves(); if(curve_num) { - Curve *curve_ptr = &curves[0]; - int shader_id = 0; - for(size_t i = 0; i < curve_num; i++) { - Curve curve = curve_ptr[i]; - Shader *shader = (curve.shader < used_shaders.size()) ? - used_shaders[curve.shader] : scene->default_surface; + Curve curve = get_curve(i); + int shader_id = curve_shader[i]; + Shader *shader = (shader_id < used_shaders.size()) ? + used_shaders[shader_id] : scene->default_surface; shader_id = scene->shader_manager->get_shader_id(shader, this, false); curve_data[i] = make_float4( @@ -732,7 +767,7 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce else id = scene->shader_manager->get_attribute_id(req.std); - if(mesh->triangles.size()) { + if(mesh->num_triangles()) { attr_map[index].x = id; attr_map[index].y = req.triangle_element; attr_map[index].z = as_uint(req.triangle_offset); @@ -747,7 +782,7 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce index++; - if(mesh->curves.size()) { + if(mesh->num_curves()) { attr_map[index].x = id; attr_map[index].y = req.curve_element; attr_map[index].z = as_uint(req.curve_offset); @@ -793,9 +828,9 @@ static void update_attribute_element_size(Mesh *mesh, if(mattr) { size_t size = mattr->element_size( mesh->verts.size(), - mesh->triangles.size(), + mesh->num_triangles(), mesh->motion_steps, - mesh->curves.size(), + mesh->num_curves(), mesh->curve_keys.size()); if(mattr->element == ATTR_ELEMENT_VOXEL) { @@ -836,9 +871,9 @@ static void update_attribute_element_offset(Mesh *mesh, /* store attribute data in arrays */ size_t size = mattr->element_size( mesh->verts.size(), - mesh->triangles.size(), + mesh->num_triangles(), mesh->motion_steps, - mesh->curves.size(), + mesh->num_curves(), mesh->curve_keys.size()); if(mattr->element == ATTR_ELEMENT_VOXEL) { @@ -1052,10 +1087,10 @@ void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene mesh->curve_offset = curve_size; vert_size += mesh->verts.size(); - tri_size += mesh->triangles.size(); + tri_size += mesh->num_triangles(); curve_key_size += mesh->curve_keys.size(); - curve_size += mesh->curves.size(); + curve_size += mesh->num_curves(); } if(tri_size != 0) { @@ -1465,16 +1500,17 @@ void Mesh::tessellate(DiagSplit *split) if(!forms_quad[f]) { /* triangle */ LinearTrianglePatch patch; + Triangle triangle = get_triangle(f); float3 *hull = patch.hull; float3 *normals = patch.normals; for(int i = 0; i < 3; i++) { - hull[i] = verts[triangles[f].v[i]]; + hull[i] = verts[triangle.v[i]]; } if(smooth[f]) { for(int i = 0; i < 3; i++) { - normals[i] = vN[triangles[f].v[i]]; + normals[i] = vN[triangle.v[i]]; } } else { @@ -1488,19 +1524,21 @@ void Mesh::tessellate(DiagSplit *split) else { /* quad */ LinearQuadPatch patch; + Triangle triangle0 = get_triangle(f); + Triangle triangle1 = get_triangle(f+1); float3 *hull = patch.hull; float3 *normals = patch.normals; - hull[0] = verts[triangles[f ].v[0]]; - hull[1] = verts[triangles[f ].v[1]]; - hull[3] = verts[triangles[f ].v[2]]; - hull[2] = verts[triangles[f+1].v[2]]; + hull[0] = verts[triangle0.v[0]]; + hull[1] = verts[triangle0.v[1]]; + hull[3] = verts[triangle0.v[2]]; + hull[2] = verts[triangle1.v[2]]; if(smooth[f]) { - normals[0] = vN[triangles[f ].v[0]]; - normals[1] = vN[triangles[f ].v[1]]; - normals[3] = vN[triangles[f ].v[2]]; - normals[2] = vN[triangles[f+1].v[2]]; + normals[0] = vN[triangle0.v[0]]; + normals[1] = vN[triangle0.v[1]]; + normals[3] = vN[triangle0.v[2]]; + normals[2] = vN[triangle1.v[2]]; } else { for(int i = 0; i < 4; i++) { diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h index 557b664bff3..edad6d32f00 100644 --- a/intern/cycles/render/mesh.h +++ b/intern/cycles/render/mesh.h @@ -18,6 +18,7 @@ #define __MESH_H__ #include "attribute.h" +#include "node.h" #include "shader.h" #include "util_boundbox.h" @@ -42,8 +43,10 @@ class DiagSplit; /* Mesh */ -class Mesh { +class Mesh : public Node { public: + NODE_DECLARE; + /* Mesh Triangle */ struct Triangle { int v[3]; @@ -51,17 +54,41 @@ public: void bounds_grow(const float3 *verts, BoundBox& bounds) const; }; + Triangle get_triangle(size_t i) const + { + Triangle tri = {{triangles[i*3 + 0], triangles[i*3 + 1], triangles[i*3 + 2]}}; + return tri; + } + + size_t num_triangles() const + { + return triangles.size() / 3; + } + /* Mesh Curve */ struct Curve { int first_key; int num_keys; - uint shader; int num_segments() { return num_keys - 1; } - void bounds_grow(const int k, const float4 *curve_keys, BoundBox& bounds) const; + void bounds_grow(const int k, const float3 *curve_keys, const float *curve_radius, BoundBox& bounds) const; }; + Curve get_curve(size_t i) const + { + int first = curve_first_key[i]; + int next_first = (i+1 < curve_first_key.size()) ? curve_first_key[i+1] : curve_keys.size(); + + Curve curve = {first, next_first - first}; + return curve; + } + + size_t num_curves() const + { + return curve_first_key.size(); + } + /* Displacement */ enum DisplacementMethod { DISPLACE_BUMP = 0, @@ -71,8 +98,6 @@ public: DISPLACE_NUM_METHODS, }; - ustring name; - /* Mesh Data */ enum GeometryFlags { GEOMETRY_NONE = 0, @@ -82,17 +107,19 @@ public: int geometry_flags; /* used to distinguish meshes with no verts and meshed for which geometry is not created */ - vector<float3> verts; - vector<Triangle> triangles; - vector<uint> shader; - vector<bool> smooth; - vector<bool> forms_quad; /* used to tell if triangle is part of a quad patch */ + array<int> triangles; + array<float3> verts; + array<int> shader; + array<bool> smooth; + array<bool> forms_quad; /* used to tell if triangle is part of a quad patch */ bool has_volume; /* Set in the device_update_flags(). */ bool has_surface_bssrdf; /* Set in the device_update_flags(). */ - vector<float4> curve_keys; /* co + radius */ - vector<Curve> curves; + array<float3> curve_keys; + array<float> curve_radius; + array<int> curve_first_key; + array<int> curve_shader; vector<Shader*> used_shaders; AttributeSet attributes; @@ -123,12 +150,16 @@ public: Mesh(); ~Mesh(); - void reserve(int numverts, int numfaces, int numcurves, int numcurvekeys); + void resize_mesh(int numverts, int numfaces); + void reserve_mesh(int numverts, int numfaces); + void resize_curves(int numcurves, int numkeys); + void reserve_curves(int numcurves, int numkeys); void clear(); - void set_triangle(int i, int v0, int v1, int v2, int shader, bool smooth, bool forms_quad = false); + void add_vertex(float3 P); + void add_vertex_slow(float3 P); void add_triangle(int v0, int v1, int v2, int shader, bool smooth, bool forms_quad = false); void add_curve_key(float3 loc, float radius); - void add_curve(int first_key, int num_keys, int shader); + void add_curve(int first_key, int shader); int split_vertex(int vertex); void compute_bounds(); diff --git a/intern/cycles/render/mesh_displace.cpp b/intern/cycles/render/mesh_displace.cpp index d19bf2084d7..95f46ff02a2 100644 --- a/intern/cycles/render/mesh_displace.cpp +++ b/intern/cycles/render/mesh_displace.cpp @@ -60,8 +60,9 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me uint4 *d_input_data = d_input.resize(num_verts); size_t d_input_size = 0; - for(size_t i = 0; i < mesh->triangles.size(); i++) { - Mesh::Triangle t = mesh->triangles[i]; + size_t num_triangles = mesh->num_triangles(); + for(size_t i = 0; i < num_triangles; i++) { + Mesh::Triangle t = mesh->get_triangle(i); int shader_index = mesh->shader[i]; Shader *shader = (shader_index < mesh->used_shaders.size()) ? mesh->used_shaders[shader_index] : scene->default_surface; @@ -146,8 +147,8 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me float4 *offset = (float4*)d_output.data_pointer; Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - for(size_t i = 0; i < mesh->triangles.size(); i++) { - Mesh::Triangle t = mesh->triangles[i]; + for(size_t i = 0; i < num_triangles; i++) { + Mesh::Triangle t = mesh->get_triangle(i); int shader_index = mesh->shader[i]; Shader *shader = (shader_index < mesh->used_shaders.size()) ? mesh->used_shaders[shader_index] : scene->default_surface; diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 998d9cf31dd..4656b3de9f3 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -30,9 +30,9 @@ CCL_NAMESPACE_BEGIN /* Texture Mapping */ -static ShaderEnum texture_mapping_type_init() +static NodeEnum texture_mapping_type_init() { - ShaderEnum enm; + NodeEnum enm; enm.insert("Point", TextureMapping::POINT); enm.insert("Texture", TextureMapping::TEXTURE); @@ -42,9 +42,9 @@ static ShaderEnum texture_mapping_type_init() return enm; } -static ShaderEnum texture_mapping_mapping_init() +static NodeEnum texture_mapping_mapping_init() { - ShaderEnum enm; + NodeEnum enm; enm.insert("None", TextureMapping::NONE); enm.insert("X", TextureMapping::X); @@ -54,9 +54,9 @@ static ShaderEnum texture_mapping_mapping_init() return enm; } -static ShaderEnum texture_mapping_projection_init() +static NodeEnum texture_mapping_projection_init() { - ShaderEnum enm; + NodeEnum enm; enm.insert("Flat", TextureMapping::FLAT); enm.insert("Cube", TextureMapping::CUBE); @@ -66,9 +66,9 @@ static ShaderEnum texture_mapping_projection_init() return enm; } -ShaderEnum TextureMapping::type_enum = texture_mapping_type_init(); -ShaderEnum TextureMapping::mapping_enum = texture_mapping_mapping_init(); -ShaderEnum TextureMapping::projection_enum = texture_mapping_projection_init(); +NodeEnum TextureMapping::type_enum = texture_mapping_type_init(); +NodeEnum TextureMapping::mapping_enum = texture_mapping_mapping_init(); +NodeEnum TextureMapping::projection_enum = texture_mapping_projection_init(); TextureMapping::TextureMapping() { @@ -193,7 +193,7 @@ int TextureMapping::compile_begin(SVMCompiler& compiler, ShaderInput *vector_in) { if(!skip()) { int offset_in = compiler.stack_assign(vector_in); - int offset_out = compiler.stack_find_offset(SHADER_SOCKET_VECTOR); + int offset_out = compiler.stack_find_offset(SocketType::VECTOR); compile(compiler, offset_in, offset_out); @@ -206,7 +206,7 @@ int TextureMapping::compile_begin(SVMCompiler& compiler, ShaderInput *vector_in) void TextureMapping::compile_end(SVMCompiler& compiler, ShaderInput *vector_in, int vector_offset) { if(!skip()) { - compiler.stack_clear_offset(vector_in->type, vector_offset); + compiler.stack_clear_offset(vector_in->type(), vector_offset); } } @@ -222,9 +222,9 @@ void TextureMapping::compile(OSLCompiler &compiler) /* Image Texture */ -static ShaderEnum color_space_init() +static NodeEnum color_space_init() { - ShaderEnum enm; + NodeEnum enm; enm.insert("None", 0); enm.insert("Color", 1); @@ -232,9 +232,9 @@ static ShaderEnum color_space_init() return enm; } -static ShaderEnum image_projection_init() +static NodeEnum image_projection_init() { - ShaderEnum enm; + NodeEnum enm; enm.insert("Flat", NODE_IMAGE_PROJ_FLAT); enm.insert("Box", NODE_IMAGE_PROJ_BOX); @@ -259,8 +259,8 @@ static const char* get_osl_interpolation_parameter(InterpolationType interpolati } } -ShaderEnum ImageTextureNode::color_space_enum = color_space_init(); -ShaderEnum ImageTextureNode::projection_enum = image_projection_init(); +NodeEnum ImageTextureNode::color_space_enum = color_space_init(); +NodeEnum ImageTextureNode::projection_enum = image_projection_init(); ImageTextureNode::ImageTextureNode() : ImageSlotTextureNode("image_texture") @@ -272,16 +272,16 @@ ImageTextureNode::ImageTextureNode() use_alpha = true; filename = ""; builtin_data = NULL; - color_space = ustring("Color"); - projection = ustring("Flat"); + color_space = NODE_COLOR_SPACE_COLOR; + projection = NODE_IMAGE_PROJ_FLAT; interpolation = INTERPOLATION_LINEAR; extension = EXTENSION_REPEAT; projection_blend = 0.0f; animated = false; - add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_UV); - add_output("Color", SHADER_SOCKET_COLOR); - add_output("Alpha", SHADER_SOCKET_FLOAT); + add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_UV); + add_output("Color", SocketType::COLOR); + add_output("Alpha", SocketType::FLOAT); } ImageTextureNode::~ImageTextureNode() @@ -341,10 +341,10 @@ void ImageTextureNode::compile(SVMCompiler& compiler) } if(slot != -1) { - int srgb = (is_linear || color_space != "Color")? 0: 1; + int srgb = (is_linear || color_space != NODE_COLOR_SPACE_COLOR)? 0: 1; int vector_offset = tex_mapping.compile_begin(compiler, vector_in); - if(projection != "Box") { + if(projection != NODE_IMAGE_PROJ_BOX) { compiler.add_node(NODE_TEX_IMAGE, slot, compiler.encode_uchar4( @@ -352,7 +352,7 @@ void ImageTextureNode::compile(SVMCompiler& compiler) compiler.stack_assign_if_linked(color_out), compiler.stack_assign_if_linked(alpha_out), srgb), - projection_enum[projection]); + projection); } else { compiler.add_node(NODE_TEX_IMAGE_BOX, @@ -421,7 +421,7 @@ void ImageTextureNode::compile(OSLCompiler& compiler) */ compiler.parameter("filename", string_printf("@%d", slot).c_str()); } - if(is_linear || color_space != "Color") + if(is_linear || color_space != NODE_COLOR_SPACE_COLOR) compiler.parameter("color_space", "Linear"); else compiler.parameter("color_space", "sRGB"); @@ -433,14 +433,14 @@ void ImageTextureNode::compile(OSLCompiler& compiler) switch(extension) { case EXTENSION_EXTEND: - compiler.parameter("wrap", "clamp"); + compiler.parameter("extension", "clamp"); break; case EXTENSION_CLIP: - compiler.parameter("wrap", "black"); + compiler.parameter("extension", "black"); break; case EXTENSION_REPEAT: default: - compiler.parameter("wrap", "periodic"); + compiler.parameter("extension", "periodic"); break; } @@ -449,9 +449,9 @@ void ImageTextureNode::compile(OSLCompiler& compiler) /* Environment Texture */ -static ShaderEnum env_projection_init() +static NodeEnum env_projection_init() { - ShaderEnum enm; + NodeEnum enm; enm.insert("Equirectangular", 0); enm.insert("Mirror Ball", 1); @@ -459,8 +459,8 @@ static ShaderEnum env_projection_init() return enm; } -ShaderEnum EnvironmentTextureNode::color_space_enum = color_space_init(); -ShaderEnum EnvironmentTextureNode::projection_enum = env_projection_init(); +NodeEnum EnvironmentTextureNode::color_space_enum = color_space_init(); +NodeEnum EnvironmentTextureNode::projection_enum = env_projection_init(); EnvironmentTextureNode::EnvironmentTextureNode() : ImageSlotTextureNode("environment_texture") @@ -472,14 +472,14 @@ EnvironmentTextureNode::EnvironmentTextureNode() use_alpha = true; filename = ""; builtin_data = NULL; - color_space = ustring("Color"); + color_space = NODE_COLOR_SPACE_COLOR; interpolation = INTERPOLATION_LINEAR; - projection = ustring("Equirectangular"); + projection = NODE_ENVIRONMENT_EQUIRECTANGULAR; animated = false; - add_input("Vector", SHADER_SOCKET_VECTOR, ShaderInput::POSITION); - add_output("Color", SHADER_SOCKET_COLOR); - add_output("Alpha", SHADER_SOCKET_FLOAT); + add_input("Vector", SocketType::VECTOR, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_POSITION); + add_output("Color", SocketType::COLOR); + add_output("Alpha", SocketType::FLOAT); } EnvironmentTextureNode::~EnvironmentTextureNode() @@ -537,7 +537,7 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler) } if(slot != -1) { - int srgb = (is_linear || color_space != "Color")? 0: 1; + int srgb = (is_linear || color_space != NODE_COLOR_SPACE_COLOR)? 0: 1; int vector_offset = tex_mapping.compile_begin(compiler, vector_in); compiler.add_node(NODE_TEX_ENVIRONMENT, @@ -547,7 +547,7 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler) compiler.stack_assign_if_linked(color_out), compiler.stack_assign_if_linked(alpha_out), srgb), - projection_enum[projection]); + projection); tex_mapping.compile_end(compiler, vector_in, vector_offset); } @@ -602,8 +602,8 @@ void EnvironmentTextureNode::compile(OSLCompiler& compiler) else { compiler.parameter("filename", string_printf("@%d", slot).c_str()); } - compiler.parameter("projection", projection); - if(is_linear || color_space != "Color") + compiler.parameter("projection", projection_enum[projection]); + if(is_linear || color_space != NODE_COLOR_SPACE_COLOR) compiler.parameter("color_space", "Linear"); else compiler.parameter("color_space", "sRGB"); @@ -738,9 +738,9 @@ static void sky_texture_precompute_new(SunSky *sunsky, float3 dir, float turbidi arhosekskymodelstate_free(sky_state); } -static ShaderEnum sky_type_init() +static NodeEnum sky_type_init() { - ShaderEnum enm; + NodeEnum enm; enm.insert("Preetham", NODE_SKY_OLD); enm.insert("Hosek / Wilkie", NODE_SKY_NEW); @@ -748,19 +748,19 @@ static ShaderEnum sky_type_init() return enm; } -ShaderEnum SkyTextureNode::type_enum = sky_type_init(); +NodeEnum SkyTextureNode::type_enum = sky_type_init(); SkyTextureNode::SkyTextureNode() : TextureNode("sky_texture") { - type = ustring("Hosek / Wilkie"); + type = NODE_SKY_NEW; sun_direction = make_float3(0.0f, 0.0f, 1.0f); turbidity = 2.2f; ground_albedo = 0.3f; - add_input("Vector", SHADER_SOCKET_VECTOR, ShaderInput::POSITION); - add_output("Color", SHADER_SOCKET_COLOR); + add_input("Vector", SocketType::VECTOR, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_POSITION); + add_output("Color", SocketType::COLOR); } void SkyTextureNode::compile(SVMCompiler& compiler) @@ -769,15 +769,15 @@ void SkyTextureNode::compile(SVMCompiler& compiler) ShaderOutput *color_out = output("Color"); SunSky sunsky; - if(type_enum[type] == NODE_SKY_OLD) + if(type == NODE_SKY_OLD) sky_texture_precompute_old(&sunsky, sun_direction, turbidity); - else if(type_enum[type] == NODE_SKY_NEW) + else if(type == NODE_SKY_NEW) sky_texture_precompute_new(&sunsky, sun_direction, turbidity, ground_albedo); else assert(false); int vector_offset = tex_mapping.compile_begin(compiler, vector_in); - int sky_model = type_enum[type]; + int sky_model = type; compiler.stack_assign(color_out); compiler.add_node(NODE_TEX_SKY, vector_offset, compiler.stack_assign(color_out), sky_model); @@ -799,14 +799,14 @@ void SkyTextureNode::compile(OSLCompiler& compiler) SunSky sunsky; - if(type_enum[type] == NODE_SKY_OLD) + if(type == NODE_SKY_OLD) sky_texture_precompute_old(&sunsky, sun_direction, turbidity); - else if(type_enum[type] == NODE_SKY_NEW) + else if(type == NODE_SKY_NEW) sky_texture_precompute_new(&sunsky, sun_direction, turbidity, ground_albedo); else assert(false); - compiler.parameter("sky_model", type); + compiler.parameter("sky_model", type_enum[type]); compiler.parameter("theta", sunsky.theta); compiler.parameter("phi", sunsky.phi); compiler.parameter_color("radiance", make_float3(sunsky.radiance_x, sunsky.radiance_y, sunsky.radiance_z)); @@ -818,9 +818,9 @@ void SkyTextureNode::compile(OSLCompiler& compiler) /* Gradient Texture */ -static ShaderEnum gradient_type_init() +static NodeEnum gradient_type_init() { - ShaderEnum enm; + NodeEnum enm; enm.insert("Linear", NODE_BLEND_LINEAR); enm.insert("Quadratic", NODE_BLEND_QUADRATIC); @@ -833,16 +833,16 @@ static ShaderEnum gradient_type_init() return enm; } -ShaderEnum GradientTextureNode::type_enum = gradient_type_init(); +NodeEnum GradientTextureNode::type_enum = gradient_type_init(); GradientTextureNode::GradientTextureNode() : TextureNode("gradient_texture") { - type = ustring("Linear"); + type = NODE_BLEND_LINEAR; - add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED); - add_output("Color", SHADER_SOCKET_COLOR); - add_output("Fac", SHADER_SOCKET_FLOAT); + add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); + add_output("Color", SocketType::COLOR); + add_output("Fac", SocketType::FLOAT); } void GradientTextureNode::compile(SVMCompiler& compiler) @@ -855,7 +855,7 @@ void GradientTextureNode::compile(SVMCompiler& compiler) compiler.add_node(NODE_TEX_GRADIENT, compiler.encode_uchar4( - type_enum[type], + type, vector_offset, compiler.stack_assign_if_linked(fac_out), compiler.stack_assign_if_linked(color_out))); @@ -867,7 +867,7 @@ void GradientTextureNode::compile(OSLCompiler& compiler) { tex_mapping.compile(compiler); - compiler.parameter("Type", type); + compiler.parameter("type", type_enum[type]); compiler.add(this, "node_gradient_texture"); } @@ -876,13 +876,13 @@ void GradientTextureNode::compile(OSLCompiler& compiler) NoiseTextureNode::NoiseTextureNode() : TextureNode("noise_texture") { - add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED); - add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f); - add_input("Detail", SHADER_SOCKET_FLOAT, 2.0f); - add_input("Distortion", SHADER_SOCKET_FLOAT, 0.0f); + add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); + add_input("Scale", SocketType::FLOAT, 1.0f); + add_input("Detail", SocketType::FLOAT, 2.0f); + add_input("Distortion", SocketType::FLOAT, 0.0f); - add_output("Color", SHADER_SOCKET_COLOR); - add_output("Fac", SHADER_SOCKET_FLOAT); + add_output("Color", SocketType::COLOR); + add_output("Fac", SocketType::FLOAT); } void NoiseTextureNode::compile(SVMCompiler& compiler) @@ -906,9 +906,9 @@ void NoiseTextureNode::compile(SVMCompiler& compiler) compiler.stack_assign_if_linked(color_out), compiler.stack_assign_if_linked(fac_out))); compiler.add_node( - __float_as_int(scale_in->value.x), - __float_as_int(detail_in->value.x), - __float_as_int(distortion_in->value.x)); + __float_as_int(scale_in->value_float()), + __float_as_int(detail_in->value_float()), + __float_as_int(distortion_in->value_float())); tex_mapping.compile_end(compiler, vector_in, vector_offset); } @@ -922,9 +922,9 @@ void NoiseTextureNode::compile(OSLCompiler& compiler) /* Voronoi Texture */ -static ShaderEnum voronoi_coloring_init() +static NodeEnum voronoi_coloring_init() { - ShaderEnum enm; + NodeEnum enm; enm.insert("Intensity", NODE_VORONOI_INTENSITY); enm.insert("Cells", NODE_VORONOI_CELLS); @@ -932,18 +932,18 @@ static ShaderEnum voronoi_coloring_init() return enm; } -ShaderEnum VoronoiTextureNode::coloring_enum = voronoi_coloring_init(); +NodeEnum VoronoiTextureNode::coloring_enum = voronoi_coloring_init(); VoronoiTextureNode::VoronoiTextureNode() : TextureNode("voronoi_texture") { - coloring = ustring("Intensity"); + coloring = NODE_VORONOI_INTENSITY; - add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f); - add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED); + add_input("Scale", SocketType::FLOAT, 1.0f); + add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); - add_output("Color", SHADER_SOCKET_COLOR); - add_output("Fac", SHADER_SOCKET_FLOAT); + add_output("Color", SocketType::COLOR); + add_output("Fac", SocketType::FLOAT); } void VoronoiTextureNode::compile(SVMCompiler& compiler) @@ -956,13 +956,13 @@ void VoronoiTextureNode::compile(SVMCompiler& compiler) int vector_offset = tex_mapping.compile_begin(compiler, vector_in); compiler.add_node(NODE_TEX_VORONOI, - coloring_enum[coloring], + coloring, compiler.encode_uchar4( compiler.stack_assign_if_linked(scale_in), vector_offset, compiler.stack_assign(fac_out), compiler.stack_assign(color_out)), - __float_as_int(scale_in->value.x)); + __float_as_int(scale_in->value_float())); tex_mapping.compile_end(compiler, vector_in, vector_offset); } @@ -971,15 +971,15 @@ void VoronoiTextureNode::compile(OSLCompiler& compiler) { tex_mapping.compile(compiler); - compiler.parameter("Coloring", coloring); + compiler.parameter("coloring", coloring_enum[coloring]); compiler.add(this, "node_voronoi_texture"); } /* Musgrave Texture */ -static ShaderEnum musgrave_type_init() +static NodeEnum musgrave_type_init() { - ShaderEnum enm; + NodeEnum enm; enm.insert("Multifractal", NODE_MUSGRAVE_MULTIFRACTAL); enm.insert("fBM", NODE_MUSGRAVE_FBM); @@ -990,23 +990,23 @@ static ShaderEnum musgrave_type_init() return enm; } -ShaderEnum MusgraveTextureNode::type_enum = musgrave_type_init(); +NodeEnum MusgraveTextureNode::type_enum = musgrave_type_init(); MusgraveTextureNode::MusgraveTextureNode() : TextureNode("musgrave_texture") { - type = ustring("fBM"); + type = NODE_MUSGRAVE_FBM; - add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f); - add_input("Detail", SHADER_SOCKET_FLOAT, 2.0f); - add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED); - add_input("Dimension", SHADER_SOCKET_FLOAT, 2.0f); - add_input("Lacunarity", SHADER_SOCKET_FLOAT, 1.0f); - add_input("Offset", SHADER_SOCKET_FLOAT, 0.0f); - add_input("Gain", SHADER_SOCKET_FLOAT, 1.0f); + add_input("Scale", SocketType::FLOAT, 1.0f); + add_input("Detail", SocketType::FLOAT, 2.0f); + add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); + add_input("Dimension", SocketType::FLOAT, 2.0f); + add_input("Lacunarity", SocketType::FLOAT, 1.0f); + add_input("Offset", SocketType::FLOAT, 0.0f); + add_input("Gain", SocketType::FLOAT, 1.0f); - add_output("Fac", SHADER_SOCKET_FLOAT); - add_output("Color", SHADER_SOCKET_COLOR); + add_output("Fac", SocketType::FLOAT); + add_output("Color", SocketType::COLOR); } void MusgraveTextureNode::compile(SVMCompiler& compiler) @@ -1025,7 +1025,7 @@ void MusgraveTextureNode::compile(SVMCompiler& compiler) compiler.add_node(NODE_TEX_MUSGRAVE, compiler.encode_uchar4( - type_enum[type], + type, vector_offset, compiler.stack_assign_if_linked(color_out), compiler.stack_assign_if_linked(fac_out)), @@ -1037,12 +1037,12 @@ void MusgraveTextureNode::compile(SVMCompiler& compiler) compiler.encode_uchar4( compiler.stack_assign_if_linked(gain_in), compiler.stack_assign_if_linked(scale_in))); - compiler.add_node(__float_as_int(dimension_in->value.x), - __float_as_int(lacunarity_in->value.x), - __float_as_int(detail_in->value.x), - __float_as_int(offset_in->value.x)); - compiler.add_node(__float_as_int(gain_in->value.x), - __float_as_int(scale_in->value.x)); + compiler.add_node(__float_as_int(dimension_in->value_float()), + __float_as_int(lacunarity_in->value_float()), + __float_as_int(detail_in->value_float()), + __float_as_int(offset_in->value_float())); + compiler.add_node(__float_as_int(gain_in->value_float()), + __float_as_int(scale_in->value_float())); tex_mapping.compile_end(compiler, vector_in, vector_offset); } @@ -1051,16 +1051,16 @@ void MusgraveTextureNode::compile(OSLCompiler& compiler) { tex_mapping.compile(compiler); - compiler.parameter("Type", type); + compiler.parameter("type", type_enum[type]); compiler.add(this, "node_musgrave_texture"); } /* Wave Texture */ -static ShaderEnum wave_type_init() +static NodeEnum wave_type_init() { - ShaderEnum enm; + NodeEnum enm; enm.insert("Bands", NODE_WAVE_BANDS); enm.insert("Rings", NODE_WAVE_RINGS); @@ -1068,9 +1068,9 @@ static ShaderEnum wave_type_init() return enm; } -static ShaderEnum wave_profile_init() +static NodeEnum wave_profile_init() { - ShaderEnum enm; + NodeEnum enm; enm.insert("Sine", NODE_WAVE_PROFILE_SIN); enm.insert("Saw", NODE_WAVE_PROFILE_SAW); @@ -1078,23 +1078,23 @@ static ShaderEnum wave_profile_init() return enm; } -ShaderEnum WaveTextureNode::type_enum = wave_type_init(); -ShaderEnum WaveTextureNode::profile_enum = wave_profile_init(); +NodeEnum WaveTextureNode::type_enum = wave_type_init(); +NodeEnum WaveTextureNode::profile_enum = wave_profile_init(); WaveTextureNode::WaveTextureNode() : TextureNode("wave_texture") { - type = ustring("Bands"); - profile = ustring("Sine"); + type = NODE_WAVE_BANDS; + profile = NODE_WAVE_PROFILE_SIN; - add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f); - add_input("Distortion", SHADER_SOCKET_FLOAT, 0.0f); - add_input("Detail", SHADER_SOCKET_FLOAT, 2.0f); - add_input("Detail Scale", SHADER_SOCKET_FLOAT, 1.0f); - add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED); + add_input("Scale", SocketType::FLOAT, 1.0f); + add_input("Distortion", SocketType::FLOAT, 0.0f); + add_input("Detail", SocketType::FLOAT, 2.0f); + add_input("Detail Scale", SocketType::FLOAT, 1.0f); + add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); - add_output("Color", SHADER_SOCKET_COLOR); - add_output("Fac", SHADER_SOCKET_FLOAT); + add_output("Color", SocketType::COLOR); + add_output("Fac", SocketType::FLOAT); } void WaveTextureNode::compile(SVMCompiler& compiler) @@ -1111,7 +1111,7 @@ void WaveTextureNode::compile(SVMCompiler& compiler) compiler.add_node(NODE_TEX_WAVE, compiler.encode_uchar4( - type_enum[type], + type, compiler.stack_assign_if_linked(color_out), compiler.stack_assign_if_linked(fac_out), compiler.stack_assign_if_linked(dscale_in)), @@ -1120,13 +1120,13 @@ void WaveTextureNode::compile(SVMCompiler& compiler) compiler.stack_assign_if_linked(scale_in), compiler.stack_assign_if_linked(detail_in), compiler.stack_assign_if_linked(distortion_in)), - profile_enum[profile]); + profile); compiler.add_node( - __float_as_int(scale_in->value.x), - __float_as_int(detail_in->value.x), - __float_as_int(distortion_in->value.x), - __float_as_int(dscale_in->value.x)); + __float_as_int(scale_in->value_float()), + __float_as_int(detail_in->value_float()), + __float_as_int(distortion_in->value_float()), + __float_as_int(dscale_in->value_float())); tex_mapping.compile_end(compiler, vector_in, vector_offset); } @@ -1135,8 +1135,8 @@ void WaveTextureNode::compile(OSLCompiler& compiler) { tex_mapping.compile(compiler); - compiler.parameter("Type", type); - compiler.parameter("Profile", profile); + compiler.parameter("type", type_enum[type]); + compiler.parameter("profile", profile_enum[profile]); compiler.add(this, "node_wave_texture"); } @@ -1148,12 +1148,12 @@ MagicTextureNode::MagicTextureNode() { depth = 2; - add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED); - add_input("Scale", SHADER_SOCKET_FLOAT, 5.0f); - add_input("Distortion", SHADER_SOCKET_FLOAT, 1.0f); + add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); + add_input("Scale", SocketType::FLOAT, 5.0f); + add_input("Distortion", SocketType::FLOAT, 1.0f); - add_output("Color", SHADER_SOCKET_COLOR); - add_output("Fac", SHADER_SOCKET_FLOAT); + add_output("Color", SocketType::COLOR); + add_output("Fac", SocketType::FLOAT); } void MagicTextureNode::compile(SVMCompiler& compiler) @@ -1176,8 +1176,8 @@ void MagicTextureNode::compile(SVMCompiler& compiler) compiler.stack_assign_if_linked(scale_in), compiler.stack_assign_if_linked(distortion_in))); compiler.add_node( - __float_as_int(scale_in->value.x), - __float_as_int(distortion_in->value.x)); + __float_as_int(scale_in->value_float()), + __float_as_int(distortion_in->value_float())); tex_mapping.compile_end(compiler, vector_in, vector_offset); } @@ -1186,7 +1186,7 @@ void MagicTextureNode::compile(OSLCompiler& compiler) { tex_mapping.compile(compiler); - compiler.parameter("Depth", depth); + compiler.parameter("depth", depth); compiler.add(this, "node_magic_texture"); } @@ -1195,13 +1195,13 @@ void MagicTextureNode::compile(OSLCompiler& compiler) CheckerTextureNode::CheckerTextureNode() : TextureNode("checker_texture") { - add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED); - add_input("Color1", SHADER_SOCKET_COLOR); - add_input("Color2", SHADER_SOCKET_COLOR); - add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f); + add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); + add_input("Color1", SocketType::COLOR); + add_input("Color2", SocketType::COLOR); + add_input("Scale", SocketType::FLOAT, 1.0f); - add_output("Color", SHADER_SOCKET_COLOR); - add_output("Fac", SHADER_SOCKET_FLOAT); + add_output("Color", SocketType::COLOR); + add_output("Fac", SocketType::FLOAT); } void CheckerTextureNode::compile(SVMCompiler& compiler) @@ -1225,7 +1225,7 @@ void CheckerTextureNode::compile(SVMCompiler& compiler) compiler.encode_uchar4( compiler.stack_assign_if_linked(color_out), compiler.stack_assign_if_linked(fac_out)), - __float_as_int(scale_in->value.x)); + __float_as_int(scale_in->value_float())); tex_mapping.compile_end(compiler, vector_in, vector_offset); } @@ -1247,18 +1247,18 @@ BrickTextureNode::BrickTextureNode() squash = 1.0f; squash_frequency = 2; - add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED); - add_input("Color1", SHADER_SOCKET_COLOR); - add_input("Color2", SHADER_SOCKET_COLOR); - add_input("Mortar", SHADER_SOCKET_COLOR); - add_input("Scale", SHADER_SOCKET_FLOAT, 5.0f); - add_input("Mortar Size", SHADER_SOCKET_FLOAT, 0.02f); - add_input("Bias", SHADER_SOCKET_FLOAT, 0.0f); - add_input("Brick Width", SHADER_SOCKET_FLOAT, 0.5f); - add_input("Row Height", SHADER_SOCKET_FLOAT, 0.25f); + add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); + add_input("Color1", SocketType::COLOR); + add_input("Color2", SocketType::COLOR); + add_input("Mortar", SocketType::COLOR); + add_input("Scale", SocketType::FLOAT, 5.0f); + add_input("Mortar Size", SocketType::FLOAT, 0.02f); + add_input("Bias", SocketType::FLOAT, 0.0f); + add_input("Brick Width", SocketType::FLOAT, 0.5f); + add_input("Row Height", SocketType::FLOAT, 0.25f); - add_output("Color", SHADER_SOCKET_COLOR); - add_output("Fac", SHADER_SOCKET_FLOAT); + add_output("Color", SocketType::COLOR); + add_output("Fac", SocketType::FLOAT); } void BrickTextureNode::compile(SVMCompiler& compiler) @@ -1295,12 +1295,12 @@ void BrickTextureNode::compile(SVMCompiler& compiler) compiler.stack_assign_if_linked(fac_out))); compiler.add_node(compiler.encode_uchar4(offset_frequency, squash_frequency), - __float_as_int(scale_in->value.x), - __float_as_int(mortar_size_in->value.x), - __float_as_int(bias_in->value.x)); + __float_as_int(scale_in->value_float()), + __float_as_int(mortar_size_in->value_float()), + __float_as_int(bias_in->value_float())); - compiler.add_node(__float_as_int(brick_width_in->value.x), - __float_as_int(row_height_in->value.x), + compiler.add_node(__float_as_int(brick_width_in->value_float()), + __float_as_int(row_height_in->value_float()), __float_as_int(offset), __float_as_int(squash)); @@ -1311,18 +1311,18 @@ void BrickTextureNode::compile(OSLCompiler& compiler) { tex_mapping.compile(compiler); - compiler.parameter("Offset", offset); - compiler.parameter("OffsetFrequency", offset_frequency); - compiler.parameter("Squash", squash); - compiler.parameter("SquashFrequency", squash_frequency); + compiler.parameter("offset", offset); + compiler.parameter("offset_frequency", offset_frequency); + compiler.parameter("squash", squash); + compiler.parameter("squash_frequency", squash_frequency); compiler.add(this, "node_brick_texture"); } /* Point Density Texture */ -static ShaderEnum point_density_space_init() +static NodeEnum point_density_space_init() { - ShaderEnum enm; + NodeEnum enm; enm.insert("Object", NODE_TEX_VOXEL_SPACE_OBJECT); enm.insert("World", NODE_TEX_VOXEL_SPACE_WORLD); @@ -1330,7 +1330,7 @@ static ShaderEnum point_density_space_init() return enm; } -ShaderEnum PointDensityTextureNode::space_enum = point_density_space_init(); +NodeEnum PointDensityTextureNode::space_enum = point_density_space_init(); PointDensityTextureNode::PointDensityTextureNode() : ShaderNode("point_density") @@ -1338,15 +1338,15 @@ PointDensityTextureNode::PointDensityTextureNode() image_manager = NULL; slot = -1; filename = ""; - space = ustring("Object"); + space = NODE_TEX_VOXEL_SPACE_OBJECT; builtin_data = NULL; interpolation = INTERPOLATION_LINEAR; tfm = transform_identity(); - add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::POSITION); - add_output("Density", SHADER_SOCKET_FLOAT); - add_output("Color", SHADER_SOCKET_COLOR); + add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_POSITION); + add_output("Density", SocketType::FLOAT); + add_output("Color", SocketType::COLOR); } PointDensityTextureNode::~PointDensityTextureNode() @@ -1405,8 +1405,8 @@ void PointDensityTextureNode::compile(SVMCompiler& compiler) compiler.encode_uchar4(compiler.stack_assign(vector_in), compiler.stack_assign_if_linked(density_out), compiler.stack_assign_if_linked(color_out), - space_enum[space])); - if(space == "World") { + space)); + if(space == NODE_TEX_VOXEL_SPACE_WORLD) { compiler.add_node(tfm.x); compiler.add_node(tfm.y); compiler.add_node(tfm.z); @@ -1453,7 +1453,7 @@ void PointDensityTextureNode::compile(OSLCompiler& compiler) if(slot != -1) { compiler.parameter("filename", string_printf("@%d", slot).c_str()); } - if(space == "World") { + if(space == NODE_TEX_VOXEL_SPACE_WORLD) { compiler.parameter("mapping", transform_transpose(tfm)); compiler.parameter("use_mapping", 1); } @@ -1481,9 +1481,9 @@ NormalNode::NormalNode() { direction = make_float3(0.0f, 0.0f, 1.0f); - add_input("Normal", SHADER_SOCKET_NORMAL); - add_output("Normal", SHADER_SOCKET_NORMAL); - add_output("Dot", SHADER_SOCKET_FLOAT); + add_input("Normal", SocketType::NORMAL); + add_output("Normal", SocketType::NORMAL); + add_output("Dot", SocketType::FLOAT); } void NormalNode::compile(SVMCompiler& compiler) @@ -1504,7 +1504,7 @@ void NormalNode::compile(SVMCompiler& compiler) void NormalNode::compile(OSLCompiler& compiler) { - compiler.parameter_normal("Direction", direction); + compiler.parameter_normal("direction", direction); compiler.add(this, "node_normal"); } @@ -1513,8 +1513,8 @@ void NormalNode::compile(OSLCompiler& compiler) MappingNode::MappingNode() : ShaderNode("mapping") { - add_input("Vector", SHADER_SOCKET_POINT); - add_output("Vector", SHADER_SOCKET_POINT); + add_input("Vector", SocketType::POINT); + add_output("Vector", SocketType::POINT); } void MappingNode::compile(SVMCompiler& compiler) @@ -1536,9 +1536,41 @@ void MappingNode::compile(OSLCompiler& compiler) compiler.add(this, "node_mapping"); } +/* RGBToBW */ + +RGBToBWNode::RGBToBWNode() +: ShaderNode("rgb_to_bw") +{ + add_input("Color", SocketType::COLOR); + add_output("Val", SocketType::FLOAT); +} + +bool RGBToBWNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +{ + if(inputs[0]->link == NULL) { + optimized->set(linear_rgb_to_gray(inputs[0]->value())); + return true; + } + + return false; +} + +void RGBToBWNode::compile(SVMCompiler& compiler) +{ + compiler.add_node(NODE_CONVERT, + NODE_CONVERT_CF, + compiler.stack_assign(inputs[0]), + compiler.stack_assign(outputs[0])); +} + +void RGBToBWNode::compile(OSLCompiler& compiler) +{ + compiler.add(this, "node_convert_from_color"); +} + /* Convert */ -ConvertNode::ConvertNode(ShaderSocketType from_, ShaderSocketType to_, bool autoconvert) +ConvertNode::ConvertNode(SocketType::Type from_, SocketType::Type to_, bool autoconvert) : ShaderNode("convert") { from = from_; @@ -1551,92 +1583,72 @@ ConvertNode::ConvertNode(ShaderSocketType from_, ShaderSocketType to_, bool auto special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT; } - if(from == SHADER_SOCKET_FLOAT) - add_input("Val", SHADER_SOCKET_FLOAT); - else if(from == SHADER_SOCKET_INT) - add_input("ValInt", SHADER_SOCKET_INT); - else if(from == SHADER_SOCKET_COLOR) - add_input("Color", SHADER_SOCKET_COLOR); - else if(from == SHADER_SOCKET_VECTOR) - add_input("Vector", SHADER_SOCKET_VECTOR); - else if(from == SHADER_SOCKET_POINT) - add_input("Point", SHADER_SOCKET_POINT); - else if(from == SHADER_SOCKET_NORMAL) - add_input("Normal", SHADER_SOCKET_NORMAL); - else if(from == SHADER_SOCKET_STRING) - add_input("String", SHADER_SOCKET_STRING); - else if(from == SHADER_SOCKET_CLOSURE) - add_input("Closure", SHADER_SOCKET_CLOSURE); + if(from == SocketType::FLOAT) + add_input("value_float", SocketType::FLOAT); + else if(from == SocketType::INT) + add_input("value_int", SocketType::INT); + else if(from == SocketType::COLOR) + add_input("value_color", SocketType::COLOR); + else if(from == SocketType::VECTOR) + add_input("value_vector", SocketType::VECTOR); + else if(from == SocketType::POINT) + add_input("value_point", SocketType::POINT); + else if(from == SocketType::NORMAL) + add_input("value_normal", SocketType::NORMAL); + else if(from == SocketType::STRING) + add_input("value_string", SocketType::STRING); + else if(from == SocketType::CLOSURE) + add_input("value_closure", SocketType::CLOSURE); else assert(0); - if(to == SHADER_SOCKET_FLOAT) - add_output("Val", SHADER_SOCKET_FLOAT); - else if(to == SHADER_SOCKET_INT) - add_output("ValInt", SHADER_SOCKET_INT); - else if(to == SHADER_SOCKET_COLOR) - add_output("Color", SHADER_SOCKET_COLOR); - else if(to == SHADER_SOCKET_VECTOR) - add_output("Vector", SHADER_SOCKET_VECTOR); - else if(to == SHADER_SOCKET_POINT) - add_output("Point", SHADER_SOCKET_POINT); - else if(to == SHADER_SOCKET_NORMAL) - add_output("Normal", SHADER_SOCKET_NORMAL); - else if(to == SHADER_SOCKET_STRING) - add_output("String", SHADER_SOCKET_STRING); - else if(to == SHADER_SOCKET_CLOSURE) - add_output("Closure", SHADER_SOCKET_CLOSURE); + if(to == SocketType::FLOAT) + add_output("value_float", SocketType::FLOAT); + else if(to == SocketType::INT) + add_output("value_int", SocketType::INT); + else if(to == SocketType::COLOR) + add_output("value_color", SocketType::COLOR); + else if(to == SocketType::VECTOR) + add_output("value_vector", SocketType::VECTOR); + else if(to == SocketType::POINT) + add_output("value_point", SocketType::POINT); + else if(to == SocketType::NORMAL) + add_output("value_normal", SocketType::NORMAL); + else if(to == SocketType::STRING) + add_output("value_string", SocketType::STRING); + else if(to == SocketType::CLOSURE) + add_output("value_closure", SocketType::CLOSURE); else assert(0); } -bool ConvertNode::constant_fold(ShaderGraph * /*graph*/, - ShaderOutput * /*socket*/, - float3 *optimized_value) +bool ConvertNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) { ShaderInput *in = inputs[0]; - float3 value = in->value; + float3 value = in->value(); /* TODO(DingTo): conversion from/to int is not supported yet, don't fold in that case */ if(in->link == NULL) { - if(from == SHADER_SOCKET_FLOAT) { - if(to == SHADER_SOCKET_INT) - /* float to int */ - return false; - else - /* float to float3 */ - *optimized_value = make_float3(value.x, value.x, value.x); - } - else if(from == SHADER_SOCKET_INT) { - if(to == SHADER_SOCKET_FLOAT) - /* int to float */ - return false; - else - /* int to vector/point/normal */ - return false; - } - else if(to == SHADER_SOCKET_FLOAT) { - if(from == SHADER_SOCKET_COLOR) - /* color to float */ - optimized_value->x = linear_rgb_to_gray(value); - else - /* vector/point/normal to float */ - optimized_value->x = average(value); - } - else if(to == SHADER_SOCKET_INT) { - if(from == SHADER_SOCKET_COLOR) - /* color to int */ - return false; - else - /* vector/point/normal to int */ - return false; + if(from == SocketType::FLOAT) { + if(SocketType::is_float3(to)) { + optimized->set(make_float3(value.x, value.x, value.x)); + return true; + } } - else { - *optimized_value = value; + else if(SocketType::is_float3(from)) { + if(to == SocketType::FLOAT) { + if(from == SocketType::COLOR) + optimized->set(linear_rgb_to_gray(value)); + else + optimized->set(average(value)); + return true; + } + else if(SocketType::is_float3(to)) { + optimized->set(value); + return true; + } } - - return true; } return false; @@ -1650,32 +1662,32 @@ void ConvertNode::compile(SVMCompiler& compiler) ShaderInput *in = inputs[0]; ShaderOutput *out = outputs[0]; - if(from == SHADER_SOCKET_FLOAT) { - if(to == SHADER_SOCKET_INT) + if(from == SocketType::FLOAT) { + if(to == SocketType::INT) /* float to int */ compiler.add_node(NODE_CONVERT, NODE_CONVERT_FI, compiler.stack_assign(in), compiler.stack_assign(out)); else /* float to float3 */ compiler.add_node(NODE_CONVERT, NODE_CONVERT_FV, compiler.stack_assign(in), compiler.stack_assign(out)); } - else if(from == SHADER_SOCKET_INT) { - if(to == SHADER_SOCKET_FLOAT) + else if(from == SocketType::INT) { + if(to == SocketType::FLOAT) /* int to float */ compiler.add_node(NODE_CONVERT, NODE_CONVERT_IF, compiler.stack_assign(in), compiler.stack_assign(out)); else /* int to vector/point/normal */ compiler.add_node(NODE_CONVERT, NODE_CONVERT_IV, compiler.stack_assign(in), compiler.stack_assign(out)); } - else if(to == SHADER_SOCKET_FLOAT) { - if(from == SHADER_SOCKET_COLOR) + else if(to == SocketType::FLOAT) { + if(from == SocketType::COLOR) /* color to float */ compiler.add_node(NODE_CONVERT, NODE_CONVERT_CF, compiler.stack_assign(in), compiler.stack_assign(out)); else /* vector/point/normal to float */ compiler.add_node(NODE_CONVERT, NODE_CONVERT_VF, compiler.stack_assign(in), compiler.stack_assign(out)); } - else if(to == SHADER_SOCKET_INT) { - if(from == SHADER_SOCKET_COLOR) + else if(to == SocketType::INT) { + if(from == SocketType::COLOR) /* color to int */ compiler.add_node(NODE_CONVERT, NODE_CONVERT_CI, compiler.stack_assign(in), compiler.stack_assign(out)); else @@ -1691,7 +1703,7 @@ void ConvertNode::compile(SVMCompiler& compiler) else { /* set 0,0,0 value */ compiler.add_node(NODE_VALUE_V, compiler.stack_assign(out)); - compiler.add_node(NODE_VALUE_V, in->value); + compiler.add_node(NODE_VALUE_V, in->value()); } } } @@ -1701,17 +1713,17 @@ void ConvertNode::compile(OSLCompiler& compiler) /* constant folding should eliminate proxy nodes */ assert(from != to); - if(from == SHADER_SOCKET_FLOAT) + if(from == SocketType::FLOAT) compiler.add(this, "node_convert_from_float"); - else if(from == SHADER_SOCKET_INT) + else if(from == SocketType::INT) compiler.add(this, "node_convert_from_int"); - else if(from == SHADER_SOCKET_COLOR) + else if(from == SocketType::COLOR) compiler.add(this, "node_convert_from_color"); - else if(from == SHADER_SOCKET_VECTOR) + else if(from == SocketType::VECTOR) compiler.add(this, "node_convert_from_vector"); - else if(from == SHADER_SOCKET_POINT) + else if(from == SocketType::POINT) compiler.add(this, "node_convert_from_point"); - else if(from == SHADER_SOCKET_NORMAL) + else if(from == SocketType::NORMAL) compiler.add(this, "node_convert_from_normal"); else assert(0); @@ -1724,17 +1736,17 @@ BsdfNode::BsdfNode(bool scattering_) { special_type = SHADER_SPECIAL_TYPE_CLOSURE; - add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f)); - add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL); - add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM); + add_input("Color", SocketType::COLOR, make_float3(0.8f, 0.8f, 0.8f)); + add_input("Normal", SocketType::NORMAL, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + add_input("SurfaceMixWeight", SocketType::FLOAT, 0.0f, SocketType::SVM_INTERNAL); if(scattering) { closure = CLOSURE_BSSRDF_CUBIC_ID; - add_output("BSSRDF", SHADER_SOCKET_CLOSURE); + add_output("BSSRDF", SocketType::CLOSURE); } else { closure = CLOSURE_BSDF_DIFFUSE_ID; - add_output("BSDF", SHADER_SOCKET_CLOSURE); + add_output("BSDF", SocketType::CLOSURE); } } @@ -1747,7 +1759,7 @@ void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput * if(color_in->link) compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in)); else - compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value); + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value()); int normal_offset = compiler.stack_assign_if_linked(normal_in); int tangent_offset = (tangent_in) ? compiler.stack_assign_if_linked(tangent_in) : SVM_STACK_INVALID; @@ -1759,8 +1771,8 @@ void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput * (param1)? compiler.stack_assign(param1): SVM_STACK_INVALID, (param2)? compiler.stack_assign(param2): SVM_STACK_INVALID, compiler.closure_mix_weight_offset()), - __float_as_int((param1)? param1->value.x: 0.0f), - __float_as_int((param2)? param2->value.x: 0.0f)); + __float_as_int((param1)? param1->value_float(): 0.0f), + __float_as_int((param2)? param2->value_float(): 0.0f)); compiler.add_node(normal_offset, tangent_offset, param3_offset, param4_offset); } @@ -1777,9 +1789,9 @@ void BsdfNode::compile(OSLCompiler& /*compiler*/) /* Anisotropic BSDF Closure */ -static ShaderEnum aniso_distribution_init() +static NodeEnum aniso_distribution_init() { - ShaderEnum enm; + NodeEnum enm; enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID); enm.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID); @@ -1788,18 +1800,18 @@ static ShaderEnum aniso_distribution_init() return enm; } -ShaderEnum AnisotropicBsdfNode::distribution_enum = aniso_distribution_init(); +NodeEnum AnisotropicBsdfNode::distribution_enum = aniso_distribution_init(); AnisotropicBsdfNode::AnisotropicBsdfNode() { closure = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID; - distribution = ustring("GGX"); + distribution = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID; - add_input("Tangent", SHADER_SOCKET_VECTOR, ShaderInput::TANGENT); + add_input("Tangent", SocketType::VECTOR, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TANGENT); - add_input("Roughness", SHADER_SOCKET_FLOAT, 0.2f); - add_input("Anisotropy", SHADER_SOCKET_FLOAT, 0.5f); - add_input("Rotation", SHADER_SOCKET_FLOAT, 0.0f); + add_input("Roughness", SocketType::FLOAT, 0.2f); + add_input("Anisotropy", SocketType::FLOAT, 0.5f); + add_input("Rotation", SocketType::FLOAT, 0.0f); } void AnisotropicBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes) @@ -1816,22 +1828,22 @@ void AnisotropicBsdfNode::attributes(Shader *shader, AttributeRequestSet *attrib void AnisotropicBsdfNode::compile(SVMCompiler& compiler) { - closure = (ClosureType)distribution_enum[distribution]; + closure = distribution; BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation")); } void AnisotropicBsdfNode::compile(OSLCompiler& compiler) { - compiler.parameter("distribution", distribution); + compiler.parameter("distribution", distribution_enum[distribution]); compiler.add(this, "node_anisotropic_bsdf"); } /* Glossy BSDF Closure */ -static ShaderEnum glossy_distribution_init() +static NodeEnum glossy_distribution_init() { - ShaderEnum enm; + NodeEnum enm; enm.insert("Sharp", CLOSURE_BSDF_REFLECTION_ID); enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID); @@ -1841,20 +1853,20 @@ static ShaderEnum glossy_distribution_init() return enm; } -ShaderEnum GlossyBsdfNode::distribution_enum = glossy_distribution_init(); +NodeEnum GlossyBsdfNode::distribution_enum = glossy_distribution_init(); GlossyBsdfNode::GlossyBsdfNode() { closure = CLOSURE_BSDF_MICROFACET_GGX_ID; - distribution = ustring("GGX"); - distribution_orig = ustring(""); + distribution = CLOSURE_BSDF_MICROFACET_GGX_ID; + distribution_orig = NBUILTIN_CLOSURES; - add_input("Roughness", SHADER_SOCKET_FLOAT, 0.2f); + add_input("Roughness", SocketType::FLOAT, 0.2f); } void GlossyBsdfNode::simplify_settings(Scene *scene) { - if(distribution_orig == "") { + if(distribution_orig == NBUILTIN_CLOSURES) { distribution_orig = distribution; } Integrator *integrator = scene->integrator; @@ -1863,26 +1875,26 @@ void GlossyBsdfNode::simplify_settings(Scene *scene) * Note: Keep the epsilon in sync with kernel! */ ShaderInput *roughness_input = input("Roughness"); - if(!roughness_input->link && roughness_input->value.x <= 1e-4f) { - distribution = ustring("Sharp"); + if(!roughness_input->link && roughness_input->value_float() <= 1e-4f) { + distribution = CLOSURE_BSDF_REFLECTION_ID; } } else { /* Rollback to original distribution when filter glossy is used. */ distribution = distribution_orig; } - closure = (ClosureType)distribution_enum[distribution]; + closure = distribution; } bool GlossyBsdfNode::has_integrator_dependency() { ShaderInput *roughness_input = input("Roughness"); - return !roughness_input->link && roughness_input->value.x <= 1e-4f; + return !roughness_input->link && roughness_input->value_float() <= 1e-4f; } void GlossyBsdfNode::compile(SVMCompiler& compiler) { - closure = (ClosureType)distribution_enum[distribution]; + closure = distribution; if(closure == CLOSURE_BSDF_REFLECTION_ID) BsdfNode::compile(compiler, NULL, NULL); @@ -1892,15 +1904,15 @@ void GlossyBsdfNode::compile(SVMCompiler& compiler) void GlossyBsdfNode::compile(OSLCompiler& compiler) { - compiler.parameter("distribution", distribution); + compiler.parameter("distribution", distribution_enum[distribution]); compiler.add(this, "node_glossy_bsdf"); } /* Glass BSDF Closure */ -static ShaderEnum glass_distribution_init() +static NodeEnum glass_distribution_init() { - ShaderEnum enm; + NodeEnum enm; enm.insert("Sharp", CLOSURE_BSDF_SHARP_GLASS_ID); enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID); @@ -1909,21 +1921,21 @@ static ShaderEnum glass_distribution_init() return enm; } -ShaderEnum GlassBsdfNode::distribution_enum = glass_distribution_init(); +NodeEnum GlassBsdfNode::distribution_enum = glass_distribution_init(); GlassBsdfNode::GlassBsdfNode() { closure = CLOSURE_BSDF_SHARP_GLASS_ID; - distribution = ustring("Sharp"); - distribution_orig = ustring(""); + distribution = CLOSURE_BSDF_SHARP_GLASS_ID; + distribution_orig = NBUILTIN_CLOSURES; - add_input("Roughness", SHADER_SOCKET_FLOAT, 0.0f); - add_input("IOR", SHADER_SOCKET_FLOAT, 0.3f); + add_input("Roughness", SocketType::FLOAT, 0.0f); + add_input("IOR", SocketType::FLOAT, 0.3f); } void GlassBsdfNode::simplify_settings(Scene *scene) { - if(distribution_orig == "") { + if(distribution_orig == NBUILTIN_CLOSURES) { distribution_orig = distribution; } Integrator *integrator = scene->integrator; @@ -1932,26 +1944,26 @@ void GlassBsdfNode::simplify_settings(Scene *scene) * Note: Keep the epsilon in sync with kernel! */ ShaderInput *roughness_input = input("Roughness"); - if(!roughness_input->link && roughness_input->value.x <= 1e-4f) { - distribution = ustring("Sharp"); + if(!roughness_input->link && roughness_input->value_float() <= 1e-4f) { + distribution = CLOSURE_BSDF_SHARP_GLASS_ID; } } else { /* Rollback to original distribution when filter glossy is used. */ distribution = distribution_orig; } - closure = (ClosureType)distribution_enum[distribution]; + closure = distribution; } bool GlassBsdfNode::has_integrator_dependency() { ShaderInput *roughness_input = input("Roughness"); - return !roughness_input->link && roughness_input->value.x <= 1e-4f; + return !roughness_input->link && roughness_input->value_float() <= 1e-4f; } void GlassBsdfNode::compile(SVMCompiler& compiler) { - closure = (ClosureType)distribution_enum[distribution]; + closure = distribution; if(closure == CLOSURE_BSDF_SHARP_GLASS_ID) BsdfNode::compile(compiler, NULL, input("IOR")); @@ -1961,15 +1973,15 @@ void GlassBsdfNode::compile(SVMCompiler& compiler) void GlassBsdfNode::compile(OSLCompiler& compiler) { - compiler.parameter("distribution", distribution); + compiler.parameter("distribution", distribution_enum[distribution]); compiler.add(this, "node_glass_bsdf"); } /* Refraction BSDF Closure */ -static ShaderEnum refraction_distribution_init() +static NodeEnum refraction_distribution_init() { - ShaderEnum enm; + NodeEnum enm; enm.insert("Sharp", CLOSURE_BSDF_REFRACTION_ID); enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID); @@ -1978,21 +1990,21 @@ static ShaderEnum refraction_distribution_init() return enm; } -ShaderEnum RefractionBsdfNode::distribution_enum = refraction_distribution_init(); +NodeEnum RefractionBsdfNode::distribution_enum = refraction_distribution_init(); RefractionBsdfNode::RefractionBsdfNode() { closure = CLOSURE_BSDF_REFRACTION_ID; - distribution = ustring("Sharp"); - distribution_orig = ustring(""); + distribution = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; + distribution_orig = NBUILTIN_CLOSURES; - add_input("Roughness", SHADER_SOCKET_FLOAT, 0.0f); - add_input("IOR", SHADER_SOCKET_FLOAT, 0.3f); + add_input("Roughness", SocketType::FLOAT, 0.0f); + add_input("IOR", SocketType::FLOAT, 0.3f); } void RefractionBsdfNode::simplify_settings(Scene *scene) { - if(distribution_orig == "") { + if(distribution_orig == NBUILTIN_CLOSURES) { distribution_orig = distribution; } Integrator *integrator = scene->integrator; @@ -2001,26 +2013,26 @@ void RefractionBsdfNode::simplify_settings(Scene *scene) * Note: Keep the epsilon in sync with kernel! */ ShaderInput *roughness_input = input("Roughness"); - if(!roughness_input->link && roughness_input->value.x <= 1e-4f) { - distribution = ustring("Sharp"); + if(!roughness_input->link && roughness_input->value_float() <= 1e-4f) { + distribution = CLOSURE_BSDF_REFRACTION_ID; } } else { /* Rollback to original distribution when filter glossy is used. */ distribution = distribution_orig; } - closure = (ClosureType)distribution_enum[distribution]; + closure = distribution; } bool RefractionBsdfNode::has_integrator_dependency() { ShaderInput *roughness_input = input("Roughness"); - return !roughness_input->link && roughness_input->value.x <= 1e-4f; + return !roughness_input->link && roughness_input->value_float() <= 1e-4f; } void RefractionBsdfNode::compile(SVMCompiler& compiler) { - closure = (ClosureType)distribution_enum[distribution]; + closure = distribution; if(closure == CLOSURE_BSDF_REFRACTION_ID) BsdfNode::compile(compiler, NULL, input("IOR")); @@ -2030,15 +2042,15 @@ void RefractionBsdfNode::compile(SVMCompiler& compiler) void RefractionBsdfNode::compile(OSLCompiler& compiler) { - compiler.parameter("distribution", distribution); + compiler.parameter("distribution", distribution_enum[distribution]); compiler.add(this, "node_refraction_bsdf"); } /* Toon BSDF Closure */ -static ShaderEnum toon_component_init() +static NodeEnum toon_component_init() { - ShaderEnum enm; + NodeEnum enm; enm.insert("Diffuse", CLOSURE_BSDF_DIFFUSE_TOON_ID); enm.insert("Glossy", CLOSURE_BSDF_GLOSSY_TOON_ID); @@ -2046,27 +2058,27 @@ static ShaderEnum toon_component_init() return enm; } -ShaderEnum ToonBsdfNode::component_enum = toon_component_init(); +NodeEnum ToonBsdfNode::component_enum = toon_component_init(); ToonBsdfNode::ToonBsdfNode() { closure = CLOSURE_BSDF_DIFFUSE_TOON_ID; - component = ustring("Diffuse"); + component = CLOSURE_BSDF_DIFFUSE_TOON_ID; - add_input("Size", SHADER_SOCKET_FLOAT, 0.5f); - add_input("Smooth", SHADER_SOCKET_FLOAT, 0.0f); + add_input("Size", SocketType::FLOAT, 0.5f); + add_input("Smooth", SocketType::FLOAT, 0.0f); } void ToonBsdfNode::compile(SVMCompiler& compiler) { - closure = (ClosureType)component_enum[component]; + closure = component; BsdfNode::compile(compiler, input("Size"), input("Smooth")); } void ToonBsdfNode::compile(OSLCompiler& compiler) { - compiler.parameter("component", component); + compiler.parameter("component", component_enum[component]); compiler.add(this, "node_toon_bsdf"); } @@ -2076,7 +2088,7 @@ VelvetBsdfNode::VelvetBsdfNode() { closure = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID; - add_input("Sigma", SHADER_SOCKET_FLOAT, 1.0f); + add_input("Sigma", SocketType::FLOAT, 1.0f); } void VelvetBsdfNode::compile(SVMCompiler& compiler) @@ -2094,7 +2106,7 @@ void VelvetBsdfNode::compile(OSLCompiler& compiler) DiffuseBsdfNode::DiffuseBsdfNode() { closure = CLOSURE_BSDF_DIFFUSE_ID; - add_input("Roughness", SHADER_SOCKET_FLOAT, 0.0f); + add_input("Roughness", SocketType::FLOAT, 0.0f); } void DiffuseBsdfNode::compile(SVMCompiler& compiler) @@ -2144,9 +2156,9 @@ void TransparentBsdfNode::compile(OSLCompiler& compiler) /* Subsurface Scattering Closure */ -static ShaderEnum subsurface_falloff_init() +static NodeEnum subsurface_falloff_init() { - ShaderEnum enm; + NodeEnum enm; enm.insert("Cubic", CLOSURE_BSSRDF_CUBIC_ID); enm.insert("Gaussian", CLOSURE_BSSRDF_GAUSSIAN_ID); @@ -2155,28 +2167,29 @@ static ShaderEnum subsurface_falloff_init() return enm; } -ShaderEnum SubsurfaceScatteringNode::falloff_enum = subsurface_falloff_init(); +NodeEnum SubsurfaceScatteringNode::falloff_enum = subsurface_falloff_init(); SubsurfaceScatteringNode::SubsurfaceScatteringNode() : BsdfNode(true) { name = "subsurface_scattering"; - closure = CLOSURE_BSSRDF_CUBIC_ID; + falloff = CLOSURE_BSSRDF_CUBIC_ID; - add_input("Scale", SHADER_SOCKET_FLOAT, 0.01f); - add_input("Radius", SHADER_SOCKET_VECTOR, make_float3(0.1f, 0.1f, 0.1f)); - add_input("Sharpness", SHADER_SOCKET_FLOAT, 0.0f); - add_input("Texture Blur", SHADER_SOCKET_FLOAT, 1.0f); + add_input("Scale", SocketType::FLOAT, 0.01f); + add_input("Radius", SocketType::VECTOR, make_float3(0.1f, 0.1f, 0.1f)); + add_input("Sharpness", SocketType::FLOAT, 0.0f); + add_input("Texture Blur", SocketType::FLOAT, 1.0f); } void SubsurfaceScatteringNode::compile(SVMCompiler& compiler) { + closure = falloff; BsdfNode::compile(compiler, input("Scale"), input("Texture Blur"), input("Radius"), input("Sharpness")); } void SubsurfaceScatteringNode::compile(OSLCompiler& compiler) { - compiler.parameter("Falloff", falloff_enum[closure]); + compiler.parameter("falloff", falloff_enum[closure]); compiler.add(this, "node_subsurface_scattering"); } @@ -2192,11 +2205,11 @@ bool SubsurfaceScatteringNode::has_bssrdf_bump() EmissionNode::EmissionNode() : ShaderNode("emission") { - add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f)); - add_input("Strength", SHADER_SOCKET_FLOAT, 10.0f); - add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM); + add_input("Color", SocketType::COLOR, make_float3(0.8f, 0.8f, 0.8f)); + add_input("Strength", SocketType::FLOAT, 10.0f); + add_input("SurfaceMixWeight", SocketType::FLOAT, 0.0f, SocketType::SVM_INTERNAL); - add_output("Emission", SHADER_SOCKET_CLOSURE); + add_output("Emission", SocketType::CLOSURE); } void EmissionNode::compile(SVMCompiler& compiler) @@ -2210,7 +2223,7 @@ void EmissionNode::compile(SVMCompiler& compiler) compiler.stack_assign(strength_in)); } else - compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value * strength_in->value.x); + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value() * strength_in->value_float()); compiler.add_node(NODE_CLOSURE_EMISSION, compiler.closure_mix_weight_offset()); } @@ -2220,13 +2233,13 @@ void EmissionNode::compile(OSLCompiler& compiler) compiler.add(this, "node_emission"); } -bool EmissionNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, float3 * /*optimized_value*/) +bool EmissionNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *) { ShaderInput *color_in = input("Color"); ShaderInput *strength_in = input("Strength"); - return ((!color_in->link && color_in->value == make_float3(0.0f, 0.0f, 0.0f)) || - (!strength_in->link && strength_in->value.x == 0.0f)); + return ((!color_in->link && color_in->value() == make_float3(0.0f, 0.0f, 0.0f)) || + (!strength_in->link && strength_in->value_float() == 0.0f)); } /* Background Closure */ @@ -2234,11 +2247,11 @@ bool EmissionNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socke BackgroundNode::BackgroundNode() : ShaderNode("background") { - add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f)); - add_input("Strength", SHADER_SOCKET_FLOAT, 1.0f); - add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM); + add_input("Color", SocketType::COLOR, make_float3(0.8f, 0.8f, 0.8f)); + add_input("Strength", SocketType::FLOAT, 1.0f); + add_input("SurfaceMixWeight", SocketType::FLOAT, 0.0f, SocketType::SVM_INTERNAL); - add_output("Background", SHADER_SOCKET_CLOSURE); + add_output("Background", SocketType::CLOSURE); } void BackgroundNode::compile(SVMCompiler& compiler) @@ -2252,7 +2265,7 @@ void BackgroundNode::compile(SVMCompiler& compiler) compiler.stack_assign(strength_in)); } else - compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value*strength_in->value.x); + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value()*strength_in->value_float()); compiler.add_node(NODE_CLOSURE_BACKGROUND, compiler.closure_mix_weight_offset()); } @@ -2262,13 +2275,13 @@ void BackgroundNode::compile(OSLCompiler& compiler) compiler.add(this, "node_background"); } -bool BackgroundNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, float3 * /*optimized_value*/) +bool BackgroundNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *) { ShaderInput *color_in = input("Color"); ShaderInput *strength_in = input("Strength"); - return ((!color_in->link && color_in->value == make_float3(0.0f, 0.0f, 0.0f)) || - (!strength_in->link && strength_in->value.x == 0.0f)); + return ((!color_in->link && color_in->value() == make_float3(0.0f, 0.0f, 0.0f)) || + (!strength_in->link && strength_in->value_float() == 0.0f)); } /* Holdout Closure */ @@ -2276,10 +2289,10 @@ bool BackgroundNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*soc HoldoutNode::HoldoutNode() : ShaderNode("holdout") { - add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM); - add_input("VolumeMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM); + add_input("SurfaceMixWeight", SocketType::FLOAT, 0.0f, SocketType::SVM_INTERNAL); + add_input("VolumeMixWeight", SocketType::FLOAT, 0.0f, SocketType::SVM_INTERNAL); - add_output("Holdout", SHADER_SOCKET_CLOSURE); + add_output("Holdout", SocketType::CLOSURE); } void HoldoutNode::compile(SVMCompiler& compiler) @@ -2300,11 +2313,11 @@ void HoldoutNode::compile(OSLCompiler& compiler) AmbientOcclusionNode::AmbientOcclusionNode() : ShaderNode("ambient_occlusion") { - add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL); - add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f)); - add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM); + add_input("NormalIn", SocketType::NORMAL, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); + add_input("Color", SocketType::COLOR, make_float3(0.8f, 0.8f, 0.8f)); + add_input("SurfaceMixWeight", SocketType::FLOAT, 0.0f, SocketType::SVM_INTERNAL); - add_output("AO", SHADER_SOCKET_CLOSURE); + add_output("AO", SocketType::CLOSURE); } void AmbientOcclusionNode::compile(SVMCompiler& compiler) @@ -2314,7 +2327,7 @@ void AmbientOcclusionNode::compile(SVMCompiler& compiler) if(color_in->link) compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in)); else - compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value); + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value()); compiler.add_node(NODE_CLOSURE_AMBIENT_OCCLUSION, compiler.closure_mix_weight_offset()); } @@ -2331,11 +2344,11 @@ VolumeNode::VolumeNode() { closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID; - add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f)); - add_input("Density", SHADER_SOCKET_FLOAT, 1.0f); - add_input("VolumeMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM); + add_input("Color", SocketType::COLOR, make_float3(0.8f, 0.8f, 0.8f)); + add_input("Density", SocketType::FLOAT, 1.0f); + add_input("VolumeMixWeight", SocketType::FLOAT, 0.0f, SocketType::SVM_INTERNAL); - add_output("Volume", SHADER_SOCKET_CLOSURE); + add_output("Volume", SocketType::CLOSURE); } void VolumeNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2) @@ -2345,15 +2358,15 @@ void VolumeNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput if(color_in->link) compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in)); else - compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value); + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value()); compiler.add_node(NODE_CLOSURE_VOLUME, compiler.encode_uchar4(closure, (param1)? compiler.stack_assign(param1): SVM_STACK_INVALID, (param2)? compiler.stack_assign(param2): SVM_STACK_INVALID, compiler.closure_mix_weight_offset()), - __float_as_int((param1)? param1->value.x: 0.0f), - __float_as_int((param2)? param2->value.x: 0.0f)); + __float_as_int((param1)? param1->value_float(): 0.0f), + __float_as_int((param2)? param2->value_float(): 0.0f)); } void VolumeNode::compile(SVMCompiler& compiler) @@ -2389,7 +2402,7 @@ ScatterVolumeNode::ScatterVolumeNode() { closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID; - add_input("Anisotropy", SHADER_SOCKET_FLOAT, 0.0f); + add_input("Anisotropy", SocketType::FLOAT, 0.0f); } void ScatterVolumeNode::compile(SVMCompiler& compiler) @@ -2404,9 +2417,9 @@ void ScatterVolumeNode::compile(OSLCompiler& compiler) /* Hair BSDF Closure */ -static ShaderEnum hair_component_init() +static NodeEnum hair_component_init() { - ShaderEnum enm; + NodeEnum enm; enm.insert("Reflection", CLOSURE_BSDF_HAIR_REFLECTION_ID); enm.insert("Transmission", CLOSURE_BSDF_HAIR_TRANSMISSION_ID); @@ -2414,29 +2427,29 @@ static ShaderEnum hair_component_init() return enm; } -ShaderEnum HairBsdfNode::component_enum = hair_component_init(); +NodeEnum HairBsdfNode::component_enum = hair_component_init(); HairBsdfNode::HairBsdfNode() { closure = CLOSURE_BSDF_HAIR_REFLECTION_ID; - component = ustring("Reflection"); + component = CLOSURE_BSDF_HAIR_REFLECTION_ID; - add_input("Offset", SHADER_SOCKET_FLOAT); - add_input("RoughnessU", SHADER_SOCKET_FLOAT); - add_input("RoughnessV", SHADER_SOCKET_FLOAT); - add_input("Tangent", SHADER_SOCKET_VECTOR); + add_input("Offset", SocketType::FLOAT); + add_input("RoughnessU", SocketType::FLOAT); + add_input("RoughnessV", SocketType::FLOAT); + add_input("Tangent", SocketType::VECTOR); } void HairBsdfNode::compile(SVMCompiler& compiler) { - closure = (ClosureType)component_enum[component]; + closure = component; BsdfNode::compile(compiler, input("RoughnessU"), input("RoughnessV"), input("Offset")); } void HairBsdfNode::compile(OSLCompiler& compiler) { - compiler.parameter("component", component); + compiler.parameter("component", component_enum[component]); compiler.add(this, "node_hair_bsdf"); } @@ -2448,15 +2461,15 @@ GeometryNode::GeometryNode() { special_type = SHADER_SPECIAL_TYPE_GEOMETRY; - add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL); - add_output("Position", SHADER_SOCKET_POINT); - add_output("Normal", SHADER_SOCKET_NORMAL); - add_output("Tangent", SHADER_SOCKET_NORMAL); - add_output("True Normal", SHADER_SOCKET_NORMAL); - add_output("Incoming", SHADER_SOCKET_VECTOR); - add_output("Parametric", SHADER_SOCKET_POINT); - add_output("Backfacing", SHADER_SOCKET_FLOAT); - add_output("Pointiness", SHADER_SOCKET_FLOAT); + add_input("NormalIn", SocketType::NORMAL, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); + add_output("Position", SocketType::POINT); + add_output("Normal", SocketType::NORMAL); + add_output("Tangent", SocketType::NORMAL); + add_output("True Normal", SocketType::NORMAL); + add_output("Incoming", SocketType::VECTOR); + add_output("Parametric", SocketType::POINT); + add_output("Backfacing", SocketType::FLOAT); + add_output("Pointiness", SocketType::FLOAT); } void GeometryNode::attributes(Shader *shader, AttributeRequestSet *attributes) @@ -2554,14 +2567,14 @@ void GeometryNode::compile(OSLCompiler& compiler) TextureCoordinateNode::TextureCoordinateNode() : ShaderNode("texture_coordinate") { - add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL); - add_output("Generated", SHADER_SOCKET_POINT); - add_output("Normal", SHADER_SOCKET_NORMAL); - add_output("UV", SHADER_SOCKET_POINT); - add_output("Object", SHADER_SOCKET_POINT); - add_output("Camera", SHADER_SOCKET_POINT); - add_output("Window", SHADER_SOCKET_POINT); - add_output("Reflection", SHADER_SOCKET_NORMAL); + add_input("NormalIn", SocketType::NORMAL, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); + add_output("Generated", SocketType::POINT); + add_output("Normal", SocketType::NORMAL); + add_output("UV", SocketType::POINT); + add_output("Object", SocketType::POINT); + add_output("Camera", SocketType::POINT); + add_output("Window", SocketType::POINT); + add_output("Reflection", SocketType::NORMAL); from_dupli = false; use_transform = false; @@ -2704,7 +2717,7 @@ UVMapNode::UVMapNode() attribute = ""; from_dupli = false; - add_output("UV", SHADER_SOCKET_POINT); + add_output("UV", SocketType::POINT); } void UVMapNode::attributes(Shader *shader, AttributeRequestSet *attributes) @@ -2773,18 +2786,18 @@ void UVMapNode::compile(OSLCompiler& compiler) LightPathNode::LightPathNode() : ShaderNode("light_path") { - add_output("Is Camera Ray", SHADER_SOCKET_FLOAT); - add_output("Is Shadow Ray", SHADER_SOCKET_FLOAT); - add_output("Is Diffuse Ray", SHADER_SOCKET_FLOAT); - add_output("Is Glossy Ray", SHADER_SOCKET_FLOAT); - add_output("Is Singular Ray", SHADER_SOCKET_FLOAT); - add_output("Is Reflection Ray", SHADER_SOCKET_FLOAT); - add_output("Is Transmission Ray", SHADER_SOCKET_FLOAT); - add_output("Is Volume Scatter Ray", SHADER_SOCKET_FLOAT); - add_output("Ray Length", SHADER_SOCKET_FLOAT); - add_output("Ray Depth", SHADER_SOCKET_FLOAT); - add_output("Transparent Depth", SHADER_SOCKET_FLOAT); - add_output("Transmission Depth", SHADER_SOCKET_FLOAT); + add_output("Is Camera Ray", SocketType::FLOAT); + add_output("Is Shadow Ray", SocketType::FLOAT); + add_output("Is Diffuse Ray", SocketType::FLOAT); + add_output("Is Glossy Ray", SocketType::FLOAT); + add_output("Is Singular Ray", SocketType::FLOAT); + add_output("Is Reflection Ray", SocketType::FLOAT); + add_output("Is Transmission Ray", SocketType::FLOAT); + add_output("Is Volume Scatter Ray", SocketType::FLOAT); + add_output("Ray Length", SocketType::FLOAT); + add_output("Ray Depth", SocketType::FLOAT); + add_output("Transparent Depth", SocketType::FLOAT); + add_output("Transmission Depth", SocketType::FLOAT); } void LightPathNode::compile(SVMCompiler& compiler) @@ -2863,11 +2876,11 @@ void LightPathNode::compile(OSLCompiler& compiler) LightFalloffNode::LightFalloffNode() : ShaderNode("light_fallof") { - add_input("Strength", SHADER_SOCKET_FLOAT, 100.0f); - add_input("Smooth", SHADER_SOCKET_FLOAT, 0.0f); - add_output("Quadratic", SHADER_SOCKET_FLOAT); - add_output("Linear", SHADER_SOCKET_FLOAT); - add_output("Constant", SHADER_SOCKET_FLOAT); + add_input("Strength", SocketType::FLOAT, 100.0f); + add_input("Smooth", SocketType::FLOAT, 0.0f); + add_output("Quadratic", SocketType::FLOAT); + add_output("Linear", SocketType::FLOAT); + add_output("Constant", SocketType::FLOAT); } void LightFalloffNode::compile(SVMCompiler& compiler) @@ -2913,10 +2926,10 @@ void LightFalloffNode::compile(OSLCompiler& compiler) ObjectInfoNode::ObjectInfoNode() : ShaderNode("object_info") { - add_output("Location", SHADER_SOCKET_VECTOR); - add_output("Object Index", SHADER_SOCKET_FLOAT); - add_output("Material Index", SHADER_SOCKET_FLOAT); - add_output("Random", SHADER_SOCKET_FLOAT); + add_output("Location", SocketType::VECTOR); + add_output("Object Index", SocketType::FLOAT); + add_output("Material Index", SocketType::FLOAT); + add_output("Random", SocketType::FLOAT); } void ObjectInfoNode::compile(SVMCompiler& compiler) @@ -2952,16 +2965,16 @@ void ObjectInfoNode::compile(OSLCompiler& compiler) ParticleInfoNode::ParticleInfoNode() : ShaderNode("particle_info") { - add_output("Index", SHADER_SOCKET_FLOAT); - add_output("Age", SHADER_SOCKET_FLOAT); - add_output("Lifetime", SHADER_SOCKET_FLOAT); - add_output("Location", SHADER_SOCKET_POINT); + add_output("Index", SocketType::FLOAT); + add_output("Age", SocketType::FLOAT); + add_output("Lifetime", SocketType::FLOAT); + add_output("Location", SocketType::POINT); #if 0 /* not yet supported */ add_output("Rotation", SHADER_SOCKET_QUATERNION); #endif - add_output("Size", SHADER_SOCKET_FLOAT); - add_output("Velocity", SHADER_SOCKET_VECTOR); - add_output("Angular Velocity", SHADER_SOCKET_VECTOR); + add_output("Size", SocketType::FLOAT); + add_output("Velocity", SocketType::VECTOR); + add_output("Angular Velocity", SocketType::VECTOR); } void ParticleInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes) @@ -3046,12 +3059,12 @@ void ParticleInfoNode::compile(OSLCompiler& compiler) HairInfoNode::HairInfoNode() : ShaderNode("hair_info") { - add_output("Is Strand", SHADER_SOCKET_FLOAT); - add_output("Intercept", SHADER_SOCKET_FLOAT); - add_output("Thickness", SHADER_SOCKET_FLOAT); - add_output("Tangent Normal", SHADER_SOCKET_NORMAL); + add_output("Is Strand", SocketType::FLOAT); + add_output("Intercept", SocketType::FLOAT); + add_output("Thickness", SocketType::FLOAT); + add_output("Tangent Normal", SocketType::NORMAL); /*output for minimum hair width transparency - deactivated*/ - /*add_output("Fade", SHADER_SOCKET_FLOAT);*/ + /*add_output("Fade", SocketType::FLOAT);*/ } void HairInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes) @@ -3110,13 +3123,12 @@ ValueNode::ValueNode() { value = 0.0f; - add_output("Value", SHADER_SOCKET_FLOAT); + add_output("Value", SocketType::FLOAT); } -bool ValueNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, - float3 *optimized_value) +bool ValueNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) { - *optimized_value = make_float3(value, value, value); + optimized->set(value); return true; } @@ -3140,13 +3152,12 @@ ColorNode::ColorNode() { value = make_float3(0.0f, 0.0f, 0.0f); - add_output("Color", SHADER_SOCKET_COLOR); + add_output("Color", SocketType::COLOR); } -bool ColorNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, - float3 *optimized_value) +bool ColorNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) { - *optimized_value = value; + optimized->set(value); return true; } @@ -3174,9 +3185,9 @@ AddClosureNode::AddClosureNode() { special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE; - add_input("Closure1", SHADER_SOCKET_CLOSURE); - add_input("Closure2", SHADER_SOCKET_CLOSURE); - add_output("Closure", SHADER_SOCKET_CLOSURE); + add_input("Closure1", SocketType::CLOSURE); + add_input("Closure2", SocketType::CLOSURE); + add_output("Closure", SocketType::CLOSURE); } void AddClosureNode::compile(SVMCompiler& /*compiler*/) @@ -3196,10 +3207,10 @@ MixClosureNode::MixClosureNode() { special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE; - add_input("Fac", SHADER_SOCKET_FLOAT, 0.5f); - add_input("Closure1", SHADER_SOCKET_CLOSURE); - add_input("Closure2", SHADER_SOCKET_CLOSURE); - add_output("Closure", SHADER_SOCKET_CLOSURE); + add_input("Fac", SocketType::FLOAT, 0.5f); + add_input("Closure1", SocketType::CLOSURE); + add_input("Closure2", SocketType::CLOSURE); + add_output("Closure", SocketType::CLOSURE); } void MixClosureNode::compile(SVMCompiler& /*compiler*/) @@ -3212,7 +3223,7 @@ void MixClosureNode::compile(OSLCompiler& compiler) compiler.add(this, "node_mix_closure"); } -bool MixClosureNode::constant_fold(ShaderGraph *graph, ShaderOutput * /*socket*/, float3 * /*optimized_value*/) +bool MixClosureNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *) { ShaderInput *fac_in = input("Fac"); ShaderInput *closure1_in = input("Closure1"); @@ -3229,12 +3240,12 @@ bool MixClosureNode::constant_fold(ShaderGraph *graph, ShaderOutput * /*socket*/ /* check for closure links and make sure factor link is disconnected */ if(closure1_in->link && closure2_in->link && !fac_in->link) { /* factor 0.0 */ - if(fac_in->value.x == 0.0f) { + if(fac_in->value_float() == 0.0f) { graph->relink(this, closure_out, closure1_in->link); return true; } /* factor 1.0 */ - else if(fac_in->value.x == 1.0f) { + else if(fac_in->value_float() == 1.0f) { graph->relink(this, closure_out, closure2_in->link); return true; } @@ -3248,10 +3259,10 @@ bool MixClosureNode::constant_fold(ShaderGraph *graph, ShaderOutput * /*socket*/ MixClosureWeightNode::MixClosureWeightNode() : ShaderNode("mix_closure_weight") { - add_input("Weight", SHADER_SOCKET_FLOAT, 1.0f); - add_input("Fac", SHADER_SOCKET_FLOAT, 1.0f); - add_output("Weight1", SHADER_SOCKET_FLOAT); - add_output("Weight2", SHADER_SOCKET_FLOAT); + add_input("Weight", SocketType::FLOAT, 1.0f); + add_input("Fac", SocketType::FLOAT, 1.0f); + add_output("Weight1", SocketType::FLOAT); + add_output("Weight2", SocketType::FLOAT); } void MixClosureWeightNode::compile(SVMCompiler& compiler) @@ -3279,9 +3290,9 @@ void MixClosureWeightNode::compile(OSLCompiler& /*compiler*/) InvertNode::InvertNode() : ShaderNode("invert") { - add_input("Fac", SHADER_SOCKET_FLOAT, 1.0f); - add_input("Color", SHADER_SOCKET_COLOR); - add_output("Color", SHADER_SOCKET_COLOR); + add_input("Fac", SocketType::FLOAT, 1.0f); + add_input("Color", SocketType::COLOR); + add_output("Color", SocketType::COLOR); } void InvertNode::compile(SVMCompiler& compiler) @@ -3306,19 +3317,19 @@ void InvertNode::compile(OSLCompiler& compiler) MixNode::MixNode() : ShaderNode("mix") { - type = ustring("Mix"); + type = NODE_MIX_BLEND; use_clamp = false; - add_input("Fac", SHADER_SOCKET_FLOAT, 0.5f); - add_input("Color1", SHADER_SOCKET_COLOR); - add_input("Color2", SHADER_SOCKET_COLOR); - add_output("Color", SHADER_SOCKET_COLOR); + add_input("Fac", SocketType::FLOAT, 0.5f); + add_input("Color1", SocketType::COLOR); + add_input("Color2", SocketType::COLOR); + add_output("Color", SocketType::COLOR); } -static ShaderEnum mix_type_init() +static NodeEnum mix_type_init() { - ShaderEnum enm; + NodeEnum enm; enm.insert("Mix", NODE_MIX_BLEND); enm.insert("Add", NODE_MIX_ADD); @@ -3342,7 +3353,7 @@ static ShaderEnum mix_type_init() return enm; } -ShaderEnum MixNode::type_enum = mix_type_init(); +NodeEnum MixNode::type_enum = mix_type_init(); void MixNode::compile(SVMCompiler& compiler) { @@ -3355,7 +3366,7 @@ void MixNode::compile(SVMCompiler& compiler) compiler.stack_assign(fac_in), compiler.stack_assign(color1_in), compiler.stack_assign(color2_in)); - compiler.add_node(NODE_MIX, type_enum[type], compiler.stack_assign(color_out)); + compiler.add_node(NODE_MIX, type, compiler.stack_assign(color_out)); if(use_clamp) { compiler.add_node(NODE_MIX, 0, compiler.stack_assign(color_out)); @@ -3365,12 +3376,12 @@ void MixNode::compile(SVMCompiler& compiler) void MixNode::compile(OSLCompiler& compiler) { - compiler.parameter("type", type); - compiler.parameter("Clamp", use_clamp); + compiler.parameter("type", type_enum[type]); + compiler.parameter("use_clamp", use_clamp); compiler.add(this, "node_mix"); } -bool MixNode::constant_fold(ShaderGraph *graph, ShaderOutput * /*socket*/, float3 * optimized_value) +bool MixNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *optimized) { if(type != ustring("Mix")) { return false; @@ -3390,19 +3401,19 @@ bool MixNode::constant_fold(ShaderGraph *graph, ShaderOutput * /*socket*/, float /* remove unused mix color input when factor is 0.0 or 1.0 */ if(!fac_in->link) { /* factor 0.0 */ - if(fac_in->value.x == 0.0f) { + if(fac_in->value_float() == 0.0f) { if(color1_in->link) graph->relink(this, color_out, color1_in->link); else - *optimized_value = color1_in->value; + optimized->set(color1_in->value()); return true; } /* factor 1.0 */ - else if(fac_in->value.x == 1.0f) { + else if(fac_in->value_float() == 1.0f) { if(color2_in->link) graph->relink(this, color_out, color2_in->link); else - *optimized_value = color2_in->value; + optimized->set(color2_in->value()); return true; } } @@ -3414,10 +3425,10 @@ bool MixNode::constant_fold(ShaderGraph *graph, ShaderOutput * /*socket*/, float CombineRGBNode::CombineRGBNode() : ShaderNode("combine_rgb") { - add_input("R", SHADER_SOCKET_FLOAT); - add_input("G", SHADER_SOCKET_FLOAT); - add_input("B", SHADER_SOCKET_FLOAT); - add_output("Image", SHADER_SOCKET_COLOR); + add_input("R", SocketType::FLOAT); + add_input("G", SocketType::FLOAT); + add_input("B", SocketType::FLOAT); + add_output("Image", SocketType::COLOR); } void CombineRGBNode::compile(SVMCompiler& compiler) @@ -3449,10 +3460,10 @@ void CombineRGBNode::compile(OSLCompiler& compiler) CombineXYZNode::CombineXYZNode() : ShaderNode("combine_xyz") { - add_input("X", SHADER_SOCKET_FLOAT); - add_input("Y", SHADER_SOCKET_FLOAT); - add_input("Z", SHADER_SOCKET_FLOAT); - add_output("Vector", SHADER_SOCKET_VECTOR); + add_input("X", SocketType::FLOAT); + add_input("Y", SocketType::FLOAT); + add_input("Z", SocketType::FLOAT); + add_output("Vector", SocketType::VECTOR); } void CombineXYZNode::compile(SVMCompiler& compiler) @@ -3484,10 +3495,10 @@ void CombineXYZNode::compile(OSLCompiler& compiler) CombineHSVNode::CombineHSVNode() : ShaderNode("combine_hsv") { - add_input("H", SHADER_SOCKET_FLOAT); - add_input("S", SHADER_SOCKET_FLOAT); - add_input("V", SHADER_SOCKET_FLOAT); - add_output("Color", SHADER_SOCKET_COLOR); + add_input("H", SocketType::FLOAT); + add_input("S", SocketType::FLOAT); + add_input("V", SocketType::FLOAT); + add_output("Color", SocketType::COLOR); } void CombineHSVNode::compile(SVMCompiler& compiler) @@ -3514,20 +3525,20 @@ void CombineHSVNode::compile(OSLCompiler& compiler) GammaNode::GammaNode() : ShaderNode("gamma") { - add_input("Color", SHADER_SOCKET_COLOR); - add_input("Gamma", SHADER_SOCKET_FLOAT); - add_output("Color", SHADER_SOCKET_COLOR); + add_input("Color", SocketType::COLOR); + add_input("Gamma", SocketType::FLOAT); + add_output("Color", SocketType::COLOR); } -bool GammaNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket, float3 *optimized_value) +bool GammaNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) { ShaderInput *color_in = input("Color"); ShaderInput *gamma_in = input("Gamma"); if(socket == output("Color")) { if(color_in->link == NULL && gamma_in->link == NULL) { - *optimized_value = svm_math_gamma_color(color_in->value, - gamma_in->value.x); + optimized->set(svm_math_gamma_color(color_in->value(), + gamma_in->value_float())); return true; } } @@ -3556,10 +3567,10 @@ void GammaNode::compile(OSLCompiler& compiler) BrightContrastNode::BrightContrastNode() : ShaderNode("brightness") { - add_input("Color", SHADER_SOCKET_COLOR); - add_input("Bright", SHADER_SOCKET_FLOAT); - add_input("Contrast", SHADER_SOCKET_FLOAT); - add_output("Color", SHADER_SOCKET_COLOR); + add_input("Color", SocketType::COLOR); + add_input("Bright", SocketType::FLOAT); + add_input("Contrast", SocketType::FLOAT); + add_output("Color", SocketType::COLOR); } void BrightContrastNode::compile(SVMCompiler& compiler) @@ -3586,10 +3597,10 @@ void BrightContrastNode::compile(OSLCompiler& compiler) SeparateRGBNode::SeparateRGBNode() : ShaderNode("separate_rgb") { - add_input("Image", SHADER_SOCKET_COLOR); - add_output("R", SHADER_SOCKET_FLOAT); - add_output("G", SHADER_SOCKET_FLOAT); - add_output("B", SHADER_SOCKET_FLOAT); + add_input("Image", SocketType::COLOR); + add_output("R", SocketType::FLOAT); + add_output("G", SocketType::FLOAT); + add_output("B", SocketType::FLOAT); } void SeparateRGBNode::compile(SVMCompiler& compiler) @@ -3621,10 +3632,10 @@ void SeparateRGBNode::compile(OSLCompiler& compiler) SeparateXYZNode::SeparateXYZNode() : ShaderNode("separate_xyz") { - add_input("Vector", SHADER_SOCKET_VECTOR); - add_output("X", SHADER_SOCKET_FLOAT); - add_output("Y", SHADER_SOCKET_FLOAT); - add_output("Z", SHADER_SOCKET_FLOAT); + add_input("Vector", SocketType::VECTOR); + add_output("X", SocketType::FLOAT); + add_output("Y", SocketType::FLOAT); + add_output("Z", SocketType::FLOAT); } void SeparateXYZNode::compile(SVMCompiler& compiler) @@ -3656,10 +3667,10 @@ void SeparateXYZNode::compile(OSLCompiler& compiler) SeparateHSVNode::SeparateHSVNode() : ShaderNode("separate_hsv") { - add_input("Color", SHADER_SOCKET_COLOR); - add_output("H", SHADER_SOCKET_FLOAT); - add_output("S", SHADER_SOCKET_FLOAT); - add_output("V", SHADER_SOCKET_FLOAT); + add_input("Color", SocketType::COLOR); + add_output("H", SocketType::FLOAT); + add_output("S", SocketType::FLOAT); + add_output("V", SocketType::FLOAT); } void SeparateHSVNode::compile(SVMCompiler& compiler) @@ -3686,12 +3697,12 @@ void SeparateHSVNode::compile(OSLCompiler& compiler) HSVNode::HSVNode() : ShaderNode("hsv") { - add_input("Hue", SHADER_SOCKET_FLOAT); - add_input("Saturation", SHADER_SOCKET_FLOAT); - add_input("Value", SHADER_SOCKET_FLOAT); - add_input("Fac", SHADER_SOCKET_FLOAT); - add_input("Color", SHADER_SOCKET_COLOR); - add_output("Color", SHADER_SOCKET_COLOR); + add_input("Hue", SocketType::FLOAT); + add_input("Saturation", SocketType::FLOAT); + add_input("Value", SocketType::FLOAT); + add_input("Fac", SocketType::FLOAT); + add_input("Color", SocketType::COLOR); + add_output("Color", SocketType::COLOR); } void HSVNode::compile(SVMCompiler& compiler) @@ -3726,9 +3737,9 @@ AttributeNode::AttributeNode() { attribute = ""; - add_output("Color", SHADER_SOCKET_COLOR); - add_output("Vector", SHADER_SOCKET_VECTOR); - add_output("Fac", SHADER_SOCKET_FLOAT); + add_output("Color", SocketType::COLOR); + add_output("Vector", SocketType::VECTOR); + add_output("Fac", SocketType::FLOAT); } void AttributeNode::attributes(Shader *shader, AttributeRequestSet *attributes) @@ -3807,9 +3818,9 @@ void AttributeNode::compile(OSLCompiler& compiler) CameraNode::CameraNode() : ShaderNode("camera") { - add_output("View Vector", SHADER_SOCKET_VECTOR); - add_output("View Z Depth", SHADER_SOCKET_FLOAT); - add_output("View Distance", SHADER_SOCKET_FLOAT); + add_output("View Vector", SocketType::VECTOR); + add_output("View Z Depth", SocketType::FLOAT); + add_output("View Distance", SocketType::FLOAT); } void CameraNode::compile(SVMCompiler& compiler) @@ -3834,9 +3845,9 @@ void CameraNode::compile(OSLCompiler& compiler) FresnelNode::FresnelNode() : ShaderNode("fresnel") { - add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL); - add_input("IOR", SHADER_SOCKET_FLOAT, 1.45f); - add_output("Fac", SHADER_SOCKET_FLOAT); + add_input("Normal", SocketType::NORMAL, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); + add_input("IOR", SocketType::FLOAT, 1.45f); + add_output("Fac", SocketType::FLOAT); } void FresnelNode::compile(SVMCompiler& compiler) @@ -3847,7 +3858,7 @@ void FresnelNode::compile(SVMCompiler& compiler) compiler.add_node(NODE_FRESNEL, compiler.stack_assign(IOR_in), - __float_as_int(IOR_in->value.x), + __float_as_int(IOR_in->value_float()), compiler.encode_uchar4( compiler.stack_assign_if_linked(normal_in), compiler.stack_assign(fac_out))); @@ -3863,11 +3874,11 @@ void FresnelNode::compile(OSLCompiler& compiler) LayerWeightNode::LayerWeightNode() : ShaderNode("layer_weight") { - add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL); - add_input("Blend", SHADER_SOCKET_FLOAT, 0.5f); + add_input("Normal", SocketType::NORMAL, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); + add_input("Blend", SocketType::FLOAT, 0.5f); - add_output("Fresnel", SHADER_SOCKET_FLOAT); - add_output("Facing", SHADER_SOCKET_FLOAT); + add_output("Fresnel", SocketType::FLOAT); + add_output("Facing", SocketType::FLOAT); } void LayerWeightNode::compile(SVMCompiler& compiler) @@ -3880,7 +3891,7 @@ void LayerWeightNode::compile(SVMCompiler& compiler) if(!fresnel_out->links.empty()) { compiler.add_node(NODE_LAYER_WEIGHT, compiler.stack_assign_if_linked(blend_in), - __float_as_int(blend_in->value.x), + __float_as_int(blend_in->value_float()), compiler.encode_uchar4(NODE_LAYER_WEIGHT_FRESNEL, compiler.stack_assign_if_linked(normal_in), compiler.stack_assign(fresnel_out))); @@ -3889,7 +3900,7 @@ void LayerWeightNode::compile(SVMCompiler& compiler) if(!facing_out->links.empty()) { compiler.add_node(NODE_LAYER_WEIGHT, compiler.stack_assign_if_linked(blend_in), - __float_as_int(blend_in->value.x), + __float_as_int(blend_in->value_float()), compiler.encode_uchar4(NODE_LAYER_WEIGHT_FACING, compiler.stack_assign_if_linked(normal_in), compiler.stack_assign(facing_out))); @@ -3906,8 +3917,8 @@ void LayerWeightNode::compile(OSLCompiler& compiler) WireframeNode::WireframeNode() : ShaderNode("wireframe") { - add_input("Size", SHADER_SOCKET_FLOAT, 0.01f); - add_output("Fac", SHADER_SOCKET_FLOAT); + add_input("Size", SocketType::FLOAT, 0.01f); + add_output("Fac", SocketType::FLOAT); use_pixel_size = false; } @@ -3951,8 +3962,8 @@ void WireframeNode::compile(OSLCompiler& compiler) WavelengthNode::WavelengthNode() : ShaderNode("wavelength") { - add_input("Wavelength", SHADER_SOCKET_FLOAT, 500.0f); - add_output("Color", SHADER_SOCKET_COLOR); + add_input("Wavelength", SocketType::FLOAT, 500.0f); + add_output("Color", SocketType::COLOR); } void WavelengthNode::compile(SVMCompiler& compiler) @@ -3975,17 +3986,17 @@ void WavelengthNode::compile(OSLCompiler& compiler) BlackbodyNode::BlackbodyNode() : ShaderNode("blackbody") { - add_input("Temperature", SHADER_SOCKET_FLOAT, 1200.0f); - add_output("Color", SHADER_SOCKET_COLOR); + add_input("Temperature", SocketType::FLOAT, 1200.0f); + add_output("Color", SocketType::COLOR); } -bool BlackbodyNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket, float3 *optimized_value) +bool BlackbodyNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) { ShaderInput *temperature_in = input("Temperature"); if(socket == output("Color")) { if(temperature_in->link == NULL) { - *optimized_value = svm_math_blackbody_color(temperature_in->value.x); + optimized->set(svm_math_blackbody_color(temperature_in->value_float())); return true; } } @@ -4015,10 +4026,10 @@ OutputNode::OutputNode() { special_type = SHADER_SPECIAL_TYPE_OUTPUT; - add_input("Surface", SHADER_SOCKET_CLOSURE); - add_input("Volume", SHADER_SOCKET_CLOSURE); - add_input("Displacement", SHADER_SOCKET_FLOAT); - add_input("Normal", SHADER_SOCKET_NORMAL); + add_input("Surface", SocketType::CLOSURE); + add_input("Volume", SocketType::CLOSURE); + add_input("Displacement", SocketType::FLOAT); + add_input("Normal", SocketType::NORMAL); } void OutputNode::compile(SVMCompiler& compiler) @@ -4047,18 +4058,18 @@ void OutputNode::compile(OSLCompiler& compiler) MathNode::MathNode() : ShaderNode("math") { - type = ustring("Add"); + type = NODE_MATH_ADD; use_clamp = false; - add_input("Value1", SHADER_SOCKET_FLOAT); - add_input("Value2", SHADER_SOCKET_FLOAT); - add_output("Value", SHADER_SOCKET_FLOAT); + add_input("Value1", SocketType::FLOAT); + add_input("Value2", SocketType::FLOAT); + add_output("Value", SocketType::FLOAT); } -static ShaderEnum math_type_init() +static NodeEnum math_type_init() { - ShaderEnum enm; + NodeEnum enm; enm.insert("Add", NODE_MATH_ADD); enm.insert("Subtract", NODE_MATH_SUBTRACT); @@ -4083,23 +4094,25 @@ static ShaderEnum math_type_init() return enm; } -ShaderEnum MathNode::type_enum = math_type_init(); +NodeEnum MathNode::type_enum = math_type_init(); -bool MathNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket, float3 *optimized_value) +bool MathNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) { ShaderInput *value1_in = input("Value1"); ShaderInput *value2_in = input("Value2"); if(socket == output("Value")) { if(value1_in->link == NULL && value2_in->link == NULL) { - optimized_value->x = svm_math((NodeMath)type_enum[type], - value1_in->value.x, - value2_in->value.x); + float value = svm_math(type, + value1_in->value_float(), + value2_in->value_float()); if(use_clamp) { - optimized_value->x = saturate(optimized_value->x); + value = saturate(value); } + optimized->set(value); + return true; } } @@ -4113,10 +4126,7 @@ void MathNode::compile(SVMCompiler& compiler) ShaderInput *value2_in = input("Value2"); ShaderOutput *value_out = output("Value"); - compiler.add_node(NODE_MATH, - type_enum[type], - compiler.stack_assign(value1_in), - compiler.stack_assign(value2_in)); + compiler.add_node(NODE_MATH, type, compiler.stack_assign(value1_in), compiler.stack_assign(value2_in)); compiler.add_node(NODE_MATH, compiler.stack_assign(value_out)); if(use_clamp) { @@ -4127,8 +4137,8 @@ void MathNode::compile(SVMCompiler& compiler) void MathNode::compile(OSLCompiler& compiler) { - compiler.parameter("type", type); - compiler.parameter("Clamp", use_clamp); + compiler.parameter("type", type_enum[type]); + compiler.parameter("use_clamp", use_clamp); compiler.add(this, "node_math"); } @@ -4137,17 +4147,17 @@ void MathNode::compile(OSLCompiler& compiler) VectorMathNode::VectorMathNode() : ShaderNode("vector_math") { - type = ustring("Add"); + type = NODE_VECTOR_MATH_ADD; - add_input("Vector1", SHADER_SOCKET_VECTOR); - add_input("Vector2", SHADER_SOCKET_VECTOR); - add_output("Value", SHADER_SOCKET_FLOAT); - add_output("Vector", SHADER_SOCKET_VECTOR); + add_input("Vector1", SocketType::VECTOR); + add_input("Vector2", SocketType::VECTOR); + add_output("Value", SocketType::FLOAT); + add_output("Vector", SocketType::VECTOR); } -static ShaderEnum vector_math_type_init() +static NodeEnum vector_math_type_init() { - ShaderEnum enm; + NodeEnum enm; enm.insert("Add", NODE_VECTOR_MATH_ADD); enm.insert("Subtract", NODE_VECTOR_MATH_SUBTRACT); @@ -4159,9 +4169,9 @@ static ShaderEnum vector_math_type_init() return enm; } -ShaderEnum VectorMathNode::type_enum = vector_math_type_init(); +NodeEnum VectorMathNode::type_enum = vector_math_type_init(); -bool VectorMathNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket, float3 *optimized_value) +bool VectorMathNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) { ShaderInput *vector1_in = input("Vector1"); ShaderInput *vector2_in = input("Vector2"); @@ -4172,16 +4182,16 @@ bool VectorMathNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket if(vector1_in->link == NULL && vector2_in->link == NULL) { svm_vector_math(&value, &vector, - (NodeVectorMath)type_enum[type], - vector1_in->value, - vector2_in->value); + type, + vector1_in->value(), + vector2_in->value()); if(socket == output("Value")) { - optimized_value->x = value; + optimized->set(value); return true; } else if(socket == output("Vector")) { - *optimized_value = vector; + optimized->set(vector); return true; } } @@ -4197,7 +4207,7 @@ void VectorMathNode::compile(SVMCompiler& compiler) ShaderOutput *vector_out = output("Vector"); compiler.add_node(NODE_VECTOR_MATH, - type_enum[type], + type, compiler.stack_assign(vector1_in), compiler.stack_assign(vector2_in)); compiler.add_node(NODE_VECTOR_MATH, @@ -4207,7 +4217,7 @@ void VectorMathNode::compile(SVMCompiler& compiler) void VectorMathNode::compile(OSLCompiler& compiler) { - compiler.parameter("type", type); + compiler.parameter("type", type_enum[type]); compiler.add(this, "node_vector_math"); } @@ -4216,17 +4226,17 @@ void VectorMathNode::compile(OSLCompiler& compiler) VectorTransformNode::VectorTransformNode() : ShaderNode("vector_transform") { - type = ustring("Vector"); - convert_from = ustring("world"); - convert_to = ustring("object"); + type = NODE_VECTOR_TRANSFORM_TYPE_VECTOR; + convert_from = NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD; + convert_to = NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT; - add_input("Vector", SHADER_SOCKET_VECTOR); - add_output("Vector", SHADER_SOCKET_VECTOR); + add_input("Vector", SocketType::VECTOR); + add_output("Vector", SocketType::VECTOR); } -static ShaderEnum vector_transform_type_init() +static NodeEnum vector_transform_type_init() { - ShaderEnum enm; + NodeEnum enm; enm.insert("Vector", NODE_VECTOR_TRANSFORM_TYPE_VECTOR); enm.insert("Point", NODE_VECTOR_TRANSFORM_TYPE_POINT); @@ -4235,9 +4245,9 @@ static ShaderEnum vector_transform_type_init() return enm; } -static ShaderEnum vector_transform_convert_space_init() +static NodeEnum vector_transform_convert_space_init() { - ShaderEnum enm; + NodeEnum enm; enm.insert("world", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD); enm.insert("object", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT); @@ -4246,8 +4256,8 @@ static ShaderEnum vector_transform_convert_space_init() return enm; } -ShaderEnum VectorTransformNode::type_enum = vector_transform_type_init(); -ShaderEnum VectorTransformNode::convert_space_enum = vector_transform_convert_space_init(); +NodeEnum VectorTransformNode::type_enum = vector_transform_type_init(); +NodeEnum VectorTransformNode::convert_space_enum = vector_transform_convert_space_init(); void VectorTransformNode::compile(SVMCompiler& compiler) { @@ -4255,18 +4265,16 @@ void VectorTransformNode::compile(SVMCompiler& compiler) ShaderOutput *vector_out = output("Vector"); compiler.add_node(NODE_VECTOR_TRANSFORM, - compiler.encode_uchar4(type_enum[type], - convert_space_enum[convert_from], - convert_space_enum[convert_to]), + compiler.encode_uchar4(type, convert_from, convert_to), compiler.encode_uchar4(compiler.stack_assign(vector_in), compiler.stack_assign(vector_out))); } void VectorTransformNode::compile(OSLCompiler& compiler) { - compiler.parameter("type", type); - compiler.parameter("convert_from", convert_from); - compiler.parameter("convert_to", convert_to); + compiler.parameter("type", type_enum[type]); + compiler.parameter("convert_from", convert_space_enum[convert_from]); + compiler.parameter("convert_to", convert_space_enum[convert_to]); compiler.add(this, "node_vector_transform"); } @@ -4281,16 +4289,16 @@ BumpNode::BumpNode() /* this input is used by the user, but after graph transform it is no longer * used and moved to sampler center/x/y instead */ - add_input("Height", SHADER_SOCKET_FLOAT); + add_input("Height", SocketType::FLOAT); - add_input("SampleCenter", SHADER_SOCKET_FLOAT); - add_input("SampleX", SHADER_SOCKET_FLOAT); - add_input("SampleY", SHADER_SOCKET_FLOAT); - add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL); - add_input("Strength", SHADER_SOCKET_FLOAT, 1.0f); - add_input("Distance", SHADER_SOCKET_FLOAT, 0.1f); + add_input("SampleCenter", SocketType::FLOAT); + add_input("SampleX", SocketType::FLOAT); + add_input("SampleY", SocketType::FLOAT); + add_input("Normal", SocketType::NORMAL, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + add_input("Strength", SocketType::FLOAT, 1.0f); + add_input("Distance", SocketType::FLOAT, 0.1f); - add_output("Normal", SHADER_SOCKET_NORMAL); + add_output("Normal", SocketType::NORMAL); } void BumpNode::compile(SVMCompiler& compiler) @@ -4323,9 +4331,7 @@ void BumpNode::compile(OSLCompiler& compiler) compiler.add(this, "node_bump"); } -bool BumpNode::constant_fold(ShaderGraph *graph, - ShaderOutput * /*socket*/, - float3 * /*optimized_value*/) +bool BumpNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *) { ShaderInput *height_in = input("Height"); ShaderInput *normal_in = input("Normal"); @@ -4352,9 +4358,9 @@ bool BumpNode::constant_fold(ShaderGraph *graph, RGBCurvesNode::RGBCurvesNode() : ShaderNode("rgb_curves") { - add_input("Fac", SHADER_SOCKET_FLOAT); - add_input("Color", SHADER_SOCKET_COLOR); - add_output("Color", SHADER_SOCKET_COLOR); + add_input("Fac", SocketType::FLOAT); + add_input("Color", SocketType::COLOR); + add_output("Color", SocketType::COLOR); min_x = 0.0f; max_x = 1.0f; @@ -4397,9 +4403,9 @@ void RGBCurvesNode::compile(OSLCompiler& compiler) VectorCurvesNode::VectorCurvesNode() : ShaderNode("vector_curves") { - add_input("Fac", SHADER_SOCKET_FLOAT); - add_input("Vector", SHADER_SOCKET_VECTOR); - add_output("Vector", SHADER_SOCKET_VECTOR); + add_input("Fac", SocketType::FLOAT); + add_input("Vector", SocketType::VECTOR); + add_output("Vector", SocketType::VECTOR); min_x = 0.0f; max_x = 1.0f; @@ -4442,9 +4448,9 @@ void VectorCurvesNode::compile(OSLCompiler& compiler) RGBRampNode::RGBRampNode() : ShaderNode("rgb_ramp") { - add_input("Fac", SHADER_SOCKET_FLOAT); - add_output("Color", SHADER_SOCKET_COLOR); - add_output("Alpha", SHADER_SOCKET_FLOAT); + add_input("Fac", SocketType::FLOAT); + add_output("Color", SocketType::COLOR); + add_output("Alpha", SocketType::FLOAT); interpolate = true; } @@ -4477,7 +4483,7 @@ void RGBRampNode::compile(OSLCompiler& compiler) compiler.parameter_color_array("ramp_color", ramp); compiler.parameter_array("ramp_alpha", ramp_alpha.data(), ramp_alpha.size()); - compiler.parameter("ramp_interpolate", interpolate); + compiler.parameter("interpolate", interpolate); compiler.add(this, "node_rgb_ramp"); } @@ -4487,8 +4493,8 @@ void RGBRampNode::compile(OSLCompiler& compiler) SetNormalNode::SetNormalNode() : ShaderNode("set_normal") { - add_input("Direction", SHADER_SOCKET_VECTOR); - add_output("Normal", SHADER_SOCKET_NORMAL); + add_input("Direction", SocketType::VECTOR); + add_output("Normal", SocketType::NORMAL); } void SetNormalNode::compile(SVMCompiler& compiler) @@ -4506,20 +4512,29 @@ void SetNormalNode::compile(OSLCompiler& compiler) compiler.add(this, "node_set_normal"); } -/* OSLScriptNode */ +/* OSLNode */ -OSLScriptNode::OSLScriptNode() -: ShaderNode("osl_script") +OSLNode::OSLNode() +: ShaderNode("osl_shader") { special_type = SHADER_SPECIAL_TYPE_SCRIPT; } -void OSLScriptNode::compile(SVMCompiler& /*compiler*/) +OSLNode::~OSLNode() +{ +} + +OSLNode* OSLNode::create(size_t) +{ + return new OSLNode(); +} + +void OSLNode::compile(SVMCompiler&) { /* doesn't work for SVM, obviously ... */ } -void OSLScriptNode::compile(OSLCompiler& compiler) +void OSLNode::compile(OSLCompiler& compiler) { if(!filepath.empty()) compiler.add(this, filepath.c_str(), true); @@ -4529,9 +4544,9 @@ void OSLScriptNode::compile(OSLCompiler& compiler) /* Normal Map */ -static ShaderEnum normal_map_space_init() +static NodeEnum normal_map_space_init() { - ShaderEnum enm; + NodeEnum enm; enm.insert("Tangent", NODE_NORMAL_MAP_TANGENT); enm.insert("Object", NODE_NORMAL_MAP_OBJECT); @@ -4542,24 +4557,24 @@ static ShaderEnum normal_map_space_init() return enm; } -ShaderEnum NormalMapNode::space_enum = normal_map_space_init(); +NodeEnum NormalMapNode::space_enum = normal_map_space_init(); NormalMapNode::NormalMapNode() : ShaderNode("normal_map") { - space = ustring("Tangent"); + space = NODE_NORMAL_MAP_TANGENT; attribute = ustring(""); - add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL); - add_input("Strength", SHADER_SOCKET_FLOAT, 1.0f); - add_input("Color", SHADER_SOCKET_COLOR); + add_input("NormalIn", SocketType::NORMAL, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); + add_input("Strength", SocketType::FLOAT, 1.0f); + add_input("Color", SocketType::COLOR); - add_output("Normal", SHADER_SOCKET_NORMAL); + add_output("Normal", SocketType::NORMAL); } void NormalMapNode::attributes(Shader *shader, AttributeRequestSet *attributes) { - if(shader->has_surface && space == ustring("Tangent")) { + if(shader->has_surface && space == NODE_NORMAL_MAP_TANGENT) { if(attribute == ustring("")) { attributes->add(ATTR_STD_UV_TANGENT); attributes->add(ATTR_STD_UV_TANGENT_SIGN); @@ -4582,7 +4597,7 @@ void NormalMapNode::compile(SVMCompiler& compiler) ShaderOutput *normal_out = output("Normal"); int attr = 0, attr_sign = 0; - if(space == ustring("Tangent")) { + if(space == NODE_NORMAL_MAP_TANGENT) { if(attribute == ustring("")) { attr = compiler.attribute(ATTR_STD_UV_TANGENT); attr_sign = compiler.attribute(ATTR_STD_UV_TANGENT_SIGN); @@ -4598,13 +4613,13 @@ void NormalMapNode::compile(SVMCompiler& compiler) compiler.stack_assign(color_in), compiler.stack_assign(strength_in), compiler.stack_assign(normal_out), - space_enum[space]), + space), attr, attr_sign); } void NormalMapNode::compile(OSLCompiler& compiler) { - if(space == ustring("Tangent")) { + if(space == NODE_NORMAL_MAP_TANGENT) { if(attribute == ustring("")) { compiler.parameter("attr_name", ustring("geom:tangent")); compiler.parameter("attr_sign_name", ustring("geom:tangent_sign")); @@ -4615,16 +4630,16 @@ void NormalMapNode::compile(OSLCompiler& compiler) } } - compiler.parameter("space", space); + compiler.parameter("space", space_enum[space]); compiler.add(this, "node_normal_map"); } /* Tangent */ -static ShaderEnum tangent_direction_type_init() +static NodeEnum tangent_direction_type_init() { - ShaderEnum enm; + NodeEnum enm; enm.insert("Radial", NODE_TANGENT_RADIAL); enm.insert("UV Map", NODE_TANGENT_UVMAP); @@ -4632,9 +4647,9 @@ static ShaderEnum tangent_direction_type_init() return enm; } -static ShaderEnum tangent_axis_init() +static NodeEnum tangent_axis_init() { - ShaderEnum enm; + NodeEnum enm; enm.insert("X", NODE_TANGENT_AXIS_X); enm.insert("Y", NODE_TANGENT_AXIS_Y); @@ -4643,24 +4658,24 @@ static ShaderEnum tangent_axis_init() return enm; } -ShaderEnum TangentNode::direction_type_enum = tangent_direction_type_init(); -ShaderEnum TangentNode::axis_enum = tangent_axis_init(); +NodeEnum TangentNode::direction_type_enum = tangent_direction_type_init(); +NodeEnum TangentNode::axis_enum = tangent_axis_init(); TangentNode::TangentNode() : ShaderNode("tangent") { - direction_type = ustring("Radial"); - axis = ustring("X"); + direction_type = NODE_TANGENT_RADIAL; + axis = NODE_TANGENT_AXIS_X; attribute = ustring(""); - add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL); - add_output("Tangent", SHADER_SOCKET_NORMAL); + add_input("NormalIn", SocketType::NORMAL, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); + add_output("Tangent", SocketType::NORMAL); } void TangentNode::attributes(Shader *shader, AttributeRequestSet *attributes) { if(shader->has_surface) { - if(direction_type == ustring("UV Map")) { + if(direction_type == NODE_TANGENT_UVMAP) { if(attribute == ustring("")) attributes->add(ATTR_STD_UV_TANGENT); else @@ -4678,7 +4693,7 @@ void TangentNode::compile(SVMCompiler& compiler) ShaderOutput *tangent_out = output("Tangent"); int attr; - if(direction_type == ustring("UV Map")) { + if(direction_type == NODE_TANGENT_UVMAP) { if(attribute == ustring("")) attr = compiler.attribute(ATTR_STD_UV_TANGENT); else @@ -4690,21 +4705,21 @@ void TangentNode::compile(SVMCompiler& compiler) compiler.add_node(NODE_TANGENT, compiler.encode_uchar4( compiler.stack_assign(tangent_out), - direction_type_enum[direction_type], - axis_enum[axis]), attr); + direction_type, + axis), attr); } void TangentNode::compile(OSLCompiler& compiler) { - if(direction_type == ustring("UV Map")) { + if(direction_type == NODE_TANGENT_UVMAP) { if(attribute == ustring("")) compiler.parameter("attr_name", ustring("geom:tangent")); else compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str())); } - compiler.parameter("direction_type", direction_type); - compiler.parameter("axis", axis); + compiler.parameter("direction_type", direction_type_enum[direction_type]); + compiler.parameter("axis", axis_enum[axis]); compiler.add(this, "node_tangent"); } diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 5df34a84559..8b17e455f7a 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -49,15 +49,15 @@ public: enum Type { POINT = 0, TEXTURE = 1, VECTOR = 2, NORMAL = 3 }; Type type; - static ShaderEnum type_enum; + static NodeEnum type_enum; enum Mapping { NONE = 0, X = 1, Y = 2, Z = 3 }; Mapping x_mapping, y_mapping, z_mapping; - static ShaderEnum mapping_enum; + static NodeEnum mapping_enum; enum Projection { FLAT, CUBE, TUBE, SPHERE }; Projection projection; - static ShaderEnum projection_enum; + static NodeEnum projection_enum; bool equals(const TextureMapping& other) { return translation == other.translation && @@ -109,15 +109,15 @@ public: bool use_alpha; string filename; void *builtin_data; - ustring color_space; - ustring projection; + NodeImageColorSpace color_space; + NodeImageProjection projection; InterpolationType interpolation; ExtensionType extension; float projection_blend; bool animated; - static ShaderEnum color_space_enum; - static ShaderEnum projection_enum; + static NodeEnum color_space_enum; + static NodeEnum projection_enum; virtual bool equals(const ShaderNode *other) { const ImageTextureNode *image_node = (const ImageTextureNode*)other; @@ -148,13 +148,13 @@ public: bool use_alpha; string filename; void *builtin_data; - ustring color_space; - ustring projection; + NodeImageColorSpace color_space; + NodeEnvironmentProjection projection; InterpolationType interpolation; bool animated; - static ShaderEnum color_space_enum; - static ShaderEnum projection_enum; + static NodeEnum color_space_enum; + static NodeEnum projection_enum; virtual bool equals(const ShaderNode *other) { const EnvironmentTextureNode *env_node = (const EnvironmentTextureNode*)other; @@ -175,12 +175,12 @@ public: virtual int get_group() { return NODE_GROUP_LEVEL_2; } + NodeSkyType type; float3 sun_direction; float turbidity; float ground_albedo; - ustring type; - static ShaderEnum type_enum; + static NodeEnum type_enum; virtual bool equals(const ShaderNode *other) { const SkyTextureNode *sky_node = (const SkyTextureNode*)other; @@ -206,8 +206,8 @@ public: virtual int get_group() { return NODE_GROUP_LEVEL_2; } - ustring type; - static ShaderEnum type_enum; + NodeGradientType type; + static NodeEnum type_enum; virtual bool equals(const ShaderNode *other) { const GradientTextureNode *gradient_node = (const GradientTextureNode*)other; @@ -227,9 +227,8 @@ public: virtual int get_group() { return NODE_GROUP_LEVEL_2; } - ustring coloring; - - static ShaderEnum coloring_enum; + NodeVoronoiColoring coloring; + static NodeEnum coloring_enum; virtual bool equals(const ShaderNode *other) { const VoronoiTextureNode *voronoi_node = (const VoronoiTextureNode*)other; @@ -244,9 +243,8 @@ public: virtual int get_group() { return NODE_GROUP_LEVEL_2; } - ustring type; - - static ShaderEnum type_enum; + NodeMusgraveType type; + static NodeEnum type_enum; virtual bool equals(const ShaderNode *other) { const MusgraveTextureNode *musgrave_node = (const MusgraveTextureNode*)other; @@ -261,10 +259,10 @@ public: virtual int get_group() { return NODE_GROUP_LEVEL_2; } - ustring type; - ustring profile; - static ShaderEnum type_enum; - static ShaderEnum profile_enum; + NodeWaveType type; + NodeWaveProfile profile; + static NodeEnum type_enum; + static NodeEnum profile_enum; virtual bool equals(const ShaderNode *other) { const WaveTextureNode *wave_node = (const WaveTextureNode*)other; @@ -329,13 +327,13 @@ public: ImageManager *image_manager; int slot; string filename; - ustring space; + NodeTexVoxelSpace space; void *builtin_data; InterpolationType interpolation; Transform tfm; - static ShaderEnum space_enum; + static NodeEnum space_enum; virtual bool equals(const ShaderNode *other) { const PointDensityTextureNode *point_dendity_node = (const PointDensityTextureNode*)other; @@ -362,14 +360,21 @@ public: } }; +class RGBToBWNode : public ShaderNode { +public: + SHADER_NODE_CLASS(RGBToBWNode) + + bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); +}; + class ConvertNode : public ShaderNode { public: - ConvertNode(ShaderSocketType from, ShaderSocketType to, bool autoconvert = false); + ConvertNode(SocketType::Type from, SocketType::Type to, bool autoconvert = false); SHADER_NODE_BASE_CLASS(ConvertNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value); + bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); - ShaderSocketType from, to; + SocketType::Type from, to; virtual bool equals(const ShaderNode *other) { @@ -403,8 +408,8 @@ class AnisotropicBsdfNode : public BsdfNode { public: SHADER_NODE_CLASS(AnisotropicBsdfNode) - ustring distribution; - static ShaderEnum distribution_enum; + ClosureType distribution; + static NodeEnum distribution_enum; void attributes(Shader *shader, AttributeRequestSet *attributes); }; @@ -438,8 +443,8 @@ public: void simplify_settings(Scene *scene); bool has_integrator_dependency(); - ustring distribution, distribution_orig; - static ShaderEnum distribution_enum; + ClosureType distribution, distribution_orig; + static NodeEnum distribution_enum; }; class GlassBsdfNode : public BsdfNode { @@ -449,8 +454,8 @@ public: void simplify_settings(Scene *scene); bool has_integrator_dependency(); - ustring distribution, distribution_orig; - static ShaderEnum distribution_enum; + ClosureType distribution, distribution_orig; + static NodeEnum distribution_enum; }; class RefractionBsdfNode : public BsdfNode { @@ -460,16 +465,16 @@ public: void simplify_settings(Scene *scene); bool has_integrator_dependency(); - ustring distribution, distribution_orig; - static ShaderEnum distribution_enum; + ClosureType distribution, distribution_orig; + static NodeEnum distribution_enum; }; class ToonBsdfNode : public BsdfNode { public: SHADER_NODE_CLASS(ToonBsdfNode) - ustring component; - static ShaderEnum component_enum; + ClosureType component; + static NodeEnum component_enum; }; class SubsurfaceScatteringNode : public BsdfNode { @@ -478,13 +483,14 @@ public: bool has_surface_bssrdf() { return true; } bool has_bssrdf_bump(); - static ShaderEnum falloff_enum; + ClosureType falloff; + static NodeEnum falloff_enum; }; class EmissionNode : public ShaderNode { public: SHADER_NODE_CLASS(EmissionNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value); + bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); virtual ClosureType get_closure_type() { return CLOSURE_EMISSION_ID; } bool has_surface_emission() { return true; } @@ -493,7 +499,7 @@ public: class BackgroundNode : public ShaderNode { public: SHADER_NODE_CLASS(BackgroundNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value); + bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); virtual ClosureType get_closure_type() { return CLOSURE_BACKGROUND_ID; } }; @@ -547,8 +553,8 @@ class HairBsdfNode : public BsdfNode { public: SHADER_NODE_CLASS(HairBsdfNode) - ustring component; - static ShaderEnum component_enum; + ClosureType component; + static NodeEnum component_enum; }; @@ -639,7 +645,7 @@ class ValueNode : public ShaderNode { public: SHADER_NODE_CLASS(ValueNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value); + bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); float value; @@ -654,7 +660,7 @@ class ColorNode : public ShaderNode { public: SHADER_NODE_CLASS(ColorNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value); + bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); float3 value; @@ -673,7 +679,7 @@ public: class MixClosureNode : public ShaderNode { public: SHADER_NODE_CLASS(MixClosureNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value); + bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); }; class MixClosureWeightNode : public ShaderNode { @@ -691,14 +697,14 @@ public: class MixNode : public ShaderNode { public: SHADER_NODE_CLASS(MixNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value); + bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); virtual int get_group() { return NODE_GROUP_LEVEL_3; } bool use_clamp; - ustring type; - static ShaderEnum type_enum; + NodeMix type; + static NodeEnum type_enum; virtual bool equals(const ShaderNode *other) { @@ -734,7 +740,7 @@ class GammaNode : public ShaderNode { public: SHADER_NODE_CLASS(GammaNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value); + bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); virtual int get_group() { return NODE_GROUP_LEVEL_1; } }; @@ -825,7 +831,7 @@ public: class BlackbodyNode : public ShaderNode { public: SHADER_NODE_CLASS(BlackbodyNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value); + bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); virtual int get_group() { return NODE_GROUP_LEVEL_3; } }; @@ -834,12 +840,12 @@ class MathNode : public ShaderNode { public: SHADER_NODE_CLASS(MathNode) virtual int get_group() { return NODE_GROUP_LEVEL_1; } - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value); + bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); bool use_clamp; - ustring type; - static ShaderEnum type_enum; + NodeMath type; + static NodeEnum type_enum; virtual bool equals(const ShaderNode *other) { @@ -869,14 +875,14 @@ class VectorMathNode : public ShaderNode { public: SHADER_NODE_CLASS(VectorMathNode) virtual int get_group() { return NODE_GROUP_LEVEL_1; } - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value); + bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); - ustring type; - static ShaderEnum type_enum; + NodeVectorMath type; + static NodeEnum type_enum; virtual bool equals(const ShaderNode *other) { - const MathNode *math_node = (const MathNode*)other; + const VectorMathNode *math_node = (const VectorMathNode*)other; return ShaderNode::equals(other) && type == math_node->type; } @@ -888,12 +894,12 @@ public: virtual int get_group() { return NODE_GROUP_LEVEL_3; } - ustring type; - ustring convert_from; - ustring convert_to; + NodeVectorTransformType type; + NodeVectorTransformConvertSpace convert_from; + NodeVectorTransformConvertSpace convert_to; - static ShaderEnum type_enum; - static ShaderEnum convert_space_enum; + static NodeEnum type_enum; + static NodeEnum convert_space_enum; virtual bool equals(const ShaderNode *other) { const VectorTransformNode *vector_transform_node = (const VectorTransformNode*)other; @@ -907,7 +913,7 @@ public: class BumpNode : public ShaderNode { public: SHADER_NODE_CLASS(BumpNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value); + bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); bool has_spatial_varying() { return true; } virtual int get_feature() { return NODE_FEATURE_BUMP; @@ -959,17 +965,22 @@ public: SHADER_NODE_CLASS(SetNormalNode) }; -class OSLScriptNode : public ShaderNode { +class OSLNode : public ShaderNode { public: - SHADER_NODE_CLASS(OSLScriptNode) + static OSLNode *create(size_t num_inputs); + ~OSLNode(); + + SHADER_NODE_BASE_CLASS(OSLNode) /* ideally we could beter detect this, but we can't query this now */ bool has_spatial_varying() { return true; } + virtual bool equals(const ShaderNode * /*other*/) { return false; } string filepath; string bytecode_hash; - virtual bool equals(const ShaderNode * /*other*/) { return false; } +private: + OSLNode(); }; class NormalMapNode : public ShaderNode { @@ -979,8 +990,8 @@ public: bool has_spatial_varying() { return true; } virtual int get_group() { return NODE_GROUP_LEVEL_3; } - ustring space; - static ShaderEnum space_enum; + NodeNormalMapSpace space; + static NodeEnum space_enum; ustring attribute; @@ -1000,11 +1011,10 @@ public: bool has_spatial_varying() { return true; } virtual int get_group() { return NODE_GROUP_LEVEL_3; } - ustring direction_type; - static ShaderEnum direction_type_enum; - - ustring axis; - static ShaderEnum axis_enum; + NodeTangentDirectionType direction_type; + NodeTangentAxis axis; + static NodeEnum direction_type_enum; + static NodeEnum axis_enum; ustring attribute; diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index e2fe0bd72a1..9ee1a9ef7a6 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -33,14 +33,25 @@ CCL_NAMESPACE_BEGIN /* Object */ +NODE_DEFINE(Object) +{ + NodeType* type = NodeType::add("object", create); + + SOCKET_NODE(mesh, "Mesh", &Mesh::node_type); + SOCKET_TRANSFORM(tfm, "Transform", transform_identity()); + SOCKET_INT(visibility, "Visibility", ~0); + SOCKET_INT(random_id, "Random ID", 0); + SOCKET_INT(pass_id, "Pass ID", 0); + SOCKET_BOOLEAN(use_holdout, "Use Holdout", false); + SOCKET_POINT(dupli_generated, "Dupli Generated", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_POINT2(dupli_uv, "Dupli UV", make_float2(0.0f, 0.0f)); + + return type; +} + Object::Object() +: Node(node_type) { - name = ""; - mesh = NULL; - tfm = transform_identity(); - visibility = ~0; - random_id = 0; - pass_id = 0; particle_system = NULL; particle_index = 0; bounds = BoundBox::empty; @@ -48,9 +59,6 @@ Object::Object() motion.mid = transform_identity(); motion.post = transform_identity(); use_motion = false; - use_holdout = false; - dupli_generated = make_float3(0.0f, 0.0f, 0.0f); - dupli_uv = make_float2(0.0f, 0.0f); } Object::~Object() @@ -137,12 +145,12 @@ void Object::apply_transform(bool apply_to_motion) /* apply transform to curve keys */ for(size_t i = 0; i < mesh->curve_keys.size(); i++) { - float3 co = transform_point(&tfm, float4_to_float3(mesh->curve_keys[i])); - float radius = mesh->curve_keys[i].w * scalar; + float3 co = transform_point(&tfm, mesh->curve_keys[i]); + float radius = mesh->curve_radius[i] * scalar; /* scale for curve radius is only correct for uniform scale */ - mesh->curve_keys[i] = float3_to_float4(co); - mesh->curve_keys[i].w = radius; + mesh->curve_keys[i] = co; + mesh->curve_radius[i] = radius; } if(apply_to_motion) { @@ -269,7 +277,9 @@ void ObjectManager::device_update_object_transform(UpdateObejctTransformState *s state->surface_area_lock.unlock(); if(it == state->surface_area_map.end()) { - foreach(Mesh::Triangle& t, mesh->triangles) { + size_t num_triangles = mesh->num_triangles(); + for(size_t j = 0; j < num_triangles; j++) { + Mesh::Triangle t = mesh->get_triangle(j); float3 p1 = mesh->verts[t.v[0]]; float3 p2 = mesh->verts[t.v[1]]; float3 p3 = mesh->verts[t.v[2]]; @@ -288,7 +298,9 @@ void ObjectManager::device_update_object_transform(UpdateObejctTransformState *s surface_area *= uniform_scale; } else { - foreach(Mesh::Triangle& t, mesh->triangles) { + size_t num_triangles = mesh->num_triangles(); + for(size_t j = 0; j < num_triangles; j++) { + Mesh::Triangle t = mesh->get_triangle(j); float3 p1 = transform_point(&tfm, mesh->verts[t.v[0]]); float3 p2 = transform_point(&tfm, mesh->verts[t.v[1]]); float3 p3 = transform_point(&tfm, mesh->verts[t.v[2]]); @@ -360,7 +372,7 @@ void ObjectManager::device_update_object_transform(UpdateObejctTransformState *s state->object_flag[object_index] = flag; /* Have curves. */ - if(mesh->curves.size()) { + if(mesh->num_curves()) { state->have_curves = true; } } diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h index c2a79ca8dc4..57614c95580 100644 --- a/intern/cycles/render/object.h +++ b/intern/cycles/render/object.h @@ -17,6 +17,7 @@ #ifndef __OBJECT_H__ #define __OBJECT_H__ +#include "node.h" #include "scene.h" #include "util_boundbox.h" @@ -37,12 +38,13 @@ struct Transform; /* Object */ -class Object { +class Object : public Node { public: + NODE_DECLARE; + Mesh *mesh; Transform tfm; BoundBox bounds; - ustring name; uint random_id; int pass_id; vector<ParamValue> attributes; diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp index 3d14965b4ca..1cfe3fb38e2 100644 --- a/intern/cycles/render/osl.cpp +++ b/intern/cycles/render/osl.cpp @@ -394,16 +394,143 @@ const char *OSLShaderManager::shader_load_bytecode(const string& hash, const str { ss->LoadMemoryCompiledShader(hash.c_str(), bytecode.c_str()); - /* this is a bit weak, but works */ OSLShaderInfo info; + + if(!info.query.open_bytecode(bytecode)) { + fprintf(stderr, "OSL query error: %s\n", info.query.geterror().c_str()); + } + + /* this is a bit weak, but works */ info.has_surface_emission = (bytecode.find("\"emission\"") != string::npos); info.has_surface_transparent = (bytecode.find("\"transparent\"") != string::npos); info.has_surface_bssrdf = (bytecode.find("\"bssrdf\"") != string::npos); + loaded_shaders[hash] = info; return loaded_shaders.find(hash)->first.c_str(); } +OSLNode *OSLShaderManager::osl_node(const std::string& filepath, + const std::string& bytecode_hash, + const std::string& bytecode) +{ + /* create query */ + const char *hash; + + if(!filepath.empty()) { + hash = shader_load_filepath(filepath); + } + else { + hash = shader_test_loaded(bytecode_hash); + if(!hash) + hash = shader_load_bytecode(bytecode_hash, bytecode); + } + + if(!hash) { + return NULL; + } + + OSLShaderInfo *info = shader_loaded_info(hash); + + /* count number of inputs */ + size_t num_inputs = 0; + + for(int i = 0; i < info->query.nparams(); i++) { + const OSL::OSLQuery::Parameter *param = info->query.getparam(i); + + /* skip unsupported types */ + if(param->varlenarray || param->isstruct || param->type.arraylen > 1) + continue; + + if(!param->isoutput) + num_inputs++; + } + + /* create node */ + OSLNode *node = OSLNode::create(num_inputs); + + /* add new sockets from parameters */ + set<void*> used_sockets; + + for(int i = 0; i < info->query.nparams(); i++) { + const OSL::OSLQuery::Parameter *param = info->query.getparam(i); + + /* skip unsupported types */ + if(param->varlenarray || param->isstruct || param->type.arraylen > 1) + continue; + + SocketType::Type socket_type; + + if(param->isclosure) { + socket_type = SocketType::CLOSURE; + } + else if(param->type.vecsemantics != TypeDesc::NOSEMANTICS) { + if(param->type.vecsemantics == TypeDesc::COLOR) + socket_type = SocketType::COLOR; + else if(param->type.vecsemantics == TypeDesc::POINT) + socket_type = SocketType::POINT; + else if(param->type.vecsemantics == TypeDesc::VECTOR) + socket_type = SocketType::VECTOR; + else if(param->type.vecsemantics == TypeDesc::NORMAL) + socket_type = SocketType::NORMAL; + else + continue; + + if(!param->isoutput && param->validdefault) { + node->add_input(param->name.c_str(), socket_type, make_float3(param->fdefault[0], param->fdefault[1], param->fdefault[2])); + continue; + } + } + else if(param->type.aggregate == TypeDesc::SCALAR) { + if(param->type.basetype == TypeDesc::INT) { + socket_type = SocketType::INT; + + if(!param->isoutput && param->validdefault) { + node->add_input(param->name.c_str(), socket_type, (float)param->idefault[0]); + continue; + } + } + else if(param->type.basetype == TypeDesc::FLOAT) { + socket_type = SocketType::FLOAT; + + if(!param->isoutput && param->validdefault) { + node->add_input(param->name.c_str(), socket_type, param->fdefault[0]); + continue; + } + } + else if(param->type.basetype == TypeDesc::STRING) { + socket_type = SocketType::STRING; + + if(!param->isoutput && param->validdefault) { + node->add_input(param->name.c_str(), socket_type); + continue; + } + } + else + continue; + } + else + continue; + + if(param->isoutput) { + node->add_output(param->name.c_str(), socket_type); + } + else { + node->add_input(param->name.c_str(), socket_type); + } + } + + /* set bytcode hash or filepath */ + if(!bytecode_hash.empty()) { + node->bytecode_hash = bytecode_hash; + } + else { + node->filepath = filepath; + } + + return node; +} + /* Graph Compiler */ OSLCompiler::OSLCompiler(void *manager_, void *shadingsys_, ImageManager *image_manager_) @@ -427,7 +554,7 @@ string OSLCompiler::id(ShaderNode *node) string OSLCompiler::compatible_name(ShaderNode *node, ShaderInput *input) { - string sname(input->name); + string sname(input->name().string()); size_t i; /* strip whitespace */ @@ -436,7 +563,7 @@ string OSLCompiler::compatible_name(ShaderNode *node, ShaderInput *input) /* if output exists with the same name, add "In" suffix */ foreach(ShaderOutput *output, node->outputs) { - if(strcmp(input->name, output->name)==0) { + if(input->name() == output->name()) { sname += "In"; break; } @@ -447,7 +574,7 @@ string OSLCompiler::compatible_name(ShaderNode *node, ShaderInput *input) string OSLCompiler::compatible_name(ShaderNode *node, ShaderOutput *output) { - string sname(output->name); + string sname(output->name().string()); size_t i; /* strip whitespace */ @@ -456,7 +583,7 @@ string OSLCompiler::compatible_name(ShaderNode *node, ShaderOutput *output) /* if input exists with the same name, add "Out" suffix */ foreach(ShaderInput *input, node->inputs) { - if(strcmp(input->name, output->name)==0) { + if(input->name() == output->name()) { sname += "Out"; break; } @@ -470,21 +597,21 @@ bool OSLCompiler::node_skip_input(ShaderNode *node, ShaderInput *input) /* exception for output node, only one input is actually used * depending on the current shader type */ - if(!(input->usage & ShaderInput::USE_OSL)) + if(input->flags() & SocketType::SVM_INTERNAL) return true; if(node->special_type == SHADER_SPECIAL_TYPE_OUTPUT) { - if(strcmp(input->name, "Surface") == 0 && current_type != SHADER_TYPE_SURFACE) + if(input->name() == "Surface" && current_type != SHADER_TYPE_SURFACE) return true; - if(strcmp(input->name, "Volume") == 0 && current_type != SHADER_TYPE_VOLUME) + if(input->name() == "Volume" && current_type != SHADER_TYPE_VOLUME) return true; - if(strcmp(input->name, "Displacement") == 0 && current_type != SHADER_TYPE_DISPLACEMENT) + if(input->name() == "Displacement" && current_type != SHADER_TYPE_DISPLACEMENT) return true; - if(strcmp(input->name, "Normal") == 0) + if(input->name() == "Normal") return true; } else if(node->special_type == SHADER_SPECIAL_TYPE_BUMP) { - if(strcmp(input->name, "Height") == 0) + if(input->name() == "Height") return true; } else if(current_type == SHADER_TYPE_DISPLACEMENT && input->link && input->link->parent->special_type == SHADER_SPECIAL_TYPE_BUMP) @@ -512,34 +639,35 @@ void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath) if(node_skip_input(node, input)) continue; /* already has default value assigned */ - else if(input->default_value != ShaderInput::NONE) + else if(input->flags() & SocketType::DEFAULT_LINK_MASK) continue; string param_name = compatible_name(node, input); - switch(input->type) { - case SHADER_SOCKET_COLOR: - parameter_color(param_name.c_str(), input->value); + switch(input->type()) { + case SocketType::COLOR: + parameter_color(param_name.c_str(), input->value()); break; - case SHADER_SOCKET_POINT: - parameter_point(param_name.c_str(), input->value); + case SocketType::POINT: + parameter_point(param_name.c_str(), input->value()); break; - case SHADER_SOCKET_VECTOR: - parameter_vector(param_name.c_str(), input->value); + case SocketType::VECTOR: + parameter_vector(param_name.c_str(), input->value()); break; - case SHADER_SOCKET_NORMAL: - parameter_normal(param_name.c_str(), input->value); + case SocketType::NORMAL: + parameter_normal(param_name.c_str(), input->value()); break; - case SHADER_SOCKET_FLOAT: - parameter(param_name.c_str(), input->value.x); + case SocketType::FLOAT: + parameter(param_name.c_str(), input->value_float()); break; - case SHADER_SOCKET_INT: - parameter(param_name.c_str(), (int)input->value.x); + case SocketType::INT: + parameter(param_name.c_str(), (int)input->value_float()); break; - case SHADER_SOCKET_STRING: - parameter(param_name.c_str(), input->value_string); + case SocketType::STRING: + parameter(param_name.c_str(), input->value_string()); break; - case SHADER_SOCKET_CLOSURE: - case SHADER_SOCKET_UNDEFINED: + case SocketType::CLOSURE: + case SocketType::UNDEFINED: + default: break; } } diff --git a/intern/cycles/render/osl.h b/intern/cycles/render/osl.h index 110897ff300..13b9d6307f9 100644 --- a/intern/cycles/render/osl.h +++ b/intern/cycles/render/osl.h @@ -22,6 +22,7 @@ #include "util_thread.h" #include "graph.h" +#include "nodes.h" #include "shader.h" #ifdef WITH_OSL @@ -54,6 +55,7 @@ struct OSLShaderInfo { has_surface_bssrdf(false) {} + OSL::OSLQuery query; bool has_surface_emission; bool has_surface_transparent; bool has_surface_bssrdf; @@ -83,6 +85,11 @@ public: const char *shader_load_filepath(string filepath); OSLShaderInfo *shader_loaded_info(const string& hash); + /* create OSL node using OSLQuery */ + OSLNode *osl_node(const std::string& filepath, + const std::string& bytecode_hash = "", + const std::string& bytecode = ""); + protected: void texture_system_init(); void texture_system_free(); diff --git a/intern/cycles/render/particles.cpp b/intern/cycles/render/particles.cpp index 50726bb4574..1a35d60fb4b 100644 --- a/intern/cycles/render/particles.cpp +++ b/intern/cycles/render/particles.cpp @@ -58,8 +58,8 @@ void ParticleSystemManager::device_update_particles(Device *device, DeviceScene * adds one dummy particle at the beginning to avoid invalid lookups, * in case a shader uses particle info without actual particle data. */ int num_particles = 1; - foreach(ParticleSystem *psys, scene->particle_systems) - num_particles += psys->particles.size(); + for(size_t j = 0; j < scene->particle_systems.size(); j++) + num_particles += scene->particle_systems[j]->particles.size(); float4 *particles = dscene->particles.resize(PARTICLE_SIZE*num_particles); @@ -71,9 +71,12 @@ void ParticleSystemManager::device_update_particles(Device *device, DeviceScene particles[4] = make_float4(0.0f, 0.0f, 0.0f, 0.0f); int i = 1; - foreach(ParticleSystem *psys, scene->particle_systems) { - foreach(Particle &pa, psys->particles) { + for(size_t j = 0; j < scene->particle_systems.size(); j++) { + ParticleSystem *psys = scene->particle_systems[j]; + + for(size_t k = 0; k < psys->particles.size(); k++) { /* pack in texture */ + Particle& pa = psys->particles[k]; int offset = i*PARTICLE_SIZE; particles[offset] = make_float4(pa.index, pa.age, pa.lifetime, pa.size); diff --git a/intern/cycles/render/particles.h b/intern/cycles/render/particles.h index bf2b6b77015..2509e27b44b 100644 --- a/intern/cycles/render/particles.h +++ b/intern/cycles/render/particles.h @@ -47,7 +47,7 @@ public: void tag_update(Scene *scene); - vector<Particle> particles; + array<Particle> particles; }; /* ParticleSystem Manager */ diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index b0052c30af4..e8367e1eb36 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -242,9 +242,14 @@ void Scene::device_update(Device *device_, Progress& progress) } if(print_stats) { + size_t mem_used = util_guarded_get_mem_used(); + size_t mem_peak = util_guarded_get_mem_peak(); + VLOG(1) << "System memory statistics after full device sync:\n" - << " Usage: " << util_guarded_get_mem_used() << "\n" - << " Peak: " << util_guarded_get_mem_peak(); + << " Usage: " << string_human_readable_number(mem_used) + << " (" << string_human_readable_size(mem_used) << ")\n" + << " Peak: " << string_human_readable_number(mem_peak) + << " (" << string_human_readable_size(mem_peak) << ")"; } } diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index 33c03d40f27..b34d6127118 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -109,10 +109,10 @@ public: device_vector<uint> sobol_directions; /* cpu images */ - device_vector<uchar4> tex_byte4_image[TEX_NUM_BYTE4_IMAGES_CPU]; - device_vector<float4> tex_float4_image[TEX_NUM_FLOAT4_IMAGES_CPU]; - device_vector<float> tex_float_image[TEX_NUM_FLOAT_IMAGES_CPU]; - device_vector<uchar> tex_byte_image[TEX_NUM_BYTE_IMAGES_CPU]; + device_vector<uchar4> tex_byte4_image[TEX_NUM_BYTE4_CPU]; + device_vector<float4> tex_float4_image[TEX_NUM_FLOAT4_CPU]; + device_vector<float> tex_float_image[TEX_NUM_FLOAT_CPU]; + device_vector<uchar> tex_byte_image[TEX_NUM_BYTE_CPU]; /* opencl images */ device_vector<uchar4> tex_image_byte4_packed; diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index 76979e9ba3e..1cd76ff2b39 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -630,7 +630,7 @@ DeviceRequestedFeatures Session::get_requested_device_features() requested_features.use_camera_motion = scene->camera->use_motion; foreach(Object *object, scene->objects) { Mesh *mesh = object->mesh; - if(mesh->curves.size() > 0) { + if(mesh->num_curves()) { requested_features.use_hair = true; } requested_features.use_object_motion |= object->use_motion | mesh->use_motion_blur; diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp index 635024d7bdf..708eeef3b50 100644 --- a/intern/cycles/render/shader.cpp +++ b/intern/cycles/render/shader.cpp @@ -456,7 +456,7 @@ void ShaderManager::add_default(Scene *scene) ShaderGraph *graph = new ShaderGraph(); closure = graph->add(new DiffuseBsdfNode()); - closure->input("Color")->value = make_float3(0.8f, 0.8f, 0.8f); + closure->input("Color")->set(make_float3(0.8f, 0.8f, 0.8f)); out = graph->output(); graph->connect(closure->output("BSDF"), out->input("Surface")); @@ -473,8 +473,8 @@ void ShaderManager::add_default(Scene *scene) ShaderGraph *graph = new ShaderGraph(); closure = graph->add(new EmissionNode()); - closure->input("Color")->value = make_float3(0.8f, 0.8f, 0.8f); - closure->input("Strength")->value.x = 0.0f; + closure->input("Color")->set(make_float3(0.8f, 0.8f, 0.8f)); + closure->input("Strength")->set(0.0f); out = graph->output(); graph->connect(closure->output("Emission"), out->input("Surface")); diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp index 4c97a5ad792..d54afd1ba6f 100644 --- a/intern/cycles/render/svm.cpp +++ b/intern/cycles/render/svm.cpp @@ -120,22 +120,22 @@ SVMCompiler::SVMCompiler(ShaderManager *shader_manager_, ImageManager *image_man compile_failed = false; } -int SVMCompiler::stack_size(ShaderSocketType type) +int SVMCompiler::stack_size(SocketType::Type type) { int size = 0; switch(type) { - case SHADER_SOCKET_FLOAT: - case SHADER_SOCKET_INT: + case SocketType::FLOAT: + case SocketType::INT: size = 1; break; - case SHADER_SOCKET_COLOR: - case SHADER_SOCKET_VECTOR: - case SHADER_SOCKET_NORMAL: - case SHADER_SOCKET_POINT: + case SocketType::COLOR: + case SocketType::VECTOR: + case SocketType::NORMAL: + case SocketType::POINT: size = 3; break; - case SHADER_SOCKET_CLOSURE: + case SocketType::CLOSURE: size = 0; break; default: @@ -146,7 +146,7 @@ int SVMCompiler::stack_size(ShaderSocketType type) return size; } -int SVMCompiler::stack_find_offset(ShaderSocketType type) +int SVMCompiler::stack_find_offset(SocketType::Type type) { int size = stack_size(type); int offset = -1; @@ -175,7 +175,7 @@ int SVMCompiler::stack_find_offset(ShaderSocketType type) return 0; } -void SVMCompiler::stack_clear_offset(ShaderSocketType type, int offset) +void SVMCompiler::stack_clear_offset(SocketType::Type type, int offset) { int size = stack_size(type); @@ -193,22 +193,22 @@ int SVMCompiler::stack_assign(ShaderInput *input) } else { /* not linked to output -> add nodes to load default value */ - input->stack_offset = stack_find_offset(input->type); + input->stack_offset = stack_find_offset(input->type()); - if(input->type == SHADER_SOCKET_FLOAT) { - add_node(NODE_VALUE_F, __float_as_int(input->value.x), input->stack_offset); + if(input->type() == SocketType::FLOAT) { + add_node(NODE_VALUE_F, __float_as_int(input->value_float()), input->stack_offset); } - else if(input->type == SHADER_SOCKET_INT) { - add_node(NODE_VALUE_F, (int)input->value.x, input->stack_offset); + else if(input->type() == SocketType::INT) { + add_node(NODE_VALUE_F, (int)input->value_float(), input->stack_offset); } - else if(input->type == SHADER_SOCKET_VECTOR || - input->type == SHADER_SOCKET_NORMAL || - input->type == SHADER_SOCKET_POINT || - input->type == SHADER_SOCKET_COLOR) + else if(input->type() == SocketType::VECTOR || + input->type() == SocketType::NORMAL || + input->type() == SocketType::POINT || + input->type() == SocketType::COLOR) { add_node(NODE_VALUE_V, input->stack_offset); - add_node(NODE_VALUE_V, input->value); + add_node(NODE_VALUE_V, input->value()); } else /* should not get called for closure */ assert(0); @@ -222,7 +222,7 @@ int SVMCompiler::stack_assign(ShaderOutput *output) { /* if no stack offset assigned yet, find one */ if(output->stack_offset == SVM_STACK_INVALID) - output->stack_offset = stack_find_offset(output->type); + output->stack_offset = stack_find_offset(output->type()); return output->stack_offset; } @@ -247,11 +247,11 @@ void SVMCompiler::stack_link(ShaderInput *input, ShaderOutput *output) { if(output->stack_offset == SVM_STACK_INVALID) { assert(input->link); - assert(stack_size(output->type) == stack_size(input->link->type)); + assert(stack_size(output->type()) == stack_size(input->link->type())); output->stack_offset = input->link->stack_offset; - int size = stack_size(output->type); + int size = stack_size(output->type()); for(int i = 0; i < size; i++) active_stack.users[output->stack_offset + i]++; @@ -279,7 +279,7 @@ void SVMCompiler::stack_clear_users(ShaderNode *node, ShaderNodeSet& done) all_done = false; if(all_done) { - stack_clear_offset(output->type, output->stack_offset); + stack_clear_offset(output->type(), output->stack_offset); output->stack_offset = SVM_STACK_INVALID; foreach(ShaderInput *in, output->links) @@ -293,7 +293,7 @@ void SVMCompiler::stack_clear_temporary(ShaderNode *node) { foreach(ShaderInput *input, node->inputs) { if(!input->link && input->stack_offset != SVM_STACK_INVALID) { - stack_clear_offset(input->type, input->stack_offset); + stack_clear_offset(input->type(), input->stack_offset); input->stack_offset = SVM_STACK_INVALID; } } @@ -446,7 +446,7 @@ void SVMCompiler::generate_closure_node(ShaderNode *node, const char *weight_name = (current_type == SHADER_TYPE_VOLUME)? "VolumeMixWeight": "SurfaceMixWeight"; ShaderInput *weight_in = node->input(weight_name); - if(weight_in && (weight_in->link || weight_in->value.x != 1.0f)) + if(weight_in && (weight_in->link || weight_in->value_float() != 1.0f)) mix_weight_offset = stack_assign(weight_in); else mix_weight_offset = SVM_STACK_INVALID; @@ -479,7 +479,7 @@ void SVMCompiler::generated_shared_closure_nodes(ShaderNode *root_node, } else { foreach(ShaderInput *in, node->inputs) { - if(in->type == SHADER_SOCKET_CLOSURE && in->link) + if(in->type() == SocketType::CLOSURE && in->link) generated_shared_closure_nodes(root_node, in->link->parent, state, diff --git a/intern/cycles/render/svm.h b/intern/cycles/render/svm.h index dbf1b1de947..e14d57d7601 100644 --- a/intern/cycles/render/svm.h +++ b/intern/cycles/render/svm.h @@ -99,8 +99,8 @@ public: int stack_assign(ShaderInput *input); int stack_assign_if_linked(ShaderInput *input); int stack_assign_if_linked(ShaderOutput *output); - int stack_find_offset(ShaderSocketType type); - void stack_clear_offset(ShaderSocketType type, int offset); + int stack_find_offset(SocketType::Type type); + void stack_clear_offset(SocketType::Type type, int offset); void stack_link(ShaderInput *input, ShaderOutput *output); void add_node(ShaderNodeType type, int a = 0, int b = 0, int c = 0); @@ -172,7 +172,7 @@ protected: }; void stack_clear_temporary(ShaderNode *node); - int stack_size(ShaderSocketType type); + int stack_size(SocketType::Type type); void stack_clear_users(ShaderNode *node, ShaderNodeSet& done); bool node_skip_input(ShaderNode *node, ShaderInput *input); diff --git a/intern/cycles/subd/subd_dice.cpp b/intern/cycles/subd/subd_dice.cpp index a5dfcd21ceb..8dba1379855 100644 --- a/intern/cycles/subd/subd_dice.cpp +++ b/intern/cycles/subd/subd_dice.cpp @@ -41,14 +41,14 @@ EdgeDice::EdgeDice(const SubdParams& params_) } } -void EdgeDice::reserve(int num_verts, int num_tris) +void EdgeDice::reserve(int num_verts) { Mesh *mesh = params.mesh; vert_offset = mesh->verts.size(); tri_offset = mesh->triangles.size(); - mesh->reserve(vert_offset + num_verts, tri_offset + num_tris, 0, 0); + mesh->resize_mesh(vert_offset + num_verts, tri_offset); Attribute *attr_vN = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL); @@ -69,7 +69,7 @@ int EdgeDice::add_vert(Patch *patch, float2 uv) if(params.ptex) { Attribute *attr_ptex_uv = params.mesh->attributes.add(ATTR_STD_PTEX_UV); - params.mesh->attributes.reserve(); + params.mesh->attributes.resize(); float3 *ptex_uv = attr_ptex_uv->data_float3(); ptex_uv[vert_offset] = make_float3(uv.x, uv.y, 0.0f); @@ -80,11 +80,17 @@ int EdgeDice::add_vert(Patch *patch, float2 uv) void EdgeDice::add_triangle(Patch *patch, int v0, int v1, int v2) { - params.mesh->add_triangle(v0, v1, v2, params.shader, params.smooth, false); + Mesh *mesh = params.mesh; + + /* todo: optimize so we can reserve in advance, this is like push_back_slow() */ + if(mesh->triangles.size() == mesh->triangles.capacity()) + mesh->reserve_mesh(mesh->verts.size(), size_t(max(mesh->triangles.size() + 1, 1) * 1.2)); + + mesh->add_triangle(v0, v1, v2, params.shader, params.smooth, false); if(params.ptex) { Attribute *attr_ptex_face_id = params.mesh->attributes.add(ATTR_STD_PTEX_FACE_ID); - params.mesh->attributes.reserve(); + params.mesh->attributes.resize(); float *ptex_face_id = attr_ptex_face_id->data_float(); ptex_face_id[tri_offset] = (float)patch->ptex_face_id(); @@ -141,8 +147,7 @@ void QuadDice::reserve(EdgeFactors& ef, int Mu, int Mv) { /* XXX need to make this also work for edge factor 0 and 1 */ int num_verts = (ef.tu0 + ef.tu1 + ef.tv0 + ef.tv1) + (Mu - 1)*(Mv - 1); - int num_tris = 0; - EdgeDice::reserve(num_verts, num_tris); + EdgeDice::reserve(num_verts); } float2 QuadDice::map_uv(SubPatch& sub, float u, float v) @@ -352,7 +357,7 @@ void TriangleDice::reserve(EdgeFactors& ef, int M) if(!(M & 1)) num_verts++; - EdgeDice::reserve(num_verts, 0); + EdgeDice::reserve(num_verts); } float2 TriangleDice::map_uv(SubPatch& sub, float2 uv) diff --git a/intern/cycles/subd/subd_dice.h b/intern/cycles/subd/subd_dice.h index 49f786e949e..85bd0ea28f0 100644 --- a/intern/cycles/subd/subd_dice.h +++ b/intern/cycles/subd/subd_dice.h @@ -72,7 +72,7 @@ public: explicit EdgeDice(const SubdParams& params); - void reserve(int num_verts, int num_tris); + void reserve(int num_verts); int add_vert(Patch *patch, float2 uv); void add_triangle(Patch *patch, int v0, int v1, int v2); diff --git a/intern/cycles/util/util_string.cpp b/intern/cycles/util/util_string.cpp index b3a8c6d7c2e..e16a83d56d0 100644 --- a/intern/cycles/util/util_string.cpp +++ b/intern/cycles/util/util_string.cpp @@ -239,5 +239,45 @@ string string_to_ansi(const string& str) #endif /* _WIN32 */ +string string_human_readable_size(size_t size) +{ + static const char suffixes[] = "BKMGTPEZY"; + + const char* suffix = suffixes; + size_t r = 0; + + while(size >= 1024) { + r = size % 1024; + size /= 1024; + suffix++; + } + + if(*suffix != 'B') + return string_printf("%.2f%c", double(size*1024+r)/1024.0, *suffix); + else + return string_printf("%zu", size); +} + +string string_human_readable_number(size_t num) +{ + /* add thousands separators */ + char buf[32]; + + char* p = buf+31; + *p = '\0'; + + int i = -1; + while(num) { + if(++i && i % 3 == 0) + *(--p) = ','; + + *(--p) = '0' + (num % 10); + + num /= 10; + } + + return p; +} + CCL_NAMESPACE_END diff --git a/intern/cycles/util/util_string.h b/intern/cycles/util/util_string.h index c4b51bda432..d3b5248c380 100644 --- a/intern/cycles/util/util_string.h +++ b/intern/cycles/util/util_string.h @@ -62,6 +62,11 @@ string string_from_wstring(const wstring& path); string string_to_ansi(const string& str); #endif +/* Make a string from a size in bytes in human readable form */ +string string_human_readable_size(size_t size); +/* Make a string from a unitless quantity in human readable form */ +string string_human_readable_number(size_t num); + CCL_NAMESPACE_END #endif /* __UTIL_STRING_H__ */ diff --git a/intern/cycles/util/util_texture.h b/intern/cycles/util/util_texture.h index 6da47858133..e00edc046f7 100644 --- a/intern/cycles/util/util_texture.h +++ b/intern/cycles/util/util_texture.h @@ -19,43 +19,47 @@ CCL_NAMESPACE_BEGIN -/* Texture limits on various devices. */ +/* Texture limits on devices. */ /* CPU */ -#define TEX_NUM_BYTE4_IMAGES_CPU 1024 -#define TEX_NUM_FLOAT4_IMAGES_CPU 1024 -#define TEX_NUM_FLOAT_IMAGES_CPU 1024 -#define TEX_NUM_BYTE_IMAGES_CPU 1024 -#define TEX_IMAGE_BYTE4_START_CPU TEX_NUM_FLOAT4_IMAGES_CPU -#define TEX_IMAGE_FLOAT_START_CPU (TEX_NUM_FLOAT4_IMAGES_CPU + TEX_NUM_BYTE4_IMAGES_CPU) -#define TEX_IMAGE_BYTE_START_CPU (TEX_NUM_FLOAT4_IMAGES_CPU + TEX_NUM_BYTE4_IMAGES_CPU + TEX_NUM_BYTE_IMAGES_CPU) +#define TEX_NUM_FLOAT4_CPU 1024 +#define TEX_NUM_BYTE4_CPU 1024 +#define TEX_NUM_FLOAT_CPU 1024 +#define TEX_NUM_BYTE_CPU 1024 +#define TEX_START_FLOAT4_CPU 0 +#define TEX_START_BYTE4_CPU TEX_NUM_FLOAT4_CPU +#define TEX_START_FLOAT_CPU (TEX_NUM_FLOAT4_CPU + TEX_NUM_BYTE4_CPU) +#define TEX_START_BYTE_CPU (TEX_NUM_FLOAT4_CPU + TEX_NUM_BYTE4_CPU + TEX_NUM_BYTE_CPU) -/* CUDA (Fermi) */ -#define TEX_NUM_BYTE4_IMAGES_CUDA 88 -#define TEX_NUM_FLOAT4_IMAGES_CUDA 5 -#define TEX_NUM_FLOAT_IMAGES_CUDA 0 -#define TEX_NUM_BYTE_IMAGES_CUDA 0 -#define TEX_IMAGE_BYTE4_START_CUDA TEX_NUM_FLOAT4_IMAGES_CUDA -#define TEX_IMAGE_FLOAT_START_CUDA (TEX_NUM_FLOAT4_IMAGES_CUDA + TEX_NUM_BYTE4_IMAGES_CUDA) -#define TEX_IMAGE_BYTE_START_CUDA (TEX_NUM_FLOAT4_IMAGES_CUDA + TEX_NUM_BYTE4_IMAGES_CUDA + TEX_NUM_BYTE_IMAGES_CUDA) +/* CUDA (Geforce 4xx and 5xx) */ +#define TEX_NUM_FLOAT4_CUDA 5 +#define TEX_NUM_BYTE4_CUDA 88 +#define TEX_NUM_FLOAT_CUDA 0 +#define TEX_NUM_BYTE_CUDA 0 +#define TEX_START_FLOAT4_CUDA 0 +#define TEX_START_BYTE4_CUDA TEX_NUM_FLOAT4_CUDA +#define TEX_START_FLOAT_CUDA (TEX_NUM_FLOAT4_CUDA + TEX_NUM_BYTE4_CUDA) +#define TEX_START_BYTE_CUDA (TEX_NUM_FLOAT4_CUDA + TEX_NUM_BYTE4_CUDA + TEX_NUM_BYTE_CUDA) -/* CUDA (KEPLER and above) */ -#define TEX_NUM_BYTE4_IMAGES_CUDA_KEPLER 1024 -#define TEX_NUM_FLOAT4_IMAGES_CUDA_KEPLER 1024 -#define TEX_NUM_FLOAT_IMAGES_CUDA_KEPLER 1024 -#define TEX_NUM_BYTE_IMAGES_CUDA_KEPLER 1024 -#define TEX_IMAGE_BYTE4_START_CUDA_KEPLER TEX_NUM_FLOAT4_IMAGES_CUDA_KEPLER -#define TEX_IMAGE_FLOAT_START_CUDA_KEPLER (TEX_NUM_FLOAT4_IMAGES_CUDA_KEPLER + TEX_NUM_BYTE4_IMAGES_CUDA_KEPLER) -#define TEX_IMAGE_BYTE_START_CUDA_KEPLER (TEX_NUM_FLOAT4_IMAGES_CUDA_KEPLER + TEX_NUM_BYTE4_IMAGES_CUDA_KEPLER + TEX_NUM_BYTE_IMAGES_CUDA_KEPLER) +/* CUDA (Kepler, Geforce 6xx and above) */ +#define TEX_NUM_FLOAT4_CUDA_KEPLER 1024 +#define TEX_NUM_BYTE4_CUDA_KEPLER 1024 +#define TEX_NUM_FLOAT_CUDA_KEPLER 1024 +#define TEX_NUM_BYTE_CUDA_KEPLER 1024 +#define TEX_START_FLOAT4_CUDA_KEPLER 0 +#define TEX_START_BYTE4_CUDA_KEPLER TEX_NUM_FLOAT4_CUDA_KEPLER +#define TEX_START_FLOAT_CUDA_KEPLER (TEX_NUM_FLOAT4_CUDA_KEPLER + TEX_NUM_BYTE4_CUDA_KEPLER) +#define TEX_START_BYTE_CUDA_KEPLER (TEX_NUM_FLOAT4_CUDA_KEPLER + TEX_NUM_BYTE4_CUDA_KEPLER + TEX_NUM_BYTE_CUDA_KEPLER) /* OpenCL */ -#define TEX_NUM_BYTE4_IMAGES_OPENCL 1024 -#define TEX_NUM_FLOAT4_IMAGES_OPENCL 1024 -#define TEX_NUM_FLOAT_IMAGES_OPENCL 0 -#define TEX_NUM_BYTE_IMAGES_OPENCL 0 -#define TEX_IMAGE_BYTE4_START_OPENCL TEX_NUM_FLOAT4_IMAGES_OPENCL -#define TEX_IMAGE_FLOAT_START_OPENCL (TEX_NUM_FLOAT4_IMAGES_OPENCL + TEX_NUM_BYTE4_IMAGES_OPENCL) -#define TEX_IMAGE_BYTE_START_OPENCL (TEX_NUM_FLOAT4_IMAGES_OPENCL + TEX_NUM_BYTE4_IMAGES_OPENCL + TEX_NUM_BYTE_IMAGES_OPENCL) +#define TEX_NUM_FLOAT4_OPENCL 1024 +#define TEX_NUM_BYTE4_OPENCL 1024 +#define TEX_NUM_FLOAT_OPENCL 0 +#define TEX_NUM_BYTE_OPENCL 0 +#define TEX_START_FLOAT4_OPENCL 0 +#define TEX_START_BYTE4_OPENCL TEX_NUM_FLOAT4_OPENCL +#define TEX_START_FLOAT_OPENCL (TEX_NUM_FLOAT4_OPENCL + TEX_NUM_BYTE4_OPENCL) +#define TEX_START_BYTE_OPENCL (TEX_NUM_FLOAT4_OPENCL + TEX_NUM_BYTE4_OPENCL + TEX_NUM_BYTE_OPENCL) /* Color to use when textures are not found. */ diff --git a/intern/ghost/intern/GHOST_NDOFManager.cpp b/intern/ghost/intern/GHOST_NDOFManager.cpp index 27285e49e9e..f18b7911f45 100644 --- a/intern/ghost/intern/GHOST_NDOFManager.cpp +++ b/intern/ghost/intern/GHOST_NDOFManager.cpp @@ -299,6 +299,12 @@ bool GHOST_NDOFManager::setDevice(unsigned short vendor_id, unsigned short produ m_buttonMask = 0x07C0F137; m_hidMap = Modern3Dx_HID_map; break; + case 0xC633: + puts("ndof: using SpaceMouse Enterprise"); + m_deviceType = NDOF_SpaceMouseEnterprise; + m_buttonCount = 31; + m_hidMap = Modern3Dx_HID_map; + break; default: printf("ndof: unknown 3Dconnexion product %04hx\n", product_id); diff --git a/intern/ghost/intern/GHOST_NDOFManager.h b/intern/ghost/intern/GHOST_NDOFManager.h index ba82f37bb2a..d3c70bbac50 100644 --- a/intern/ghost/intern/GHOST_NDOFManager.h +++ b/intern/ghost/intern/GHOST_NDOFManager.h @@ -40,6 +40,7 @@ typedef enum { NDOF_SpaceMousePro, NDOF_SpaceMouseWireless, NDOF_SpaceMouseProWireless, + NDOF_SpaceMouseEnterprise, // older devices NDOF_SpacePilot, diff --git a/intern/opencolorio/gpu_shader_display_transform.glsl b/intern/opencolorio/gpu_shader_display_transform.glsl index 5921d6d9c73..853bf575582 100644 --- a/intern/opencolorio/gpu_shader_display_transform.glsl +++ b/intern/opencolorio/gpu_shader_display_transform.glsl @@ -38,7 +38,7 @@ float read_curve_mapping(int table, int index) * But is it actually correct to subtract 1 here? */ float texture_index = float(index) / float(curve_mapping_lut_size - 1); - return texture1D(curve_mapping_texture, texture_index) [table]; + return texture1D(curve_mapping_texture, texture_index)[table]; } float curvemap_calc_extend(int table, float x, vec2 first, vec2 last) diff --git a/intern/opensubdiv/gpu_shader_opensubd_display.glsl b/intern/opensubdiv/gpu_shader_opensubd_display.glsl index 51e8ed46c34..a17dcef81c7 100644 --- a/intern/opensubdiv/gpu_shader_opensubd_display.glsl +++ b/intern/opensubdiv/gpu_shader_opensubd_display.glsl @@ -111,7 +111,7 @@ void emit(int index, vec3 normal) outpt.v.normal = normal; /* TODO(sergey): Only uniform subdivisions atm. */ - vec2 quadst[4] = vec2[](vec2(0,0), vec2(1,0), vec2(1,1), vec2(0,1)); + vec2 quadst[4] = vec2[](vec2(0, 0), vec2(1, 0), vec2(1, 1), vec2(0, 1)); vec2 st = quadst[index]; INTERP_FACE_VARYING_2(outpt.v.uv, osd_active_uv_offset, st); @@ -135,7 +135,7 @@ void emit(int index) outpt.v.normal = inpt[index].v.normal; /* TODO(sergey): Only uniform subdivisions atm. */ - vec2 quadst[4] = vec2[](vec2(0,0), vec2(1,0), vec2(1,1), vec2(0,1)); + vec2 quadst[4] = vec2[](vec2(0, 0), vec2(1, 0), vec2(1, 1), vec2(0, 1)); vec2 st = quadst[index]; INTERP_FACE_VARYING_2(outpt.v.uv, osd_active_uv_offset, st); @@ -261,7 +261,7 @@ void main() #else /* USE_COLOR_MATERIAL */ vec3 varying_position = inpt.v.position.xyz; vec3 V = (gl_ProjectionMatrix[3][3] == 0.0) ? - normalize(varying_position): vec3(0.0, 0.0, -1.0); + normalize(varying_position) : vec3(0.0, 0.0, -1.0); for (int i = 0; i < num_enabled_lights; i++) { /* todo: this is a slow check for disabled lights */ if (lightSource[i].specular.a == 0.0) @@ -299,7 +299,7 @@ void main() /* diffuse light */ vec3 light_diffuse = lightSource[i].diffuse.rgb; float diffuse_bsdf = max(dot(N, light_direction), 0.0); - L_diffuse += light_diffuse*diffuse_bsdf*intensity; + L_diffuse += light_diffuse * diffuse_bsdf * intensity; /* specular light */ vec3 light_specular = lightSource[i].specular.rgb; @@ -307,7 +307,7 @@ void main() float specular_bsdf = pow(max(dot(N, H), 0.0), gl_FrontMaterial.shininess); - L_specular += light_specular*specular_bsdf * intensity; + L_specular += light_specular * specular_bsdf * intensity; } #endif /* USE_COLOR_MATERIAL */ diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py index c1a37d10961..d194de32bf3 100644 --- a/release/scripts/modules/bpy_types.py +++ b/release/scripts/modules/bpy_types.py @@ -408,6 +408,14 @@ class Mesh(bpy_types.ID): the *vertices* argument. eg: [(5, 6, 8, 9), (1, 2, 3), ...] :type faces: iterable object + + .. warning:: + + Invalid mesh data + *(out of range indices, edges with matching indices, + 2 sided faces... etc)* are **not** prevented. + If the data used for mesh creation isn't known to be valid, + run :class:`Mesh.validate` after this function. """ from itertools import chain, islice, accumulate diff --git a/release/scripts/presets/interface_theme/blender_24x.xml b/release/scripts/presets/interface_theme/blender_24x.xml index 445c23b4c4e..ae42b605556 100644 --- a/release/scripts/presets/interface_theme/blender_24x.xml +++ b/release/scripts/presets/interface_theme/blender_24x.xml @@ -179,7 +179,7 @@ </wcol_tooltip> <wcol_menu_item> <ThemeWidgetColors outline="#000000" - inner="#00000000" + inner="#d2d2d200" inner_sel="#7f7f7fff" item="#ffffffff" text="#000000" diff --git a/release/scripts/presets/keyconfig/maya.py b/release/scripts/presets/keyconfig/maya.py index cdd16f26877..67fd1fddcac 100644 --- a/release/scripts/presets/keyconfig/maya.py +++ b/release/scripts/presets/keyconfig/maya.py @@ -698,7 +698,7 @@ kmi.properties.level = 5 km = kc.keymaps.new('Knife Tool Modal Map', space_type='EMPTY', region_type='WINDOW', modal=True) kmi = km.keymap_items.new_modal('CANCEL', 'ESC', 'ANY', any=True) -kmi = km.keymap_items.new_modal('ADD_CUT', 'LEFTMOUSE', 'ANY') +kmi = km.keymap_items.new_modal('ADD_CUT', 'LEFTMOUSE', 'ANY', any=True) kmi = km.keymap_items.new_modal('PANNING', 'LEFTMOUSE', 'ANY', alt=True) kmi = km.keymap_items.new_modal('PANNING', 'MIDDLEMOUSE', 'ANY', alt=True) kmi = km.keymap_items.new_modal('PANNING', 'RIGHTMOUSE', 'ANY', alt=True) diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 2b13a847e14..8ccc4a6eb0e 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -757,22 +757,22 @@ void DM_update_weight_mcol( typedef struct DMVertexAttribs { struct { struct MLoopUV *array; - int em_offset, gl_index, gl_texco; + int em_offset, gl_index, gl_texco, gl_info_index; } tface[MAX_MTFACE]; struct { struct MLoopCol *array; - int em_offset, gl_index; + int em_offset, gl_index, gl_info_index; } mcol[MAX_MCOL]; struct { float (*array)[4]; - int em_offset, gl_index; + int em_offset, gl_index, gl_info_index; } tang[MAX_MTFACE]; struct { float (*array)[3]; - int em_offset, gl_index, gl_texco; + int em_offset, gl_index, gl_texco, gl_info_index; } orco; int tottface, totmcol, tottang, totorco; diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index bcc3b60b34e..d590a35bb57 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -2003,15 +2003,10 @@ static void mesh_calc_modifiers( DM_add_edge_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL); DM_add_poly_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL); -#pragma omp parallel sections if (dm->numVertData + dm->numEdgeData + dm->numPolyData >= BKE_MESH_OMP_LIMIT) - { -#pragma omp section - { range_vn_i(DM_get_vert_data_layer(dm, CD_ORIGINDEX), dm->numVertData, 0); } -#pragma omp section - { range_vn_i(DM_get_edge_data_layer(dm, CD_ORIGINDEX), dm->numEdgeData, 0); } -#pragma omp section - { range_vn_i(DM_get_poly_data_layer(dm, CD_ORIGINDEX), dm->numPolyData, 0); } - } + /* Not worth parallelizing this, gives less than 0.1% overall speedup in best of best cases... */ + range_vn_i(DM_get_vert_data_layer(dm, CD_ORIGINDEX), dm->numVertData, 0); + range_vn_i(DM_get_edge_data_layer(dm, CD_ORIGINDEX), dm->numEdgeData, 0); + range_vn_i(DM_get_poly_data_layer(dm, CD_ORIGINDEX), dm->numPolyData, 0); } } @@ -3269,17 +3264,18 @@ void DM_calc_loop_tangents_step_0( bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n, char *ract_uv_name, char *rren_uv_name, char *rtangent_mask) { /* Active uv in viewport */ + int layer_index = CustomData_get_layer_index(loopData, CD_MLOOPUV); *ract_uv_n = CustomData_get_active_layer(loopData, CD_MLOOPUV); ract_uv_name[0] = 0; if (*ract_uv_n != -1) { - strcpy(ract_uv_name, loopData->layers[*ract_uv_n].name); + strcpy(ract_uv_name, loopData->layers[*ract_uv_n + layer_index].name); } /* Active tangent in render */ *rren_uv_n = CustomData_get_render_layer(loopData, CD_MLOOPUV); rren_uv_name[0] = 0; if (*rren_uv_n != -1) { - strcpy(rren_uv_name, loopData->layers[*rren_uv_n].name); + strcpy(rren_uv_name, loopData->layers[*rren_uv_n + layer_index].name); } /* If active tangent not in tangent_names we take it into account */ @@ -3677,6 +3673,7 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs, } attribs->tface[a].gl_index = gattribs->layer[b].glindex; + attribs->tface[a].gl_info_index = gattribs->layer[b].glinfoindoex; attribs->tface[a].gl_texco = gattribs->layer[b].gltexco; } else if (type == CD_MCOL) { @@ -3700,6 +3697,7 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs, } attribs->mcol[a].gl_index = gattribs->layer[b].glindex; + attribs->mcol[a].gl_info_index = gattribs->layer[b].glinfoindoex; } else if (type == CD_TANGENT) { /* note, even with 'is_editmesh' this uses the derived-meshes loop data */ @@ -3722,6 +3720,7 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs, } attribs->tang[a].gl_index = gattribs->layer[b].glindex; + attribs->tang[a].gl_info_index = gattribs->layer[b].glinfoindoex; } else if (type == CD_ORCO) { /* original coordinates */ @@ -3741,6 +3740,7 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs, attribs->orco.gl_index = gattribs->layer[b].glindex; attribs->orco.gl_texco = gattribs->layer[b].gltexco; + attribs->orco.gl_info_index = gattribs->layer[b].glinfoindoex; } } } @@ -3769,6 +3769,7 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert, glTexCoord3fv(orco); else glVertexAttrib3fv(attribs->orco.gl_index, orco); + glUniform1i(attribs->orco.gl_info_index, 0); } /* uv texture coordinates */ @@ -3787,6 +3788,7 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert, glTexCoord2fv(uv); else glVertexAttrib2fv(attribs->tface[b].gl_index, uv); + glUniform1i(attribs->tface[b].gl_info_index, 0); } /* vertex colors */ @@ -3802,6 +3804,7 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert, } glVertexAttrib4fv(attribs->mcol[b].gl_index, col); + glUniform1i(attribs->mcol[b].gl_info_index, GPU_ATTR_INFO_SRGB); } /* tangent for normal mapping */ @@ -3811,6 +3814,7 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert, const float *tang = (array) ? array[a * 4 + vert] : zero; glVertexAttrib4fv(attribs->tang[b].gl_index, tang); } + glUniform1i(attribs->tang[b].gl_info_index, 0); } } diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 9c163990dd2..249e4ccd89c 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -1020,6 +1020,7 @@ static void cdDM_drawMappedFacesGLSL( if (matconv[a].attribs.totorco && matconv[a].attribs.orco.array) { matconv[a].datatypes[numdata].index = matconv[a].attribs.orco.gl_index; + matconv[a].datatypes[numdata].info_index = matconv[a].attribs.orco.gl_info_index; matconv[a].datatypes[numdata].size = 3; matconv[a].datatypes[numdata].type = GL_FLOAT; numdata++; @@ -1027,6 +1028,7 @@ static void cdDM_drawMappedFacesGLSL( for (b = 0; b < matconv[a].attribs.tottface; b++) { if (matconv[a].attribs.tface[b].array) { matconv[a].datatypes[numdata].index = matconv[a].attribs.tface[b].gl_index; + matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tface[b].gl_info_index; matconv[a].datatypes[numdata].size = 2; matconv[a].datatypes[numdata].type = GL_FLOAT; numdata++; @@ -1035,6 +1037,7 @@ static void cdDM_drawMappedFacesGLSL( for (b = 0; b < matconv[a].attribs.totmcol; b++) { if (matconv[a].attribs.mcol[b].array) { matconv[a].datatypes[numdata].index = matconv[a].attribs.mcol[b].gl_index; + matconv[a].datatypes[numdata].info_index = matconv[a].attribs.mcol[b].gl_info_index; matconv[a].datatypes[numdata].size = 4; matconv[a].datatypes[numdata].type = GL_UNSIGNED_BYTE; numdata++; @@ -1043,6 +1046,7 @@ static void cdDM_drawMappedFacesGLSL( for (b = 0; b < matconv[a].attribs.tottang; b++) { if (matconv[a].attribs.tang[b].array) { matconv[a].datatypes[numdata].index = matconv[a].attribs.tang[b].gl_index; + matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tang[b].gl_info_index; matconv[a].datatypes[numdata].size = 4; matconv[a].datatypes[numdata].type = GL_FLOAT; numdata++; diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index bac59c8c62d..c1f1f0128f5 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -43,6 +43,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_utildefines.h" +#include "BLI_task.h" #include "BLI_threads.h" #include "BKE_colortools.h" @@ -53,10 +54,6 @@ #include "IMB_colormanagement.h" #include "IMB_imbuf_types.h" -#ifdef _OPENMP -# include <omp.h> -#endif - /* ********************************* color curve ********************* */ /* ***************** operations on full struct ************* */ @@ -1089,31 +1086,170 @@ void BKE_histogram_update_sample_line(Histogram *hist, ImBuf *ibuf, const ColorM } /* if view_settings, it also applies this to byte buffers */ +typedef struct ScopesUpdateData { + Scopes *scopes; + const ImBuf *ibuf; + struct ColormanageProcessor *cm_processor; + const unsigned char *display_buffer; + const int ycc_mode; + + unsigned int *bin_lum, *bin_r, *bin_g, *bin_b, *bin_a; +} ScopesUpdateData; + +typedef struct ScopesUpdateDataChunk { + unsigned int bin_lum[256]; + unsigned int bin_r[256]; + unsigned int bin_g[256]; + unsigned int bin_b[256]; + unsigned int bin_a[256]; + float min[3], max[3]; +} ScopesUpdateDataChunk; + +static void scopes_update_cb(void *userdata, void *userdata_chunk, const int y, const int UNUSED(threadid)) +{ + const ScopesUpdateData *data = userdata; + + Scopes *scopes = data->scopes; + const ImBuf *ibuf = data->ibuf; + struct ColormanageProcessor *cm_processor = data->cm_processor; + const unsigned char *display_buffer = data->display_buffer; + const int ycc_mode = data->ycc_mode; + + ScopesUpdateDataChunk *data_chunk = userdata_chunk; + unsigned int *bin_lum = data_chunk->bin_lum; + unsigned int *bin_r = data_chunk->bin_r; + unsigned int *bin_g = data_chunk->bin_g; + unsigned int *bin_b = data_chunk->bin_b; + unsigned int *bin_a = data_chunk->bin_a; + float *min = data_chunk->min; + float *max = data_chunk->max; + + const float *rf = NULL; + const unsigned char *rc = NULL; + const int rows_per_sample_line = ibuf->y / scopes->sample_lines; + const int savedlines = y / rows_per_sample_line; + const bool do_sample_line = (savedlines < scopes->sample_lines) && (y % rows_per_sample_line) == 0; + const bool is_float = (ibuf->rect_float != NULL); + + if (is_float) + rf = ibuf->rect_float + ((size_t)y) * ibuf->x * ibuf->channels; + else { + rc = display_buffer + ((size_t)y) * ibuf->x * ibuf->channels; + } + + for (int x = 0; x < ibuf->x; x++) { + float rgba[4], ycc[3], luma; + + if (is_float) { + switch (ibuf->channels) { + case 4: + copy_v4_v4(rgba, rf); + IMB_colormanagement_processor_apply_v4(cm_processor, rgba); + break; + case 3: + copy_v3_v3(rgba, rf); + IMB_colormanagement_processor_apply_v3(cm_processor, rgba); + rgba[3] = 1.0f; + break; + case 2: + copy_v3_fl(rgba, rf[0]); + rgba[3] = rf[1]; + break; + case 1: + copy_v3_fl(rgba, rf[0]); + rgba[3] = 1.0f; + break; + default: + BLI_assert(0); + } + } + else { + for (int c = 4; c--;) + rgba[c] = rc[c] * INV_255; + } + + /* we still need luma for histogram */ + luma = IMB_colormanagement_get_luminance(rgba); + + /* check for min max */ + if (ycc_mode == -1) { + minmax_v3v3_v3(min, max, rgba); + } + else { + rgb_to_ycc(rgba[0], rgba[1], rgba[2], &ycc[0], &ycc[1], &ycc[2], ycc_mode); + mul_v3_fl(ycc, INV_255); + minmax_v3v3_v3(min, max, ycc); + } + /* increment count for histo*/ + bin_lum[get_bin_float(luma)]++; + bin_r[get_bin_float(rgba[0])]++; + bin_g[get_bin_float(rgba[1])]++; + bin_b[get_bin_float(rgba[2])]++; + bin_a[get_bin_float(rgba[3])]++; + + /* save sample if needed */ + if (do_sample_line) { + const float fx = (float)x / (float)ibuf->x; + const int idx = 2 * (ibuf->x * savedlines + x); + save_sample_line(scopes, idx, fx, rgba, ycc); + } + + rf += ibuf->channels; + rc += ibuf->channels; + } +} + +static void scopes_update_finalize(void *userdata, void *userdata_chunk) +{ + const ScopesUpdateData *data = userdata; + const ScopesUpdateDataChunk *data_chunk = userdata_chunk; + + unsigned int *bin_lum = data->bin_lum; + unsigned int *bin_r = data->bin_r; + unsigned int *bin_g = data->bin_g; + unsigned int *bin_b = data->bin_b; + unsigned int *bin_a = data->bin_a; + const unsigned int *bin_lum_c = data_chunk->bin_lum; + const unsigned int *bin_r_c = data_chunk->bin_r; + const unsigned int *bin_g_c = data_chunk->bin_g; + const unsigned int *bin_b_c = data_chunk->bin_b; + const unsigned int *bin_a_c = data_chunk->bin_a; + + float (*minmax)[2] = data->scopes->minmax; + const float *min = data_chunk->min; + const float *max = data_chunk->max; + + for (int b = 256; b--;) { + bin_lum[b] += bin_lum_c[b]; + bin_r[b] += bin_r_c[b]; + bin_g[b] += bin_g_c[b]; + bin_b[b] += bin_b_c[b]; + bin_a[b] += bin_a_c[b]; + } + + for (int c = 3; c--;) { + if (min[c] < minmax[c][0]) + minmax[c][0] = min[c]; + if (max[c] > minmax[c][1]) + minmax[c][1] = max[c]; + } +} + void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings) { -#ifdef _OPENMP - const int num_threads = BLI_system_thread_count(); -#endif - int a, y; + int a; unsigned int nl, na, nr, ng, nb; double divl, diva, divr, divg, divb; - unsigned char *display_buffer; + const unsigned char *display_buffer = NULL; unsigned int bin_lum[256] = {0}, bin_r[256] = {0}, bin_g[256] = {0}, bin_b[256] = {0}, bin_a[256] = {0}; - unsigned int bin_lum_t[BLENDER_MAX_THREADS][256] = {{0}}, - bin_r_t[BLENDER_MAX_THREADS][256] = {{0}}, - bin_g_t[BLENDER_MAX_THREADS][256] = {{0}}, - bin_b_t[BLENDER_MAX_THREADS][256] = {{0}}, - bin_a_t[BLENDER_MAX_THREADS][256] = {{0}}; int ycc_mode = -1; - const bool is_float = (ibuf->rect_float != NULL); void *cache_handle = NULL; struct ColormanageProcessor *cm_processor = NULL; - int rows_per_sample_line; if (ibuf->rect == NULL && ibuf->rect_float == NULL) return; @@ -1151,7 +1287,6 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings * scopes->sample_lines = ibuf->y; /* scan the image */ - rows_per_sample_line = ibuf->y / scopes->sample_lines; for (a = 0; a < 3; a++) { scopes->minmax[a][0] = 25500.0f; scopes->minmax[a][1] = -25500.0f; @@ -1177,129 +1312,21 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings * cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings); } else { - display_buffer = (unsigned char *)IMB_display_buffer_acquire(ibuf, - view_settings, - display_settings, - &cache_handle); + display_buffer = (const unsigned char *)IMB_display_buffer_acquire( + ibuf, view_settings, display_settings, &cache_handle); } /* Keep number of threads in sync with the merge parts below. */ -#pragma omp parallel for private(y) schedule(static) num_threads(num_threads) if (ibuf->y > 256) - for (y = 0; y < ibuf->y; y++) { -#ifdef _OPENMP - const int thread_idx = omp_get_thread_num(); -#else - const int thread_idx = 0; -#endif - const float *rf = NULL; - const unsigned char *rc = NULL; - const int savedlines = y / rows_per_sample_line; - const bool do_sample_line = (savedlines < scopes->sample_lines) && (y % rows_per_sample_line) == 0; - float min[3] = { FLT_MAX, FLT_MAX, FLT_MAX}, - max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX}; - int x, c; - if (is_float) - rf = ibuf->rect_float + ((size_t)y) * ibuf->x * ibuf->channels; - else { - rc = display_buffer + ((size_t)y) * ibuf->x * ibuf->channels; - } - for (x = 0; x < ibuf->x; x++) { - float rgba[4], ycc[3], luma; - if (is_float) { - - switch (ibuf->channels) { - case 4: - copy_v4_v4(rgba, rf); - IMB_colormanagement_processor_apply_v4(cm_processor, rgba); - break; - case 3: - copy_v3_v3(rgba, rf); - IMB_colormanagement_processor_apply_v3(cm_processor, rgba); - rgba[3] = 1.0f; - break; - case 2: - copy_v3_fl(rgba, rf[0]); - rgba[3] = rf[1]; - break; - case 1: - copy_v3_fl(rgba, rf[0]); - rgba[3] = 1.0f; - break; - default: - BLI_assert(0); - } - } - else { - for (c = 0; c < 4; c++) - rgba[c] = rc[c] * INV_255; - } - - /* we still need luma for histogram */ - luma = IMB_colormanagement_get_luminance(rgba); - - /* check for min max */ - if (ycc_mode == -1) { - for (c = 0; c < 3; c++) { - if (rgba[c] < min[c]) min[c] = rgba[c]; - if (rgba[c] > max[c]) max[c] = rgba[c]; - } - } - else { - rgb_to_ycc(rgba[0], rgba[1], rgba[2], &ycc[0], &ycc[1], &ycc[2], ycc_mode); - for (c = 0; c < 3; c++) { - ycc[c] *= INV_255; - if (ycc[c] < min[c]) min[c] = ycc[c]; - if (ycc[c] > max[c]) max[c] = ycc[c]; - } - } - /* increment count for histo*/ - bin_lum_t[thread_idx][get_bin_float(luma)] += 1; - bin_r_t[thread_idx][get_bin_float(rgba[0])] += 1; - bin_g_t[thread_idx][get_bin_float(rgba[1])] += 1; - bin_b_t[thread_idx][get_bin_float(rgba[2])] += 1; - bin_a_t[thread_idx][get_bin_float(rgba[3])] += 1; - - /* save sample if needed */ - if (do_sample_line) { - const float fx = (float)x / (float)ibuf->x; - const int idx = 2 * (ibuf->x * savedlines + x); - save_sample_line(scopes, idx, fx, rgba, ycc); - } - - rf += ibuf->channels; - rc += ibuf->channels; - } -#pragma omp critical - { - for (c = 0; c < 3; c++) { - if (min[c] < scopes->minmax[c][0]) scopes->minmax[c][0] = min[c]; - if (max[c] > scopes->minmax[c][1]) scopes->minmax[c][1] = max[c]; - } - } - } - -#ifdef _OPENMP - if (ibuf->y > 256) { - for (a = 0; a < num_threads; a++) { - int b; - for (b = 0; b < 256; b++) { - bin_lum[b] += bin_lum_t[a][b]; - bin_r[b] += bin_r_t[a][b]; - bin_g[b] += bin_g_t[a][b]; - bin_b[b] += bin_b_t[a][b]; - bin_a[b] += bin_a_t[a][b]; - } - } - } - else -#endif - { - memcpy(bin_lum, bin_lum_t[0], sizeof(bin_lum)); - memcpy(bin_r, bin_r_t[0], sizeof(bin_r)); - memcpy(bin_g, bin_g_t[0], sizeof(bin_g)); - memcpy(bin_b, bin_b_t[0], sizeof(bin_b)); - memcpy(bin_a, bin_a_t[0], sizeof(bin_a)); - } + ScopesUpdateData data = { + .scopes = scopes, . ibuf = ibuf, + .cm_processor = cm_processor, .display_buffer = display_buffer, .ycc_mode = ycc_mode, + .bin_lum = bin_lum, .bin_r = bin_r, .bin_g = bin_g, .bin_b = bin_b, .bin_a = bin_a, + }; + ScopesUpdateDataChunk data_chunk = {0}; + INIT_MINMAX(data_chunk.min, data_chunk.max); + + BLI_task_parallel_range_finalize(0, ibuf->y, &data, &data_chunk, sizeof(data_chunk), + scopes_update_cb, scopes_update_finalize, ibuf->y > 256, false); /* test for nicer distribution even - non standard, leave it out for a while */ #if 0 diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c index e57e9ffcd66..5fba6c253a3 100644 --- a/source/blender/blenkernel/intern/editderivedmesh.c +++ b/source/blender/blenkernel/intern/editderivedmesh.c @@ -57,6 +57,7 @@ #include "MEM_guardedalloc.h" #include "GPU_glew.h" +#include "GPU_buffers.h" #include "GPU_shader.h" #include "GPU_basic_shader.h" @@ -1427,6 +1428,7 @@ static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const B glTexCoord3fv(orco); else glVertexAttrib3fv(attribs->orco.gl_index, orco); + glUniform1i(attribs->orco.gl_info_index, 0); } for (i = 0; i < attribs->tottface; i++) { const float *uv; @@ -1443,17 +1445,19 @@ static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const B glTexCoord2fv(uv); else glVertexAttrib2fv(attribs->tface[i].gl_index, uv); + glUniform1i(attribs->tface[i].gl_info_index, 0); } for (i = 0; i < attribs->totmcol; i++) { - GLubyte col[4]; + float col[4]; if (attribs->mcol[i].em_offset != -1) { const MLoopCol *cp = BM_ELEM_CD_GET_VOID_P(loop, attribs->mcol[i].em_offset); - copy_v4_v4_uchar(col, &cp->r); + rgba_uchar_to_float(col, &cp->r); } else { - col[0] = 0; col[1] = 0; col[2] = 0; col[3] = 0; + col[0] = 0.0f; col[1] = 0.0f; col[2] = 0.0f; col[3] = 0.0f; } - glVertexAttrib4ubv(attribs->mcol[i].gl_index, col); + glVertexAttrib4fv(attribs->mcol[i].gl_index, col); + glUniform1i(attribs->mcol[i].gl_info_index, GPU_ATTR_INFO_SRGB); } for (i = 0; i < attribs->tottang; i++) { @@ -1465,6 +1469,7 @@ static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const B tang = zero; } glVertexAttrib4fv(attribs->tang[i].gl_index, tang); + glUniform1i(attribs->tang[i].gl_info_index, 0); } } diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 1ae7ca189fb..0b2c844cb2c 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -109,8 +109,8 @@ static void image_add_view(Image *ima, const char *viewname, const char *filepat #define IMA_NO_INDEX 0x7FEFEFEF /* quick lookup: supports 1 million frames, thousand passes */ -#define IMA_MAKE_INDEX(frame, index) ((frame) << 10) + index -#define IMA_INDEX_FRAME(index) (index >> 10) +#define IMA_MAKE_INDEX(frame, index) (((frame) << 10) + (index)) +#define IMA_INDEX_FRAME(index) ((index) >> 10) /* #define IMA_INDEX_PASS(index) (index & ~1023) */ diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 1fec725dbb7..30f82a50ed9 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -1148,7 +1148,6 @@ static void init_render_nodetree(bNodeTree *ntree, Material *basemat, int r_mode /* parses the geom+tex nodes */ ntreeShaderGetTexcoMode(ntree, r_mode, &basemat->texco, &basemat->mode_l); - basemat->nmap_tangent_names_count = 0; for (node = ntree->nodes.first; node; node = node->next) { if (node->id) { if (GS(node->id->name) == ID_MA) { @@ -1199,7 +1198,7 @@ void init_render_material(Material *mat, int r_mode, float *amb) * mode_l will have it set when all node materials are shadeless. */ mat->mode_l = (mat->mode & MA_MODE_PIPELINE) | MA_SHLESS; mat->mode2_l = mat->mode2 & MA_MODE2_PIPELINE; - + mat->nmap_tangent_names_count = 0; init_render_nodetree(mat->nodetree, mat, r_mode, amb); if (!mat->nodetree->execdata) diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index e855f6faa22..518d8d68919 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -44,6 +44,7 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +#include "BLI_task.h" #include "BKE_shrinkwrap.h" #include "BKE_DerivedMesh.h" @@ -58,7 +59,7 @@ /* for timing... */ #if 0 -# include "PIL_time.h" +# include "PIL_time_utildefines.h" #else # define TIMEIT_BENCH(expr, id) (expr) #endif @@ -66,16 +67,88 @@ /* Util macros */ #define OUT_OF_MEMORY() ((void)printf("Shrinkwrap: Out of memory\n")) +typedef struct ShrinkwrapCalcCBData { + ShrinkwrapCalcData *calc; + + void *treeData; + void *auxData; + BVHTree *targ_tree; + BVHTree *aux_tree; + void *targ_callback; + void *aux_callback; + + float *proj_axis; + SpaceTransform *local2aux; +} ShrinkwrapCalcCBData; + /* * Shrinkwrap to the nearest vertex * * it builds a kdtree of vertexs we can attach to and then * for each vertex performs a nearest vertex search on the tree */ -static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) +static void shrinkwrap_calc_nearest_vertex_cb_ex( + void *userdata, void *userdata_chunk, const int i, const int UNUSED(threadid)) { - int i; + ShrinkwrapCalcCBData *data = userdata; + + ShrinkwrapCalcData *calc = data->calc; + BVHTreeFromMesh *treeData = data->treeData; + BVHTreeNearest *nearest = userdata_chunk; + + float *co = calc->vertexCos[i]; + float tmp_co[3]; + float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup); + + if (calc->invert_vgroup) { + weight = 1.0f - weight; + } + + if (weight == 0.0f) { + return; + } + + /* Convert the vertex to tree coordinates */ + if (calc->vert) { + copy_v3_v3(tmp_co, calc->vert[i].co); + } + else { + copy_v3_v3(tmp_co, co); + } + BLI_space_transform_apply(&calc->local2target, tmp_co); + + /* Use local proximity heuristics (to reduce the nearest search) + * + * If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex + * so we can initiate the "nearest.dist" with the expected value to that last hit. + * This will lead in pruning of the search tree. */ + if (nearest->index != -1) + nearest->dist_sq = len_squared_v3v3(tmp_co, nearest->co); + else + nearest->dist_sq = FLT_MAX; + + BLI_bvhtree_find_nearest(treeData->tree, tmp_co, nearest, treeData->nearest_callback, treeData); + + + /* Found the nearest vertex */ + if (nearest->index != -1) { + /* Adjusting the vertex weight, + * so that after interpolating it keeps a certain distance from the nearest position */ + if (nearest->dist_sq > FLT_EPSILON) { + const float dist = sqrtf(nearest->dist_sq); + weight *= (dist - calc->keepDist) / dist; + } + + /* Convert the coordinates back to mesh coordinates */ + copy_v3_v3(tmp_co, nearest->co); + BLI_space_transform_invert(&calc->local2target, tmp_co); + + interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */ + } +} +static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) +{ BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh; BVHTreeNearest nearest = NULL_BVHTreeNearest; @@ -89,61 +162,11 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) /* Setup nearest */ nearest.index = -1; nearest.dist_sq = FLT_MAX; -#ifndef __APPLE__ -#pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(treeData, calc) schedule(static) if (calc->numVerts > BKE_MESH_OMP_LIMIT) -#endif - for (i = 0; i < calc->numVerts; ++i) { - float *co = calc->vertexCos[i]; - float tmp_co[3]; - float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup); - - if (calc->invert_vgroup) { - weight = 1.0f - weight; - } - - if (weight == 0.0f) { - continue; - } - - - /* Convert the vertex to tree coordinates */ - if (calc->vert) { - copy_v3_v3(tmp_co, calc->vert[i].co); - } - else { - copy_v3_v3(tmp_co, co); - } - BLI_space_transform_apply(&calc->local2target, tmp_co); - - /* Use local proximity heuristics (to reduce the nearest search) - * - * If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex - * so we can initiate the "nearest.dist" with the expected value to that last hit. - * This will lead in pruning of the search tree. */ - if (nearest.index != -1) - nearest.dist_sq = len_squared_v3v3(tmp_co, nearest.co); - else - nearest.dist_sq = FLT_MAX; - - BLI_bvhtree_find_nearest(treeData.tree, tmp_co, &nearest, treeData.nearest_callback, &treeData); - - - /* Found the nearest vertex */ - if (nearest.index != -1) { - /* Adjusting the vertex weight, - * so that after interpolating it keeps a certain distance from the nearest position */ - if (nearest.dist_sq > FLT_EPSILON) { - const float dist = sqrtf(nearest.dist_sq); - weight *= (dist - calc->keepDist) / dist; - } - /* Convert the coordinates back to mesh coordinates */ - copy_v3_v3(tmp_co, nearest.co); - BLI_space_transform_invert(&calc->local2target, tmp_co); - - interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */ - } - } + ShrinkwrapCalcCBData data = {.calc = calc, .treeData = &treeData}; + BLI_task_parallel_range_ex( + 0, calc->numVerts, &data, &nearest, sizeof(nearest), shrinkwrap_calc_nearest_vertex_cb_ex, + calc->numVerts > BKE_MESH_OMP_LIMIT, false); free_bvhtree_from_mesh(&treeData); } @@ -230,13 +253,109 @@ bool BKE_shrinkwrap_project_normal( return false; } +static void shrinkwrap_calc_normal_projection_cb_ex( + void *userdata, void *userdata_chunk, const int i, const int UNUSED(threadid)) +{ + ShrinkwrapCalcCBData *data = userdata; + + ShrinkwrapCalcData *calc = data->calc; + void *treeData = data->treeData; + void *auxData = data->auxData; + BVHTree *targ_tree = data->targ_tree; + BVHTree *aux_tree = data->aux_tree; + void *targ_callback = data->targ_callback; + void *aux_callback = data->aux_callback; + + float *proj_axis = data->proj_axis; + SpaceTransform *local2aux = data->local2aux; + + BVHTreeRayHit *hit = userdata_chunk; + + const float proj_limit_squared = calc->smd->projLimit * calc->smd->projLimit; + float *co = calc->vertexCos[i]; + float tmp_co[3], tmp_no[3]; + float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup); + + if (calc->invert_vgroup) { + weight = 1.0f - weight; + } + + if (weight == 0.0f) { + return; + } + + if (calc->vert) { + /* calc->vert contains verts from derivedMesh */ + /* this coordinated are deformed by vertexCos only for normal projection (to get correct normals) */ + /* for other cases calc->varts contains undeformed coordinates and vertexCos should be used */ + if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) { + copy_v3_v3(tmp_co, calc->vert[i].co); + normal_short_to_float_v3(tmp_no, calc->vert[i].no); + } + else { + copy_v3_v3(tmp_co, co); + copy_v3_v3(tmp_no, proj_axis); + } + } + else { + copy_v3_v3(tmp_co, co); + copy_v3_v3(tmp_no, proj_axis); + } + + + hit->index = -1; + hit->dist = BVH_RAYCAST_DIST_MAX; /* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */ + + /* Project over positive direction of axis */ + if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) { + if (aux_tree) { + BKE_shrinkwrap_project_normal( + 0, tmp_co, tmp_no, + local2aux, aux_tree, hit, + aux_callback, auxData); + } + + BKE_shrinkwrap_project_normal( + calc->smd->shrinkOpts, tmp_co, tmp_no, + &calc->local2target, targ_tree, hit, + targ_callback, treeData); + } + + /* Project over negative direction of axis */ + if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR) { + float inv_no[3]; + negate_v3_v3(inv_no, tmp_no); + + if (aux_tree) { + BKE_shrinkwrap_project_normal( + 0, tmp_co, inv_no, + local2aux, aux_tree, hit, + aux_callback, auxData); + } + + BKE_shrinkwrap_project_normal( + calc->smd->shrinkOpts, tmp_co, inv_no, + &calc->local2target, targ_tree, hit, + targ_callback, treeData); + } + + /* don't set the initial dist (which is more efficient), + * because its calculated in the targets space, we want the dist in our own space */ + if (proj_limit_squared != 0.0f) { + if (len_squared_v3v3(hit->co, co) > proj_limit_squared) { + hit->index = -1; + } + } + + if (hit->index != -1) { + madd_v3_v3v3fl(hit->co, hit->co, tmp_no, calc->keepDist); + interp_v3_v3v3(co, co, hit->co, weight); + } +} static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for_render) { - int i; - /* Options about projection direction */ - const float proj_limit_squared = calc->smd->projLimit * calc->smd->projLimit; float proj_axis[3] = {0.0f, 0.0f, 0.0f}; /* Raycast and tree stuff */ @@ -305,7 +424,7 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for } if (targ_tree) { BVHTree *aux_tree = NULL; - void *aux_callback; + void *aux_callback = NULL; if (auxMesh != NULL) { /* use editmesh to avoid array allocation */ if (calc->smd->auxTarget && auxMesh->type == DM_TYPE_EDITBMESH) { @@ -316,99 +435,22 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for } } else { - if ((aux_tree = bvhtree_from_mesh_looptri(&dmauxdata_stack, calc->target, 0.0, 4, 6)) != NULL) { + if ((aux_tree = bvhtree_from_mesh_looptri(&dmauxdata_stack, auxMesh, 0.0, 4, 6)) != NULL) { aux_callback = dmauxdata_stack.raycast_callback; auxData = &dmauxdata_stack; } } } /* After sucessufuly build the trees, start projection vertexs */ - -#ifndef __APPLE__ -#pragma omp parallel for private(i, hit) schedule(static) if (calc->numVerts > BKE_MESH_OMP_LIMIT) -#endif - for (i = 0; i < calc->numVerts; ++i) { - float *co = calc->vertexCos[i]; - float tmp_co[3], tmp_no[3]; - float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup); - - if (calc->invert_vgroup) { - weight = 1.0f - weight; - } - - if (weight == 0.0f) { - continue; - } - - if (calc->vert) { - /* calc->vert contains verts from derivedMesh */ - /* this coordinated are deformed by vertexCos only for normal projection (to get correct normals) */ - /* for other cases calc->varts contains undeformed coordinates and vertexCos should be used */ - if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) { - copy_v3_v3(tmp_co, calc->vert[i].co); - normal_short_to_float_v3(tmp_no, calc->vert[i].no); - } - else { - copy_v3_v3(tmp_co, co); - copy_v3_v3(tmp_no, proj_axis); - } - } - else { - copy_v3_v3(tmp_co, co); - copy_v3_v3(tmp_no, proj_axis); - } - - - hit.index = -1; - hit.dist = BVH_RAYCAST_DIST_MAX; /* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */ - - /* Project over positive direction of axis */ - if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) { - - if (aux_tree) { - BKE_shrinkwrap_project_normal( - 0, tmp_co, tmp_no, - &local2aux, aux_tree, &hit, - aux_callback, auxData); - } - - BKE_shrinkwrap_project_normal( - calc->smd->shrinkOpts, tmp_co, tmp_no, - &calc->local2target, targ_tree, &hit, - targ_callback, treeData); - } - - /* Project over negative direction of axis */ - if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR) { - float inv_no[3]; - negate_v3_v3(inv_no, tmp_no); - - if (aux_tree) { - BKE_shrinkwrap_project_normal( - 0, tmp_co, inv_no, - &local2aux, aux_tree, &hit, - aux_callback, auxData); - } - - BKE_shrinkwrap_project_normal( - calc->smd->shrinkOpts, tmp_co, inv_no, - &calc->local2target, targ_tree, &hit, - targ_callback, treeData); - } - - /* don't set the initial dist (which is more efficient), - * because its calculated in the targets space, we want the dist in our own space */ - if (proj_limit_squared != 0.0f) { - if (len_squared_v3v3(hit.co, co) > proj_limit_squared) { - hit.index = -1; - } - } - - if (hit.index != -1) { - madd_v3_v3v3fl(hit.co, hit.co, tmp_no, calc->keepDist); - interp_v3_v3v3(co, co, hit.co, weight); - } - } + ShrinkwrapCalcCBData data = { + .calc = calc, + .treeData = treeData, .targ_tree = targ_tree, .targ_callback = targ_callback, + .auxData = auxData, .aux_tree = aux_tree, .aux_callback = aux_callback, + .proj_axis = proj_axis, .local2aux = &local2aux, + }; + BLI_task_parallel_range_ex( + 0, calc->numVerts, &data, &hit, sizeof(hit), shrinkwrap_calc_normal_projection_cb_ex, + calc->numVerts > BKE_MESH_OMP_LIMIT, false); } /* free data structures */ @@ -428,10 +470,75 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for * it builds a BVHTree from the target mesh and then performs a * NN matches for each vertex */ -static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) +static void shrinkwrap_calc_nearest_surface_point_cb_ex( + void *userdata, void *userdata_chunk, const int i, const int UNUSED(threadid)) { - int i; + ShrinkwrapCalcCBData *data = userdata; + + ShrinkwrapCalcData *calc = data->calc; + BVHTreeFromMesh *treeData = data->treeData; + BVHTreeNearest *nearest = userdata_chunk; + + float *co = calc->vertexCos[i]; + float tmp_co[3]; + float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup); + + if (calc->invert_vgroup) { + weight = 1.0f - weight; + } + + if (weight == 0.0f) { + return; + } + + /* Convert the vertex to tree coordinates */ + if (calc->vert) { + copy_v3_v3(tmp_co, calc->vert[i].co); + } + else { + copy_v3_v3(tmp_co, co); + } + BLI_space_transform_apply(&calc->local2target, tmp_co); + + /* Use local proximity heuristics (to reduce the nearest search) + * + * If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex + * so we can initiate the "nearest.dist" with the expected value to that last hit. + * This will lead in pruning of the search tree. */ + if (nearest->index != -1) + nearest->dist_sq = len_squared_v3v3(tmp_co, nearest->co); + else + nearest->dist_sq = FLT_MAX; + + BLI_bvhtree_find_nearest(treeData->tree, tmp_co, nearest, treeData->nearest_callback, treeData); + + /* Found the nearest vertex */ + if (nearest->index != -1) { + if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE) { + /* Make the vertex stay on the front side of the face */ + madd_v3_v3v3fl(tmp_co, nearest->co, nearest->no, calc->keepDist); + } + else { + /* Adjusting the vertex weight, + * so that after interpolating it keeps a certain distance from the nearest position */ + const float dist = sasqrt(nearest->dist_sq); + if (dist > FLT_EPSILON) { + /* linear interpolation */ + interp_v3_v3v3(tmp_co, tmp_co, nearest->co, (dist - calc->keepDist) / dist); + } + else { + copy_v3_v3(tmp_co, nearest->co); + } + } + /* Convert the coordinates back to mesh coordinates */ + BLI_space_transform_invert(&calc->local2target, tmp_co); + interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */ + } +} + +static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) +{ BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh; BVHTreeNearest nearest = NULL_BVHTreeNearest; @@ -446,67 +553,11 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) nearest.index = -1; nearest.dist_sq = FLT_MAX; - /* Find the nearest vertex */ -#ifndef __APPLE__ -#pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(calc, treeData) schedule(static) if (calc->numVerts > BKE_MESH_OMP_LIMIT) -#endif - for (i = 0; i < calc->numVerts; ++i) { - float *co = calc->vertexCos[i]; - float tmp_co[3]; - float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup); - - if (calc->invert_vgroup) { - weight = 1.0f - weight; - } - - if (weight == 0.0f) continue; - - /* Convert the vertex to tree coordinates */ - if (calc->vert) { - copy_v3_v3(tmp_co, calc->vert[i].co); - } - else { - copy_v3_v3(tmp_co, co); - } - BLI_space_transform_apply(&calc->local2target, tmp_co); - - /* Use local proximity heuristics (to reduce the nearest search) - * - * If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex - * so we can initiate the "nearest.dist" with the expected value to that last hit. - * This will lead in pruning of the search tree. */ - if (nearest.index != -1) - nearest.dist_sq = len_squared_v3v3(tmp_co, nearest.co); - else - nearest.dist_sq = FLT_MAX; - - BLI_bvhtree_find_nearest(treeData.tree, tmp_co, &nearest, treeData.nearest_callback, &treeData); - - /* Found the nearest vertex */ - if (nearest.index != -1) { - if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE) { - /* Make the vertex stay on the front side of the face */ - madd_v3_v3v3fl(tmp_co, nearest.co, nearest.no, calc->keepDist); - } - else { - /* Adjusting the vertex weight, - * so that after interpolating it keeps a certain distance from the nearest position */ - const float dist = sasqrt(nearest.dist_sq); - if (dist > FLT_EPSILON) { - /* linear interpolation */ - interp_v3_v3v3(tmp_co, tmp_co, nearest.co, (dist - calc->keepDist) / dist); - } - else { - copy_v3_v3(tmp_co, nearest.co); - } - } - - /* Convert the coordinates back to mesh coordinates */ - BLI_space_transform_invert(&calc->local2target, tmp_co); - interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */ - } - } + ShrinkwrapCalcCBData data = {.calc = calc, .treeData = &treeData}; + BLI_task_parallel_range_ex( + 0, calc->numVerts, &data, &nearest, sizeof(nearest), shrinkwrap_calc_nearest_surface_point_cb_ex, + calc->numVerts > BKE_MESH_OMP_LIMIT, false); free_bvhtree_from_mesh(&treeData); } diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 5b6adb3778a..b0d19320230 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -2995,6 +2995,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm, if (matconv[a].attribs.totorco && matconv[a].attribs.orco.array) { matconv[a].datatypes[numdata].index = matconv[a].attribs.orco.gl_index; + matconv[a].datatypes[numdata].info_index = matconv[a].attribs.orco.gl_info_index; matconv[a].datatypes[numdata].size = 3; matconv[a].datatypes[numdata].type = GL_FLOAT; numdata++; @@ -3002,6 +3003,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm, for (b = 0; b < matconv[a].attribs.tottface; b++) { if (matconv[a].attribs.tface[b].array) { matconv[a].datatypes[numdata].index = matconv[a].attribs.tface[b].gl_index; + matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tface[b].gl_info_index; matconv[a].datatypes[numdata].size = 2; matconv[a].datatypes[numdata].type = GL_FLOAT; numdata++; @@ -3010,6 +3012,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm, for (b = 0; b < matconv[a].attribs.totmcol; b++) { if (matconv[a].attribs.mcol[b].array) { matconv[a].datatypes[numdata].index = matconv[a].attribs.mcol[b].gl_index; + matconv[a].datatypes[numdata].info_index = matconv[a].attribs.mcol[b].gl_info_index; matconv[a].datatypes[numdata].size = 4; matconv[a].datatypes[numdata].type = GL_UNSIGNED_BYTE; numdata++; @@ -3018,6 +3021,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm, for (b = 0; b < matconv[a].attribs.tottang; b++) { if (matconv[a].attribs.tottang && matconv[a].attribs.tang[b].array) { matconv[a].datatypes[numdata].index = matconv[a].attribs.tang[b].gl_index; + matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tang[b].gl_info_index; matconv[a].datatypes[numdata].size = 4; matconv[a].datatypes[numdata].type = GL_FLOAT; numdata++; diff --git a/source/blender/blenlib/BLI_array_store.h b/source/blender/blenlib/BLI_array_store.h new file mode 100644 index 00000000000..f4cbc07bf26 --- /dev/null +++ b/source/blender/blenlib/BLI_array_store.h @@ -0,0 +1,66 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BLI_ARRAY_STORE_H__ +#define __BLI_ARRAY_STORE_H__ + +/** \file BLI_array_store.h + * \ingroup bli + * \brief Efficient in-memory storage of multiple similar arrays. + */ + +typedef struct BArrayStore BArrayStore; +typedef struct BArrayState BArrayState; + +BArrayStore *BLI_array_store_create( + unsigned int stride, unsigned int chunk_count); +void BLI_array_store_destroy( + BArrayStore *bs); +void BLI_array_store_clear( + BArrayStore *bs); + +/* find the memory used by all states (expanded & real) */ +size_t BLI_array_store_calc_size_expanded_get( + const BArrayStore *bs); +size_t BLI_array_store_calc_size_compacted_get( + const BArrayStore *bs); + +BArrayState *BLI_array_store_state_add( + BArrayStore *bs, + const void *data, const size_t data_len, + const BArrayState *state_reference); +void BLI_array_store_state_remove( + BArrayStore *bs, + BArrayState *state); + +size_t BLI_array_store_state_size_get( + BArrayState *state); +void BLI_array_store_state_data_get( + BArrayState *state, + void *data); +void *BLI_array_store_state_data_get_alloc( + BArrayState *state, + size_t *r_data_len); + +/* only for tests */ +bool BLI_array_store_is_valid( + BArrayStore *bs); + +#endif /* __BLI_ARRAY_STORE_H__ */ diff --git a/source/blender/blenlib/BLI_stackdefines.h b/source/blender/blenlib/BLI_stackdefines.h index b26dc3e26aa..42b11eb9a2b 100644 --- a/source/blender/blenlib/BLI_stackdefines.h +++ b/source/blender/blenlib/BLI_stackdefines.h @@ -31,28 +31,28 @@ /* only validate array-bounds in debug mode */ #ifdef DEBUG # define STACK_DECLARE(stack) unsigned int _##stack##_index, _##stack##_totalloc -# define STACK_INIT(stack, tot) ((void)stack, (void)((_##stack##_index) = 0), (void)((_##stack##_totalloc) = tot)) -# define _STACK_SIZETEST(stack, off) (BLI_assert((_##stack##_index) + off <= _##stack##_totalloc)) +# define STACK_INIT(stack, tot) ((void)stack, (void)((_##stack##_index) = 0), (void)((_##stack##_totalloc) = (tot))) +# define _STACK_SIZETEST(stack, off) (BLI_assert((_##stack##_index) + (off) <= _##stack##_totalloc)) # define _STACK_SWAP_TOTALLOC(stack_a, stack_b) SWAP(unsigned int, _##stack_a##_totalloc, _##stack_b##_totalloc) #else # define STACK_DECLARE(stack) unsigned int _##stack##_index -# define STACK_INIT(stack, tot) ((void)stack, (void)((_##stack##_index) = 0), (void)(0 ? tot : 0)) +# define STACK_INIT(stack, tot) ((void)stack, (void)((_##stack##_index) = 0), (void)(0 ? (tot) : 0)) # define _STACK_SIZETEST(stack, off) (void)(stack), (void)(off) # define _STACK_SWAP_TOTALLOC(stack_a, stack_b) (void)(stack_a), (void)(stack_b) #endif -#define _STACK_BOUNDSTEST(stack, index) ((void)stack, BLI_assert((unsigned int)index < _##stack##_index)) +#define _STACK_BOUNDSTEST(stack, index) ((void)stack, BLI_assert((unsigned int)(index) < _##stack##_index)) #define STACK_SIZE(stack) ((void)stack, (_##stack##_index)) #define STACK_CLEAR(stack) {(void)stack; _##stack##_index = 0; } ((void)0) /** add item to stack */ -#define STACK_PUSH(stack, val) ((void)stack, _STACK_SIZETEST(stack, 1), ((stack)[(_##stack##_index)++] = val)) +#define STACK_PUSH(stack, val) ((void)stack, _STACK_SIZETEST(stack, 1), ((stack)[(_##stack##_index)++] = (val))) #define STACK_PUSH_RET(stack) ((void)stack, _STACK_SIZETEST(stack, 1), ((stack)[(_##stack##_index)++])) #define STACK_PUSH_RET_PTR(stack) ((void)stack, _STACK_SIZETEST(stack, 1), &((stack)[(_##stack##_index)++])) /** take last item from stack */ #define STACK_POP(stack) ((_##stack##_index) ? ((stack)[--(_##stack##_index)]) : NULL) #define STACK_POP_PTR(stack) ((_##stack##_index) ? &((stack)[--(_##stack##_index)]) : NULL) -#define STACK_POP_DEFAULT(stack, r) ((_##stack##_index) ? ((stack)[--(_##stack##_index)]) : r) +#define STACK_POP_DEFAULT(stack, r) ((_##stack##_index) ? ((stack)[--(_##stack##_index)]) : (r)) /** look at last item (assumes non-empty stack) */ #define STACK_PEEK(stack) (BLI_assert(_##stack##_index), ((stack)[_##stack##_index - 1])) #define STACK_PEEK_PTR(stack) (BLI_assert(_##stack##_index), &((stack)[_##stack##_index - 1])) diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 944ba60eb58..42d958774d8 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -52,6 +52,7 @@ set(SRC intern/BLI_memarena.c intern/BLI_mempool.c intern/DLRB_tree.c + intern/array_store.c intern/array_utils.c intern/astar.c intern/boxpack2d.c @@ -120,6 +121,7 @@ set(SRC BLI_alloca.h BLI_args.h BLI_array.h + BLI_array_store.h BLI_array_utils.h BLI_astar.h BLI_bitmap.h diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c index 06946e520a8..0b5adab3929 100644 --- a/source/blender/blenlib/intern/BLI_ghash.c +++ b/source/blender/blenlib/intern/BLI_ghash.c @@ -441,7 +441,7 @@ static GHash *ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info, gh->flag = flag; ghash_buckets_reset(gh, nentries_reserve); - gh->entrypool = BLI_mempool_create(GHASH_ENTRY_SIZE(flag & GHASH_FLAG_IS_GSET), 64, 64, BLI_MEMPOOL_NOP); + gh->entrypool = BLI_mempool_create(GHASH_ENTRY_SIZE(flag & GHASH_FLAG_IS_GSET), 0, 64, BLI_MEMPOOL_NOP); return gh; } @@ -1287,7 +1287,7 @@ bool BLI_ghashutil_paircmp(const void *a, const void *b) const GHashPair *A = a; const GHashPair *B = b; - return (BLI_ghashutil_ptrcmp(A->first, B->first) || + return (BLI_ghashutil_ptrcmp(A->first, B->first) && BLI_ghashutil_ptrcmp(A->second, B->second)); } diff --git a/source/blender/blenlib/intern/BLI_mempool.c b/source/blender/blenlib/intern/BLI_mempool.c index 7338804c685..38d15750761 100644 --- a/source/blender/blenlib/intern/BLI_mempool.c +++ b/source/blender/blenlib/intern/BLI_mempool.c @@ -57,12 +57,29 @@ #ifdef __BIG_ENDIAN__ /* Big Endian */ # define MAKE_ID(a, b, c, d) ( (int)(a) << 24 | (int)(b) << 16 | (c) << 8 | (d) ) +# define MAKE_ID_8(a, b, c, d, e, f, g, h) \ + ((int64_t)(a) << 56 | (int64_t)(b) << 48 | (int64_t)(c) << 40 | (int64_t)(d) << 32 | \ + (int64_t)(e) << 24 | (int64_t)(f) << 16 | (int64_t)(g) << 8 | (h) ) #else /* Little Endian */ # define MAKE_ID(a, b, c, d) ( (int)(d) << 24 | (int)(c) << 16 | (b) << 8 | (a) ) +# define MAKE_ID_8(a, b, c, d, e, f, g, h) \ + ((int64_t)(h) << 56 | (int64_t)(g) << 48 | (int64_t)(f) << 40 | (int64_t)(e) << 32 | \ + (int64_t)(d) << 24 | (int64_t)(c) << 16 | (int64_t)(b) << 8 | (a) ) #endif -#define FREEWORD MAKE_ID('f', 'r', 'e', 'e') +/** + * Important that this value is an is _not_ aligned with ``sizeof(void *)``. + * So having a pointer to 2/4/8... aligned memory is enough to ensure the freeword will never be used. + * To be safe, use a word thats the same in both directions. + */ +#define FREEWORD ((sizeof(void *) > sizeof(int32_t)) ? \ + MAKE_ID_8('e', 'e', 'r', 'f', 'f', 'r', 'e', 'e') : \ + MAKE_ID('e', 'f', 'f', 'e')) + +/** + * The 'used' word just needs to be set to something besides FREEWORD. + */ #define USEDWORD MAKE_ID('u', 's', 'e', 'd') /* currently totalloc isnt used */ @@ -87,7 +104,7 @@ static bool mempool_debug_memset = false; */ typedef struct BLI_freenode { struct BLI_freenode *next; - int freeword; /* used to identify this as a freed node */ + intptr_t freeword; /* used to identify this as a freed node */ } BLI_freenode; /** diff --git a/source/blender/blenlib/intern/array_store.c b/source/blender/blenlib/intern/array_store.c new file mode 100644 index 00000000000..7f657f4a048 --- /dev/null +++ b/source/blender/blenlib/intern/array_store.c @@ -0,0 +1,1731 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenlib/intern/array_store.c + * \ingroup bli + * \brief Array storage to minimize duplication. + * + * This is done by splitting arrays into chunks and using copy-on-write (COW), + * to de-duplicate chunks, + * from the users perspective this is an implementation detail. + * + * + * Overview + * ======== + * + * + * Data Structure + * -------------- + * + * This diagram is an overview of the structure of a single array-store. + * + * \note The only 2 structues here which are referenced externally are the. + * + * - BArrayStore: The whole array store. + * - BArrayState: Represents a single state (array) of data. + * These can be add using a reference state, while this could be considered the previous or parent state. + * no relationship is kept, so the caller is free to add any state from the same BArrayStore as a reference. + * + * <pre> + * <+> BArrayStore: root data-structure, + * | can store many 'states', which share memory. + * | + * | This can store many arrays, however they must share the same 'stride'. + * | Arrays of different types will need to use a new BArrayStore. + * | + * +- <+> states (Collection of BArrayState's): + * | | Each represents an array added by the user of this API. + * | | and references a chunk_list (each state is a chunk_list user). + * | | Note that the list order has no significance. + * | | + * | +- <+> chunk_list (BChunkList): + * | | The chunks that make up this state. + * | | Each state is a chunk_list user, + * | | avoids duplicating lists when there is no change between states. + * | | + * | +- chunk_refs (List of BChunkRef): Each chunk_ref links to a a BChunk. + * | Each reference is a chunk user, + * | avoids duplicating smaller chunks of memory found in multiple states. + * | + * +- info (BArrayInfo): + * | Sizes and offsets for this array-store. + * | Also caches some variables for reuse. + * | + * +- <+> memory (BArrayMemory): + * | Memory pools for storing BArrayStore data. + * | + * +- chunk_list (Pool of BChunkList): + * | All chunk_lists, (reference counted, used by BArrayState). + * | + * +- chunk_ref (Pool of BChunkRef): + * | All chunk_refs (link between BChunkList & BChunk). + * | + * +- chunks (Pool of BChunk): + * All chunks, (reference counted, used by BChunkList). + * These have their headers hashed for reuse so we can quickly check for duplicates. + * </pre> + * + * + * De-Duplication + * -------------- + * + * When creating a new state, a previous state can be given as a reference, + * matching chunks from this state are re-used in the new state. + * + * First matches at either end of the array are detected. + * For identical arrays this is all thats needed. + * + * De-duplication is performed on any remaining chunks, by hasing the first few bytes of the chunk + * (see: BCHUNK_HASH_TABLE_ACCUMULATE_STEPS). + * + * \note This is cached for reuse since the referenced data never changes. + * + * An array is created to store hash values at every 'stride', + * then stepped over to search for matching chunks. + * + * Once a match is found, there is a high chance next chunks match too, + * so this is checked to avoid performing so many hash-lookups. + * Otherwise new chunks are created. + */ + +#include <stdlib.h> +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_mempool.h" + +#include "BLI_strict_flags.h" + +#include "BLI_array_store.h" /* own include */ + +/* only for BLI_array_store_is_valid */ +#include "BLI_ghash.h" + +/** \name Defines + * + * Some of the logic for merging is quite involved, + * support disabling some parts of this. + * \{ */ + +/* Scan first chunks (happy path when beginning of the array matches). + * When the array is a perfect match, we can re-use the entire list. + * + * Note that disabling makes some tests fail that check for output-size. + */ +#define USE_FASTPATH_CHUNKS_FIRST + +/* Scan last chunks (happy path when end of the array matches). + * When the end of the array matches, we can quickly add these chunks. + * note that we will add contiguous matching chunks + * so this isn't as useful as USE_FASTPATH_CHUNKS_FIRST, + * however it avoids adding matching chunks into the lookup table, + * so creating the lookup table won't be as expensive. + */ +#ifdef USE_FASTPATH_CHUNKS_FIRST +# define USE_FASTPATH_CHUNKS_LAST +#endif + +/* For arrays of matching length, test that *enough* of the chunks are aligned, + * and simply step over both arrays, using matching chunks. + * This avoids overhead of using a lookup table for cases when we can assume they're mostly aligned. + */ +#define USE_ALIGN_CHUNKS_TEST + +/* Accumulate hashes from right to left so we can create a hash for the chunk-start. + * This serves to increase uniqueness and will help when there is many values which are the same. + */ +#define USE_HASH_TABLE_ACCUMULATE + +#ifdef USE_HASH_TABLE_ACCUMULATE +/* Number of times to propagate hashes back. + * Effectively a 'triangle-number'. + * so 4 -> 7, 5 -> 10, 6 -> 15... etc. + */ +# define BCHUNK_HASH_TABLE_ACCUMULATE_STEPS 4 +#else +/* How many items to hash (multiplied by stride) + */ +# define BCHUNK_HASH_LEN 4 +#endif + +/* Calculate the key once and reuse it + */ +#define USE_HASH_TABLE_KEY_CACHE +#ifdef USE_HASH_TABLE_KEY_CACHE +# define HASH_TABLE_KEY_UNSET ((uint64_t)-1) +# define HASH_TABLE_KEY_FALLBACK ((uint64_t)-2) +#endif + +/* How much larger the table is then the total number of chunks. + */ +#define BCHUNK_HASH_TABLE_MUL 3 + +/* Merge too small/large chunks: + * + * Using this means chunks below a threshold will be merged together. + * Even though short term this uses more memory, + * long term the overhead of maintaining many small chunks is reduced. + * This is defined by setting the minimum chunk size (as a fraction of the regular chunk size). + * + * Chunks may also become too large (when incrementally growing an array), + * this also enables chunk splitting. + */ +#define USE_MERGE_CHUNKS + +#ifdef USE_MERGE_CHUNKS +/* Merge chunks smaller then: (chunk_size / BCHUNK_MIN_SIZE_DIV) + */ +# define BCHUNK_SIZE_MIN_DIV 8 + +/* Disallow chunks bigger then the regular chunk size scaled by this value + * note: must be at least 2! + * however, this code runs wont run in tests unless its ~1.1 ugh. + * so lower only to check splitting works. + */ +# define BCHUNK_SIZE_MAX_MUL 2 +#endif /* USE_MERGE_CHUNKS */ + +/* slow (keep disabled), but handy for debugging */ +// #define USE_VALIDATE_LIST_SIZE + +// #define USE_VALIDATE_LIST_DATA_PARTIAL + +// #define USE_PARANOID_CHECKS + +/** \} */ + + +/** \name Internal Structs + * \{ */ + +typedef unsigned int uint; +typedef unsigned char ubyte; + +typedef uint64_t hash_key; + + +typedef struct BArrayInfo { + size_t chunk_stride; + uint chunk_count; + + /* pre-calculated */ + size_t chunk_byte_size; + size_t chunk_byte_size_min; + + size_t accum_read_ahead_bytes; +#ifdef USE_HASH_TABLE_ACCUMULATE + size_t accum_steps; + size_t accum_read_ahead_len; +#endif +} BArrayInfo; + +typedef struct BArrayMemory { + BLI_mempool *chunk_list; /* BChunkList */ + BLI_mempool *chunk_ref; /* BChunkRef */ + BLI_mempool *chunk; /* BChunk */ +} BArrayMemory; + +/** + * Main storage for all states + */ +typedef struct BArrayStore { + /* static */ + BArrayInfo info; + + /* memory storage */ + BArrayMemory memory; + + /** + * #BArrayState may be in any order (logic should never depend on state order). + */ + ListBase states; +} BArrayStore; + +/** + * A single instance of an array. + * + * This is how external API's hold a reference to an in-memory state, + * although the struct is private. + * + * \note Currently each 'state' is allocated separately. + * While this could be moved to a memory pool, + * it makes it easier to trace invalid usage, so leave as-is for now. + */ +typedef struct BArrayState { + /** linked list in #BArrayStore.states */ + struct BArrayState *next, *prev; + + struct BChunkList *chunk_list; /* BChunkList's */ + +} BArrayState; + +typedef struct BChunkList { + ListBase chunk_refs; /* BChunkRef's */ + uint chunk_refs_len; /* BLI_listbase_count(chunks), store for reuse. */ + size_t total_size; /* size of all chunks */ + + /** number of #BArrayState using this. */ + int users; +} BChunkList; + +/* a chunk of an array */ +typedef struct BChunk { + const ubyte *data; + size_t data_len; + /** number of #BChunkList using this. */ + int users; + +#ifdef USE_HASH_TABLE_KEY_CACHE + hash_key key; +#endif +} BChunk; + +/** + * Links to store #BChunk data in #BChunkList.chunks. + */ +typedef struct BChunkRef { + struct BChunkRef *next, *prev; + BChunk *link; +} BChunkRef; + +/** + * Single linked list used when putting chunks into a temporary table, + * used for lookups. + * + * Point to the #BChunkRef, not the #BChunk, + * to allow talking down the chunks in-order until a mis-match is found, + * this avoids having to do so many table lookups. + */ +typedef struct BTableRef { + struct BTableRef *next; + const BChunkRef *cref; +} BTableRef; + +/** \} */ + + +static size_t bchunk_list_size(const BChunkList *chunk_list); + + +/** \name Internal BChunk API + * \{ */ + +static BChunk *bchunk_new( + BArrayMemory *bs_mem, const ubyte *data, const size_t data_len) +{ + BChunk *chunk = BLI_mempool_alloc(bs_mem->chunk); + chunk->data = data; + chunk->data_len = data_len; + chunk->users = 0; +#ifdef USE_HASH_TABLE_KEY_CACHE + chunk->key = HASH_TABLE_KEY_UNSET; +#endif + return chunk; +} + +static BChunk *bchunk_new_copydata( + BArrayMemory *bs_mem, const ubyte *data, const size_t data_len) +{ + ubyte *data_copy = MEM_mallocN(data_len, __func__); + memcpy(data_copy, data, data_len); + return bchunk_new(bs_mem, data_copy, data_len); +} + +static void bchunk_decref( + BArrayMemory *bs_mem, BChunk *chunk) +{ + BLI_assert(chunk->users > 0); + if (chunk->users == 1) { + MEM_freeN((void *)chunk->data); + BLI_mempool_free(bs_mem->chunk, chunk); + } + else { + chunk->users -= 1; + } +} + +static bool bchunk_data_compare( + const BChunk *chunk, + const ubyte *data_base, const size_t data_base_len, + const size_t offset) +{ + if (offset + (size_t)chunk->data_len <= data_base_len) { + return (memcmp(&data_base[offset], chunk->data, chunk->data_len) == 0); + } + else { + return false; + } +} + +/** \} */ + + +/** \name Internal BChunkList API + * \{ */ + +static BChunkList *bchunk_list_new( + BArrayMemory *bs_mem, size_t total_size) +{ + BChunkList *chunk_list = BLI_mempool_alloc(bs_mem->chunk_list); + + BLI_listbase_clear(&chunk_list->chunk_refs); + chunk_list->chunk_refs_len = 0; + chunk_list->total_size = total_size; + chunk_list->users = 0; + return chunk_list; +} + +static void bchunk_list_decref( + BArrayMemory *bs_mem, BChunkList *chunk_list) +{ + BLI_assert(chunk_list->users > 0); + if (chunk_list->users == 1) { + for (BChunkRef *cref = chunk_list->chunk_refs.first, *cref_next; cref; cref = cref_next) { + cref_next = cref->next; + bchunk_decref(bs_mem, cref->link); + BLI_mempool_free(bs_mem->chunk_ref, cref); + } + + BLI_mempool_free(bs_mem->chunk_list, chunk_list); + } + else { + chunk_list->users -= 1; + } +} + +#ifdef USE_VALIDATE_LIST_SIZE +# ifndef NDEBUG +# define ASSERT_CHUNKLIST_SIZE(chunk_list, n) BLI_assert(bchunk_list_size(chunk_list) == n) +# endif +#endif +#ifndef ASSERT_CHUNKLIST_SIZE +# define ASSERT_CHUNKLIST_SIZE(chunk_list, n) (EXPR_NOP(chunk_list), EXPR_NOP(n)) +#endif + + +#ifdef USE_VALIDATE_LIST_DATA_PARTIAL +static size_t bchunk_list_data_check( + const BChunkList *chunk_list, const ubyte *data) +{ + size_t total_size = 0; + for (BChunkRef *cref = chunk_list->chunk_refs.first; cref; cref = cref->next) { + if (memcmp(&data[total_size], cref->link->data, cref->link->data_len) != 0) { + return false; + } + total_size += cref->link->data_len; + } + return true; +} +# define ASSERT_CHUNKLIST_DATA(chunk_list, data) BLI_assert(bchunk_list_data_check(chunk_list, data)) +#else +# define ASSERT_CHUNKLIST_DATA(chunk_list, data) (EXPR_NOP(chunk_list), EXPR_NOP(data)) +#endif + + +#ifdef USE_MERGE_CHUNKS +static void bchunk_list_ensure_min_size_last( + const BArrayInfo *info, BArrayMemory *bs_mem, + BChunkList *chunk_list) +{ + BChunkRef *cref = chunk_list->chunk_refs.last; + if (cref && cref->prev) { + /* both are decref'd after use (end of this block) */ + BChunk *chunk_curr = cref->link; + BChunk *chunk_prev = cref->prev->link; + + if (MIN2(chunk_prev->data_len, chunk_curr->data_len) < info->chunk_byte_size_min) { + const size_t data_merge_len = chunk_prev->data_len + chunk_curr->data_len; + /* we could pass, but no need */ + if (data_merge_len <= (info->chunk_byte_size * BCHUNK_SIZE_MAX_MUL)) { + /* we have enough space to merge */ + + /* remove last from linklist */ + BLI_assert(chunk_list->chunk_refs.last != chunk_list->chunk_refs.first); + cref->prev->next = NULL; + chunk_list->chunk_refs.last = cref->prev; + chunk_list->chunk_refs_len -= 1; + + ubyte *data_merge = MEM_mallocN(data_merge_len, __func__); + memcpy(data_merge, chunk_prev->data, chunk_prev->data_len); + memcpy(&data_merge[chunk_prev->data_len], chunk_curr->data, chunk_curr->data_len); + + cref->prev->link = bchunk_new(bs_mem, data_merge, data_merge_len); + cref->prev->link->users += 1; + + BLI_mempool_free(bs_mem->chunk_ref, cref); + } + else { + /* If we always merge small slices, we should _almost_ never end up having very large chunks. + * Gradual expanding on contracting will cause this. + * + * if we do, the code below works (test by setting 'BCHUNK_SIZE_MAX_MUL = 1.2') */ + + /* keep chunk on the left hand side a regular size */ + const size_t split = info->chunk_byte_size; + + /* merge and split */ + const size_t data_prev_len = split; + const size_t data_curr_len = data_merge_len - split; + ubyte *data_prev = MEM_mallocN(data_prev_len, __func__); + ubyte *data_curr = MEM_mallocN(data_curr_len, __func__); + + if (data_prev_len <= chunk_prev->data_len) { + const size_t data_curr_shrink_len = chunk_prev->data_len - data_prev_len; + + /* setup 'data_prev' */ + memcpy(data_prev, chunk_prev->data, data_prev_len); + + /* setup 'data_curr' */ + memcpy(data_curr, &chunk_prev->data[data_prev_len], data_curr_shrink_len); + memcpy(&data_curr[data_curr_shrink_len], chunk_curr->data, chunk_curr->data_len); + } + else { + BLI_assert(data_curr_len <= chunk_curr->data_len); + BLI_assert(data_prev_len >= chunk_prev->data_len); + + const size_t data_prev_grow_len = data_prev_len - chunk_prev->data_len; + + /* setup 'data_prev' */ + memcpy(data_prev, chunk_prev->data, chunk_prev->data_len); + memcpy(&data_prev[chunk_prev->data_len], chunk_curr->data, data_prev_grow_len); + + /* setup 'data_curr' */ + memcpy(data_curr, &chunk_curr->data[data_prev_grow_len], data_curr_len); + } + + cref->prev->link = bchunk_new(bs_mem, data_prev, data_prev_len); + cref->prev->link->users += 1; + + cref->link = bchunk_new(bs_mem, data_curr, data_curr_len); + cref->link->users += 1; + } + + /* free zero users */ + bchunk_decref(bs_mem, chunk_curr); + bchunk_decref(bs_mem, chunk_prev); + } + } +} +#endif /* USE_MERGE_CHUNKS */ + +/** + * Append and don't manage merging small chunks. + */ +static bool bchunk_list_append_only( + BArrayMemory *bs_mem, + BChunkList *chunk_list, BChunk *chunk) +{ + BChunkRef *cref = BLI_mempool_alloc(bs_mem->chunk_ref); + BLI_addtail(&chunk_list->chunk_refs, cref); + cref->link = chunk; + chunk_list->chunk_refs_len += 1; + chunk->users += 1; + return chunk; +} + +static void bchunk_list_append_data( + const BArrayInfo *info, BArrayMemory *bs_mem, + BChunkList *chunk_list, + const ubyte *data, const size_t data_len) +{ + BLI_assert(data_len != 0); + // printf("data_len: %d\n", data_len); +#ifdef USE_MERGE_CHUNKS + if (!BLI_listbase_is_empty(&chunk_list->chunk_refs)) { + BChunkRef *cref = chunk_list->chunk_refs.last; + BChunk *chunk_prev = cref->link; + + if (MIN2(chunk_prev->data_len, data_len) < info->chunk_byte_size_min) { + const size_t data_merge_len = chunk_prev->data_len + data_len; + /* realloc for single user */ + if (cref->link->users == 1) { + ubyte *data_merge = MEM_reallocN((void *)cref->link->data, data_merge_len); + memcpy(&data_merge[chunk_prev->data_len], data, data_len); + cref->link->data = data_merge; + cref->link->data_len = data_merge_len; + } + else { + ubyte *data_merge = MEM_mallocN(data_merge_len, __func__); + memcpy(data_merge, chunk_prev->data, chunk_prev->data_len); + memcpy(&data_merge[chunk_prev->data_len], data, data_len); + cref->link = bchunk_new(bs_mem, data_merge, data_merge_len); + cref->link->users += 1; + bchunk_decref(bs_mem, chunk_prev); + } + return; + } + } +#else + UNUSED_VARS(info); +#endif /* USE_MERGE_CHUNKS */ + + BChunk *chunk = bchunk_new_copydata(bs_mem, data, data_len); + bchunk_list_append_only(bs_mem, chunk_list, chunk); + + /* don't run this, instead preemptively avoid creating a chunk only to merge it (above). */ +#if 0 +#ifdef USE_MERGE_CHUNKS + bchunk_list_ensure_min_size_last(info, bs_mem, chunk_list, chunk_size_min); +#endif +#endif +} + +static void bchunk_list_append( + const BArrayInfo *info, BArrayMemory *bs_mem, + BChunkList *chunk_list, + BChunk *chunk) +{ + bchunk_list_append_only(bs_mem, chunk_list, chunk); + +#ifdef USE_MERGE_CHUNKS + bchunk_list_ensure_min_size_last(info, bs_mem, chunk_list); +#else + UNUSED_VARS(info); +#endif +} + +static void bchunk_list_fill_from_array( + const BArrayInfo *info, BArrayMemory *bs_mem, + BChunkList *chunk_list, + const ubyte *data, + const size_t data_len) +{ + BLI_assert(BLI_listbase_is_empty(&chunk_list->chunk_refs)); + + size_t data_last_chunk_len = 0; + size_t data_trim_len = data_len; + +#ifdef USE_MERGE_CHUNKS + /* avoid creating too-small chunks + * more efficient then merging after */ + if (data_len > info->chunk_byte_size) { + data_last_chunk_len = (data_trim_len % info->chunk_byte_size); + data_trim_len = data_trim_len - data_last_chunk_len; + if (data_last_chunk_len) { + if (data_last_chunk_len < info->chunk_byte_size_min) { + /* may be zero and thats OK */ + data_trim_len -= info->chunk_byte_size; + data_last_chunk_len += info->chunk_byte_size; + } + } + } + else { + data_trim_len = 0; + data_last_chunk_len = data_len; + } +#else + data_last_chunk_len = (data_trim_len % info->chunk_byte_size); + data_trim_len = data_trim_len - data_last_chunk_len; +#endif + + + BLI_assert(data_trim_len + data_last_chunk_len == data_len); + + size_t i_prev = 0; + while (i_prev < data_trim_len) { + const size_t i = i_prev + info->chunk_byte_size; + BChunk *chunk = bchunk_new_copydata(bs_mem, &data[i_prev], i - i_prev); + bchunk_list_append_only(bs_mem, chunk_list, chunk); + i_prev = i; + } + + if (data_last_chunk_len) { + BChunk *chunk = bchunk_new_copydata(bs_mem, &data[i_prev], data_last_chunk_len); + bchunk_list_append_only(bs_mem, chunk_list, chunk); + // i_prev = data_len; + } + +#ifdef USE_MERGE_CHUNKS + if (data_len > info->chunk_byte_size) { + BLI_assert(((BChunkRef *)chunk_list->chunk_refs.last)->link->data_len >= info->chunk_byte_size_min); + } +#endif + + /* works but better avoid redundant re-alloc */ +#if 0 +#ifdef USE_MERGE_CHUNKS + bchunk_list_ensure_min_size_last(info, bs_mem, chunk_list); +#endif +#endif + + ASSERT_CHUNKLIST_SIZE(chunk_list, data_len); + ASSERT_CHUNKLIST_DATA(chunk_list, data); +} + + +/* --------------------------------------------------------------------------- + * Internal Table Lookup Functions + */ + +/** \name Internal Hashing/De-Duplication API + * + * Only used by #bchunk_list_from_data_merge + * \{ */ + +#define HASH_INIT (5381) + +BLI_INLINE uint hash_data_single(const ubyte p) +{ + return (HASH_INIT << 5) + HASH_INIT + (unsigned int)p; +} + +/* hash bytes, from BLI_ghashutil_strhash_n */ +static uint hash_data(const ubyte *key, size_t n) +{ + const signed char *p; + unsigned int h = HASH_INIT; + + for (p = (const signed char *)key; n--; p++) { + h = (h << 5) + h + (unsigned int)*p; + } + + return h; +} + +#undef HASH_INIT + + +#ifdef USE_HASH_TABLE_ACCUMULATE +static void hash_array_from_data( + const BArrayInfo *info, const ubyte *data_slice, const size_t data_slice_len, + hash_key *hash_array) +{ + if (info->chunk_stride != 1) { + for (size_t i = 0, i_step = 0; i_step < data_slice_len; i++, i_step += info->chunk_stride) { + hash_array[i] = hash_data(&data_slice[i_step], info->chunk_stride); + } + } + else { + /* fast-path for bytes */ + for (size_t i = 0; i < data_slice_len; i++) { + hash_array[i] = hash_data_single(data_slice[i]); + } + } +} + +/* + * Similar to hash_array_from_data, + * but able to step into the next chunk if we run-out of data. + */ +static void hash_array_from_cref( + const BArrayInfo *info, const BChunkRef *cref, const size_t data_len, + hash_key *hash_array) +{ + const size_t hash_array_len = data_len / info->chunk_stride; + size_t i = 0; + do { + size_t i_next = hash_array_len - i; + size_t data_trim_len = i_next * info->chunk_stride; + if (data_trim_len > cref->link->data_len) { + data_trim_len = cref->link->data_len; + i_next = data_trim_len / info->chunk_stride; + } + BLI_assert(data_trim_len <= cref->link->data_len); + hash_array_from_data(info, cref->link->data, data_trim_len, &hash_array[i]); + i += i_next; + cref = cref->next; + } while ((i < hash_array_len) && (cref != NULL)); + + /* If this isn't equal, the caller didn't properly check + * that there was enough data left in all chunks */ + BLI_assert(i == hash_array_len); +} + +static void hash_accum(hash_key *hash_array, const size_t hash_array_len, size_t iter_steps) +{ + /* _very_ unlikely, can happen if you select a chunk-size of 1 for example. */ + if (UNLIKELY((iter_steps > hash_array_len))) { + iter_steps = hash_array_len; + } + + const size_t hash_array_search_len = hash_array_len - iter_steps; + while (iter_steps != 0) { + const size_t hash_offset = iter_steps; + for (uint i = 0; i < hash_array_search_len; i++) { + hash_array[i] += (hash_array[i + hash_offset]) * ((hash_array[i] & 0xff) + 1); + } + iter_steps -= 1; + } +} + +/** + * When we only need a single value, can use a small optimization. + * we can avoid accumulating the tail of the array a little, each iteration. + */ +static void hash_accum_single(hash_key *hash_array, const size_t hash_array_len, size_t iter_steps) +{ + BLI_assert(iter_steps <= hash_array_len); + if (UNLIKELY(!(iter_steps <= hash_array_len))) { + /* while this shouldn't happen, avoid crashing */ + iter_steps = hash_array_len; + } + /* We can increase this value each step to avoid accumulating quite as much + * while getting the same results as hash_accum */ + size_t iter_steps_sub = iter_steps; + + while (iter_steps != 0) { + const size_t hash_array_search_len = hash_array_len - iter_steps_sub; + const size_t hash_offset = iter_steps; + for (uint i = 0; i < hash_array_search_len; i++) { + hash_array[i] += (hash_array[i + hash_offset]) * ((hash_array[i] & 0xff) + 1); + } + iter_steps -= 1; + iter_steps_sub += iter_steps; + } +} + +static hash_key key_from_chunk_ref( + const BArrayInfo *info, const BChunkRef *cref, + /* avoid reallicating each time */ + hash_key *hash_store, const size_t hash_store_len) +{ + /* in C, will fill in a reusable array */ + BChunk *chunk = cref->link; + BLI_assert(info->accum_read_ahead_bytes * info->chunk_stride); + + if (info->accum_read_ahead_bytes <= chunk->data_len) { + hash_key key; + +#ifdef USE_HASH_TABLE_KEY_CACHE + key = chunk->key; + if (key != HASH_TABLE_KEY_UNSET) { + /* Using key cache! + * avoids calculating every time */ + } + else { + hash_array_from_cref(info, cref, info->accum_read_ahead_bytes, hash_store); + hash_accum_single(hash_store, hash_store_len, info->accum_steps); + key = hash_store[0]; + + /* cache the key */ + if (key == HASH_TABLE_KEY_UNSET) { + key = HASH_TABLE_KEY_FALLBACK; + } + chunk->key = key; + } +#else + hash_array_from_cref(info, cref, info->accum_read_ahead_bytes, hash_store); + hash_accum_single(hash_store, hash_store_len, info->accum_steps); + key = hash_store[0]; +#endif + return key; + } + else { + /* corner case - we're too small, calculate the key each time. */ + + hash_array_from_cref(info, cref, info->accum_read_ahead_bytes, hash_store); + hash_accum_single(hash_store, hash_store_len, info->accum_steps); + hash_key key = hash_store[0]; + +#ifdef USE_HASH_TABLE_KEY_CACHE + if (UNLIKELY(key == HASH_TABLE_KEY_UNSET)) { + key = HASH_TABLE_KEY_FALLBACK; + } +#endif + return key; + } +} + +static const BChunkRef *table_lookup( + const BArrayInfo *info, BTableRef **table, const size_t table_len, const size_t i_table_start, + const ubyte *data, const size_t data_len, const size_t offset, const hash_key *table_hash_array) +{ + size_t size_left = data_len - offset; + hash_key key = table_hash_array[((offset - i_table_start) / info->chunk_stride)]; + size_t key_index = (size_t)(key % (hash_key)table_len); + for (BTableRef *tref = table[key_index]; tref; tref = tref->next) { + const BChunkRef *cref = tref->cref; +#ifdef USE_HASH_TABLE_KEY_CACHE + if (cref->link->key == key) +#endif + { + BChunk *chunk_test = cref->link; + if (chunk_test->data_len <= size_left) { + if (bchunk_data_compare(chunk_test, data, data_len, offset)) { + /* we could remove the chunk from the table, to avoid multiple hits */ + return cref; + } + } + } + } + return NULL; +} + +#else /* USE_HASH_TABLE_ACCUMULATE */ + +/* NON USE_HASH_TABLE_ACCUMULATE code (simply hash each chunk) */ + +static hash_key key_from_chunk_ref(const BArrayInfo *info, const BChunkRef *cref) +{ + const size_t data_hash_len = BCHUNK_HASH_LEN * info->chunk_stride; + hash_key key; + BChunk *chunk = cref->link; + +#ifdef USE_HASH_TABLE_KEY_CACHE + key = chunk->key; + if (key != HASH_TABLE_KEY_UNSET) { + /* Using key cache! + * avoids calculating every time */ + } + else { + /* cache the key */ + key = hash_data(chunk->data, data_hash_len); + if (key == HASH_TABLE_KEY_UNSET) { + key = HASH_TABLE_KEY_FALLBACK; + } + chunk->key = key; + } +#else + key = hash_data(chunk->data, data_hash_len); +#endif + + return key; +} + +static const BChunkRef *table_lookup( + const BArrayInfo *info, BTableRef **table, const size_t table_len, const uint UNUSED(i_table_start), + const ubyte *data, const size_t data_len, const size_t offset, const hash_key *UNUSED(table_hash_array)) +{ + const size_t data_hash_len = BCHUNK_HASH_LEN * info->chunk_stride; /* TODO, cache */ + + size_t size_left = data_len - offset; + hash_key key = hash_data(&data[offset], MIN2(data_hash_len, size_left)); + size_t key_index = (size_t)(key % (hash_key)table_len); + for (BTableRef *tref = table[key_index]; tref; tref = tref->next) { + const BChunkRef *cref = tref->cref; +#ifdef USE_HASH_TABLE_KEY_CACHE + if (cref->link->key == key) +#endif + { + BChunk *chunk_test = cref->link; + if (chunk_test->data_len <= size_left) { + if (bchunk_data_compare(chunk_test, data, data_len, offset)) { + /* we could remove the chunk from the table, to avoid multiple hits */ + return cref; + } + } + } + } + return NULL; +} + +#endif /* USE_HASH_TABLE_ACCUMULATE */ + +/* End Table Lookup + * ---------------- */ + +/** \} */ + +/** + * \param data: Data to store in the returned value. + * \param data_len_original: Length of data in bytes. + * \param chunk_list_reference: Reuse this list or chunks within it, don't modify its content. + * \note Caller is responsible for adding the user. + */ +static BChunkList *bchunk_list_from_data_merge( + const BArrayInfo *info, BArrayMemory *bs_mem, + const ubyte *data, const size_t data_len_original, + const BChunkList *chunk_list_reference) +{ + ASSERT_CHUNKLIST_SIZE(chunk_list_reference, chunk_list_reference->total_size); + + /* ----------------------------------------------------------------------- + * Fast-Path for exact match + * Check for exact match, if so, return the current list. + */ + + const BChunkRef *cref_match_first = NULL; + + uint chunk_list_reference_skip_len = 0; + size_t chunk_list_reference_skip_bytes = 0; + size_t i_prev = 0; + +#ifdef USE_FASTPATH_CHUNKS_FIRST + bool full_match = false; + + { + full_match = true; + + const BChunkRef *cref = chunk_list_reference->chunk_refs.first; + while (i_prev < data_len_original) { + if (cref != NULL && bchunk_data_compare(cref->link, data, data_len_original, i_prev)) { + cref_match_first = cref; + chunk_list_reference_skip_len += 1; + chunk_list_reference_skip_bytes += cref->link->data_len; + i_prev += cref->link->data_len; + cref = cref->next; + } + else { + full_match = false; + break; + } + } + + if (full_match) { + if (chunk_list_reference->total_size == data_len_original) { + return (BChunkList *)chunk_list_reference; + } + } + } + + /* End Fast-Path (first) + * --------------------- */ + +#endif /* USE_FASTPATH_CHUNKS_FIRST */ + + /* Copy until we have a mismatch */ + BChunkList *chunk_list = bchunk_list_new(bs_mem, data_len_original); + if (cref_match_first != NULL) { + size_t chunk_size_step = 0; + const BChunkRef *cref = chunk_list_reference->chunk_refs.first; + while (true) { + BChunk *chunk = cref->link; + chunk_size_step += chunk->data_len; + bchunk_list_append_only(bs_mem, chunk_list, chunk); + ASSERT_CHUNKLIST_SIZE(chunk_list, chunk_size_step); + ASSERT_CHUNKLIST_DATA(chunk_list, data); + if (cref == cref_match_first) { + break; + } + else { + cref = cref->next; + } + } + /* happens when bytes are removed from the end of the array */ + if (chunk_size_step == data_len_original) { + return chunk_list; + } + + i_prev = chunk_size_step; + } + else { + i_prev = 0; + } + + /* ------------------------------------------------------------------------ + * Fast-Path for end chunks + * + * Check for trailing chunks + */ + + /* In this case use 'chunk_list_reference_last' to define the last index + * index_match_last = -1 */ + + /* warning, from now on don't use len(data) + * since we want to ignore chunks already matched */ + size_t data_len = data_len_original; +#define data_len_original invalid_usage +#ifdef data_len_original /* quiet warning */ +#endif + + const BChunkRef *chunk_list_reference_last = NULL; + +#ifdef USE_FASTPATH_CHUNKS_LAST + if (!BLI_listbase_is_empty(&chunk_list_reference->chunk_refs)) { + const BChunkRef *cref = chunk_list_reference->chunk_refs.last; + while ((cref->prev != NULL) && + (cref != cref_match_first) && + (cref->link->data_len <= data_len - i_prev)) + { + BChunk *chunk_test = cref->link; + size_t offset = data_len - chunk_test->data_len; + if (bchunk_data_compare(chunk_test, data, data_len, offset)) { + data_len = offset; + chunk_list_reference_last = cref; + chunk_list_reference_skip_len += 1; + chunk_list_reference_skip_bytes += cref->link->data_len; + cref = cref->prev; + } + else { + break; + } + } + } + + /* End Fast-Path (last) + * -------------------- */ +#endif /* USE_FASTPATH_CHUNKS_LAST */ + + /* ----------------------------------------------------------------------- + * Check for aligned chunks + * + * This saves a lot of searching, so use simple heuristics to detect aligned arrays. + * (may need to tweak exact method). + */ + + bool use_aligned = false; + +#ifdef USE_ALIGN_CHUNKS_TEST + if (chunk_list->total_size == chunk_list_reference->total_size) { + /* if we're already a quarter aligned */ + if (data_len - i_prev <= chunk_list->total_size / 4) { + use_aligned = true; + } + else { + /* TODO, walk over chunks and check if some arbitrary amount align */ + } + } +#endif /* USE_ALIGN_CHUNKS_TEST */ + + /* End Aligned Chunk Case + * ----------------------- */ + + if (use_aligned) { + /* Copy matching chunks, creates using the same 'layout' as the reference */ + const BChunkRef *cref = cref_match_first ? cref_match_first->next : chunk_list_reference->chunk_refs.first; + while (i_prev != data_len) { + const size_t i = i_prev + cref->link->data_len; + BLI_assert(i != i_prev); + + if ((cref != chunk_list_reference_last) && + bchunk_data_compare(cref->link, data, data_len, i_prev)) + { + bchunk_list_append(info, bs_mem, chunk_list, cref->link); + ASSERT_CHUNKLIST_SIZE(chunk_list, i); + ASSERT_CHUNKLIST_DATA(chunk_list, data); + } + else { + bchunk_list_append_data(info, bs_mem, chunk_list, &data[i_prev], i - i_prev); + ASSERT_CHUNKLIST_SIZE(chunk_list, i); + ASSERT_CHUNKLIST_DATA(chunk_list, data); + } + + cref = cref->next; + + i_prev = i; + } + } + else if ((data_len - i_prev >= info->chunk_byte_size) && + (chunk_list_reference->chunk_refs_len >= chunk_list_reference_skip_len) && + (chunk_list_reference->chunk_refs.first != NULL)) + { + + /* -------------------------------------------------------------------- + * Non-Aligned Chunk De-Duplication */ + + /* only create a table if we have at least one chunk to search + * otherwise just make a new one. + * + * Support re-arranged chunks */ + +#ifdef USE_HASH_TABLE_ACCUMULATE + size_t i_table_start = i_prev; + const size_t table_hash_array_len = (data_len - i_prev) / info->chunk_stride; + hash_key *table_hash_array = MEM_mallocN(sizeof(*table_hash_array) * table_hash_array_len, __func__); + hash_array_from_data(info, &data[i_prev], data_len - i_prev, table_hash_array); + + hash_accum(table_hash_array, table_hash_array_len, info->accum_steps); +#else + /* dummy vars */ + uint i_table_start = 0; + hash_key *table_hash_array = NULL; +#endif + + const uint chunk_list_reference_remaining_len = + (chunk_list_reference->chunk_refs_len - chunk_list_reference_skip_len) + 1; + BTableRef *table_ref_stack = MEM_mallocN(chunk_list_reference_remaining_len * sizeof(BTableRef), __func__); + uint table_ref_stack_n = 0; + + const size_t table_len = chunk_list_reference_remaining_len * BCHUNK_HASH_TABLE_MUL; + BTableRef **table = MEM_callocN(table_len * sizeof(*table), __func__); + + /* table_make - inline + * include one matching chunk, to allow for repeating values */ + { +#ifdef USE_HASH_TABLE_ACCUMULATE + const size_t hash_store_len = info->accum_read_ahead_len; + hash_key *hash_store = MEM_mallocN(sizeof(hash_key) * hash_store_len, __func__); +#endif + + const BChunkRef *cref; + size_t chunk_list_reference_bytes_remaining = + chunk_list_reference->total_size - chunk_list_reference_skip_bytes; + + if (cref_match_first) { + cref = cref_match_first; + chunk_list_reference_bytes_remaining += cref->link->data_len; + } + else { + cref = chunk_list_reference->chunk_refs.first; + } + +#ifdef USE_PARANOID_CHECKS + { + size_t test_bytes_len = 0; + const BChunkRef *cr = cref; + while (cr != chunk_list_reference_last) { + test_bytes_len += cr->link->data_len; + cr = cr->next; + } + BLI_assert(test_bytes_len == chunk_list_reference_bytes_remaining); + } +#endif + + while ((cref != chunk_list_reference_last) && + (chunk_list_reference_bytes_remaining >= info->accum_read_ahead_bytes)) + { + hash_key key = key_from_chunk_ref(info, cref + +#ifdef USE_HASH_TABLE_ACCUMULATE + , hash_store, hash_store_len +#endif + ); + size_t key_index = (size_t)(key % (hash_key)table_len); + BTableRef *tref_prev = table[key_index]; + BLI_assert(table_ref_stack_n < chunk_list_reference_remaining_len); + BTableRef *tref = &table_ref_stack[table_ref_stack_n++]; + tref->cref = cref; + tref->next = tref_prev; + table[key_index] = tref; + + chunk_list_reference_bytes_remaining -= cref->link->data_len; + cref = cref->next; + } + + BLI_assert(table_ref_stack_n <= chunk_list_reference_remaining_len); + +#ifdef USE_HASH_TABLE_ACCUMULATE + MEM_freeN(hash_store); +#endif + } + /* done making the table */ + + BLI_assert(i_prev <= data_len); + for (size_t i = i_prev; i < data_len; ) { + /* Assumes exiting chunk isnt a match! */ + + const BChunkRef *cref_found = table_lookup( + info, + table, table_len, i_table_start, + data, data_len, i, table_hash_array); + if (cref_found != NULL) { + BLI_assert(i < data_len); + if (i != i_prev) { + size_t i_step = MIN2(i_prev + info->chunk_byte_size, data_len); + BLI_assert(i_step <= data_len); + + while (i_prev != i) { + i_step = MIN2(i_step, i); + const ubyte *data_slice = &data[i_prev]; + const size_t data_slice_len = i_step - i_prev; + /* First add all previous chunks! */ + i_prev += data_slice_len; + bchunk_list_append_data(info, bs_mem, chunk_list, data_slice, data_slice_len); + BLI_assert(i_prev <= data_len); + ASSERT_CHUNKLIST_SIZE(chunk_list, i_prev); + ASSERT_CHUNKLIST_DATA(chunk_list, data); + i_step += info->chunk_byte_size; + } + } + + /* now add the reference chunk */ + { + BChunk *chunk_found = cref_found->link; + i += chunk_found->data_len; + bchunk_list_append(info, bs_mem, chunk_list, chunk_found); + } + i_prev = i; + BLI_assert(i_prev <= data_len); + ASSERT_CHUNKLIST_SIZE(chunk_list, i_prev); + ASSERT_CHUNKLIST_DATA(chunk_list, data); + + /* its likely that the next chunk in the list will be a match, so check it! */ + while ((cref_found->next != NULL) && + (cref_found->next != chunk_list_reference_last)) + { + cref_found = cref_found->next; + BChunk *chunk_found = cref_found->link; + + if (bchunk_data_compare(chunk_found, data, data_len, i_prev)) { + /* may be useful to remove table data, assuming we dont have repeating memory + * where it would be useful to re-use chunks. */ + i += chunk_found->data_len; + bchunk_list_append(info, bs_mem, chunk_list, chunk_found); + /* chunk_found may be freed! */ + i_prev = i; + BLI_assert(i_prev <= data_len); + ASSERT_CHUNKLIST_SIZE(chunk_list, i_prev); + ASSERT_CHUNKLIST_DATA(chunk_list, data); + } + else { + break; + } + } + } + else { + i = i + info->chunk_stride; + } + } + +#ifdef USE_HASH_TABLE_ACCUMULATE + MEM_freeN(table_hash_array); +#endif + MEM_freeN(table); + MEM_freeN(table_ref_stack); + + /* End Table Lookup + * ---------------- */ + } + + ASSERT_CHUNKLIST_SIZE(chunk_list, i_prev); + ASSERT_CHUNKLIST_DATA(chunk_list, data); + + /* ----------------------------------------------------------------------- + * No Duplicates to copy, write new chunks + * + * Trailing chunks, no matches found in table lookup above. + * Write all new data. */ + BLI_assert(i_prev <= data_len); + while (i_prev != data_len) { + size_t i = i_prev + info->chunk_byte_size; + i = MIN2(i, data_len); + BLI_assert(i != i_prev); + bchunk_list_append_data(info, bs_mem, chunk_list, &data[i_prev], i - i_prev); + ASSERT_CHUNKLIST_DATA(chunk_list, data); + i_prev = i; + } + + BLI_assert(i_prev == data_len); + +#ifdef USE_FASTPATH_CHUNKS_LAST + if (chunk_list_reference_last != NULL) { + /* write chunk_list_reference_last since it hasn't been written yet */ + const BChunkRef *cref = chunk_list_reference_last; + while (cref != NULL) { + BChunk *chunk = cref->link; + // BLI_assert(bchunk_data_compare(chunk, data, data_len, i_prev)); + i_prev += chunk->data_len; + /* use simple since we assume the references chunks have already been sized correctly. */ + bchunk_list_append_only(bs_mem, chunk_list, chunk); + ASSERT_CHUNKLIST_DATA(chunk_list, data); + cref = cref->next; + } + } +#endif + +#undef data_len_original + + BLI_assert(i_prev == data_len_original); + + /* check we're the correct size and that we didn't accidentally modify the reference */ + ASSERT_CHUNKLIST_SIZE(chunk_list, data_len_original); + ASSERT_CHUNKLIST_SIZE(chunk_list_reference, chunk_list_reference->total_size); + + ASSERT_CHUNKLIST_DATA(chunk_list, data); + + return chunk_list; +} +/* end private API */ + +/** \} */ + + +/** \name Main Array Storage API + * \{ */ + + +/** + * Create a new array store, which can store any number of arrays + * as long as their stride matches. + * + * \param stride: ``sizeof()`` each element, + * + * \note while a stride of ``1`` will always work, + * its less efficient since duplicate chunks of memory will be searched + * at positions unaligned with the array data. + * + * \param chunk_count: Number of elements to split each chunk into. + * - A small value increases the ability to de-duplicate chunks, + * but adds overhead by increasing the number of chunks to look-up when searching for duplicates, + * as well as some overhead constructing the original array again, with more calls to ``memcpy``. + * - Larger values reduce the *book keeping* overhead, + * but increase the chance a small, isolated change will cause a larger amount of data to be duplicated. + * + * \return A new array store, to be freed with #BLI_array_store_destroy. + */ +BArrayStore *BLI_array_store_create( + uint stride, + uint chunk_count) +{ + BArrayStore *bs = MEM_callocN(sizeof(BArrayStore), __func__); + + bs->info.chunk_stride = stride; + bs->info.chunk_count = chunk_count; + + bs->info.chunk_byte_size = chunk_count * stride; +#ifdef USE_MERGE_CHUNKS + bs->info.chunk_byte_size_min = MAX2(1u, chunk_count / BCHUNK_SIZE_MIN_DIV) * stride; +#endif + +#ifdef USE_HASH_TABLE_ACCUMULATE + bs->info.accum_steps = BCHUNK_HASH_TABLE_ACCUMULATE_STEPS - 1; + /* Triangle number, identifying now much read-ahead we need: + * https://en.wikipedia.org/wiki/Triangular_number (+ 1) */ + bs->info.accum_read_ahead_len = (uint)((((bs->info.accum_steps * (bs->info.accum_steps + 1))) / 2) + 1); + bs->info.accum_read_ahead_bytes = bs->info.accum_read_ahead_len * stride; +#else + bs->info.accum_read_ahead_bytes = BCHUNK_HASH_LEN * stride; +#endif + + bs->memory.chunk_list = BLI_mempool_create(sizeof(BChunkList), 0, 512, BLI_MEMPOOL_NOP); + bs->memory.chunk_ref = BLI_mempool_create(sizeof(BChunkRef), 0, 512, BLI_MEMPOOL_NOP); + /* allow iteration to simplify freeing, otherwise its not needed + * (we could loop over all states as an alternative). */ + bs->memory.chunk = BLI_mempool_create(sizeof(BChunk), 0, 512, BLI_MEMPOOL_ALLOW_ITER); + + return bs; +} + +static void array_store_free_data(BArrayStore *bs) +{ + /* free chunk data */ + { + BLI_mempool_iter iter; + BChunk *chunk; + BLI_mempool_iternew(bs->memory.chunk, &iter); + while ((chunk = BLI_mempool_iterstep(&iter))) { + BLI_assert(chunk->users > 0); + MEM_freeN((void *)chunk->data); + } + } + + /* free states */ + for (BArrayState *state = bs->states.first, *state_next; state; state = state_next) { + state_next = state->next; + MEM_freeN(state); + } +} + +/** + * Free the #BArrayStore, including all states and chunks. + */ +void BLI_array_store_destroy( + BArrayStore *bs) +{ + array_store_free_data(bs); + + BLI_mempool_destroy(bs->memory.chunk_list); + BLI_mempool_destroy(bs->memory.chunk_ref); + BLI_mempool_destroy(bs->memory.chunk); + + MEM_freeN(bs); +} + +/** + * Clear all contents, allowing reuse of \a bs. + */ +void BLI_array_store_clear( + BArrayStore *bs) +{ + array_store_free_data(bs); + + BLI_listbase_clear(&bs->states); + + BLI_mempool_clear(bs->memory.chunk_list); + BLI_mempool_clear(bs->memory.chunk_ref); + BLI_mempool_clear(bs->memory.chunk); +} + +/** \name BArrayStore Statistics + * \{ */ + +/** + * \return the total amount of memory that would be used by getting the arrays for all states. + */ +size_t BLI_array_store_calc_size_expanded_get( + const BArrayStore *bs) +{ + size_t size_accum = 0; + for (const BArrayState *state = bs->states.first; state; state = state->next) { + size_accum += state->chunk_list->total_size; + } + return size_accum; +} + +/** + * \return the amount of memory used by all #BChunk.data + * (duplicate chunks are only counted once). + */ +size_t BLI_array_store_calc_size_compacted_get( + const BArrayStore *bs) +{ + size_t size_total = 0; + BLI_mempool_iter iter; + BChunk *chunk; + BLI_mempool_iternew(bs->memory.chunk, &iter); + while ((chunk = BLI_mempool_iterstep(&iter))) { + BLI_assert(chunk->users > 0); + size_total += (size_t)chunk->data_len; + } + return size_total; +} + +/** \} */ + + +/** \name BArrayState Access + * \{ */ + +/** + * + * \param data: Data used to create + * \param state_reference: The state to use as a reference when adding the new state, + * typically this is the previous state, + * however it can be any previously created state from this \a bs. + * + * \return The new state, which is used by the caller as a handle to get back the contents of \a data. + * This may be removed using #BLI_array_store_state_remove, + * otherwise it will be removed with #BLI_array_store_destroy. + */ +BArrayState *BLI_array_store_state_add( + BArrayStore *bs, + const void *data, const size_t data_len, + const BArrayState *state_reference) +{ + /* ensure we're aligned to the stride */ + BLI_assert((data_len % bs->info.chunk_stride) == 0); + +#ifdef USE_PARANOID_CHECKS + if (state_reference) { + BLI_assert(BLI_findindex(&bs->states, state_reference) != -1); + } +#endif + + BChunkList *chunk_list; + if (state_reference) { + chunk_list = bchunk_list_from_data_merge( + &bs->info, &bs->memory, + (const ubyte *)data, data_len, + /* re-use reference chunks */ + state_reference->chunk_list); + } + else { + chunk_list = bchunk_list_new(&bs->memory, data_len); + bchunk_list_fill_from_array( + &bs->info, &bs->memory, + chunk_list, + (const ubyte *)data, data_len); + } + + chunk_list->users += 1; + + BArrayState *state = MEM_callocN(sizeof(BArrayState), __func__); + state->chunk_list = chunk_list; + + BLI_addtail(&bs->states, state); + +#ifdef USE_PARANOID_CHECKS + { + size_t data_test_len; + void *data_test = BLI_array_store_state_data_get_alloc(state, &data_test_len); + BLI_assert(data_test_len == data_len); + BLI_assert(memcmp(data_test, data, data_len) == 0); + MEM_freeN(data_test); + } +#endif + + return state; +} + +/** + * Remove a state and free any unused #BChunk data. + * + * The states can be freed in any order. + */ +void BLI_array_store_state_remove( + BArrayStore *bs, + BArrayState *state) +{ +#ifdef USE_PARANOID_CHECKS + BLI_assert(BLI_findindex(&bs->states, state) != -1); +#endif + + bchunk_list_decref(&bs->memory, state->chunk_list); + BLI_remlink(&bs->states, state); + + MEM_freeN(state); +} + +/** + * \return the expanded size of the array, + * use this to know how much memory to allocate #BLI_array_store_state_data_get's argument. + */ +size_t BLI_array_store_state_size_get( + BArrayState *state) +{ + return state->chunk_list->total_size; +} + +/** + * Fill in existing allocated memory with the contents of \a state. + */ +void BLI_array_store_state_data_get( + BArrayState *state, + void *data) +{ +#ifdef USE_PARANOID_CHECKS + size_t data_test_len = 0; + for (BChunkRef *cref = state->chunk_list->chunk_refs.first; cref; cref = cref->next) { + data_test_len += cref->link->data_len; + } + BLI_assert(data_test_len == state->chunk_list->total_size); +#endif + + ubyte *data_step = (ubyte *)data; + for (BChunkRef *cref = state->chunk_list->chunk_refs.first; cref; cref = cref->next) { + BLI_assert(cref->link->users > 0); + memcpy(data_step, cref->link->data, cref->link->data_len); + data_step += cref->link->data_len; + } +} + +/** + * Allocate an array for \a state and return it. + */ +void *BLI_array_store_state_data_get_alloc( + BArrayState *state, + size_t *r_data_len) +{ + void *data = MEM_mallocN(state->chunk_list->total_size, __func__); + BLI_array_store_state_data_get(state, data); + *r_data_len = state->chunk_list->total_size; + return data; +} + +/** \} */ + + +/** \name Debigging API (for testing). + * \{ */ + +/* only for test validation */ +static size_t bchunk_list_size(const BChunkList *chunk_list) +{ + size_t total_size = 0; + for (BChunkRef *cref = chunk_list->chunk_refs.first; cref; cref = cref->next) { + total_size += cref->link->data_len; + } + return total_size; +} + +bool BLI_array_store_is_valid( + BArrayStore *bs) +{ + bool ok = true; + + /* Check Length + * ------------ */ + + for (BArrayState *state = bs->states.first; state; state = state->next) { + BChunkList *chunk_list = state->chunk_list; + if (!(bchunk_list_size(chunk_list) == chunk_list->total_size)) { + return false; + } + } + + { + BLI_mempool_iter iter; + BChunk *chunk; + BLI_mempool_iternew(bs->memory.chunk, &iter); + while ((chunk = BLI_mempool_iterstep(&iter))) { + if (!(MEM_allocN_len(chunk->data) >= chunk->data_len)) { + return false; + } + } + } + + /* Check User Count & Lost References + * ---------------------------------- */ + { + GHashIterator gh_iter; + +#define GHASH_PTR_ADD_USER(gh, pt) \ + { \ + void **val; \ + if (BLI_ghash_ensure_p((gh), (pt), &val)) { \ + *((int *)val) += 1; \ + } \ + else { \ + *((int *)val) = 1; \ + } \ + } ((void)0) + + + /* count chunk_list's */ + int totrefs = 0; + GHash *chunk_list_map = BLI_ghash_ptr_new(__func__); + for (BArrayState *state = bs->states.first; state; state = state->next) { + GHASH_PTR_ADD_USER(chunk_list_map, state->chunk_list); + } + GHASH_ITER (gh_iter, chunk_list_map) { + const struct BChunkList *chunk_list = BLI_ghashIterator_getKey(&gh_iter); + const int users = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter)); + if (!(chunk_list->users == users)) { + ok = false; + goto user_finally; + } + } + if (!(BLI_mempool_count(bs->memory.chunk_list) == (int)BLI_ghash_size(chunk_list_map))) { + ok = false; + goto user_finally; + } + + /* count chunk's */ + GHash *chunk_map = BLI_ghash_ptr_new(__func__); + GHASH_ITER (gh_iter, chunk_list_map) { + const struct BChunkList *chunk_list = BLI_ghashIterator_getKey(&gh_iter); + for (const BChunkRef *cref = chunk_list->chunk_refs.first; cref; cref = cref->next) { + GHASH_PTR_ADD_USER(chunk_map, cref->link); + totrefs += 1; + } + } + if (!(BLI_mempool_count(bs->memory.chunk) == (int)BLI_ghash_size(chunk_map))) { + ok = false; + goto user_finally; + } + if (!(BLI_mempool_count(bs->memory.chunk_ref) == totrefs)) { + ok = false; + goto user_finally; + } + + GHASH_ITER (gh_iter, chunk_map) { + const struct BChunk *chunk = BLI_ghashIterator_getKey(&gh_iter); + const int users = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter)); + if (!(chunk->users == users)) { + ok = false; + goto user_finally; + } + } + +#undef GHASH_PTR_ADD_USER + +user_finally: + BLI_ghash_free(chunk_list_map, NULL, NULL); + BLI_ghash_free(chunk_map, NULL, NULL); + } + + + return ok; + /* TODO, dangling pointer checks */ +} + +/** \} */ diff --git a/source/blender/blenlib/intern/noise.c b/source/blender/blenlib/intern/noise.c index c3a0c44d7c5..f834c5b4c74 100644 --- a/source/blender/blenlib/intern/noise.c +++ b/source/blender/blenlib/intern/noise.c @@ -1048,8 +1048,8 @@ static float noise3_perlin(float vec[3]) b01 = p[i + by1]; b11 = p[j + by1]; -#define VALUE_AT(rx, ry, rz) (rx * q[0] + ry * q[1] + rz * q[2]) -#define SURVE(t) (t * t * (3.0f - 2.0f * t)) +#define VALUE_AT(rx, ry, rz) ((rx) * q[0] + (ry) * q[1] + (rz) * q[2]) +#define SURVE(t) ((t) * (t) * (3.0f - 2.0f * (t))) /* lerp moved to improved perlin above */ diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.c b/source/blender/bmesh/intern/bmesh_mesh_conv.c index 7b102c9283b..bb61f66e267 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_conv.c +++ b/source/blender/bmesh/intern/bmesh_mesh_conv.c @@ -804,10 +804,10 @@ void BM_mesh_bm_to_me( BMEditSelection *selected; me->totselect = BLI_listbase_count(&(bm->selected)); - if (me->mselect) MEM_freeN(me->mselect); - - me->mselect = MEM_callocN(sizeof(MSelect) * me->totselect, "Mesh selection history"); - + MEM_SAFE_FREE(me->mselect); + if (me->totselect != 0) { + me->mselect = MEM_mallocN(sizeof(MSelect) * me->totselect, "Mesh selection history"); + } for (i = 0, selected = bm->selected.first; selected; i++, selected = selected->next) { if (selected->htype == BM_VERT) { diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 5a7788c0b62..f7e3622e53c 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -345,6 +345,36 @@ static EdgeHalf *next_bev(BevVert *bv, EdgeHalf *from_e) return NULL; } +/* return count of edges between e1 and e2 when going around bv CCW */ +static int count_ccw_edges_between(EdgeHalf *e1, EdgeHalf *e2) +{ + int cnt = 0; + EdgeHalf *e = e1; + + do { + if (e == e2) + break; + e = e->next; + cnt++; + } while (e != e1); + return cnt; +} + +/* Assume bme1 and bme2 both share some vert. Do they share a face? + * If they share a face then there is some loop around bme1 that is in a face + * where the next or previous edge in the face must be bme2. */ +static bool edges_face_connected_at_vert(BMEdge *bme1, BMEdge *bme2) +{ + BMLoop *l; + BMIter iter; + + BM_ITER_ELEM(l, &iter, bme1, BM_LOOPS_OF_EDGE) { + if (l->prev->e == bme2 || l->next->e == bme2) + return true; + } + return false; +} + /* Return a good representative face (for materials, etc.) for faces * created around/near BoundVert v. * Sometimes care about a second choice, if there is one. @@ -1557,7 +1587,7 @@ static void build_boundary_vertex_only(BevelParams *bp, BevVert *bv, bool constr if (construct) { v = add_new_bound_vert(bp->mem_arena, vm, co); v->efirst = v->elast = e; - e->leftv = v; + e->leftv = e->rightv = v; } else { adjust_bound_vert(e->leftv, co); @@ -1637,7 +1667,7 @@ static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf v->efirst = e->prev; v->elast = v->ebev = e; e->leftv = v; - e->prev->leftv = v; + e->prev->leftv = e->prev->rightv = v; } else { adjust_bound_vert(e->leftv, co); @@ -1648,7 +1678,7 @@ static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf v = add_new_bound_vert(mem_arena, vm, co); v->efirst = e->prev; v->elast = e; - e->leftv = v; + e->leftv = e->rightv = v; e->prev->rightv = v; } else { @@ -1661,7 +1691,7 @@ static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf if (construct) { v = add_new_bound_vert(mem_arena, vm, co); v->efirst = v->elast = e; - e->leftv = v; + e->leftv = e->rightv = v; } else { adjust_bound_vert(e->leftv, co); @@ -3237,6 +3267,11 @@ static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv) if (!weld) create_mesh_bmvert(bm, vm, i, 0, k, bv->v); } + else if (n == 2 && !v->ebev && vm->mesh_kind != M_ADJ) { + /* case of one edge beveled and this is the v without ebev */ + /* want to copy the verts from other v, in reverse order */ + copy_mesh_vert(vm, i, 0, k, 1 - i, 0, ns - k); + } } } while ((v = v->next) != vm->boundstart); @@ -3305,6 +3340,219 @@ static float edge_face_angle(EdgeHalf *e) #define BM_BEVEL_EDGE_TAG_DISABLE(bme) BM_ELEM_API_FLAG_DISABLE( (bme), _FLAG_OVERLAP) #define BM_BEVEL_EDGE_TAG_TEST(bme) BM_ELEM_API_FLAG_TEST( (bme), _FLAG_OVERLAP) +/* Try to extend the bv->edges[] array beyond i by finding more successor edges. + * This is a possibly exponential-time search, but it is only exponential in the number + * of "internal faces" at a vertex -- i.e., faces that bridge between the edges that naturally + * form a manifold cap around bv. It is rare to have more than one of these, so unlikely + * that the exponential time case will be hit in practice. + * Returns the new index i' where bv->edges[i'] ends the best path found. + * The path will have the tags of all of its edges set. */ +static int bevel_edge_order_extend(BMesh *bm, BevVert *bv, int i) +{ + BMEdge *bme, *bme2, *nextbme; + BMLoop *l; + BMIter iter; + int j, tryj, bestj, nsucs, sucindex, k; + BMEdge **sucs = NULL; + BMEdge **save_path = NULL; + BLI_array_staticdeclare(sucs, 4); /* likely very few faces attached to same edge */ + BLI_array_staticdeclare(save_path, BM_DEFAULT_NGON_STACK_SIZE); + + bme = bv->edges[i].e; + /* fill sucs with all unmarked edges of bmes */ + BM_ITER_ELEM(l, &iter, bme, BM_LOOPS_OF_EDGE) { + bme2 = (l->v == bv->v) ? l->prev->e : l->next->e; + if (!BM_BEVEL_EDGE_TAG_TEST(bme2)) { + BLI_array_append(sucs, bme2); + } + } + nsucs = BLI_array_count(sucs); + + bestj = j = i; + for (sucindex = 0; sucindex < nsucs; sucindex++) { + nextbme = sucs[sucindex]; + BLI_assert(nextbme != NULL); + BLI_assert(!BM_BEVEL_EDGE_TAG_TEST(nextbme)); + BLI_assert(j + 1 < bv->edgecount); + bv->edges[j + 1].e = nextbme; + BM_BEVEL_EDGE_TAG_ENABLE(nextbme); + tryj = bevel_edge_order_extend(bm, bv, j + 1); + if (tryj > bestj || (tryj == bestj && edges_face_connected_at_vert(bv->edges[tryj].e, bv->edges[0].e))) { + bestj = tryj; + BLI_array_empty(save_path); + for (k = j + 1; k <= bestj; k++) { + BLI_array_append(save_path, bv->edges[k].e); + } + } + /* now reset to path only-going-to-j state */ + for (k = j + 1; k <= tryj; k++) { + BM_BEVEL_EDGE_TAG_DISABLE(bv->edges[k].e); + bv->edges[k].e = NULL; + } + } + /* at this point we should be back at invariant on entrance: path up to j */ + if (bestj > j) { + /* save_path should have from j + 1 to bestj inclusive edges to add to edges[] before returning */ + for (k = j + 1; k <= bestj; k++) { + BLI_assert(save_path[k - (j + 1)] != NULL); + bv->edges[k].e = save_path[k - (j + 1)]; + BM_BEVEL_EDGE_TAG_ENABLE(bv->edges[k].e); + } + } + BLI_array_free(sucs); + BLI_array_free(save_path); + return bestj; +} + +/* See if we have usual case for bevel edge order: + * there is an ordering such that all the faces are between + * successive edges and form a manifold "cap" at bv. + * If this is the case, set bv->edges to such an order + * and return true; else return unmark any partial path and return false. + * Assume the first edge is already in bv->edges[0].e and it is tagged. */ +#ifdef FASTER_FASTORDER +/* The alternative older code is O(n^2) where n = # of edges incident to bv->v. + * This implementation is O(n * m) where m = average number of faces attached to an edge incident to bv->v, + * which is almost certainly a small constant except in very strange cases. But this code produces different + * choices of ordering than the legacy system, leading to differences in vertex orders etc. in user models, + * so for now will continue to use the legacy code. */ +static bool fast_bevel_edge_order(BevVert *bv) +{ + int j, k, nsucs; + BMEdge *bme, *bme2, *bmenext; + BMIter iter; + BMLoop *l; + + for (j = 1; j < bv->edgecount; j++) { + bme = bv->edges[j - 1].e; + bmenext = NULL; + nsucs = 0; + BM_ITER_ELEM(l, &iter, bme, BM_LOOPS_OF_EDGE) { + bme2 = (l->v == bv->v) ? l->prev->e : l->next->e; + if (!BM_BEVEL_EDGE_TAG_TEST(bme2)) { + nsucs++; + if (bmenext == NULL) + bmenext = bme2; + } + } + if (nsucs == 0 || (nsucs == 2 && j != 1) || nsucs > 2 || + (j == bv->edgecount - 1 && !edges_face_connected_at_vert(bmenext, bv->edges[0].e))) + { + for (k = 1; k < j; k++) { + BM_BEVEL_EDGE_TAG_DISABLE(bv->edges[k].e); + bv->edges[k].e = NULL; + } + return false; + } + bv->edges[j].e = bmenext; + BM_BEVEL_EDGE_TAG_ENABLE(bmenext); + } + return true; +} +#else +static bool fast_bevel_edge_order(BevVert *bv) +{ + BMEdge *bme, *bme2, *first_suc; + BMIter iter, iter2; + BMFace *f; + EdgeHalf *e; + int i, k, ntot, num_shared_face; + + ntot = bv->edgecount; + + /* add edges to bv->edges in order that keeps adjacent edges sharing + * a unique face, if possible */ + e = &bv->edges[0]; + bme = e->e; + if (!bme->l) + return false; + for (i = 1; i < ntot; i++) { + /* find an unflagged edge bme2 that shares a face f with previous bme */ + num_shared_face = 0; + first_suc = NULL; /* keep track of first successor to match legacy behavior */ + BM_ITER_ELEM (bme2, &iter, bv->v, BM_EDGES_OF_VERT) { + if (BM_BEVEL_EDGE_TAG_TEST(bme2)) + continue; + BM_ITER_ELEM (f, &iter2, bme2, BM_FACES_OF_EDGE) { + if (BM_face_edge_share_loop(f, bme)) { + num_shared_face++; + if (first_suc == NULL) + first_suc = bme2; + } + } + if (num_shared_face >= 3) + break; + } + if (num_shared_face == 1 || (i == 1 && num_shared_face == 2)) { + e = &bv->edges[i]; + e->e = bme = first_suc; + BM_BEVEL_EDGE_TAG_ENABLE(bme); + } + else { + for (k = 1; k < i; k++) { + BM_BEVEL_EDGE_TAG_DISABLE(bv->edges[k].e); + bv->edges[k].e = NULL; + } + return false; + } + } + return true; +} +#endif + +/* Fill in bv->edges with a good ordering of non-wire edges around bv->v. + * Use only edges where BM_BEVEL_EDGE_TAG is disabled so far + * (if edge beveling, others are wire). + * first_bme is a good edge to start with.*/ +static void find_bevel_edge_order(BMesh *bm, BevVert *bv, BMEdge *first_bme) +{ + BMEdge *bme, *bme2; + BMIter iter; + BMFace *f; + EdgeHalf *e; + EdgeHalf *e2; + BMLoop *l; + int i, ntot; + + ntot = bv->edgecount; + i = 0; + for (;;) { + BLI_assert(first_bme != NULL); + bv->edges[i].e = first_bme; + BM_BEVEL_EDGE_TAG_ENABLE(first_bme); + if (fast_bevel_edge_order(bv)) + break; + i = bevel_edge_order_extend(bm, bv, i); + i++; + if (i >= bv->edgecount) + break; + /* Not done yet: find a new first_bme */ + first_bme = NULL; + BM_ITER_ELEM(bme, &iter, bv->v, BM_EDGES_OF_VERT) { + if (BM_BEVEL_EDGE_TAG_TEST(bme)) + continue; + if (!first_bme) + first_bme = bme; + if (BM_edge_face_count(bme) == 1) { + first_bme = bme; + break; + } + } + } + /* now fill in the faces ... */ + for (i = 0; i < ntot; i++) { + e = &bv->edges[i]; + e2 = (i == bv->edgecount - 1) ? &bv->edges[0] : &bv->edges[i + 1]; + bme = e->e; + bme2 = e2->e; + BM_ITER_ELEM(l, &iter, bme, BM_LOOPS_OF_EDGE) { + f = l->f; + if ((l->prev->e == bme2 || l->next->e == bme2) && !e->fnext && !e2->fprev) + e->fnext = e2->fprev = f; + } + } +} + /* * Construction around the vertex */ @@ -3312,13 +3560,12 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) { BMEdge *bme; BevVert *bv; - BMEdge *bme2, *unflagged_bme, *first_bme; - BMFace *f; + BMEdge *first_bme; BMVert *v1, *v2; - BMIter iter, iter2; + BMIter iter; EdgeHalf *e; float weight, z; - int i, found_shared_face, ccw_test_sum; + int i, ccw_test_sum; int nsel = 0; int ntot = 0; int nwire = 0; @@ -3398,47 +3645,12 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) } BLI_ghash_insert(bp->vert_hash, v, bv); - /* add edges to bv->edges in order that keeps adjacent edges sharing - * a face, if possible */ - i = 0; + find_bevel_edge_order(bm, bv, first_bme); - bme = first_bme; - BM_BEVEL_EDGE_TAG_ENABLE(bme); - e = &bv->edges[0]; - e->e = bme; + /* fill in other attributes of EdgeHalfs */ for (i = 0; i < ntot; i++) { - if (i > 0) { - /* find an unflagged edge bme2 that shares a face f with previous bme */ - found_shared_face = 0; - unflagged_bme = NULL; - BM_ITER_ELEM (bme2, &iter, v, BM_EDGES_OF_VERT) { - if (BM_BEVEL_EDGE_TAG_TEST(bme2)) - continue; - if (!unflagged_bme) - unflagged_bme = bme2; - if (!bme->l) - continue; - BM_ITER_ELEM (f, &iter2, bme2, BM_FACES_OF_EDGE) { - if (BM_face_edge_share_loop(f, bme)) { - found_shared_face = 1; - break; - } - } - if (found_shared_face) - break; - } - e = &bv->edges[i]; - if (found_shared_face) { - e->e = bme2; - e->fprev = f; - bv->edges[i - 1].fnext = f; - } - else { - e->e = unflagged_bme; - } - } + e = &bv->edges[i]; bme = e->e; - BM_BEVEL_EDGE_TAG_ENABLE(bme); if (BM_elem_flag_test(bme, BM_ELEM_TAG) && !bp->vertex_only) { e->is_bev = true; e->seg = bp->seg; @@ -3449,16 +3661,6 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) } e->is_rev = (bme->v2 == v); } - /* find wrap-around shared face */ - BM_ITER_ELEM (f, &iter2, bme, BM_FACES_OF_EDGE) { - if (bv->edges[0].e->l && BM_face_edge_share_loop(f, bv->edges[0].e)) { - if (bv->edges[0].fnext == f) - continue; /* if two shared faces, want the other one now */ - bv->edges[ntot - 1].fnext = f; - bv->edges[0].fprev = f; - break; - } - } /* now done with tag flag */ BM_ITER_ELEM (bme, &iter, v, BM_EDGES_OF_VERT) { @@ -3586,6 +3788,7 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f) VMesh *vm; int i, k, n; bool do_rebuild = false; + bool go_ccw, corner3special; BMVert *bmv; BMEdge *bme, *bme_new, *bme_prev; BMFace *f_new; @@ -3600,47 +3803,88 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f) if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { lprev = l->prev; bv = find_bevvert(bp, l->v); + vm = bv->vmesh; e = find_edge_half(bv, l->e); bme = e->e; eprev = find_edge_half(bv, lprev->e); BLI_assert(e != NULL && eprev != NULL); - vstart = eprev->leftv; - if (e->is_bev) - vend = e->rightv; - else + + /* which direction around our vertex do we travel to match orientation of f? */ + if (e->prev == eprev) { + if (eprev->prev == e) { + /* valence 2 vertex: use f is one of e->fnext or e->fprev to break tie */ + go_ccw = (e->fnext != f); + } + else { + go_ccw = true; /* going ccw around bv to trace this corner */ + } + } + else if (eprev->prev == e) { + go_ccw = false; /* going cw around bv to trace this corner */ + } + else { + /* edges in face are non-contiguous in our ordering around bv. + * Which way should we go when going from eprev to e? */ + if (count_ccw_edges_between(eprev, e) < count_ccw_edges_between(e, eprev)) { + /* go counterclockewise from eprev to e */ + go_ccw = true; + } + else { + /* go clockwise from eprev to e */ + go_ccw = false; + } + } + if (go_ccw) { + vstart = eprev->rightv; vend = e->leftv; + } + else { + vstart = eprev->leftv; + vend = e->rightv; + } + BLI_assert(vstart != NULL && vend != NULL); v = vstart; - vm = bv->vmesh; BLI_array_append(vv, v->nv.v); BLI_array_append(ee, bme); + /* check for special case: multisegment 3rd face opposite a beveled edge with no vmesh */ + corner3special = (vm->mesh_kind == M_NONE && v->ebev != e && v->ebev != eprev); while (v != vend) { - if (vm->mesh_kind == M_NONE && v->ebev && v->ebev->seg > 1 && v->ebev != e && v->ebev != eprev) { - /* case of 3rd face opposite a beveled edge, with no vmesh */ - i = v->index; - e = v->ebev; - for (k = 1; k < e->seg; k++) { - bmv = mesh_vert(vm, i, 0, k)->v; - BLI_array_append(vv, bmv); - BLI_array_append(ee, bme); - /* may want to merge UVs of these later */ - if (!e->is_seam) - BLI_array_append(vv_fix, bmv); + if (go_ccw) { + if (vm->seg > 1) { + if (vm->mesh_kind == M_ADJ || bp->vertex_only || corner3special) { + i = v->index; + for (k = 1; k < vm->seg; k++) { + bmv = mesh_vert(vm, i, 0, k)->v; + BLI_array_append(vv, bmv); + BLI_array_append(ee, bme); /* TODO: maybe better edge here */ + if (corner3special && v->ebev && !v->ebev->is_seam) + BLI_array_append(vv_fix, bmv); + } + } } + v = v->next; } - else if ((vm->mesh_kind == M_ADJ || bp->vertex_only) && vm->seg > 1 && !e->is_bev && !eprev->is_bev) { - BLI_assert(v->prev == vend); - i = vend->index; - for (k = vm->seg - 1; k > 0; k--) { - bmv = mesh_vert(vm, i, 0, k)->v; - BLI_array_append(vv, bmv); - BLI_array_append(ee, bme); + else { + /* going cw */ + if (vm->seg > 1) { + if (vm->mesh_kind == M_ADJ || bp->vertex_only || + (vm->mesh_kind == M_NONE && v->ebev != e && v->ebev != eprev)) + { + i = v->prev->index; + for (k = vm->seg - 1; k > 0; k--) { + bmv = mesh_vert(vm, i, 0, k)->v; + BLI_array_append(vv, bmv); + BLI_array_append(ee, bme); + if (corner3special && v->ebev && !v->ebev->is_seam) + BLI_array_append(vv_fix, bmv); + } + } } + v = v->prev; } - v = v->prev; BLI_array_append(vv, v->nv.v); BLI_array_append(ee, bme); } - do_rebuild = true; } else { diff --git a/source/blender/collada/ArmatureExporter.cpp b/source/blender/collada/ArmatureExporter.cpp index 36ab85b9b5b..4f5cf83f5ca 100644 --- a/source/blender/collada/ArmatureExporter.cpp +++ b/source/blender/collada/ArmatureExporter.cpp @@ -67,12 +67,19 @@ void ArmatureExporter::add_armature_bones(Object *ob_arm, Scene *sce, std::list<Object *>& child_objects) { // write bone nodes + + bArmature * armature = (bArmature *)ob_arm->data; + ED_armature_to_edit(armature); + bArmature *arm = (bArmature *)ob_arm->data; for (Bone *bone = (Bone *)arm->bonebase.first; bone; bone = bone->next) { // start from root bones if (!bone->parent) add_bone_node(bone, ob_arm, sce, se, child_objects); } + + ED_armature_from_edit(armature); + ED_armature_edit_free(armature); } void ArmatureExporter::write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone) @@ -167,12 +174,30 @@ void ArmatureExporter::add_bone_node(Bone *bone, Object *ob_arm, Scene *sce, node.setNodeName(node_name); node.setNodeSid(node_sid); -#if 0 - if (BLI_listbase_is_empty(&bone->childbase) || BLI_listbase_count_ex(&bone->childbase, 2) == 2) { - add_blender_leaf_bone( bone, ob_arm, node); + if (this->export_settings->use_blender_profile) + { + if (bone->parent) { + if (bone->flag & BONE_CONNECTED) { + node.addExtraTechniqueParameter("blender", "connect", true); + } + } + std::string layers = BoneExtended::get_bone_layers(bone->layer); + node.addExtraTechniqueParameter("blender", "layer", layers); + + bArmature *armature = (bArmature *)ob_arm->data; + EditBone *ebone = bc_get_edit_bone(armature, bone->name); + if (ebone && ebone->roll != 0) + { + node.addExtraTechniqueParameter("blender", "roll", ebone->roll); + } + if (bc_is_leaf_bone(bone)) + { + node.addExtraTechniqueParameter("blender", "tip_x", bone->arm_tail[0] - bone->arm_head[0]); + node.addExtraTechniqueParameter("blender", "tip_y", bone->arm_tail[1] - bone->arm_head[1]); + node.addExtraTechniqueParameter("blender", "tip_z", bone->arm_tail[2] - bone->arm_head[2]); + } } - else { -#endif + node.start(); add_bone_transform(ob_arm, bone, node); @@ -227,25 +252,6 @@ void ArmatureExporter::add_bone_node(Bone *bone, Object *ob_arm, Scene *sce, } } -//#if 1 -void ArmatureExporter::add_blender_leaf_bone(Bone *bone, Object *ob_arm, COLLADASW::Node& node) -{ - node.start(); - - add_bone_transform(ob_arm, bone, node); - - node.addExtraTechniqueParameter("blender", "tip_x", bone->tail[0]); - node.addExtraTechniqueParameter("blender", "tip_y", bone->tail[1]); - node.addExtraTechniqueParameter("blender", "tip_z", bone->tail[2]); - - /*for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) { - add_bone_node(child, ob_arm, sce, se, child_objects); - }*/ - node.end(); - -} -//#endif - void ArmatureExporter::add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node& node) { //bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name); diff --git a/source/blender/collada/ArmatureExporter.h b/source/blender/collada/ArmatureExporter.h index 931cc5d2988..883a6aca847 100644 --- a/source/blender/collada/ArmatureExporter.h +++ b/source/blender/collada/ArmatureExporter.h @@ -92,8 +92,6 @@ private: void add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node& node); - void add_blender_leaf_bone(Bone *bone, Object *ob_arm, COLLADASW::Node& node); - std::string get_controller_id(Object *ob_arm, Object *ob); void write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone); diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp index fd08e1ebfab..fca9b9ffa55 100644 --- a/source/blender/collada/ArmatureImporter.cpp +++ b/source/blender/collada/ArmatureImporter.cpp @@ -50,19 +50,6 @@ static const char *bc_get_joint_name(T *node) return id.size() ? id.c_str() : node->getOriginalId().c_str(); } -static EditBone *get_edit_bone(bArmature * armature, char *name) { - EditBone *eBone; - - for (eBone = (EditBone *)armature->edbo->first; eBone; eBone = eBone->next) { - if (STREQ(name, eBone->name)) - return eBone; - } - - return NULL; - -} - - ArmatureImporter::ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Scene *sce, const ImportSettings *import_settings) : import_settings(import_settings), @@ -110,7 +97,7 @@ JointData *ArmatureImporter::get_joint_data(COLLADAFW::Node *node); #endif int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBone *parent, int totchild, - float parent_mat[4][4], bArmature *arm) + float parent_mat[4][4], bArmature *arm, std::vector<std::string> &layer_labels) { float mat[4][4]; float joint_inv_bind_mat[4][4]; @@ -157,22 +144,41 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon if (parent) bone->parent = parent; float loc[3], size[3], rot[3][3]; - float angle; - float vec[3] = {0.0f, 0.5f, 0.0f}; - mat4_to_loc_rot_size(loc, rot, size, mat); - //copy_m3_m4(bonemat,mat); - mat3_to_vec_roll(rot, vec, &angle); - - bone->roll = angle; - // set head - copy_v3_v3(bone->head, mat[3]); - // set tail, don't set it to head because 0-length bones are not allowed - add_v3_v3v3(bone->tail, bone->head, vec); + BoneExtended &be = add_bone_extended(bone, node, layer_labels); + int layer = be.get_bone_layers(); + if (layer) bone->layer = layer; + arm->layer |= layer; // ensure that all populated bone layers are visible after import + + float *tail = be.get_tail(); + int use_connect = be.get_use_connect(); + + switch (use_connect) { + case 1: bone->flag |= BONE_CONNECTED; + break; + case 0: bone->flag &= ~BONE_CONNECTED; + case -1: break; // not defined + } + + if (be.has_roll()) { + bone->roll = be.get_roll(); + } + else { + float angle; + mat4_to_loc_rot_size(loc, rot, size, mat); + mat3_to_vec_roll(rot, NULL, &angle); + } + + copy_v3_v3(bone->head, mat[3]); + add_v3_v3v3(bone->tail, bone->head, tail); //tail must be non zero /* find smallest bone length in armature (used later for leaf bone length) */ if (parent) { + if (use_connect == 1) { + copy_v3_v3(parent->tail, bone->head); + } + /* guess reasonable leaf bone length */ float length = len_v3v3(parent->head, bone->head); if ((length < leaf_bone_length || totbone == 0) && length > MINIMUM_BONE_LENGTH) { @@ -182,11 +188,8 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon COLLADAFW::NodePointerArray& children = node->getChildNodes(); - BoneExtended &be = add_bone_extended(bone, node); - be.set_leaf_bone(true); - for (unsigned int i = 0; i < children.getCount(); i++) { - int cl = create_bone(skin, children[i], bone, children.getCount(), mat, arm); + int cl = create_bone(skin, children[i], bone, children.getCount(), mat, arm, layer_labels); if (cl > chain_length) chain_length = cl; } @@ -209,22 +212,23 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon **/ void ArmatureImporter::fix_leaf_bones(bArmature *armature, Bone *bone) { - /* armature has no bones */ if (bone == NULL) return; - BoneExtended *be = extended_bones[bone->name]; - if (be != NULL && be->is_leaf_bone() ) { - /* Collada only knows Joints, Here we guess a reasonable leaf bone length */ - float leaf_length = (leaf_bone_length == FLT_MAX) ? 1.0 : leaf_bone_length; + if (bc_is_leaf_bone(bone)) { + + BoneExtended *be = extended_bones[bone->name]; + if (be == NULL || !be->has_tail()) { - EditBone *ebone = get_edit_bone(armature, bone->name); - float vec[3]; + /* Collada only knows Joints, Here we guess a reasonable leaf bone length */ + float leaf_length = (leaf_bone_length == FLT_MAX) ? 1.0 : leaf_bone_length; + + EditBone *ebone = bc_get_edit_bone(armature, bone->name); + float vec[3]; - if (this->import_settings->fix_orientation) { if (ebone->parent != NULL) { EditBone *parent = ebone->parent; - sub_v3_v3v3(vec, ebone->head, parent->tail); + sub_v3_v3v3(vec, ebone->head, parent->head); if (len_squared_v3(vec) < MINIMUM_BONE_LENGTH) { sub_v3_v3v3(vec, parent->tail, parent->head); @@ -234,19 +238,31 @@ void ArmatureImporter::fix_leaf_bones(bArmature *armature, Bone *bone) vec[2] = 0.1f; sub_v3_v3v3(vec, ebone->tail, ebone->head); } - } - else { - sub_v3_v3v3(vec, ebone->tail, ebone->head); - } - normalize_v3_v3(vec, vec); - mul_v3_fl(vec, leaf_length); - add_v3_v3v3(ebone->tail, ebone->head, vec); + normalize_v3_v3(vec, vec); + mul_v3_fl(vec, leaf_length); + add_v3_v3v3(ebone->tail, ebone->head, vec); + } } for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) { fix_leaf_bones(armature, child); } +} + +void ArmatureImporter::fix_parent_connect(bArmature *armature, Bone *bone) +{ + /* armature has no bones */ + if (bone == NULL) + return; + + if (bone->parent && bone->flag & BONE_CONNECTED) { + copy_v3_v3(bone->parent->tail, bone->head); + } + + for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) { + fix_parent_connect(armature, child); + } } @@ -281,8 +297,8 @@ void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone BoneExtended *pbe = extended_bones[parentbone->name]; if (dominant_child != NULL) { /* Found a valid chain. Now connect current bone with that chain.*/ - EditBone *pebone = get_edit_bone(armature, parentbone->name); - EditBone *cebone = get_edit_bone(armature, dominant_child->get_name()); + EditBone *pebone = bc_get_edit_bone(armature, parentbone->name); + EditBone *cebone = bc_get_edit_bone(armature, dominant_child->get_name()); if (pebone && !(cebone->flag & BONE_CONNECTED)) { float vec[3]; @@ -421,6 +437,7 @@ ArmatureJoints& ArmatureImporter::get_armature_joints(Object *ob_arm) void ArmatureImporter::create_armature_bones( ) { std::vector<COLLADAFW::Node *>::iterator ri; + std::vector<std::string> layer_labels; leaf_bone_length = FLT_MAX; //if there is an armature created for root_joint next root_joint @@ -445,8 +462,9 @@ void ArmatureImporter::create_armature_bones( ) clear_extended_boneset(); ED_armature_to_edit(armature); + armature->layer = 0; // layer is set according to imported bone set in create_bone() - create_bone(NULL, *ri , NULL, (*ri)->getChildNodes().getCount(), NULL, armature); + create_bone(NULL, *ri , NULL, (*ri)->getChildNodes().getCount(), NULL, armature, layer_labels); /* exit armature edit mode to populate the Armature object */ ED_armature_from_edit(armature); @@ -455,14 +473,23 @@ void ArmatureImporter::create_armature_bones( ) /* and step back to edit mode to fix the leaf nodes */ ED_armature_to_edit(armature); - connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX); - fix_leaf_bones(armature, (Bone *)armature->bonebase.first); + if (this->import_settings->fix_orientation || this->import_settings->find_chains) { + + if (this->import_settings->find_chains) + connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX); - // exit armature edit mode - unskinned_armature_map[(*ri)->getUniqueId()] = ob_arm; + if (this->import_settings->fix_orientation) + fix_leaf_bones(armature, (Bone *)armature->bonebase.first); + + // exit armature edit mode + unskinned_armature_map[(*ri)->getUniqueId()] = ob_arm; + } + + fix_parent_connect(armature, (Bone *)armature->bonebase.first); ED_armature_from_edit(armature); ED_armature_edit_free(armature); + DAG_id_tag_update(&ob_arm->id, OB_RECALC_OB | OB_RECALC_DATA); } } @@ -513,6 +540,7 @@ void ArmatureImporter::create_armature_bones(SkinInfo& skin) SkinInfo *a = &skin; Object *shared = NULL; std::vector<COLLADAFW::Node *> skin_root_joints; + std::vector<std::string> layer_labels; std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it; for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) { @@ -578,7 +606,7 @@ void ArmatureImporter::create_armature_bones(SkinInfo& skin) // since root_joints may contain joints for multiple controllers, we need to filter if (skin.uses_joint_or_descendant(*ri)) { - create_bone(&skin, *ri, NULL, (*ri)->getChildNodes().getCount(), NULL, armature); + create_bone(&skin, *ri, NULL, (*ri)->getChildNodes().getCount(), NULL, armature, layer_labels); if (joint_parent_map.find((*ri)->getUniqueId()) != joint_parent_map.end() && !skin.get_parent()) skin.set_parent(joint_parent_map[(*ri)->getUniqueId()]); @@ -594,8 +622,8 @@ void ArmatureImporter::create_armature_bones(SkinInfo& skin) if (armature->bonebase.first) { /* Do this only if Armature has bones */ - connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX); - fix_leaf_bones(armature, (Bone *)armature->bonebase.first); + //connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX); + //fix_leaf_bones(armature, (Bone *)armature->bonebase.first); } // exit armature edit mode ED_armature_from_edit(armature); @@ -894,70 +922,44 @@ bool ArmatureImporter::get_joint_bind_mat(float m[4][4], COLLADAFW::Node *joint) return found; } - -/** - * BoneExtended is a helper class needed for the Bone chain finder - * See ArmatureImporter::fix_leaf_bones() - * and ArmatureImporter::connect_bone_chains() - **/ - -BoneExtended::BoneExtended(EditBone *aBone) -{ - this->set_name(aBone->name); - this->chain_length = 0; - this->is_leaf = false; -} - -char *BoneExtended::get_name() -{ - return name; -} - -void BoneExtended::set_name(char *aName) -{ - BLI_strncpy(name, aName, MAXBONENAME); -} - -int BoneExtended::get_chain_length() -{ - return chain_length; -} - -void BoneExtended::set_chain_length(const int aLength) -{ - chain_length = aLength; -} - - -void BoneExtended::set_leaf_bone(bool state) -{ - is_leaf = state; -} - -bool BoneExtended::is_leaf_bone() -{ - return is_leaf; -} - -BoneExtended &ArmatureImporter::add_bone_extended(EditBone *bone, COLLADAFW::Node *node) +BoneExtended &ArmatureImporter::add_bone_extended(EditBone *bone, COLLADAFW::Node *node, std::vector<std::string> &layer_labels) { + BoneExtended *be = new BoneExtended(bone); + extended_bones[bone->name] = be; TagsMap::iterator etit; ExtraTags *et = 0; etit = uid_tags_map.find(node->getUniqueId().toAscii()); if (etit != uid_tags_map.end()) { - float x, y, z; + + float tail[3] = { FLT_MAX, FLT_MAX, FLT_MAX }; + float roll = 0; + int use_connect = -1; + std::string layers; et = etit->second; - et->setData("tip_x", &x); - et->setData("tip_y", &y); - et->setData("tip_z", &z); - float vec[3] = { x, y, z }; - copy_v3_v3(bone->tail, bone->head); - add_v3_v3v3(bone->tail, bone->head, vec); + + bool has_tail = false; + has_tail |= et->setData("tip_x", &tail[0]); + has_tail |= et->setData("tip_y", &tail[1]); + has_tail |= et->setData("tip_z", &tail[2]); + + bool has_connect = et->setData("connect", &use_connect); + bool has_roll = et->setData("roll", &roll); + + layers = et->setData("layer", layers); + + if (has_tail && !has_connect) + { + use_connect = 0; // got a bone tail definition but no connect info -> bone is not connected + } + + be->set_bone_layers(layers, layer_labels); + if (has_tail) be->set_tail(tail); + if (has_roll) be->set_roll(roll); + be->set_use_connect(use_connect); } + be->set_leaf_bone(true); - BoneExtended *be = new BoneExtended(bone); - extended_bones[bone->name] = be; return *be; } diff --git a/source/blender/collada/ArmatureImporter.h b/source/blender/collada/ArmatureImporter.h index 732fda80ff1..f38bd1a6c66 100644 --- a/source/blender/collada/ArmatureImporter.h +++ b/source/blender/collada/ArmatureImporter.h @@ -59,25 +59,6 @@ extern "C" { #define UNLIMITED_CHAIN_MAX INT_MAX #define MINIMUM_BONE_LENGTH 0.000001f -class BoneExtended { - -private: - char name[MAXBONENAME]; - int chain_length; - bool is_leaf; - -public: - - BoneExtended(EditBone *aBone); - char *get_name(); - int get_chain_length(); - - void set_name(char *aName); - void set_chain_length(const int aLength); - void set_leaf_bone(bool state); - bool is_leaf_bone(); -}; - class ArmatureImporter : private TransformReader { private: @@ -125,12 +106,13 @@ private: #endif int create_bone(SkinInfo* skin, COLLADAFW::Node *node, EditBone *parent, int totchild, - float parent_mat[4][4], bArmature *arm); + float parent_mat[4][4], bArmature *arm, std::vector<std::string> &layer_labels); - BoneExtended &add_bone_extended(EditBone *bone, COLLADAFW::Node * node); + BoneExtended &add_bone_extended(EditBone *bone, COLLADAFW::Node * node, std::vector<std::string> &layer_labels); void clear_extended_boneset(); void fix_leaf_bones(bArmature *armature, Bone *bone); + void fix_parent_connect(bArmature *armature, Bone *bone); void connect_bone_chains(bArmature *armature, Bone *bone, const int max_chain_length); void set_pose( Object *ob_arm, COLLADAFW::Node *root_node, const char *parentname, float parent_mat[4][4]); diff --git a/source/blender/collada/ExportSettings.h b/source/blender/collada/ExportSettings.h index 3dc7e74379e..9451cac9dae 100644 --- a/source/blender/collada/ExportSettings.h +++ b/source/blender/collada/ExportSettings.h @@ -48,6 +48,7 @@ public: bool triangulate; bool use_object_instantiation; + bool use_blender_profile; bool sort_by_name; BC_export_transformation_type export_transformation_type; bool open_sim; diff --git a/source/blender/collada/ExtraTags.cpp b/source/blender/collada/ExtraTags.cpp index 6af61432fda..ea225d8a4ae 100644 --- a/source/blender/collada/ExtraTags.cpp +++ b/source/blender/collada/ExtraTags.cpp @@ -85,32 +85,45 @@ std::string ExtraTags::asString(std::string tag, bool *ok) } -void ExtraTags::setData(std::string tag, short *data) +bool ExtraTags::setData(std::string tag, short *data) { bool ok = false; int tmp = asInt(tag, &ok); if (ok) *data = (short)tmp; + return ok; } -void ExtraTags::setData(std::string tag, int *data) + +bool ExtraTags::setData(std::string tag, int *data) { bool ok = false; int tmp = asInt(tag, &ok); if (ok) *data = tmp; + return ok; } -void ExtraTags::setData(std::string tag, float *data) + +bool ExtraTags::setData(std::string tag, float *data) { bool ok = false; float tmp = asFloat(tag, &ok); if (ok) *data = tmp; + return ok; } -void ExtraTags::setData(std::string tag, char *data) + +bool ExtraTags::setData(std::string tag, char *data) { bool ok = false; int tmp = asInt(tag, &ok); if (ok) *data = (char)tmp; + return ok; +} + +std::string ExtraTags::setData(std::string tag, std::string &data) +{ + bool ok = false; + std::string tmp = asString(tag, &ok); + return (ok) ? tmp : data; } - diff --git a/source/blender/collada/ExtraTags.h b/source/blender/collada/ExtraTags.h index 03a311a7e86..ad272dcba65 100644 --- a/source/blender/collada/ExtraTags.h +++ b/source/blender/collada/ExtraTags.h @@ -43,17 +43,18 @@ public: bool addTag(std::string tag, std::string data); /** Set given short pointer to value of tag, if it exists. */ - void setData(std::string tag, short *data); + bool setData(std::string tag, short *data); /** Set given int pointer to value of tag, if it exists. */ - void setData(std::string tag, int *data); + bool setData(std::string tag, int *data); /** Set given float pointer to value of tag, if it exists. */ - void setData(std::string tag, float *data); + bool setData(std::string tag, float *data); /** Set given char pointer to value of tag, if it exists. */ - void setData(std::string tag, char *data); - + bool setData(std::string tag, char *data); + std::string setData(std::string tag, std::string &data); + /** Return true if the extra tags is for specified profile. */ bool isProfile(std::string profile); diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp index a884268fd5e..76f24545248 100644 --- a/source/blender/collada/MeshImporter.cpp +++ b/source/blender/collada/MeshImporter.cpp @@ -259,7 +259,8 @@ bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh) // checks if mesh has su COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives(); const std::string &name = bc_get_dae_name(mesh); - + int hole_count = 0; + for (unsigned i = 0; i < prim_arr.getCount(); i++) { COLLADAFW::MeshPrimitive *mp = prim_arr[i]; @@ -275,13 +276,21 @@ bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh) // checks if mesh has su for (unsigned int j = 0; j < vca.getCount(); j++) { int count = vca[j]; - if (count < 3) { - fprintf(stderr, "Primitive %s in %s has at least one face with vertex count < 3\n", + if (abs(count) < 3) { + fprintf(stderr, "ERROR: Primitive %s in %s has at least one face with vertex count < 3\n", type_str, name.c_str()); return false; } + if (count < 0) + { + hole_count ++; + } + } + + if (hole_count > 0) + { + fprintf(stderr, "WARNING: Primitive %s in %s: %d holes not imported (unsupported)\n", type_str, name.c_str(), hole_count); } - } else if (type == COLLADAFW::MeshPrimitive::LINES) { @@ -289,13 +298,13 @@ bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh) // checks if mesh has su } else if (type != COLLADAFW::MeshPrimitive::TRIANGLES && type != COLLADAFW::MeshPrimitive::TRIANGLE_FANS) { - fprintf(stderr, "Primitive type %s is not supported.\n", type_str); + fprintf(stderr, "ERROR: Primitive type %s is not supported.\n", type_str); return false; } } if (mesh->getPositions().empty()) { - fprintf(stderr, "Mesh %s has no vertices.\n", name.c_str()); + fprintf(stderr, "ERROR: Mesh %s has no vertices.\n", name.c_str()); return false; } @@ -409,11 +418,18 @@ void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me) size_t prim_poly_count = mpvc->getFaceCount(); size_t prim_loop_count = 0; - for (int index=0; index < prim_poly_count; index++) { - prim_loop_count += get_vertex_count(mpvc, index); + for (int index=0; index < prim_poly_count; index++) + { + int vcount = get_vertex_count(mpvc, index); + if (vcount > 0) { + prim_loop_count += vcount; + total_poly_count++; + } + else { + // TODO: this is a hole and not another polygon! + } } - total_poly_count += prim_poly_count; total_loop_count += prim_loop_count; break; @@ -683,9 +699,12 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me) COLLADAFW::IndexListArray& index_list_array_vcolor = mp->getColorIndicesArray(); for (unsigned int j = 0; j < prim_totpoly; j++) { - + // Vertices in polygon: int vcount = get_vertex_count(mpvc, j); + if (vcount < 0) { + continue; // TODO: add support for holes + } set_poly_indices(mpoly, mloop, loop_index, position_indices, vcount); diff --git a/source/blender/collada/collada.cpp b/source/blender/collada/collada.cpp index b64b10e0833..e1b8a2dd30a 100644 --- a/source/blender/collada/collada.cpp +++ b/source/blender/collada/collada.cpp @@ -81,8 +81,9 @@ int collada_export(Scene *sce, int use_texture_copies, int triangulate, - int use_object_instantiation, - int sort_by_name, + int use_object_instantiation, + int use_blender_profile, + int sort_by_name, BC_export_transformation_type export_transformation_type, int open_sim) { @@ -105,6 +106,7 @@ int collada_export(Scene *sce, export_settings.triangulate = triangulate != 0; export_settings.use_object_instantiation = use_object_instantiation != 0; + export_settings.use_blender_profile = use_blender_profile != 0; export_settings.sort_by_name = sort_by_name != 0; export_settings.export_transformation_type = export_transformation_type; export_settings.open_sim = open_sim != 0; diff --git a/source/blender/collada/collada.h b/source/blender/collada/collada.h index 6819a62fdf0..db8ea884222 100644 --- a/source/blender/collada/collada.h +++ b/source/blender/collada/collada.h @@ -78,6 +78,7 @@ int collada_export(struct Scene *sce, int triangulate, int use_object_instantiation, + int use_blender_profile, int sort_by_name, BC_export_transformation_type export_transformation_type, int open_sim); diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp index f8feed8145c..f0984fbc127 100644 --- a/source/blender/collada/collada_utils.cpp +++ b/source/blender/collada/collada_utils.cpp @@ -54,6 +54,8 @@ extern "C" { #include "BKE_scene.h" #include "BKE_DerivedMesh.h" +#include "ED_armature.h" + #include "WM_api.h" // XXX hrm, see if we can do without this #include "WM_types.h" @@ -366,3 +368,212 @@ void bc_triangulate_mesh(Mesh *me) BM_mesh_bm_to_me(bm, me, &bm_to_me_params); BM_mesh_free(bm); } + +/* +* A bone is a leaf when it has no children or all children are not connected. +*/ +bool bc_is_leaf_bone(Bone *bone) +{ + for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) { + if (child->flag & BONE_CONNECTED) + return false; + } + return true; +} + +EditBone *bc_get_edit_bone(bArmature * armature, char *name) { + EditBone *eBone; + + for (eBone = (EditBone *)armature->edbo->first; eBone; eBone = eBone->next) { + if (STREQ(name, eBone->name)) + return eBone; + } + + return NULL; + +} +int bc_set_layer(int bitfield, int layer) +{ + return bc_set_layer(bitfield, layer, true); /* enable */ +} + +int bc_set_layer(int bitfield, int layer, bool enable) +{ + int bit = 1u << layer; + + if (enable) + bitfield |= bit; + else + bitfield &= ~bit; + + return bitfield; +} + +/** +* BoneExtended is a helper class needed for the Bone chain finder +* See ArmatureImporter::fix_leaf_bones() +* and ArmatureImporter::connect_bone_chains() +**/ + +BoneExtended::BoneExtended(EditBone *aBone) +{ + this->set_name(aBone->name); + this->chain_length = 0; + this->is_leaf = false; + this->tail[0] = 0.0f; + this->tail[1] = 0.5f; + this->tail[2] = 0.0f; + this->use_connect = -1; + this->roll = 0; + this->bone_layers = 0; + + this->has_custom_tail = false; + this->has_custom_roll = false; +} + +char *BoneExtended::get_name() +{ + return name; +} + +void BoneExtended::set_name(char *aName) +{ + BLI_strncpy(name, aName, MAXBONENAME); +} + +int BoneExtended::get_chain_length() +{ + return chain_length; +} + +void BoneExtended::set_chain_length(const int aLength) +{ + chain_length = aLength; +} + +void BoneExtended::set_leaf_bone(bool state) +{ + is_leaf = state; +} + +bool BoneExtended::is_leaf_bone() +{ + return is_leaf; +} + +void BoneExtended::set_roll(float roll) +{ + this->roll = roll; + this->has_custom_roll = true; +} + +bool BoneExtended::has_roll() +{ + return this->has_custom_roll; +} + +float BoneExtended::get_roll() +{ + return this->roll; +} + +void BoneExtended::set_tail(float vec[]) +{ + this->tail[0] = vec[0]; + this->tail[1] = vec[1]; + this->tail[2] = vec[2]; + this->has_custom_tail = true; +} + +bool BoneExtended::has_tail() +{ + return this->has_custom_tail; +} + +float *BoneExtended::get_tail() +{ + return this->tail; +} + +inline bool isInteger(const std::string & s) +{ + if (s.empty() || ((!isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) return false; + + char * p; + strtol(s.c_str(), &p, 10); + + return (*p == 0); +} + +void BoneExtended::set_bone_layers(std::string layerString, std::vector<std::string> &layer_labels) +{ + std::stringstream ss(layerString); + std::string layer; + int pos; + + while (ss >> layer) { + + /* Blender uses numbers to specify layers*/ + if (isInteger(layer)) + { + pos = atoi(layer.c_str()); + if (pos >= 0 && pos < 32) { + this->bone_layers = bc_set_layer(this->bone_layers, pos); + continue; + } + } + + /* layer uses labels (not supported by blender). Map to layer numbers:*/ + pos = find(layer_labels.begin(), layer_labels.end(), layer) - layer_labels.begin(); + if (pos >= layer_labels.size()) { + layer_labels.push_back(layer); /* remember layer number for future usage*/ + } + + if (pos > 31) + { + fprintf(stderr, "Too many layers in Import. Layer %s mapped to Blender layer 31\n", layer.c_str()); + pos = 31; + } + + /* If numeric layers and labeled layers are used in parallel (unlikely), + we get a potential mixup. Just leave as is for now. + */ + this->bone_layers = bc_set_layer(this->bone_layers, pos); + + } +} + +std::string BoneExtended::get_bone_layers(int bitfield) +{ + std::string result = ""; + std::string sep = ""; + int bit = 1u; + + std::ostringstream ss; + for (int i = 0; i < 32; i++) + { + if (bit & bitfield) + { + ss << sep << i; + sep = " "; + } + bit = bit << 1; + } + return ss.str(); +} + +int BoneExtended::get_bone_layers() +{ + return (bone_layers == 0) ? 1 : bone_layers; // ensure that the bone is in at least one bone layer! +} + + +void BoneExtended::set_use_connect(int use_connect) +{ + this->use_connect = use_connect; +} + +int BoneExtended::get_use_connect() +{ + return this->use_connect; +} diff --git a/source/blender/collada/collada_utils.h b/source/blender/collada/collada_utils.h index 4bc2f55cf33..74f8dca1492 100644 --- a/source/blender/collada/collada_utils.h +++ b/source/blender/collada/collada_utils.h @@ -34,6 +34,7 @@ #include <vector> #include <map> +#include <algorithm> extern "C" { #include "DNA_object_types.h" @@ -46,6 +47,7 @@ extern "C" { #include "BLI_linklist.h" #include "BLI_utildefines.h" +#include "BLI_string.h" #include "BKE_context.h" #include "BKE_object.h" @@ -87,7 +89,10 @@ extern void bc_match_scale(Object *ob, UnitConverter &bc_unit, bool scale_to_sce extern void bc_match_scale(std::vector<Object *> *objects_done, UnitConverter &unit_converter, bool scale_to_scene); extern void bc_triangulate_mesh(Mesh *me); - +extern bool bc_is_leaf_bone(Bone *bone); +extern EditBone *bc_get_edit_bone(bArmature * armature, char *name); +extern int bc_set_layer(int bitfield, int layer, bool enable); +extern int bc_set_layer(int bitfield, int layer); class BCPolygonNormalsIndices { @@ -105,4 +110,48 @@ class BCPolygonNormalsIndices }; +class BoneExtended { + +private: + char name[MAXBONENAME]; + int chain_length; + bool is_leaf; + float tail[3]; + float roll; + + int bone_layers; + bool use_connect; + bool has_custom_tail; + bool has_custom_roll; + +public: + + BoneExtended(EditBone *aBone); + + void set_name(char *aName); + char *get_name(); + + void set_chain_length(const int aLength); + int get_chain_length(); + + void set_leaf_bone(bool state); + bool is_leaf_bone(); + + void set_bone_layers(std::string layers, std::vector<std::string> &layer_labels); + int get_bone_layers(); + static std::string get_bone_layers(int bitfield); + + void set_roll(float roll); + bool has_roll(); + float get_roll(); + + void set_tail(float *vec); + float *get_tail(); + bool has_tail(); + + void set_use_connect(int use_connect); + int get_use_connect(); +}; + + #endif diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt index 2b4df85f29c..fd2a521bec5 100644 --- a/source/blender/depsgraph/CMakeLists.txt +++ b/source/blender/depsgraph/CMakeLists.txt @@ -25,8 +25,6 @@ set(INC . - intern - util ../blenkernel ../blenlib ../bmesh @@ -42,45 +40,50 @@ set(INC_SYS ) set(SRC + intern/builder/deg_builder.cc + intern/builder/deg_builder_cycle.cc + intern/builder/deg_builder_nodes.cc + intern/builder/deg_builder_pchanmap.cc + intern/builder/deg_builder_relations.cc + intern/builder/deg_builder_transitive.cc + intern/debug/deg_debug_graphviz.cc + intern/eval/deg_eval.cc + intern/eval/deg_eval_debug.cc + intern/eval/deg_eval_flush.cc + intern/nodes/deg_node.cc + intern/nodes/deg_node_component.cc + intern/nodes/deg_node_operation.cc intern/depsgraph.cc - intern/depsnode.cc - intern/depsnode_component.cc - intern/depsnode_operation.cc intern/depsgraph_build.cc - intern/depsgraph_build_nodes.cc - intern/depsgraph_build_relations.cc intern/depsgraph_debug.cc intern/depsgraph_eval.cc intern/depsgraph_query.cc - intern/depsgraph_queue.cc intern/depsgraph_tag.cc intern/depsgraph_type_defines.cc - util/depsgraph_util_cycle.cc - util/depsgraph_util_pchanmap.cc - util/depsgraph_util_transitive.cc DEG_depsgraph.h DEG_depsgraph_build.h DEG_depsgraph_debug.h DEG_depsgraph_query.h + + intern/builder/deg_builder.h + intern/builder/deg_builder_cycle.h + intern/builder/deg_builder_nodes.h + intern/builder/deg_builder_pchanmap.h + intern/builder/deg_builder_relations.h + intern/builder/deg_builder_transitive.h + intern/eval/deg_eval.h + intern/eval/deg_eval_debug.h + intern/eval/deg_eval_flush.h + intern/nodes/deg_node.h + intern/nodes/deg_node_component.h + intern/nodes/deg_node_operation.h intern/depsgraph.h - intern/depsnode.h - intern/depsnode_component.h - intern/depsnode_operation.h - intern/depsnode_opcodes.h - intern/depsgraph_build.h - intern/depsgraph_debug.h intern/depsgraph_intern.h - intern/depsgraph_queue.h intern/depsgraph_types.h - util/depsgraph_util_cycle.h - util/depsgraph_util_function.h - util/depsgraph_util_hash.h - util/depsgraph_util_map.h - util/depsgraph_util_pchanmap.h - util/depsgraph_util_set.h - util/depsgraph_util_transitive.h + util/deg_util_function.h + util/deg_util_hash.h ) if(WITH_CXX11) diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h index f37ba71ab65..d1de83ec8a9 100644 --- a/source/blender/depsgraph/DEG_depsgraph.h +++ b/source/blender/depsgraph/DEG_depsgraph.h @@ -131,9 +131,6 @@ void DEG_ids_clear_recalc(struct Main *bmain); /* Update Flushing ------------------------------- */ -/* Flush updates */ -void DEG_graph_flush_updates(struct Main *bmain, Depsgraph *graph); - /* Flush updates for all IDs */ void DEG_ids_flush_tagged(struct Main *bmain); @@ -144,11 +141,6 @@ void DEG_ids_check_recalc(struct Main *bmain, struct Scene *scene, bool time); -/* Clear all update tags - * - For aborted updates, or after successful evaluation - */ -void DEG_graph_clear_tags(Depsgraph *graph); - /* ************************************************ */ /* Evaluation Engine API */ diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h index f680c47247a..49b648c7dae 100644 --- a/source/blender/depsgraph/DEG_depsgraph_build.h +++ b/source/blender/depsgraph/DEG_depsgraph_build.h @@ -43,9 +43,6 @@ struct Depsgraph; struct Main; struct Scene; -struct PointerRNA; -struct PropertyRNA; - #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/depsgraph/DEG_depsgraph_debug.h b/source/blender/depsgraph/DEG_depsgraph_debug.h index 374fad63c34..0d19b8e1e97 100644 --- a/source/blender/depsgraph/DEG_depsgraph_debug.h +++ b/source/blender/depsgraph/DEG_depsgraph_debug.h @@ -39,13 +39,10 @@ extern "C" { #endif -struct DepsgraphSettings; struct GHash; struct ID; struct Depsgraph; -struct DepsNode; -struct DepsRelation; /* ************************************************ */ /* Statistics */ diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h index 60d673d4c5b..ccd204a2083 100644 --- a/source/blender/depsgraph/DEG_depsgraph_query.h +++ b/source/blender/depsgraph/DEG_depsgraph_query.h @@ -19,7 +19,7 @@ * All rights reserved. * * Original Author: Joshua Leung - * Contributor(s): None Yet + * Contributor(s): Sergey Sharybin * * ***** END GPL LICENSE BLOCK ***** */ @@ -33,155 +33,14 @@ #ifndef __DEG_DEPSGRAPH_QUERY_H__ #define __DEG_DEPSGRAPH_QUERY_H__ -struct ListBase; struct ID; struct Depsgraph; -struct DepsNode; -struct DepsRelation; #ifdef __cplusplus extern "C" { #endif -/* ************************************************ */ -/* Type Defines */ - -/* FilterPredicate Callback - * - * Defines a callback function which can be supplied to check whether a - * node is relevant or not. - * - * < graph: Depsgraph that we're traversing - * < node: The node to check - * < userdata: FilterPredicate state data (as needed) - * > returns: True if node is relevant - */ -typedef bool (*DEG_FilterPredicate)(const struct Depsgraph *graph, const struct DepsNode *node, void *userdata); - - -/* Node Operation - * - * Performs some action on the given node, provided that the node was - * deemed to be relevant to operate on. - * - * < graph: Depsgraph that we're traversing - * < node: The node to perform operation on/with - * < userdata: Node Operation's state data (as needed) - * > returns: True if traversal should be aborted at this point - */ -typedef bool (*DEG_NodeOperation)(const struct Depsgraph *graph, struct DepsNode *node, void *userdata); - -/* ************************************************ */ -/* Low-Level Filtering API */ - -/* Create a filtered copy of the given graph which contains only the - * nodes which fulfill the criteria specified using the FilterPredicate - * passed in. - * - * < graph: The graph to be copied and filtered - * < filter: FilterPredicate used to check which nodes should be included - * (If null, full graph is copied as-is) - * < userdata: State data for filter (as necessary) - * - * > returns: a full copy of all the relevant nodes - the matching subgraph - */ -// XXX: is there any need for extra settings/options for how the filtering goes? -Depsgraph *DEG_graph_filter(const struct Depsgraph *graph, DEG_FilterPredicate *filter, void *userdata); - - -/* Traverse nodes in graph which are deemed relevant, - * performing the provided operation on the nodes. - * - * < graph: The graph to perform operations on - * < filter: FilterPredicate used to check which nodes should be included - * (If null, all nodes are considered valid targets) - * < filter_data: Custom state data for FilterPredicate - * (Note: This can be the same as op_data, where appropriate) - * < op: NodeOperation to perform on each node - * (If null, no graph traversal is performed for efficiency) - * < op_data: Custom state data for NodeOperation - * (Note: This can be the same as filter_data, where appropriate) - */ -void DEG_graph_traverse(const struct Depsgraph *graph, - DEG_FilterPredicate *filter, void *filter_data, - DEG_NodeOperation *op, void *op_data); - -/* ************************************************ */ -/* Node-Based Operations */ -// XXX: do we want to be able to attach conditional requirements here? - -/* Find an (outer) node matching given conditions - * ! Assumes that there will only be one such node, or that only the first one matters - * - * < graph: a dependency graph which may or may not contain a node matching these requirements - * < query: query conditions for the criteria that the node must satisfy - */ -//DepsNode *DEG_node_find(const Depsgraph *graph, DEG_QueryConditions *query); - -/* Topology Queries (Direct) ---------------------- */ - -/* Get list of nodes which directly depend on given node - * - * > result: list to write results to - * < node: the node to find the children/dependents of - */ -void DEG_node_get_children(struct ListBase *result, const struct DepsNode *node); - - -/* Get list of nodes which given node directly depends on - * - * > result: list to write results to - * < node: the node to find the dependencies of - */ -void DEG_node_get_dependencies(struct ListBase *result, const struct DepsNode *node); - - -/* Topology Queries (Subgraph) -------------------- */ -// XXX: given that subgraphs potentially involve many interconnected nodes, we currently -// just spit out a copy of the subgraph which matches. This works well for the cases -// where these are used - mostly for efficient updating of subsets of the nodes. - -// XXX: allow supplying a filter predicate to provide further filtering/pruning? - - -/* Get all descendants of a node - * - * That is, get the subgraph / subset of nodes which are dependent - * on the results of the given node. - */ -Depsgraph *DEG_node_get_descendants(const struct Depsgraph *graph, const struct DepsNode *node); - - -/* Get all ancestors of a node - * - * That is, get the subgraph / subset of nodes which the given node - * is dependent on in order to be evaluated. - */ -Depsgraph *DEG_node_get_ancestors(const struct Depsgraph *graph, const struct DepsNode *node); - -/* ************************************************ */ -/* Higher-Level Queries */ - -/* Get ID-blocks which would be affected if specified ID is modified - * < only_direct: True = Only ID-blocks with direct relationships to ID-block will be returned - * - * > result: (LinkData : ID) a list of ID-blocks matching the specified criteria - * > returns: number of matching ID-blocks - */ -size_t DEG_query_affected_ids(struct ListBase *result, const struct ID *id, const bool only_direct); - - -/* Get ID-blocks which are needed to update/evaluate specified ID - * < only_direct: True = Only ID-blocks with direct relationships to ID-block will be returned - * - * > result: (LinkData : ID) a list of ID-blocks matching the specified criteria - * > returns: number of matching ID-blocks - */ -size_t DEG_query_required_ids(struct ListBase *result, const struct ID *id, const bool only_direct); - -/* ************************************************ */ - /* Check if given ID type was tagged for update. */ bool DEG_id_type_tagged(struct Main *bmain, short idtype); diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc new file mode 100644 index 00000000000..9f80c21a6a4 --- /dev/null +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -0,0 +1,129 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 Blender Foundation. + * All rights reserved. + * + * Original Author: Sergey Sharybin + * Contributor(s): None Yet + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/build/deg_builder.cc + * \ingroup depsgraph + */ + +#include "intern/builder/deg_builder.h" + +// TODO(sergey): Use own wrapper over STD. +#include <stack> + +#include "DNA_anim_types.h" + +#include "BLI_utildefines.h" +#include "BLI_ghash.h" + +#include "intern/depsgraph.h" +#include "intern/depsgraph_types.h" +#include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_operation.h" + +#include "util/deg_util_foreach.h" + +namespace DEG { + +string deg_fcurve_id_name(const FCurve *fcu) +{ + char index_buf[32]; + // TODO(sergey): Use int-to-string utility or so. + BLI_snprintf(index_buf, sizeof(index_buf), "[%d]", fcu->array_index); + return string(fcu->rna_path) + index_buf; +} + +void deg_graph_build_finalize(Depsgraph *graph) +{ + std::stack<OperationDepsNode *> stack; + + foreach (OperationDepsNode *node, graph->operations) { + IDDepsNode *id_node = node->owner->owner; + node->done = 0; + node->num_links_pending = 0; + foreach (DepsRelation *rel, node->outlinks) { + if ((rel->from->type == DEPSNODE_TYPE_OPERATION) && + (rel->flag & DEPSREL_FLAG_CYCLIC) == 0) + { + ++node->num_links_pending; + } + } + if (node->num_links_pending == 0) { + stack.push(node); + node->done = 1; + } + node->owner->layers = id_node->layers; + id_node->id->tag |= LIB_TAG_DOIT; + } + + while (!stack.empty()) { + OperationDepsNode *node = stack.top(); + stack.pop(); + /* Flush layers to parents. */ + foreach (DepsRelation *rel, node->inlinks) { + if (rel->from->type == DEPSNODE_TYPE_OPERATION) { + OperationDepsNode *from = (OperationDepsNode *)rel->from; + from->owner->layers |= node->owner->layers; + } + } + /* Schedule parent nodes. */ + foreach (DepsRelation *rel, node->inlinks) { + if (rel->from->type == DEPSNODE_TYPE_OPERATION) { + OperationDepsNode *from = (OperationDepsNode *)rel->from; + if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) { + BLI_assert(from->num_links_pending > 0); + --from->num_links_pending; + } + if (from->num_links_pending == 0 && from->done == 0) { + stack.push(from); + from->done = 1; + } + } + } + } + + /* Re-tag IDs for update if it was tagged before the relations update tag. */ + GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, graph->id_hash) + { + GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp, id_node->components) + { + id_node->layers |= comp->layers; + } + GHASH_FOREACH_END(); + + ID *id = id_node->id; + if (id->tag & LIB_TAG_ID_RECALC_ALL && + id->tag & LIB_TAG_DOIT) + { + id_node->tag_update(graph); + id->tag &= ~LIB_TAG_DOIT; + } + id_node->finalize_build(); + } + GHASH_FOREACH_END(); +} + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder.h b/source/blender/depsgraph/intern/builder/deg_builder.h new file mode 100644 index 00000000000..7ecb4b20684 --- /dev/null +++ b/source/blender/depsgraph/intern/builder/deg_builder.h @@ -0,0 +1,46 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 Blender Foundation. + * All rights reserved. + * + * Original Author: Sergey Sharybin + * Contributor(s): None Yet + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/build/deg_builder.h + * \ingroup depsgraph + */ + +#pragma once + +#include "intern/depsgraph_types.h" + +struct FCurve; + +namespace DEG { + +struct Depsgraph; + +/* Get unique identifier for FCurves and Drivers */ +string deg_fcurve_id_name(const FCurve *fcu); + +void deg_graph_build_finalize(struct Depsgraph *graph); + +} // namespace DEG diff --git a/source/blender/depsgraph/util/depsgraph_util_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc index 5eae8c087ad..225cc64ae4d 100644 --- a/source/blender/depsgraph/util/depsgraph_util_cycle.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc @@ -23,28 +23,30 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/util/depsgraph_util_cycle.cc +/** \file blender/depsgraph/intern/builder/deg_builder_cycle.cc * \ingroup depsgraph */ +#include "intern/builder/deg_builder_cycle.h" + +// TOO(sergey): Use some wrappers over those? #include <cstdio> #include <cstdlib> #include <stack> extern "C" { #include "BLI_utildefines.h" +} -#include "DNA_ID.h" +#include "util/deg_util_foreach.h" -#include "RNA_access.h" -#include "RNA_types.h" -} +#include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_operation.h" -#include "depsgraph_util_cycle.h" -#include "depsgraph.h" -#include "depsnode.h" -#include "depsnode_component.h" -#include "depsnode_operation.h" +#include "intern/depsgraph.h" + +namespace DEG { struct StackEntry { OperationDepsNode *node; @@ -62,17 +64,9 @@ void deg_graph_detect_cycles(Depsgraph *graph) const int NODE_IN_STACK = 2; std::stack<StackEntry> traversal_stack; - for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin(); - it_op != graph->operations.end(); - ++it_op) - { - OperationDepsNode *node = *it_op; + foreach (OperationDepsNode *node, graph->operations) { bool has_inlinks = false; - for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin(); - it_rel != node->inlinks.end(); - ++it_rel) - { - DepsRelation *rel = *it_rel; + foreach (DepsRelation *rel, node->inlinks) { if (rel->from->type == DEPSNODE_TYPE_OPERATION) { has_inlinks = true; } @@ -94,11 +88,7 @@ void deg_graph_detect_cycles(Depsgraph *graph) StackEntry &entry = traversal_stack.top(); OperationDepsNode *node = entry.node; bool all_child_traversed = true; - for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin(); - it_rel != node->outlinks.end(); - ++it_rel) - { - DepsRelation *rel = *it_rel; + foreach (DepsRelation *rel, node->outlinks) { if (rel->to->type == DEPSNODE_TYPE_OPERATION) { OperationDepsNode *to = (OperationDepsNode *)rel->to; if (to->done == NODE_IN_STACK) { @@ -138,3 +128,5 @@ void deg_graph_detect_cycles(Depsgraph *graph) } } } + +} // namespace DEG diff --git a/source/blender/depsgraph/util/depsgraph_util_cycle.h b/source/blender/depsgraph/intern/builder/deg_builder_cycle.h index fac38b61057..386fbd80d19 100644 --- a/source/blender/depsgraph/util/depsgraph_util_cycle.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.h @@ -23,15 +23,18 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/util/depsgraph_util_cycle.h +/** \file blender/depsgraph/intern/builder/deg_builder_cycle.h * \ingroup depsgraph */ -#ifndef __DEPSGRAPH_UTIL_CYCLE_H__ -#define __DEPSGRAPH_UTIL_CYCLE_H__ + +#pragma once + +namespace DEG { struct Depsgraph; +/* Detect and solve dependency cycles. */ void deg_graph_detect_cycles(Depsgraph *graph); -#endif /* __DEPSGRAPH_UTIL_CYCLE_H__ */ +} // namespace DEG diff --git a/source/blender/depsgraph/intern/depsgraph_build_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index c29532a02c6..17b6acfd680 100644 --- a/source/blender/depsgraph/intern/depsgraph_build_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -24,12 +24,14 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/depsgraph_build_nodes.cc +/** \file blender/depsgraph/intern/builder/deg_build_nodes.cc * \ingroup depsgraph * * Methods for constructing depsgraph's nodes */ +#include "intern/builder/deg_builder_nodes.h" + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -95,12 +97,14 @@ extern "C" { #include "RNA_types.h" } /* extern "C" */ -#include "depsnode.h" -#include "depsnode_component.h" -#include "depsnode_operation.h" -#include "depsgraph_types.h" -#include "depsgraph_build.h" -#include "depsgraph_intern.h" +#include "intern/builder/deg_builder.h" +#include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_operation.h" +#include "intern/depsgraph_types.h" +#include "intern/depsgraph_intern.h" + +namespace DEG { /* ************ */ /* Node Builder */ @@ -215,6 +219,17 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node( return add_operation_node(comp_node, optype, op, opcode, description); } +OperationDepsNode *DepsgraphNodeBuilder::add_operation_node( + ID *id, + eDepsNode_Type comp_type, + eDepsOperation_Type optype, + DepsEvalOperationCb op, + eDepsOperation_Code opcode, + const string& description) +{ + return add_operation_node(id, comp_type, "", optype, op, opcode, description); +} + bool DepsgraphNodeBuilder::has_operation_node(ID *id, eDepsNode_Type comp_type, const string &comp_name, @@ -235,6 +250,14 @@ OperationDepsNode *DepsgraphNodeBuilder::find_operation_node( return comp_node->has_operation(opcode, description); } +OperationDepsNode *DepsgraphNodeBuilder::find_operation_node( + ID *id, + eDepsNode_Type comp_type, + eDepsOperation_Code opcode, + const string& description) +{ + return find_operation_node(id, comp_type, "", opcode, description); +} /* **** Build functions for entity nodes **** */ @@ -341,7 +364,7 @@ SubgraphDepsNode *DepsgraphNodeBuilder::build_subgraph(Group *group) return NULL; /* create new subgraph's data */ - Depsgraph *subgraph = DEG_graph_new(); + Depsgraph *subgraph = reinterpret_cast<Depsgraph *>(DEG_graph_new()); DepsgraphNodeBuilder subgraph_builder(m_bmain, subgraph); @@ -379,11 +402,11 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob) IDDepsNode *id_node = add_id_node(&ob->id); id_node->layers = base->lay; + ob->customdata_mask = 0; /* standard components */ build_object_transform(scene, ob); - /* object data */ if (ob->data) { /* type-specific data... */ @@ -1187,3 +1210,5 @@ void DepsgraphNodeBuilder::build_gpencil(bGPdata *gpd) */ build_animdata(gpd_id); } + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h new file mode 100644 index 00000000000..6ee0b8406a1 --- /dev/null +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -0,0 +1,153 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Original Author: Lukas Toenne + * Contributor(s): None Yet + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/builder/deg_builder_nodes.h + * \ingroup depsgraph + */ + +#pragma once + +#include "intern/depsgraph_types.h" + +struct Base; +struct bGPdata; +struct ListBase; +struct GHash; +struct ID; +struct FCurve; +struct Group; +struct Key; +struct Main; +struct Material; +struct MTex; +struct bNodeTree; +struct Object; +struct bPoseChannel; +struct bConstraint; +struct Scene; +struct Tex; +struct World; + +struct PropertyRNA; + +namespace DEG { + +struct Depsgraph; +struct DepsNode; +struct RootDepsNode; +struct SubgraphDepsNode; +struct IDDepsNode; +struct TimeSourceDepsNode; +struct ComponentDepsNode; +struct OperationDepsNode; + +struct DepsgraphNodeBuilder { + DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph); + ~DepsgraphNodeBuilder(); + + RootDepsNode *add_root_node(); + IDDepsNode *add_id_node(ID *id); + TimeSourceDepsNode *add_time_source(ID *id); + + ComponentDepsNode *add_component_node(ID *id, + eDepsNode_Type comp_type, + const string& comp_name = ""); + + OperationDepsNode *add_operation_node(ComponentDepsNode *comp_node, + eDepsOperation_Type optype, + DepsEvalOperationCb op, + eDepsOperation_Code opcode, + const string& description = ""); + OperationDepsNode *add_operation_node(ID *id, + eDepsNode_Type comp_type, + const string& comp_name, + eDepsOperation_Type optype, + DepsEvalOperationCb op, + eDepsOperation_Code opcode, + const string& description = ""); + OperationDepsNode *add_operation_node(ID *id, + eDepsNode_Type comp_type, + eDepsOperation_Type optype, + DepsEvalOperationCb op, + eDepsOperation_Code opcode, + const string& description = ""); + + bool has_operation_node(ID *id, + eDepsNode_Type comp_type, + const string& comp_name, + eDepsOperation_Code opcode, + const string& description = ""); + + OperationDepsNode *find_operation_node(ID *id, + eDepsNode_Type comp_type, + const string &comp_name, + eDepsOperation_Code opcode, + const string &description = ""); + + OperationDepsNode *find_operation_node(ID *id, + eDepsNode_Type comp_type, + eDepsOperation_Code opcode, + const string &description = ""); + + void build_scene(Main *bmain, Scene *scene); + SubgraphDepsNode *build_subgraph(Group *group); + void build_group(Scene *scene, Base *base, Group *group); + void build_object(Scene *scene, Base *base, Object *ob); + void build_object_transform(Scene *scene, Object *ob); + void build_object_constraints(Scene *scene, Object *ob); + void build_pose_constraints(Object *ob, bPoseChannel *pchan); + void build_rigidbody(Scene *scene); + void build_particles(Scene *scene, Object *ob); + void build_animdata(ID *id); + OperationDepsNode *build_driver(ID *id, FCurve *fcurve); + void build_ik_pose(Scene *scene, + Object *ob, + bPoseChannel *pchan, + bConstraint *con); + void build_splineik_pose(Scene *scene, + Object *ob, + bPoseChannel *pchan, + bConstraint *con); + void build_rig(Scene *scene, Object *ob); + void build_proxy_rig(Object *ob); + void build_shapekeys(Key *key); + void build_obdata_geom(Scene *scene, Object *ob); + void build_camera(Object *ob); + void build_lamp(Object *ob); + void build_nodetree(DepsNode *owner_node, bNodeTree *ntree); + void build_material(DepsNode *owner_node, Material *ma); + void build_texture(DepsNode *owner_node, Tex *tex); + void build_texture_stack(DepsNode *owner_node, MTex **texture_stack); + void build_world(World *world); + void build_compositor(Scene *scene); + void build_gpencil(bGPdata *gpd); + +protected: + Main *m_bmain; + Depsgraph *m_graph; +}; + +} // namespace DEG diff --git a/source/blender/depsgraph/util/depsgraph_util_pchanmap.cc b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc index 80b37ec622d..0e78df52ff8 100644 --- a/source/blender/depsgraph/util/depsgraph_util_pchanmap.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc @@ -24,11 +24,11 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/util/depsgraph_util_pchanmap.cc +/** \file blender/depsgraph/intern/builder/deg_builder_pchanmap.h * \ingroup depsgraph */ -#include "depsgraph_util_pchanmap.h" +#include "intern/builder/deg_builder_pchanmap.h" #include <stdio.h> #include <string.h> @@ -38,6 +38,8 @@ extern "C" { #include "BLI_ghash.h" } +namespace DEG { + static void free_rootpchanmap_valueset(void *val) { /* Just need to free the set itself - the names stored are all references. */ @@ -48,13 +50,13 @@ static void free_rootpchanmap_valueset(void *val) RootPChanMap::RootPChanMap() { /* Just create empty map. */ - m_map = BLI_ghash_str_new("RootPChanMap"); + map_ = BLI_ghash_str_new("RootPChanMap"); } RootPChanMap::~RootPChanMap() { /* Free the map, and all the value sets. */ - BLI_ghash_free(m_map, NULL, free_rootpchanmap_valueset); + BLI_ghash_free(map_, NULL, free_rootpchanmap_valueset); } /* Debug contents of map */ @@ -64,7 +66,7 @@ void RootPChanMap::print_debug() GSetIterator it2; printf("Root PChan Map:\n"); - GHASH_ITER(it1, m_map) { + GHASH_ITER(it1, map_) { const char *item = (const char *)BLI_ghashIterator_getKey(&it1); GSet *values = (GSet *)BLI_ghashIterator_getValue(&it1); @@ -80,11 +82,11 @@ void RootPChanMap::print_debug() /* Add a mapping. */ void RootPChanMap::add_bone(const char *bone, const char *root) { - if (BLI_ghash_haskey(m_map, bone)) { + if (BLI_ghash_haskey(map_, bone)) { /* Add new entry, but only add the root if it doesn't already * exist in there. */ - GSet *values = (GSet *)BLI_ghash_lookup(m_map, bone); + GSet *values = (GSet *)BLI_ghash_lookup(map_, bone); BLI_gset_add(values, (void *)root); } else { @@ -92,7 +94,7 @@ void RootPChanMap::add_bone(const char *bone, const char *root) GSet *values = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "RootPChanMap Value Set"); - BLI_ghash_insert(m_map, (void *)bone, (void *)values); + BLI_ghash_insert(map_, (void *)bone, (void *)values); /* Add new entry now. */ BLI_gset_insert(values, (void *)root); @@ -103,20 +105,20 @@ void RootPChanMap::add_bone(const char *bone, const char *root) bool RootPChanMap::has_common_root(const char *bone1, const char *bone2) { /* Ensure that both are in the map... */ - if (BLI_ghash_haskey(m_map, bone1) == false) { + if (BLI_ghash_haskey(map_, bone1) == false) { //fprintf("RootPChanMap: bone1 '%s' not found (%s => %s)\n", bone1, bone1, bone2); //print_debug(); return false; } - if (BLI_ghash_haskey(m_map, bone2) == false) { + if (BLI_ghash_haskey(map_, bone2) == false) { //fprintf("RootPChanMap: bone2 '%s' not found (%s => %s)\n", bone2, bone1, bone2); //print_debug(); return false; } - GSet *bone1_roots = (GSet *)BLI_ghash_lookup(m_map, (void *)bone1); - GSet *bone2_roots = (GSet *)BLI_ghash_lookup(m_map, (void *)bone2); + GSet *bone1_roots = (GSet *)BLI_ghash_lookup(map_, (void *)bone1); + GSet *bone2_roots = (GSet *)BLI_ghash_lookup(map_, (void *)bone2); GSetIterator it1, it2; GSET_ITER(it1, bone1_roots) { @@ -134,3 +136,5 @@ bool RootPChanMap::has_common_root(const char *bone1, const char *bone2) //fprintf("RootPChanMap: No common root found (%s => %s)\n", bone1, bone2); return false; } + +} // namespace DEG diff --git a/source/blender/depsgraph/util/depsgraph_util_pchanmap.h b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h index b7f4c495933..233d8602fce 100644 --- a/source/blender/depsgraph/util/depsgraph_util_pchanmap.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h @@ -24,12 +24,15 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/util/depsgraph_util_pchanmap.h +/** \file blender/depsgraph/intern/builder/deg_builder_pchanmap.h * \ingroup depsgraph */ -#ifndef __DEPSGRAPH_UTIL_PCHANMAP_H__ -#define __DEPSGRAPH_UTIL_PCHANMAP_H__ +#pragma once + +struct GHash; + +namespace DEG { struct RootPChanMap { /* ctor and dtor - Create and free the internal map respectively. */ @@ -45,7 +48,7 @@ struct RootPChanMap { /* Check if there's a common root bone between two bones. */ bool has_common_root(const char *bone1, const char *bone2); -private: +protected: /* The actual map: * - Keys are "strings" (const char *) - not dynamically allocated. * - Values are "sets" (const char *) - not dynamically allocated. @@ -53,7 +56,7 @@ private: * We don't use the C++ maps here, as it's more convenient to use * Blender's GHash and be able to compare by-value instead of by-ref. */ - struct GHash *m_map; + struct GHash *map_; }; -#endif /* __DEPSGRAPH_UTIL_PCHANMAP_H__ */ +} // namespace DEG diff --git a/source/blender/depsgraph/intern/depsgraph_build_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 23d3b391f8a..6564292e7f4 100644 --- a/source/blender/depsgraph/intern/depsgraph_build_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -24,12 +24,14 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/depsgraph_build_relations.cc +/** \file blender/depsgraph/intern/builder/deg_builder_relations.cc * \ingroup depsgraph * * Methods for constructing depsgraph */ +#include "intern/builder/deg_builder_relations.h" + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -91,15 +93,19 @@ extern "C" { #include "RNA_types.h" } /* extern "C" */ -#include "depsnode.h" -#include "depsnode_component.h" -#include "depsnode_operation.h" -#include "depsgraph_build.h" -#include "depsgraph_debug.h" -#include "depsgraph_intern.h" -#include "depsgraph_types.h" +#include "intern/builder/deg_builder.h" +#include "intern/builder/deg_builder_pchanmap.h" + +#include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_operation.h" + +#include "intern/depsgraph_intern.h" +#include "intern/depsgraph_types.h" + +#include "util/deg_util_foreach.h" -#include "depsgraph_util_pchanmap.h" +namespace DEG { /* ***************** */ /* Relations Builder */ @@ -302,6 +308,19 @@ void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene) if (scene->gpd) { build_gpencil(&scene->id, scene->gpd); } + + for (Depsgraph::OperationNodes::const_iterator it_op = m_graph->operations.begin(); + it_op != m_graph->operations.end(); + ++it_op) + { + OperationDepsNode *node = *it_op; + IDDepsNode *id_node = node->owner->owner; + ID *id = id_node->id; + if (GS(id->name) == ID_OB) { + Object *object = (Object *)id; + object->customdata_mask |= node->customdata_mask; + } + } } void DepsgraphRelationBuilder::build_group(Main *bmain, @@ -466,8 +485,12 @@ void DepsgraphRelationBuilder::build_object_parent(Object *ob) { ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_GEOMETRY); add_relation(parent_key, ob_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Vertex Parent"); + /* XXX not sure what this is for or how you could be done properly - lukas */ - //parent_node->customdata_mask |= CD_MASK_ORIGINDEX; + OperationDepsNode *parent_node = find_operation_node(parent_key); + if (parent_node != NULL) { + parent_node->customdata_mask |= CD_MASK_ORIGINDEX; + } ComponentKey transform_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM); add_relation(transform_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Vertex Parent TFM"); @@ -618,7 +641,10 @@ void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode add_relation(target_key, constraint_op_key, DEPSREL_TYPE_GEOMETRY_EVAL, cti->name); if (ct->tar->type == OB_MESH) { - //node2->customdata_mask |= CD_MASK_MDEFORMVERT; + OperationDepsNode *node2 = find_operation_node(target_key); + if (node2 != NULL) { + node2->customdata_mask |= CD_MASK_MDEFORMVERT; + } } } else if (con->type == CONSTRAINT_TYPE_SHRINKWRAP) { @@ -759,8 +785,7 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) if (arm_node && bone_name) { /* find objects which use this, and make their eval callbacks depend on this */ - DEPSNODE_RELATIONS_ITER_BEGIN(arm_node->outlinks, rel) - { + foreach (DepsRelation *rel, arm_node->outlinks) { IDDepsNode *to_node = (IDDepsNode *)rel->to; /* we only care about objects with pose data which use this... */ @@ -774,7 +799,6 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) } } } - DEPSNODE_RELATIONS_ITER_END; /* free temp data */ MEM_freeN(bone_name); @@ -1067,7 +1091,10 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob, add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name); if (data->tar->type == OB_MESH) { - //node2->customdata_mask |= CD_MASK_MDEFORMVERT; + OperationDepsNode *node2 = find_operation_node(target_key); + if (node2 != NULL) { + node2->customdata_mask |= CD_MASK_MDEFORMVERT; + } } } else { @@ -1099,7 +1126,10 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob, add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name); if (data->poletar->type == OB_MESH) { - //node2->customdata_mask |= CD_MASK_MDEFORMVERT; + OperationDepsNode *node2 = find_operation_node(target_key); + if (node2 != NULL) { + node2->customdata_mask |= CD_MASK_MDEFORMVERT; + } } } else { @@ -1475,13 +1505,18 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje if (mti->updateDepsgraph) { DepsNodeHandle handle = create_node_handle(mod_key); - mti->updateDepsgraph(md, bmain, scene, ob, &handle); + mti->updateDepsgraph( + md, + bmain, + scene, + ob, + reinterpret_cast< ::DepsNodeHandle* >(&handle)); } if (BKE_object_modifier_use_time(ob, md)) { TimeSourceKey time_src_key; add_relation(time_src_key, mod_key, DEPSREL_TYPE_TIME, "Time Source"); - + /* Hacky fix for T45633 (Animated modifiers aren't updated) * * This check works because BKE_object_modifier_use_time() tests @@ -1791,3 +1826,4 @@ bool DepsgraphRelationBuilder::needs_animdata_node(ID *id) return false; } +} // namespace DEG diff --git a/source/blender/depsgraph/intern/depsgraph_build.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index af61ab4eb8b..c0bf82becda 100644 --- a/source/blender/depsgraph/intern/depsgraph_build.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -24,12 +24,27 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/depsgraph_build.h +/** \file blender/depsgraph/intern/builder/deg_builder_relations.h * \ingroup depsgraph */ -#ifndef __DEPSGRAPH_BUILD_H__ -#define __DEPSGRAPH_BUILD_H__ +#pragma once + +#include <cstdio> + +#include "intern/depsgraph_types.h" + +#include "DNA_ID.h" + +#include "RNA_access.h" +#include "RNA_types.h" + +#include "BLI_utildefines.h" +#include "BLI_string.h" + +#include "intern/depsgraph_types.h" +#include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_operation.h" struct Base; struct bGPdata; @@ -52,6 +67,8 @@ struct World; struct PropertyRNA; +namespace DEG { + struct Depsgraph; struct DepsNode; struct DepsNodeHandle; @@ -63,74 +80,6 @@ struct ComponentDepsNode; struct OperationDepsNode; struct RootPChanMap; -struct DepsgraphNodeBuilder { - DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph); - ~DepsgraphNodeBuilder(); - - RootDepsNode *add_root_node(); - IDDepsNode *add_id_node(ID *id); - TimeSourceDepsNode *add_time_source(ID *id); - - ComponentDepsNode *add_component_node(ID *id, eDepsNode_Type comp_type, const string &comp_name = ""); - - OperationDepsNode *add_operation_node(ComponentDepsNode *comp_node, eDepsOperation_Type optype, - DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &description = ""); - OperationDepsNode *add_operation_node(ID *id, eDepsNode_Type comp_type, const string &comp_name, eDepsOperation_Type optype, - DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &description = ""); - OperationDepsNode *add_operation_node(ID *id, eDepsNode_Type comp_type, eDepsOperation_Type optype, - DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &description = "") - { - return add_operation_node(id, comp_type, "", optype, op, opcode, description); - } - - bool has_operation_node(ID *id, eDepsNode_Type comp_type, const string &comp_name, - eDepsOperation_Code opcode, const string &description = ""); - - OperationDepsNode *find_operation_node(ID *id, - eDepsNode_Type comp_type, - const string &comp_name, - eDepsOperation_Code opcode, - const string &description = ""); - - OperationDepsNode *find_operation_node(ID *id, - eDepsNode_Type comp_type, - eDepsOperation_Code opcode, - const string &description = "") - { - return find_operation_node(id, comp_type, "", opcode, description); - } - - void build_scene(Main *bmain, Scene *scene); - SubgraphDepsNode *build_subgraph(Group *group); - void build_group(Scene *scene, Base *base, Group *group); - void build_object(Scene *scene, Base *base, Object *ob); - void build_object_transform(Scene *scene, Object *ob); - void build_object_constraints(Scene *scene, Object *ob); - void build_pose_constraints(Object *ob, bPoseChannel *pchan); - void build_rigidbody(Scene *scene); - void build_animdata(ID *id); - OperationDepsNode *build_driver(ID *id, FCurve *fcurve); - void build_ik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con); - void build_splineik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con); - void build_rig(Scene *scene, Object *ob); - void build_proxy_rig(Object *ob); - void build_shapekeys(Key *key); - void build_obdata_geom(Scene *scene, Object *ob); - void build_camera(Object *ob); - void build_lamp(Object *ob); - void build_nodetree(DepsNode *owner_node, bNodeTree *ntree); - void build_material(DepsNode *owner_node, Material *ma); - void build_texture(DepsNode *owner_node, Tex *tex); - void build_texture_stack(DepsNode *owner_node, MTex **texture_stack); - void build_world(World *world); - void build_compositor(Scene *scene); - void build_gpencil(bGPdata *gpd); - -private: - Main *m_bmain; - Depsgraph *m_graph; -}; - struct RootKey { RootKey() {} @@ -163,7 +112,7 @@ struct ComponentKey const char *idname = (id) ? id->name : "<None>"; char typebuf[5]; - sprintf(typebuf, "%d", type); + BLI_snprintf(typebuf, sizeof(typebuf), "%d", type); return string("ComponentKey(") + idname + ", " + typebuf + ", '" + name + "')"; } @@ -203,7 +152,7 @@ struct OperationKey string identifier() const { char typebuf[5]; - sprintf(typebuf, "%d", component_type); + BLI_snprintf(typebuf, sizeof(typebuf), "%d", component_type); return string("OperationKey(") + "t: " + typebuf + ", cn: '" + component_name + "', c: " + DEG_OPNAMES[opcode] + ", n: '" + name + "')"; } @@ -244,29 +193,45 @@ struct DepsgraphRelationBuilder DepsgraphRelationBuilder(Depsgraph *graph); template <typename KeyFrom, typename KeyTo> - void add_relation(const KeyFrom &key_from, const KeyTo &key_to, - eDepsRelation_Type type, const char *description); + void add_relation(const KeyFrom& key_from, + const KeyTo& key_to, + eDepsRelation_Type type, + const char *description); template <typename KeyTo> - void add_relation(const TimeSourceKey &key_from, const KeyTo &key_to, - eDepsRelation_Type type, const char *description); + void add_relation(const TimeSourceKey& key_from, + const KeyTo& key_to, + eDepsRelation_Type type, + const char *description); template <typename KeyType> - void add_node_handle_relation(const KeyType &key_from, const DepsNodeHandle *handle, - eDepsRelation_Type type, const char *description); + void add_node_handle_relation(const KeyType& key_from, + const DepsNodeHandle *handle, + eDepsRelation_Type type, + const char *description); void build_scene(Main *bmain, Scene *scene); void build_group(Main *bmain, Scene *scene, Object *object, Group *group); void build_object(Main *bmain, Scene *scene, Object *ob); void build_object_parent(Object *ob); - void build_constraints(Scene *scene, ID *id, eDepsNode_Type component_type, const char *component_subdata, - ListBase *constraints, RootPChanMap *root_map); + void build_constraints(Scene *scene, ID *id, + eDepsNode_Type component_type, + const char *component_subdata, + ListBase *constraints, + RootPChanMap *root_map); void build_animdata(ID *id); void build_driver(ID *id, FCurve *fcurve); void build_world(World *world); void build_rigidbody(Scene *scene); - void build_ik_pose(Object *ob, bPoseChannel *pchan, bConstraint *con, RootPChanMap *root_map); - void build_splineik_pose(Object *ob, bPoseChannel *pchan, bConstraint *con, RootPChanMap *root_map); + void build_particles(Scene *scene, Object *ob); + void build_ik_pose(Object *ob, + bPoseChannel *pchan, + bConstraint *con, + RootPChanMap *root_map); + void build_splineik_pose(Object *ob, + bPoseChannel *pchan, + bConstraint *con, + RootPChanMap *root_map); void build_rig(Scene *scene, Object *ob); void build_proxy_rig(Object *ob); void build_shapekeys(ID *obdata, Key *key); @@ -280,6 +245,9 @@ struct DepsgraphRelationBuilder void build_compositor(Scene *scene); void build_gpencil(ID *owner, bGPdata *gpd); + template <typename KeyType> + OperationDepsNode *find_operation_node(const KeyType &key); + protected: RootDepsNode *find_node(const RootKey &key) const; TimeSourceDepsNode *find_node(const TimeSourceKey &key) const; @@ -288,12 +256,17 @@ protected: DepsNode *find_node(const RNAPathKey &key) const; OperationDepsNode *has_node(const OperationKey &key) const; - void add_time_relation(TimeSourceDepsNode *timesrc, DepsNode *node_to, const char *description); - void add_operation_relation(OperationDepsNode *node_from, OperationDepsNode *node_to, - eDepsRelation_Type type, const char *description); + void add_time_relation(TimeSourceDepsNode *timesrc, + DepsNode *node_to, + const char *description); + void add_operation_relation(OperationDepsNode *node_from, + OperationDepsNode *node_to, + eDepsRelation_Type type, + const char *description); template <typename KeyType> - DepsNodeHandle create_node_handle(const KeyType &key, const string &default_name = ""); + DepsNodeHandle create_node_handle(const KeyType& key, + const string& default_name = ""); bool needs_animdata_node(ID *id); @@ -318,8 +291,11 @@ struct DepsNodeHandle /* Utilities for Builders ----------------------------------------------------- */ -/* Get unique identifier for FCurves and Drivers */ -string deg_fcurve_id_name(const FCurve *fcu); +template <typename KeyType> +OperationDepsNode *DepsgraphRelationBuilder::find_operation_node(const KeyType& key) { + DepsNode *node = find_node(key); + return node != NULL ? node->get_exit_operation() : NULL; +} template <typename KeyFrom, typename KeyTo> void DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from, @@ -375,10 +351,11 @@ void DepsgraphRelationBuilder::add_relation(const TimeSourceKey &key_from, } template <typename KeyType> -void DepsgraphRelationBuilder::add_node_handle_relation(const KeyType &key_from, - const DepsNodeHandle *handle, - eDepsRelation_Type type, - const char *description) +void DepsgraphRelationBuilder::add_node_handle_relation( + const KeyType &key_from, + const DepsNodeHandle *handle, + eDepsRelation_Type type, + const char *description) { DepsNode *node_from = find_node(key_from); OperationDepsNode *op_from = node_from ? node_from->get_exit_operation() : NULL; @@ -397,10 +374,11 @@ void DepsgraphRelationBuilder::add_node_handle_relation(const KeyType &key_from, } template <typename KeyType> -DepsNodeHandle DepsgraphRelationBuilder::create_node_handle(const KeyType &key, - const string &default_name) +DepsNodeHandle DepsgraphRelationBuilder::create_node_handle( + const KeyType &key, + const string &default_name) { return DepsNodeHandle(this, find_node(key), default_name); } -#endif /* __DEPSGRAPH_BUILD_H__ */ +} // namespace DEG diff --git a/source/blender/depsgraph/util/depsgraph_util_transitive.cc b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc index 98192a9540f..0322ef7fa1d 100644 --- a/source/blender/depsgraph/util/depsgraph_util_transitive.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc @@ -24,26 +24,25 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/util/depsgraph_util_transitive.cc +/** \file blender/depsgraph/intern/builder/deg_builder_transitive.cc * \ingroup depsgraph */ +#include "intern/builder/deg_builder_transitive.h" + extern "C" { #include "MEM_guardedalloc.h" +} -#include "BLI_utildefines.h" +#include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_operation.h" -#include "DNA_ID.h" +#include "intern/depsgraph.h" -#include "RNA_access.h" -#include "RNA_types.h" -} +#include "util/deg_util_foreach.h" -#include "depsgraph_util_transitive.h" -#include "depsgraph.h" -#include "depsnode.h" -#include "depsnode_component.h" -#include "depsnode_operation.h" +namespace DEG { /* -------------------------------------------------- */ @@ -67,16 +66,11 @@ enum { static void deg_graph_tag_paths_recursive(DepsNode *node) { - if (node->done & OP_VISITED) + if (node->done & OP_VISITED) { return; + } node->done |= OP_VISITED; - - for (OperationDepsNode::Relations::const_iterator it = node->inlinks.begin(); - it != node->inlinks.end(); - ++it) - { - DepsRelation *rel = *it; - + foreach (DepsRelation *rel, node->inlinks) { deg_graph_tag_paths_recursive(rel->from); /* Do this only in inlinks loop, so the target node does not get * flagged. @@ -87,18 +81,9 @@ static void deg_graph_tag_paths_recursive(DepsNode *node) void deg_graph_transitive_reduction(Depsgraph *graph) { - for (Depsgraph::OperationNodes::const_iterator it_target = graph->operations.begin(); - it_target != graph->operations.end(); - ++it_target) - { - OperationDepsNode *target = *it_target; - + foreach (OperationDepsNode *target, graph->operations) { /* Clear tags. */ - for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin(); - it != graph->operations.end(); - ++it) - { - OperationDepsNode *node = *it; + foreach (OperationDepsNode *node, graph->operations) { node->done = 0; } @@ -107,19 +92,14 @@ void deg_graph_transitive_reduction(Depsgraph *graph) * flagged. */ target->done |= OP_VISITED; - for (OperationDepsNode::Relations::const_iterator it = target->inlinks.begin(); - it != target->inlinks.end(); - ++it) - { - DepsRelation *rel = *it; - + foreach (DepsRelation *rel, target->inlinks) { deg_graph_tag_paths_recursive(rel->from); } - /* Eemove redundant paths to the target. */ + /* Remove redundant paths to the target. */ for (DepsNode::Relations::const_iterator it_rel = target->inlinks.begin(); it_rel != target->inlinks.end(); - ) + ) { DepsRelation *rel = *it_rel; /* Increment in advance, so we can safely remove the relation. */ @@ -137,3 +117,5 @@ void deg_graph_transitive_reduction(Depsgraph *graph) } } } + +} // namespace DEG diff --git a/source/blender/depsgraph/util/depsgraph_util_transitive.h b/source/blender/depsgraph/intern/builder/deg_builder_transitive.h index a80a1d783d7..be9d7c3ca9c 100644 --- a/source/blender/depsgraph/util/depsgraph_util_transitive.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.h @@ -24,15 +24,17 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/util/depsgraph_util_transitive.h +/** \file blender/depsgraph/intern/builder/deg_builder_transitive.h * \ingroup depsgraph */ -#ifndef __DEPSGRAPH_UTIL_TRANSITIVE_H__ -#define __DEPSGRAPH_UTIL_TRANSITIVE_H__ +#pragma once + +namespace DEG { struct Depsgraph; +/* Performs a transitive reduction to remove redundant relations. */ void deg_graph_transitive_reduction(Depsgraph *graph); -#endif /* __DEPSGRAPH_UTIL_TRANSITIVE_H__ */ +} // namespace DEG diff --git a/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc new file mode 100644 index 00000000000..5ce84ee29db --- /dev/null +++ b/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc @@ -0,0 +1,588 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2014 Blender Foundation. + * All rights reserved. + * + * Original Author: Lukas Toenne + * Contributor(s): None Yet + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/debug/deg_debug_graphviz.cc + * \ingroup depsgraph + * + * Implementation of tools for debugging the depsgraph + */ + +#include "BLI_utildefines.h" +#include "BLI_ghash.h" + +extern "C" { +#include "DNA_listBase.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_debug.h" +} /* extern "C" */ + +#include "intern/depsgraph_intern.h" +#include "util/deg_util_foreach.h" + +/* ****************** */ +/* Graphviz Debugging */ + +namespace DEG { + +#define NL "\r\n" + +/* Only one should be enabled, defines whether graphviz nodes + * get colored by individual types or classes. + */ +#define COLOR_SCHEME_NODE_CLASS 1 +//#define COLOR_SCHEME_NODE_TYPE 2 + +static const char *deg_debug_graphviz_fontname = "helvetica"; +static float deg_debug_graphviz_graph_label_size = 20.0f; +static float deg_debug_graphviz_node_label_size = 14.0f; +static const int deg_debug_max_colors = 12; +#ifdef COLOR_SCHEME_NODE_TYPE +static const char *deg_debug_colors[] = { + "#a6cee3", "#1f78b4", "#b2df8a", + "#33a02c", "#fb9a99", "#e31a1c", + "#fdbf6f", "#ff7f00", "#cab2d6", + "#6a3d9a", "#ffff99", "#b15928", +}; +#endif +static const char *deg_debug_colors_light[] = { + "#8dd3c7", "#ffffb3", "#bebada", + "#fb8072", "#80b1d3", "#fdb462", + "#b3de69", "#fccde5", "#d9d9d9", + "#bc80bd", "#ccebc5", "#ffed6f", +}; + +#ifdef COLOR_SCHEME_NODE_TYPE +static const int deg_debug_node_type_color_map[][2] = { + {DEPSNODE_TYPE_ROOT, 0}, + {DEPSNODE_TYPE_TIMESOURCE, 1}, + {DEPSNODE_TYPE_ID_REF, 2}, + {DEPSNODE_TYPE_SUBGRAPH, 3}, + + /* Outer Types */ + {DEPSNODE_TYPE_PARAMETERS, 4}, + {DEPSNODE_TYPE_PROXY, 5}, + {DEPSNODE_TYPE_ANIMATION, 6}, + {DEPSNODE_TYPE_TRANSFORM, 7}, + {DEPSNODE_TYPE_GEOMETRY, 8}, + {DEPSNODE_TYPE_SEQUENCER, 9}, + {DEPSNODE_TYPE_SHADING, 10}, + {-1, 0} +}; +#endif + +static int deg_debug_node_color_index(const DepsNode *node) +{ +#ifdef COLOR_SCHEME_NODE_CLASS + /* Some special types. */ + switch (node->type) { + case DEPSNODE_TYPE_ID_REF: + return 5; + case DEPSNODE_TYPE_OPERATION: + { + OperationDepsNode *op_node = (OperationDepsNode *)node; + if (op_node->is_noop()) + return 8; + break; + } + + default: + break; + } + /* Do others based on class. */ + switch (node->tclass) { + case DEPSNODE_CLASS_OPERATION: + return 4; + case DEPSNODE_CLASS_COMPONENT: + return 1; + default: + return 9; + } +#endif + +#ifdef COLOR_SCHEME_NODE_TYPE + const int (*pair)[2]; + for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) { + if ((*pair)[0] == node->type) { + return (*pair)[1]; + } + } + return -1; +#endif +} + +struct DebugContext { + FILE *file; + bool show_tags; + bool show_eval_priority; +}; + +static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...) ATTR_PRINTF_FORMAT(2, 3); +static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vfprintf(ctx.file, fmt, args); + va_end(args); +} + +static void deg_debug_graphviz_legend_color(const DebugContext &ctx, + const char *name, + const char *color) +{ + deg_debug_fprintf(ctx, "<TR>"); + deg_debug_fprintf(ctx, "<TD>%s</TD>", name); + deg_debug_fprintf(ctx, "<TD BGCOLOR=\"%s\"></TD>", color); + deg_debug_fprintf(ctx, "</TR>" NL); +} + +static void deg_debug_graphviz_legend(const DebugContext &ctx) +{ + deg_debug_fprintf(ctx, "{" NL); + deg_debug_fprintf(ctx, "rank = sink;" NL); + deg_debug_fprintf(ctx, "Legend [shape=none, margin=0, label=<" NL); + deg_debug_fprintf(ctx, " <TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\" CELLPADDING=\"4\">" NL); + deg_debug_fprintf(ctx, "<TR><TD COLSPAN=\"2\"><B>Legend</B></TD></TR>" NL); + +#ifdef COLOR_SCHEME_NODE_CLASS + const char **colors = deg_debug_colors_light; + deg_debug_graphviz_legend_color(ctx, "Operation", colors[4]); + deg_debug_graphviz_legend_color(ctx, "Component", colors[1]); + deg_debug_graphviz_legend_color(ctx, "ID Node", colors[5]); + deg_debug_graphviz_legend_color(ctx, "NOOP", colors[8]); +#endif + +#ifdef COLOR_SCHEME_NODE_TYPE + const int (*pair)[2]; + for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) { + DepsNodeFactory *nti = DEG_get_node_factory((eDepsNode_Type)(*pair)[0]); + deg_debug_graphviz_legend_color(ctx, + nti->tname().c_str(), + deg_debug_colors_light[(*pair)[1] % deg_debug_max_colors]); + } +#endif + + deg_debug_fprintf(ctx, "</TABLE>" NL); + deg_debug_fprintf(ctx, ">" NL); + deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname); + deg_debug_fprintf(ctx, "];" NL); + deg_debug_fprintf(ctx, "}" NL); +} + +static void deg_debug_graphviz_node_color(const DebugContext &ctx, + const DepsNode *node) +{ + const char *color_default = "black"; + const char *color_modified = "orangered4"; + const char *color_update = "dodgerblue3"; + const char *color = color_default; + if (ctx.show_tags) { + if (node->tclass == DEPSNODE_CLASS_OPERATION) { + OperationDepsNode *op_node = (OperationDepsNode *)node; + if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) { + color = color_modified; + } + else if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) { + color = color_update; + } + } + } + deg_debug_fprintf(ctx, "\"%s\"", color); +} + +static void deg_debug_graphviz_node_penwidth(const DebugContext &ctx, + const DepsNode *node) +{ + float penwidth_default = 1.0f; + float penwidth_modified = 4.0f; + float penwidth_update = 4.0f; + float penwidth = penwidth_default; + if (ctx.show_tags) { + if (node->tclass == DEPSNODE_CLASS_OPERATION) { + OperationDepsNode *op_node = (OperationDepsNode *)node; + if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) { + penwidth = penwidth_modified; + } + else if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) { + penwidth = penwidth_update; + } + } + } + deg_debug_fprintf(ctx, "\"%f\"", penwidth); +} + +static void deg_debug_graphviz_node_fillcolor(const DebugContext &ctx, + const DepsNode *node) +{ + const char *defaultcolor = "gainsboro"; + int color_index = deg_debug_node_color_index(node); + const char *fillcolor = color_index < 0 ? defaultcolor : deg_debug_colors_light[color_index % deg_debug_max_colors]; + deg_debug_fprintf(ctx, "\"%s\"", fillcolor); +} + +static void deg_debug_graphviz_relation_color(const DebugContext &ctx, + const DepsRelation *rel) +{ + const char *color_default = "black"; + const char *color_error = "red4"; + const char *color = color_default; + if (rel->flag & DEPSREL_FLAG_CYCLIC) { + color = color_error; + } + deg_debug_fprintf(ctx, "%s", color); +} + +static void deg_debug_graphviz_node_style(const DebugContext &ctx, const DepsNode *node) +{ + const char *base_style = "filled"; /* default style */ + if (ctx.show_tags) { + if (node->tclass == DEPSNODE_CLASS_OPERATION) { + OperationDepsNode *op_node = (OperationDepsNode *)node; + if (op_node->flag & (DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE)) { + base_style = "striped"; + } + } + } + switch (node->tclass) { + case DEPSNODE_CLASS_GENERIC: + deg_debug_fprintf(ctx, "\"%s\"", base_style); + break; + case DEPSNODE_CLASS_COMPONENT: + deg_debug_fprintf(ctx, "\"%s\"", base_style); + break; + case DEPSNODE_CLASS_OPERATION: + deg_debug_fprintf(ctx, "\"%s,rounded\"", base_style); + break; + } +} + +static void deg_debug_graphviz_node_single(const DebugContext &ctx, + const DepsNode *node) +{ + const char *shape = "box"; + string name = node->identifier(); + float priority = -1.0f; + if (node->type == DEPSNODE_TYPE_ID_REF) { + IDDepsNode *id_node = (IDDepsNode *)node; + char buf[256]; + BLI_snprintf(buf, sizeof(buf), " (Layers: %d)", id_node->layers); + name += buf; + } + if (ctx.show_eval_priority && node->tclass == DEPSNODE_CLASS_OPERATION) { + priority = ((OperationDepsNode *)node)->eval_priority; + } + deg_debug_fprintf(ctx, "// %s\n", name.c_str()); + deg_debug_fprintf(ctx, "\"node_%p\"", node); + deg_debug_fprintf(ctx, "["); +// deg_debug_fprintf(ctx, "label=<<B>%s</B>>", name); + if (priority >= 0.0f) { + deg_debug_fprintf(ctx, "label=<%s<BR/>(<I>%.2f</I>)>", + name.c_str(), + priority); + } + else { + deg_debug_fprintf(ctx, "label=<%s>", name.c_str()); + } + deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname); + deg_debug_fprintf(ctx, ",fontsize=%f", deg_debug_graphviz_node_label_size); + deg_debug_fprintf(ctx, ",shape=%s", shape); + deg_debug_fprintf(ctx, ",style="); deg_debug_graphviz_node_style(ctx, node); + deg_debug_fprintf(ctx, ",color="); deg_debug_graphviz_node_color(ctx, node); + deg_debug_fprintf(ctx, ",fillcolor="); deg_debug_graphviz_node_fillcolor(ctx, node); + deg_debug_fprintf(ctx, ",penwidth="); deg_debug_graphviz_node_penwidth(ctx, node); + deg_debug_fprintf(ctx, "];" NL); + deg_debug_fprintf(ctx, NL); +} + +static void deg_debug_graphviz_node_cluster_begin(const DebugContext &ctx, + const DepsNode *node) +{ + string name = node->identifier().c_str(); + if (node->type == DEPSNODE_TYPE_ID_REF) { + IDDepsNode *id_node = (IDDepsNode *)node; + char buf[256]; + BLI_snprintf(buf, sizeof(buf), " (Layers: %d)", id_node->layers); + name += buf; + } + deg_debug_fprintf(ctx, "// %s\n", name.c_str()); + deg_debug_fprintf(ctx, "subgraph \"cluster_%p\" {" NL, node); +// deg_debug_fprintf(ctx, "label=<<B>%s</B>>;" NL, name); + deg_debug_fprintf(ctx, "label=<%s>;" NL, name.c_str()); + deg_debug_fprintf(ctx, "fontname=\"%s\";" NL, deg_debug_graphviz_fontname); + deg_debug_fprintf(ctx, "fontsize=%f;" NL, deg_debug_graphviz_node_label_size); + deg_debug_fprintf(ctx, "margin=\"%d\";" NL, 16); + deg_debug_fprintf(ctx, "style="); deg_debug_graphviz_node_style(ctx, node); deg_debug_fprintf(ctx, ";" NL); + deg_debug_fprintf(ctx, "color="); deg_debug_graphviz_node_color(ctx, node); deg_debug_fprintf(ctx, ";" NL); + deg_debug_fprintf(ctx, "fillcolor="); deg_debug_graphviz_node_fillcolor(ctx, node); deg_debug_fprintf(ctx, ";" NL); + deg_debug_fprintf(ctx, "penwidth="); deg_debug_graphviz_node_penwidth(ctx, node); deg_debug_fprintf(ctx, ";" NL); + /* dummy node, so we can add edges between clusters */ + deg_debug_fprintf(ctx, "\"node_%p\"", node); + deg_debug_fprintf(ctx, "["); + deg_debug_fprintf(ctx, "shape=%s", "point"); + deg_debug_fprintf(ctx, ",style=%s", "invis"); + deg_debug_fprintf(ctx, "];" NL); + deg_debug_fprintf(ctx, NL); +} + +static void deg_debug_graphviz_node_cluster_end(const DebugContext &ctx) +{ + deg_debug_fprintf(ctx, "}" NL); + deg_debug_fprintf(ctx, NL); +} + +static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx, + const Depsgraph *graph); +static void deg_debug_graphviz_graph_relations(const DebugContext &ctx, + const Depsgraph *graph); + +static void deg_debug_graphviz_node(const DebugContext &ctx, + const DepsNode *node) +{ + switch (node->type) { + case DEPSNODE_TYPE_ID_REF: + { + const IDDepsNode *id_node = (const IDDepsNode *)node; + if (BLI_ghash_size(id_node->components) == 0) { + deg_debug_graphviz_node_single(ctx, node); + } + else { + deg_debug_graphviz_node_cluster_begin(ctx, node); + GHASH_FOREACH_BEGIN(const ComponentDepsNode *, comp, id_node->components) + { + deg_debug_graphviz_node(ctx, comp); + } + GHASH_FOREACH_END(); + deg_debug_graphviz_node_cluster_end(ctx); + } + break; + } + case DEPSNODE_TYPE_SUBGRAPH: + { + SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node; + if (sub_node->graph) { + deg_debug_graphviz_node_cluster_begin(ctx, node); + deg_debug_graphviz_graph_nodes(ctx, sub_node->graph); + deg_debug_graphviz_node_cluster_end(ctx); + } + else { + deg_debug_graphviz_node_single(ctx, node); + } + break; + } + case DEPSNODE_TYPE_PARAMETERS: + case DEPSNODE_TYPE_ANIMATION: + case DEPSNODE_TYPE_TRANSFORM: + case DEPSNODE_TYPE_PROXY: + case DEPSNODE_TYPE_GEOMETRY: + case DEPSNODE_TYPE_SEQUENCER: + case DEPSNODE_TYPE_EVAL_POSE: + case DEPSNODE_TYPE_BONE: + case DEPSNODE_TYPE_SHADING: + case DEPSNODE_TYPE_EVAL_PARTICLES: + { + ComponentDepsNode *comp_node = (ComponentDepsNode *)node; + if (!comp_node->operations.empty()) { + deg_debug_graphviz_node_cluster_begin(ctx, node); + foreach (DepsNode *op_node, comp_node->operations) { + deg_debug_graphviz_node(ctx, op_node); + } + deg_debug_graphviz_node_cluster_end(ctx); + } + else { + deg_debug_graphviz_node_single(ctx, node); + } + break; + } + default: + deg_debug_graphviz_node_single(ctx, node); + break; + } +} + +static bool deg_debug_graphviz_is_cluster(const DepsNode *node) +{ + switch (node->type) { + case DEPSNODE_TYPE_ID_REF: + { + const IDDepsNode *id_node = (const IDDepsNode *)node; + return BLI_ghash_size(id_node->components) > 0; + } + case DEPSNODE_TYPE_SUBGRAPH: + { + SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node; + return sub_node->graph != NULL; + } + case DEPSNODE_TYPE_PARAMETERS: + case DEPSNODE_TYPE_ANIMATION: + case DEPSNODE_TYPE_TRANSFORM: + case DEPSNODE_TYPE_PROXY: + case DEPSNODE_TYPE_GEOMETRY: + case DEPSNODE_TYPE_SEQUENCER: + case DEPSNODE_TYPE_EVAL_POSE: + case DEPSNODE_TYPE_BONE: + { + ComponentDepsNode *comp_node = (ComponentDepsNode *)node; + return !comp_node->operations.empty(); + } + default: + return false; + } +} + +static bool deg_debug_graphviz_is_owner(const DepsNode *node, + const DepsNode *other) +{ + switch (node->tclass) { + case DEPSNODE_CLASS_COMPONENT: + { + ComponentDepsNode *comp_node = (ComponentDepsNode *)node; + if (comp_node->owner == other) + return true; + break; + } + case DEPSNODE_CLASS_OPERATION: + { + OperationDepsNode *op_node = (OperationDepsNode *)node; + if (op_node->owner == other) + return true; + else if (op_node->owner->owner == other) + return true; + break; + } + default: break; + } + return false; +} + +static void deg_debug_graphviz_node_relations(const DebugContext &ctx, + const DepsNode *node) +{ + foreach (DepsRelation *rel, node->inlinks) { + float penwidth = 2.0f; + + const DepsNode *tail = rel->to; /* same as node */ + const DepsNode *head = rel->from; + deg_debug_fprintf(ctx, "// %s -> %s\n", + head->identifier().c_str(), + tail->identifier().c_str()); + deg_debug_fprintf(ctx, "\"node_%p\"", head); + deg_debug_fprintf(ctx, " -> "); + deg_debug_fprintf(ctx, "\"node_%p\"", tail); + + deg_debug_fprintf(ctx, "["); + /* Note: without label an id seem necessary to avoid bugs in graphviz/dot */ + deg_debug_fprintf(ctx, "id=\"%s\"", rel->name); + deg_debug_fprintf(ctx, ",color="); deg_debug_graphviz_relation_color(ctx, rel); + deg_debug_fprintf(ctx, ",penwidth=\"%f\"", penwidth); + /* NOTE: edge from node to own cluster is not possible and gives graphviz + * warning, avoid this here by just linking directly to the invisible + * placeholder node + */ + if (deg_debug_graphviz_is_cluster(tail) && !deg_debug_graphviz_is_owner(head, tail)) { + deg_debug_fprintf(ctx, ",ltail=\"cluster_%p\"", tail); + } + if (deg_debug_graphviz_is_cluster(head) && !deg_debug_graphviz_is_owner(tail, head)) { + deg_debug_fprintf(ctx, ",lhead=\"cluster_%p\"", head); + } + deg_debug_fprintf(ctx, "];" NL); + deg_debug_fprintf(ctx, NL); + } +} + +static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx, + const Depsgraph *graph) +{ + if (graph->root_node) { + deg_debug_graphviz_node(ctx, graph->root_node); + } + GHASH_FOREACH_BEGIN (DepsNode *, node, graph->id_hash) + { + deg_debug_graphviz_node(ctx, node); + } + GHASH_FOREACH_END(); + TimeSourceDepsNode *time_source = graph->find_time_source(NULL); + if (time_source != NULL) { + deg_debug_graphviz_node(ctx, time_source); + } +} + +static void deg_debug_graphviz_graph_relations(const DebugContext &ctx, + const Depsgraph *graph) +{ + GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, graph->id_hash) + { + GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, id_node->components) + { + foreach (OperationDepsNode *op_node, comp_node->operations) { + deg_debug_graphviz_node_relations(ctx, op_node); + } + } + GHASH_FOREACH_END(); + } + GHASH_FOREACH_END(); + + TimeSourceDepsNode *time_source = graph->find_time_source(NULL); + if (time_source != NULL) { + deg_debug_graphviz_node_relations(ctx, time_source); + } +} + +} // namespace DEG + +void DEG_debug_graphviz(const Depsgraph *graph, FILE *f, const char *label, bool show_eval) +{ + if (!graph) { + return; + } + + const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph); + + DEG::DebugContext ctx; + ctx.file = f; + ctx.show_tags = show_eval; + ctx.show_eval_priority = show_eval; + + DEG::deg_debug_fprintf(ctx, "digraph depgraph {" NL); + DEG::deg_debug_fprintf(ctx, "rankdir=LR;" NL); + DEG::deg_debug_fprintf(ctx, "graph ["); + DEG::deg_debug_fprintf(ctx, "compound=true"); + DEG::deg_debug_fprintf(ctx, ",labelloc=\"t\""); + DEG::deg_debug_fprintf(ctx, ",fontsize=%f", DEG::deg_debug_graphviz_graph_label_size); + DEG::deg_debug_fprintf(ctx, ",fontname=\"%s\"", DEG::deg_debug_graphviz_fontname); + DEG::deg_debug_fprintf(ctx, ",label=\"%s\"", label); + DEG::deg_debug_fprintf(ctx, ",splines=ortho"); + DEG::deg_debug_fprintf(ctx, ",overlap=scalexy"); // XXX: only when using neato + DEG::deg_debug_fprintf(ctx, "];" NL); + + DEG::deg_debug_graphviz_graph_nodes(ctx, deg_graph); + DEG::deg_debug_graphviz_graph_relations(ctx, deg_graph); + + DEG::deg_debug_graphviz_legend(ctx); + + DEG::deg_debug_fprintf(ctx, "}" NL); +} + +#undef NL diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index d293d03f63d..2b7c63767ab 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -30,10 +30,14 @@ * Core routines for how the Depsgraph works. */ +#include "intern/depsgraph.h" /* own include */ + #include <string.h> #include "MEM_guardedalloc.h" +#include "BLI_utildefines.h" +#include "BLI_ghash.h" #include "BLI_listbase.h" extern "C" { @@ -50,11 +54,15 @@ extern "C" { } #include "DEG_depsgraph.h" -#include "depsgraph.h" /* own include */ -#include "depsnode.h" -#include "depsnode_operation.h" -#include "depsnode_component.h" -#include "depsgraph_intern.h" + +#include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_operation.h" + +#include "intern/depsgraph_intern.h" +#include "util/deg_util_foreach.h" + +namespace DEG { static DEG_EditorUpdateIDCb deg_editor_update_id_cb = NULL; static DEG_EditorUpdateSceneCb deg_editor_update_scene_cb = NULL; @@ -66,6 +74,9 @@ Depsgraph::Depsgraph() layers(0) { BLI_spin_init(&lock); + id_hash = BLI_ghash_ptr_new("Depsgraph id hash"); + subgraphs = BLI_gset_ptr_new("Depsgraph subgraphs"); + entry_tags = BLI_gset_ptr_new("Depsgraph entry_tags"); } Depsgraph::~Depsgraph() @@ -73,6 +84,9 @@ Depsgraph::~Depsgraph() /* Free root node - it won't have been freed yet... */ clear_id_nodes(); clear_subgraph_nodes(); + BLI_ghash_free(id_hash, NULL, NULL); + BLI_gset_free(subgraphs, NULL); + BLI_gset_free(entry_tags, NULL); if (this->root_node != NULL) { OBJECT_GUARDED_DELETE(this->root_node, RootDepsNode); } @@ -235,10 +249,16 @@ DepsNode *Depsgraph::find_node_from_pointer(const PointerRNA *ptr, /* Node Management ---------------------------- */ +static void id_node_deleter(void *value) +{ + IDDepsNode *id_node = reinterpret_cast<IDDepsNode *>(value); + OBJECT_GUARDED_DELETE(id_node, IDDepsNode); +} + RootDepsNode *Depsgraph::add_root_node() { if (!root_node) { - DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_ROOT); + DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_ROOT); root_node = (RootDepsNode *)factory->create_node(NULL, "", "Root (Scene)"); } return root_node; @@ -267,12 +287,12 @@ TimeSourceDepsNode *Depsgraph::find_time_source(const ID *id) const SubgraphDepsNode *Depsgraph::add_subgraph_node(const ID *id) { - DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_SUBGRAPH); + DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_SUBGRAPH); SubgraphDepsNode *subgraph_node = (SubgraphDepsNode *)factory->create_node(id, "", id->name + 2); /* Add to subnodes list. */ - this->subgraphs.insert(subgraph_node); + BLI_gset_insert(subgraphs, subgraph_node); /* if there's an ID associated, add to ID-nodes lookup too */ if (id) { @@ -289,37 +309,34 @@ SubgraphDepsNode *Depsgraph::add_subgraph_node(const ID *id) void Depsgraph::remove_subgraph_node(SubgraphDepsNode *subgraph_node) { - subgraphs.erase(subgraph_node); + BLI_gset_remove(subgraphs, subgraph_node, NULL); OBJECT_GUARDED_DELETE(subgraph_node, SubgraphDepsNode); } void Depsgraph::clear_subgraph_nodes() { - for (Subgraphs::iterator it = subgraphs.begin(); - it != subgraphs.end(); - ++it) + GSET_FOREACH_BEGIN(SubgraphDepsNode *, subgraph_node, subgraphs) { - SubgraphDepsNode *subgraph_node = *it; OBJECT_GUARDED_DELETE(subgraph_node, SubgraphDepsNode); } - subgraphs.clear(); + GSET_FOREACH_END(); + BLI_gset_clear(subgraphs, NULL); } IDDepsNode *Depsgraph::find_id_node(const ID *id) const { - IDNodeMap::const_iterator it = this->id_hash.find(id); - return it != this->id_hash.end() ? it->second : NULL; + return reinterpret_cast<IDDepsNode *>(BLI_ghash_lookup(id_hash, id)); } IDDepsNode *Depsgraph::add_id_node(ID *id, const string &name) { IDDepsNode *id_node = find_id_node(id); if (!id_node) { - DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_ID_REF); + DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_ID_REF); id_node = (IDDepsNode *)factory->create_node(id, "", name); id->tag |= LIB_TAG_DOIT; /* register */ - this->id_hash[id] = id_node; + BLI_ghash_insert(id_hash, id, id_node); } return id_node; } @@ -329,21 +346,14 @@ void Depsgraph::remove_id_node(const ID *id) IDDepsNode *id_node = find_id_node(id); if (id_node) { /* unregister */ - this->id_hash.erase(id); + BLI_ghash_remove(id_hash, id, NULL, NULL); OBJECT_GUARDED_DELETE(id_node, IDDepsNode); } } void Depsgraph::clear_id_nodes() { - for (IDNodeMap::const_iterator it = id_hash.begin(); - it != id_hash.end(); - ++it) - { - IDDepsNode *id_node = it->second; - OBJECT_GUARDED_DELETE(id_node, IDDepsNode); - } - id_hash.clear(); + BLI_ghash_clear(id_hash, NULL, id_node_deleter); } /* Add new relationship between two nodes. */ @@ -449,33 +459,52 @@ void Depsgraph::add_entry_tag(OperationDepsNode *node) /* Add to graph-level set of directly modified nodes to start searching from. * NOTE: this is necessary since we have several thousand nodes to play with... */ - this->entry_tags.insert(node); + BLI_gset_insert(entry_tags, node); } void Depsgraph::clear_all_nodes() { clear_id_nodes(); clear_subgraph_nodes(); - id_hash.clear(); + BLI_ghash_clear(id_hash, NULL, NULL); if (this->root_node) { OBJECT_GUARDED_DELETE(this->root_node, RootDepsNode); root_node = NULL; } } +void deg_editors_id_update(Main *bmain, ID *id) +{ + if (deg_editor_update_id_cb != NULL) { + deg_editor_update_id_cb(bmain, id); + } +} + +void deg_editors_scene_update(Main *bmain, Scene *scene, bool updated) +{ + if (deg_editor_update_scene_cb != NULL) { + deg_editor_update_scene_cb(bmain, scene, updated); + } +} + +} // namespace DEG + /* **************** */ /* Public Graph API */ /* Initialize a new Depsgraph */ Depsgraph *DEG_graph_new() { - return OBJECT_GUARDED_NEW(Depsgraph); + DEG::Depsgraph *deg_depsgraph = OBJECT_GUARDED_NEW(DEG::Depsgraph); + return reinterpret_cast<Depsgraph *>(deg_depsgraph); } /* Free graph's contents and graph itself */ void DEG_graph_free(Depsgraph *graph) { - OBJECT_GUARDED_DELETE(graph, Depsgraph); + using DEG::Depsgraph; + DEG::Depsgraph *deg_depsgraph = reinterpret_cast<DEG::Depsgraph *>(graph); + OBJECT_GUARDED_DELETE(deg_depsgraph, Depsgraph); } /* Set callbacks which are being called when depsgraph changes. */ @@ -483,28 +512,14 @@ void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func, DEG_EditorUpdateSceneCb scene_func, DEG_EditorUpdateScenePreCb scene_pre_func) { - deg_editor_update_id_cb = id_func; - deg_editor_update_scene_cb = scene_func; - deg_editor_update_scene_pre_cb = scene_pre_func; + DEG::deg_editor_update_id_cb = id_func; + DEG::deg_editor_update_scene_cb = scene_func; + DEG::deg_editor_update_scene_pre_cb = scene_pre_func; } void DEG_editors_update_pre(Main *bmain, Scene *scene, bool time) { - if (deg_editor_update_scene_pre_cb != NULL) { - deg_editor_update_scene_pre_cb(bmain, scene, time); - } -} - -void deg_editors_id_update(Main *bmain, ID *id) -{ - if (deg_editor_update_id_cb != NULL) { - deg_editor_update_id_cb(bmain, id); - } -} - -void deg_editors_scene_update(Main *bmain, Scene *scene, bool updated) -{ - if (deg_editor_update_scene_cb != NULL) { - deg_editor_update_scene_cb(bmain, scene, updated); + if (DEG::deg_editor_update_scene_pre_cb != NULL) { + DEG::deg_editor_update_scene_pre_cb(bmain, scene, time); } } diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h index 9533fbd10d5..213bb304d73 100644 --- a/source/blender/depsgraph/intern/depsgraph.h +++ b/source/blender/depsgraph/intern/depsgraph.h @@ -34,19 +34,20 @@ * in the graph. */ -#ifndef __DEPSGRAPH_H__ -#define __DEPSGRAPH_H__ +#pragma once #include "BLI_threads.h" /* for SpinLock */ -#include "depsgraph_types.h" - -#include "depsgraph_util_map.h" -#include "depsgraph_util_set.h" +#include "intern/depsgraph_types.h" +struct ID; +struct GHash; +struct GSet; struct PointerRNA; struct PropertyRNA; +namespace DEG { + struct DepsNode; struct RootDepsNode; struct TimeSourceDepsNode; @@ -94,9 +95,6 @@ struct DepsRelation { /* Dependency Graph object */ struct Depsgraph { - typedef unordered_map<const ID *, IDDepsNode *> IDNodeMap; - typedef unordered_set<SubgraphDepsNode *> Subgraphs; - typedef unordered_set<OperationDepsNode *> EntryTags; typedef vector<OperationDepsNode *> OperationNodes; Depsgraph(); @@ -163,13 +161,13 @@ struct Depsgraph { /* <ID : IDDepsNode> mapping from ID blocks to nodes representing these blocks * (for quick lookups). */ - IDNodeMap id_hash; + GHash *id_hash; /* "root" node - the one where all evaluation enters from. */ RootDepsNode *root_node; /* Subgraphs referenced in tree. */ - Subgraphs subgraphs; + GSet *subgraphs; /* Indicates whether relations needs to be updated. */ bool need_update; @@ -177,7 +175,7 @@ struct Depsgraph { /* Quick-Access Temp Data ............. */ /* Nodes which have been tagged as "directly modified". */ - EntryTags entry_tags; + GSet *entry_tags; /* Convenience Data ................... */ @@ -198,27 +196,4 @@ struct Depsgraph { // XXX: additional stuff like eval contexts, mempools for allocating nodes from, etc. }; -/** - * Helper macros for iterating over set of relationship links - * incident on each node. - * - * \note it is safe to perform removal operations here... - * - * relations_set[in]: (DepsNode::Relations) set of relationships (in/out links) - * relation[out]: (DepsRelation *) identifier where DepsRelation that we're - * currently accessing comes up - */ -#define DEPSNODE_RELATIONS_ITER_BEGIN(relations_set_, relation_) \ - { \ - OperationDepsNode::Relations::const_iterator __rel_iter = relations_set_.begin(); \ - while (__rel_iter != relations_set_.end()) { \ - DepsRelation *relation_ = *__rel_iter; \ - ++__rel_iter; \ - - /* ... code for iterator body can be written here ... */ - -#define DEPSNODE_RELATIONS_ITER_END \ - } \ - } ((void)0) - -#endif /* __DEPSGRAPH_H__ */ +} // namespace DEG diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc index 82f312c2171..b1271c39851 100644 --- a/source/blender/depsgraph/intern/depsgraph_build.cc +++ b/source/blender/depsgraph/intern/depsgraph_build.cc @@ -30,135 +30,128 @@ * Methods for constructing depsgraph. */ -#include <stack> - #include "MEM_guardedalloc.h" extern "C" { -#include "BLI_blenlib.h" -#include "BLI_string.h" -#include "BLI_utildefines.h" - -#include "DNA_action_types.h" -#include "DNA_anim_types.h" -#include "DNA_armature_types.h" -#include "DNA_camera_types.h" -#include "DNA_constraint_types.h" -#include "DNA_curve_types.h" -#include "DNA_effect_types.h" -#include "DNA_group_types.h" -#include "DNA_key_types.h" -#include "DNA_lamp_types.h" -#include "DNA_material_types.h" -#include "DNA_mesh_types.h" -#include "DNA_meta_types.h" -#include "DNA_node_types.h" #include "DNA_object_types.h" -#include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" -#include "DNA_texture_types.h" -#include "DNA_world_types.h" - -#include "BKE_action.h" -#include "BKE_armature.h" -#include "BKE_animsys.h" -#include "BKE_constraint.h" -#include "BKE_curve.h" -#include "BKE_effect.h" -#include "BKE_fcurve.h" -#include "BKE_group.h" -#include "BKE_key.h" -#include "BKE_library.h" + +#include "BLI_utildefines.h" +#include "BLI_ghash.h" + #include "BKE_main.h" -#include "BKE_material.h" -#include "BKE_mball.h" -#include "BKE_modifier.h" -#include "BKE_node.h" -#include "BKE_object.h" -#include "BKE_rigidbody.h" -#include "BKE_sound.h" -#include "BKE_texture.h" -#include "BKE_tracking.h" -#include "BKE_world.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_debug.h" #include "DEG_depsgraph_build.h" -#include "RNA_access.h" -#include "RNA_types.h" } /* extern "C" */ -#include "depsnode.h" -#include "depsnode_component.h" -#include "depsgraph_debug.h" -#include "depsnode_operation.h" -#include "depsgraph_types.h" -#include "depsgraph_build.h" -#include "depsgraph_intern.h" +#include "builder/deg_builder.h" +#include "builder/deg_builder_cycle.h" +#include "builder/deg_builder_nodes.h" +#include "builder/deg_builder_relations.h" +#include "builder/deg_builder_transitive.h" + +#include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_operation.h" + +#include "intern/depsgraph_types.h" +#include "intern/depsgraph_intern.h" -#include "depsgraph_util_cycle.h" -#include "depsgraph_util_transitive.h" +#include "util/deg_util_foreach.h" /* ****************** */ /* External Build API */ -static eDepsNode_Type deg_build_scene_component_type(eDepsSceneComponentType component) +static DEG::eDepsNode_Type deg_build_scene_component_type( + eDepsSceneComponentType component) { switch (component) { - case DEG_SCENE_COMP_PARAMETERS: return DEPSNODE_TYPE_PARAMETERS; - case DEG_SCENE_COMP_ANIMATION: return DEPSNODE_TYPE_ANIMATION; - case DEG_SCENE_COMP_SEQUENCER: return DEPSNODE_TYPE_SEQUENCER; + case DEG_SCENE_COMP_PARAMETERS: return DEG::DEPSNODE_TYPE_PARAMETERS; + case DEG_SCENE_COMP_ANIMATION: return DEG::DEPSNODE_TYPE_ANIMATION; + case DEG_SCENE_COMP_SEQUENCER: return DEG::DEPSNODE_TYPE_SEQUENCER; } - return DEPSNODE_TYPE_UNDEFINED; + return DEG::DEPSNODE_TYPE_UNDEFINED; } -static eDepsNode_Type deg_build_object_component_type(eDepsObjectComponentType component) +static DEG::eDepsNode_Type deg_build_object_component_type( + eDepsObjectComponentType component) { switch (component) { - case DEG_OB_COMP_PARAMETERS: return DEPSNODE_TYPE_PARAMETERS; - case DEG_OB_COMP_PROXY: return DEPSNODE_TYPE_PROXY; - case DEG_OB_COMP_ANIMATION: return DEPSNODE_TYPE_ANIMATION; - case DEG_OB_COMP_TRANSFORM: return DEPSNODE_TYPE_TRANSFORM; - case DEG_OB_COMP_GEOMETRY: return DEPSNODE_TYPE_GEOMETRY; - case DEG_OB_COMP_EVAL_POSE: return DEPSNODE_TYPE_EVAL_POSE; - case DEG_OB_COMP_BONE: return DEPSNODE_TYPE_BONE; - case DEG_OB_COMP_EVAL_PARTICLES: return DEPSNODE_TYPE_EVAL_PARTICLES; - case DEG_OB_COMP_SHADING: return DEPSNODE_TYPE_SHADING; + case DEG_OB_COMP_PARAMETERS: return DEG::DEPSNODE_TYPE_PARAMETERS; + case DEG_OB_COMP_PROXY: return DEG::DEPSNODE_TYPE_PROXY; + case DEG_OB_COMP_ANIMATION: return DEG::DEPSNODE_TYPE_ANIMATION; + case DEG_OB_COMP_TRANSFORM: return DEG::DEPSNODE_TYPE_TRANSFORM; + case DEG_OB_COMP_GEOMETRY: return DEG::DEPSNODE_TYPE_GEOMETRY; + case DEG_OB_COMP_EVAL_POSE: return DEG::DEPSNODE_TYPE_EVAL_POSE; + case DEG_OB_COMP_BONE: return DEG::DEPSNODE_TYPE_BONE; + case DEG_OB_COMP_EVAL_PARTICLES: return DEG::DEPSNODE_TYPE_EVAL_PARTICLES; + case DEG_OB_COMP_SHADING: return DEG::DEPSNODE_TYPE_SHADING; } - return DEPSNODE_TYPE_UNDEFINED; + return DEG::DEPSNODE_TYPE_UNDEFINED; } -void DEG_add_scene_relation(DepsNodeHandle *handle, struct Scene *scene, eDepsSceneComponentType component, const char *description) +static DEG::DepsNodeHandle *get_handle(DepsNodeHandle *handle) { - eDepsNode_Type type = deg_build_scene_component_type(component); - ComponentKey comp_key(&scene->id, type); - handle->builder->add_node_handle_relation(comp_key, handle, DEPSREL_TYPE_GEOMETRY_EVAL, description); + return reinterpret_cast<DEG::DepsNodeHandle *>(handle); } -void DEG_add_object_relation(DepsNodeHandle *handle, struct Object *ob, eDepsObjectComponentType component, const char *description) +void DEG_add_scene_relation(DepsNodeHandle *handle, + Scene *scene, + eDepsSceneComponentType component, + const char *description) { - eDepsNode_Type type = deg_build_object_component_type(component); - ComponentKey comp_key(&ob->id, type); - handle->builder->add_node_handle_relation(comp_key, handle, DEPSREL_TYPE_GEOMETRY_EVAL, description); + DEG::eDepsNode_Type type = deg_build_scene_component_type(component); + DEG::ComponentKey comp_key(&scene->id, type); + DEG::DepsNodeHandle *deg_handle = get_handle(handle); + deg_handle->builder->add_node_handle_relation(comp_key, + deg_handle, + DEG::DEPSREL_TYPE_GEOMETRY_EVAL, + description); } -void DEG_add_bone_relation(DepsNodeHandle *handle, struct Object *ob, const char *bone_name, eDepsObjectComponentType component, const char *description) +void DEG_add_object_relation(DepsNodeHandle *handle, + Object *ob, + eDepsObjectComponentType component, + const char *description) { - eDepsNode_Type type = deg_build_object_component_type(component); - ComponentKey comp_key(&ob->id, type, bone_name); + DEG::eDepsNode_Type type = deg_build_object_component_type(component); + DEG::ComponentKey comp_key(&ob->id, type); + DEG::DepsNodeHandle *deg_handle = get_handle(handle); + deg_handle->builder->add_node_handle_relation(comp_key, + deg_handle, + DEG::DEPSREL_TYPE_GEOMETRY_EVAL, + description); +} - // XXX: "Geometry Eval" might not always be true, but this only gets called from modifier building now - handle->builder->add_node_handle_relation(comp_key, handle, DEPSREL_TYPE_GEOMETRY_EVAL, description); +void DEG_add_bone_relation(DepsNodeHandle *handle, + Object *ob, + const char *bone_name, + eDepsObjectComponentType component, + const char *description) +{ + DEG::eDepsNode_Type type = deg_build_object_component_type(component); + DEG::ComponentKey comp_key(&ob->id, type, bone_name); + DEG::DepsNodeHandle *deg_handle = get_handle(handle); + /* XXX: "Geometry Eval" might not always be true, but this only gets called + * from modifier building now. + */ + deg_handle->builder->add_node_handle_relation(comp_key, + deg_handle, + DEG::DEPSREL_TYPE_GEOMETRY_EVAL, + description); } void DEG_add_special_eval_flag(Depsgraph *graph, ID *id, short flag) { + DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); if (graph == NULL) { BLI_assert(!"Graph should always be valid"); return; } - IDDepsNode *id_node = graph->find_id_node(id); + DEG::IDDepsNode *id_node = deg_graph->find_id_node(id); if (id_node == NULL) { BLI_assert(!"ID should always be valid"); return; @@ -166,110 +159,21 @@ void DEG_add_special_eval_flag(Depsgraph *graph, ID *id, short flag) id_node->eval_flags |= flag; } -/* ********************** */ -/* Utilities for Builders */ - -/* Get unique identifier for FCurves and Drivers */ -string deg_fcurve_id_name(const FCurve *fcu) -{ - char index_buf[32]; - sprintf(index_buf, "[%d]", fcu->array_index); - - return string(fcu->rna_path) + index_buf; -} - -static void deg_graph_build_finalize(Depsgraph *graph) -{ - std::stack<OperationDepsNode *> stack; - - for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin(); - it_op != graph->operations.end(); - ++it_op) - { - OperationDepsNode *node = *it_op; - node->done = 0; - node->num_links_pending = 0; - for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin(); - it_rel != node->inlinks.end(); - ++it_rel) - { - DepsRelation *rel = *it_rel; - if ((rel->from->type == DEPSNODE_TYPE_OPERATION) && - (rel->flag & DEPSREL_FLAG_CYCLIC) == 0) - { - ++node->num_links_pending; - } - } - if (node->num_links_pending == 0) { - stack.push(node); - } - IDDepsNode *id_node = node->owner->owner; - id_node->id->tag |= LIB_TAG_DOIT; - } - - while (!stack.empty()) { - OperationDepsNode *node = stack.top(); - if (node->done == 0 && node->outlinks.size() != 0) { - for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin(); - it_rel != node->outlinks.end(); - ++it_rel) - { - DepsRelation *rel = *it_rel; - if (rel->to->type == DEPSNODE_TYPE_OPERATION) { - OperationDepsNode *to = (OperationDepsNode *)rel->to; - if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) { - BLI_assert(to->num_links_pending > 0); - --to->num_links_pending; - } - if (to->num_links_pending == 0) { - stack.push(to); - } - } - } - node->done = 1; - } - else { - stack.pop(); - IDDepsNode *id_node = node->owner->owner; - for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin(); - it_rel != node->outlinks.end(); - ++it_rel) - { - DepsRelation *rel = *it_rel; - if (rel->to->type == DEPSNODE_TYPE_OPERATION) { - OperationDepsNode *to = (OperationDepsNode *)rel->to; - IDDepsNode *id_to = to->owner->owner; - id_node->layers |= id_to->layers; - } - } - } - } - - /* Re-tag IDs for update if it was tagged before the relations update tag. */ - for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin(); - it != graph->id_hash.end(); - ++it) - { - IDDepsNode *id_node = it->second; - ID *id = id_node->id; - if (id->tag & LIB_TAG_ID_RECALC_ALL && - id->tag & LIB_TAG_DOIT) - { - id_node->tag_update(graph); - id->tag &= ~LIB_TAG_DOIT; - } - } -} - /* ******************** */ /* Graph Building API's */ -/* Build depsgraph for the given scene, and dump results in given graph container */ -// XXX: assume that this is called from outside, given the current scene as the "main" scene +/* Build depsgraph for the given scene, and dump results in given + * graph container. + */ +/* XXX: assume that this is called from outside, given the current scene as + * the "main" scene. + */ void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene) { + DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); + /* 1) Generate all the nodes in the graph first */ - DepsgraphNodeBuilder node_builder(bmain, graph); + DEG::DepsgraphNodeBuilder node_builder(bmain, deg_graph); /* create root node for scene first * - this way it should be the first in the graph, * reflecting its role as the entrypoint @@ -277,29 +181,40 @@ void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene) node_builder.add_root_node(); node_builder.build_scene(bmain, scene); - /* 2) Hook up relationships between operations - to determine evaluation order */ - DepsgraphRelationBuilder relation_builder(graph); - /* hook scene up to the root node as entrypoint to graph */ + /* 2) Hook up relationships between operations - to determine evaluation + * order. + */ + DEG::DepsgraphRelationBuilder relation_builder(deg_graph); + /* Hook scene up to the root node as entrypoint to graph. */ /* XXX what does this relation actually mean? - * it doesnt add any operations anyway and is not clear what part of the scene is to be connected. + * it doesnt add any operations anyway and is not clear what part of the + * scene is to be connected. */ - //relation_builder.add_relation(RootKey(), IDKey(scene), DEPSREL_TYPE_ROOT_TO_ACTIVE, "Root to Active Scene"); +#if 0 + relation_builder.add_relation(RootKey(), + IDKey(scene), + DEPSREL_TYPE_ROOT_TO_ACTIVE, + "Root to Active Scene"); +#endif relation_builder.build_scene(bmain, scene); /* Detect and solve cycles. */ - deg_graph_detect_cycles(graph); + DEG::deg_graph_detect_cycles(deg_graph); - /* 3) Simplify the graph by removing redundant relations (to optimise traversal later) */ - // TODO: it would be useful to have an option to disable this in cases where it is causing trouble + /* 3) Simplify the graph by removing redundant relations (to optimize + * traversal later). */ + /* TODO: it would be useful to have an option to disable this in cases where + * it is causing trouble. + */ if (G.debug_value == 799) { - deg_graph_transitive_reduction(graph); + DEG::deg_graph_transitive_reduction(deg_graph); } /* 4) Flush visibility layer and re-schedule nodes for update. */ - deg_graph_build_finalize(graph); + DEG::deg_graph_build_finalize(deg_graph); #if 0 - if (!DEG_debug_consistency_check(graph)) { + if (!DEG_debug_consistency_check(deg_graph)) { printf("Consistency validation failed, ABORTING!\n"); abort(); } @@ -309,7 +224,8 @@ void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene) /* Tag graph relations for update. */ void DEG_graph_tag_relations_update(Depsgraph *graph) { - graph->need_update = true; + DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); + deg_graph->need_update = true; } /* Tag all relations for update. */ @@ -337,7 +253,7 @@ void DEG_scene_relations_update(Main *bmain, Scene *scene) return; } - Depsgraph *graph = scene->depsgraph; + DEG::Depsgraph *graph = reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph); if (!graph->need_update) { /* Graph is up to date, nothing to do. */ return; @@ -346,10 +262,12 @@ void DEG_scene_relations_update(Main *bmain, Scene *scene) /* Clear all previous nodes and operations. */ graph->clear_all_nodes(); graph->operations.clear(); - graph->entry_tags.clear(); + BLI_gset_clear(graph->entry_tags, NULL); /* Build new nodes and relations. */ - DEG_graph_build_from_scene(graph, bmain, scene); + DEG_graph_build_from_scene(reinterpret_cast< ::Depsgraph * >(graph), + bmain, + scene); graph->need_update = false; } diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc index efb3e330857..d3b48930779 100644 --- a/source/blender/depsgraph/intern/depsgraph_debug.cc +++ b/source/blender/depsgraph/intern/depsgraph_debug.cc @@ -30,956 +30,39 @@ * Implementation of tools for debugging the depsgraph */ -//#include <stdlib.h> -#include <string.h> - -extern "C" { #include "BLI_utildefines.h" -#include "BLI_listbase.h" #include "BLI_ghash.h" -#include "BLI_string.h" +extern "C" { #include "DNA_scene_types.h" -#include "DNA_userdef_types.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_debug.h" #include "DEG_depsgraph_build.h" - -#include "WM_api.h" -#include "WM_types.h" } /* extern "C" */ -#include "depsgraph_debug.h" -#include "depsnode.h" -#include "depsnode_component.h" -#include "depsnode_operation.h" -#include "depsgraph_intern.h" - -/* ****************** */ -/* Graphviz Debugging */ - -#define NL "\r\n" - -/* Only one should be enabled, defines whether graphviz nodes - * get colored by individual types or classes. - */ -#define COLOR_SCHEME_NODE_CLASS 1 -//#define COLOR_SCHEME_NODE_TYPE 2 - -static const char *deg_debug_graphviz_fontname = "helvetica"; -static float deg_debug_graphviz_graph_label_size = 20.0f; -static float deg_debug_graphviz_node_label_size = 14.0f; -static const int deg_debug_max_colors = 12; -#if 0 -static const char *deg_debug_colors_dark[] = { - "#6e8997", "#144f77", "#76945b", - "#216a1d", "#a76665", "#971112", - "#a87f49", "#0a9540", "#86768e", - "#462866", "#a9a965", "#753b1a", -}; -#endif -#ifdef COLOR_SCHEME_NODE_TYPE -static const char *deg_debug_colors[] = { - "#a6cee3", "#1f78b4", "#b2df8a", - "#33a02c", "#fb9a99", "#e31a1c", - "#fdbf6f", "#ff7f00", "#cab2d6", - "#6a3d9a", "#ffff99", "#b15928", -}; -#endif -static const char *deg_debug_colors_light[] = { - "#8dd3c7", "#ffffb3", "#bebada", - "#fb8072", "#80b1d3", "#fdb462", - "#b3de69", "#fccde5", "#d9d9d9", - "#bc80bd", "#ccebc5", "#ffed6f", -}; - -#ifdef COLOR_SCHEME_NODE_TYPE -static const int deg_debug_node_type_color_map[][2] = { - {DEPSNODE_TYPE_ROOT, 0}, - {DEPSNODE_TYPE_TIMESOURCE, 1}, - {DEPSNODE_TYPE_ID_REF, 2}, - {DEPSNODE_TYPE_SUBGRAPH, 3}, - - /* Outer Types */ - {DEPSNODE_TYPE_PARAMETERS, 4}, - {DEPSNODE_TYPE_PROXY, 5}, - {DEPSNODE_TYPE_ANIMATION, 6}, - {DEPSNODE_TYPE_TRANSFORM, 7}, - {DEPSNODE_TYPE_GEOMETRY, 8}, - {DEPSNODE_TYPE_SEQUENCER, 9}, - {DEPSNODE_TYPE_SHADING, 10}, - {-1, 0} -}; -#endif - -#if 0 /* unused */ -static const int deg_debug_relation_type_color_map[][2] = { - {DEPSREL_TYPE_STANDARD, 0}, - {DEPSREL_TYPE_ROOT_TO_ACTIVE, 1}, - {DEPSREL_TYPE_DATABLOCK, 2}, - {DEPSREL_TYPE_TIME, 3}, - {DEPSREL_TYPE_COMPONENT_ORDER, 4}, - {DEPSREL_TYPE_OPERATION, 5}, - {DEPSREL_TYPE_DRIVER, 6}, - {DEPSREL_TYPE_DRIVER_TARGET, 7}, - {DEPSREL_TYPE_TRANSFORM, 8}, - {DEPSREL_TYPE_GEOMETRY_EVAL, 9}, - {DEPSREL_TYPE_UPDATE, 10}, - {DEPSREL_TYPE_UPDATE_UI, 11}, - {-1, 0} -}; -#endif - -static int deg_debug_node_color_index(const DepsNode *node) -{ -#ifdef COLOR_SCHEME_NODE_CLASS - /* Some special types. */ - switch (node->type) { - case DEPSNODE_TYPE_ID_REF: - return 5; - case DEPSNODE_TYPE_OPERATION: - { - OperationDepsNode *op_node = (OperationDepsNode *)node; - if (op_node->is_noop()) - return 8; - break; - } - - default: - break; - } - /* Do others based on class. */ - switch (node->tclass) { - case DEPSNODE_CLASS_OPERATION: - return 4; - case DEPSNODE_CLASS_COMPONENT: - return 1; - default: - return 9; - } -#endif - -#ifdef COLOR_SCHEME_NODE_TYPE - const int (*pair)[2]; - for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) { - if ((*pair)[0] == node->type) { - return (*pair)[1]; - } - } - return -1; -#endif -} - -struct DebugContext { - FILE *file; - bool show_tags; - bool show_eval_priority; -}; - -static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...) ATTR_PRINTF_FORMAT(2, 3); -static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - vfprintf(ctx.file, fmt, args); - va_end(args); -} - -static void deg_debug_graphviz_legend_color(const DebugContext &ctx, - const char *name, - const char *color) -{ - deg_debug_fprintf(ctx, "<TR>"); - deg_debug_fprintf(ctx, "<TD>%s</TD>", name); - deg_debug_fprintf(ctx, "<TD BGCOLOR=\"%s\"></TD>", color); - deg_debug_fprintf(ctx, "</TR>" NL); -} - -#if 0 -static void deg_debug_graphviz_legend_line(const DebugContext &ctx, - const char *name, - const char *color, - const char *style) -{ - /* XXX TODO */ - deg_debug_fprintf(ctx, "" NL); -} - -static void deg_debug_graphviz_legend_cluster(const DebugContext &ctx, - const char *name, - const char *color, - const char *style) -{ - deg_debug_fprintf(ctx, "<TR>"); - deg_debug_fprintf(ctx, "<TD>%s</TD>", name); - deg_debug_fprintf(ctx, "<TD CELLPADDING=\"4\"><TABLE BORDER=\"1\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\">"); - deg_debug_fprintf(ctx, "<TR><TD BGCOLOR=\"%s\"></TD></TR>", color); - deg_debug_fprintf(ctx, "</TABLE></TD>"); - deg_debug_fprintf(ctx, "</TR>" NL); -} -#endif - -static void deg_debug_graphviz_legend(const DebugContext &ctx) -{ - deg_debug_fprintf(ctx, "{" NL); - deg_debug_fprintf(ctx, "rank = sink;" NL); - deg_debug_fprintf(ctx, "Legend [shape=none, margin=0, label=<" NL); - deg_debug_fprintf(ctx, " <TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\" CELLPADDING=\"4\">" NL); - deg_debug_fprintf(ctx, "<TR><TD COLSPAN=\"2\"><B>Legend</B></TD></TR>" NL); - -#ifdef COLOR_SCHEME_NODE_CLASS - const char **colors = deg_debug_colors_light; - deg_debug_graphviz_legend_color(ctx, "Operation", colors[4]); - deg_debug_graphviz_legend_color(ctx, "Component", colors[1]); - deg_debug_graphviz_legend_color(ctx, "ID Node", colors[5]); - deg_debug_graphviz_legend_color(ctx, "NOOP", colors[8]); -#endif - -#ifdef COLOR_SCHEME_NODE_TYPE - const int (*pair)[2]; - for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) { - DepsNodeFactory *nti = DEG_get_node_factory((eDepsNode_Type)(*pair)[0]); - deg_debug_graphviz_legend_color(ctx, - nti->tname().c_str(), - deg_debug_colors_light[(*pair)[1] % deg_debug_max_colors]); - } -#endif - - deg_debug_fprintf(ctx, "</TABLE>" NL); - deg_debug_fprintf(ctx, ">" NL); - deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname); - deg_debug_fprintf(ctx, "];" NL); - deg_debug_fprintf(ctx, "}" NL); -} - -#if 0 /* unused */ -static int deg_debug_relation_type_color_index(eDepsRelation_Type type) -{ - const int (*pair)[2]; - for (pair = deg_debug_relation_type_color_map; (*pair)[0] >= 0; ++pair) { - if ((*pair)[0] == type) { - return (*pair)[1]; - } - } - return -1; -} -#endif - -static void deg_debug_graphviz_node_color(const DebugContext &ctx, - const DepsNode *node) -{ - const char *color_default = "black"; - const char *color_modified = "orangered4"; - const char *color_update = "dodgerblue3"; - const char *color = color_default; - if (ctx.show_tags) { - if (node->tclass == DEPSNODE_CLASS_OPERATION) { - OperationDepsNode *op_node = (OperationDepsNode *)node; - if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) { - color = color_modified; - } - else if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) { - color = color_update; - } - } - } - deg_debug_fprintf(ctx, "\"%s\"", color); -} - -static void deg_debug_graphviz_node_penwidth(const DebugContext &ctx, - const DepsNode *node) -{ - float penwidth_default = 1.0f; - float penwidth_modified = 4.0f; - float penwidth_update = 4.0f; - float penwidth = penwidth_default; - if (ctx.show_tags) { - if (node->tclass == DEPSNODE_CLASS_OPERATION) { - OperationDepsNode *op_node = (OperationDepsNode *)node; - if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) { - penwidth = penwidth_modified; - } - else if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) { - penwidth = penwidth_update; - } - } - } - deg_debug_fprintf(ctx, "\"%f\"", penwidth); -} - -static void deg_debug_graphviz_node_fillcolor(const DebugContext &ctx, - const DepsNode *node) -{ - const char *defaultcolor = "gainsboro"; - int color_index = deg_debug_node_color_index(node); - const char *fillcolor = color_index < 0 ? defaultcolor : deg_debug_colors_light[color_index % deg_debug_max_colors]; - deg_debug_fprintf(ctx, "\"%s\"", fillcolor); -} - -#if 0 /* implementation using stripes, a bit too noisy ... */ -static void deg_debug_graphviz_node_fillcolor(const DebugContext &ctx, - const DepsNode *node) -{ - const char *defaultcolor = "gainsboro"; - const char *color_needs_update = "orange"; - const int num_stripes = 10; - int color_index = deg_debug_node_color_index(node); - const char *base_color = color_index < 0 ? defaultcolor : deg_debug_colors_light[color_index % deg_debug_max_colors]; - if (ctx.show_tags && - (node->flag & (DEPSNODE_FLAG_DIRECTLY_MODIFIED | DEPSNODE_FLAG_NEEDS_UPDATE))) - { - deg_debug_fprintf(ctx, "\""); - for (int i = 0; i < num_stripes; ++i) { - if (i > 0) { - deg_debug_fprintf(ctx, ":"); - } - deg_debug_fprintf(ctx, "%s:%s", base_color, color_needs_update); - } - deg_debug_fprintf(ctx, "\""); - } - else { - deg_debug_fprintf(ctx, "\"%s\"", base_color); - } -} -#endif - -static void deg_debug_graphviz_relation_color(const DebugContext &ctx, - const DepsRelation *rel) -{ - const char *color_default = "black"; - const char *color_error = "red4"; - const char *color = color_default; -#if 0 /* disabled for now, edge colors are hardly distinguishable */ - int color = deg_debug_relation_type_color_index(rel->type); - if (color < 0) { - deg_debug_fprintf(ctx, "%s", defaultcolor); - } - else { - deg_debug_fprintf(ctx, "\"%s\"", deg_debug_colors_dark[color % deg_debug_max_colors]); - } -#else - if (rel->flag & DEPSREL_FLAG_CYCLIC) - color = color_error; - - deg_debug_fprintf(ctx, "%s", color); -#endif -} - -static void deg_debug_graphviz_node_style(const DebugContext &ctx, const DepsNode *node) -{ - const char *base_style = "filled"; /* default style */ - if (ctx.show_tags) { - if (node->tclass == DEPSNODE_CLASS_OPERATION) { - OperationDepsNode *op_node = (OperationDepsNode *)node; - if (op_node->flag & (DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE)) { - base_style = "striped"; - } - } - } - switch (node->tclass) { - case DEPSNODE_CLASS_GENERIC: - deg_debug_fprintf(ctx, "\"%s\"", base_style); - break; - case DEPSNODE_CLASS_COMPONENT: - deg_debug_fprintf(ctx, "\"%s\"", base_style); - break; - case DEPSNODE_CLASS_OPERATION: - deg_debug_fprintf(ctx, "\"%s,rounded\"", base_style); - break; - } -} - -static void deg_debug_graphviz_node_single(const DebugContext &ctx, - const DepsNode *node) -{ - const char *shape = "box"; - string name = node->identifier(); - float priority = -1.0f; - if (node->type == DEPSNODE_TYPE_ID_REF) { - IDDepsNode *id_node = (IDDepsNode *)node; - char buf[256]; - BLI_snprintf(buf, sizeof(buf), " (Layers: %d)", id_node->layers); - name += buf; - } - if (ctx.show_eval_priority && node->tclass == DEPSNODE_CLASS_OPERATION) { - priority = ((OperationDepsNode *)node)->eval_priority; - } - deg_debug_fprintf(ctx, "// %s\n", name.c_str()); - deg_debug_fprintf(ctx, "\"node_%p\"", node); - deg_debug_fprintf(ctx, "["); -// deg_debug_fprintf(ctx, "label=<<B>%s</B>>", name); - if (priority >= 0.0f) { - deg_debug_fprintf(ctx, "label=<%s<BR/>(<I>%.2f</I>)>", - name.c_str(), - priority); - } - else { - deg_debug_fprintf(ctx, "label=<%s>", name.c_str()); - } - deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname); - deg_debug_fprintf(ctx, ",fontsize=%f", deg_debug_graphviz_node_label_size); - deg_debug_fprintf(ctx, ",shape=%s", shape); - deg_debug_fprintf(ctx, ",style="); deg_debug_graphviz_node_style(ctx, node); - deg_debug_fprintf(ctx, ",color="); deg_debug_graphviz_node_color(ctx, node); - deg_debug_fprintf(ctx, ",fillcolor="); deg_debug_graphviz_node_fillcolor(ctx, node); - deg_debug_fprintf(ctx, ",penwidth="); deg_debug_graphviz_node_penwidth(ctx, node); - deg_debug_fprintf(ctx, "];" NL); - deg_debug_fprintf(ctx, NL); -} - -static void deg_debug_graphviz_node_cluster_begin(const DebugContext &ctx, - const DepsNode *node) -{ - string name = node->identifier().c_str(); - if (node->type == DEPSNODE_TYPE_ID_REF) { - IDDepsNode *id_node = (IDDepsNode *)node; - char buf[256]; - BLI_snprintf(buf, sizeof(buf), " (Layers: %d)", id_node->layers); - name += buf; - } - deg_debug_fprintf(ctx, "// %s\n", name.c_str()); - deg_debug_fprintf(ctx, "subgraph \"cluster_%p\" {" NL, node); -// deg_debug_fprintf(ctx, "label=<<B>%s</B>>;" NL, name); - deg_debug_fprintf(ctx, "label=<%s>;" NL, name.c_str()); - deg_debug_fprintf(ctx, "fontname=\"%s\";" NL, deg_debug_graphviz_fontname); - deg_debug_fprintf(ctx, "fontsize=%f;" NL, deg_debug_graphviz_node_label_size); - deg_debug_fprintf(ctx, "margin=\"%d\";" NL, 16); - deg_debug_fprintf(ctx, "style="); deg_debug_graphviz_node_style(ctx, node); deg_debug_fprintf(ctx, ";" NL); - deg_debug_fprintf(ctx, "color="); deg_debug_graphviz_node_color(ctx, node); deg_debug_fprintf(ctx, ";" NL); - deg_debug_fprintf(ctx, "fillcolor="); deg_debug_graphviz_node_fillcolor(ctx, node); deg_debug_fprintf(ctx, ";" NL); - deg_debug_fprintf(ctx, "penwidth="); deg_debug_graphviz_node_penwidth(ctx, node); deg_debug_fprintf(ctx, ";" NL); - /* dummy node, so we can add edges between clusters */ - deg_debug_fprintf(ctx, "\"node_%p\"", node); - deg_debug_fprintf(ctx, "["); - deg_debug_fprintf(ctx, "shape=%s", "point"); - deg_debug_fprintf(ctx, ",style=%s", "invis"); - deg_debug_fprintf(ctx, "];" NL); - deg_debug_fprintf(ctx, NL); -} - -static void deg_debug_graphviz_node_cluster_end(const DebugContext &ctx) -{ - deg_debug_fprintf(ctx, "}" NL); - deg_debug_fprintf(ctx, NL); -} - -static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx, - const Depsgraph *graph); -static void deg_debug_graphviz_graph_relations(const DebugContext &ctx, - const Depsgraph *graph); - -static void deg_debug_graphviz_node(const DebugContext &ctx, - const DepsNode *node) -{ - switch (node->type) { - case DEPSNODE_TYPE_ID_REF: - { - const IDDepsNode *id_node = (const IDDepsNode *)node; - if (id_node->components.empty()) { - deg_debug_graphviz_node_single(ctx, node); - } - else { - deg_debug_graphviz_node_cluster_begin(ctx, node); - for (IDDepsNode::ComponentMap::const_iterator it = id_node->components.begin(); - it != id_node->components.end(); - ++it) - { - const ComponentDepsNode *comp = it->second; - deg_debug_graphviz_node(ctx, comp); - } - deg_debug_graphviz_node_cluster_end(ctx); - } - break; - } - case DEPSNODE_TYPE_SUBGRAPH: - { - SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node; - if (sub_node->graph) { - deg_debug_graphviz_node_cluster_begin(ctx, node); - deg_debug_graphviz_graph_nodes(ctx, sub_node->graph); - deg_debug_graphviz_node_cluster_end(ctx); - } - else { - deg_debug_graphviz_node_single(ctx, node); - } - break; - } - case DEPSNODE_TYPE_PARAMETERS: - case DEPSNODE_TYPE_ANIMATION: - case DEPSNODE_TYPE_TRANSFORM: - case DEPSNODE_TYPE_PROXY: - case DEPSNODE_TYPE_GEOMETRY: - case DEPSNODE_TYPE_SEQUENCER: - case DEPSNODE_TYPE_EVAL_POSE: - case DEPSNODE_TYPE_BONE: - case DEPSNODE_TYPE_SHADING: - case DEPSNODE_TYPE_EVAL_PARTICLES: - { - ComponentDepsNode *comp_node = (ComponentDepsNode *)node; - if (!comp_node->operations.empty()) { - deg_debug_graphviz_node_cluster_begin(ctx, node); - for (ComponentDepsNode::OperationMap::const_iterator it = comp_node->operations.begin(); - it != comp_node->operations.end(); - ++it) - { - const DepsNode *op_node = it->second; - deg_debug_graphviz_node(ctx, op_node); - } - deg_debug_graphviz_node_cluster_end(ctx); - } - else { - deg_debug_graphviz_node_single(ctx, node); - } - break; - } - default: - deg_debug_graphviz_node_single(ctx, node); - break; - } -} - -static bool deg_debug_graphviz_is_cluster(const DepsNode *node) -{ - switch (node->type) { - case DEPSNODE_TYPE_ID_REF: - { - const IDDepsNode *id_node = (const IDDepsNode *)node; - return !id_node->components.empty(); - } - case DEPSNODE_TYPE_SUBGRAPH: - { - SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node; - return sub_node->graph != NULL; - } - case DEPSNODE_TYPE_PARAMETERS: - case DEPSNODE_TYPE_ANIMATION: - case DEPSNODE_TYPE_TRANSFORM: - case DEPSNODE_TYPE_PROXY: - case DEPSNODE_TYPE_GEOMETRY: - case DEPSNODE_TYPE_SEQUENCER: - case DEPSNODE_TYPE_EVAL_POSE: - case DEPSNODE_TYPE_BONE: - { - ComponentDepsNode *comp_node = (ComponentDepsNode *)node; - return !comp_node->operations.empty(); - } - default: - return false; - } -} - -static bool deg_debug_graphviz_is_owner(const DepsNode *node, - const DepsNode *other) -{ - switch (node->tclass) { - case DEPSNODE_CLASS_COMPONENT: - { - ComponentDepsNode *comp_node = (ComponentDepsNode *)node; - if (comp_node->owner == other) - return true; - break; - } - case DEPSNODE_CLASS_OPERATION: - { - OperationDepsNode *op_node = (OperationDepsNode *)node; - if (op_node->owner == other) - return true; - else if (op_node->owner->owner == other) - return true; - break; - } - default: break; - } - return false; -} - -static void deg_debug_graphviz_node_relations(const DebugContext &ctx, - const DepsNode *node) -{ - DEPSNODE_RELATIONS_ITER_BEGIN(node->inlinks, rel) - { - float penwidth = 2.0f; - - const DepsNode *tail = rel->to; /* same as node */ - const DepsNode *head = rel->from; - deg_debug_fprintf(ctx, "// %s -> %s\n", - head->identifier().c_str(), - tail->identifier().c_str()); - deg_debug_fprintf(ctx, "\"node_%p\"", head); - deg_debug_fprintf(ctx, " -> "); - deg_debug_fprintf(ctx, "\"node_%p\"", tail); - - deg_debug_fprintf(ctx, "["); - /* XXX labels on relations are not very helpful: - * - they tend to appear too far away to be associated with the edge lines - * - names are mostly redundant, reflecting simply their from/to nodes - * - no behavior or typing of relations themselves to justify labels - */ -#if 0 - deg_debug_fprintf(ctx, "label=\"%s\"", rel->name); - deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname); -#else - /* Note: without label an id seem necessary to avoid bugs in graphviz/dot */ - deg_debug_fprintf(ctx, "id=\"%s\"", rel->name); -#endif - deg_debug_fprintf(ctx, ",color="); deg_debug_graphviz_relation_color(ctx, rel); - deg_debug_fprintf(ctx, ",penwidth=\"%f\"", penwidth); - /* NOTE: edge from node to own cluster is not possible and gives graphviz - * warning, avoid this here by just linking directly to the invisible - * placeholder node - */ - if (deg_debug_graphviz_is_cluster(tail) && !deg_debug_graphviz_is_owner(head, tail)) { - deg_debug_fprintf(ctx, ",ltail=\"cluster_%p\"", tail); - } - if (deg_debug_graphviz_is_cluster(head) && !deg_debug_graphviz_is_owner(tail, head)) { - deg_debug_fprintf(ctx, ",lhead=\"cluster_%p\"", head); - } - deg_debug_fprintf(ctx, "];" NL); - deg_debug_fprintf(ctx, NL); - } - DEPSNODE_RELATIONS_ITER_END; - -#if 0 - if (node->tclass == DEPSNODE_CLASS_COMPONENT) { - const ComponentDepsNode *comp_node = (const ComponentDepsNode *)node; - for (ComponentDepsNode::OperationMap::const_iterator it = comp_node->operations.begin(); - it != comp_node->operations.end(); - ++it) - { - OperationDepsNode *op_node = it->second; - deg_debug_graphviz_node_relations(ctx, op_node); - } - } - else if (node->type == DEPSNODE_TYPE_ID_REF) { - const IDDepsNode *id_node = (const IDDepsNode *)node; - for (IDDepsNode::ComponentMap::const_iterator it = id_node->components.begin(); - it != id_node->components.end(); - ++it) - { - const ComponentDepsNode *comp = it->second; - deg_debug_graphviz_node_relations(ctx, comp); - } - } - else if (node->type == DEPSNODE_TYPE_SUBGRAPH) { - SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node; - if (sub_node->graph) { - deg_debug_graphviz_graph_relations(ctx, sub_node->graph); - } - } -#endif -} - -static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx, - const Depsgraph *graph) -{ - if (graph->root_node) { - deg_debug_graphviz_node(ctx, graph->root_node); - } - for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin(); - it != graph->id_hash.end(); - ++it) - { - DepsNode *node = it->second; - deg_debug_graphviz_node(ctx, node); - } - TimeSourceDepsNode *time_source = graph->find_time_source(NULL); - if (time_source != NULL) { - deg_debug_graphviz_node(ctx, time_source); - } -} - -static void deg_debug_graphviz_graph_relations(const DebugContext &ctx, - const Depsgraph *graph) -{ -#if 0 - if (graph->root_node) { - deg_debug_graphviz_node_relations(ctx, graph->root_node); - } - for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin(); - it != graph->id_hash.end(); - ++it) - { - DepsNode *id_node = it->second; - deg_debug_graphviz_node_relations(ctx, id_node); - } -#else - /* XXX not in use yet */ -// for (Depsgraph::OperationNodes::const_iterator it = graph->all_opnodes.begin(); -// it != graph->all_opnodes.end(); -// ++it) -// { -// OperationDepsNode *op_node = *it; -// deg_debug_graphviz_node_relations(ctx, op_node); -// } - for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin(); - it != graph->id_hash.end(); - ++it) - { - IDDepsNode *id_node = it->second; - for (IDDepsNode::ComponentMap::const_iterator it = id_node->components.begin(); - it != id_node->components.end(); - ++it) - { - ComponentDepsNode *comp_node = it->second; - for (ComponentDepsNode::OperationMap::const_iterator it = comp_node->operations.begin(); - it != comp_node->operations.end(); - ++it) - { - OperationDepsNode *op_node = it->second; - deg_debug_graphviz_node_relations(ctx, op_node); - } - } - } - - TimeSourceDepsNode *time_source = graph->find_time_source(NULL); - if (time_source != NULL) { - deg_debug_graphviz_node_relations(ctx, time_source); - } -#endif -} - -void DEG_debug_graphviz(const Depsgraph *graph, FILE *f, const char *label, bool show_eval) -{ -#if 0 /* generate shaded color set */ - static char colors[][3] = {{0xa6, 0xce, 0xe3},{0x1f, 0x78, 0xb4},{0xb2, 0xdf, 0x8a},{0x33, 0xa0, 0x2c}, - {0xfb, 0x9a, 0x99},{0xe3, 0x1a, 0x1c},{0xfd, 0xbf, 0x6f},{0xff, 0x7f, 0x00}, - {0xca, 0xb2, 0xd6},{0x6a, 0x3d, 0x9a},{0xff, 0xff, 0x99},{0xb1, 0x59, 0x28}}; - int i; - const float factor = 0.666f; - for (i=0; i < 12; ++i) - printf("\"#%x%x%x\"\n", (char)(colors[i][0] * factor), (char)(colors[i][1] * factor), (char)(colors[i][2] * factor)); -#endif - - if (!graph) { - return; - } - - DebugContext ctx; - ctx.file = f; - ctx.show_tags = show_eval; - ctx.show_eval_priority = show_eval; - - deg_debug_fprintf(ctx, "digraph depgraph {" NL); - deg_debug_fprintf(ctx, "rankdir=LR;" NL); - deg_debug_fprintf(ctx, "graph ["); - deg_debug_fprintf(ctx, "compound=true"); - deg_debug_fprintf(ctx, ",labelloc=\"t\""); - deg_debug_fprintf(ctx, ",fontsize=%f", deg_debug_graphviz_graph_label_size); - deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname); - deg_debug_fprintf(ctx, ",label=\"%s\"", label); - deg_debug_fprintf(ctx, ",splines=ortho"); - deg_debug_fprintf(ctx, ",overlap=scalexy"); // XXX: only when using neato - deg_debug_fprintf(ctx, "];" NL); - - deg_debug_graphviz_graph_nodes(ctx, graph); - deg_debug_graphviz_graph_relations(ctx, graph); - - deg_debug_graphviz_legend(ctx); - - deg_debug_fprintf(ctx, "}" NL); -} - -#undef NL +#include "intern/eval/deg_eval_debug.h" +#include "intern/depsgraph_intern.h" +#include "util/deg_util_foreach.h" /* ************************************************ */ -static string get_component_name(eDepsNode_Type type, const string &name = "") -{ - DepsNodeFactory *factory = DEG_get_node_factory(type); - if (name.empty()) { - return string(factory->tname()); - } - else { - return string(factory->tname()) + " | " + name; - } -} - -static void times_clear(DepsgraphStatsTimes ×) -{ - times.duration_last = 0.0f; -} - -static void times_add(DepsgraphStatsTimes ×, float time) -{ - times.duration_last += time; -} - -void DepsgraphDebug::eval_begin(const EvaluationContext *UNUSED(eval_ctx)) -{ - /* TODO(sergey): Stats are currently globally disabled. */ - /* verify_stats(); */ - reset_stats(); -} - -void DepsgraphDebug::eval_end(const EvaluationContext *UNUSED(eval_ctx)) -{ - WM_main_add_notifier(NC_SPACE | ND_SPACE_INFO_REPORT, NULL); -} - -void DepsgraphDebug::eval_step(const EvaluationContext *UNUSED(eval_ctx), - const char *message) -{ -#ifdef DEG_DEBUG_BUILD - if (deg_debug_eval_cb) - deg_debug_eval_cb(deg_debug_eval_userdata, message); -#else - (void)message; /* Ignored. */ -#endif -} - -void DepsgraphDebug::task_started(Depsgraph *graph, - const OperationDepsNode *node) -{ - if (stats) { - BLI_spin_lock(&graph->lock); - - ComponentDepsNode *comp = node->owner; - ID *id = comp->owner->id; - - DepsgraphStatsID *id_stats = get_id_stats(id, true); - times_clear(id_stats->times); - - /* XXX TODO use something like: if (id->flag & ID_DEG_DETAILS) {...} */ - if (0) { - /* XXX component name usage needs cleanup! currently mixes identifier and description strings! */ - DepsgraphStatsComponent *comp_stats = get_component_stats(id, get_component_name(comp->type, comp->name), true); - times_clear(comp_stats->times); - } - - BLI_spin_unlock(&graph->lock); - } -} - -void DepsgraphDebug::task_completed(Depsgraph *graph, - const OperationDepsNode *node, - double time) -{ - if (stats) { - BLI_spin_lock(&graph->lock); - - ComponentDepsNode *comp = node->owner; - ID *id = comp->owner->id; - - DepsgraphStatsID *id_stats = get_id_stats(id, true); - times_add(id_stats->times, time); - - /* XXX TODO use something like: if (id->flag & ID_DEG_DETAILS) {...} */ - if (0) { - /* XXX component name usage needs cleanup! currently mixes identifier and description strings! */ - DepsgraphStatsComponent *comp_stats = get_component_stats(id, get_component_name(comp->type, comp->name), true); - times_add(comp_stats->times, time); - } - - BLI_spin_unlock(&graph->lock); - } -} - -/* ********** */ -/* Statistics */ - -DepsgraphStats *DepsgraphDebug::stats = NULL; - -/* GHash callback */ -static void deg_id_stats_free(void *val) -{ - DepsgraphStatsID *id_stats = (DepsgraphStatsID *)val; - - if (id_stats) { - BLI_freelistN(&id_stats->components); - MEM_freeN(id_stats); - } -} - -void DepsgraphDebug::stats_init() -{ - if (!stats) { - stats = (DepsgraphStats *)MEM_callocN(sizeof(DepsgraphStats), "Depsgraph Stats"); - stats->id_stats = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "Depsgraph ID Stats Hash"); - } -} - -void DepsgraphDebug::stats_free() -{ - if (stats) { - BLI_ghash_free(stats->id_stats, NULL, deg_id_stats_free); - MEM_freeN(stats); - stats = NULL; - } -} - -void DepsgraphDebug::verify_stats() -{ - stats_init(); -} - -void DepsgraphDebug::reset_stats() -{ - if (!stats) { - return; - } - - /* XXX this doesn't work, will immediately clear all info, - * since most depsgraph updates have none or very few updates to handle. - * - * Could consider clearing only zero-user ID blocks here - */ -// BLI_ghash_clear(stats->id_stats, NULL, deg_id_stats_free); -} - -DepsgraphStatsID *DepsgraphDebug::get_id_stats(ID *id, bool create) -{ - DepsgraphStatsID *id_stats = (DepsgraphStatsID *)BLI_ghash_lookup(stats->id_stats, id); - - if (!id_stats && create) { - id_stats = (DepsgraphStatsID *)MEM_callocN(sizeof(DepsgraphStatsID), "Depsgraph ID Stats"); - id_stats->id = id; - - BLI_ghash_insert(stats->id_stats, id, id_stats); - } - - return id_stats; -} - -DepsgraphStatsComponent *DepsgraphDebug::get_component_stats( - DepsgraphStatsID *id_stats, - const string &name, - bool create) -{ - DepsgraphStatsComponent *comp_stats; - for (comp_stats = (DepsgraphStatsComponent *)id_stats->components.first; - comp_stats != NULL; - comp_stats = comp_stats->next) - { - if (STREQ(comp_stats->name, name.c_str())) - break; - } - if (!comp_stats && create) { - comp_stats = (DepsgraphStatsComponent *)MEM_callocN(sizeof(DepsgraphStatsComponent), "Depsgraph Component Stats"); - BLI_strncpy(comp_stats->name, name.c_str(), sizeof(comp_stats->name)); - BLI_addtail(&id_stats->components, comp_stats); - } - return comp_stats; -} - -/* ------------------------------------------------ */ - DepsgraphStats *DEG_stats(void) { - return DepsgraphDebug::stats; + return DEG::DepsgraphDebug::stats; } void DEG_stats_verify() { - DepsgraphDebug::verify_stats(); + DEG::DepsgraphDebug::verify_stats(); } DepsgraphStatsID *DEG_stats_id(ID *id) { - if (!DepsgraphDebug::stats) { + if (!DEG::DepsgraphDebug::stats) { return NULL; } - return DepsgraphDebug::get_id_stats(id, false); + return DEG::DepsgraphDebug::get_id_stats(id, false); } bool DEG_debug_compare(const struct Depsgraph *graph1, @@ -987,7 +70,9 @@ bool DEG_debug_compare(const struct Depsgraph *graph1, { BLI_assert(graph1 != NULL); BLI_assert(graph2 != NULL); - if (graph1->operations.size() != graph2->operations.size()) { + const DEG::Depsgraph *deg_graph1 = reinterpret_cast<const DEG::Depsgraph *>(graph1); + const DEG::Depsgraph *deg_graph2 = reinterpret_cast<const DEG::Depsgraph *>(graph2); + if (deg_graph1->operations.size() != deg_graph2->operations.size()) { return false; } /* TODO(sergey): Currently we only do real stupid check, @@ -1017,34 +102,21 @@ bool DEG_debug_scene_relations_validate(Main *bmain, bool DEG_debug_consistency_check(Depsgraph *graph) { - /* Validate links exists in both directions. */ - for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin(); - it_op != graph->operations.end(); - ++it_op) - { - OperationDepsNode *node = *it_op; - for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin(); - it_rel != node->outlinks.end(); - ++it_rel) - { - DepsRelation *rel = *it_rel; + const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph); + /* Validate links exists in both directions. */ + foreach (DEG::OperationDepsNode *node, deg_graph->operations) { + foreach (DEG::DepsRelation *rel, node->outlinks) { int counter1 = 0; - for (OperationDepsNode::Relations::const_iterator tmp_rel = node->outlinks.begin(); - tmp_rel != node->outlinks.end(); - ++tmp_rel) - { - if (*tmp_rel == rel) { + foreach (DEG::DepsRelation *tmp_rel, node->outlinks) { + if (tmp_rel == rel) { ++counter1; } } int counter2 = 0; - for (OperationDepsNode::Relations::const_iterator tmp_rel = rel->to->inlinks.begin(); - tmp_rel != rel->to->inlinks.end(); - ++tmp_rel) - { - if (*tmp_rel == rel) { + foreach (DEG::DepsRelation *tmp_rel, rel->to->inlinks) { + if (tmp_rel == rel) { ++counter2; } } @@ -1057,33 +129,18 @@ bool DEG_debug_consistency_check(Depsgraph *graph) } } - for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin(); - it_op != graph->operations.end(); - ++it_op) - { - OperationDepsNode *node = *it_op; - for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin(); - it_rel != node->inlinks.end(); - ++it_rel) - { - DepsRelation *rel = *it_rel; - + foreach (DEG::OperationDepsNode *node, deg_graph->operations) { + foreach (DEG::DepsRelation *rel, node->inlinks) { int counter1 = 0; - for (OperationDepsNode::Relations::const_iterator tmp_rel = node->inlinks.begin(); - tmp_rel != node->inlinks.end(); - ++tmp_rel) - { - if (*tmp_rel == rel) { + foreach (DEG::DepsRelation *tmp_rel, node->inlinks) { + if (tmp_rel == rel) { ++counter1; } } int counter2 = 0; - for (OperationDepsNode::Relations::const_iterator tmp_rel = rel->from->outlinks.begin(); - tmp_rel != rel->from->outlinks.end(); - ++tmp_rel) - { - if (*tmp_rel == rel) { + foreach (DEG::DepsRelation *tmp_rel, rel->from->outlinks) { + if (tmp_rel == rel) { ++counter2; } } @@ -1096,32 +153,20 @@ bool DEG_debug_consistency_check(Depsgraph *graph) } /* Validate node valency calculated in both directions. */ - for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin(); - it_op != graph->operations.end(); - ++it_op) - { - OperationDepsNode *node = *it_op; + foreach (DEG::OperationDepsNode *node, deg_graph->operations) { node->num_links_pending = 0; node->done = 0; } - for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin(); - it_op != graph->operations.end(); - ++it_op) - { - OperationDepsNode *node = *it_op; + foreach (DEG::OperationDepsNode *node, deg_graph->operations) { if (node->done) { printf("Node %s is twice in the operations!\n", node->identifier().c_str()); return false; } - for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin(); - it_rel != node->outlinks.end(); - ++it_rel) - { - DepsRelation *rel = *it_rel; - if (rel->to->type == DEPSNODE_TYPE_OPERATION) { - OperationDepsNode *to = (OperationDepsNode *)rel->to; + foreach (DEG::DepsRelation *rel, node->outlinks) { + if (rel->to->type == DEG::DEPSNODE_TYPE_OPERATION) { + DEG::OperationDepsNode *to = (DEG::OperationDepsNode *)rel->to; BLI_assert(to->num_links_pending < to->inlinks.size()); ++to->num_links_pending; } @@ -1129,18 +174,10 @@ bool DEG_debug_consistency_check(Depsgraph *graph) node->done = 1; } - for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin(); - it_op != graph->operations.end(); - ++it_op) - { - OperationDepsNode *node = *it_op; + foreach (DEG::OperationDepsNode *node, deg_graph->operations) { int num_links_pending = 0; - for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin(); - it_rel != node->inlinks.end(); - ++it_rel) - { - DepsRelation *rel = *it_rel; - if (rel->from->type == DEPSNODE_TYPE_OPERATION) { + foreach (DEG::DepsRelation *rel, node->inlinks) { + if (rel->from->type == DEG::DEPSNODE_TYPE_OPERATION) { ++num_links_pending; } } @@ -1166,12 +203,14 @@ bool DEG_debug_consistency_check(Depsgraph *graph) void DEG_stats_simple(const Depsgraph *graph, size_t *r_outer, size_t *r_operations, size_t *r_relations) { + const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph); + /* number of operations */ if (r_operations) { /* All operations should be in this list, allowing us to count the total * number of nodes. */ - *r_operations = graph->operations.size(); + *r_operations = deg_graph->operations.size(); } /* Count number of outer nodes and/or relations between these. */ @@ -1179,29 +218,21 @@ void DEG_stats_simple(const Depsgraph *graph, size_t *r_outer, size_t tot_outer = 0; size_t tot_rels = 0; - for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin(); - it != graph->id_hash.end(); - ++it) + GHASH_FOREACH_BEGIN(DEG::IDDepsNode *, id_node, deg_graph->id_hash) { - IDDepsNode *id_node = it->second; tot_outer++; - for (IDDepsNode::ComponentMap::const_iterator it = id_node->components.begin(); - it != id_node->components.end(); - ++it) + GHASH_FOREACH_BEGIN(DEG::ComponentDepsNode *, comp_node, id_node->components) { - ComponentDepsNode *comp_node = it->second; tot_outer++; - for (ComponentDepsNode::OperationMap::const_iterator it = comp_node->operations.begin(); - it != comp_node->operations.end(); - ++it) - { - OperationDepsNode *op_node = it->second; + foreach (DEG::OperationDepsNode *op_node, comp_node->operations) { tot_rels += op_node->inlinks.size(); } } + GHASH_FOREACH_END(); } + GHASH_FOREACH_END(); - TimeSourceDepsNode *time_source = graph->find_time_source(NULL); + DEG::TimeSourceDepsNode *time_source = deg_graph->find_time_source(NULL); if (time_source != NULL) { tot_rels += time_source->inlinks.size(); } @@ -1210,4 +241,3 @@ void DEG_stats_simple(const Depsgraph *graph, size_t *r_outer, if (r_outer) *r_outer = tot_outer; } } - diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc index 66535f5214b..f8d40d0e6a8 100644 --- a/source/blender/depsgraph/intern/depsgraph_eval.cc +++ b/source/blender/depsgraph/intern/depsgraph_eval.cc @@ -32,11 +32,9 @@ #include "MEM_guardedalloc.h" -#include "PIL_time.h" - extern "C" { #include "BLI_utildefines.h" -#include "BLI_task.h" +#include "BLI_ghash.h" #include "BKE_depsgraph.h" #include "BKE_scene.h" @@ -44,13 +42,13 @@ extern "C" { #include "DEG_depsgraph.h" } /* extern "C" */ -#include "atomic_ops.h" +#include "intern/eval/deg_eval.h" +#include "intern/eval/deg_eval_flush.h" + +#include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_operation.h" -#include "depsgraph.h" -#include "depsnode.h" -#include "depsnode_component.h" -#include "depsnode_operation.h" -#include "depsgraph_debug.h" +#include "intern/depsgraph.h" #ifdef WITH_LEGACY_DEPSGRAPH static bool use_legacy_depsgraph = true; @@ -118,359 +116,16 @@ void DEG_evaluation_context_free(EvaluationContext *eval_ctx) MEM_freeN(eval_ctx); } -/* ********************** */ -/* Evaluation Entrypoints */ - -/* Forward declarations. */ -static void schedule_children(TaskPool *pool, - Depsgraph *graph, - OperationDepsNode *node, - const int layers, - const int thread_id); - -struct DepsgraphEvalState { - EvaluationContext *eval_ctx; - Depsgraph *graph; - int layers; -}; - -static void deg_task_run_func(TaskPool *pool, - void *taskdata, - int thread_id) -{ - DepsgraphEvalState *state = (DepsgraphEvalState *)BLI_task_pool_userdata(pool); - OperationDepsNode *node = (OperationDepsNode *)taskdata; - - BLI_assert(!node->is_noop() && "NOOP nodes should not actually be scheduled"); - - /* Should only be the case for NOOPs, which never get to this point. */ - BLI_assert(node->evaluate); - - while (true) { - /* Get context. */ - // TODO: who initialises this? "Init" operations aren't able to initialise it!!! - /* TODO(sergey): We don't use component contexts at this moment. */ - /* ComponentDepsNode *comp = node->owner; */ - BLI_assert(node->owner != NULL); - - /* Since we're not leaving the thread for until the graph branches it is - * possible to have NO-OP on the way. for which evaluate() will be NULL. - * but that's all fine, we'll just scheduler it's children. - */ - if (node->evaluate) { - /* Take note of current time. */ - double start_time = PIL_check_seconds_timer(); - DepsgraphDebug::task_started(state->graph, node); - - /* Perform operation. */ - node->evaluate(state->eval_ctx); - - /* Note how long this took. */ - double end_time = PIL_check_seconds_timer(); - DepsgraphDebug::task_completed(state->graph, - node, - end_time - start_time); - } - - /* If there's only one outgoing link we try to immediately switch to - * that node evaluation, without leaving the thread. - * - * It's only doable if the child don't have extra relations or all they - * are satisfied. - * - * TODO(sergey): Checks here can be de-duplicated with the ones from - * schedule_node(), however, how to do it nicely? - */ - if (node->outlinks.size() == 1) { - DepsRelation *rel = node->outlinks[0]; - OperationDepsNode *child = (OperationDepsNode *)rel->to; - BLI_assert(child->type == DEPSNODE_TYPE_OPERATION); - if (!child->scheduled) { - int id_layers = child->owner->owner->layers; - if (!((child->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0 && - (id_layers & state->layers) != 0)) - { - /* Node does not need an update, so can;t continue with the - * chain and need to switch to another one by leaving the - * thread. - */ - break; - } - if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) { - BLI_assert(child->num_links_pending > 0); - atomic_sub_uint32(&child->num_links_pending, 1); - } - if (child->num_links_pending == 0) { - bool is_scheduled = atomic_fetch_and_or_uint8((uint8_t *)&child->scheduled, (uint8_t)true); - if (!is_scheduled) { - /* Node was not scheduled, switch to it! */ - node = child; - } - else { - /* Someone else scheduled the node, leaving us - * unemployed in this thread, we're leaving. - */ - break; - } - } - else { - /* There are other dependencies on the child, can't do - * anything in the current thread. - */ - break; - } - } - else { - /* Happens when having cyclic dependencies. - * - * Nothing to do here, single child was already scheduled, we - * can leave the thread now. - */ - break; - } - } - else { - /* TODO(sergey): It's possible to use one of the outgoing relations - * as a chain which we'll try to keep alive, but it's a bit more - * involved change. - */ - schedule_children(pool, state->graph, node, state->layers, thread_id); - break; - } - } -} - -typedef struct CalculatePengindData { - Depsgraph *graph; - int layers; -} CalculatePengindData; - -static void calculate_pending_func(void *data_v, int i) -{ - CalculatePengindData *data = (CalculatePengindData *)data_v; - Depsgraph *graph = data->graph; - int layers = data->layers; - OperationDepsNode *node = graph->operations[i]; - IDDepsNode *id_node = node->owner->owner; - - node->num_links_pending = 0; - node->scheduled = false; - - /* count number of inputs that need updates */ - if ((id_node->layers & layers) != 0 && - (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0) - { - DEPSNODE_RELATIONS_ITER_BEGIN(node->inlinks, rel) - { - if (rel->from->type == DEPSNODE_TYPE_OPERATION && - (rel->flag & DEPSREL_FLAG_CYCLIC) == 0) - { - OperationDepsNode *from = (OperationDepsNode *)rel->from; - IDDepsNode *id_from_node = from->owner->owner; - if ((id_from_node->layers & layers) != 0 && - (from->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0) - { - ++node->num_links_pending; - } - } - } - DEPSNODE_RELATIONS_ITER_END; - } -} - -static void calculate_pending_parents(Depsgraph *graph, int layers) -{ - const int num_operations = graph->operations.size(); - const bool do_threads = num_operations > 256; - CalculatePengindData data; - data.graph = graph; - data.layers = layers; - BLI_task_parallel_range(0, num_operations, &data, calculate_pending_func, do_threads); -} - -#ifdef USE_EVAL_PRIORITY -static void calculate_eval_priority(OperationDepsNode *node) -{ - if (node->done) { - return; - } - node->done = 1; - - if (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) { - /* XXX standard cost of a node, could be estimated somewhat later on */ - const float cost = 1.0f; - /* NOOP nodes have no cost */ - node->eval_priority = node->is_noop() ? cost : 0.0f; - - for (OperationDepsNode::Relations::const_iterator it = node->outlinks.begin(); - it != node->outlinks.end(); - ++it) - { - DepsRelation *rel = *it; - OperationDepsNode *to = (OperationDepsNode *)rel->to; - BLI_assert(to->type == DEPSNODE_TYPE_OPERATION); - calculate_eval_priority(to); - node->eval_priority += to->eval_priority; - } - } - else { - node->eval_priority = 0.0f; - } -} -#endif - -/* Schedule a node if it needs evaluation. - * dec_parents: Decrement pending parents count, true when child nodes are scheduled - * after a task has been completed. - */ -static void schedule_node(TaskPool *pool, Depsgraph *graph, int layers, - OperationDepsNode *node, bool dec_parents, - const int thread_id) -{ - int id_layers = node->owner->owner->layers; - - if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0 && - (id_layers & layers) != 0) - { - if (dec_parents) { - BLI_assert(node->num_links_pending > 0); - atomic_sub_uint32(&node->num_links_pending, 1); - } - - if (node->num_links_pending == 0) { - bool is_scheduled = atomic_fetch_and_or_uint8((uint8_t *)&node->scheduled, (uint8_t)true); - if (!is_scheduled) { - if (node->is_noop()) { - /* skip NOOP node, schedule children right away */ - schedule_children(pool, graph, node, layers, thread_id); - } - else { - /* children are scheduled once this task is completed */ - BLI_task_pool_push_from_thread(pool, - deg_task_run_func, - node, - false, - TASK_PRIORITY_LOW, - thread_id); - } - } - } - } -} - -static void schedule_graph(TaskPool *pool, - Depsgraph *graph, - const int layers) -{ - for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin(); - it != graph->operations.end(); - ++it) - { - OperationDepsNode *node = *it; - schedule_node(pool, graph, layers, node, false, 0); - } -} - -static void schedule_children(TaskPool *pool, - Depsgraph *graph, - OperationDepsNode *node, - const int layers, - const int thread_id) -{ - DEPSNODE_RELATIONS_ITER_BEGIN(node->outlinks, rel) - { - OperationDepsNode *child = (OperationDepsNode *)rel->to; - BLI_assert(child->type == DEPSNODE_TYPE_OPERATION); - if (child->scheduled) { - /* Happens when having cyclic dependencies. */ - continue; - } - schedule_node(pool, graph, layers, child, (rel->flag & DEPSREL_FLAG_CYCLIC) == 0, thread_id); - } - DEPSNODE_RELATIONS_ITER_END; -} - -/** - * Evaluate all nodes tagged for updating, - * \warning This is usually done as part of main loop, but may also be - * called from frame-change update. - * - * \note Time sources should be all valid! - */ -void DEG_evaluate_on_refresh_ex(EvaluationContext *eval_ctx, - Depsgraph *graph, - const int layers) -{ - /* Generate base evaluation context, upon which all the others are derived. */ - // TODO: this needs both main and scene access... - - /* Nothing to update, early out. */ - if (graph->entry_tags.size() == 0) { - return; - } - - /* Set time for the current graph evaluation context. */ - TimeSourceDepsNode *time_src = graph->find_time_source(); - eval_ctx->ctime = time_src->cfra; - - /* XXX could use a separate pool for each eval context */ - DepsgraphEvalState state; - state.eval_ctx = eval_ctx; - state.graph = graph; - state.layers = layers; - - TaskScheduler *task_scheduler = BLI_task_scheduler_get(); - TaskPool *task_pool = BLI_task_pool_create(task_scheduler, &state); - - if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) { - BLI_pool_set_num_threads(task_pool, 1); - } - - calculate_pending_parents(graph, layers); - - /* Clear tags. */ - for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin(); - it != graph->operations.end(); - ++it) - { - OperationDepsNode *node = *it; - node->done = 0; - } - - /* Calculate priority for operation nodes. */ -#ifdef USE_EVAL_PRIORITY - for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin(); - it != graph->operations.end(); - ++it) - { - OperationDepsNode *node = *it; - calculate_eval_priority(node); - } -#endif - - DepsgraphDebug::eval_begin(eval_ctx); - - schedule_graph(task_pool, graph, layers); - - BLI_task_pool_work_and_wait(task_pool); - BLI_task_pool_free(task_pool); - - DepsgraphDebug::eval_end(eval_ctx); - - /* Clear any uncleared tags - just in case. */ - DEG_graph_clear_tags(graph); -} - /* Evaluate all nodes tagged for updating. */ void DEG_evaluate_on_refresh(EvaluationContext *eval_ctx, Depsgraph *graph, Scene *scene) { + DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); /* Update time on primary timesource. */ - TimeSourceDepsNode *tsrc = graph->find_time_source(); + DEG::TimeSourceDepsNode *tsrc = deg_graph->find_time_source(); tsrc->cfra = BKE_scene_frame_get(scene); - - DEG_evaluate_on_refresh_ex(eval_ctx, graph, graph->layers); + DEG::deg_evaluate_on_refresh(eval_ctx, deg_graph, deg_graph->layers); } /* Frame-change happened for root scene that graph belongs to. */ @@ -480,19 +135,18 @@ void DEG_evaluate_on_framechange(EvaluationContext *eval_ctx, float ctime, const int layers) { + DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); /* Update time on primary timesource. */ - TimeSourceDepsNode *tsrc = graph->find_time_source(); + DEG::TimeSourceDepsNode *tsrc = deg_graph->find_time_source(); tsrc->cfra = ctime; - - tsrc->tag_update(graph); - - DEG_graph_flush_updates(bmain, graph); - + tsrc->tag_update(deg_graph); + DEG::deg_graph_flush_updates(bmain, deg_graph); /* Perform recalculation updates. */ - DEG_evaluate_on_refresh_ex(eval_ctx, graph, layers); + DEG::deg_evaluate_on_refresh(eval_ctx, deg_graph, layers); } bool DEG_needs_eval(Depsgraph *graph) { - return graph->entry_tags.size() != 0; + DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); + return BLI_gset_size(deg_graph->entry_tags) != 0; } diff --git a/source/blender/depsgraph/intern/depsgraph_intern.h b/source/blender/depsgraph/intern/depsgraph_intern.h index 7fdc2454564..e5d3d1f5861 100644 --- a/source/blender/depsgraph/intern/depsgraph_intern.h +++ b/source/blender/depsgraph/intern/depsgraph_intern.h @@ -31,65 +31,26 @@ * - Also, defines for "Node Type Info" */ -#ifndef __DEPSGRAPH_INTERN_H__ -#define __DEPSGRAPH_INTERN_H__ +#pragma once #include <cstdlib> #include "MEM_guardedalloc.h" -#include "depsgraph.h" -#include "depsnode.h" +extern "C" { +#include "BKE_global.h" +} + +#include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_operation.h" +#include "intern/depsgraph.h" struct Main; struct Group; struct Scene; -/* Graph Building ======================================================== */ - -/** - * Build depsgraph for the given group, and dump results in given graph container - * This is usually used for building subgraphs for groups to use... - */ -void DEG_graph_build_from_group(Depsgraph *graph, struct Main *bmain, struct Group *group); - -/* Build subgraph for group */ -DepsNode *DEG_graph_build_group_subgraph(Depsgraph *graph_main, struct Main *bmain, struct Group *group); - -/* Graph Copying ========================================================= */ -/* (Part of the Filtering API) */ - -/** - * Depsgraph Copying Context (dcc) - * - * Keeps track of node relationships/links/etc. during the copy - * operation so that they can be safely remapped... - */ -typedef struct DepsgraphCopyContext { - struct GHash *nodes_hash; /* <DepsNode, DepsNode> mapping from src node to dst node */ - struct GHash *rels_hash; // XXX: same for relationships? - - // XXX: filtering criteria... -} DepsgraphCopyContext; - -/* Internal Filtering API ---------------------------------------------- */ - -/* Create filtering context */ -// XXX: needs params for conditions? -DepsgraphCopyContext *DEG_filter_init(void); - -/* Free filtering context once filtering is done */ -void DEG_filter_cleanup(DepsgraphCopyContext *dcc); - - -/* Data Copy Operations ------------------------------------------------ */ - -/** - * Make a (deep) copy of provided node and it's little subgraph - * \warning Newly created node is not added to the existing graph - * \param dcc: Context info for helping resolve links - */ -DepsNode *DEG_copy_node(DepsgraphCopyContext *dcc, const DepsNode *src); +namespace DEG { /* Node Types Handling ================================================= */ @@ -101,8 +62,9 @@ struct DepsNodeFactory { virtual eDepsNode_Class tclass() const = 0; virtual const char *tname() const = 0; - virtual DepsNode *create_node(const ID *id, const string &subdata, const string &name) const = 0; - virtual DepsNode *copy_node(DepsgraphCopyContext *dcc, const DepsNode *copy) const = 0; + virtual DepsNode *create_node(const ID *id, + const string &subdata, + const string &name) const = 0; }; template <class NodeType> @@ -130,34 +92,18 @@ struct DepsNodeFactoryImpl : public DepsNodeFactory { return node; } - - virtual DepsNode *copy_node(DepsgraphCopyContext *dcc, const DepsNode *copy) const - { - BLI_assert(copy->type == type()); - DepsNode *node = OBJECT_GUARDED_NEW(NodeType); - - /* populate base node settings */ - node->type = type(); - node->tclass = tclass(); - // XXX: need to review the name here, as we can't have exact duplicates... - node->name = copy->name; - - node->copy(dcc, static_cast<const NodeType *>(copy)); - - return node; - } }; /* Typeinfo Management -------------------------------------------------- */ /* Register typeinfo */ -void DEG_register_node_typeinfo(DepsNodeFactory *factory); +void deg_register_node_typeinfo(DepsNodeFactory *factory); /* Get typeinfo for specified type */ -DepsNodeFactory *DEG_get_node_factory(const eDepsNode_Type type); +DepsNodeFactory *deg_get_node_factory(const eDepsNode_Type type); /* Get typeinfo for provided node */ -DepsNodeFactory *DEG_node_get_factory(const DepsNode *node); +DepsNodeFactory *deg_node_get_factory(const DepsNode *node); /* Editors Integration -------------------------------------------------- */ @@ -165,4 +111,11 @@ void deg_editors_id_update(struct Main *bmain, struct ID *id); void deg_editors_scene_update(struct Main *bmain, struct Scene *scene, bool updated); -#endif /* __DEPSGRAPH_INTERN_H__ */ +#define DEG_DEBUG_PRINTF(...) \ + do { \ + if (G.debug & G_DEBUG_DEPSGRAPH) { \ + fprintf(stderr, __VA_ARGS__); \ + } \ + } while (0) + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc index 73193747b93..cac4eaae215 100644 --- a/source/blender/depsgraph/intern/depsgraph_query.cc +++ b/source/blender/depsgraph/intern/depsgraph_query.cc @@ -33,162 +33,12 @@ #include "MEM_guardedalloc.h" extern "C" { -#include "BLI_utildefines.h" -#include "BLI_ghash.h" - #include "BKE_main.h" #include "DEG_depsgraph_query.h" } /* extern "C" */ -#include "depsgraph_queue.h" -#include "depsnode.h" -#include "depsnode_operation.h" -#include "depsgraph_intern.h" - -/* ************************* */ -/* Low-Level Graph Traversal */ - -#if 0 -/* Prepare for graph traversal, by tagging nodes, etc. */ -static void DEG_graph_traverse_begin(Depsgraph * /*graph*/) -{ - /* go over all nodes, initialising the valence counts */ - // XXX: this will end up being O(|V|), which is bad when we're just updating a few nodes... -} - -/* Perform a traversal of graph from given starting node (in execution order) */ -// TODO: additional flags for controlling the process? -void DEG_graph_traverse_from_node(Depsgraph *graph, OperationDepsNode *start_node, - DEG_FilterPredicate filter, void *filter_data, - DEG_NodeOperation op, void *operation_data) -{ - DepsgraphQueue *q; - - /* sanity checks */ - if (ELEM(NULL, graph, start_node, op)) - return; - - /* add node as starting node to be evaluated, with value of 0 */ - q = DEG_queue_new(); - - start_node->num_links_pending = 0; - DEG_queue_push(q, start_node, 0.0f); - - /* while we still have nodes in the queue, grab and work on next one */ - do { - /* grab item at front of queue */ - // XXX: in practice, we may need to wait until one becomes available... - OperationDepsNode *node = (OperationDepsNode *)DEG_queue_pop(q); - - /* perform operation on node */ - op(graph, node, operation_data); - - /* schedule up operations which depend on this */ - DEPSNODE_RELATIONS_ITER_BEGIN(node->outlinks, rel) - { - /* ensure that relationship is not tagged for ignoring (i.e. cyclic, etc.) */ - // TODO: cyclic refs should probably all get clustered towards the end, so that we can just stop on the first one - if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) { - OperationDepsNode *child_node = (OperationDepsNode *)rel->to; - - /* only visit node if the filtering function agrees */ - if ((filter == NULL) || filter(graph, child_node, filter_data)) { - /* schedule up node... */ - child_node->num_links_pending--; - DEG_queue_push(q, child_node, (float)child_node->num_links_pending); - } - } - } - DEPSNODE_RELATIONS_ITER_END; - } while (DEG_queue_is_empty(q) == false); - - /* cleanup */ - DEG_queue_free(q); -} -#endif - -/* ************************************************************** */ -/* Filtering API - Basically, making a copy of the existing graph */ - -/* Create filtering context */ -// TODO: allow passing in a number of criteria? -DepsgraphCopyContext *DEG_filter_init() -{ - DepsgraphCopyContext *dcc = (DepsgraphCopyContext *)MEM_callocN(sizeof(DepsgraphCopyContext), "DepsgraphCopyContext"); - - /* init hashes for easy lookups */ - dcc->nodes_hash = BLI_ghash_ptr_new("Depsgraph Filter NodeHash"); - dcc->rels_hash = BLI_ghash_ptr_new("Depsgraph Filter Relationship Hash"); // XXX? - - /* store filtering criteria? */ - // xxx... - - return dcc; -} - -/* Cleanup filtering context */ -void DEG_filter_cleanup(DepsgraphCopyContext *dcc) -{ - /* sanity check */ - if (dcc == NULL) - return; - - /* free hashes - contents are weren't copied, so are ok... */ - BLI_ghash_free(dcc->nodes_hash, NULL, NULL); - BLI_ghash_free(dcc->rels_hash, NULL, NULL); - - /* clear filtering criteria */ - // ... - - /* free dcc itself */ - MEM_freeN(dcc); -} - -/* -------------------------------------------------- */ - -/* Create a copy of provided node */ -// FIXME: the handling of sub-nodes and links will need to be subject to filtering options... -// XXX: perhaps this really shouldn't be exposed, as it will just be a sub-step of the evaluation process? -DepsNode *DEG_copy_node(DepsgraphCopyContext *dcc, const DepsNode *src) -{ - /* sanity check */ - if (src == NULL) - return NULL; - - DepsNodeFactory *factory = DEG_get_node_factory(src->type); - BLI_assert(factory != NULL); - DepsNode *dst = factory->copy_node(dcc, src); - - /* add this node-pair to the hash... */ - BLI_ghash_insert(dcc->nodes_hash, (DepsNode *)src, dst); - -#if 0 /* XXX TODO */ - /* now, fix up any links in standard "node header" (i.e. DepsNode struct, that all - * all others are derived from) that are now corrupt - */ - { - /* relationships to other nodes... */ - // FIXME: how to handle links? We may only have partial set of all nodes still? - // XXX: the exact details of how to handle this are really part of the querying API... - - // XXX: BUT, for copying subgraphs, we'll need to define an API for doing this stuff anyways - // (i.e. for resolving and patching over links that exist within subtree...) - dst->inlinks.clear(); - dst->outlinks.clear(); - - /* clear traversal data */ - dst->num_links_pending = 0; - dst->lasttime = 0; - } - - /* fix links */ - // XXX... -#endif - - /* return copied node */ - return dst; -} +#include "intern/depsgraph_intern.h" bool DEG_id_type_tagged(Main *bmain, short idtype) { @@ -207,7 +57,9 @@ short DEG_get_eval_flags_for_id(Depsgraph *graph, ID *id) return 0; } - IDDepsNode *id_node = graph->find_id_node(id); + DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); + + DEG::IDDepsNode *id_node = deg_graph->find_id_node(id); if (id_node == NULL) { /* TODO(sergey): Does it mean we need to check set scene? */ return 0; diff --git a/source/blender/depsgraph/intern/depsgraph_queue.cc b/source/blender/depsgraph/intern/depsgraph_queue.cc deleted file mode 100644 index da60d73bc46..00000000000 --- a/source/blender/depsgraph/intern/depsgraph_queue.cc +++ /dev/null @@ -1,177 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2013 Blender Foundation. - * All rights reserved. - * - * Original Author: Joshua Leung - * Contributor(s): None Yet - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/depsgraph/intern/depsgraph_queue.cc - * \ingroup depsgraph - * - * Implementation of special queue type for use in Depsgraph traversals. - */ - -#include <stdlib.h> - -#include "MEM_guardedalloc.h" - -extern "C" { -#include "BLI_utildefines.h" -#include "BLI_heap.h" -#include "BLI_ghash.h" -} /* extern "C" */ - -#include "depsgraph_queue.h" - -/* ****************************** */ -/* Depsgraph Queue implementation */ - -/* Data Management ----------------------------------------- */ - -DepsgraphQueue *DEG_queue_new(void) -{ - DepsgraphQueue *q = (DepsgraphQueue *)MEM_callocN(sizeof(DepsgraphQueue), "DEG_queue_new()"); - - /* init data structures for use here */ - q->pending_heap = BLI_heap_new(); - q->pending_hash = BLI_ghash_ptr_new("DEG Queue Pending Hash"); - - q->ready_heap = BLI_heap_new(); - - /* init settings */ - q->idx = 0; - q->tot = 0; - - /* return queue */ - return q; -} - -void DEG_queue_free(DepsgraphQueue *q) -{ - /* free data structures */ - BLI_assert(BLI_heap_size(q->pending_heap) == 0); - BLI_assert(BLI_heap_size(q->ready_heap) == 0); - BLI_assert(BLI_ghash_size(q->pending_hash) == 0); - - BLI_heap_free(q->pending_heap, NULL); - BLI_heap_free(q->ready_heap, NULL); - BLI_ghash_free(q->pending_hash, NULL, NULL); - - /* free queue itself */ - MEM_freeN(q); -} - -/* Statistics --------------------------------------------- */ - -/* Get the number of nodes which are we should visit, but are not able to yet */ -size_t DEG_queue_num_pending(DepsgraphQueue *q) -{ - return BLI_heap_size(q->pending_heap); -} - -/* Get the number of nodes which are now ready to be visited */ -size_t DEG_queue_num_ready(DepsgraphQueue *q) -{ - return BLI_heap_size(q->ready_heap); -} - -/* Get total size of queue */ -size_t DEG_queue_size(DepsgraphQueue *q) -{ - return DEG_queue_num_pending(q) + DEG_queue_num_ready(q); -} - -/* Check if queue has any items in it (still passing through) */ -bool DEG_queue_is_empty(DepsgraphQueue *q) -{ - return DEG_queue_size(q) == 0; -} - -/* Queue Operations --------------------------------------- */ - -/** - * Add DepsNode to the queue - * \param dnode: ``(DepsNode *)`` node to add to the queue - * Each node is only added once to the queue; Subsequent pushes - * merely update its status (e.g. moving it from "pending" to "ready") - * \param cost: new "num_links_pending" count for node *after* it has encountered - * via an outlink from the node currently being visited - * (i.e. we're one of the dependencies which may now be able to be processed) - */ -void DEG_queue_push(DepsgraphQueue *q, void *dnode, float cost) -{ - HeapNode *hnode = NULL; - - /* Shortcut: Directly add to ready if node isn't waiting on anything now... */ - if (cost == 0) { - /* node is now ready to be visited - schedule it up for such */ - if (BLI_ghash_haskey(q->pending_hash, dnode)) { - /* remove from pending queue - we're moving it to the scheduling queue */ - hnode = (HeapNode *)BLI_ghash_lookup(q->pending_hash, dnode); - BLI_heap_remove(q->pending_heap, hnode); - - BLI_ghash_remove(q->pending_hash, dnode, NULL, NULL); - } - - /* schedule up node using latest count (of ready nodes) */ - BLI_heap_insert(q->ready_heap, (float)q->idx, dnode); - q->idx++; - } - else { - /* node is still waiting on some other ancestors, - * so add it to the pending heap in the meantime... - */ - // XXX: is this even necessary now? - if (BLI_ghash_haskey(q->pending_hash, dnode)) { - /* just update cost on pending node */ - hnode = (HeapNode *)BLI_ghash_lookup(q->pending_hash, dnode); - BLI_heap_remove(q->pending_heap, hnode); - BLI_heap_insert(q->pending_heap, cost, hnode); - } - else { - /* add new node to pending queue, and increase size of overall queue */ - hnode = BLI_heap_insert(q->pending_heap, cost, dnode); - q->tot++; - } - } -} - -/* Grab a "ready" node from the queue */ -void *DEG_queue_pop(DepsgraphQueue *q) -{ - /* sanity check: if there are no "ready" nodes, - * start pulling from "pending" to keep things moving, - * but throw a warning so that we know that something's up here... - */ - if (BLI_heap_is_empty(q->ready_heap)) { - // XXX: this should never happen - // XXX: if/when it does happen, we may want instead to just wait until something pops up here... - printf("DepsgraphHeap Warning: No more ready nodes available. Trying from pending (idx = %d, tot = %d, pending = %d, ready = %d)\n", - (int)q->idx, (int)q->tot, (int)DEG_queue_num_pending(q), (int)DEG_queue_num_ready(q)); - - return BLI_heap_popmin(q->pending_heap); - } - else { - /* only grab "ready" nodes */ - return BLI_heap_popmin(q->ready_heap); - } -} diff --git a/source/blender/depsgraph/intern/depsgraph_queue.h b/source/blender/depsgraph/intern/depsgraph_queue.h deleted file mode 100644 index b85d46bd173..00000000000 --- a/source/blender/depsgraph/intern/depsgraph_queue.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2013 Blender Foundation. - * All rights reserved. - * - * Original Author: Joshua Leung - * Contributor(s): None Yet - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/depsgraph/intern/depsgraph_queue.h - * \ingroup depsgraph - * - * Defines for special queue type for use in Depsgraph traversals. - */ - -#ifndef __DEPSGRAPH_QUEUE_H__ -#define __DEPSGRAPH_QUEUE_H__ - -struct DepsNode; - -struct Heap; -struct GHash; - -/* *********************************************** */ -/* Dependency Graph Traversal Queue - * - * There are two parts to this: - * a) "Pending" Nodes - This part contains the set of nodes - * which are related to those which have been visited - * previously, but are not yet ready to actually be visited. - * b) "Scheduled" Nodes - These are the nodes whose ancestors - * have all been evaluated already, which means that any - * or all of them can be picked (in practically in order) to - * be visited immediately. - * - * Internally, the queue makes sure that each node in the graph - * only gets added to the queue once. This is because there can - * be multiple inlinks to each node given the way that the relations - * work. - */ - -/* Depsgraph Queue Type */ -typedef struct DepsgraphQueue { - /* Pending */ - struct Heap *pending_heap; /* (valence:int, DepsNode*) */ - struct GHash *pending_hash; /* (DepsNode* : HeapNode*>) */ - - /* Ready to be visited - fifo */ - struct Heap *ready_heap; /* (idx:int, DepsNode*) */ - - /* Size/Order counts */ - size_t idx; /* total number of nodes which are/have been ready so far (including those already visited) */ - size_t tot; /* total number of nodes which have passed through queue; mainly for debug */ -} DepsgraphQueue; - -/* ************************** */ -/* Depsgraph Queue Operations */ - -/* Data management */ -DepsgraphQueue *DEG_queue_new(void); -void DEG_queue_free(DepsgraphQueue *q); - -/* Statistics */ -size_t DEG_queue_num_pending(DepsgraphQueue *q); -size_t DEG_queue_num_ready(DepsgraphQueue *q); - -size_t DEG_queue_size(DepsgraphQueue *q); -bool DEG_queue_is_empty(DepsgraphQueue *q); - -/* Operations */ -void DEG_queue_push(DepsgraphQueue *q, void *dnode, float cost = 0.0f); -void *DEG_queue_pop(DepsgraphQueue *q); - -#endif /* DEPSGRAPH_QUEUE_H */ diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index f00bce29f64..7c048751869 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -54,11 +54,14 @@ extern "C" { #include "DEG_depsgraph.h" } /* extern "C" */ -#include "depsgraph_debug.h" -#include "depsnode.h" -#include "depsnode_component.h" -#include "depsnode_operation.h" -#include "depsgraph_intern.h" +#include "intern/eval/deg_eval_flush.h" + +#include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_operation.h" + +#include "intern/depsgraph_intern.h" +#include "util/deg_util_foreach.h" /* *********************** */ /* Update Tagging/Flushing */ @@ -126,19 +129,21 @@ void lib_id_recalc_tag_flag(Main *bmain, ID *id, int flag) */ void DEG_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id) { - IDDepsNode *node = graph->find_id_node(id); + DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); + DEG::IDDepsNode *node = deg_graph->find_id_node(id); lib_id_recalc_tag(bmain, id); if (node != NULL) { - node->tag_update(graph); + node->tag_update(deg_graph); } } /* Tag nodes related to a specific piece of data */ void DEG_graph_data_tag_update(Depsgraph *graph, const PointerRNA *ptr) { - DepsNode *node = graph->find_node_from_pointer(ptr, NULL); - if (node) { - node->tag_update(graph); + DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); + DEG::DepsNode *node = deg_graph->find_node_from_pointer(ptr, NULL); + if (node != NULL) { + node->tag_update(deg_graph); } else { printf("Missing node in %s\n", __func__); @@ -151,9 +156,10 @@ void DEG_graph_property_tag_update(Depsgraph *graph, const PointerRNA *ptr, const PropertyRNA *prop) { - DepsNode *node = graph->find_node_from_pointer(ptr, prop); - if (node) { - node->tag_update(graph); + DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); + DEG::DepsNode *node = deg_graph->find_node_from_pointer(ptr, prop); + if (node != NULL) { + node->tag_update(deg_graph); } else { printf("Missing node in %s\n", __func__); @@ -223,131 +229,6 @@ void DEG_id_type_tag(Main *bmain, short idtype) bmain->id_tag_update[((unsigned char *)&idtype)[0]] = 1; } -/* Update Flushing ---------------------------------- */ - -/* FIFO queue for tagged nodes that need flushing */ -/* XXX This may get a dedicated implementation later if needed - lukas */ -typedef std::queue<OperationDepsNode *> FlushQueue; - -static void flush_init_func(void *data_v, int i) -{ - /* ID node's done flag is used to avoid multiple editors update - * for the same ID. - */ - Depsgraph *graph = (Depsgraph *)data_v; - OperationDepsNode *node = graph->operations[i]; - IDDepsNode *id_node = node->owner->owner; - id_node->done = 0; - node->scheduled = false; - node->owner->flags &= ~DEPSCOMP_FULLY_SCHEDULED; -} - -/* Flush updates from tagged nodes outwards until all affected nodes are tagged. */ -void DEG_graph_flush_updates(Main *bmain, Depsgraph *graph) -{ - /* sanity check */ - if (graph == NULL) - return; - - /* Nothing to update, early out. */ - if (graph->entry_tags.size() == 0) { - return; - } - - /* TODO(sergey): With a bit of flag magic we can get rid of this - * extra loop. - */ - const int num_operations = graph->operations.size(); - const bool do_threads = num_operations > 256; - BLI_task_parallel_range(0, num_operations, graph, flush_init_func, do_threads); - - FlushQueue queue; - /* Starting from the tagged "entry" nodes, flush outwards... */ - /* NOTE: Also need to ensure that for each of these, there is a path back to - * root, or else they won't be done. - * NOTE: Count how many nodes we need to handle - entry nodes may be - * component nodes which don't count for this purpose! - */ - for (Depsgraph::EntryTags::const_iterator it = graph->entry_tags.begin(); - it != graph->entry_tags.end(); - ++it) - { - OperationDepsNode *node = *it; - IDDepsNode *id_node = node->owner->owner; - queue.push(node); - if (id_node->done == 0) { - deg_editors_id_update(bmain, id_node->id); - id_node->done = 1; - } - node->scheduled = true; - } - - while (!queue.empty()) { - OperationDepsNode *node = queue.front(); - queue.pop(); - - IDDepsNode *id_node = node->owner->owner; - lib_id_recalc_tag(bmain, id_node->id); - /* TODO(sergey): For until we've got proper data nodes in the graph. */ - lib_id_recalc_data_tag(bmain, id_node->id); - - ID *id = id_node->id; - /* This code is used to preserve those areas which does direct - * object update, - * - * Plus it ensures visibility changes and relations and layers - * visibility update has proper flags to work with. - */ - if (GS(id->name) == ID_OB) { - Object *object = (Object *)id; - ComponentDepsNode *comp_node = node->owner; - if (comp_node->type == DEPSNODE_TYPE_ANIMATION) { - object->recalc |= OB_RECALC_TIME; - } - else if (comp_node->type == DEPSNODE_TYPE_TRANSFORM) { - object->recalc |= OB_RECALC_OB; - } - else { - object->recalc |= OB_RECALC_DATA; - } - } - - /* Flush to nodes along links... */ - for (OperationDepsNode::Relations::const_iterator it = node->outlinks.begin(); - it != node->outlinks.end(); - ++it) - { - DepsRelation *rel = *it; - OperationDepsNode *to_node = (OperationDepsNode *)rel->to; - if (to_node->scheduled == false) { - to_node->flag |= DEPSOP_FLAG_NEEDS_UPDATE; - queue.push(to_node); - to_node->scheduled = true; - if (id_node->done == 0) { - deg_editors_id_update(bmain, id_node->id); - id_node->done = 1; - } - } - } - - /* TODO(sergey): For until incremental updates are possible - * witin a component at least we tag the whole component - * for update. - */ - ComponentDepsNode *component = node->owner; - if ((component->flags & DEPSCOMP_FULLY_SCHEDULED) == 0) { - for (ComponentDepsNode::OperationMap::iterator it = component->operations.begin(); - it != node->owner->operations.end(); - ++it) - { - OperationDepsNode *op = it->second; - op->flag |= DEPSOP_FLAG_NEEDS_UPDATE; - } - component->flags |= DEPSCOMP_FULLY_SCHEDULED; - } - } -} - /* Recursively push updates out to all nodes dependent on this, * until all affected are tagged and/or scheduled up for eval */ @@ -359,34 +240,17 @@ void DEG_ids_flush_tagged(Main *bmain) { /* TODO(sergey): Only visible scenes? */ if (scene->depsgraph != NULL) { - DEG_graph_flush_updates(bmain, scene->depsgraph); + DEG::deg_graph_flush_updates( + bmain, + reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph)); } } } -static void graph_clear_func(void *data_v, int i) -{ - Depsgraph *graph = (Depsgraph *)data_v; - OperationDepsNode *node = graph->operations[i]; - /* Clear node's "pending update" settings. */ - node->flag &= ~(DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE); -} - -/* Clear tags from all operation nodes. */ -void DEG_graph_clear_tags(Depsgraph *graph) -{ - /* Go over all operation nodes, clearing tags. */ - const int num_operations = graph->operations.size(); - const bool do_threads = num_operations > 256; - BLI_task_parallel_range(0, num_operations, graph, graph_clear_func, do_threads); - /* Clear any entry tags which haven't been flushed. */ - graph->entry_tags.clear(); -} - /* Update dependency graph when visible scenes/layers changes. */ void DEG_graph_on_visible_update(Main *bmain, Scene *scene) { - Depsgraph *graph = scene->depsgraph; + DEG::Depsgraph *graph = reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph); wmWindowManager *wm = (wmWindowManager *)bmain->wm.first; int old_layers = graph->layers; if (wm != NULL) { @@ -414,11 +278,8 @@ void DEG_graph_on_visible_update(Main *bmain, Scene *scene) * This is mainly needed on file load only, after that updates of invisible objects * will be stored in the pending list. */ - for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin(); - it != graph->id_hash.end(); - ++it) + GHASH_FOREACH_BEGIN(DEG::IDDepsNode *, id_node, graph->id_hash) { - IDDepsNode *id_node = it->second; ID *id = id_node->id; if ((id->tag & LIB_TAG_ID_RECALC_ALL) != 0 || (id_node->layers & scene->lay_updated) == 0) @@ -436,14 +297,15 @@ void DEG_graph_on_visible_update(Main *bmain, Scene *scene) (object->recalc & OB_RECALC_ALL) != 0) { id_node->tag_update(graph); - ComponentDepsNode *anim_comp = - id_node->find_component(DEPSNODE_TYPE_ANIMATION); + DEG::ComponentDepsNode *anim_comp = + id_node->find_component(DEG::DEPSNODE_TYPE_ANIMATION); if (anim_comp != NULL && object->recalc & OB_RECALC_TIME) { anim_comp->tag_update(graph); } } } } + GHASH_FOREACH_END(); } scene->lay_updated |= graph->layers; } @@ -484,7 +346,7 @@ void DEG_ids_check_recalc(Main *bmain, Scene *scene, bool time) } } - deg_editors_scene_update(bmain, scene, (updated || time)); + DEG::deg_editors_scene_update(bmain, scene, (updated || time)); } void DEG_ids_clear_recalc(Main *bmain) diff --git a/source/blender/depsgraph/intern/depsgraph_type_defines.cc b/source/blender/depsgraph/intern/depsgraph_type_defines.cc index 5a3048a4aa3..97208939e57 100644 --- a/source/blender/depsgraph/intern/depsgraph_type_defines.cc +++ b/source/blender/depsgraph/intern/depsgraph_type_defines.cc @@ -30,6 +30,8 @@ * Defines and code for core node types. */ +#include <cstdlib> // for BLI_assert() + extern "C" { #include "BLI_utildefines.h" #include "BLI_ghash.h" @@ -37,10 +39,13 @@ extern "C" { #include "DEG_depsgraph.h" } /* extern "C" */ -#include "depsgraph_intern.h" -#include "depsnode.h" -#include "depsnode_component.h" -#include "depsnode_operation.h" +#include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_operation.h" + +#include "intern/depsgraph_intern.h" + +namespace DEG { /* ************ */ /* External API */ @@ -59,44 +64,108 @@ static GHash *_depsnode_typeinfo_registry = NULL; /* Registration ------------------------------------------- */ /* Register node type */ -void DEG_register_node_typeinfo(DepsNodeFactory *factory) +void deg_register_node_typeinfo(DepsNodeFactory *factory) { BLI_assert(factory != NULL); BLI_ghash_insert(_depsnode_typeinfo_registry, SET_INT_IN_POINTER(factory->type()), factory); } -/* Register all node types */ -void DEG_register_node_types(void) -{ - /* initialise registry */ - _depsnode_typeinfo_registry = BLI_ghash_int_new("Depsgraph Node Type Registry"); - - /* register node types */ - DEG_register_base_depsnodes(); - DEG_register_component_depsnodes(); - DEG_register_operation_depsnodes(); -} - -/* Free registry on exit */ -void DEG_free_node_types(void) -{ - BLI_ghash_free(_depsnode_typeinfo_registry, NULL, NULL); -} - /* Getters ------------------------------------------------- */ /* Get typeinfo for specified type */ -DepsNodeFactory *DEG_get_node_factory(const eDepsNode_Type type) +DepsNodeFactory *deg_get_node_factory(const eDepsNode_Type type) { /* look up type - at worst, it doesn't exist in table yet, and we fail */ return (DepsNodeFactory *)BLI_ghash_lookup(_depsnode_typeinfo_registry, SET_INT_IN_POINTER(type)); } /* Get typeinfo for provided node */ -DepsNodeFactory *DEG_node_get_factory(const DepsNode *node) +DepsNodeFactory *deg_node_get_factory(const DepsNode *node) { - if (!node) + if (node != NULL) { return NULL; + } + return deg_get_node_factory(node->type); +} + +/* Stringified opcodes ------------------------------------- */ + +DepsOperationStringifier DEG_OPNAMES; - return DEG_get_node_factory(node->type); +static const char *stringify_opcode(eDepsOperation_Code opcode) +{ + switch (opcode) { +#define STRINGIFY_OPCODE(name) case DEG_OPCODE_##name: return #name + STRINGIFY_OPCODE(OPERATION); + STRINGIFY_OPCODE(PLACEHOLDER); + STRINGIFY_OPCODE(NOOP); + STRINGIFY_OPCODE(ANIMATION); + STRINGIFY_OPCODE(DRIVER); + //STRINGIFY_OPCODE(PROXY); + STRINGIFY_OPCODE(TRANSFORM_LOCAL); + STRINGIFY_OPCODE(TRANSFORM_PARENT); + STRINGIFY_OPCODE(TRANSFORM_CONSTRAINTS); + //STRINGIFY_OPCODE(TRANSFORM_CONSTRAINTS_INIT); + //STRINGIFY_OPCODE(TRANSFORM_CONSTRAINT); + //STRINGIFY_OPCODE(TRANSFORM_CONSTRAINTS_DONE); + STRINGIFY_OPCODE(RIGIDBODY_REBUILD); + STRINGIFY_OPCODE(RIGIDBODY_SIM); + STRINGIFY_OPCODE(TRANSFORM_RIGIDBODY); + STRINGIFY_OPCODE(TRANSFORM_FINAL); + STRINGIFY_OPCODE(OBJECT_UBEREVAL); + STRINGIFY_OPCODE(GEOMETRY_UBEREVAL); + STRINGIFY_OPCODE(GEOMETRY_MODIFIER); + STRINGIFY_OPCODE(GEOMETRY_PATH); + STRINGIFY_OPCODE(POSE_INIT); + STRINGIFY_OPCODE(POSE_DONE); + STRINGIFY_OPCODE(POSE_IK_SOLVER); + STRINGIFY_OPCODE(POSE_SPLINE_IK_SOLVER); + STRINGIFY_OPCODE(BONE_LOCAL); + STRINGIFY_OPCODE(BONE_POSE_PARENT); + STRINGIFY_OPCODE(BONE_CONSTRAINTS); + //STRINGIFY_OPCODE(BONE_CONSTRAINTS_INIT); + //STRINGIFY_OPCODE(BONE_CONSTRAINT); + //STRINGIFY_OPCODE(BONE_CONSTRAINTS_DONE); + STRINGIFY_OPCODE(BONE_READY); + STRINGIFY_OPCODE(BONE_DONE); + STRINGIFY_OPCODE(PSYS_EVAL); + + case DEG_NUM_OPCODES: return "SpecialCase"; +#undef STRINGIFY_OPCODE + } + return "UNKNOWN"; +} + +DepsOperationStringifier::DepsOperationStringifier() { + for (int i = 0; i < DEG_NUM_OPCODES; ++i) { + names_[i] = stringify_opcode((eDepsOperation_Code)i); + } +} + +const char *DepsOperationStringifier::operator[](eDepsOperation_Code opcode) { + BLI_assert((opcode > 0) && (opcode < DEG_NUM_OPCODES)); + if (opcode >= 0 && opcode < DEG_NUM_OPCODES) { + return names_[opcode]; + } + return "UnknownOpcode"; +} + +} // namespace DEG + +/* Register all node types */ +void DEG_register_node_types(void) +{ + /* initialise registry */ + DEG::_depsnode_typeinfo_registry = BLI_ghash_int_new("Depsgraph Node Type Registry"); + + /* register node types */ + DEG::deg_register_base_depsnodes(); + DEG::deg_register_component_depsnodes(); + DEG::deg_register_operation_depsnodes(); +} + +/* Free registry on exit */ +void DEG_free_node_types(void) +{ + BLI_ghash_free(DEG::_depsnode_typeinfo_registry, NULL, NULL); } diff --git a/source/blender/depsgraph/intern/depsgraph_types.h b/source/blender/depsgraph/intern/depsgraph_types.h index f5fbf0bcc76..7516ccbfdc2 100644 --- a/source/blender/depsgraph/intern/depsgraph_types.h +++ b/source/blender/depsgraph/intern/depsgraph_types.h @@ -34,10 +34,9 @@ * in the graph. */ -#ifndef __DEPSGRAPH_TYPES_H__ -#define __DEPSGRAPH_TYPES_H__ +#pragma once -#include "depsgraph_util_function.h" +#include "util/deg_util_function.h" /* TODO(sergey): Ideally we'll just use char* and statically allocated strings * to avoid any possible overhead caused by string (re)allocation/formatting. @@ -55,69 +54,232 @@ struct PointerRNA; struct EvaluationContext; struct FCurve; +namespace DEG { + /* Evaluation Operation for atomic operation */ // XXX: move this to another header that can be exposed? typedef function<void(struct EvaluationContext *)> DepsEvalOperationCb; -/* Metatype of Nodes - The general "level" in the graph structure the node serves */ +/* Metatype of Nodes - The general "level" in the graph structure + * the node serves. + */ typedef enum eDepsNode_Class { - DEPSNODE_CLASS_GENERIC = 0, /* Types generally unassociated with user-visible entities, but needed for graph functioning */ - - DEPSNODE_CLASS_COMPONENT = 1, /* [Outer Node] An "aspect" of evaluating/updating an ID-Block, requiring certain types of evaluation behaviours */ - DEPSNODE_CLASS_OPERATION = 2, /* [Inner Node] A glorified function-pointer/callback for scheduling up evaluation operations for components, subject to relationship requirements */ + /* Types generally unassociated with user-visible entities, + * but needed for graph functioning. + */ + DEPSNODE_CLASS_GENERIC = 0, + /* [Outer Node] An "aspect" of evaluating/updating an ID-Block, requiring + * certain types of evaluation behavior. + */ + DEPSNODE_CLASS_COMPONENT = 1, + /* [Inner Node] A glorified function-pointer/callback for scheduling up + * evaluation operations for components, subject to relationship + * requirements. + */ + DEPSNODE_CLASS_OPERATION = 2, } eDepsNode_Class; /* Types of Nodes */ typedef enum eDepsNode_Type { - DEPSNODE_TYPE_UNDEFINED = -1, /* fallback type for invalid return value */ + /* Fallback type for invalid return value */ + DEPSNODE_TYPE_UNDEFINED = -1, + /* Inner Node (Operation) */ + DEPSNODE_TYPE_OPERATION = 0, + + /* **** Generic Types **** */ + + /* "Current Scene" - basically whatever kicks off the evaluation process. */ + DEPSNODE_TYPE_ROOT = 1, + /* Time-Source */ + DEPSNODE_TYPE_TIMESOURCE = 2, + /* ID-Block reference - used as landmarks/collection point for components, + * but not usually part of main graph. + */ + DEPSNODE_TYPE_ID_REF = 3, + /* Isolated sub-graph - used for keeping instanced data separate from + * instances using them. + */ + DEPSNODE_TYPE_SUBGRAPH = 4, - DEPSNODE_TYPE_OPERATION = 0, /* Inner Node (Operation) */ + /* **** Outer Types **** */ - /* Generic Types */ - DEPSNODE_TYPE_ROOT = 1, /* "Current Scene" - basically whatever kicks off the evaluation process */ - DEPSNODE_TYPE_TIMESOURCE = 2, /* Time-Source */ + /* Parameters Component - Default when nothing else fits + * (i.e. just SDNA property setting). + */ + DEPSNODE_TYPE_PARAMETERS = 11, + /* Generic "Proxy-Inherit" Component + * XXX: Also for instancing of subgraphs? + */ + DEPSNODE_TYPE_PROXY = 12, + /* Animation Component + * + * XXX: merge in with parameters? + */ + DEPSNODE_TYPE_ANIMATION = 13, + /* Transform Component (Parenting/Constraints) */ + DEPSNODE_TYPE_TRANSFORM = 14, + /* Geometry Component (DerivedMesh/Displist) */ + DEPSNODE_TYPE_GEOMETRY = 15, + /* Sequencer Component (Scene Only) */ + DEPSNODE_TYPE_SEQUENCER = 16, + + /* **** Evaluation-Related Outer Types (with Subdata) **** */ + + /* Pose Component - Owner/Container of Bones Eval */ + DEPSNODE_TYPE_EVAL_POSE = 21, + /* Bone Component - Child/Subcomponent of Pose */ + DEPSNODE_TYPE_BONE = 22, + /* Particle Systems Component */ + DEPSNODE_TYPE_EVAL_PARTICLES = 23, + /* Material Shading Component */ + DEPSNODE_TYPE_SHADING = 24, +} eDepsNode_Type; - DEPSNODE_TYPE_ID_REF = 3, /* ID-Block reference - used as landmarks/collection point for components, but not usually part of main graph */ - DEPSNODE_TYPE_SUBGRAPH = 4, /* Isolated sub-graph - used for keeping instanced data separate from instances using them */ +/* Identifiers for common operations (as an enum). */ +typedef enum eDepsOperation_Code { + /* Generic Operations ------------------------------ */ - /* Outer Types */ - DEPSNODE_TYPE_PARAMETERS = 11, /* Parameters Component - Default when nothing else fits (i.e. just SDNA property setting) */ - DEPSNODE_TYPE_PROXY = 12, /* Generic "Proxy-Inherit" Component */ // XXX: Also for instancing of subgraphs? - DEPSNODE_TYPE_ANIMATION = 13, /* Animation Component */ // XXX: merge in with parameters? - DEPSNODE_TYPE_TRANSFORM = 14, /* Transform Component (Parenting/Constraints) */ - DEPSNODE_TYPE_GEOMETRY = 15, /* Geometry Component (DerivedMesh/Displist) */ - DEPSNODE_TYPE_SEQUENCER = 16, /* Sequencer Component (Scene Only) */ + /* Placeholder for operations which don't need special mention */ + DEG_OPCODE_OPERATION = 0, - /* Evaluation-Related Outer Types (with Subdata) */ - DEPSNODE_TYPE_EVAL_POSE = 21, /* Pose Component - Owner/Container of Bones Eval */ - DEPSNODE_TYPE_BONE = 22, /* Bone Component - Child/Subcomponent of Pose */ + // XXX: Placeholder while porting depsgraph code + DEG_OPCODE_PLACEHOLDER, - DEPSNODE_TYPE_EVAL_PARTICLES = 23, /* Particle Systems Component */ - DEPSNODE_TYPE_SHADING = 24, /* Material Shading Component */ -} eDepsNode_Type; + DEG_OPCODE_NOOP, -/* Identifiers for common operations (as an enum) */ -typedef enum eDepsOperation_Code { -#define DEF_DEG_OPCODE(label) DEG_OPCODE_##label, -#include "depsnode_opcodes.h" -#undef DEF_DEG_OPCODE + /* Animation, Drivers, etc. ------------------------ */ + + /* NLA + Action */ + DEG_OPCODE_ANIMATION, + + /* Driver */ + DEG_OPCODE_DRIVER, + + /* Proxy Inherit? */ + //DEG_OPCODE_PROXY, + + /* Transform --------------------------------------- */ + + /* Transform entry point - local transforms only */ + DEG_OPCODE_TRANSFORM_LOCAL, + + /* Parenting */ + DEG_OPCODE_TRANSFORM_PARENT, + + /* Constraints */ + DEG_OPCODE_TRANSFORM_CONSTRAINTS, + //DEG_OPCODE_TRANSFORM_CONSTRAINTS_INIT, + //DEG_OPCODE_TRANSFORM_CONSTRAINT, + //DEG_OPCODE_TRANSFORM_CONSTRAINTS_DONE, + + /* Rigidbody Sim - Perform Sim */ + DEG_OPCODE_RIGIDBODY_REBUILD, + DEG_OPCODE_RIGIDBODY_SIM, + + /* Rigidbody Sim - Copy Results to Object */ + DEG_OPCODE_TRANSFORM_RIGIDBODY, + + /* Transform exitpoint */ + DEG_OPCODE_TRANSFORM_FINAL, + + /* XXX: ubereval is for temporary porting purposes only */ + DEG_OPCODE_OBJECT_UBEREVAL, + + /* Geometry ---------------------------------------- */ + + /* XXX: Placeholder - UberEval */ + DEG_OPCODE_GEOMETRY_UBEREVAL, + + /* Modifier */ + DEG_OPCODE_GEOMETRY_MODIFIER, + + /* Curve Objects - Path Calculation (used for path-following tools, */ + DEG_OPCODE_GEOMETRY_PATH, + + /* Pose -------------------------------------------- */ + + /* Init IK Trees, etc. */ + DEG_OPCODE_POSE_INIT, + + /* Free IK Trees + Compute Deform Matrices */ + DEG_OPCODE_POSE_DONE, + + /* IK/Spline Solvers */ + DEG_OPCODE_POSE_IK_SOLVER, + DEG_OPCODE_POSE_SPLINE_IK_SOLVER, + + /* Bone -------------------------------------------- */ + + /* Bone local transforms - Entrypoint */ + DEG_OPCODE_BONE_LOCAL, + + /* Pose-space conversion (includes parent + restpose, */ + DEG_OPCODE_BONE_POSE_PARENT, + + /* Constraints */ + DEG_OPCODE_BONE_CONSTRAINTS, + //DEG_OPCODE_BONE_CONSTRAINTS_INIT, + //DEG_OPCODE_BONE_CONSTRAINT, + //DEG_OPCODE_BONE_CONSTRAINTS_DONE, + + /* Bone transforms are ready + * + * - "READY" This (internal, noop is used to signal that all pre-IK + * operations are done. Its role is to help mediate situations + * where cyclic relations may otherwise form (i.e. one bone in + * chain targetting another in same chain, + * + * - "DONE" This noop is used to signal that the bone's final pose + * transform can be read by others + */ + // TODO: deform mats could get calculated in the final_transform ops... + DEG_OPCODE_BONE_READY, + DEG_OPCODE_BONE_DONE, + + /* Particles --------------------------------------- */ + + /* XXX: placeholder - Particle System eval */ + DEG_OPCODE_PSYS_EVAL, + + DEG_NUM_OPCODES, } eDepsOperation_Code; -/* String defines for these opcodes, defined in depsnode_operation.cpp */ -extern const char *DEG_OPNAMES[]; +/* Some magic to stringify operation codes. */ +class DepsOperationStringifier { +public: + DepsOperationStringifier(); + const char *operator[](eDepsOperation_Code opcodex); +protected: + const char *names_[DEG_NUM_OPCODES]; +}; +/* String defines for these opcodes, defined in depsgraph_type_defines.cpp */ +extern DepsOperationStringifier DEG_OPNAMES; /* Type of operation */ typedef enum eDepsOperation_Type { - /* Primary operation types */ - DEPSOP_TYPE_INIT = 0, /* initialise evaluation data */ - DEPSOP_TYPE_EXEC = 1, /* standard evaluation step */ - DEPSOP_TYPE_POST = 2, /* cleanup evaluation data + flush results */ - - /* Additional operation types */ - DEPSOP_TYPE_OUT = 3, /* indicator for outputting a temporary result that other components can use */ // XXX? - DEPSOP_TYPE_SIM = 4, /* indicator for things like IK Solvers and Rigidbody Sim steps which modify final results of separate entities at once */ - DEPSOP_TYPE_REBUILD = 5, /* rebuild internal evaluation data - used for Rigidbody Reset and Armature Rebuild-On-Load */ + /* **** Primary operation types **** */ + + /* Initialise evaluation data */ + DEPSOP_TYPE_INIT = 0, + /* Standard evaluation step */ + DEPSOP_TYPE_EXEC = 1, + /* Cleanup evaluation data + flush results */ + DEPSOP_TYPE_POST = 2, + + /* **** Additional operation types **** */ + /* Indicator for outputting a temporary result that other components + * can use. // XXX? + */ + DEPSOP_TYPE_OUT = 3, + /* Indicator for things like IK Solvers and Rigidbody Sim steps which + * modify final results of separate entities at once. + */ + DEPSOP_TYPE_SIM = 4, + /* Rebuild internal evaluation data - used for Rigidbody Reset and + * Armature Rebuild-On-Load. + */ + DEPSOP_TYPE_REBUILD = 5, } eDepsOperation_Type; /* Types of relationships between nodes @@ -170,4 +332,4 @@ typedef enum eDepsRelation_Type { DEPSREL_TYPE_UPDATE_UI, } eDepsRelation_Type; -#endif /* __DEPSGRAPH_TYPES_H__ */ +} // namespace DEG diff --git a/source/blender/depsgraph/intern/depsnode_opcodes.h b/source/blender/depsgraph/intern/depsnode_opcodes.h deleted file mode 100644 index b81822c0ac5..00000000000 --- a/source/blender/depsgraph/intern/depsnode_opcodes.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2014 Blender Foundation. - * All rights reserved. - * - * Original Author: Joshua Leung - * Contributor(s): None Yet - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/depsgraph/intern/depsnode_opcodes.h - * \ingroup depsgraph - * - * \par OpCodes for OperationDepsNodes - * - * This file defines all the "operation codes" (opcodes) used to identify - * common operation node types. The intention of these defines is to have - * a fast and reliable way of identifying the relevant nodes within a component - * without having to use fragile dynamic strings. - * - * This file is meant to be used like UI_icons.h. That is, before including - * the file, the host file must define the DEG_OPCODE(_label) macro, which - * is responsible for converting the define into whatever form is suitable. - * Therefore, it intentionally doesn't have header guards. - */ - - -/* Example macro define: */ -/* #define DEF_DEG_OPCODE(label) DEG_OPCODE_##label, */ - -/* Generic Operations ------------------------------ */ - -/* Placeholder for operations which don't need special mention */ -DEF_DEG_OPCODE(OPERATION) - -// XXX: Placeholder while porting depsgraph code -DEF_DEG_OPCODE(PLACEHOLDER) - -DEF_DEG_OPCODE(NOOP) - -/* Animation, Drivers, etc. ------------------------ */ - -/* NLA + Action */ -DEF_DEG_OPCODE(ANIMATION) - -/* Driver */ -DEF_DEG_OPCODE(DRIVER) - -/* Proxy Inherit? */ -//DEF_DEG_OPCODE(PROXY) - -/* Transform --------------------------------------- */ - -/* Transform entry point - local transforms only */ -DEF_DEG_OPCODE(TRANSFORM_LOCAL) - -/* Parenting */ -DEF_DEG_OPCODE(TRANSFORM_PARENT) - -/* Constraints */ -DEF_DEG_OPCODE(TRANSFORM_CONSTRAINTS) -//DEF_DEG_OPCODE(TRANSFORM_CONSTRAINTS_INIT) -//DEF_DEG_OPCODE(TRANSFORM_CONSTRAINT) -//DEF_DEG_OPCODE(TRANSFORM_CONSTRAINTS_DONE) - -/* Rigidbody Sim - Perform Sim */ -DEF_DEG_OPCODE(RIGIDBODY_REBUILD) -DEF_DEG_OPCODE(RIGIDBODY_SIM) - -/* Rigidbody Sim - Copy Results to Object */ -DEF_DEG_OPCODE(TRANSFORM_RIGIDBODY) - -/* Transform exitpoint */ -DEF_DEG_OPCODE(TRANSFORM_FINAL) - -/* XXX: ubereval is for temporary porting purposes only */ -DEF_DEG_OPCODE(OBJECT_UBEREVAL) - -/* Geometry ---------------------------------------- */ - -/* XXX: Placeholder - UberEval */ -DEF_DEG_OPCODE(GEOMETRY_UBEREVAL) - -/* Modifier */ -DEF_DEG_OPCODE(GEOMETRY_MODIFIER) - -/* Curve Objects - Path Calculation (used for path-following tools) */ -DEF_DEG_OPCODE(GEOMETRY_PATH) - -/* Pose -------------------------------------------- */ - -/* Init IK Trees, etc. */ -DEF_DEG_OPCODE(POSE_INIT) - -/* Free IK Trees + Compute Deform Matrices */ -DEF_DEG_OPCODE(POSE_DONE) - -/* IK/Spline Solvers */ -DEF_DEG_OPCODE(POSE_IK_SOLVER) -DEF_DEG_OPCODE(POSE_SPLINE_IK_SOLVER) - -/* Bone -------------------------------------------- */ - -/* Bone local transforms - Entrypoint */ -DEF_DEG_OPCODE(BONE_LOCAL) - -/* Pose-space conversion (includes parent + restpose) */ -DEF_DEG_OPCODE(BONE_POSE_PARENT) - -/* Constraints */ -DEF_DEG_OPCODE(BONE_CONSTRAINTS) -//DEF_DEG_OPCODE(BONE_CONSTRAINTS_INIT) -//DEF_DEG_OPCODE(BONE_CONSTRAINT) -//DEF_DEG_OPCODE(BONE_CONSTRAINTS_DONE) - -/* Bone transforms are ready - * - "READY" This (internal) noop is used to signal that all pre-IK operations are done. - * Its role is to help mediate situations where cyclic relations may otherwise form - * (i.e. one bone in chain targetting another in same chain) - * - "DONE" This noop is used to signal that the bone's final pose transform can be read by others - */ -// TODO: deform mats could get calculated in the final_transform ops... -DEF_DEG_OPCODE(BONE_READY) -DEF_DEG_OPCODE(BONE_DONE) - -/* Particles --------------------------------------- */ - -/* XXX: placeholder - Particle System eval */ -DEF_DEG_OPCODE(PSYS_EVAL) diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc new file mode 100644 index 00000000000..198cd349002 --- /dev/null +++ b/source/blender/depsgraph/intern/eval/deg_eval.cc @@ -0,0 +1,409 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Original Author: Joshua Leung + * Contributor(s): None Yet + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/depsgraph_eval.cc + * \ingroup depsgraph + * + * Evaluation engine entrypoints for Depsgraph Engine. + */ + +#include "intern/eval/deg_eval.h" + +#include "PIL_time.h" + +extern "C" { +#include "BLI_utildefines.h" +#include "BLI_task.h" +#include "BLI_ghash.h" + +#include "BKE_depsgraph.h" +#include "BKE_global.h" + +#include "DEG_depsgraph.h" +} /* extern "C" */ + +#include "atomic_ops.h" + +#include "intern/eval/deg_eval_debug.h" +#include "intern/eval/deg_eval_flush.h" +#include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_operation.h" +#include "intern/depsgraph.h" +#include "util/deg_util_foreach.h" + +/* Unfinished and unused, and takes quite some pre-processing time. */ +#undef USE_EVAL_PRIORITY + +/* Use integrated debugger to keep track how much each of the nodes was + * evaluating. + */ +#undef USE_DEBUGGER + +namespace DEG { + +/* ********************** */ +/* Evaluation Entrypoints */ + +/* Forward declarations. */ +static void schedule_children(TaskPool *pool, + Depsgraph *graph, + OperationDepsNode *node, + const int layers, + const int thread_id); + +struct DepsgraphEvalState { + EvaluationContext *eval_ctx; + Depsgraph *graph; + int layers; +}; + +static void deg_task_run_func(TaskPool *pool, + void *taskdata, + int thread_id) +{ + DepsgraphEvalState *state = + reinterpret_cast<DepsgraphEvalState *>(BLI_task_pool_userdata(pool)); + OperationDepsNode *node = reinterpret_cast<OperationDepsNode *>(taskdata); + + BLI_assert(!node->is_noop() && "NOOP nodes should not actually be scheduled"); + + /* Should only be the case for NOOPs, which never get to this point. */ + BLI_assert(node->evaluate); + + while (true) { + /* Get context. */ + /* TODO: Who initialises this? "Init" operations aren't able to + * initialise it!!! + */ + /* TODO(sergey): We don't use component contexts at this moment. */ + /* ComponentDepsNode *comp = node->owner; */ + BLI_assert(node->owner != NULL); + + /* Since we're not leaving the thread for until the graph branches it is + * possible to have NO-OP on the way. for which evaluate() will be NULL. + * but that's all fine, we'll just scheduler it's children. + */ + if (node->evaluate) { + /* Take note of current time. */ +#ifdef USE_DEBUGGER + double start_time = PIL_check_seconds_timer(); + DepsgraphDebug::task_started(state->graph, node); +#endif + + /* Perform operation. */ + node->evaluate(state->eval_ctx); + + /* Note how long this took. */ +#ifdef USE_DEBUGGER + double end_time = PIL_check_seconds_timer(); + DepsgraphDebug::task_completed(state->graph, + node, + end_time - start_time); +#endif + } + + /* If there's only one outgoing link we try to immediately switch to + * that node evaluation, without leaving the thread. + * + * It's only doable if the child don't have extra relations or all they + * are satisfied. + * + * TODO(sergey): Checks here can be de-duplicated with the ones from + * schedule_node(), however, how to do it nicely? + */ + if (node->outlinks.size() == 1) { + DepsRelation *rel = node->outlinks[0]; + OperationDepsNode *child = (OperationDepsNode *)rel->to; + BLI_assert(child->type == DEPSNODE_TYPE_OPERATION); + if (!child->scheduled) { + int id_layers = child->owner->owner->layers; + if (!((child->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0 && + (id_layers & state->layers) != 0)) + { + /* Node does not need an update, so can;t continue with the + * chain and need to switch to another one by leaving the + * thread. + */ + break; + } + if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) { + BLI_assert(child->num_links_pending > 0); + atomic_sub_uint32(&child->num_links_pending, 1); + } + if (child->num_links_pending == 0) { + bool is_scheduled = atomic_fetch_and_or_uint8( + (uint8_t *)&child->scheduled, (uint8_t)true); + if (!is_scheduled) { + /* Node was not scheduled, switch to it! */ + node = child; + } + else { + /* Someone else scheduled the node, leaving us + * unemployed in this thread, we're leaving. + */ + break; + } + } + else { + /* There are other dependencies on the child, can't do + * anything in the current thread. + */ + break; + } + } + else { + /* Happens when having cyclic dependencies. + * + * Nothing to do here, single child was already scheduled, we + * can leave the thread now. + */ + break; + } + } + else { + /* TODO(sergey): It's possible to use one of the outgoing relations + * as a chain which we'll try to keep alive, but it's a bit more + * involved change. + */ + schedule_children(pool, state->graph, node, state->layers, thread_id); + break; + } + } +} + +typedef struct CalculatePengindData { + Depsgraph *graph; + int layers; +} CalculatePengindData; + +static void calculate_pending_func(void *data_v, int i) +{ + CalculatePengindData *data = (CalculatePengindData *)data_v; + Depsgraph *graph = data->graph; + int layers = data->layers; + OperationDepsNode *node = graph->operations[i]; + IDDepsNode *id_node = node->owner->owner; + + node->num_links_pending = 0; + node->scheduled = false; + + /* count number of inputs that need updates */ + if ((id_node->layers & layers) != 0 && + (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0) + { + foreach (DepsRelation *rel, node->inlinks) { + if (rel->from->type == DEPSNODE_TYPE_OPERATION && + (rel->flag & DEPSREL_FLAG_CYCLIC) == 0) + { + OperationDepsNode *from = (OperationDepsNode *)rel->from; + IDDepsNode *id_from_node = from->owner->owner; + if ((id_from_node->layers & layers) != 0 && + (from->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0) + { + ++node->num_links_pending; + } + } + } + } +} + +static void calculate_pending_parents(Depsgraph *graph, int layers) +{ + const int num_operations = graph->operations.size(); + const bool do_threads = num_operations > 256; + CalculatePengindData data; + data.graph = graph; + data.layers = layers; + BLI_task_parallel_range(0, + num_operations, + &data, + calculate_pending_func, + do_threads); +} + +#ifdef USE_EVAL_PRIORITY +static void calculate_eval_priority(OperationDepsNode *node) +{ + if (node->done) { + return; + } + node->done = 1; + + if (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) { + /* XXX standard cost of a node, could be estimated somewhat later on */ + const float cost = 1.0f; + /* NOOP nodes have no cost */ + node->eval_priority = node->is_noop() ? cost : 0.0f; + + foreach (DepsRelation *rel, node->outlinks) { + OperationDepsNode *to = (OperationDepsNode *)rel->to; + BLI_assert(to->type == DEPSNODE_TYPE_OPERATION); + calculate_eval_priority(to); + node->eval_priority += to->eval_priority; + } + } + else { + node->eval_priority = 0.0f; + } +} +#endif + +/* Schedule a node if it needs evaluation. + * dec_parents: Decrement pending parents count, true when child nodes are + * scheduled after a task has been completed. + */ +static void schedule_node(TaskPool *pool, Depsgraph *graph, int layers, + OperationDepsNode *node, bool dec_parents, + const int thread_id) +{ + int id_layers = node->owner->owner->layers; + + if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0 && + (id_layers & layers) != 0) + { + if (dec_parents) { + BLI_assert(node->num_links_pending > 0); + atomic_sub_uint32(&node->num_links_pending, 1); + } + + if (node->num_links_pending == 0) { + bool is_scheduled = atomic_fetch_and_or_uint8( + (uint8_t *)&node->scheduled, (uint8_t)true); + if (!is_scheduled) { + if (node->is_noop()) { + /* skip NOOP node, schedule children right away */ + schedule_children(pool, graph, node, layers, thread_id); + } + else { + /* children are scheduled once this task is completed */ + BLI_task_pool_push_from_thread(pool, + deg_task_run_func, + node, + false, + TASK_PRIORITY_LOW, + thread_id); + } + } + } + } +} + +static void schedule_graph(TaskPool *pool, + Depsgraph *graph, + const int layers) +{ + foreach (OperationDepsNode *node, graph->operations) { + schedule_node(pool, graph, layers, node, false, 0); + } +} + +static void schedule_children(TaskPool *pool, + Depsgraph *graph, + OperationDepsNode *node, + const int layers, + const int thread_id) +{ + foreach (DepsRelation *rel, node->outlinks) { + OperationDepsNode *child = (OperationDepsNode *)rel->to; + BLI_assert(child->type == DEPSNODE_TYPE_OPERATION); + if (child->scheduled) { + /* Happens when having cyclic dependencies. */ + continue; + } + schedule_node(pool, + graph, + layers, + child, + (rel->flag & DEPSREL_FLAG_CYCLIC) == 0, + thread_id); + } +} + +/** + * Evaluate all nodes tagged for updating, + * \warning This is usually done as part of main loop, but may also be + * called from frame-change update. + * + * \note Time sources should be all valid! + */ +void deg_evaluate_on_refresh(EvaluationContext *eval_ctx, + Depsgraph *graph, + const int layers) +{ + /* Generate base evaluation context, upon which all the others are derived. */ + // TODO: this needs both main and scene access... + + /* Nothing to update, early out. */ + if (BLI_gset_size(graph->entry_tags) == 0) { + return; + } + + /* Set time for the current graph evaluation context. */ + TimeSourceDepsNode *time_src = graph->find_time_source(); + eval_ctx->ctime = time_src->cfra; + + /* XXX could use a separate pool for each eval context */ + DepsgraphEvalState state; + state.eval_ctx = eval_ctx; + state.graph = graph; + state.layers = layers; + + TaskScheduler *task_scheduler = BLI_task_scheduler_get(); + TaskPool *task_pool = BLI_task_pool_create(task_scheduler, &state); + + if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) { + BLI_pool_set_num_threads(task_pool, 1); + } + + calculate_pending_parents(graph, layers); + + /* Clear tags. */ + foreach (OperationDepsNode *node, graph->operations) { + node->done = 0; + } + + /* Calculate priority for operation nodes. */ +#ifdef USE_EVAL_PRIORITY + foreach (OperationDepsNode *node, graph->operations) { + calculate_eval_priority(node); + } +#endif + + DepsgraphDebug::eval_begin(eval_ctx); + + schedule_graph(task_pool, graph, layers); + + BLI_task_pool_work_and_wait(task_pool); + BLI_task_pool_free(task_pool); + + DepsgraphDebug::eval_end(eval_ctx); + + /* Clear any uncleared tags - just in case. */ + deg_graph_clear_tags(graph); +} + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/eval/deg_eval.h b/source/blender/depsgraph/intern/eval/deg_eval.h new file mode 100644 index 00000000000..0d42f63433f --- /dev/null +++ b/source/blender/depsgraph/intern/eval/deg_eval.h @@ -0,0 +1,52 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Original Author: Joshua Leung + * Contributor(s): None Yet + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/eval/deg_eval.cc + * \ingroup depsgraph + * + * Evaluation engine entrypoints for Depsgraph Engine. + */ + +#pragma once + +struct EvaluationContext; + +namespace DEG { + +struct Depsgraph; + +/** + * Evaluate all nodes tagged for updating, + * \warning This is usually done as part of main loop, but may also be + * called from frame-change update. + * + * \note Time sources should be all valid! + */ +void deg_evaluate_on_refresh(EvaluationContext *eval_ctx, + Depsgraph *graph, + const int layers); + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/eval/deg_eval_debug.cc b/source/blender/depsgraph/intern/eval/deg_eval_debug.cc new file mode 100644 index 00000000000..67d64aae8bf --- /dev/null +++ b/source/blender/depsgraph/intern/eval/deg_eval_debug.cc @@ -0,0 +1,249 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2014 Blender Foundation. + * All rights reserved. + * + * Original Author: Lukas Toenne + * Contributor(s): None Yet + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/eval/deg_eval_debug.cc + * \ingroup depsgraph + * + * Implementation of tools for debugging the depsgraph + */ + +#include <cstring> + +#include "intern/eval/deg_eval_debug.h" + +extern "C" { +#include "BLI_listbase.h" +#include "BLI_ghash.h" + +#include "DEG_depsgraph_debug.h" + +#include "WM_api.h" +#include "WM_types.h" +} /* extern "C" */ + +#include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_operation.h" +#include "intern/depsgraph_intern.h" + +namespace DEG { + +DepsgraphStats *DepsgraphDebug::stats = NULL; + +static string get_component_name(eDepsNode_Type type, const string &name = "") +{ + DepsNodeFactory *factory = deg_get_node_factory(type); + if (name.empty()) { + return string(factory->tname()); + } + else { + return string(factory->tname()) + " | " + name; + } +} + +static void times_clear(DepsgraphStatsTimes ×) +{ + times.duration_last = 0.0f; +} + +static void times_add(DepsgraphStatsTimes ×, float time) +{ + times.duration_last += time; +} + +void DepsgraphDebug::eval_begin(const EvaluationContext *UNUSED(eval_ctx)) +{ + /* TODO(sergey): Stats are currently globally disabled. */ + /* verify_stats(); */ + reset_stats(); +} + +void DepsgraphDebug::eval_end(const EvaluationContext *UNUSED(eval_ctx)) +{ + WM_main_add_notifier(NC_SPACE | ND_SPACE_INFO_REPORT, NULL); +} + +void DepsgraphDebug::eval_step(const EvaluationContext *UNUSED(eval_ctx), + const char *message) +{ +#ifdef DEG_DEBUG_BUILD + if (deg_debug_eval_cb) + deg_debug_eval_cb(deg_debug_eval_userdata, message); +#else + (void)message; /* Ignored. */ +#endif +} + +void DepsgraphDebug::task_started(Depsgraph *graph, + const OperationDepsNode *node) +{ + if (stats) { + BLI_spin_lock(&graph->lock); + + ComponentDepsNode *comp = node->owner; + ID *id = comp->owner->id; + + DepsgraphStatsID *id_stats = get_id_stats(id, true); + times_clear(id_stats->times); + + /* XXX TODO use something like: if (id->flag & ID_DEG_DETAILS) {...} */ + if (0) { + /* XXX component name usage needs cleanup! currently mixes identifier + * and description strings! + */ + DepsgraphStatsComponent *comp_stats = + get_component_stats(id, get_component_name(comp->type, + comp->name), + true); + times_clear(comp_stats->times); + } + + BLI_spin_unlock(&graph->lock); + } +} + +void DepsgraphDebug::task_completed(Depsgraph *graph, + const OperationDepsNode *node, + double time) +{ + if (stats) { + BLI_spin_lock(&graph->lock); + + ComponentDepsNode *comp = node->owner; + ID *id = comp->owner->id; + + DepsgraphStatsID *id_stats = get_id_stats(id, true); + times_add(id_stats->times, time); + + /* XXX TODO use something like: if (id->flag & ID_DEG_DETAILS) {...} */ + if (0) { + /* XXX component name usage needs cleanup! currently mixes identifier + * and description strings! + */ + DepsgraphStatsComponent *comp_stats = + get_component_stats(id, + get_component_name(comp->type, + comp->name), + true); + times_add(comp_stats->times, time); + } + + BLI_spin_unlock(&graph->lock); + } +} + +/* ********** */ +/* Statistics */ + + +/* GHash callback */ +static void deg_id_stats_free(void *val) +{ + DepsgraphStatsID *id_stats = (DepsgraphStatsID *)val; + + if (id_stats) { + BLI_freelistN(&id_stats->components); + MEM_freeN(id_stats); + } +} + +void DepsgraphDebug::stats_init() +{ + if (!stats) { + stats = (DepsgraphStats *)MEM_callocN(sizeof(DepsgraphStats), + "Depsgraph Stats"); + stats->id_stats = BLI_ghash_new(BLI_ghashutil_ptrhash, + BLI_ghashutil_ptrcmp, + "Depsgraph ID Stats Hash"); + } +} + +void DepsgraphDebug::stats_free() +{ + if (stats) { + BLI_ghash_free(stats->id_stats, NULL, deg_id_stats_free); + MEM_freeN(stats); + stats = NULL; + } +} + +void DepsgraphDebug::verify_stats() +{ + stats_init(); +} + +void DepsgraphDebug::reset_stats() +{ + if (!stats) { + return; + } + + /* XXX this doesn't work, will immediately clear all info, + * since most depsgraph updates have none or very few updates to handle. + * + * Could consider clearing only zero-user ID blocks here + */ +// BLI_ghash_clear(stats->id_stats, NULL, deg_id_stats_free); +} + +DepsgraphStatsID *DepsgraphDebug::get_id_stats(ID *id, bool create) +{ + DepsgraphStatsID *id_stats = (DepsgraphStatsID *)BLI_ghash_lookup(stats->id_stats, id); + + if (!id_stats && create) { + id_stats = (DepsgraphStatsID *)MEM_callocN(sizeof(DepsgraphStatsID), + "Depsgraph ID Stats"); + id_stats->id = id; + + BLI_ghash_insert(stats->id_stats, id, id_stats); + } + + return id_stats; +} + +DepsgraphStatsComponent *DepsgraphDebug::get_component_stats( + DepsgraphStatsID *id_stats, + const string &name, + bool create) +{ + DepsgraphStatsComponent *comp_stats; + for (comp_stats = (DepsgraphStatsComponent *)id_stats->components.first; + comp_stats != NULL; + comp_stats = comp_stats->next) + { + if (STREQ(comp_stats->name, name.c_str())) + break; + } + if (!comp_stats && create) { + comp_stats = (DepsgraphStatsComponent *)MEM_callocN(sizeof(DepsgraphStatsComponent), + "Depsgraph Component Stats"); + BLI_strncpy(comp_stats->name, name.c_str(), sizeof(comp_stats->name)); + BLI_addtail(&id_stats->components, comp_stats); + } + return comp_stats; +} + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/depsgraph_debug.h b/source/blender/depsgraph/intern/eval/deg_eval_debug.h index 64b97855f57..9109019eb2d 100644 --- a/source/blender/depsgraph/intern/depsgraph_debug.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_debug.h @@ -24,27 +24,26 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/depsgraph_debug.h +/** \file blender/depsgraph/intern/eval/deg_eval_debug.h * \ingroup depsgraph */ -#ifndef __DEPSGRAPH_DEBUG_H__ -#define __DEPSGRAPH_DEBUG_H__ +#pragma once -#include "depsgraph_types.h" +#include "intern/depsgraph_types.h" -extern "C" { -#include "BKE_global.h" -} +struct ID; +struct EvaluationContext; struct DepsgraphStats; struct DepsgraphStatsID; struct DepsgraphStatsComponent; -struct DepsgraphSettings; -struct EvaluationContext; -struct OperationDepsNode; + +namespace DEG { struct Depsgraph; +struct DepsgraphSettings; +struct OperationDepsNode; struct DepsgraphDebug { static DepsgraphStats *stats; @@ -77,11 +76,4 @@ struct DepsgraphDebug { } }; -#define DEG_DEBUG_PRINTF(...) \ - { \ - if (G.debug & G_DEBUG_DEPSGRAPH) { \ - fprintf(stderr, __VA_ARGS__); \ - } \ - } \ - -#endif /* __DEPSGRAPH_DEBUG_H__ */ +} // namespace DEG diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc new file mode 100644 index 00000000000..af68f5c55c4 --- /dev/null +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -0,0 +1,224 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Original Author: Joshua Leung + * Contributor(s): None Yet + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/depsgraph_tag.cc + * \ingroup depsgraph + * + * Core routines for how the Depsgraph works. + */ + +#include "intern/eval/deg_eval_flush.h" + +// TODO(sergey): Use some sort of wrapper. +#include <queue> + +extern "C" { +#include "DNA_object_types.h" + +#include "BLI_utildefines.h" +#include "BLI_task.h" +#include "BLI_ghash.h" + +#include "DEG_depsgraph.h" +} /* extern "C" */ + +#include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_operation.h" + +#include "intern/depsgraph_intern.h" +#include "util/deg_util_foreach.h" + +namespace DEG { + +namespace { + +// TODO(sergey): De-duplicate with depsgraph_tag,cc +void lib_id_recalc_tag(Main *bmain, ID *id) +{ + id->tag |= LIB_TAG_ID_RECALC; + DEG_id_type_tag(bmain, GS(id->name)); +} + +void lib_id_recalc_data_tag(Main *bmain, ID *id) +{ + id->tag |= LIB_TAG_ID_RECALC_DATA; + DEG_id_type_tag(bmain, GS(id->name)); +} + +} /* namespace */ + +typedef std::queue<OperationDepsNode *> FlushQueue; + +static void flush_init_func(void *data_v, int i) +{ + /* ID node's done flag is used to avoid multiple editors update + * for the same ID. + */ + Depsgraph *graph = (Depsgraph *)data_v; + OperationDepsNode *node = graph->operations[i]; + IDDepsNode *id_node = node->owner->owner; + id_node->done = 0; + node->scheduled = false; + node->owner->flags &= ~DEPSCOMP_FULLY_SCHEDULED; +} + +/* Flush updates from tagged nodes outwards until all affected nodes + * are tagged. + */ +void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) +{ + /* Sanity check. */ + if (graph == NULL) { + return; + } + + /* Nothing to update, early out. */ + if (BLI_gset_size(graph->entry_tags) == 0) { + return; + } + + /* TODO(sergey): With a bit of flag magic we can get rid of this + * extra loop. + */ + const int num_operations = graph->operations.size(); + const bool do_threads = num_operations > 256; + BLI_task_parallel_range(0, + num_operations, + graph, + flush_init_func, + do_threads); + + FlushQueue queue; + /* Starting from the tagged "entry" nodes, flush outwards... */ + /* NOTE: Also need to ensure that for each of these, there is a path back to + * root, or else they won't be done. + * NOTE: Count how many nodes we need to handle - entry nodes may be + * component nodes which don't count for this purpose! + */ + GSET_FOREACH_BEGIN(OperationDepsNode *, node, graph->entry_tags) + { + queue.push(node); + node->scheduled = true; + } + GSET_FOREACH_END(); + + while (!queue.empty()) { + OperationDepsNode *node = queue.front(); + queue.pop(); + + for (;;) { + node->flag |= DEPSOP_FLAG_NEEDS_UPDATE; + + IDDepsNode *id_node = node->owner->owner; + + if (id_node->done == 0) { + deg_editors_id_update(bmain, id_node->id); + id_node->done = 1; + } + + lib_id_recalc_tag(bmain, id_node->id); + /* TODO(sergey): For until we've got proper data nodes in the graph. */ + lib_id_recalc_data_tag(bmain, id_node->id); + + ID *id = id_node->id; + /* This code is used to preserve those areas which does direct + * object update, + * + * Plus it ensures visibility changes and relations and layers + * visibility update has proper flags to work with. + */ + if (GS(id->name) == ID_OB) { + Object *object = (Object *)id; + ComponentDepsNode *comp_node = node->owner; + if (comp_node->type == DEPSNODE_TYPE_ANIMATION) { + object->recalc |= OB_RECALC_TIME; + } + else if (comp_node->type == DEPSNODE_TYPE_TRANSFORM) { + object->recalc |= OB_RECALC_OB; + } + else { + object->recalc |= OB_RECALC_DATA; + } + } + + /* TODO(sergey): For until incremental updates are possible + * witin a component at least we tag the whole component + * for update. + */ + ComponentDepsNode *component = node->owner; + if ((component->flags & DEPSCOMP_FULLY_SCHEDULED) == 0) { + foreach (OperationDepsNode *op, component->operations) { + op->flag |= DEPSOP_FLAG_NEEDS_UPDATE; + } + component->flags |= DEPSCOMP_FULLY_SCHEDULED; + } + + /* Flush to nodes along links... */ + if (node->outlinks.size() == 1) { + OperationDepsNode *to_node = (OperationDepsNode *)node->outlinks[0]->to; + if (to_node->scheduled == false) { + to_node->scheduled = true; + node = to_node; + } + else { + break; + } + } + else { + foreach (DepsRelation *rel, node->outlinks) { + OperationDepsNode *to_node = (OperationDepsNode *)rel->to; + if (to_node->scheduled == false) { + queue.push(to_node); + to_node->scheduled = true; + } + } + break; + } + } + } +} + +static void graph_clear_func(void *data_v, int i) +{ + Depsgraph *graph = (Depsgraph *)data_v; + OperationDepsNode *node = graph->operations[i]; + /* Clear node's "pending update" settings. */ + node->flag &= ~(DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE); +} + +/* Clear tags from all operation nodes. */ +void deg_graph_clear_tags(Depsgraph *graph) +{ + /* Go over all operation nodes, clearing tags. */ + const int num_operations = graph->operations.size(); + const bool do_threads = num_operations > 256; + BLI_task_parallel_range(0, num_operations, graph, graph_clear_func, do_threads); + /* Clear any entry tags which haven't been flushed. */ + BLI_gset_clear(graph->entry_tags, NULL); +} + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.h b/source/blender/depsgraph/intern/eval/deg_eval_flush.h new file mode 100644 index 00000000000..8912aebee7d --- /dev/null +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.h @@ -0,0 +1,49 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Original Author: Joshua Leung + * Contributor(s): None Yet + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/eval/deg_eval_flush.cc + * \ingroup depsgraph + * + * Core routines for how the Depsgraph works. + */ + +#pragma once + +struct Main; + +namespace DEG { + +struct Depsgraph; + +/* Flush updates from tagged nodes outwards until all affected nodes + * are tagged. + */ +void deg_graph_flush_updates(struct Main *bmain, struct Depsgraph *graph); + +/* Clear tags from all operation nodes. */ +void deg_graph_clear_tags(struct Depsgraph *graph); + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/depsnode.cc b/source/blender/depsgraph/intern/nodes/deg_node.cc index 8aa1059d2dc..78293f7f483 100644 --- a/source/blender/depsgraph/intern/depsnode.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node.cc @@ -28,10 +28,13 @@ * \ingroup depsgraph */ +#include "intern/nodes/deg_node.h" + #include <stdio.h> #include <string.h> #include "BLI_utildefines.h" +#include "BLI_ghash.h" extern "C" { #include "DNA_ID.h" @@ -42,10 +45,13 @@ extern "C" { #include "DEG_depsgraph.h" } -#include "depsnode.h" /* own include */ -#include "depsnode_component.h" -#include "depsnode_operation.h" -#include "depsgraph_intern.h" +#include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_operation.h" +#include "intern/depsgraph_intern.h" +#include "util/deg_util_foreach.h" +#include "util/deg_util_hash.h" + +namespace DEG { /* *************** */ /* Node Management */ @@ -66,7 +72,7 @@ DepsNode::TypeInfo::TypeInfo(eDepsNode_Type type, const char *tname) DepsNode::DepsNode() { - this->name[0] = '\0'; + name[0] = '\0'; } DepsNode::~DepsNode() @@ -76,11 +82,9 @@ DepsNode::~DepsNode() * when we're trying to free same link from both it's sides. We don't have * dangling links so this is not a problem from memory leaks point of view. */ - DEPSNODE_RELATIONS_ITER_BEGIN(this->inlinks, rel) - { + foreach (DepsRelation *rel, inlinks) { OBJECT_GUARDED_DELETE(rel, DepsRelation); } - DEPSNODE_RELATIONS_ITER_END; } @@ -100,11 +104,7 @@ string DepsNode::identifier() const void TimeSourceDepsNode::tag_update(Depsgraph *graph) { - for (DepsNode::Relations::const_iterator it = outlinks.begin(); - it != outlinks.end(); - ++it) - { - DepsRelation *rel = *it; + foreach (DepsRelation *rel, outlinks) { DepsNode *node = rel->to; node->tag_update(graph); } @@ -125,7 +125,7 @@ RootDepsNode::~RootDepsNode() TimeSourceDepsNode *RootDepsNode::add_time_source(const string &name) { if (!time_source) { - DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_TIMESOURCE); + DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_TIMESOURCE); time_source = (TimeSourceDepsNode *)factory->create_node(NULL, "", name); /*time_source->owner = this;*/ // XXX } @@ -142,6 +142,36 @@ static DepsNodeFactoryImpl<TimeSourceDepsNode> DNTI_TIMESOURCE; /* ID Node ================================================ */ +static unsigned int id_deps_node_hash_key(const void *key_v) +{ + const IDDepsNode::ComponentIDKey *key = + reinterpret_cast<const IDDepsNode::ComponentIDKey *>(key_v); + return hash_combine(BLI_ghashutil_uinthash(key->type), + BLI_ghashutil_strhash_p(key->name.c_str())); +} + +static bool id_deps_node_hash_key_cmp(const void *a, const void *b) +{ + const IDDepsNode::ComponentIDKey *key_a = + reinterpret_cast<const IDDepsNode::ComponentIDKey *>(a); + const IDDepsNode::ComponentIDKey *key_b = + reinterpret_cast<const IDDepsNode::ComponentIDKey *>(b); + return !(*key_a == *key_b); +} + +static void id_deps_node_hash_key_free(void *key_v) +{ + typedef IDDepsNode::ComponentIDKey ComponentIDKey; + ComponentIDKey *key = reinterpret_cast<ComponentIDKey *>(key_v); + OBJECT_GUARDED_DELETE(key, ComponentIDKey); +} + +static void id_deps_node_hash_value_free(void *value_v) +{ + ComponentDepsNode *comp_node = reinterpret_cast<ComponentDepsNode *>(value_v); + OBJECT_GUARDED_DELETE(comp_node, ComponentDepsNode); +} + /* Initialize 'id' node - from pointer data given. */ void IDDepsNode::init(const ID *id, const string &UNUSED(subdata)) { @@ -151,6 +181,10 @@ void IDDepsNode::init(const ID *id, const string &UNUSED(subdata)) this->layers = (1 << 20) - 1; this->eval_flags = 0; + components = BLI_ghash_new(id_deps_node_hash_key, + id_deps_node_hash_key_cmp, + "Depsgraph id components hash"); + /* NOTE: components themselves are created if/when needed. * This prevents problems with components getting added * twice if an ID-Ref needs to be created to house it... @@ -161,51 +195,27 @@ void IDDepsNode::init(const ID *id, const string &UNUSED(subdata)) IDDepsNode::~IDDepsNode() { clear_components(); -} - -/* Copy 'id' node. */ -void IDDepsNode::copy(DepsgraphCopyContext *dcc, const IDDepsNode *src) -{ - (void)src; /* Ignored. */ - /* Iterate over items in original hash, adding them to new hash. */ - for (IDDepsNode::ComponentMap::const_iterator it = this->components.begin(); - it != this->components.end(); - ++it) - { - /* Get current <type : component> mapping. */ - ComponentIDKey c_key = it->first; - DepsNode *old_component = it->second; - - /* Make a copy of component. */ - ComponentDepsNode *component = (ComponentDepsNode *)DEG_copy_node(dcc, old_component); - - /* Add new node to hash... */ - this->components[c_key] = component; - } - - // TODO: perform a second loop to fix up links? - BLI_assert(!"Not expected to be used"); + BLI_ghash_free(components, id_deps_node_hash_key_free, NULL); } ComponentDepsNode *IDDepsNode::find_component(eDepsNode_Type type, const string &name) const { ComponentIDKey key(type, name); - ComponentMap::const_iterator it = components.find(key); - return it != components.end() ? it->second : NULL; + return reinterpret_cast<ComponentDepsNode *>(BLI_ghash_lookup(components, &key)); } ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type, const string &name) { - ComponentIDKey key(type, name); ComponentDepsNode *comp_node = find_component(type, name); if (!comp_node) { - DepsNodeFactory *factory = DEG_get_node_factory(type); + DepsNodeFactory *factory = deg_get_node_factory(type); comp_node = (ComponentDepsNode *)factory->create_node(this->id, "", name); /* Register. */ - this->components[key] = comp_node; + ComponentIDKey *key = OBJECT_GUARDED_NEW(ComponentIDKey, type, name); + BLI_ghash_insert(components, key, comp_node); comp_node->owner = this; } return comp_node; @@ -213,34 +223,28 @@ ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type, void IDDepsNode::remove_component(eDepsNode_Type type, const string &name) { - ComponentIDKey key(type, name); ComponentDepsNode *comp_node = find_component(type, name); if (comp_node) { /* Unregister. */ - this->components.erase(key); - OBJECT_GUARDED_DELETE(comp_node, ComponentDepsNode); + ComponentIDKey key(type, name); + BLI_ghash_remove(components, + &key, + id_deps_node_hash_key_free, + id_deps_node_hash_value_free); } } void IDDepsNode::clear_components() { - for (ComponentMap::const_iterator it = components.begin(); - it != components.end(); - ++it) - { - ComponentDepsNode *comp_node = it->second; - OBJECT_GUARDED_DELETE(comp_node, ComponentDepsNode); - } - components.clear(); + BLI_ghash_clear(components, + id_deps_node_hash_key_free, + id_deps_node_hash_value_free); } void IDDepsNode::tag_update(Depsgraph *graph) { - for (ComponentMap::const_iterator it = components.begin(); - it != components.end(); - ++it) + GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, components) { - ComponentDepsNode *comp_node = it->second; /* TODO(sergey): What about drievrs? */ bool do_component_tag = comp_node->type != DEPSNODE_TYPE_ANIMATION; if (comp_node->type == DEPSNODE_TYPE_ANIMATION) { @@ -254,6 +258,16 @@ void IDDepsNode::tag_update(Depsgraph *graph) comp_node->tag_update(graph); } } + GHASH_FOREACH_END(); +} + +void IDDepsNode::finalize_build() +{ + GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, components) + { + comp_node->finalize_build(); + } + GHASH_FOREACH_END(); } DEG_DEPSNODE_DEFINE(IDDepsNode, DEPSNODE_TYPE_ID_REF, "ID Node"); @@ -281,31 +295,21 @@ SubgraphDepsNode::~SubgraphDepsNode() // XXX: prune these flags a bit... if ((this->flag & SUBGRAPH_FLAG_FIRSTREF) || !(this->flag & SUBGRAPH_FLAG_SHARED)) { /* Free the referenced graph. */ - DEG_graph_free(this->graph); - this->graph = NULL; + DEG_graph_free(reinterpret_cast< ::Depsgraph* >(graph)); + graph = NULL; } } -/* Copy 'subgraph' node - Assume that the subgraph doesn't get copied for now... */ -void SubgraphDepsNode::copy(DepsgraphCopyContext * /*dcc*/, - const SubgraphDepsNode * /*src*/) -{ - //const SubgraphDepsNode *src_node = (const SubgraphDepsNode *)src; - //SubgraphDepsNode *dst_node = (SubgraphDepsNode *)dst; - - /* for now, subgraph itself isn't copied... */ - BLI_assert(!"Not expected to be used"); -} - DEG_DEPSNODE_DEFINE(SubgraphDepsNode, DEPSNODE_TYPE_SUBGRAPH, "Subgraph Node"); static DepsNodeFactoryImpl<SubgraphDepsNode> DNTI_SUBGRAPH; - -void DEG_register_base_depsnodes() +void deg_register_base_depsnodes() { - DEG_register_node_typeinfo(&DNTI_ROOT); - DEG_register_node_typeinfo(&DNTI_TIMESOURCE); + deg_register_node_typeinfo(&DNTI_ROOT); + deg_register_node_typeinfo(&DNTI_TIMESOURCE); - DEG_register_node_typeinfo(&DNTI_ID_REF); - DEG_register_node_typeinfo(&DNTI_SUBGRAPH); + deg_register_node_typeinfo(&DNTI_ID_REF); + deg_register_node_typeinfo(&DNTI_SUBGRAPH); } + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/depsnode.h b/source/blender/depsgraph/intern/nodes/deg_node.h index 4a464955384..d79d3d2348d 100644 --- a/source/blender/depsgraph/intern/depsnode.h +++ b/source/blender/depsgraph/intern/nodes/deg_node.h @@ -28,21 +28,18 @@ * \ingroup depsgraph */ -#ifndef __DEPSNODE_H__ -#define __DEPSNODE_H__ +#pragma once -#include "depsgraph_types.h" - -#include "depsgraph_util_hash.h" -#include "depsgraph_util_map.h" -#include "depsgraph_util_set.h" +#include "intern/depsgraph_types.h" struct ID; +struct GHash; struct Scene; +namespace DEG { + struct Depsgraph; struct DepsRelation; -struct DepsgraphCopyContext; struct OperationDepsNode; /* *********************************** */ @@ -94,8 +91,6 @@ struct DepsNode { virtual void init(const ID * /*id*/, const string &/*subdata*/) {} - virtual void copy(DepsgraphCopyContext * /*dcc*/, - const DepsNode * /*src*/) {} virtual void tag_update(Depsgraph * /*graph*/) {} @@ -160,24 +155,7 @@ struct IDDepsNode : public DepsNode { string name; }; - /* XXX can't specialize std::hash for this purpose, because ComponentIDKey is - * a nested type ... - * - * http://stackoverflow.com/a/951245 - */ - struct component_key_hash { - bool operator() (const ComponentIDKey &key) const - { - return hash_combine(hash<int>()(key.type), hash<string>()(key.name)); - } - }; - - typedef unordered_map<ComponentIDKey, - ComponentDepsNode *, - component_key_hash> ComponentMap; - void init(const ID *id, const string &subdata); - void copy(DepsgraphCopyContext *dcc, const IDDepsNode *src); ~IDDepsNode(); ComponentDepsNode *find_component(eDepsNode_Type type, @@ -189,11 +167,13 @@ struct IDDepsNode : public DepsNode { void tag_update(Depsgraph *graph); + void finalize_build(); + /* ID Block referenced. */ ID *id; /* Hash to make it faster to look up components. */ - ComponentMap components; + GHash *components; /* Layers of this node with accumulated layers of it's output relations. */ int layers; @@ -210,7 +190,6 @@ struct IDDepsNode : public DepsNode { /* Subgraph Reference. */ struct SubgraphDepsNode : public DepsNode { void init(const ID *id, const string &subdata); - void copy(DepsgraphCopyContext *dcc, const SubgraphDepsNode *src); ~SubgraphDepsNode(); /* Instanced graph. */ @@ -243,6 +222,6 @@ typedef enum eSubgraphRef_Flag { SUBGRAPH_FLAG_FIRSTREF = (1 << 1), } eSubgraphRef_Flag; -void DEG_register_base_depsnodes(); +void deg_register_base_depsnodes(); -#endif /* __DEPSNODE_H__ */ +} // namespace DEG diff --git a/source/blender/depsgraph/intern/depsnode_component.cc b/source/blender/depsgraph/intern/nodes/deg_node_component.cc index a47a0d29228..7e49fec051f 100644 --- a/source/blender/depsgraph/intern/depsnode_component.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node_component.cc @@ -28,6 +28,8 @@ * \ingroup depsgraph */ +#include "intern/nodes/deg_node_component.h" + #include <stdio.h> #include <string.h> @@ -39,20 +41,57 @@ extern "C" { #include "BKE_action.h" } /* extern "C" */ -#include "depsnode_component.h" /* own include */ -#include "depsnode_operation.h" -#include "depsgraph_intern.h" +#include "intern/nodes/deg_node_operation.h" +#include "intern/depsgraph_intern.h" +#include "util/deg_util_foreach.h" +#include "util/deg_util_hash.h" + +namespace DEG { /* *********** */ /* Outer Nodes */ /* Standard Component Methods ============================= */ +static unsigned int comp_node_hash_key(const void *key_v) +{ + const ComponentDepsNode::OperationIDKey *key = + reinterpret_cast<const ComponentDepsNode::OperationIDKey *>(key_v); + return hash_combine(BLI_ghashutil_uinthash(key->opcode), + BLI_ghashutil_strhash_p(key->name.c_str())); +} + +static bool comp_node_hash_key_cmp(const void *a, const void *b) +{ + const ComponentDepsNode::OperationIDKey *key_a = + reinterpret_cast<const ComponentDepsNode::OperationIDKey *>(a); + const ComponentDepsNode::OperationIDKey *key_b = + reinterpret_cast<const ComponentDepsNode::OperationIDKey *>(b); + return !(*key_a == *key_b); +} + +static void comp_node_hash_key_free(void *key_v) +{ + typedef ComponentDepsNode::OperationIDKey OperationIDKey; + OperationIDKey *key = reinterpret_cast<OperationIDKey *>(key_v); + OBJECT_GUARDED_DELETE(key, OperationIDKey); +} + +static void comp_node_hash_value_free(void *value_v) +{ + OperationDepsNode *op_node = reinterpret_cast<OperationDepsNode *>(value_v); + OBJECT_GUARDED_DELETE(op_node, OperationDepsNode); +} + ComponentDepsNode::ComponentDepsNode() : entry_operation(NULL), exit_operation(NULL), - flags(0) + flags(0), + layers(0) { + operations_map = BLI_ghash_new(comp_node_hash_key, + comp_node_hash_key_cmp, + "Depsgraph id hash"); } /* Initialize 'component' node - from pointer data given */ @@ -63,37 +102,15 @@ void ComponentDepsNode::init(const ID * /*id*/, // XXX: maybe this needs a special API? } -/* Copy 'component' node */ -void ComponentDepsNode::copy(DepsgraphCopyContext * /*dcc*/, - const ComponentDepsNode * /*src*/) -{ -#if 0 // XXX: remove all this - /* duplicate list of operation nodes */ - this->operations.clear(); - - for (OperationMap::const_iterator it = src->operations.begin(); it != src->operations.end(); ++it) { - const string &pchan_name = it->first; - OperationDepsNode *src_op = it->second; - - /* recursive copy */ - DepsNodeFactory *factory = DEG_node_get_factory(src_op); - OperationDepsNode *dst_op = (OperationDepsNode *)factory->copy_node(dcc, src_op); - this->operations[pchan_name] = dst_op; - - /* fix links... */ - // ... - } - - /* copy evaluation contexts */ - // -#endif - BLI_assert(!"Not expected to be called"); -} - /* Free 'component' node */ ComponentDepsNode::~ComponentDepsNode() { clear_operations(); + if (operations_map != NULL) { + BLI_ghash_free(operations_map, + comp_node_hash_key_free, + comp_node_hash_value_free); + } } string ComponentDepsNode::identifier() const @@ -103,15 +120,17 @@ string ComponentDepsNode::identifier() const char typebuf[7]; sprintf(typebuf, "(%d)", type); - return string(typebuf) + name + " : " + idname; + char layers[7]; + sprintf(layers, "%d", this->layers); + + return string(typebuf) + name + " : " + idname + " (Layers: " + layers + ")"; } OperationDepsNode *ComponentDepsNode::find_operation(OperationIDKey key) const { - OperationMap::const_iterator it = this->operations.find(key); - - if (it != this->operations.end()) { - return it->second; + OperationDepsNode *node = reinterpret_cast<OperationDepsNode *>(BLI_ghash_lookup(operations_map, &key)); + if (node != NULL) { + return node; } else { fprintf(stderr, "%s: find_operation(%s) failed\n", @@ -129,11 +148,7 @@ OperationDepsNode *ComponentDepsNode::find_operation(eDepsOperation_Code opcode, OperationDepsNode *ComponentDepsNode::has_operation(OperationIDKey key) const { - OperationMap::const_iterator it = this->operations.find(key); - if (it != this->operations.end()) { - return it->second; - } - return NULL; + return reinterpret_cast<OperationDepsNode *>(BLI_ghash_lookup(operations_map, &key)); } OperationDepsNode *ComponentDepsNode::has_operation(eDepsOperation_Code opcode, @@ -147,12 +162,12 @@ OperationDepsNode *ComponentDepsNode::add_operation(eDepsOperation_Type optype, { OperationDepsNode *op_node = has_operation(opcode, name); if (!op_node) { - DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_OPERATION); + DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_OPERATION); op_node = (OperationDepsNode *)factory->create_node(this->owner->id, "", name); /* register opnode in this component's operation set */ - OperationIDKey key(opcode, name); - this->operations[key] = op_node; + OperationIDKey *key = OBJECT_GUARDED_NEW(OperationIDKey, opcode, name); + BLI_ghash_insert(operations_map, key, op_node); /* set as entry/exit node of component (if appropriate) */ if (optype == DEPSOP_TYPE_INIT) { @@ -185,18 +200,22 @@ OperationDepsNode *ComponentDepsNode::add_operation(eDepsOperation_Type optype, void ComponentDepsNode::remove_operation(eDepsOperation_Code opcode, const string &name) { - OperationDepsNode *op_node = find_operation(opcode, name); - if (op_node) { - /* unregister */ - this->operations.erase(OperationIDKey(opcode, name)); - OBJECT_GUARDED_DELETE(op_node, OperationDepsNode); - } + /* unregister */ + OperationIDKey key(opcode, name); + BLI_ghash_remove(operations_map, + &key, + comp_node_hash_key_free, + comp_node_hash_key_free); } void ComponentDepsNode::clear_operations() { - for (OperationMap::const_iterator it = operations.begin(); it != operations.end(); ++it) { - OperationDepsNode *op_node = it->second; + if (operations_map != NULL) { + BLI_ghash_clear(operations_map, + comp_node_hash_key_free, + comp_node_hash_value_free); + } + foreach (OperationDepsNode *op_node, operations) { OBJECT_GUARDED_DELETE(op_node, OperationDepsNode); } operations.clear(); @@ -208,30 +227,79 @@ void ComponentDepsNode::tag_update(Depsgraph *graph) if (entry_op != NULL && entry_op->flag & DEPSOP_FLAG_NEEDS_UPDATE) { return; } - for (OperationMap::const_iterator it = operations.begin(); it != operations.end(); ++it) { - OperationDepsNode *op_node = it->second; + foreach (OperationDepsNode *op_node, operations) { op_node->tag_update(graph); } + // It is possible that tag happens before finalization. + if (operations_map != NULL) { + GHASH_FOREACH_BEGIN(OperationDepsNode *, op_node, operations_map) + { + op_node->tag_update(graph); + } + GHASH_FOREACH_END(); + } } OperationDepsNode *ComponentDepsNode::get_entry_operation() { - if (entry_operation) + if (entry_operation) { return entry_operation; - else if (operations.size() == 1) - return operations.begin()->second; + } + else if (operations_map != NULL && BLI_ghash_size(operations_map) == 1) { + OperationDepsNode *op_node = NULL; + /* TODO(sergey): This is somewhat slow. */ + GHASH_FOREACH_BEGIN(OperationDepsNode *, tmp, operations_map) + { + op_node = tmp; + } + GHASH_FOREACH_END(); + /* Cache for the subsequent usage. */ + entry_operation = op_node; + return op_node; + } + else if(operations.size() == 1) { + return operations[0]; + } return NULL; } OperationDepsNode *ComponentDepsNode::get_exit_operation() { - if (exit_operation) + if (exit_operation) { return exit_operation; - else if (operations.size() == 1) - return operations.begin()->second; + } + else if (operations_map != NULL && BLI_ghash_size(operations_map) == 1) { + OperationDepsNode *op_node = NULL; + /* TODO(sergey): This is somewhat slow. */ + GHASH_FOREACH_BEGIN(OperationDepsNode *, tmp, operations_map) + { + op_node = tmp; + } + GHASH_FOREACH_END(); + /* Cache for the subsequent usage. */ + exit_operation = op_node; + return op_node; + } + else if(operations.size() == 1) { + return operations[0]; + } return NULL; } +void ComponentDepsNode::finalize_build() +{ + operations.reserve(BLI_ghash_size(operations_map)); + GHASH_FOREACH_BEGIN(OperationDepsNode *, op_node, operations_map) + { + operations.push_back(op_node); + } + GHASH_FOREACH_END(); + BLI_ghash_free(operations_map, + comp_node_hash_key_free, + NULL); + operations_map = NULL; +} + /* Parameter Component Defines ============================ */ DEG_DEPSNODE_DEFINE(ParametersComponentDepsNode, DEPSNODE_TYPE_PARAMETERS, "Parameters Component"); @@ -302,18 +370,20 @@ static DepsNodeFactoryImpl<ShadingComponentDepsNode> DNTI_SHADING; /* Node Types Register =================================== */ -void DEG_register_component_depsnodes() +void deg_register_component_depsnodes() { - DEG_register_node_typeinfo(&DNTI_PARAMETERS); - DEG_register_node_typeinfo(&DNTI_PROXY); - DEG_register_node_typeinfo(&DNTI_ANIMATION); - DEG_register_node_typeinfo(&DNTI_TRANSFORM); - DEG_register_node_typeinfo(&DNTI_GEOMETRY); - DEG_register_node_typeinfo(&DNTI_SEQUENCER); - - DEG_register_node_typeinfo(&DNTI_EVAL_POSE); - DEG_register_node_typeinfo(&DNTI_BONE); - - DEG_register_node_typeinfo(&DNTI_EVAL_PARTICLES); - DEG_register_node_typeinfo(&DNTI_SHADING); + deg_register_node_typeinfo(&DNTI_PARAMETERS); + deg_register_node_typeinfo(&DNTI_PROXY); + deg_register_node_typeinfo(&DNTI_ANIMATION); + deg_register_node_typeinfo(&DNTI_TRANSFORM); + deg_register_node_typeinfo(&DNTI_GEOMETRY); + deg_register_node_typeinfo(&DNTI_SEQUENCER); + + deg_register_node_typeinfo(&DNTI_EVAL_POSE); + deg_register_node_typeinfo(&DNTI_BONE); + + deg_register_node_typeinfo(&DNTI_EVAL_PARTICLES); + deg_register_node_typeinfo(&DNTI_SHADING); } + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/depsnode_component.h b/source/blender/depsgraph/intern/nodes/deg_node_component.h index 7f44c0ed03f..df321ea9299 100644 --- a/source/blender/depsgraph/intern/depsnode_component.h +++ b/source/blender/depsgraph/intern/nodes/deg_node_component.h @@ -28,21 +28,22 @@ * \ingroup depsgraph */ -#ifndef __DEPSNODE_COMPONENT_H__ -#define __DEPSNODE_COMPONENT_H__ +#pragma once -#include "depsnode.h" +#include "intern/nodes/deg_node.h" -#include "depsgraph_util_hash.h" -#include "depsgraph_util_map.h" -#include "depsgraph_util_set.h" +#include "BLI_utildefines.h" +#include "BLI_string.h" struct ID; struct bPoseChannel; +struct GHash; -struct Depsgraph; -struct DepsgraphCopyContext; struct EvaluationContext; + +namespace DEG { + +struct Depsgraph; struct OperationDepsNode; struct BoneComponentDepsNode; @@ -75,7 +76,7 @@ struct ComponentDepsNode : public DepsNode { string identifier() const { char codebuf[5]; - sprintf(codebuf, "%d", opcode); + BLI_snprintf(codebuf, sizeof(codebuf), "%d", opcode); return string("OperationIDKey(") + codebuf + ", " + name + ")"; } @@ -86,47 +87,41 @@ struct ComponentDepsNode : public DepsNode { } }; - /* XXX can't specialize std::hash for this purpose, because ComponentKey is a nested type ... - * http://stackoverflow.com/a/951245 - */ - struct operation_key_hash { - bool operator() (const OperationIDKey &key) const - { - return hash_combine(hash<int>()(key.opcode), hash<string>()(key.name)); - } - }; - /* Typedef for container of operations */ - typedef unordered_map<OperationIDKey, OperationDepsNode *, operation_key_hash> OperationMap; - - ComponentDepsNode(); ~ComponentDepsNode(); void init(const ID *id, const string &subdata); - void copy(DepsgraphCopyContext *dcc, const ComponentDepsNode *src); string identifier() const; /* Find an existing operation, will throw an assert() if it does not exist. */ OperationDepsNode *find_operation(OperationIDKey key) const; - OperationDepsNode *find_operation(eDepsOperation_Code opcode, const string &name) const; + OperationDepsNode *find_operation(eDepsOperation_Code opcode, + const string &name) const; /* Check operation exists and return it. */ OperationDepsNode *has_operation(OperationIDKey key) const; - OperationDepsNode *has_operation(eDepsOperation_Code opcode, const string &name) const; + OperationDepsNode *has_operation(eDepsOperation_Code opcode, + const string &name) const; /** * Create a new node for representing an operation and add this to graph - * \warning If an existing node is found, it will be modified. This helps when node may - * have been partially created earlier (e.g. parent ref before parent item is added) + * \warning If an existing node is found, it will be modified. This helps + * when node may have been partially created earlier (e.g. parent ref before + * parent item is added) * - * \param type: Operation node type (corresponding to context/component that it operates in) - * \param optype: Role that operation plays within component (i.e. where in eval process) + * \param type: Operation node type (corresponding to context/component that + * it operates in) + * \param optype: Role that operation plays within component + * (i.e. where in eval process) * \param op: The operation to perform * \param name: Identifier for operation - used to find/locate it again */ - OperationDepsNode *add_operation(eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &name); + OperationDepsNode *add_operation(eDepsOperation_Type optype, + DepsEvalOperationCb op, + eDepsOperation_Code opcode, + const string &name); void remove_operation(eDepsOperation_Code opcode, const string &name); void clear_operations(); @@ -135,9 +130,13 @@ struct ComponentDepsNode : public DepsNode { /* Evaluation Context Management .................. */ - /* Initialize component's evaluation context used for the specified purpose */ + /* Initialize component's evaluation context used for the specified + * purpose. + */ virtual bool eval_context_init(EvaluationContext * /*eval_ctx*/) { return false; } - /* Free data in component's evaluation context which is used for the specified purpose + /* Free data in component's evaluation context which is used for + * the specified purpose + * * NOTE: this does not free the actual context in question */ virtual void eval_context_free(EvaluationContext * /*eval_ctx*/) {} @@ -145,15 +144,31 @@ struct ComponentDepsNode : public DepsNode { OperationDepsNode *get_entry_operation(); OperationDepsNode *get_exit_operation(); + void finalize_build(); + IDDepsNode *owner; - OperationMap operations; /* inner nodes for this component */ + /* ** Inner nodes for this component ** */ + + /* Operations stored as a hash map, for faster build. + * This hash map will be freed when graph is fully built. + */ + GHash *operations_map; + + /* This is a "normal" list of operations, used by evaluation + * and other routines after construction. + */ + vector<OperationDepsNode *> operations; + OperationDepsNode *entry_operation; OperationDepsNode *exit_operation; // XXX: a poll() callback to check if component's first node can be started? int flags; + + /* Temporary bitmask, used during graph construction. */ + int layers; }; /* ---------------------------------------- */ @@ -204,6 +219,6 @@ struct ShadingComponentDepsNode : public ComponentDepsNode { }; -void DEG_register_component_depsnodes(); +void deg_register_component_depsnodes(); -#endif /* __DEPSNODE_COMPONENT_H__ */ +} // namespace DEG diff --git a/source/blender/depsgraph/intern/depsnode_operation.cc b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc index 6aeb163356b..a9f9703bb3b 100644 --- a/source/blender/depsgraph/intern/depsnode_operation.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc @@ -28,35 +28,27 @@ * \ingroup depsgraph */ +#include "intern/nodes/deg_node_operation.h" + #include "MEM_guardedalloc.h" extern "C" { #include "BLI_utildefines.h" } /* extern "C" */ -#include "depsnode_operation.h" /* own include */ -#include "depsnode_component.h" -#include "depsgraph.h" -#include "depsgraph_intern.h" - -/* ******************************************************************* */ -/* OpNode Identifiers Array - Exported to other depsgraph files too... */ +#include "intern/depsgraph.h" +#include "intern/depsgraph_intern.h" +#include "util/deg_util_hash.h" -/* identifiers for operations */ -const char *DEG_OPNAMES[] = { -#define DEF_DEG_OPCODE(label) #label, -#include "depsnode_opcodes.h" -#undef DEF_DEG_OPCODE - - "<Invalid>" -}; +namespace DEG { /* *********** */ /* Inner Nodes */ OperationDepsNode::OperationDepsNode() : eval_priority(0.0f), - flag(0) + flag(0), + customdata_mask(0) { } @@ -66,7 +58,6 @@ OperationDepsNode::~OperationDepsNode() string OperationDepsNode::identifier() const { - BLI_assert((opcode > 0) && (opcode < ARRAY_SIZE(DEG_OPNAMES))); return string(DEG_OPNAMES[opcode]) + "(" + name + ")"; } @@ -98,7 +89,9 @@ void OperationDepsNode::tag_update(Depsgraph *graph) DEG_DEPSNODE_DEFINE(OperationDepsNode, DEPSNODE_TYPE_OPERATION, "Operation"); static DepsNodeFactoryImpl<OperationDepsNode> DNTI_OPERATION; -void DEG_register_operation_depsnodes() +void deg_register_operation_depsnodes() { - DEG_register_node_typeinfo(&DNTI_OPERATION); + deg_register_node_typeinfo(&DNTI_OPERATION); } + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/depsnode_operation.h b/source/blender/depsgraph/intern/nodes/deg_node_operation.h index 1119e10805d..f03078fc3db 100644 --- a/source/blender/depsgraph/intern/depsnode_operation.h +++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.h @@ -28,15 +28,15 @@ * \ingroup depsgraph */ -#ifndef __DEPSNODE_OPERATION_H__ -#define __DEPSNODE_OPERATION_H__ +#pragma once -#include "depsnode.h" +#include "intern/nodes/deg_node.h" struct ID; struct Depsgraph; -struct DepsgraphCopyContext; + +namespace DEG { /* Flags for Depsgraph Nodes */ typedef enum eDepsOperation_Flag { @@ -44,10 +44,14 @@ typedef enum eDepsOperation_Flag { DEPSOP_FLAG_NEEDS_UPDATE = (1 << 0), /* node was directly modified, causing need for update */ - /* XXX: intention is to make it easier to tell when we just need to take subgraphs */ + /* XXX: intention is to make it easier to tell when we just need to + * take subgraphs. + */ DEPSOP_FLAG_DIRECTLY_MODIFIED = (1 << 1), - /* Operation is evaluated using CPython; has GIL and security implications... */ + /* Operation is evaluated using CPython; has GIL and security + * implications... + */ DEPSOP_FLAG_USES_PYTHON = (1 << 2), } eDepsOperation_Flag; @@ -68,23 +72,33 @@ struct OperationDepsNode : public DepsNode { OperationDepsNode *get_entry_operation() { return this; } OperationDepsNode *get_exit_operation() { return this; } - ComponentDepsNode *owner; /* component that contains the operation */ + /* Component that contains the operation. */ + ComponentDepsNode *owner; - DepsEvalOperationCb evaluate; /* callback for operation */ + /* Callback for operation. */ + DepsEvalOperationCb evaluate; - uint32_t num_links_pending; /* how many inlinks are we still waiting on before we can be evaluated... */ + /* How many inlinks are we still waiting on before we can be evaluated. */ + uint32_t num_links_pending; float eval_priority; bool scheduled; - short optype; /* (eDepsOperation_Type) stage of evaluation */ - int opcode; /* (eDepsOperation_Code) identifier for the operation being performed */ + /* Stage of evaluation */ + eDepsOperation_Type optype; + + /* Identifier for the operation being performed. */ + eDepsOperation_Code opcode; + + /* (eDepsOperation_Flag) extra settings affecting evaluation. */ + int flag; - int flag; /* (eDepsOperation_Flag) extra settings affecting evaluation */ + /* Extra customdata mask which needs to be evaluated for the object. */ + uint64_t customdata_mask; DEG_DEPSNODE_DECLARE; }; -void DEG_register_operation_depsnodes(); +void deg_register_operation_depsnodes(); -#endif /* __DEPSNODE_OPERATION_H__ */ +} // namespace DEG diff --git a/source/blender/depsgraph/util/deg_util_foreach.h b/source/blender/depsgraph/util/deg_util_foreach.h new file mode 100644 index 00000000000..14cf4fc11ed --- /dev/null +++ b/source/blender/depsgraph/util/deg_util_foreach.h @@ -0,0 +1,68 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 Blender Foundation. + * All rights reserved. + * + * Original Author: Sergey Sharybin + * Contributor(s): + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/util/deg_util_foreach.h + * \ingroup depsgraph + */ + +#pragma once + +#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800) +# define foreach(x, y) for(x : y) +#elif defined(HAVE_BOOST_FUNCTION_BINDINGS) +# include <boost/foreach.hpp> +# define foreach BOOST_FOREACH +#else +#pragma message("No available foreach() implementation. Using stub instead, disabling new depsgraph") + +#ifndef WITH_LEGACY_DEPSGRAPH +# error "Unable to build new depsgraph and legacy one is disabled." +#endif + +#define DISABLE_NEW_DEPSGRAPH + +# define foreach(x, y) for (x; false; (void)y) +#endif + +#define GHASH_FOREACH_BEGIN(type, var, what) \ + do { \ + GHashIterator gh_iter##var; \ + GHASH_ITER(gh_iter##var, what) { \ + type var = reinterpret_cast<type>(BLI_ghashIterator_getValue(&gh_iter##var)); \ + +#define GHASH_FOREACH_END() \ + } \ + } while(0) + +#define GSET_FOREACH_BEGIN(type, var, what) \ + do { \ + GSetIterator gh_iter##var; \ + GSET_ITER(gh_iter##var, what) { \ + type var = reinterpret_cast<type>(BLI_gsetIterator_getKey(&gh_iter##var)); \ + +#define GSET_FOREACH_END() \ + } \ + } while(0) diff --git a/source/blender/depsgraph/util/depsgraph_util_function.h b/source/blender/depsgraph/util/deg_util_function.h index a4301833408..1e34ae04d9a 100644 --- a/source/blender/depsgraph/util/depsgraph_util_function.h +++ b/source/blender/depsgraph/util/deg_util_function.h @@ -24,12 +24,11 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/util/depsgraph_util_function.h +/** \file blender/depsgraph/util/deg_util_function.h * \ingroup depsgraph */ -#ifndef __DEPSGRAPH_UTIL_FUNCTION_H__ -#define __DEPSGRAPH_UTIL_FUNCTION_H__ +#pragma once #if (__cplusplus > 199711L) @@ -57,6 +56,7 @@ using boost::function; #define DISABLE_NEW_DEPSGRAPH +#include "BLI_utildefines.h" #include <cstdlib> template<typename T> @@ -108,5 +108,3 @@ void *function_bind(T func, #define _4 Wrap() #endif - -#endif /* __DEPSGRAPH_UTIL_FUNCTION_H__ */ diff --git a/source/blender/depsgraph/util/depsgraph_util_set.h b/source/blender/depsgraph/util/deg_util_hash.h index 008ec6b74ca..e490be1a7a1 100644 --- a/source/blender/depsgraph/util/depsgraph_util_set.h +++ b/source/blender/depsgraph/util/deg_util_hash.h @@ -24,43 +24,18 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/util/depsgraph_util_set.h +/** \file blender/depsgraph/util/deg_util_hash.h * \ingroup depsgraph */ -#ifndef __DEPSGRAPH_UTIL_SET_H__ -#define __DEPSGRAPH_UTIL_SET_H__ +#pragma once -#include <set> +#include "BLI_utildefines.h" -#include "depsgraph_util_hash.h" +#include "BLI_ghash.h" -using std::set; - -#if defined(DEG_NO_UNORDERED_MAP) -# include <set> -typedef std::set unordered_set; -#endif - -#if defined(DEG_TR1_UNORDERED_MAP) -# include <tr1/unordered_set> -using std::tr1::unordered_set; -#endif - -#if defined(DEG_STD_UNORDERED_MAP) -# include <unordered_set> -using std::unordered_set; -#endif - -#if defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) -# include <unordered_set> -using std::tr1::unordered_set; -#endif - -#if !defined(DEG_NO_UNORDERED_MAP) && !defined(DEG_TR1_UNORDERED_MAP) && \ - !defined(DEG_STD_UNORDERED_MAP) && !defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT -# error One of: DEG_NO_UNORDERED_MAP, DEG_TR1_UNORDERED_MAP,\ - DEG_STD_UNORDERED_MAP, DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT -#endif - -#endif /* __DEPSGRAPH_UTIL_SET_H__ */ +/* XXX this might require 2 different variants for sizeof(size_t) (32 vs 64 bit) */ +BLI_INLINE size_t hash_combine(size_t hash_a, size_t hash_b) +{ + return hash_a ^ (hash_b + 0x9e3779b9 + (hash_a << 6) + (hash_a >> 2)); +} diff --git a/source/blender/depsgraph/util/depsgraph_util_hash.h b/source/blender/depsgraph/util/depsgraph_util_hash.h deleted file mode 100644 index bc75627a026..00000000000 --- a/source/blender/depsgraph/util/depsgraph_util_hash.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2014 Blender Foundation. - * All rights reserved. - * - * Original Author: Brecht van Lommel - * Contributor(s): Lukas Toenne - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/depsgraph/util/depsgraph_util_hash.h - * \ingroup depsgraph - */ - -#ifndef __DEPSGRAPH_UTIL_HASH_H__ -#define __DEPSGRAPH_UTIL_HASH_H__ - -#if defined(DEG_NO_UNORDERED_MAP) -# define DEG_HASH_NAMESPACE_BEGIN -# define DEG_HASH_NAMESPACE_END -#endif - -#if defined(DEG_TR1_UNORDERED_MAP) -# include <tr1/unordered_map> -# define DEG_HASH_NAMESPACE_BEGIN namespace std { namespace tr1 { -# define DEG_HASH_NAMESPACE_END } } -using std::tr1::hash; -#endif - -#if defined(DEG_STD_UNORDERED_MAP) -# include <unordered_map> -# define DEG_HASH_NAMESPACE_BEGIN namespace std { -# define DEG_HASH_NAMESPACE_END } -using std::hash; -#endif - -#if defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) -# include <unordered_map> -# define DEG_HASH_NAMESPACE_BEGIN namespace std { namespace tr1 { -# define DEG_HASH_NAMESPACE_END } } -using std::tr1::hash; -#endif - -#if !defined(DEG_NO_UNORDERED_MAP) && !defined(DEG_TR1_UNORDERED_MAP) && \ - !defined(DEG_STD_UNORDERED_MAP) && !defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT -# error One of: DEG_NO_UNORDERED_MAP, DEG_TR1_UNORDERED_MAP,\ - DEG_STD_UNORDERED_MAP, DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT -#endif - -/* XXX this might require 2 different variants for sizeof(size_t) (32 vs 64 bit) */ -inline size_t hash_combine(size_t hash_a, size_t hash_b) -{ - return hash_a ^ (hash_b + 0x9e3779b9 + (hash_a << 6) + (hash_a >> 2)); -} - -#endif /* __DEPSGRAPH_UTIL_HASH_H__ */ diff --git a/source/blender/depsgraph/util/depsgraph_util_map.h b/source/blender/depsgraph/util/depsgraph_util_map.h deleted file mode 100644 index 0eae1d79e34..00000000000 --- a/source/blender/depsgraph/util/depsgraph_util_map.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2014 Blender Foundation. - * All rights reserved. - * - * Original Author: Brecht van Lommel - * Contributor(s): Lukas Toenne - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/depsgraph/util/depsgraph_util_map.h - * \ingroup depsgraph - */ - -#ifndef __DEPSGRAPH_UTIL_MAP_H__ -#define __DEPSGRAPH_UTIL_MAP_H__ - -#include <map> - -#include "depsgraph_util_hash.h" - -using std::map; -using std::pair; - -#if defined(DEG_NO_UNORDERED_MAP) -# include <map> -typedef std::map unordered_map; -#endif - -#if defined(DEG_TR1_UNORDERED_MAP) -# include <tr1/unordered_map> -using std::tr1::unordered_map; -#endif - -#if defined(DEG_STD_UNORDERED_MAP) -# include <unordered_map> -using std::unordered_map; -#endif - -#if defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) -# include <unordered_map> -using std::tr1::unordered_map; -#endif - -#if !defined(DEG_NO_UNORDERED_MAP) && !defined(DEG_TR1_UNORDERED_MAP) && \ - !defined(DEG_STD_UNORDERED_MAP) && !defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT -# error One of: DEG_NO_UNORDERED_MAP, DEG_TR1_UNORDERED_MAP,\ - DEG_STD_UNORDERED_MAP, DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT -#endif - -#endif /* __DEPSGRAPH_UTIL_MAP_H__ */ diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c index 5665ce59783..437dd2b2de2 100644 --- a/source/blender/editors/animation/anim_deps.c +++ b/source/blender/editors/animation/anim_deps.c @@ -399,7 +399,13 @@ void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data) ANIM_list_elem_update(ac->scene, ale); } } - + else if (ale->datatype == ALE_NLASTRIP) { + if (ale->update & ANIM_UPDATE_DEPS) { + ale->update &= ~ANIM_UPDATE_DEPS; + ANIM_list_elem_update(ac->scene, ale); + } + } + BLI_assert(ale->update == 0); } } diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index afc4e5c9e61..51f962d4a1e 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -866,7 +866,7 @@ static int add_driver_button_exec(bContext *C, wmOperator *op) } /* Show menu or create drivers */ -static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { PropertyRNA *prop; @@ -877,7 +877,8 @@ static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent * else { /* Show menu */ // TODO: This should get filtered by the enum filter - return WM_menu_invoke(C, op, event); + /* important to execute in the region we're currently in */ + return WM_menu_invoke_ex(C, op, WM_OP_INVOKE_DEFAULT); } } diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 6a19cf679be..172f2b9069e 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -2024,17 +2024,25 @@ bool autokeyframe_cfra_can_key(Scene *scene, ID *id) /* only filter if auto-key mode requires this */ if (IS_AUTOKEY_ON(scene) == 0) return false; - - if (IS_AUTOKEY_MODE(scene, NORMAL)) { - /* can insert anytime we like... */ - return true; - } - else { /* REPLACE */ - /* for whole block - only key if there's a keyframe on that frame already - * this is a valid assumption when we're blocking + tweaking + + if (IS_AUTOKEY_MODE(scene, EDITKEYS)) { + /* Replace Mode: + * For whole block, only key if there's a keyframe on that frame already + * This is a valid assumption when we're blocking + tweaking */ return id_frame_has_keyframe(id, cfra, ANIMFILTER_KEYS_LOCAL); } + else { + /* Normal Mode (or treat as being normal mode): + * + * Just in case the flags are't set properly (i.e. only on/off is set, without a mode) + * let's set the "normal" flag too, so that it will all be sane everywhere... + */ + scene->toolsettings->autokey_mode = AUTOKEY_MODE_NORMAL; + + /* Can insert anytime we like... */ + return true; + } } /* ******************************************* */ diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c index d73536e5ba7..6306926e0b2 100644 --- a/source/blender/editors/armature/armature_utils.c +++ b/source/blender/editors/armature/armature_utils.c @@ -367,6 +367,8 @@ void transform_armature_mirror_update(Object *obedit) eboflip->tail[2] = ebo->tail[2]; eboflip->rad_tail = ebo->rad_tail; eboflip->roll = -ebo->roll; + eboflip->curveOutX = -ebo->curveOutX; + eboflip->roll2 = -ebo->roll2; /* Also move connected children, in case children's name aren't mirrored properly */ for (children = arm->edbo->first; children; children = children->next) { @@ -382,6 +384,8 @@ void transform_armature_mirror_update(Object *obedit) eboflip->head[2] = ebo->head[2]; eboflip->rad_head = ebo->rad_head; eboflip->roll = -ebo->roll; + eboflip->curveInX = -ebo->curveInX; + eboflip->roll1 = -ebo->roll1; /* Also move connected parent, in case parent's name isn't mirrored properly */ if (eboflip->parent && eboflip->flag & BONE_CONNECTED) { @@ -395,6 +399,11 @@ void transform_armature_mirror_update(Object *obedit) eboflip->roll = -ebo->roll; eboflip->xwidth = ebo->xwidth; eboflip->zwidth = ebo->zwidth; + + eboflip->curveInX = -ebo->curveInX; + eboflip->curveOutX = -ebo->curveOutX; + eboflip->roll1 = -ebo->roll1; + eboflip->roll2 = -ebo->roll2; } } } diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 9e49d7e7e90..d4d3e1af1fd 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -2327,6 +2327,12 @@ static void ui_block_colorpicker(uiBlock *block, float rgba[4], PointerRNA *ptr, RNA_property_float_range(ptr, prop, &hardmin, &hardmax); RNA_property_float_get_array(ptr, prop, rgba); + /* when the softmax isn't defined in the RNA, + * using very large numbers causes sRGB/linear round trip to fail. */ + if (softmax == FLT_MAX) { + softmax = 1.0f; + } + switch (U.color_picker_type) { case USER_CP_SQUARE_SV: ui_colorpicker_square(block, ptr, prop, UI_GRAD_SV, cpicker); @@ -2418,7 +2424,7 @@ static void ui_block_colorpicker(uiBlock *block, float rgba[4], PointerRNA *ptr, BLI_snprintf(hexcol, sizeof(hexcol), "%02X%02X%02X", UNPACK3_EX((unsigned int), rgb_gamma_uchar, )); yco = -3.0f * UI_UNIT_Y; - bt = uiDefBut(block, UI_BTYPE_TEXT, 0, IFACE_("Hex: "), 0, yco, butwidth, UI_UNIT_Y, hexcol, 0, 8, 0, 0, TIP_("Hex triplet for color (#RRGGBB)")); + bt = uiDefBut(block, UI_BTYPE_TEXT, 0, IFACE_("Hex: "), 0, yco, butwidth, UI_UNIT_Y, hexcol, 0, 7, 0, 0, TIP_("Hex triplet for color (#RRGGBB)")); UI_but_func_set(bt, ui_colorpicker_hex_rna_cb, bt, hexcol); bt->custom_data = cpicker; uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("(Gamma Corrected)"), 0, yco - UI_UNIT_Y, butwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index d4c976fb544..acb8e8e7512 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -94,6 +94,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op) int triangulate; int use_object_instantiation; + int use_blender_profile; int sort_by_name; int export_transformation_type; int open_sim; @@ -142,6 +143,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op) triangulate = RNA_boolean_get(op->ptr, "triangulate"); use_object_instantiation = RNA_boolean_get(op->ptr, "use_object_instantiation"); + use_blender_profile = RNA_boolean_get(op->ptr, "use_blender_profile"); sort_by_name = RNA_boolean_get(op->ptr, "sort_by_name"); export_transformation_type = RNA_enum_get(op->ptr, "export_transformation_type_selection"); open_sim = RNA_boolean_get(op->ptr, "open_sim"); @@ -167,6 +169,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op) triangulate, use_object_instantiation, + use_blender_profile, sort_by_name, export_transformation_type, open_sim); @@ -256,6 +259,8 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr) uiItemR(row, imfptr, "triangulate", 0, NULL, ICON_NONE); row = uiLayoutRow(box, false); uiItemR(row, imfptr, "use_object_instantiation", 0, NULL, ICON_NONE); + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "use_blender_profile", 0, NULL, ICON_NONE); row = uiLayoutRow(box, false); split = uiLayoutSplit(row, 0.6f, UI_LAYOUT_ALIGN_RIGHT); @@ -349,7 +354,10 @@ void WM_OT_collada_export(wmOperatorType *ot) "Export Polygons (Quads & NGons) as Triangles"); RNA_def_boolean(ot->srna, "use_object_instantiation", 1, "Use Object Instances", - "Instantiate multiple Objects from same Data"); + "Instantiate multiple Objects from same Data"); + + RNA_def_boolean(ot->srna, "use_blender_profile", 1, "Use Blender Profile", + "Export additional Blender specific information (for material, shaders, bones, etc.)"); RNA_def_boolean(ot->srna, "sort_by_name", 0, "Sort by Object name", "Sort exported data by Object name"); diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt index 0280f662a26..8783367ef7e 100644 --- a/source/blender/editors/mesh/CMakeLists.txt +++ b/source/blender/editors/mesh/CMakeLists.txt @@ -55,6 +55,7 @@ set(SRC editmesh_rip_edge.c editmesh_select.c editmesh_tools.c + editmesh_undo.c editmesh_utils.c mesh_data.c mesh_ops.c diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c new file mode 100644 index 00000000000..b9d3fd6c8be --- /dev/null +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -0,0 +1,726 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/mesh/editmesh_undo.c + * \ingroup edmesh + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_object_types.h" +#include "DNA_key_types.h" + +#include "BLI_listbase.h" + +#include "BKE_DerivedMesh.h" +#include "BKE_context.h" +#include "BKE_key.h" +#include "BKE_mesh.h" +#include "BKE_editmesh.h" + +#include "ED_mesh.h" +#include "ED_util.h" + +#define USE_ARRAY_STORE + +#ifdef USE_ARRAY_STORE +// # define DEBUG_PRINT +// # define DEBUG_TIME +# ifdef DEBUG_TIME +# include "PIL_time_utildefines.h" +# endif + +# include "BLI_array_store.h" +# include "BLI_math_base.h" + /* check on best size later... */ +# define ARRAY_CHUNK_SIZE 256 + +# define USE_ARRAY_STORE_THREAD +#endif + +#ifdef USE_ARRAY_STORE_THREAD +# include "BLI_task.h" +#endif + + +#ifdef USE_ARRAY_STORE + +/* Single linked list of layers stored per type */ +typedef struct BArrayCustomData { + struct BArrayCustomData *next; + CustomDataType type; + int states_len; /* number of layers for each type */ + BArrayState *states[0]; +} BArrayCustomData; + +#endif + +typedef struct UndoMesh { + Mesh me; + int selectmode; + + /** \note + * this isn't a prefect solution, if you edit keys and change shapes this works well (fixing [#32442]), + * but editing shape keys, going into object mode, removing or changing their order, + * then go back into editmode and undo will give issues - where the old index will be out of sync + * with the new object index. + * + * There are a few ways this could be made to work but for now its a known limitation with mixing + * object and editmode operations - Campbell */ + int shapenr; + +#ifdef USE_ARRAY_STORE + /* NULL arrays are considered empty */ + struct { + /* most data is stored as 'custom' data */ + BArrayCustomData *vdata, *edata, *ldata, *pdata; + BArrayState **keyblocks; + BArrayState *mselect; + } store; +#endif /* USE_ARRAY_STORE */ +} UndoMesh; + + +#ifdef USE_ARRAY_STORE + +/** \name Array Store + * \{ */ + +static struct { + BArrayStore **bs_all; + int bs_all_len; + int users; + + /* We could have the undo API pass in the previous state, for now store a local list */ + ListBase local_links; + +#ifdef USE_ARRAY_STORE_THREAD + TaskPool *task_pool; +#endif + +} um_arraystore = {NULL}; + +static BArrayStore *array_store_at_size_ensure(const int stride) +{ + if (um_arraystore.bs_all_len < stride) { + um_arraystore.bs_all_len = stride; + um_arraystore.bs_all = MEM_recallocN(um_arraystore.bs_all, sizeof(*um_arraystore.bs_all) * stride); + } + BArrayStore **bs_p = &um_arraystore.bs_all[stride - 1]; + + if ((*bs_p) == NULL) { +#if 0 + unsigned int chunk_count = ARRAY_CHUNK_SIZE; +#else + /* calculate best chunk-count to fit a power of two */ + unsigned int chunk_count = ARRAY_CHUNK_SIZE; + { + unsigned int size = chunk_count * stride; + size = power_of_2_max_u(size); + size = MEM_SIZE_OPTIMAL(size); + chunk_count = size / stride; + } +#endif + + (*bs_p) = BLI_array_store_create(stride, chunk_count); + } + return *bs_p; +} + +static BArrayStore *array_store_at_size_get(const int stride) +{ + BLI_assert(stride > 0 && stride <= um_arraystore.bs_all_len); + return um_arraystore.bs_all[stride - 1]; +} + +#ifdef DEBUG_PRINT +static void um_arraystore_memory_usage(size_t *r_size_expanded, size_t *r_size_compacted) +{ + size_t size_compacted = 0; + size_t size_expanded = 0; + for (int i = 0; i < um_arraystore.bs_all_len; i++) { + BArrayStore *bs = um_arraystore.bs_all[i]; + if (bs) { + size_compacted += BLI_array_store_calc_size_compacted_get(bs); + size_expanded += BLI_array_store_calc_size_expanded_get(bs); + } + } + + *r_size_expanded = size_expanded; + *r_size_compacted = size_compacted; +} +#endif + +static void um_arraystore_cd_compact( + struct CustomData *cdata, const size_t data_len, + bool create, + const BArrayCustomData *bcd_reference, + BArrayCustomData **r_bcd_first) +{ + if (data_len == 0) { + if (create) { + *r_bcd_first = NULL; + } + } + + const BArrayCustomData *bcd_reference_current = bcd_reference; + BArrayCustomData *bcd = NULL, *bcd_first = NULL, *bcd_prev = NULL; + for (int layer_start = 0, layer_end; layer_start < cdata->totlayer; layer_start = layer_end) { + const CustomDataType type = cdata->layers[layer_start].type; + + layer_end = layer_start + 1; + while ((layer_end < cdata->totlayer) && + (type == cdata->layers[layer_end].type)) + { + layer_end++; + } + + const int stride = CustomData_sizeof(type); + BArrayStore *bs = create ? array_store_at_size_ensure(stride) : NULL; + const int layer_len = layer_end - layer_start; + + if (create) { + if (bcd_reference_current && (bcd_reference_current->type == type)) { + /* common case, the reference is aligned */ + } + else { + bcd_reference_current = NULL; + + /* do a full lookup when un-alligned */ + if (bcd_reference) { + const BArrayCustomData *bcd_iter = bcd_reference; + while (bcd_iter) { + if (bcd_iter->type == type) { + bcd_reference_current = bcd_iter; + break; + } + bcd_iter = bcd_iter->next; + } + } + } + } + + if (create) { + bcd = MEM_callocN(sizeof(BArrayCustomData) + (layer_len * sizeof(BArrayState *)), __func__); + bcd->next = NULL; + bcd->type = type; + bcd->states_len = layer_end - layer_start; + + if (bcd_prev) { + bcd_prev->next = bcd; + bcd_prev = bcd; + } + else { + bcd_first = bcd; + bcd_prev = bcd; + } + } + + CustomDataLayer *layer = &cdata->layers[layer_start]; + for (int i = 0; i < layer_len; i++, layer++) { + if (create) { + if (layer->data) { + BArrayState *state_reference = + (bcd_reference_current && i < bcd_reference_current->states_len) ? + bcd_reference_current->states[i] : NULL; + bcd->states[i] = BLI_array_store_state_add( + bs, layer->data, (size_t)data_len * stride, state_reference); + } + else { + bcd->states[i] = NULL; + } + } + + if (layer->data) { + MEM_freeN(layer->data); + layer->data = NULL; + } + } + + if (create) { + if (bcd_reference_current) { + bcd_reference_current = bcd_reference_current->next; + } + } + } + + if (create) { + *r_bcd_first = bcd_first; + } +} + +/** + * \note There is no room for data going out of sync here. + * The layers and the states are stored together so this can be kept working. + */ +static void um_arraystore_cd_expand( + const BArrayCustomData *bcd, struct CustomData *cdata, const size_t data_len) +{ + CustomDataLayer *layer = cdata->layers; + while (bcd) { + const int stride = CustomData_sizeof(bcd->type); + for (int i = 0; i < bcd->states_len; i++) { + BLI_assert(bcd->type == layer->type); + if (bcd->states[i]) { + size_t state_len; + layer->data = BLI_array_store_state_data_get_alloc(bcd->states[i], &state_len); + BLI_assert(stride * data_len == state_len); + UNUSED_VARS_NDEBUG(stride, data_len); + } + else { + layer->data = NULL; + } + layer++; + } + bcd = bcd->next; + } +} + +static void um_arraystore_cd_free(BArrayCustomData *bcd) +{ + while (bcd) { + BArrayCustomData *bcd_next = bcd->next; + const int stride = CustomData_sizeof(bcd->type); + BArrayStore *bs = array_store_at_size_get(stride); + for (int i = 0; i < bcd->states_len; i++) { + if (bcd->states[i]) { + BLI_array_store_state_remove(bs, bcd->states[i]); + } + } + MEM_freeN(bcd); + bcd = bcd_next; + } +} + +/** + * \param create: When false, only free the arrays. + * This is done since when reading from an undo state, they must be temporarily expanded. + * then discarded afterwards, having this argument avoids having 2x code paths. + */ +static void um_arraystore_compact_ex( + UndoMesh *um, const UndoMesh *um_ref, + bool create) +{ + Mesh *me = &um->me; + + um_arraystore_cd_compact(&me->vdata, me->totvert, create, um_ref ? um_ref->store.vdata : NULL, &um->store.vdata); + um_arraystore_cd_compact(&me->edata, me->totedge, create, um_ref ? um_ref->store.edata : NULL, &um->store.edata); + um_arraystore_cd_compact(&me->ldata, me->totloop, create, um_ref ? um_ref->store.ldata : NULL, &um->store.ldata); + um_arraystore_cd_compact(&me->pdata, me->totpoly, create, um_ref ? um_ref->store.pdata : NULL, &um->store.pdata); + + if (me->key && me->key->totkey) { + const size_t stride = me->key->elemsize; + BArrayStore *bs = create ? array_store_at_size_ensure(stride) : NULL; + if (create) { + um->store.keyblocks = MEM_mallocN(me->key->totkey * sizeof(*um->store.keyblocks), __func__); + } + KeyBlock *keyblock = me->key->block.first; + for (int i = 0; i < me->key->totkey; i++, keyblock = keyblock->next) { + if (create) { + BArrayState *state_reference = + (um_ref && um_ref->me.key && (i < um_ref->me.key->totkey)) ? + um_ref->store.keyblocks[i] : NULL; + um->store.keyblocks[i] = BLI_array_store_state_add( + bs, keyblock->data, (size_t)keyblock->totelem * stride, + state_reference); + } + + if (keyblock->data) { + MEM_freeN(keyblock->data); + keyblock->data = NULL; + } + } + } + + if (me->mselect && me->totselect) { + BLI_assert(create == (um->store.mselect == NULL)); + if (create) { + BArrayState *state_reference = um_ref ? um_ref->store.mselect : NULL; + const size_t stride = sizeof(*me->mselect); + BArrayStore *bs = array_store_at_size_ensure(stride); + um->store.mselect = BLI_array_store_state_add( + bs, me->mselect, (size_t)me->totselect * stride, state_reference); + } + + /* keep me->totselect for validation */ + MEM_freeN(me->mselect); + me->mselect = NULL; + } + + if (create) { + um_arraystore.users += 1; + } + + BKE_mesh_update_customdata_pointers(me, false); +} + +/** + * Move data from allocated arrays to de-duplicated states and clear arrays. + */ +static void um_arraystore_compact(UndoMesh *um, const UndoMesh *um_ref) +{ + um_arraystore_compact_ex(um, um_ref, true); +} + +static void um_arraystore_compact_with_info(UndoMesh *um, const UndoMesh *um_ref) +{ +#ifdef DEBUG_PRINT + size_t size_expanded_prev, size_compacted_prev; + um_arraystore_memory_usage(&size_expanded_prev, &size_compacted_prev); +#endif + +#ifdef DEBUG_TIME + TIMEIT_START(mesh_undo_compact); +#endif + + um_arraystore_compact(um, um_ref); + +#ifdef DEBUG_TIME + TIMEIT_END(mesh_undo_compact); +#endif + +#ifdef DEBUG_PRINT + { + size_t size_expanded, size_compacted; + um_arraystore_memory_usage(&size_expanded, &size_compacted); + + const double percent_total = size_expanded ? + (((double)size_compacted / (double)size_expanded) * 100.0) : -1.0; + + size_t size_expanded_step = size_expanded - size_expanded_prev; + size_t size_compacted_step = size_compacted - size_compacted_prev; + const double percent_step = size_expanded_step ? + (((double)size_compacted_step / (double)size_expanded_step) * 100.0) : -1.0; + + printf("overall memory use: %.8f%% of expanded size\n", percent_total); + printf("step memory use: %.8f%% of expanded size\n", percent_step); + } +#endif +} + +#ifdef USE_ARRAY_STORE_THREAD + +struct UMArrayData { + UndoMesh *um; + const UndoMesh *um_ref; /* can be NULL */ +}; +static void um_arraystore_compact_cb(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid)) +{ + struct UMArrayData *um_data = taskdata; + um_arraystore_compact_with_info(um_data->um, um_data->um_ref); +} + +#endif /* USE_ARRAY_STORE_THREAD */ + +/** + * Remove data we only expanded for temporary use. + */ +static void um_arraystore_expand_clear(UndoMesh *um) +{ + um_arraystore_compact_ex(um, NULL, false); +} + +static void um_arraystore_expand(UndoMesh *um) +{ + Mesh *me = &um->me; + + um_arraystore_cd_expand(um->store.vdata, &me->vdata, me->totvert); + um_arraystore_cd_expand(um->store.edata, &me->edata, me->totedge); + um_arraystore_cd_expand(um->store.ldata, &me->ldata, me->totloop); + um_arraystore_cd_expand(um->store.pdata, &me->pdata, me->totpoly); + + if (um->store.keyblocks) { + const size_t stride = me->key->elemsize; + KeyBlock *keyblock = me->key->block.first; + for (int i = 0; i < me->key->totkey; i++, keyblock = keyblock->next) { + BArrayState *state = um->store.keyblocks[i]; + size_t state_len; + keyblock->data = BLI_array_store_state_data_get_alloc(state, &state_len); + BLI_assert(keyblock->totelem == (state_len / stride)); + UNUSED_VARS_NDEBUG(stride); + } + } + + if (um->store.mselect) { + const size_t stride = sizeof(*me->mselect); + BArrayState *state = um->store.mselect; + size_t state_len; + me->mselect = BLI_array_store_state_data_get_alloc(state, &state_len); + BLI_assert(me->totselect == (state_len / stride)); + UNUSED_VARS_NDEBUG(stride); + } + + /* not essential, but prevents accidental dangling pointer access */ + BKE_mesh_update_customdata_pointers(me, false); +} + +static void um_arraystore_free(UndoMesh *um) +{ + Mesh *me = &um->me; + + um_arraystore_cd_free(um->store.vdata); + um_arraystore_cd_free(um->store.edata); + um_arraystore_cd_free(um->store.ldata); + um_arraystore_cd_free(um->store.pdata); + + if (um->store.keyblocks) { + const size_t stride = me->key->elemsize; + BArrayStore *bs = array_store_at_size_get(stride); + for (int i = 0; i < me->key->totkey; i++) { + BArrayState *state = um->store.keyblocks[i]; + BLI_array_store_state_remove(bs, state); + } + MEM_freeN(um->store.keyblocks); + um->store.keyblocks = NULL; + } + + if (um->store.mselect) { + const size_t stride = sizeof(*me->mselect); + BArrayStore *bs = array_store_at_size_get(stride); + BArrayState *state = um->store.mselect; + BLI_array_store_state_remove(bs, state); + um->store.mselect = NULL; + } + + um_arraystore.users -= 1; + + BLI_assert(um_arraystore.users >= 0); + + if (um_arraystore.users == 0) { +#ifdef DEBUG_PRINT + printf("mesh undo store: freeing all data!\n"); +#endif + for (int i = 0; i < um_arraystore.bs_all_len; i += 1) { + if (um_arraystore.bs_all[i]) { + BLI_array_store_destroy(um_arraystore.bs_all[i]); + } + } + + MEM_freeN(um_arraystore.bs_all); + um_arraystore.bs_all = NULL; + um_arraystore.bs_all_len = 0; + +#ifdef USE_ARRAY_STORE_THREAD + BLI_task_pool_free(um_arraystore.task_pool); + um_arraystore.task_pool = NULL; +#endif + } + +} + +/** \} */ + +#endif /* USE_ARRAY_STORE */ + + +/* for callbacks */ +/* undo simply makes copies of a bmesh */ +static void *editbtMesh_to_undoMesh(void *emv, void *obdata) +{ + +#ifdef USE_ARRAY_STORE_THREAD + /* changes this waits is low, but must have finished */ + if (um_arraystore.task_pool) { + BLI_task_pool_work_and_wait(um_arraystore.task_pool); + } +#endif + + BMEditMesh *em = emv; + Mesh *obme = obdata; + + UndoMesh *um = MEM_callocN(sizeof(UndoMesh), "undo Mesh"); + + /* make sure shape keys work */ + um->me.key = obme->key ? BKE_key_copy_nolib(obme->key) : NULL; + + /* BM_mesh_validate(em->bm); */ /* for troubleshooting */ + + BM_mesh_bm_to_me( + em->bm, &um->me, (&(struct BMeshToMeshParams){ + .cd_mask_extra = CD_MASK_SHAPE_KEYINDEX, + })); + + um->selectmode = em->selectmode; + um->shapenr = em->bm->shapenr; + +#ifdef USE_ARRAY_STORE + { + /* We could be more clever here, + * the previous undo state may be from a separate mesh. */ + const UndoMesh *um_ref = um_arraystore.local_links.last ? + ((LinkData *)um_arraystore.local_links.last)->data : NULL; + + /* add oursrlves */ + BLI_addtail(&um_arraystore.local_links, BLI_genericNodeN(um)); + +#ifdef USE_ARRAY_STORE_THREAD + if (um_arraystore.task_pool == NULL) { + TaskScheduler *scheduler = BLI_task_scheduler_get(); + um_arraystore.task_pool = BLI_task_pool_create_background(scheduler, NULL); + } + + struct UMArrayData *um_data = MEM_mallocN(sizeof(*um_data), __func__); + um_data->um = um; + um_data->um_ref = um_ref; + + BLI_task_pool_push( + um_arraystore.task_pool, + um_arraystore_compact_cb, um_data, true, TASK_PRIORITY_LOW); +#else + um_arraystore_compact_with_info(um, um_ref); +#endif + } +#endif + + return um; +} + +static void undoMesh_to_editbtMesh(void *um_v, void *em_v, void *obdata) +{ + BMEditMesh *em = em_v, *em_tmp; + Object *ob = em->ob; + UndoMesh *um = um_v; + BMesh *bm; + Key *key = ((Mesh *) obdata)->key; + +#ifdef USE_ARRAY_STORE +#ifdef USE_ARRAY_STORE_THREAD + /* changes this waits is low, but must have finished */ + BLI_task_pool_work_and_wait(um_arraystore.task_pool); +#endif + +#ifdef DEBUG_TIME + TIMEIT_START(mesh_undo_expand); +#endif + + um_arraystore_expand(um); + +#ifdef DEBUG_TIME + TIMEIT_END(mesh_undo_expand); +#endif +#endif /* USE_ARRAY_STORE */ + + const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(&um->me); + + em->bm->shapenr = um->shapenr; + + EDBM_mesh_free(em); + + bm = BM_mesh_create(&allocsize); + + BM_mesh_bm_from_me( + bm, &um->me, (&(struct BMeshFromMeshParams){ + .calc_face_normal = true, .active_shapekey = um->shapenr, + })); + + em_tmp = BKE_editmesh_create(bm, true); + *em = *em_tmp; + + em->selectmode = um->selectmode; + bm->selectmode = um->selectmode; + em->ob = ob; + + /* T35170: Restore the active key on the RealMesh. Otherwise 'fake' offset propagation happens + * if the active is a basis for any other. */ + if (key && (key->type == KEY_RELATIVE)) { + /* Since we can't add, remove or reorder keyblocks in editmode, it's safe to assume + * shapenr from restored bmesh and keyblock indices are in sync. */ + const int kb_act_idx = ob->shapenr - 1; + + /* If it is, let's patch the current mesh key block to its restored value. + * Else, the offsets won't be computed and it won't matter. */ + if (BKE_keyblock_is_basis(key, kb_act_idx)) { + KeyBlock *kb_act = BLI_findlink(&key->block, kb_act_idx); + + if (kb_act->totelem != um->me.totvert) { + /* The current mesh has some extra/missing verts compared to the undo, adjust. */ + MEM_SAFE_FREE(kb_act->data); + kb_act->data = MEM_mallocN((size_t)(key->elemsize * bm->totvert), __func__); + kb_act->totelem = um->me.totvert; + } + + BKE_keyblock_update_from_mesh(&um->me, kb_act); + } + } + + ob->shapenr = um->shapenr; + + MEM_freeN(em_tmp); + +#ifdef USE_ARRAY_STORE + um_arraystore_expand_clear(um); +#endif +} + +static void free_undo(void *um_v) +{ + UndoMesh *um = um_v; + Mesh *me = &um->me; + +#ifdef USE_ARRAY_STORE + +#ifdef USE_ARRAY_STORE_THREAD + /* changes this waits is low, but must have finished */ + BLI_task_pool_work_and_wait(um_arraystore.task_pool); +#endif + + /* we need to expand so any allocations in custom-data are freed with the mesh */ + um_arraystore_expand(um); + + { + LinkData *link = BLI_findptr(&um_arraystore.local_links, um, offsetof(LinkData, data)); + BLI_remlink(&um_arraystore.local_links, link); + MEM_freeN(link); + } + um_arraystore_free(um); +#endif + + if (me->key) { + BKE_key_free(me->key); + MEM_freeN(me->key); + } + + BKE_mesh_free(me, false); + MEM_freeN(me); +} + +static void *getEditMesh(bContext *C) +{ + Object *obedit = CTX_data_edit_object(C); + if (obedit && obedit->type == OB_MESH) { + Mesh *me = obedit->data; + return me->edit_btmesh; + } + return NULL; +} + +/* and this is all the undo system needs to know */ +void undo_push_mesh(bContext *C, const char *name) +{ + /* em->ob gets out of date and crashes on mesh undo, + * this is an easy way to ensure its OK + * though we could investigate the matter further. */ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + em->ob = obedit; + + undo_editmode_push(C, name, getEditMesh, free_undo, undoMesh_to_editbtMesh, editbtMesh_to_undoMesh, NULL); +} diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 82ec93c162f..99be37845ee 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -45,7 +45,6 @@ #include "BKE_context.h" #include "BKE_global.h" #include "BKE_depsgraph.h" -#include "BKE_key.h" #include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" @@ -60,7 +59,6 @@ #include "ED_mesh.h" #include "ED_screen.h" -#include "ED_util.h" #include "ED_view3d.h" #include "mesh_intern.h" /* own include */ @@ -491,140 +489,6 @@ void EDBM_flag_enable_all(BMEditMesh *em, const char hflag) BM_mesh_elem_hflag_enable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, hflag, true); } -/**************-------------- Undo ------------*****************/ - -/* for callbacks */ - -static void *getEditMesh(bContext *C) -{ - Object *obedit = CTX_data_edit_object(C); - if (obedit && obedit->type == OB_MESH) { - Mesh *me = obedit->data; - return me->edit_btmesh; - } - return NULL; -} - -typedef struct UndoMesh { - Mesh me; - int selectmode; - - /** \note - * this isn't a prefect solution, if you edit keys and change shapes this works well (fixing [#32442]), - * but editing shape keys, going into object mode, removing or changing their order, - * then go back into editmode and undo will give issues - where the old index will be out of sync - * with the new object index. - * - * There are a few ways this could be made to work but for now its a known limitation with mixing - * object and editmode operations - Campbell */ - int shapenr; -} UndoMesh; - -/* undo simply makes copies of a bmesh */ -static void *editbtMesh_to_undoMesh(void *emv, void *obdata) -{ - BMEditMesh *em = emv; - Mesh *obme = obdata; - - UndoMesh *um = MEM_callocN(sizeof(UndoMesh), "undo Mesh"); - - /* make sure shape keys work */ - um->me.key = obme->key ? BKE_key_copy_nolib(obme->key) : NULL; - - /* BM_mesh_validate(em->bm); */ /* for troubleshooting */ - - BM_mesh_bm_to_me( - em->bm, &um->me, (&(struct BMeshToMeshParams){ - .cd_mask_extra = CD_MASK_SHAPE_KEYINDEX, - })); - - um->selectmode = em->selectmode; - um->shapenr = em->bm->shapenr; - - return um; -} - -static void undoMesh_to_editbtMesh(void *umv, void *em_v, void *obdata) -{ - BMEditMesh *em = em_v, *em_tmp; - Object *ob = em->ob; - UndoMesh *um = umv; - BMesh *bm; - Key *key = ((Mesh *) obdata)->key; - - const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(&um->me); - - em->bm->shapenr = um->shapenr; - - EDBM_mesh_free(em); - - bm = BM_mesh_create(&allocsize); - - BM_mesh_bm_from_me( - bm, &um->me, (&(struct BMeshFromMeshParams){ - .calc_face_normal = true, .active_shapekey = um->shapenr, - })); - - em_tmp = BKE_editmesh_create(bm, true); - *em = *em_tmp; - - em->selectmode = um->selectmode; - bm->selectmode = um->selectmode; - em->ob = ob; - - /* T35170: Restore the active key on the RealMesh. Otherwise 'fake' offset propagation happens - * if the active is a basis for any other. */ - if (key && (key->type == KEY_RELATIVE)) { - /* Since we can't add, remove or reorder keyblocks in editmode, it's safe to assume - * shapenr from restored bmesh and keyblock indices are in sync. */ - const int kb_act_idx = ob->shapenr - 1; - - /* If it is, let's patch the current mesh key block to its restored value. - * Else, the offsets won't be computed and it won't matter. */ - if (BKE_keyblock_is_basis(key, kb_act_idx)) { - KeyBlock *kb_act = BLI_findlink(&key->block, kb_act_idx); - - if (kb_act->totelem != um->me.totvert) { - /* The current mesh has some extra/missing verts compared to the undo, adjust. */ - MEM_SAFE_FREE(kb_act->data); - kb_act->data = MEM_mallocN((size_t)(key->elemsize * bm->totvert), __func__); - kb_act->totelem = um->me.totvert; - } - - BKE_keyblock_update_from_mesh(&um->me, kb_act); - } - } - - ob->shapenr = um->shapenr; - - MEM_freeN(em_tmp); -} - -static void free_undo(void *me_v) -{ - Mesh *me = me_v; - if (me->key) { - BKE_key_free(me->key); - MEM_freeN(me->key); - } - - BKE_mesh_free(me, false); - MEM_freeN(me); -} - -/* and this is all the undo system needs to know */ -void undo_push_mesh(bContext *C, const char *name) -{ - /* em->ob gets out of date and crashes on mesh undo, - * this is an easy way to ensure its OK - * though we could investigate the matter further. */ - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - em->ob = obedit; - - undo_editmode_push(C, name, getEditMesh, free_undo, undoMesh_to_editbtMesh, editbtMesh_to_undoMesh, NULL); -} - /** * Return a new UVVertMap from the editmesh */ diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index b6c026ebd37..20e159f4f51 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -2863,7 +2863,7 @@ static void initBend(TransInfo *t) //copy_v3_v3(t->center, ED_view3d_cursor3d_get(t->scene, t->view)); calculateCenterCursor(t, t->center); - calculateCenterGlobal(t); + calculateCenterGlobal(t, t->center, t->center_global); t->val = 0.0f; diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index f4d93389776..4e8aa0cc20b 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -369,6 +369,11 @@ typedef struct TransCustomData { unsigned int use_free : 1; } TransCustomData; +typedef struct TransCenterData { + float local[3], global[3]; + unsigned int is_set : 1; +} TransCenterData; + typedef struct TransInfo { int mode; /* current mode */ int flag; /* generic flags for special behaviors */ @@ -396,6 +401,9 @@ typedef struct TransInfo { float center[3]; /* center of transformation (in local-space) */ float center_global[3]; /* center of transformation (in global-space) */ float center2d[2]; /* center in screen coordinates */ + /* Lazy initialize center data for when we need other center values. + * V3D_AROUND_ACTIVE + 1 (static assert checks this) */ + TransCenterData center_cache[5]; short idx_max; /* maximum index on the input vector */ float snap[3]; /* Snapping Gears */ float snap_spatial[3]; /* Spatial snapping gears(even when rotating, scaling... etc) */ @@ -741,8 +749,11 @@ void restoreTransObjects(TransInfo *t); void recalcData(TransInfo *t); void calculateCenter2D(TransInfo *t); -void calculateCenterGlobal(TransInfo *t); +void calculateCenterGlobal( + TransInfo *t, const float center_local[3], + float r_center_global[3]); +const TransCenterData *transformCenter_from_type(TransInfo *t, int around); void calculateCenter(TransInfo *t); /* API functions for getting center points */ diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 28202f21c0e..78cebbf2c6e 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1601,16 +1601,18 @@ void calculateCenter2D(TransInfo *t) } } -void calculateCenterGlobal(TransInfo *t) +void calculateCenterGlobal( + TransInfo *t, const float center_local[3], + float r_center_global[3]) { /* setting constraint center */ /* note, init functions may over-ride t->center */ if (t->flag & (T_EDIT | T_POSE)) { Object *ob = t->obedit ? t->obedit : t->poseobj; - mul_v3_m4v3(t->center_global, ob->obmat, t->center); + mul_v3_m4v3(r_center_global, ob->obmat, center_local); } else { - copy_v3_v3(t->center_global, t->center); + copy_v3_v3(r_center_global, center_local); } } @@ -1785,43 +1787,55 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3]) return ok; } - -void calculateCenter(TransInfo *t) +static void calculateCenter_FromAround(TransInfo *t, int around, float r_center[3]) { - switch (t->around) { + switch (around) { case V3D_AROUND_CENTER_BOUNDS: - calculateCenterBound(t, t->center); + calculateCenterBound(t, r_center); break; case V3D_AROUND_CENTER_MEAN: - calculateCenterMedian(t, t->center); + calculateCenterMedian(t, r_center); break; case V3D_AROUND_CURSOR: if (ELEM(t->spacetype, SPACE_IMAGE, SPACE_CLIP)) - calculateCenterCursor2D(t, t->center); + calculateCenterCursor2D(t, r_center); else if (t->spacetype == SPACE_IPO) - calculateCenterCursorGraph2D(t, t->center); + calculateCenterCursorGraph2D(t, r_center); else - calculateCenterCursor(t, t->center); + calculateCenterCursor(t, r_center); break; case V3D_AROUND_LOCAL_ORIGINS: /* Individual element center uses median center for helpline and such */ - calculateCenterMedian(t, t->center); + calculateCenterMedian(t, r_center); break; case V3D_AROUND_ACTIVE: { - if (calculateCenterActive(t, false, t->center)) { + if (calculateCenterActive(t, false, r_center)) { /* pass */ } else { /* fallback */ - calculateCenterMedian(t, t->center); + calculateCenterMedian(t, r_center); } break; } } +} + +void calculateCenter(TransInfo *t) +{ + calculateCenter_FromAround(t, t->around, t->center); + calculateCenterGlobal(t, t->center, t->center_global); + + /* avoid calculating again */ + { + TransCenterData *cd = &t->center_cache[t->around]; + copy_v3_v3(cd->local, t->center); + copy_v3_v3(cd->global, t->center_global); + cd->is_set = true; + } calculateCenter2D(t); - calculateCenterGlobal(t); /* for panning from cameraview */ if (t->flag & T_OBJECT) { @@ -1875,6 +1889,23 @@ void calculateCenter(TransInfo *t) } } +BLI_STATIC_ASSERT(ARRAY_SIZE(((TransInfo *)NULL)->center_cache) == (V3D_AROUND_ACTIVE + 1), "test size"); + +/** + * Lazy initialize transform center data, when we need to access center values from other types. + */ +const TransCenterData *transformCenter_from_type(TransInfo *t, int around) +{ + BLI_assert(around <= V3D_AROUND_ACTIVE); + TransCenterData *cd = &t->center_cache[around]; + if (cd->is_set == false) { + calculateCenter_FromAround(t, around, cd->local); + calculateCenterGlobal(t, cd->local, cd->global); + cd->is_set = true; + } + return cd; +} + void calculatePropRatio(TransInfo *t) { TransData *td = t->data; diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 1bb8b768981..cb981bc4771 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -1512,11 +1512,21 @@ static void applyGridIncrement(TransInfo *t, float *val, int max_index, const fl /* absolute snapping on grid based on global center */ if ((t->tsnap.snap_spatial_grid) && (t->mode == TFM_TRANSLATION)) { + const float *center_global = t->center_global; + + /* use a fallback for cursor selection, + * this isn't useful as a global center for absolute grid snapping + * since its not based on the position of the selection. */ + if (t->around == V3D_AROUND_CURSOR) { + const TransCenterData *cd = transformCenter_from_type(t, V3D_AROUND_CENTER_MEAN); + center_global = cd->global; + } + for (i = 0; i <= max_index; i++) { /* do not let unconstrained axis jump to absolute grid increments */ if (!(t->con.mode & CON_APPLY) || t->con.mode & (CON_AXIS0 << i)) { const float iter_fac = fac[action] * asp[i]; - val[i] = iter_fac * roundf((val[i] + t->center_global[i]) / iter_fac) - t->center_global[i]; + val[i] = iter_fac * roundf((val[i] + center_global[i]) / iter_fac) - center_global[i]; } } } diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h index a8656c05224..ee7abe08aba 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -147,6 +147,7 @@ typedef struct GPUVertPointLink { /* used for GLSL materials */ typedef struct GPUAttrib { int index; + int info_index; int size; int type; } GPUAttrib; @@ -179,6 +180,10 @@ typedef enum { GPU_BINDING_INDEX = 1, } GPUBindingType; +typedef enum { + GPU_ATTR_INFO_SRGB = (1 << 0), +} GPUAttrInfo; + /* called before drawing */ void GPU_vertex_setup(struct DerivedMesh *dm); void GPU_normal_setup(struct DerivedMesh *dm); diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index 4c674b460aa..762329ee077 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -104,6 +104,7 @@ typedef struct GPUVertexAttribs { struct { int type; int glindex; + int glinfoindoex; int gltexco; int attribid; char name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 6ff4a60610b..bd7a3b628c8 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -822,6 +822,12 @@ void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numda for (i = 0; i < numdata; i++) { glEnableVertexAttribArray(data[i].index); + int info = 0; + if (data[i].type == GL_UNSIGNED_BYTE) { + info |= GPU_ATTR_INFO_SRGB; + } + glUniform1i(data[i].info_index, info); + glVertexAttribPointer(data[i].index, data[i].size, data[i].type, GL_TRUE, elementsize, BUFFER_OFFSET(offset)); offset += data[i].size * GPU_typesize(data[i].type); diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index be5a0ab4173..9f41253b176 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -741,6 +741,7 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type) BLI_dynstr_appendf(ds, "%s %s att%d;\n", GLEW_VERSION_3_0 ? "in" : "attribute", GPU_DATATYPE_STR[input->type], input->attribid); + BLI_dynstr_appendf(ds, "uniform int att%d_info;\n", input->attribid); BLI_dynstr_appendf(ds, "%s %s var%d;\n", GLEW_VERSION_3_0 ? "out" : "varying", GPU_DATATYPE_STR[input->type], input->attribid); @@ -793,7 +794,8 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type) BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n"); } #endif - BLI_dynstr_appendf(ds, "\tvar%d = att%d;\n", input->attribid, input->attribid); + BLI_dynstr_appendf(ds, "\tset_var_from_attr(att%d, att%d_info, var%d);\n", + input->attribid, input->attribid, input->attribid); #ifdef WITH_OPENSUBDIV if (is_mtface) { BLI_dynstr_appendf(ds, "#endif\n"); diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c index c15e49a8ed1..a6d120b8943 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.c +++ b/source/blender/gpu/intern/gpu_framebuffer.c @@ -575,7 +575,7 @@ void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels) glFramebufferTexture2DEXT( GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + ofs->color->fb_attachment, GL_TEXTURE_2D_MULTISAMPLE, ofs->color->bindcode, 0); - status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER_EXT); + status = glCheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER_EXT); if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { goto finally; } @@ -583,11 +583,11 @@ void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels) /* write into new single-sample buffer */ glGenFramebuffersEXT(1, &fbo_blit); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, fbo_blit); + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, fbo_blit); glFramebufferTexture2DEXT( - GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0, + GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, tex_blit, 0); - status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER_EXT); + status = glCheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT); if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { goto finally; } diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 2bded95a1b5..b2e479043d2 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -207,6 +207,9 @@ static void gpu_material_set_attrib_id(GPUMaterial *material) BLI_snprintf(name, sizeof(name), "att%d", attribs->layer[a].attribid); attribs->layer[a].glindex = GPU_shader_get_attribute(shader, name); + BLI_snprintf(name, sizeof(name), "att%d_info", attribs->layer[a].attribid); + attribs->layer[a].glinfoindoex = GPU_shader_get_uniform(shader, name); + if (attribs->layer[a].glindex >= 0) { attribs->layer[b] = attribs->layer[a]; b++; diff --git a/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl b/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl index 2f501dfab05..ad4182340d6 100644 --- a/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl @@ -91,7 +91,7 @@ void main() discard; } else if (stipple_id == STIPPLE_CHECKER_8PX) { - int result = int(mod(int(gl_FragCoord.x)/8 + int(gl_FragCoord.y) / 8, 2)); + int result = int(mod(int(gl_FragCoord.x) / 8 + int(gl_FragCoord.y) / 8, 2)); if (result != 0) discard; } @@ -165,7 +165,7 @@ void main() /* diffuse light */ vec3 light_diffuse = gl_LightSource[i].diffuse.rgb; float diffuse_bsdf = max(dot(N, light_direction), 0.0); - L_diffuse += light_diffuse*diffuse_bsdf; + L_diffuse += light_diffuse * diffuse_bsdf; #ifndef NO_SPECULAR /* specular light */ @@ -173,7 +173,7 @@ void main() vec3 H = gl_LightSource[i].halfVector.xyz; float specular_bsdf = pow(max(dot(N, H), 0.0), gl_FrontMaterial.shininess); - L_specular += light_specular*specular_bsdf; + L_specular += light_specular * specular_bsdf; #endif } #else @@ -181,7 +181,7 @@ void main() #ifndef NO_SPECULAR /* view vector computation, depends on orthographics or perspective */ - vec3 V = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(varying_position): vec3(0.0, 0.0, -1.0); + vec3 V = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(varying_position) : vec3(0.0, 0.0, -1.0); #endif for (int i = 0; i < NUM_SCENE_LIGHTS; i++) { @@ -212,14 +212,14 @@ void main() float distance = length(d); intensity /= gl_LightSource[i].constantAttenuation + - gl_LightSource[i].linearAttenuation * distance + - gl_LightSource[i].quadraticAttenuation * distance * distance; + gl_LightSource[i].linearAttenuation * distance + + gl_LightSource[i].quadraticAttenuation * distance * distance; } /* diffuse light */ vec3 light_diffuse = gl_LightSource[i].diffuse.rgb; float diffuse_bsdf = max(dot(N, light_direction), 0.0); - L_diffuse += light_diffuse*diffuse_bsdf*intensity; + L_diffuse += light_diffuse * diffuse_bsdf * intensity; #ifndef NO_SPECULAR /* specular light */ @@ -227,7 +227,7 @@ void main() vec3 H = normalize(light_direction - V); float specular_bsdf = pow(max(dot(N, H), 0.0), gl_FrontMaterial.shininess); - L_specular += light_specular*specular_bsdf*intensity; + L_specular += light_specular * specular_bsdf * intensity; #endif } #endif @@ -257,7 +257,7 @@ void main() vec3 L = gl_FrontLightModelProduct.sceneColor.rgb + L_diffuse; #ifndef NO_SPECULAR - L += L_specular*gl_FrontMaterial.specular.rgb; + L += L_specular * gl_FrontMaterial.specular.rgb; #endif /* write out fragment color */ diff --git a/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl b/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl index 674dd534352..a88681a5fd3 100644 --- a/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl +++ b/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl @@ -1,6 +1,6 @@ /* -* Used the implementation of wide lines of Timo Suoranta (http://neure.dy.fi/wideline.html) -*/ + * Used the implementation of wide lines of Timo Suoranta (http://neure.dy.fi/wideline.html) + */ #define PASSTHROUGH 0 @@ -24,72 +24,72 @@ uniform int stipple_factor; void main(void) { - vec2 window_size = viewport.zw; - vec4 start = gl_in[0].gl_Position; - vec4 end = gl_in[1].gl_Position; + vec2 window_size = viewport.zw; + vec4 start = gl_in[0].gl_Position; + vec4 end = gl_in[1].gl_Position; #if PASSTHROUGH - gl_Position = start; EmitVertex(); - gl_Position = end; EmitVertex(); - EndPrimitive(); - return; + gl_Position = start; EmitVertex(); + gl_Position = end; EmitVertex(); + EndPrimitive(); + return; #endif -/* t = 0 t = ~(len(end - start) + 2*line_width) - * A-------------------------------------B - * | | | | - * | side | | - * | | | | - * |--axis--*start--------------*end-----| - * | | | | - * | | | | - * | | | | - * D-------------------------------------C - */ - - /* Clip the line before homogenization. - * Compute line start and end distances to nearplane in clipspace - * Distances are t0 = dot(start, plane) and t1 = dot(end, plane) - */ - float t0 = start.z + start.w; - float t1 = end.z + end.w; - if (t0 < 0.0) { - if (t1 < 0.0) { - return; - } - start = mix(start, end, (0 - t0) / (t1 - t0)); - } - if (t1 < 0.0) { - end = mix(start, end, (0 - t0) / (t1 - t0)); - } - - /* Compute line axis and side vector in screen space */ - vec2 startInNDC = start.xy / start.w; /* clip to NDC: homogenize and drop z */ - vec2 endInNDC = end.xy / end.w; - vec2 lineInNDC = endInNDC - startInNDC; - vec2 lineInScreen = lineInNDC * window_size; /* ndc to screen (direction vector) */ - - vec2 axisInScreen = normalize(lineInScreen); - vec2 sideInScreen = vec2(-axisInScreen.y, axisInScreen.x); /* rotate */ - vec2 axisInNDC = axisInScreen / window_size; /* screen to NDC */ - vec2 sideInNDC = sideInScreen / window_size; - vec4 axis = vec4(axisInNDC, 0.0, 0.0) * line_width; /* NDC to clip (delta vector) */ - vec4 side = vec4(sideInNDC, 0.0, 0.0) * line_width; - - vec4 A = (start + (side - axis) * start.w); - vec4 B = (end + (side + axis) * end.w); - vec4 C = (end - (side - axis) * end.w); - vec4 D = (start - (side + axis) * start.w); - - /* There is no relation between lines yet */ - /* TODO Pass here t0 to make continuous pattern. */ - t0 = 0; - t1 = (length(lineInScreen) + 2*line_width)/ (2*line_width * stipple_factor); - - gl_Position = A; t = t0; varying_vertex_color = varying_vertex_color_line[0]; EmitVertex(); - gl_Position = D; t = t0; varying_vertex_color = varying_vertex_color_line[0]; EmitVertex(); - gl_Position = B; t = t1; varying_vertex_color = varying_vertex_color_line[1]; EmitVertex(); - gl_Position = C; t = t1; varying_vertex_color = varying_vertex_color_line[1]; EmitVertex(); - EndPrimitive(); + /* t = 0 t = ~(len(end - start) + 2*line_width) + * A-------------------------------------B + * | | | | + * | side | | + * | | | | + * |--axis--*start--------------*end-----| + * | | | | + * | | | | + * | | | | + * D-------------------------------------C + */ + + /* Clip the line before homogenization. + * Compute line start and end distances to nearplane in clipspace + * Distances are t0 = dot(start, plane) and t1 = dot(end, plane) + */ + float t0 = start.z + start.w; + float t1 = end.z + end.w; + if (t0 < 0.0) { + if (t1 < 0.0) { + return; + } + start = mix(start, end, (0 - t0) / (t1 - t0)); + } + if (t1 < 0.0) { + end = mix(start, end, (0 - t0) / (t1 - t0)); + } + + /* Compute line axis and side vector in screen space */ + vec2 startInNDC = start.xy / start.w; /* clip to NDC: homogenize and drop z */ + vec2 endInNDC = end.xy / end.w; + vec2 lineInNDC = endInNDC - startInNDC; + vec2 lineInScreen = lineInNDC * window_size; /* ndc to screen (direction vector) */ + + vec2 axisInScreen = normalize(lineInScreen); + vec2 sideInScreen = vec2(-axisInScreen.y, axisInScreen.x); /* rotate */ + vec2 axisInNDC = axisInScreen / window_size; /* screen to NDC */ + vec2 sideInNDC = sideInScreen / window_size; + vec4 axis = vec4(axisInNDC, 0.0, 0.0) * line_width; /* NDC to clip (delta vector) */ + vec4 side = vec4(sideInNDC, 0.0, 0.0) * line_width; + + vec4 A = (start + (side - axis) * start.w); + vec4 B = (end + (side + axis) * end.w); + vec4 C = (end - (side - axis) * end.w); + vec4 D = (start - (side + axis) * start.w); + + /* There is no relation between lines yet */ + /* TODO Pass here t0 to make continuous pattern. */ + t0 = 0; + t1 = (length(lineInScreen) + 2 * line_width) / (2 * line_width * stipple_factor); + + gl_Position = A; t = t0; varying_vertex_color = varying_vertex_color_line[0]; EmitVertex(); + gl_Position = D; t = t0; varying_vertex_color = varying_vertex_color_line[0]; EmitVertex(); + gl_Position = B; t = t1; varying_vertex_color = varying_vertex_color_line[1]; EmitVertex(); + gl_Position = C; t = t1; varying_vertex_color = varying_vertex_color_line[1]; EmitVertex(); + EndPrimitive(); } #else diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl index e9dab04de5d..338ef6d51a7 100644 --- a/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl @@ -115,9 +115,9 @@ void second_pass() color += texture2D(colorbuffer, uvcoordsvar.xy + invrendertargetdim) * 0.234375; color += texture2D(colorbuffer, uvcoordsvar.xy + 2.5 * invrendertargetdim) * 0.09375; color += texture2D(colorbuffer, uvcoordsvar.xy + 4.5 * invrendertargetdim) * 0.015625; - color += texture2D(colorbuffer, uvcoordsvar.xy -invrendertargetdim) * 0.234375; - color += texture2D(colorbuffer, uvcoordsvar.xy -2.5 * invrendertargetdim) * 0.09375; - color += texture2D(colorbuffer, uvcoordsvar.xy -4.5 * invrendertargetdim) * 0.015625; + color += texture2D(colorbuffer, uvcoordsvar.xy - invrendertargetdim) * 0.234375; + color += texture2D(colorbuffer, uvcoordsvar.xy - 2.5 * invrendertargetdim) * 0.09375; + color += texture2D(colorbuffer, uvcoordsvar.xy - 4.5 * invrendertargetdim) * 0.015625; gl_FragColor = color; } @@ -128,7 +128,7 @@ void third_pass() { vec4 color = texture2D(colorbuffer, uvcoordsvar.xy); vec4 color_blurred = texture2D(blurredcolorbuffer, uvcoordsvar.xy); - float coc = 2.0 * max(color_blurred.a, color.a); - color.a; + float coc = 2.0 * max(color_blurred.a, color.a); -color.a; gl_FragColor = vec4(color.rgb, coc); } @@ -146,7 +146,7 @@ void fourth_pass() vec4 small_sample_blur(in sampler2D colorbuffer, in vec2 uv, in vec4 color) { - float weight = 1.0/ 17.0; + float weight = 1.0 / 17.0; vec4 result = weight * color; weight *= 4.0; diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl index 7657fbb71ab..182113367d3 100644 --- a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl @@ -103,7 +103,7 @@ void accumulate_pass(void) { r = 1.0; else r = cos(M_PI / dof_params.w) / - (cos(theta - (2.0 * M_PI / dof_params.w) * floor((dof_params.w * theta + M_PI) / (2.0 * M_PI)))); + (cos(theta - (2.0 * M_PI / dof_params.w) * floor((dof_params.w * theta + M_PI) / (2.0 * M_PI)))); if (dot(particlecoord, particlecoord) > r * r) discard; diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl index a2ef990c4e8..63b57d5775c 100644 --- a/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl @@ -38,8 +38,12 @@ void vert_dof_first_pass() void vert_dof_fourth_pass() { vec4 halfpixel = vec4(-0.5, 0.5, -0.5, 0.5); - uvcoordsvar = gl_MultiTexCoord0.xxyy + halfpixel * vec4(invrendertargetdim.x, - invrendertargetdim.x, invrendertargetdim.y, invrendertargetdim.y); + uvcoordsvar = gl_MultiTexCoord0.xxyy + + halfpixel * + vec4(invrendertargetdim.x, + invrendertargetdim.x, + invrendertargetdim.y, + invrendertargetdim.y); gl_Position = gl_Vertex; } diff --git a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl index c2cd927898e..054a2f795ee 100644 --- a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl @@ -77,7 +77,7 @@ float calculate_ssao_factor(float depth) /* use minor bias here to avoid self shadowing */ if (f > 0.05 * len + 0.0001) - factor += f * 1.0/(len * (1.0 + len * len * ssao_params.z)); + factor += f * 1.0 / (len * (1.0 + len * len * ssao_params.z)); } } diff --git a/source/blender/gpu/shaders/gpu_shader_geometry.glsl b/source/blender/gpu/shaders/gpu_shader_geometry.glsl index 16fba0dd055..1663915549c 100644 --- a/source/blender/gpu/shaders/gpu_shader_geometry.glsl +++ b/source/blender/gpu/shaders/gpu_shader_geometry.glsl @@ -49,7 +49,7 @@ void emit_flat(int index, vec3 normal) varposition = outpt.v.position.xyz; /* TODO(sergey): Only uniform subdivisions atm. */ - vec2 quadst[4] = vec2[](vec2(0,0), vec2(1,0), vec2(1,1), vec2(0,1)); + vec2 quadst[4] = vec2[](vec2(0, 0), vec2(1, 0), vec2(1, 1), vec2(0, 1)); vec2 st = quadst[index]; INTERP_FACE_VARYING_2(outpt.v.uv, osd_active_uv_offset, st); @@ -70,7 +70,7 @@ void emit_smooth(int index) varposition = outpt.v.position.xyz; /* TODO(sergey): Only uniform subdivisions atm. */ - vec2 quadst[4] = vec2[](vec2(0,0), vec2(1,0), vec2(1,1), vec2(0,1)); + vec2 quadst[4] = vec2[](vec2(0, 0), vec2(1, 0), vec2(1, 1), vec2(0, 1)); vec2 st = quadst[index]; INTERP_FACE_VARYING_2(outpt.v.uv, osd_active_uv_offset, st); diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index a63e7b8dbf0..9914c4bb362 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -3,7 +3,7 @@ float convert_rgba_to_float(vec4 color) { #ifdef USE_NEW_SHADING - return color.r*0.2126 + color.g*0.7152 + color.b*0.0722; + return color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722; #else return (color.r + color.g + color.b) / 3.0; #endif @@ -39,11 +39,11 @@ void rgb_to_hsv(vec4 rgb, out vec4 outcol) cmax = max(rgb[0], max(rgb[1], rgb[2])); cmin = min(rgb[0], min(rgb[1], rgb[2])); - cdelta = cmax-cmin; + cdelta = cmax - cmin; v = cmax; - if (cmax!=0.0) - s = cdelta/cmax; + if (cmax != 0.0) + s = cdelta / cmax; else { s = 0.0; h = 0.0; @@ -53,15 +53,15 @@ void rgb_to_hsv(vec4 rgb, out vec4 outcol) h = 0.0; } else { - c = (vec3(cmax, cmax, cmax) - rgb.xyz)/cdelta; + c = (vec3(cmax, cmax, cmax) - rgb.xyz) / cdelta; - if (rgb.x==cmax) h = c[2] - c[1]; - else if (rgb.y==cmax) h = 2.0 + c[0] - c[2]; + if (rgb.x == cmax) h = c[2] - c[1]; + else if (rgb.y == cmax) h = 2.0 + c[0] - c[2]; else h = 4.0 + c[1] - c[0]; h /= 6.0; - if (h<0.0) + if (h < 0.0) h += 1.0; } @@ -77,21 +77,21 @@ void hsv_to_rgb(vec4 hsv, out vec4 outcol) s = hsv[1]; v = hsv[2]; - if (s==0.0) { + if (s == 0.0) { rgb = vec3(v, v, v); } else { - if (h==1.0) + if (h == 1.0) h = 0.0; - + h *= 6.0; i = floor(h); f = h - i; rgb = vec3(f, f, f); - p = v*(1.0-s); - q = v*(1.0-(s*f)); - t = v*(1.0-(s*(1.0-f))); - + p = v * (1.0 - s); + q = v * (1.0 - (s * f)); + t = v * (1.0 - (s * (1.0 - f))); + if (i == 0.0) rgb = vec3(v, t, p); else if (i == 1.0) rgb = vec3(q, v, p); else if (i == 2.0) rgb = vec3(p, v, t); @@ -106,17 +106,17 @@ void hsv_to_rgb(vec4 hsv, out vec4 outcol) float srgb_to_linearrgb(float c) { if (c < 0.04045) - return (c < 0.0) ? 0.0: c * (1.0 / 12.92); + return (c < 0.0) ? 0.0 : c * (1.0 / 12.92); else - return pow((c + 0.055)*(1.0/1.055), 2.4); + return pow((c + 0.055) * (1.0 / 1.055), 2.4); } float linearrgb_to_srgb(float c) { if (c < 0.0031308) - return (c < 0.0) ? 0.0: c * 12.92; + return (c < 0.0) ? 0.0 : c * 12.92; else - return 1.055 * pow(c, 1.0/2.4) - 0.055; + return 1.055 * pow(c, 1.0 / 2.4) - 0.055; } void srgb_to_linearrgb(vec4 col_from, out vec4 col_to) @@ -168,7 +168,7 @@ void vcol_attribute(vec4 attvcol, out vec4 vcol) void uv_attribute(vec2 attuv, out vec3 uv) { - uv = vec3(attuv*2.0 - vec2(1.0, 1.0), 0.0); + uv = vec3(attuv * 2.0 - vec2(1.0, 1.0), 0.0); } void geom( @@ -177,15 +177,15 @@ void geom( out vec3 normal, out vec4 vcol, out float vcol_alpha, out float frontback) { local = co; - view = (gl_ProjectionMatrix[3][3] == 0.0)? normalize(local): vec3(0.0, 0.0, -1.0); - global = (viewinvmat*vec4(local, 1.0)).xyz; + view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(local) : vec3(0.0, 0.0, -1.0); + global = (viewinvmat * vec4(local, 1.0)).xyz; orco = attorco; uv_attribute(attuv, uv); - normal = -normalize(nor); /* blender render normal is negated */ + normal = -normalize(nor); /* blender render normal is negated */ vcol_attribute(attvcol, vcol); srgb_to_linearrgb(vcol, vcol); vcol_alpha = attvcol.a; - frontback = (gl_FrontFacing)? 1.0: 0.0; + frontback = (gl_FrontFacing) ? 1.0 : 0.0; } void particle_info( @@ -210,12 +210,48 @@ void vect_normalize(vec3 vin, out vec3 vout) void direction_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout) { - vout = (mat*vec4(vin, 0.0)).xyz; + vout = (mat * vec4(vin, 0.0)).xyz; } void point_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout) { - vout = (mat*vec4(vin, 1.0)).xyz; + vout = (mat * vec4(vin, 1.0)).xyz; +} + +void point_texco_remap_square(vec3 vin, out vec3 vout) +{ + vout = vec3(vin - vec3(0.5, 0.5, 0.5)) * 2.0; +} + +void point_map_to_sphere(vec3 vin, out vec3 vout) +{ + float len = length(vin); + float v, u; + if (len > 0.0) { + if (vin.x == 0.0 && vin.y == 0.0) + u = 0.0; + else + u = (1.0 - atan(vin.x, vin.y) / M_PI) / 2.0; + + v = 1.0 - acos(vin.z / len) / M_PI; + } + else + v = u = 0.0; + + vout = vec3(u, v, 0.0); +} + +void point_map_to_tube(vec3 vin, out vec3 vout) +{ + float u, v; + v = (vin.z + 1.0) * 0.5; + float len = sqrt(vin.x * vin.x + vin.y * vin[1]); + if (len > 0.0) + u = (1.0 - (atan(vin.x / len, vin.y / len) / M_PI)) * 0.5; + else + v = u = 0.0; + + vout = vec3(u, v, 0.0); } void mapping(vec3 vec, mat4 mat, vec3 minvec, vec3 maxvec, float domin, float domax, out vec3 outvec) @@ -322,9 +358,9 @@ void math_pow(float val1, float val2, out float outval) void math_log(float val1, float val2, out float outval) { if (val1 > 0.0 && val2 > 0.0) - outval= log2(val1) / log2(val2); + outval = log2(val1) / log2(val2); else - outval= 0.0; + outval = 0.0; } void math_max(float val1, float val2, out float outval) @@ -339,7 +375,7 @@ void math_min(float val1, float val2, out float outval) void math_round(float val, out float outval) { - outval= floor(val + 0.5); + outval = floor(val + 0.5); } void math_less_than(float val1, float val2, out float outval) @@ -377,19 +413,19 @@ void math_abs(float val1, out float outval) void squeeze(float val, float width, float center, out float outval) { - outval = 1.0/(1.0 + pow(2.71828183, -((val-center)*width))); + outval = 1.0 / (1.0 + pow(2.71828183, -((val - center) * width))); } void vec_math_add(vec3 v1, vec3 v2, out vec3 outvec, out float outval) { outvec = v1 + v2; - outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2]))/3.0; + outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) / 3.0; } void vec_math_sub(vec3 v1, vec3 v2, out vec3 outvec, out float outval) { outvec = v1 - v2; - outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2]))/3.0; + outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) / 3.0; } void vec_math_average(vec3 v1, vec3 v2, out vec3 outvec, out float outval) @@ -400,7 +436,7 @@ void vec_math_average(vec3 v1, vec3 v2, out vec3 outvec, out float outval) } void vec_math_mix(float strength, vec3 v1, vec3 v2, out vec3 outvec) { - outvec = strength*v1 + (1 - strength) * v2; + outvec = strength * v1 + (1 - strength) * v2; } void vec_math_dot(vec3 v1, vec3 v2, out vec3 outvec, out float outval) @@ -447,12 +483,12 @@ void normal_new_shading(vec3 dir, vec3 nor, out vec3 outnor, out float outdot) void curves_vec(float fac, vec3 vec, sampler2D curvemap, out vec3 outvec) { - outvec.x = texture2D(curvemap, vec2((vec.x + 1.0)*0.5, 0.0)).x; - outvec.y = texture2D(curvemap, vec2((vec.y + 1.0)*0.5, 0.0)).y; - outvec.z = texture2D(curvemap, vec2((vec.z + 1.0)*0.5, 0.0)).z; + outvec.x = texture2D(curvemap, vec2((vec.x + 1.0) * 0.5, 0.0)).x; + outvec.y = texture2D(curvemap, vec2((vec.y + 1.0) * 0.5, 0.0)).y; + outvec.z = texture2D(curvemap, vec2((vec.z + 1.0) * 0.5, 0.0)).z; if (fac != 1.0) - outvec = (outvec*fac) + (vec*(1.0-fac)); + outvec = (outvec * fac) + (vec * (1.0 - fac)); } @@ -463,7 +499,7 @@ void curves_rgb(float fac, vec4 col, sampler2D curvemap, out vec4 outcol) outcol.b = texture2D(curvemap, vec2(texture2D(curvemap, vec2(col.b, 0.0)).a, 0.0)).b; if (fac != 1.0) - outcol = (outcol*fac) + (col*(1.0-fac)); + outcol = (outcol * fac) + (col * (1.0 - fac)); outcol.a = col.a; } @@ -516,11 +552,11 @@ void set_rgba_one(out vec4 outval) void brightness_contrast(vec4 col, float brightness, float contrast, out vec4 outcol) { float a = 1.0 + contrast; - float b = brightness - contrast*0.5; + float b = brightness - contrast * 0.5; - outcol.r = max(a*col.r + b, 0.0); - outcol.g = max(a*col.g + b, 0.0); - outcol.b = max(a*col.b + b, 0.0); + outcol.r = max(a * col.r + b, 0.0); + outcol.g = max(a * col.g + b, 0.0); + outcol.b = max(a * col.b + b, 0.0); outcol.a = col.a; } @@ -550,7 +586,7 @@ void mix_screen(float fac, vec4 col1, vec4 col2, out vec4 outcol) fac = clamp(fac, 0.0, 1.0); float facm = 1.0 - fac; - outcol = vec4(1.0) - (vec4(facm) + fac*(vec4(1.0) - col2))*(vec4(1.0) - col1); + outcol = vec4(1.0) - (vec4(facm) + fac * (vec4(1.0) - col2)) * (vec4(1.0) - col1); outcol.a = col1.a; } @@ -562,19 +598,19 @@ void mix_overlay(float fac, vec4 col1, vec4 col2, out vec4 outcol) outcol = col1; if (outcol.r < 0.5) - outcol.r *= facm + 2.0*fac*col2.r; + outcol.r *= facm + 2.0 * fac * col2.r; else - outcol.r = 1.0 - (facm + 2.0*fac*(1.0 - col2.r))*(1.0 - outcol.r); + outcol.r = 1.0 - (facm + 2.0 * fac * (1.0 - col2.r)) * (1.0 - outcol.r); if (outcol.g < 0.5) - outcol.g *= facm + 2.0*fac*col2.g; + outcol.g *= facm + 2.0 * fac * col2.g; else - outcol.g = 1.0 - (facm + 2.0*fac*(1.0 - col2.g))*(1.0 - outcol.g); + outcol.g = 1.0 - (facm + 2.0 * fac * (1.0 - col2.g)) * (1.0 - outcol.g); if (outcol.b < 0.5) - outcol.b *= facm + 2.0*fac*col2.b; + outcol.b *= facm + 2.0 * fac * col2.b; else - outcol.b = 1.0 - (facm + 2.0*fac*(1.0 - col2.b))*(1.0 - outcol.b); + outcol.b = 1.0 - (facm + 2.0 * fac * (1.0 - col2.b)) * (1.0 - outcol.b); } void mix_sub(float fac, vec4 col1, vec4 col2, out vec4 outcol) @@ -591,9 +627,9 @@ void mix_div(float fac, vec4 col1, vec4 col2, out vec4 outcol) outcol = col1; - if (col2.r != 0.0) outcol.r = facm*outcol.r + fac*outcol.r/col2.r; - if (col2.g != 0.0) outcol.g = facm*outcol.g + fac*outcol.g/col2.g; - if (col2.b != 0.0) outcol.b = facm*outcol.b + fac*outcol.b/col2.b; + if (col2.r != 0.0) outcol.r = facm * outcol.r + fac * outcol.r / col2.r; + if (col2.g != 0.0) outcol.g = facm * outcol.g + fac * outcol.g / col2.g; + if (col2.b != 0.0) outcol.b = facm * outcol.b + fac * outcol.b / col2.b; } void mix_diff(float fac, vec4 col1, vec4 col2, out vec4 outcol) @@ -606,14 +642,14 @@ void mix_diff(float fac, vec4 col1, vec4 col2, out vec4 outcol) void mix_dark(float fac, vec4 col1, vec4 col2, out vec4 outcol) { fac = clamp(fac, 0.0, 1.0); - outcol.rgb = min(col1.rgb, col2.rgb*fac); + outcol.rgb = min(col1.rgb, col2.rgb * fac); outcol.a = col1.a; } void mix_light(float fac, vec4 col1, vec4 col2, out vec4 outcol) { fac = clamp(fac, 0.0, 1.0); - outcol.rgb = max(col1.rgb, col2.rgb*fac); + outcol.rgb = max(col1.rgb, col2.rgb * fac); outcol.a = col1.a; } @@ -623,28 +659,28 @@ void mix_dodge(float fac, vec4 col1, vec4 col2, out vec4 outcol) outcol = col1; if (outcol.r != 0.0) { - float tmp = 1.0 - fac*col2.r; + float tmp = 1.0 - fac * col2.r; if (tmp <= 0.0) outcol.r = 1.0; - else if ((tmp = outcol.r/tmp) > 1.0) + else if ((tmp = outcol.r / tmp) > 1.0) outcol.r = 1.0; else outcol.r = tmp; } if (outcol.g != 0.0) { - float tmp = 1.0 - fac*col2.g; + float tmp = 1.0 - fac * col2.g; if (tmp <= 0.0) outcol.g = 1.0; - else if ((tmp = outcol.g/tmp) > 1.0) + else if ((tmp = outcol.g / tmp) > 1.0) outcol.g = 1.0; else outcol.g = tmp; } if (outcol.b != 0.0) { - float tmp = 1.0 - fac*col2.b; + float tmp = 1.0 - fac * col2.b; if (tmp <= 0.0) outcol.b = 1.0; - else if ((tmp = outcol.b/tmp) > 1.0) + else if ((tmp = outcol.b / tmp) > 1.0) outcol.b = 1.0; else outcol.b = tmp; @@ -658,30 +694,30 @@ void mix_burn(float fac, vec4 col1, vec4 col2, out vec4 outcol) outcol = col1; - tmp = facm + fac*col2.r; + tmp = facm + fac * col2.r; if (tmp <= 0.0) outcol.r = 0.0; - else if ((tmp = (1.0 - (1.0 - outcol.r)/tmp)) < 0.0) + else if ((tmp = (1.0 - (1.0 - outcol.r) / tmp)) < 0.0) outcol.r = 0.0; else if (tmp > 1.0) outcol.r = 1.0; else outcol.r = tmp; - tmp = facm + fac*col2.g; + tmp = facm + fac * col2.g; if (tmp <= 0.0) outcol.g = 0.0; - else if ((tmp = (1.0 - (1.0 - outcol.g)/tmp)) < 0.0) + else if ((tmp = (1.0 - (1.0 - outcol.g) / tmp)) < 0.0) outcol.g = 0.0; else if (tmp > 1.0) outcol.g = 1.0; else outcol.g = tmp; - tmp = facm + fac*col2.b; + tmp = facm + fac * col2.b; if (tmp <= 0.0) outcol.b = 0.0; - else if ((tmp = (1.0 - (1.0 - outcol.b)/tmp)) < 0.0) + else if ((tmp = (1.0 - (1.0 - outcol.b) / tmp)) < 0.0) outcol.b = 0.0; else if (tmp > 1.0) outcol.b = 1.0; @@ -702,7 +738,7 @@ void mix_hue(float fac, vec4 col1, vec4 col2, out vec4 outcol) if (hsv2.y != 0.0) { rgb_to_hsv(outcol, hsv); hsv.x = hsv2.x; - hsv_to_rgb(hsv, tmp); + hsv_to_rgb(hsv, tmp); outcol = mix(outcol, tmp, fac); outcol.a = col1.a; @@ -722,7 +758,7 @@ void mix_sat(float fac, vec4 col1, vec4 col2, out vec4 outcol) if (hsv.y != 0.0) { rgb_to_hsv(col2, hsv2); - hsv.y = facm*hsv.y + fac*hsv2.y; + hsv.y = facm * hsv.y + fac * hsv2.y; hsv_to_rgb(hsv, outcol); } } @@ -736,7 +772,7 @@ void mix_val(float fac, vec4 col1, vec4 col2, out vec4 outcol) rgb_to_hsv(col1, hsv); rgb_to_hsv(col2, hsv2); - hsv.z = facm*hsv.z + fac*hsv2.z; + hsv.z = facm * hsv.z + fac * hsv2.z; hsv_to_rgb(hsv, outcol); } @@ -754,7 +790,7 @@ void mix_color(float fac, vec4 col1, vec4 col2, out vec4 outcol) rgb_to_hsv(outcol, hsv); hsv.x = hsv2.x; hsv.y = hsv2.y; - hsv_to_rgb(hsv, tmp); + hsv_to_rgb(hsv, tmp); outcol = mix(outcol, tmp, fac); outcol.a = col1.a; @@ -766,16 +802,16 @@ void mix_soft(float fac, vec4 col1, vec4 col2, out vec4 outcol) fac = clamp(fac, 0.0, 1.0); float facm = 1.0 - fac; - vec4 one= vec4(1.0); - vec4 scr= one - (one - col2)*(one - col1); - outcol = facm*col1 + fac*((one - col1)*col2*col1 + col1*scr); + vec4 one = vec4(1.0); + vec4 scr = one - (one - col2) * (one - col1); + outcol = facm * col1 + fac * ((one - col1) * col2 * col1 + col1 * scr); } void mix_linear(float fac, vec4 col1, vec4 col2, out vec4 outcol) { fac = clamp(fac, 0.0, 1.0); - outcol = col1 + fac*(2.0*(col2 - vec4(0.5))); + outcol = col1 + fac * (2.0 * (col2 - vec4(0.5))); } void valtorgb(float fac, sampler2D colormap, out vec4 outcol, out float outalpha) @@ -784,12 +820,12 @@ void valtorgb(float fac, sampler2D colormap, out vec4 outcol, out float outalpha outalpha = outcol.a; } -void rgbtobw(vec4 color, out float outval) +void rgbtobw(vec4 color, out float outval) { #ifdef USE_NEW_SHADING - outval = color.r*0.2126 + color.g*0.7152 + color.b*0.0722; + outval = color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722; #else - outval = color.r*0.35 + color.g*0.45 + color.b*0.2; /* keep these factors in sync with texture.h:RGBTOBW */ + outval = color.r * 0.35 + color.g * 0.45 + color.b * 0.2; /* keep these factors in sync with texture.h:RGBTOBW */ #endif } @@ -816,11 +852,11 @@ void hue_sat(float hue, float sat, float value, float fac, vec4 col, out vec4 ou rgb_to_hsv(col, hsv); hsv[0] += (hue - 0.5); - if (hsv[0]>1.0) hsv[0]-=1.0; else if (hsv[0]<0.0) hsv[0]+= 1.0; + if (hsv[0] > 1.0) hsv[0] -= 1.0; else if (hsv[0] < 0.0) hsv[0] += 1.0; hsv[1] *= sat; - if (hsv[1]>1.0) hsv[1]= 1.0; else if (hsv[1]<0.0) hsv[1]= 0.0; + if (hsv[1] > 1.0) hsv[1] = 1.0; else if (hsv[1] < 0.0) hsv[1] = 0.0; hsv[2] *= value; - if (hsv[2]>1.0) hsv[2]= 1.0; else if (hsv[2]<0.0) hsv[2]= 0.0; + if (hsv[2] > 1.0) hsv[2] = 1.0; else if (hsv[2] < 0.0) hsv[2] = 0.0; hsv_to_rgb(hsv, outcol); @@ -880,19 +916,19 @@ void texture_flip_blend(vec3 vec, out vec3 outvec) void texture_blend_lin(vec3 vec, out float outval) { - outval = (1.0+vec.x)/2.0; + outval = (1.0 + vec.x) / 2.0; } void texture_blend_quad(vec3 vec, out float outval) { - outval = max((1.0+vec.x)/2.0, 0.0); + outval = max((1.0 + vec.x) / 2.0, 0.0); outval *= outval; } void texture_wood_sin(vec3 vec, out float value, out vec4 color, out vec3 normal) { - float a = sqrt(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z)*20.0; - float wi = 0.5 + 0.5*sin(a); + float a = sqrt(vec.x * vec.x + vec.y * vec.y + vec.z * vec.z) * 20.0; + float wi = 0.5 + 0.5 * sin(a); value = wi; color = vec4(wi, wi, wi, 1.0); @@ -901,12 +937,12 @@ void texture_wood_sin(vec3 vec, out float value, out vec4 color, out vec3 normal void texture_image(vec3 vec, sampler2D ima, out float value, out vec4 color, out vec3 normal) { - color = texture2D(ima, (vec.xy + vec2(1.0, 1.0))*0.5); + color = texture2D(ima, (vec.xy + vec2(1.0, 1.0)) * 0.5); value = color.a; - normal.x = 2.0*(color.r - 0.5); - normal.y = 2.0*(0.5 - color.g); - normal.z = 2.0*(color.b - 0.5); + normal.x = 2.0 * (color.r - 0.5); + normal.y = 2.0 * (0.5 - color.g); + normal.z = 2.0 * (color.b - 0.5); } /************* MTEX *****************/ @@ -937,17 +973,17 @@ void texco_tangent(vec4 tangent, out vec3 outtangent) void texco_global(mat4 viewinvmat, vec3 co, out vec3 global) { - global = (viewinvmat*vec4(co, 1.0)).xyz; + global = (viewinvmat * vec4(co, 1.0)).xyz; } void texco_object(mat4 viewinvmat, mat4 obinvmat, vec3 co, out vec3 object) { - object = (obinvmat*(viewinvmat*vec4(co, 1.0))).xyz; + object = (obinvmat * (viewinvmat * vec4(co, 1.0))).xyz; } void texco_refl(vec3 vn, vec3 view, out vec3 ref) { - ref = view - 2.0*dot(vn, view)*vn; + ref = view - 2.0 * dot(vn, view) * vn; } void shade_norm(vec3 normal, out vec3 outnormal) @@ -966,9 +1002,9 @@ void mtex_rgb_blend(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 i float facm; fact *= facg; - facm = 1.0-fact; + facm = 1.0 - fact; - incol = fact*texcol + facm*outcol; + incol = fact * texcol + facm * outcol; } void mtex_rgb_mul(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) @@ -976,9 +1012,9 @@ void mtex_rgb_mul(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 inc float facm; fact *= facg; - facm = 1.0-fact; + facm = 1.0 - fact; - incol = (facm + fact*texcol)*outcol; + incol = (facm + fact * texcol) * outcol; } void mtex_rgb_screen(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) @@ -986,9 +1022,9 @@ void mtex_rgb_screen(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 float facm; fact *= facg; - facm = 1.0-fact; + facm = 1.0 - fact; - incol = vec3(1.0) - (vec3(facm) + fact*(vec3(1.0) - texcol))*(vec3(1.0) - outcol); + incol = vec3(1.0) - (vec3(facm) + fact * (vec3(1.0) - texcol)) * (vec3(1.0) - outcol); } void mtex_rgb_overlay(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) @@ -996,32 +1032,32 @@ void mtex_rgb_overlay(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 float facm; fact *= facg; - facm = 1.0-fact; + facm = 1.0 - fact; if (outcol.r < 0.5) - incol.r = outcol.r*(facm + 2.0*fact*texcol.r); + incol.r = outcol.r * (facm + 2.0 * fact * texcol.r); else - incol.r = 1.0 - (facm + 2.0*fact*(1.0 - texcol.r))*(1.0 - outcol.r); + incol.r = 1.0 - (facm + 2.0 * fact * (1.0 - texcol.r)) * (1.0 - outcol.r); if (outcol.g < 0.5) - incol.g = outcol.g*(facm + 2.0*fact*texcol.g); + incol.g = outcol.g * (facm + 2.0 * fact * texcol.g); else - incol.g = 1.0 - (facm + 2.0*fact*(1.0 - texcol.g))*(1.0 - outcol.g); + incol.g = 1.0 - (facm + 2.0 * fact * (1.0 - texcol.g)) * (1.0 - outcol.g); if (outcol.b < 0.5) - incol.b = outcol.b*(facm + 2.0*fact*texcol.b); + incol.b = outcol.b * (facm + 2.0 * fact * texcol.b); else - incol.b = 1.0 - (facm + 2.0*fact*(1.0 - texcol.b))*(1.0 - outcol.b); + incol.b = 1.0 - (facm + 2.0 * fact * (1.0 - texcol.b)) * (1.0 - outcol.b); } void mtex_rgb_sub(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) { - incol = -fact*facg*texcol + outcol; + incol = -fact * facg * texcol + outcol; } void mtex_rgb_add(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) { - incol = fact*facg*texcol + outcol; + incol = fact * facg * texcol + outcol; } void mtex_rgb_div(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) @@ -1029,11 +1065,11 @@ void mtex_rgb_div(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 inc float facm; fact *= facg; - facm = 1.0-fact; + facm = 1.0 - fact; - if (texcol.r != 0.0) incol.r = facm*outcol.r + fact*outcol.r/texcol.r; - if (texcol.g != 0.0) incol.g = facm*outcol.g + fact*outcol.g/texcol.g; - if (texcol.b != 0.0) incol.b = facm*outcol.b + fact*outcol.b/texcol.b; + if (texcol.r != 0.0) incol.r = facm * outcol.r + fact * outcol.r / texcol.r; + if (texcol.g != 0.0) incol.g = facm * outcol.g + fact * outcol.g / texcol.g; + if (texcol.b != 0.0) incol.b = facm * outcol.b + fact * outcol.b / texcol.b; } void mtex_rgb_diff(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) @@ -1041,9 +1077,9 @@ void mtex_rgb_diff(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 in float facm; fact *= facg; - facm = 1.0-fact; + facm = 1.0 - fact; - incol = facm*outcol + fact*abs(texcol - outcol); + incol = facm * outcol + fact * abs(texcol - outcol); } void mtex_rgb_dark(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) @@ -1051,7 +1087,7 @@ void mtex_rgb_dark(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 in float facm, col; fact *= facg; - facm = 1.0-fact; + facm = 1.0 - fact; incol.r = min(outcol.r, texcol.r) * fact + outcol.r * facm; incol.g = min(outcol.g, texcol.g) * fact + outcol.g * facm; @@ -1064,11 +1100,11 @@ void mtex_rgb_light(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 i fact *= facg; - col = fact*texcol.r; + col = fact * texcol.r; if (col > outcol.r) incol.r = col; else incol.r = outcol.r; - col = fact*texcol.g; + col = fact * texcol.g; if (col > outcol.g) incol.g = col; else incol.g = outcol.g; - col = fact*texcol.b; + col = fact * texcol.b; if (col > outcol.b) incol.b = col; else incol.b = outcol.b; } @@ -1076,7 +1112,7 @@ void mtex_rgb_hue(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 inc { vec4 col; - mix_hue(fact*facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col); + mix_hue(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col); incol.rgb = col.rgb; } @@ -1084,7 +1120,7 @@ void mtex_rgb_sat(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 inc { vec4 col; - mix_sat(fact*facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col); + mix_sat(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col); incol.rgb = col.rgb; } @@ -1092,7 +1128,7 @@ void mtex_rgb_val(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 inc { vec4 col; - mix_val(fact*facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col); + mix_val(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col); incol.rgb = col.rgb; } @@ -1100,7 +1136,7 @@ void mtex_rgb_color(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 i { vec4 col; - mix_color(fact*facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col); + mix_color(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col); incol.rgb = col.rgb; } @@ -1109,11 +1145,11 @@ void mtex_rgb_soft(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 in float facm; fact *= facg; - facm = 1.0-fact; + facm = 1.0 - fact; vec3 one = vec3(1.0); - vec3 scr = one - (one - texcol)*(one - outcol); - incol = facm*outcol + fact*((one - texcol)*outcol*texcol + outcol*scr); + vec3 scr = one - (one - texcol) * (one - outcol); + incol = facm * outcol + fact * ((one - texcol) * outcol * texcol + outcol * scr); } void mtex_rgb_linear(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) @@ -1121,25 +1157,25 @@ void mtex_rgb_linear(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 fact *= facg; if (texcol.r > 0.5) - incol.r = outcol.r + fact*(2.0*(texcol.r - 0.5)); + incol.r = outcol.r + fact * (2.0 * (texcol.r - 0.5)); else - incol.r = outcol.r + fact*(2.0*(texcol.r) - 1.0); + incol.r = outcol.r + fact * (2.0 * (texcol.r) - 1.0); if (texcol.g > 0.5) - incol.g = outcol.g + fact*(2.0*(texcol.g - 0.5)); + incol.g = outcol.g + fact * (2.0 * (texcol.g - 0.5)); else - incol.g = outcol.g + fact*(2.0*(texcol.g) - 1.0); + incol.g = outcol.g + fact * (2.0 * (texcol.g) - 1.0); if (texcol.b > 0.5) - incol.b = outcol.b + fact*(2.0*(texcol.b - 0.5)); + incol.b = outcol.b + fact * (2.0 * (texcol.b - 0.5)); else - incol.b = outcol.b + fact*(2.0*(texcol.b) - 1.0); + incol.b = outcol.b + fact * (2.0 * (texcol.b) - 1.0); } void mtex_value_vars(inout float fact, float facg, out float facm) { fact *= abs(facg); - facm = 1.0-fact; + facm = 1.0 - fact; if (facg < 0.0) { float tmp = fact; @@ -1153,7 +1189,7 @@ void mtex_value_blend(float outcol, float texcol, float fact, float facg, out fl float facm; mtex_value_vars(fact, facg, facm); - incol = fact*texcol + facm*outcol; + incol = fact * texcol + facm * outcol; } void mtex_value_mul(float outcol, float texcol, float fact, float facg, out float incol) @@ -1162,7 +1198,7 @@ void mtex_value_mul(float outcol, float texcol, float fact, float facg, out floa mtex_value_vars(fact, facg, facm); facm = 1.0 - facg; - incol = (facm + fact*texcol)*outcol; + incol = (facm + fact * texcol) * outcol; } void mtex_value_screen(float outcol, float texcol, float fact, float facg, out float incol) @@ -1171,7 +1207,7 @@ void mtex_value_screen(float outcol, float texcol, float fact, float facg, out f mtex_value_vars(fact, facg, facm); facm = 1.0 - facg; - incol = 1.0 - (facm + fact*(1.0 - texcol))*(1.0 - outcol); + incol = 1.0 - (facm + fact * (1.0 - texcol)) * (1.0 - outcol); } void mtex_value_sub(float outcol, float texcol, float fact, float facg, out float incol) @@ -1180,7 +1216,7 @@ void mtex_value_sub(float outcol, float texcol, float fact, float facg, out floa mtex_value_vars(fact, facg, facm); fact = -fact; - incol = fact*texcol + outcol; + incol = fact * texcol + outcol; } void mtex_value_add(float outcol, float texcol, float fact, float facg, out float incol) @@ -1189,7 +1225,7 @@ void mtex_value_add(float outcol, float texcol, float fact, float facg, out floa mtex_value_vars(fact, facg, facm); fact = fact; - incol = fact*texcol + outcol; + incol = fact * texcol + outcol; } void mtex_value_div(float outcol, float texcol, float fact, float facg, out float incol) @@ -1198,7 +1234,7 @@ void mtex_value_div(float outcol, float texcol, float fact, float facg, out floa mtex_value_vars(fact, facg, facm); if (texcol != 0.0) - incol = facm*outcol + fact*outcol/texcol; + incol = facm * outcol + fact * outcol / texcol; else incol = 0.0; } @@ -1208,7 +1244,7 @@ void mtex_value_diff(float outcol, float texcol, float fact, float facg, out flo float facm; mtex_value_vars(fact, facg, facm); - incol = facm*outcol + fact*abs(texcol - outcol); + incol = facm * outcol + fact * abs(texcol - outcol); } void mtex_value_dark(float outcol, float texcol, float fact, float facg, out float incol) @@ -1216,7 +1252,7 @@ void mtex_value_dark(float outcol, float texcol, float fact, float facg, out flo float facm; mtex_value_vars(fact, facg, facm); - incol = facm*outcol + fact*min(outcol, texcol); + incol = facm * outcol + fact * min(outcol, texcol); } void mtex_value_light(float outcol, float texcol, float fact, float facg, out float incol) @@ -1224,7 +1260,7 @@ void mtex_value_light(float outcol, float texcol, float fact, float facg, out fl float facm; mtex_value_vars(fact, facg, facm); - float col = fact*texcol; + float col = fact * texcol; if (col > outcol) incol = col; else incol = outcol; } @@ -1240,7 +1276,7 @@ void mtex_value_clamp(float fac, out float outfac) void mtex_har_divide(float har, out float outhar) { - outhar = har/128.0; + outhar = har / 128.0; } void mtex_har_multiply_clamp(float har, out float outhar) @@ -1285,15 +1321,15 @@ void mtex_rgb_invert(vec4 inrgb, out vec4 outrgb) void mtex_value_stencil(float stencil, float intensity, out float outstencil, out float outintensity) { float fact = intensity; - outintensity = intensity*stencil; - outstencil = stencil*fact; + outintensity = intensity * stencil; + outstencil = stencil * fact; } void mtex_rgb_stencil(float stencil, vec4 rgb, out float outstencil, out vec4 outrgb) { float fact = rgb.a; - outrgb = vec4(rgb.rgb, rgb.a*stencil); - outstencil = stencil*fact; + outrgb = vec4(rgb.rgb, rgb.a * stencil); + outstencil = stencil * fact; } void mtex_mapping_ofs(vec3 texco, vec3 ofs, out vec3 outtexco) @@ -1303,17 +1339,17 @@ void mtex_mapping_ofs(vec3 texco, vec3 ofs, out vec3 outtexco) void mtex_mapping_size(vec3 texco, vec3 size, out vec3 outtexco) { - outtexco = size*texco; + outtexco = size * texco; } void mtex_2d_mapping(vec3 vec, out vec3 outvec) { - outvec = vec3(vec.xy*0.5 + vec2(0.5), vec.z); + outvec = vec3(vec.xy * 0.5 + vec2(0.5), vec.z); } vec3 mtex_2d_mapping(vec3 vec) { - return vec3(vec.xy*0.5 + vec2(0.5), vec.z); + return vec3(vec.xy * 0.5 + vec2(0.5), vec.z); } void mtex_cube_map(vec3 co, samplerCube ima, out float value, out vec4 color) @@ -1347,10 +1383,10 @@ void mtex_normal(vec3 texco, sampler2D ima, out vec3 normal) // the normal used points inward. // Should this ever change this negate must be removed. vec4 color = texture2D(ima, texco.xy); - normal = 2.0*(vec3(-color.r, color.g, color.b) - vec3(-0.5, 0.5, 0.5)); + normal = 2.0 * (vec3(-color.r, color.g, color.b) - vec3(-0.5, 0.5, 0.5)); } -void mtex_bump_normals_init( vec3 vN, out vec3 vNorg, out vec3 vNacc, out float fPrevMagnitude ) +void mtex_bump_normals_init(vec3 vN, out vec3 vNorg, out vec3 vNacc, out float fPrevMagnitude) { vNorg = vN; vNacc = vN; @@ -1376,20 +1412,20 @@ void mtex_bump_init_objspace( { mat3 obj2view = to_mat3(gl_ModelViewMatrix); mat3 view2obj = to_mat3(gl_ModelViewMatrixInverse); - - vec3 vSigmaS = view2obj * dFdx( surf_pos ); - vec3 vSigmaT = view2obj * dFdy( surf_pos ); - vec3 vN = normalize( surf_norm * obj2view ); - vR1 = cross( vSigmaT, vN ); - vR2 = cross( vN, vSigmaS ) ; - fDet = dot ( vSigmaS, vR1 ); - + vec3 vSigmaS = view2obj * dFdx(surf_pos); + vec3 vSigmaT = view2obj * dFdy(surf_pos); + vec3 vN = normalize(surf_norm * obj2view); + + vR1 = cross(vSigmaT, vN); + vR2 = cross(vN, vSigmaS); + fDet = dot(vSigmaS, vR1); + /* pretransform vNacc (in mtex_bump_apply) using the inverse transposed */ vR1 = vR1 * view2obj; vR2 = vR2 * view2obj; vN = vN * view2obj; - + float fMagnitude = abs(fDet) * length(vN); vNacc_out = vNacc_in * (fMagnitude / fPrevMagnitude_in); fPrevMagnitude_out = fMagnitude; @@ -1401,14 +1437,14 @@ void mtex_bump_init_texturespace( out float fPrevMagnitude_out, out vec3 vNacc_out, out vec3 vR1, out vec3 vR2, out float fDet) { - vec3 vSigmaS = dFdx( surf_pos ); - vec3 vSigmaT = dFdy( surf_pos ); + vec3 vSigmaS = dFdx(surf_pos); + vec3 vSigmaT = dFdy(surf_pos); vec3 vN = surf_norm; /* normalized interpolated vertex normal */ - - vR1 = normalize( cross( vSigmaT, vN ) ); - vR2 = normalize( cross( vN, vSigmaS ) ); - fDet = sign( dot(vSigmaS, vR1) ); - + + vR1 = normalize(cross(vSigmaT, vN)); + vR2 = normalize(cross(vN, vSigmaS)); + fDet = sign(dot(vSigmaS, vR1)); + float fMagnitude = abs(fDet); vNacc_out = vNacc_in * (fMagnitude / fPrevMagnitude_in); fPrevMagnitude_out = fMagnitude; @@ -1420,14 +1456,14 @@ void mtex_bump_init_viewspace( out float fPrevMagnitude_out, out vec3 vNacc_out, out vec3 vR1, out vec3 vR2, out float fDet) { - vec3 vSigmaS = dFdx( surf_pos ); - vec3 vSigmaT = dFdy( surf_pos ); + vec3 vSigmaS = dFdx(surf_pos); + vec3 vSigmaT = dFdy(surf_pos); vec3 vN = surf_norm; /* normalized interpolated vertex normal */ - - vR1 = cross( vSigmaT, vN ); - vR2 = cross( vN, vSigmaS ) ; - fDet = dot ( vSigmaS, vR1 ); - + + vR1 = cross(vSigmaT, vN); + vR2 = cross(vN, vSigmaS); + fDet = dot(vSigmaS, vR1); + float fMagnitude = abs(fDet); vNacc_out = vNacc_in * (fMagnitude / fPrevMagnitude_in); fPrevMagnitude_out = fMagnitude; @@ -1438,14 +1474,14 @@ void mtex_bump_tap3( out float dBs, out float dBt) { vec2 STll = texco.xy; - vec2 STlr = texco.xy + dFdx(texco.xy) ; - vec2 STul = texco.xy + dFdy(texco.xy) ; - - float Hll,Hlr,Hul; - rgbtobw( texture2D(ima, STll), Hll ); - rgbtobw( texture2D(ima, STlr), Hlr ); - rgbtobw( texture2D(ima, STul), Hul ); - + vec2 STlr = texco.xy + dFdx(texco.xy); + vec2 STul = texco.xy + dFdy(texco.xy); + + float Hll, Hlr, Hul; + rgbtobw(texture2D(ima, STll), Hll); + rgbtobw(texture2D(ima, STlr), Hlr); + rgbtobw(texture2D(ima, STul), Hul); + dBs = hScale * (Hlr - Hll); dBt = hScale * (Hul - Hll); } @@ -1460,83 +1496,82 @@ void mtex_bump_bicubic( float Hr; float Hd; float Hu; - + vec2 TexDx = dFdx(texco.xy); vec2 TexDy = dFdy(texco.xy); - - vec2 STl = texco.xy - 0.5 * TexDx ; - vec2 STr = texco.xy + 0.5 * TexDx ; - vec2 STd = texco.xy - 0.5 * TexDy ; - vec2 STu = texco.xy + 0.5 * TexDy ; - + + vec2 STl = texco.xy - 0.5 * TexDx; + vec2 STr = texco.xy + 0.5 * TexDx; + vec2 STd = texco.xy - 0.5 * TexDy; + vec2 STu = texco.xy + 0.5 * TexDy; + rgbtobw(texture2D(ima, STl), Hl); rgbtobw(texture2D(ima, STr), Hr); rgbtobw(texture2D(ima, STd), Hd); rgbtobw(texture2D(ima, STu), Hu); - + vec2 dHdxy = vec2(Hr - Hl, Hu - Hd); - float fBlend = clamp(1.0-textureQueryLOD(ima, texco.xy).x, 0.0, 1.0); - if (fBlend!=0.0) - { + float fBlend = clamp(1.0 - textureQueryLOD(ima, texco.xy).x, 0.0, 1.0); + if (fBlend != 0.0) { // the derivative of the bicubic sampling of level 0 ivec2 vDim; vDim = textureSize(ima, 0); // taking the fract part of the texture coordinate is a hardcoded wrap mode. - // this is acceptable as textures use wrap mode exclusively in 3D view elsewhere in blender. + // this is acceptable as textures use wrap mode exclusively in 3D view elsewhere in blender. // this is done so that we can still get a valid texel with uvs outside the 0,1 range // by texelFetch below, as coordinates are clamped when using this function. - vec2 fTexLoc = vDim*fract(texco.xy) - vec2(0.5, 0.5); + vec2 fTexLoc = vDim * fract(texco.xy) - vec2(0.5, 0.5); ivec2 iTexLoc = ivec2(floor(fTexLoc)); - vec2 t = clamp(fTexLoc - iTexLoc, 0.0, 1.0); // sat just to be pedantic + vec2 t = clamp(fTexLoc - iTexLoc, 0.0, 1.0); // sat just to be pedantic /******************************************************************************************* * This block will replace the one below when one channel textures are properly supported. * ******************************************************************************************* - vec4 vSamplesUL = textureGather(ima, (iTexLoc+ivec2(-1,-1) + vec2(0.5,0.5))/vDim ); - vec4 vSamplesUR = textureGather(ima, (iTexLoc+ivec2(1,-1) + vec2(0.5,0.5))/vDim ); - vec4 vSamplesLL = textureGather(ima, (iTexLoc+ivec2(-1,1) + vec2(0.5,0.5))/vDim ); - vec4 vSamplesLR = textureGather(ima, (iTexLoc+ivec2(1,1) + vec2(0.5,0.5))/vDim ); + vec4 vSamplesUL = textureGather(ima, (iTexLoc+ivec2(-1,-1) + vec2(0.5,0.5))/vDim); + vec4 vSamplesUR = textureGather(ima, (iTexLoc+ivec2(1,-1) + vec2(0.5,0.5))/vDim); + vec4 vSamplesLL = textureGather(ima, (iTexLoc+ivec2(-1,1) + vec2(0.5,0.5))/vDim); + vec4 vSamplesLR = textureGather(ima, (iTexLoc+ivec2(1,1) + vec2(0.5,0.5))/vDim); mat4 H = mat4(vSamplesUL.w, vSamplesUL.x, vSamplesLL.w, vSamplesLL.x, - vSamplesUL.z, vSamplesUL.y, vSamplesLL.z, vSamplesLL.y, - vSamplesUR.w, vSamplesUR.x, vSamplesLR.w, vSamplesLR.x, - vSamplesUR.z, vSamplesUR.y, vSamplesLR.z, vSamplesLR.y); -*/ + vSamplesUL.z, vSamplesUL.y, vSamplesLL.z, vSamplesLL.y, + vSamplesUR.w, vSamplesUR.x, vSamplesLR.w, vSamplesLR.x, + vSamplesUR.z, vSamplesUR.y, vSamplesLR.z, vSamplesLR.y); + */ ivec2 iTexLocMod = iTexLoc + ivec2(-1, -1); mat4 H; - + for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { - ivec2 iTexTmp = iTexLocMod + ivec2(i,j); - + ivec2 iTexTmp = iTexLocMod + ivec2(i, j); + // wrap texture coordinates manually for texelFetch to work on uvs oitside the 0,1 range. // this is guaranteed to work since we take the fractional part of the uv above. - iTexTmp.x = (iTexTmp.x < 0)? iTexTmp.x + vDim.x : ((iTexTmp.x >= vDim.x)? iTexTmp.x - vDim.x : iTexTmp.x); - iTexTmp.y = (iTexTmp.y < 0)? iTexTmp.y + vDim.y : ((iTexTmp.y >= vDim.y)? iTexTmp.y - vDim.y : iTexTmp.y); + iTexTmp.x = (iTexTmp.x < 0) ? iTexTmp.x + vDim.x : ((iTexTmp.x >= vDim.x) ? iTexTmp.x - vDim.x : iTexTmp.x); + iTexTmp.y = (iTexTmp.y < 0) ? iTexTmp.y + vDim.y : ((iTexTmp.y >= vDim.y) ? iTexTmp.y - vDim.y : iTexTmp.y); rgbtobw(texelFetch(ima, iTexTmp, 0), H[i][j]); } } - + float x = t.x, y = t.y; float x2 = x * x, x3 = x2 * x, y2 = y * y, y3 = y2 * y; - vec4 X = vec4(-0.5*(x3+x)+x2, 1.5*x3-2.5*x2+1, -1.5*x3+2*x2+0.5*x, 0.5*(x3-x2)); - vec4 Y = vec4(-0.5*(y3+y)+y2, 1.5*y3-2.5*y2+1, -1.5*y3+2*y2+0.5*y, 0.5*(y3-y2)); - vec4 dX = vec4(-1.5*x2+2*x-0.5, 4.5*x2-5*x, -4.5*x2+4*x+0.5, 1.5*x2-x); - vec4 dY = vec4(-1.5*y2+2*y-0.5, 4.5*y2-5*y, -4.5*y2+4*y+0.5, 1.5*y2-y); - + vec4 X = vec4(-0.5 * (x3 + x) + x2, 1.5 * x3 - 2.5 * x2 + 1, -1.5 * x3 + 2 * x2 + 0.5 * x, 0.5 * (x3 - x2)); + vec4 Y = vec4(-0.5 * (y3 + y) + y2, 1.5 * y3 - 2.5 * y2 + 1, -1.5 * y3 + 2 * y2 + 0.5 * y, 0.5 * (y3 - y2)); + vec4 dX = vec4(-1.5 * x2 + 2 * x - 0.5, 4.5 * x2 - 5 * x, -4.5 * x2 + 4 * x + 0.5, 1.5 * x2 - x); + vec4 dY = vec4(-1.5 * y2 + 2 * y - 0.5, 4.5 * y2 - 5 * y, -4.5 * y2 + 4 * y + 0.5, 1.5 * y2 - y); + // complete derivative in normalized coordinates (mul by vDim) vec2 dHdST = vDim * vec2(dot(Y, H * dX), dot(dY, H * X)); // transform derivative to screen-space - vec2 dHdxy_bicubic = vec2( dHdST.x * TexDx.x + dHdST.y * TexDx.y, - dHdST.x * TexDy.x + dHdST.y * TexDy.y ); + vec2 dHdxy_bicubic = vec2(dHdST.x * TexDx.x + dHdST.y * TexDx.y, + dHdST.x * TexDy.x + dHdST.y * TexDy.y); // blend between the two - dHdxy = dHdxy*(1-fBlend) + dHdxy_bicubic*fBlend; + dHdxy = dHdxy * (1 - fBlend) + dHdxy_bicubic * fBlend; } dBs = hScale * dHdxy.x; @@ -1553,18 +1588,18 @@ void mtex_bump_tap5( vec2 TexDy = dFdy(texco.xy); vec2 STc = texco.xy; - vec2 STl = texco.xy - 0.5 * TexDx ; - vec2 STr = texco.xy + 0.5 * TexDx ; - vec2 STd = texco.xy - 0.5 * TexDy ; - vec2 STu = texco.xy + 0.5 * TexDy ; - - float Hc,Hl,Hr,Hd,Hu; - rgbtobw( texture2D(ima, STc), Hc ); - rgbtobw( texture2D(ima, STl), Hl ); - rgbtobw( texture2D(ima, STr), Hr ); - rgbtobw( texture2D(ima, STd), Hd ); - rgbtobw( texture2D(ima, STu), Hu ); - + vec2 STl = texco.xy - 0.5 * TexDx; + vec2 STr = texco.xy + 0.5 * TexDx; + vec2 STd = texco.xy - 0.5 * TexDy; + vec2 STu = texco.xy + 0.5 * TexDy; + + float Hc, Hl, Hr, Hd, Hu; + rgbtobw(texture2D(ima, STc), Hc); + rgbtobw(texture2D(ima, STl), Hl); + rgbtobw(texture2D(ima, STr), Hr); + rgbtobw(texture2D(ima, STd), Hd); + rgbtobw(texture2D(ima, STu), Hu); + dBs = hScale * (Hr - Hl); dBt = hScale * (Hu - Hd); } @@ -1573,27 +1608,27 @@ void mtex_bump_deriv( vec3 texco, sampler2D ima, float ima_x, float ima_y, float hScale, out float dBs, out float dBt) { - float s = 1.0; // negate this if flipped texture coordinate + float s = 1.0; // negate this if flipped texture coordinate vec2 TexDx = dFdx(texco.xy); vec2 TexDy = dFdy(texco.xy); - + // this variant using a derivative map is described here // http://mmikkelsen3d.blogspot.com/2011/07/derivative-maps.html vec2 dim = vec2(ima_x, ima_y); - vec2 dBduv = hScale*dim*(2.0*texture2D(ima, texco.xy).xy-1.0); - - dBs = dBduv.x*TexDx.x + s*dBduv.y*TexDx.y; - dBt = dBduv.x*TexDy.x + s*dBduv.y*TexDy.y; + vec2 dBduv = hScale * dim * (2.0 * texture2D(ima, texco.xy).xy - 1.0); + + dBs = dBduv.x * TexDx.x + s * dBduv.y * TexDx.y; + dBt = dBduv.x * TexDy.x + s * dBduv.y * TexDy.y; } void mtex_bump_apply( float fDet, float dBs, float dBt, vec3 vR1, vec3 vR2, vec3 vNacc_in, out vec3 vNacc_out, out vec3 perturbed_norm) { - vec3 vSurfGrad = sign(fDet) * ( dBs * vR1 + dBt * vR2 ); - + vec3 vSurfGrad = sign(fDet) * (dBs * vR1 + dBt * vR2); + vNacc_out = vNacc_in - vSurfGrad; - perturbed_norm = normalize( vNacc_out ); + perturbed_norm = normalize(vNacc_out); } void mtex_bump_apply_texspace( @@ -1604,12 +1639,12 @@ void mtex_bump_apply_texspace( vec2 TexDx = dFdx(texco.xy); vec2 TexDy = dFdy(texco.xy); - vec3 vSurfGrad = sign(fDet) * ( - dBs / length( vec2(ima_x*TexDx.x, ima_y*TexDx.y) ) * vR1 + - dBt / length( vec2(ima_x*TexDy.x, ima_y*TexDy.y) ) * vR2 ); + vec3 vSurfGrad = sign(fDet) * ( + dBs / length(vec2(ima_x * TexDx.x, ima_y * TexDx.y)) * vR1 + + dBt / length(vec2(ima_x * TexDy.x, ima_y * TexDy.y)) * vR2); vNacc_out = vNacc_in - vSurfGrad; - perturbed_norm = normalize( vNacc_out ); + perturbed_norm = normalize(vNacc_out); } void mtex_negate_texnormal(vec3 normal, out vec3 outnormal) @@ -1621,13 +1656,13 @@ void mtex_nspace_tangent(vec4 tangent, vec3 normal, vec3 texnormal, out vec3 out { vec3 B = tangent.w * cross(normal, tangent.xyz); - outnormal = texnormal.x*tangent.xyz + texnormal.y*B + texnormal.z*normal; + outnormal = texnormal.x * tangent.xyz + texnormal.y * B + texnormal.z * normal; outnormal = normalize(outnormal); } void mtex_nspace_world(mat4 viewmat, vec3 texnormal, out vec3 outnormal) { - outnormal = normalize((viewmat*vec4(texnormal, 0.0)).xyz); + outnormal = normalize((viewmat * vec4(texnormal, 0.0)).xyz); } void mtex_nspace_object(vec3 texnormal, out vec3 outnormal) @@ -1637,7 +1672,7 @@ void mtex_nspace_object(vec3 texnormal, out vec3 outnormal) void mtex_blend_normal(float norfac, vec3 normal, vec3 newnormal, out vec3 outnormal) { - outnormal = (1.0 - norfac)*normal + norfac*newnormal; + outnormal = (1.0 - norfac) * normal + norfac * newnormal; outnormal = normalize(outnormal); } @@ -1660,26 +1695,26 @@ void lamp_visibility_other(vec3 co, vec3 lampco, out vec3 lv, out float dist, ou void lamp_falloff_invlinear(float lampdist, float dist, out float visifac) { - visifac = lampdist/(lampdist + dist); + visifac = lampdist / (lampdist + dist); } void lamp_falloff_invsquare(float lampdist, float dist, out float visifac) { - visifac = lampdist/(lampdist + dist*dist); + visifac = lampdist / (lampdist + dist * dist); } void lamp_falloff_sliders(float lampdist, float ld1, float ld2, float dist, out float visifac) { - float lampdistkw = lampdist*lampdist; + float lampdistkw = lampdist * lampdist; - visifac = lampdist/(lampdist + ld1*dist); - visifac *= lampdistkw/(lampdistkw + ld2*dist*dist); + visifac = lampdist / (lampdist + ld1 * dist); + visifac *= lampdistkw / (lampdistkw + ld2 * dist * dist); } void lamp_falloff_invcoefficients(float coeff_const, float coeff_lin, float coeff_quad, float dist, out float visifac) { vec3 coeff = vec3(coeff_const, coeff_lin, coeff_quad); - vec3 d_coeff = vec3(1.0, dist, dist*dist); + vec3 d_coeff = vec3(1.0, dist, dist * dist); float visifac_r = dot(coeff, d_coeff); if (visifac_r > 0.0) visifac = 1.0 / visifac_r; @@ -1689,25 +1724,25 @@ void lamp_falloff_invcoefficients(float coeff_const, float coeff_lin, float coef void lamp_falloff_curve(float lampdist, sampler2D curvemap, float dist, out float visifac) { - visifac = texture2D(curvemap, vec2(dist/lampdist, 0.0)).x; + visifac = texture2D(curvemap, vec2(dist / lampdist, 0.0)).x; } void lamp_visibility_sphere(float lampdist, float dist, float visifac, out float outvisifac) { - float t= lampdist - dist; + float t = lampdist - dist; - outvisifac= visifac*max(t, 0.0)/lampdist; + outvisifac = visifac * max(t, 0.0) / lampdist; } void lamp_visibility_spot_square(vec3 lampvec, mat4 lampimat, vec2 scale, vec3 lv, out float inpr) { if (dot(lv, lampvec) > 0.0) { - vec3 lvrot = (lampimat*vec4(lv, 0.0)).xyz; + vec3 lvrot = (lampimat * vec4(lv, 0.0)).xyz; /* without clever non-uniform scale, we could do: */ // float x = max(abs(lvrot.x / lvrot.z), abs(lvrot.y / lvrot.z)); float x = max(abs((lvrot.x / scale.x) / lvrot.z), abs((lvrot.y / scale.y) / lvrot.z)); - inpr = 1.0/sqrt(1.0 + x*x); + inpr = 1.0 / sqrt(1.0 + x * x); } else inpr = 0.0; @@ -1742,15 +1777,15 @@ void lamp_visibility_spot(float spotsi, float spotbl, float inpr, float visifac, /* soft area */ if (spotbl != 0.0) - inpr *= smoothstep(0.0, 1.0, t/spotbl); + inpr *= smoothstep(0.0, 1.0, t / spotbl); - outvisifac = visifac*inpr; + outvisifac = visifac * inpr; } } void lamp_visibility_clamp(float visifac, out float outvisifac) { - outvisifac = (visifac < 0.001)? 0.0: visifac; + outvisifac = (visifac < 0.001) ? 0.0 : visifac; } void world_paper_view(vec3 vec, out vec3 outvec) @@ -1790,7 +1825,7 @@ void world_blend(vec3 vec, out float blend) void shade_view(vec3 co, out vec3 view) { /* handle perspective/orthographic */ - view = (gl_ProjectionMatrix[3][3] == 0.0)? normalize(co): vec3(0.0, 0.0, -1.0); + view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(co) : vec3(0.0, 0.0, -1.0); } void shade_tangent_v(vec3 lv, vec3 tang, out vec3 vn) @@ -1813,14 +1848,14 @@ void shade_is_no_diffuse(out float is) void shade_is_hemi(float inp, out float is) { - is = 0.5*inp + 0.5; + is = 0.5 * inp + 0.5; } float area_lamp_energy(mat4 area, vec3 co, vec3 vn) { vec3 vec[4], c[4]; float rad[4], fac; - + vec[0] = normalize(co - area[0].xyz); vec[1] = normalize(co - area[1].xyz); vec[2] = normalize(co - area[2].xyz); @@ -1836,10 +1871,10 @@ float area_lamp_energy(mat4 area, vec3 co, vec3 vn) rad[2] = acos(dot(vec[2], vec[3])); rad[3] = acos(dot(vec[3], vec[0])); - fac= rad[0]*dot(vn, c[0]); - fac+= rad[1]*dot(vn, c[1]); - fac+= rad[2]*dot(vn, c[2]); - fac+= rad[3]*dot(vn, c[3]); + fac = rad[0] * dot(vn, c[0]); + fac += rad[1] * dot(vn, c[1]); + fac += rad[2] * dot(vn, c[2]); + fac += rad[3] * dot(vn, c[3]); return max(fac, 0.0); } @@ -1857,7 +1892,7 @@ void shade_inp_area( else { float intens = area_lamp_energy(area, co, vn); - inp = pow(intens*areasize, k); + inp = pow(intens * areasize, k); } } @@ -1879,8 +1914,8 @@ void shade_diffuse_oren_nayer(float nl, vec3 n, vec3 l, vec3 v, float rough, out float Lit_A = acos(realnl); float View_A = acos(nv); - vec3 Lit_B = normalize(l - realnl*n); - vec3 View_B = normalize(v - nv*n); + vec3 Lit_B = normalize(l - realnl * n); + vec3 View_B = normalize(v - nv * n); float t = max(dot(Lit_B, View_B), 0.0); @@ -1895,11 +1930,11 @@ void shade_diffuse_oren_nayer(float nl, vec3 n, vec3 l, vec3 v, float rough, out b = Lit_A; } - float A = 1.0 - (0.5*((rough*rough)/((rough*rough) + 0.33))); - float B = 0.45*((rough*rough)/((rough*rough) + 0.09)); + float A = 1.0 - (0.5 * ((rough * rough) / ((rough * rough) + 0.33))); + float B = 0.45 * ((rough * rough) / ((rough * rough) + 0.09)); b *= 0.95; - is = nl*(A + (B * t * sin(a) * tan(b))); + is = nl * (A + (B * t * sin(a) * tan(b))); } } @@ -1910,7 +1945,7 @@ void shade_diffuse_toon(vec3 n, vec3 l, vec3 v, float size, float tsmooth, out f if (ang < size) is = 1.0; else if (ang > (size + tsmooth) || tsmooth == 0.0) is = 0.0; - else is = 1.0 - ((ang - size)/tsmooth); + else is = 1.0 - ((ang - size) / tsmooth); } void shade_diffuse_minnaert(float nl, vec3 n, vec3 v, float darkness, out float is) @@ -1922,9 +1957,9 @@ void shade_diffuse_minnaert(float nl, vec3 n, vec3 v, float darkness, out float float nv = max(dot(n, v), 0.0); if (darkness <= 1.0) - is = nl*pow(max(nv*nl, 0.1), darkness - 1.0); + is = nl * pow(max(nv * nl, 0.1), darkness - 1.0); else - is = nl*pow(1.0001 - nv, darkness - 1.0); + is = nl * pow(1.0001 - nv, darkness - 1.0); } } @@ -1933,18 +1968,18 @@ float fresnel_fac(vec3 view, vec3 vn, float grad, float fac) float t1, t2; float ffac; - if (fac==0.0) { + if (fac == 0.0) { ffac = 1.0; } else { - t1= dot(view, vn); - if (t1>0.0) t2= 1.0+t1; - else t2= 1.0-t1; + t1 = dot(view, vn); + if (t1 > 0.0) t2 = 1.0 + t1; + else t2 = 1.0 - t1; - t2= grad + (1.0-grad)*pow(t2, fac); + t2 = grad + (1.0 - grad) * pow(t2, fac); - if (t2<0.0) ffac = 0.0; - else if (t2>1.0) ffac = 1.0; + if (t2 < 0.0) ffac = 0.0; + else if (t2 > 1.0) ffac = 1.0; else ffac = t2; } @@ -1958,18 +1993,18 @@ void shade_diffuse_fresnel(vec3 vn, vec3 lv, vec3 view, float fac_i, float fac, void shade_cubic(float is, out float outis) { - if (is>0.0 && is<1.0) - outis= smoothstep(0.0, 1.0, is); + if (is > 0.0 && is < 1.0) + outis = smoothstep(0.0, 1.0, is); else - outis= is; + outis = is; } void shade_visifac(float i, float visifac, float refl, out float outi) { /*if (i > 0.0)*/ - outi = max(i*visifac*refl, 0.0); + outi = max(i * visifac * refl, 0.0); /*else - outi = i;*/ + outi = i;*/ } void shade_tangent_v_spec(vec3 tang, out vec3 vn) @@ -1980,7 +2015,7 @@ void shade_tangent_v_spec(vec3 tang, out vec3 vn) void shade_add_to_diffuse(float i, vec3 lampcol, vec3 col, out vec3 outcol) { if (i > 0.0) - outcol = i*lampcol*col; + outcol = i * lampcol * col; else outcol = vec3(0.0, 0.0, 0.0); } @@ -1991,9 +2026,9 @@ void shade_hemi_spec(vec3 vn, vec3 lv, vec3 view, float spec, float hard, float lv = normalize(lv); t = dot(vn, lv); - t = 0.5*t + 0.5; + t = 0.5 * t + 0.5; - t = visifac*spec*pow(t, hard); + t = visifac * spec * pow(t, hard); } void shade_phong_spec(vec3 n, vec3 l, vec3 v, float hard, out float specfac) @@ -2016,7 +2051,7 @@ void shade_cooktorr_spec(vec3 n, vec3 l, vec3 v, float hard, out float specfac) float nv = max(dot(n, v), 0.0); float i = pow(nh, hard); - i = i/(0.1+nv); + i = i / (0.1 + nv); specfac = i; } } @@ -2030,10 +2065,10 @@ void shade_blinn_spec(vec3 n, vec3 l, vec3 v, float refrac, float spec_power, ou specfac = 0.0; } else { - if (spec_power<100.0) - spec_power= sqrt(1.0/spec_power); + if (spec_power < 100.0) + spec_power = sqrt(1.0 / spec_power); else - spec_power= 10.0/spec_power; + spec_power = 10.0 / spec_power; vec3 h = normalize(v + l); float nh = dot(n, h); @@ -2050,8 +2085,8 @@ void shade_blinn_spec(vec3 n, vec3 l, vec3 v, float refrac, float spec_power, ou float vh = max(dot(v, h), 0.01); float a = 1.0; - float b = (2.0*nh*nv)/vh; - float c = (2.0*nh*nl)/vh; + float b = (2.0 * nh * nv) / vh; + float c = (2.0 * nh * nl) / vh; float g = 0.0; @@ -2065,7 +2100,7 @@ void shade_blinn_spec(vec3 n, vec3 l, vec3 v, float refrac, float spec_power, ou (((vh * (p - vh)) + 1.0) * ((vh * (p - vh)) + 1.0))))); float ang = acos(nh); - specfac = max(f*g*exp_blender((-(ang*ang)/(2.0*spec_power*spec_power))), 0.0); + specfac = max(f * g * exp_blender((-(ang * ang) / (2.0 * spec_power * spec_power))), 0.0); } } } @@ -2080,7 +2115,7 @@ void shade_wardiso_spec(vec3 n, vec3 l, vec3 v, float rms, out float specfac) float angle = tan(acos(nh)); float alpha = max(rms, 0.001); - specfac= nl * (1.0/(4.0*M_PI*alpha*alpha))*(exp_blender(-(angle*angle)/(alpha*alpha))/(sqrt(nv*nl))); + specfac = nl * (1.0 / (4.0 * M_PI * alpha * alpha)) * (exp_blender(-(angle * angle) / (alpha * alpha)) / (sqrt(nv * nl))); } void shade_toon_spec(vec3 n, vec3 l, vec3 v, float size, float tsmooth, out float specfac) @@ -2091,24 +2126,24 @@ void shade_toon_spec(vec3 n, vec3 l, vec3 v, float size, float tsmooth, out floa if (ang < size) rslt = 1.0; else if (ang >= (size + tsmooth) || tsmooth == 0.0) rslt = 0.0; - else rslt = 1.0 - ((ang - size)/tsmooth); + else rslt = 1.0 - ((ang - size) / tsmooth); specfac = rslt; } void shade_spec_area_inp(float specfac, float inp, out float outspecfac) { - outspecfac = specfac*inp; + outspecfac = specfac * inp; } void shade_spec_t(float shadfac, float spec, float visifac, float specfac, out float t) { - t = shadfac*spec*visifac*specfac; + t = shadfac * spec * visifac * specfac; } void shade_add_spec(float t, vec3 lampcol, vec3 speccol, out vec3 outcol) { - outcol = t*lampcol*speccol; + outcol = t * lampcol * speccol; } void shade_add_mirror(vec3 mir, vec4 refcol, vec3 combined, out vec3 result) @@ -2134,7 +2169,7 @@ void shade_add(vec4 col1, vec4 col2, out vec4 outcol) void shade_madd(vec4 col, vec4 col1, vec4 col2, out vec4 outcol) { - outcol = col + col1*col2; + outcol = col + col1 * col2; } void shade_add_clamped(vec4 col1, vec4 col2, out vec4 outcol) @@ -2144,52 +2179,52 @@ void shade_add_clamped(vec4 col1, vec4 col2, out vec4 outcol) void shade_madd_clamped(vec4 col, vec4 col1, vec4 col2, out vec4 outcol) { - outcol = col + max(col1*col2, vec4(0.0, 0.0, 0.0, 0.0)); + outcol = col + max(col1 * col2, vec4(0.0, 0.0, 0.0, 0.0)); } void shade_maddf(vec4 col, float f, vec4 col1, out vec4 outcol) { - outcol = col + f*col1; + outcol = col + f * col1; } void shade_mul(vec4 col1, vec4 col2, out vec4 outcol) { - outcol = col1*col2; + outcol = col1 * col2; } void shade_mul_value(float fac, vec4 col, out vec4 outcol) { - outcol = col*fac; + outcol = col * fac; } void shade_mul_value_v3(float fac, vec3 col, out vec3 outcol) { - outcol = col*fac; + outcol = col * fac; } void shade_obcolor(vec4 col, vec4 obcol, out vec4 outcol) { - outcol = vec4(col.rgb*obcol.rgb, col.a); + outcol = vec4(col.rgb * obcol.rgb, col.a); } void ramp_rgbtobw(vec3 color, out float outval) { - outval = color.r*0.3 + color.g*0.58 + color.b*0.12; + outval = color.r * 0.3 + color.g * 0.58 + color.b * 0.12; } void shade_only_shadow(float i, float shadfac, float energy, vec3 shadcol, out vec3 outshadrgb) { - outshadrgb = i*energy*(1.0 - shadfac)*(vec3(1.0)-shadcol); + outshadrgb = i * energy * (1.0 - shadfac) * (vec3(1.0) - shadcol); } void shade_only_shadow_diffuse(vec3 shadrgb, vec3 rgb, vec4 diff, out vec4 outdiff) { - outdiff = diff - vec4(rgb*shadrgb, 0.0); + outdiff = diff - vec4(rgb * shadrgb, 0.0); } void shade_only_shadow_specular(vec3 shadrgb, vec3 specrgb, vec4 spec, out vec4 outspec) { - outspec = spec - vec4(specrgb*shadrgb, 0.0); + outspec = spec - vec4(specrgb * shadrgb, 0.0); } void shade_clamp_positive(vec4 col, out vec4 outcol) @@ -2205,12 +2240,12 @@ void test_shadowbuf( result = 0.0; } else { - vec4 co = shadowpersmat*vec4(rco, 1.0); + vec4 co = shadowpersmat * vec4(rco, 1.0); //float bias = (1.5 - inp*inp)*shadowbias; - co.z -= shadowbias*co.w; - - if (co.w > 0.0 && co.x > 0.0 && co.x/co.w < 1.0 && co.y > 0.0 && co.y/co.w < 1.0) + co.z -= shadowbias * co.w; + + if (co.w > 0.0 && co.x > 0.0 && co.x / co.w < 1.0 && co.y > 0.0 && co.y / co.w < 1.0) result = shadow2DProj(shadowmap, co).x; else result = 1.0; @@ -2225,23 +2260,23 @@ void test_shadowbuf_vsm( result = 0.0; } else { - vec4 co = shadowpersmat*vec4(rco, 1.0); - if (co.w > 0.0 && co.x > 0.0 && co.x/co.w < 1.0 && co.y > 0.0 && co.y/co.w < 1.0) { + vec4 co = shadowpersmat * vec4(rco, 1.0); + if (co.w > 0.0 && co.x > 0.0 && co.x / co.w < 1.0 && co.y > 0.0 && co.y / co.w < 1.0) { vec2 moments = texture2DProj(shadowmap, co).rg; - float dist = co.z/co.w; + float dist = co.z / co.w; float p = 0.0; - + if (dist <= moments.x) p = 1.0; - float variance = moments.y - (moments.x*moments.x); - variance = max(variance, shadowbias/10.0); + float variance = moments.y - (moments.x * moments.x); + variance = max(variance, shadowbias / 10.0); float d = moments.x - dist; - float p_max = variance / (variance + d*d); + float p_max = variance / (variance + d * d); // Now reduce light-bleeding by removing the [0, x] tail and linearly rescaling (x, 1] - p_max = clamp((p_max-bleedbias)/(1.0-bleedbias), 0.0, 1.0); + p_max = clamp((p_max - bleedbias) / (1.0 - bleedbias), 0.0, 1.0); result = max(p, p_max); } @@ -2284,14 +2319,14 @@ void shadows_only_vsm( void shade_light_texture(vec3 rco, sampler2D cookie, mat4 shadowpersmat, out vec4 result) { - vec4 co = shadowpersmat*vec4(rco, 1.0); + vec4 co = shadowpersmat * vec4(rco, 1.0); result = texture2DProj(cookie, co); } void shade_exposure_correct(vec3 col, float linfac, float logfac, out vec3 outcol) { - outcol = linfac*(1.0 - exp(col*logfac)); + outcol = linfac * (1.0 - exp(col * logfac)); } void shade_mist_factor( @@ -2301,11 +2336,11 @@ void shade_mist_factor( if (enable == 1.0) { float fac, zcor; - zcor = (gl_ProjectionMatrix[3][3] == 0.0)? length(co): -co[2]; - + zcor = (gl_ProjectionMatrix[3][3] == 0.0) ? length(co) : -co[2]; + fac = clamp((zcor - miststa) / mistdist, 0.0, 1.0); if (misttype == 0.0) fac *= fac; - else if (misttype == 1.0); + else if (misttype == 1.0) ; else fac = sqrt(fac); outfac = 1.0 - (1.0 - fac) * (1.0 - misi); @@ -2328,7 +2363,7 @@ void shade_alpha_opaque(vec4 col, out vec4 outcol) void shade_alpha_obcolor(vec4 col, vec4 obcol, out vec4 outcol) { - outcol = vec4(col.rgb, col.a*obcol.a); + outcol = vec4(col.rgb, col.a * obcol.a); } /*********** NEW SHADER UTILITIES **************/ @@ -2343,9 +2378,9 @@ float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) if (g > 0.0) { g = sqrt(g); - float A =(g - c)/(g + c); - float B =(c *(g + c)- 1.0)/(c *(g - c)+ 1.0); - result = 0.5 * A * A *(1.0 + B * B); + float A = (g - c) / (g + c); + float B = (c * (g + c) - 1.0) / (c * (g - c) + 1.0); + result = 0.5 * A * A * (1.0 + B * B); } else { result = 1.0; /* TIR (no refracted component) */ @@ -2356,7 +2391,7 @@ float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) float hypot(float x, float y) { - return sqrt(x*x + y*y); + return sqrt(x * x + y * y); } void generated_from_orco(vec3 orco, out vec3 generated) @@ -2364,6 +2399,17 @@ void generated_from_orco(vec3 orco, out vec3 generated) generated = orco * 0.5 + vec3(0.5); } +int floor_to_int(float x) +{ + return int(floor(x)); +} + +int quick_floor(float x) +{ + return int(x) - ((x < 0) ? 1 : 0); +} + +#ifdef BIT_OPERATIONS float integer_noise(int n) { int nn; @@ -2373,24 +2419,18 @@ float integer_noise(int n) return 0.5 * (float(nn) / 1073741824.0); } -int floor_to_int(float x) -{ - return int(floor(x)); -} - -#ifdef BIT_OPERATIONS uint hash(uint kx, uint ky, uint kz) { -#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) -#define final(a,b,c) \ +#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k)))) +#define final(a, b, c) \ { \ - c ^= b; c -= rot(b,14); \ - a ^= c; a -= rot(c,11); \ - b ^= a; b -= rot(a,25); \ - c ^= b; c -= rot(b,16); \ - a ^= c; a -= rot(c,4); \ - b ^= a; b -= rot(a,14); \ - c ^= b; c -= rot(b,24); \ + c ^= b; c -= rot(b, 14); \ + a ^= c; a -= rot(c, 11); \ + b ^= a; b -= rot(a, 25); \ + c ^= b; c -= rot(b, 16); \ + a ^= c; a -= rot(c, 4); \ + b ^= a; b -= rot(a, 14); \ + c ^= b; c -= rot(b, 24); \ } // now hash the data! uint a, b, c, len = 3u; @@ -2399,7 +2439,7 @@ uint hash(uint kx, uint ky, uint kz) c += kz; b += ky; a += kx; - final(a, b, c); + final (a, b, c); return c; #undef rot @@ -2419,9 +2459,9 @@ float bits_to_01(uint bits) float cellnoise(vec3 p) { - int ix = floor_to_int(p.x); - int iy = floor_to_int(p.y); - int iz = floor_to_int(p.z); + int ix = quick_floor(p.x); + int iy = quick_floor(p.y); + int iz = quick_floor(p.z); return bits_to_01(hash(uint(ix), uint(iy), uint(iz))); } @@ -2459,10 +2499,10 @@ void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out vec4 result) vec3 light_diffuse = gl_LightSource[i].diffuse.rgb; float bsdf = max(dot(N, light_position), 0.0); - L += light_diffuse*bsdf; + L += light_diffuse * bsdf; } - result = vec4(L*color.rgb, 1.0); + result = vec4(L * color.rgb, 1.0); } void node_bsdf_glossy(vec4 color, float roughness, vec3 N, out vec4 result) @@ -2478,12 +2518,12 @@ void node_bsdf_glossy(vec4 color, float roughness, vec3 N, out vec4 result) vec3 light_specular = gl_LightSource[i].specular.rgb; /* we mix in some diffuse so low roughness still shows up */ - float bsdf = 0.5*pow(max(dot(N, H), 0.0), 1.0/roughness); - bsdf += 0.5*max(dot(N, light_position), 0.0); - L += light_specular*bsdf; + float bsdf = 0.5 * pow(max(dot(N, H), 0.0), 1.0 / roughness); + bsdf += 0.5 * max(dot(N, light_position), 0.0); + L += light_specular * bsdf; } - result = vec4(L*color.rgb, 1.0); + result = vec4(L * color.rgb, 1.0); } void node_bsdf_anisotropic( @@ -2548,7 +2588,7 @@ void node_ambient_occlusion(vec4 color, out vec4 result) void node_emission(vec4 color, float strength, vec3 N, out vec4 result) { - result = color*strength; + result = color * strength; } /* background */ @@ -2564,7 +2604,7 @@ void background_transform_to_world(vec3 viewvec, out vec3 worldvec) void node_background(vec4 color, float strength, vec3 N, out vec4 result) { - result = color*strength; + result = color * strength; } /* closures */ @@ -2584,10 +2624,10 @@ void node_add_shader(vec4 shader1, vec4 shader2, out vec4 shader) void node_fresnel(float ior, vec3 N, vec3 I, out float result) { /* handle perspective/orthographic */ - vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0)? normalize(I): vec3(0.0, 0.0, -1.0); + vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0); float eta = max(ior, 0.00001); - result = fresnel_dielectric(I_view, N, (gl_FrontFacing)? eta: 1.0/eta); + result = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? eta : 1.0 / eta); } /* layer_weight */ @@ -2596,15 +2636,15 @@ void node_layer_weight(float blend, vec3 N, vec3 I, out float fresnel, out float { /* fresnel */ float eta = max(1.0 - blend, 0.00001); - vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0)? normalize(I): vec3(0.0, 0.0, -1.0); + vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0); - fresnel = fresnel_dielectric(I_view, N, (gl_FrontFacing)? 1.0/eta : eta ); + fresnel = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? 1.0 / eta : eta); /* facing */ facing = abs(dot(I_view, N)); if (blend != 0.5) { blend = clamp(blend, 0.0, 0.99999); - blend = (blend < 0.5)? 2.0*blend: 0.5/(1.0 - blend); + blend = (blend < 0.5) ? 2.0 * blend : 0.5 / (1.0 - blend); facing = pow(facing, blend); } facing = 1.0 - facing; @@ -2628,12 +2668,9 @@ void node_gamma(vec4 col, float gamma, out vec4 outcol) void node_attribute(vec3 attr, out vec4 outcol, out vec3 outvec, out float outf) { - /* TODO(sergey): This needs linearization for vertex color. - * But how to detect cases when input is linear and when it's srgb? - */ outcol = vec4(attr, 1.0); outvec = attr; - outf = (attr.x + attr.y + attr.z)/3.0; + outf = (attr.x + attr.y + attr.z) / 3.0; } void node_uvmap(vec3 attr_uv, out vec3 outvec) @@ -2641,48 +2678,51 @@ void node_uvmap(vec3 attr_uv, out vec3 outvec) outvec = attr_uv; } -void node_geometry(vec3 I, vec3 N, mat4 toworld, - out vec3 position, out vec3 normal, out vec3 tangent, - out vec3 true_normal, out vec3 incoming, out vec3 parametric, - out float backfacing, out float pointiness) +void node_geometry( + vec3 I, vec3 N, mat4 toworld, + out vec3 position, out vec3 normal, out vec3 tangent, + out vec3 true_normal, out vec3 incoming, out vec3 parametric, + out float backfacing, out float pointiness) { - position = (toworld*vec4(I, 1.0)).xyz; - normal = (toworld*vec4(N, 0.0)).xyz; + position = (toworld * vec4(I, 1.0)).xyz; + normal = (toworld * vec4(N, 0.0)).xyz; tangent = vec3(0.0); true_normal = normal; /* handle perspective/orthographic */ - vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0)? normalize(I): vec3(0.0, 0.0, -1.0); - incoming = -(toworld*vec4(I_view, 0.0)).xyz; + vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0); + incoming = -(toworld * vec4(I_view, 0.0)).xyz; parametric = vec3(0.0); - backfacing = (gl_FrontFacing)? 0.0: 1.0; + backfacing = (gl_FrontFacing) ? 0.0 : 1.0; pointiness = 0.0; } -void node_tex_coord(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, vec4 camerafac, - vec3 attr_orco, vec3 attr_uv, - out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object, - out vec3 camera, out vec3 window, out vec3 reflection) +void node_tex_coord( + vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, vec4 camerafac, + vec3 attr_orco, vec3 attr_uv, + out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object, + out vec3 camera, out vec3 window, out vec3 reflection) { generated = attr_orco * 0.5 + vec3(0.5); - normal = normalize((obinvmat*(viewinvmat*vec4(N, 0.0))).xyz); + normal = normalize((obinvmat * (viewinvmat * vec4(N, 0.0))).xyz); uv = attr_uv; - object = (obinvmat*(viewinvmat*vec4(I, 1.0))).xyz; + object = (obinvmat * (viewinvmat * vec4(I, 1.0))).xyz; camera = vec3(I.xy, -I.z); vec4 projvec = gl_ProjectionMatrix * vec4(I, 1.0); - window = vec3(mtex_2d_mapping(projvec.xyz/projvec.w).xy * camerafac.xy + camerafac.zw, 0.0); + window = vec3(mtex_2d_mapping(projvec.xyz / projvec.w).xy * camerafac.xy + camerafac.zw, 0.0); vec3 shade_I; shade_view(I, shade_I); vec3 view_reflection = reflect(shade_I, normalize(N)); - reflection = (viewinvmat*vec4(view_reflection, 0.0)).xyz; + reflection = (viewinvmat * vec4(view_reflection, 0.0)).xyz; } -void node_tex_coord_background(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, vec4 camerafac, - vec3 attr_orco, vec3 attr_uv, - out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object, - out vec3 camera, out vec3 window, out vec3 reflection) +void node_tex_coord_background( + vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, vec4 camerafac, + vec3 attr_orco, vec3 attr_uv, + out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object, + out vec3 camera, out vec3 window, out vec3 reflection) { vec4 v = (gl_ProjectionMatrix[3][3] == 0.0) ? vec4(I, 1.0) : vec4(0.0, 0.0, 1.0, 1.0); vec4 co_homogenous = (gl_ProjectionMatrixInverse * v); @@ -2698,9 +2738,9 @@ void node_tex_coord_background(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, v object = coords; camera = vec3(co.xy, -co.z); - window = (gl_ProjectionMatrix[3][3] == 0.0) ? - vec3(mtex_2d_mapping(I).xy * camerafac.xy + camerafac.zw, 0.0) : - vec3(vec2(0.5) * camerafac.xy + camerafac.zw, 0.0); + window = (gl_ProjectionMatrix[3][3] == 0.0) ? + vec3(mtex_2d_mapping(I).xy * camerafac.xy + camerafac.zw, 0.0) : + vec3(vec2(0.5) * camerafac.xy + camerafac.zw, 0.0); reflection = -coords; } @@ -2718,12 +2758,12 @@ float calc_gradient(vec3 p, int gradient_type) } else if (gradient_type == 1) { /* quadratic */ float r = max(x, 0.0); - return r*r; + return r * r; } else if (gradient_type == 2) { /* easing */ float r = min(max(x, 0.0), 1.0); - float t = r*r; - return (3.0*t - 2.0*t*r); + float t = r * r; + return (3.0 * t - 2.0 * t * r); } else if (gradient_type == 3) { /* diagonal */ return (x + y) * 0.5; @@ -2732,9 +2772,9 @@ float calc_gradient(vec3 p, int gradient_type) return atan(y, x) / (M_PI * 2) + 0.5; } else { - float r = max(1.0 - sqrt(x*x + y*y + z*z), 0.0); + float r = max(1.0 - sqrt(x * x + y * y + z * z), 0.0); if (gradient_type == 5) { /* quadratic sphere */ - return r*r; + return r * r; } else if (gradient_type == 6) { /* sphere */ return r; @@ -2757,20 +2797,21 @@ void node_tex_checker(vec3 co, vec4 color1, vec4 color2, float scale, out vec4 c vec3 p = co * scale; /* Prevent precision issues on unit coordinates. */ - p.x = (p.x + 0.000001)*0.999999; - p.y = (p.y + 0.000001)*0.999999; - p.z = (p.z + 0.000001)*0.999999; + p.x = (p.x + 0.000001) * 0.999999; + p.y = (p.y + 0.000001) * 0.999999; + p.z = (p.z + 0.000001) * 0.999999; - int xi = abs(int(floor(p.x))); - int yi = abs(int(floor(p.y))); - int zi = abs(int(floor(p.z))); + int xi = int(abs(floor(p.x))); + int yi = int(abs(floor(p.y))); + int zi = int(abs(floor(p.z))); - bool check = ((xi % 2 == yi % 2) == bool(zi % 2)); + bool check = ((mod(xi, 2) == mod(yi, 2)) == bool(mod(zi, 2))); color = check ? color1 : color2; fac = check ? 1.0 : 0.0; } +#ifdef BIT_OPERATIONS vec2 calc_brick_texture(vec3 p, float mortar_size, float bias, float brick_width, float row_height, float offset_amount, int offset_frequency, @@ -2784,19 +2825,20 @@ vec2 calc_brick_texture(vec3 p, float mortar_size, float bias, if (offset_frequency != 0 && squash_frequency != 0) { brick_width *= (rownum % squash_frequency != 0) ? 1.0 : squash_amount; /* squash */ - offset = (rownum % offset_frequency != 0) ? 0.0 : (brick_width*offset_amount); /* offset */ + offset = (rownum % offset_frequency != 0) ? 0.0 : (brick_width * offset_amount); /* offset */ } - bricknum = floor_to_int((p.x+offset) / brick_width); + bricknum = floor_to_int((p.x + offset) / brick_width); - x = (p.x+offset) - brick_width*bricknum; - y = p.y - row_height*rownum; + x = (p.x + offset) - brick_width * bricknum; + y = p.y - row_height * rownum; return vec2(clamp((integer_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias), 0.0, 1.0), (x < mortar_size || y < mortar_size || x > (brick_width - mortar_size) || y > (row_height - mortar_size)) ? 1.0 : 0.0); } +#endif void node_tex_brick(vec3 co, vec4 color1, vec4 color2, @@ -2807,7 +2849,8 @@ void node_tex_brick(vec3 co, float squash_amount, float squash_frequency, out vec4 color, out float fac) { - vec2 f2 = calc_brick_texture(co*scale, +#ifdef BIT_OPERATIONS + vec2 f2 = calc_brick_texture(co * scale, mortar_size, bias, brick_width, row_height, offset_amount, int(offset_frequency), @@ -2820,6 +2863,10 @@ void node_tex_brick(vec3 co, } color = (f == 1.0) ? mortar : color1; fac = f; +#else + color = vec4(1.0); + fac = 1.0; +#endif } void node_tex_clouds(vec3 co, float size, out vec4 color, out float fac) @@ -2831,8 +2878,8 @@ void node_tex_clouds(vec3 co, float size, out vec4 color, out float fac) void node_tex_environment_equirectangular(vec3 co, sampler2D ima, out vec4 color) { vec3 nco = normalize(co); - float u = -atan(nco.y, nco.x)/(2.0*M_PI) + 0.5; - float v = atan(nco.z, hypot(nco.x, nco.y))/M_PI + 0.5; + float u = -atan(nco.y, nco.x) / (2.0 * M_PI) + 0.5; + float v = atan(nco.z, hypot(nco.x, nco.y)) / M_PI + 0.5; color = texture2D(ima, vec2(u, v)); } @@ -2843,12 +2890,12 @@ void node_tex_environment_mirror_ball(vec3 co, sampler2D ima, out vec4 color) nco.y -= 1.0; - float div = 2.0*sqrt(max(-0.5*nco.y, 0.0)); + float div = 2.0 * sqrt(max(-0.5 * nco.y, 0.0)); if (div > 0.0) nco /= div; - float u = 0.5*(nco.x + 1.0); - float v = 0.5*(nco.z + 1.0); + float u = 0.5 * (nco.x + 1.0); + float v = 0.5 * (nco.z + 1.0); color = texture2D(ima, vec2(u, v)); } @@ -2864,6 +2911,82 @@ void node_tex_image(vec3 co, sampler2D ima, out vec4 color, out float alpha) alpha = color.a; } +void node_tex_image_box(vec3 texco, + vec3 nob, + sampler2D ima, + float blend, + out vec4 color, + out float alpha) +{ + /* project from direction vector to barycentric coordinates in triangles */ + nob = vec3(abs(nob.x), abs(nob.y), abs(nob.z)); + nob /= (nob.x + nob.y + nob.z); + + /* basic idea is to think of this as a triangle, each corner representing + * one of the 3 faces of the cube. in the corners we have single textures, + * in between we blend between two textures, and in the middle we a blend + * between three textures. + * + * the Nxyz values are the barycentric coordinates in an equilateral + * triangle, which in case of blending, in the middle has a smaller + * equilateral triangle where 3 textures blend. this divides things into + * 7 zones, with an if () test for each zone */ + + vec3 weight = vec3(0.0, 0.0, 0.0); + float limit = 0.5 * (1.0 + blend); + + /* first test for corners with single texture */ + if (nob.x > limit * (nob.x + nob.y) && nob.x > limit * (nob.x + nob.z)) { + weight.x = 1.0; + } + else if (nob.y > limit * (nob.x + nob.y) && nob.y > limit * (nob.y + nob.z)) { + weight.y = 1.0; + } + else if (nob.z > limit * (nob.x + nob.z) && nob.z > limit * (nob.y + nob.z)) { + weight.z = 1.0; + } + else if (blend > 0.0) { + /* in case of blending, test for mixes between two textures */ + if (nob.z < (1.0 - limit) * (nob.y + nob.x)) { + weight.x = nob.x / (nob.x + nob.y); + weight.x = clamp((weight.x - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0); + weight.y = 1.0 - weight.x; + } + else if (nob.x < (1.0 - limit) * (nob.y + nob.z)) { + weight.y = nob.y / (nob.y + nob.z); + weight.y = clamp((weight.y - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0); + weight.z = 1.0 - weight.y; + } + else if (nob.y < (1.0 - limit) * (nob.x + nob.z)) { + weight.x = nob.x / (nob.x + nob.z); + weight.x = clamp((weight.x - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0); + weight.z = 1.0 - weight.x; + } + else { + /* last case, we have a mix between three */ + weight.x = ((2.0 - limit) * nob.x + (limit - 1.0)) / (2.0 * limit - 1.0); + weight.y = ((2.0 - limit) * nob.y + (limit - 1.0)) / (2.0 * limit - 1.0); + weight.z = ((2.0 - limit) * nob.z + (limit - 1.0)) / (2.0 * limit - 1.0); + } + } + else { + /* Desperate mode, no valid choice anyway, fallback to one side.*/ + weight.x = 1.0; + } + color = vec4(0); + if (weight.x > 0.0) { + color += weight.x * texture2D(ima, texco.yz); + } + if (weight.y > 0.0) { + color += weight.y * texture2D(ima, texco.xz); + } + if (weight.z > 0.0) { + color += weight.z * texture2D(ima, texco.yx); + } + + alpha = color.a; +} + void node_tex_image_empty(vec3 co, out vec4 color, out float alpha) { color = vec4(0.0); @@ -2873,42 +2996,42 @@ void node_tex_image_empty(vec3 co, out vec4 color, out float alpha) void node_tex_magic(vec3 co, float scale, float distortion, float depth, out vec4 color, out float fac) { vec3 p = co * scale; - float x = sin((p.x + p.y + p.z)*5.0); - float y = cos((-p.x + p.y - p.z)*5.0); - float z = -cos((-p.x - p.y + p.z)*5.0); + float x = sin((p.x + p.y + p.z) * 5.0); + float y = cos((-p.x + p.y - p.z) * 5.0); + float z = -cos((-p.x - p.y + p.z) * 5.0); if (depth > 0) { x *= distortion; y *= distortion; z *= distortion; - y = -cos(x-y+z); + y = -cos(x - y + z); y *= distortion; if (depth > 1) { - x = cos(x-y-z); + x = cos(x - y - z); x *= distortion; if (depth > 2) { - z = sin(-x-y-z); + z = sin(-x - y - z); z *= distortion; if (depth > 3) { - x = -cos(-x+y-z); + x = -cos(-x + y - z); x *= distortion; if (depth > 4) { - y = -sin(-x+y+z); + y = -sin(-x + y + z); y *= distortion; if (depth > 5) { - y = -cos(-x+y+z); + y = -cos(-x + y + z); y *= distortion; if (depth > 6) { - x = cos(x+y+z); + x = cos(x + y + z); x *= distortion; if (depth > 7) { - z = sin(x+y-z); + z = sin(x + y - z); z *= distortion; if (depth > 8) { - x = -cos(-x-y+z); + x = -cos(-x - y + z); x *= distortion; if (depth > 9) { - y = -sin(x-y+z); + y = -sin(x - y + z); y *= distortion; } } @@ -2927,7 +3050,7 @@ void node_tex_magic(vec3 co, float scale, float distortion, float depth, out vec z /= distortion; } - color = vec4(0.5 - x, 0.5 - y, 0.f - z, 1.0); + color = vec4(0.5 - x, 0.5 - y, 0.5 - z, 1.0); fac = (color.x + color.y + color.z) / 3.0; } @@ -2968,14 +3091,14 @@ float noise_perlin(float x, float y, float z) float result; - result = noise_nerp(w, noise_nerp(v, noise_nerp(u, noise_grad(hash(X, Y, Z), fx, fy, fz ), - noise_grad(hash(X+1, Y, Z), fx-1.0, fy, fz)), - noise_nerp(u, noise_grad(hash(X, Y+1, Z), fx, fy - 1.0, fz), - noise_grad(hash(X+1, Y+1, Z), fx-1.0, fy-1.0, fz))), - noise_nerp(v, noise_nerp(u, noise_grad(hash(X, Y, Z+1), fx, fy, fz-1.0), - noise_grad(hash(X+1, Y, Z+1), fx-1.0, fy, fz-1.0)), - noise_nerp(u, noise_grad(hash(X, Y+1, Z+1), fx, fy-1.0, fz-1.0), - noise_grad(hash(X+1, Y+1, Z+1), fx-1.0, fy-1.0, fz-1.0)))); + result = noise_nerp(w, noise_nerp(v, noise_nerp(u, noise_grad(hash(X, Y, Z), fx, fy, fz), + noise_grad(hash(X + 1, Y, Z), fx - 1.0, fy, fz)), + noise_nerp(u, noise_grad(hash(X, Y + 1, Z), fx, fy - 1.0, fz), + noise_grad(hash(X + 1, Y + 1, Z), fx - 1.0, fy - 1.0, fz))), + noise_nerp(v, noise_nerp(u, noise_grad(hash(X, Y, Z + 1), fx, fy, fz - 1.0), + noise_grad(hash(X + 1, Y, Z + 1), fx - 1.0, fy, fz - 1.0)), + noise_nerp(u, noise_grad(hash(X, Y + 1, Z + 1), fx, fy - 1.0, fz - 1.0), + noise_grad(hash(X + 1, Y + 1, Z + 1), fx - 1.0, fy - 1.0, fz - 1.0)))); return noise_scale3(result); } @@ -2998,27 +3121,27 @@ float noise_turbulence(vec3 p, float octaves, int hard) octaves = clamp(octaves, 0.0, 16.0); n = int(octaves); for (i = 0; i <= n; i++) { - float t = noise(fscale*p); + float t = noise(fscale * p); if (hard != 0) { - t = abs(2.0*t - 1.0); + t = abs(2.0 * t - 1.0); } - sum += t*amp; + sum += t * amp; amp *= 0.5; fscale *= 2.0; } float rmd = octaves - floor(octaves); if (rmd != 0.0) { - float t = noise(fscale*p); + float t = noise(fscale * p); if (hard != 0) { - t = abs(2.0*t - 1.0); + t = abs(2.0 * t - 1.0); } - float sum2 = sum + t*amp; - sum *= (float(1 << n) / float((1 << (n+1)) - 1)); - sum2 *= (float(1 << (n+1)) / float((1 << (n+2)) - 1)); - return (1.0 - rmd)*sum + rmd*sum2; + float sum2 = sum + t * amp; + sum *= (float(1 << n) / float((1 << (n + 1)) - 1)); + sum2 *= (float(1 << (n + 1)) / float((1 << (n + 2)) - 1)); + return (1.0 - rmd) * sum + rmd * sum2; } else { - sum *= (float(1 << n) / float((1 << (n+1)) - 1)); + sum *= (float(1 << n) / float((1 << (n + 1)) - 1)); return sum; } } @@ -3224,15 +3347,15 @@ float svm_musgrave(int type, vec3 p) { if (type == 0 /*NODE_MUSGRAVE_MULTIFRACTAL*/) - return intensity*noise_musgrave_multi_fractal(p, dimension, lacunarity, octaves); + return intensity * noise_musgrave_multi_fractal(p, dimension, lacunarity, octaves); else if (type == 1 /*NODE_MUSGRAVE_FBM*/) - return intensity*noise_musgrave_fBm(p, dimension, lacunarity, octaves); + return intensity * noise_musgrave_fBm(p, dimension, lacunarity, octaves); else if (type == 2 /*NODE_MUSGRAVE_HYBRID_MULTIFRACTAL*/) - return intensity*noise_musgrave_hybrid_multi_fractal(p, dimension, lacunarity, octaves, offset, gain); + return intensity * noise_musgrave_hybrid_multi_fractal(p, dimension, lacunarity, octaves, offset, gain); else if (type == 3 /*NODE_MUSGRAVE_RIDGED_MULTIFRACTAL*/) - return intensity*noise_musgrave_ridged_multi_fractal(p, dimension, lacunarity, octaves, offset, gain); + return intensity * noise_musgrave_ridged_multi_fractal(p, dimension, lacunarity, octaves, offset, gain); else if (type == 4 /*NODE_MUSGRAVE_HETERO_TERRAIN*/) - return intensity*noise_musgrave_hetero_terrain(p, dimension, lacunarity, octaves, offset); + return intensity * noise_musgrave_hetero_terrain(p, dimension, lacunarity, octaves, offset); return 0.0; } #endif // #ifdef BIT_OPERATIONS @@ -3256,7 +3379,7 @@ void node_tex_musgrave(vec3 co, offset, 1.0, gain, - co*scale); + co * scale); #else fac = 1.0; #endif @@ -3353,7 +3476,7 @@ float calc_wave(vec3 p, float distortion, float detail, float detail_scale, int n = length(p) * 20.0; if (distortion != 0.0) - n += distortion * noise_turbulence(p*detail_scale, detail, 0); + n += distortion * noise_turbulence(p * detail_scale, detail, 0); if (wave_profile == 0) { /* profile sin */ return 0.5 + 0.5 * sin(n); @@ -3361,7 +3484,7 @@ float calc_wave(vec3 p, float distortion, float detail, float detail_scale, int else { /* profile saw */ n /= 2.0 * M_PI; n -= int(n); - return (n < 0.0)? n + 1.0: n; + return (n < 0.0) ? n + 1.0 : n; } } #endif // BIT_OPERATIONS @@ -3372,7 +3495,7 @@ void node_tex_wave( { #ifdef BIT_OPERATIONS float f; - f = calc_wave(co*scale, distortion, detail, detail_scale, int(wave_type), int(wave_profile)); + f = calc_wave(co * scale, distortion, detail, detail_scale, int(wave_type), int(wave_profile)); color = vec4(f, f, f, 1.0); fac = f; @@ -3451,12 +3574,12 @@ void node_bump(float strength, float dist, float height, vec3 N, vec3 surf_pos, float dHdx = dFdx(height); float dHdy = dFdy(height); - vec3 surfgrad = dHdx*Rx + dHdy*Ry; + vec3 surfgrad = dHdx * Rx + dHdy * Ry; strength = max(strength, 0.0); - result = normalize(absdet*N - dist*sign(det)*surfgrad); - result = normalize(strength*result + (1.0 - strength)*N); + result = normalize(absdet * N - dist * sign(det) * surfgrad); + result = normalize(strength * result + (1.0 - strength) * N); } /* output */ @@ -3479,7 +3602,7 @@ void material_preview_matcap(vec4 color, sampler2D ima, vec4 N, vec4 mask, out v vec2 tex; #ifndef USE_OPENSUBDIV - /* remap to 0.0 - 1.0 range. This is done because OpenGL 2.0 clamps colors + /* remap to 0.0 - 1.0 range. This is done because OpenGL 2.0 clamps colors * between shader stages and we want the full range of the normal */ normal = vec3(2.0, 2.0, 2.0) * vec3(N.x, N.y, N.z) - vec3(1.0, 1.0, 1.0); if (normal.z < 0.0) { diff --git a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl index 5f406c959f1..b485d2cce86 100644 --- a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl @@ -4,13 +4,13 @@ uniform sampler2D textureSource; void main() { vec4 color = vec4(0.0); - color += texture2D( textureSource, gl_TexCoord[0].st + vec2(-3.0 * ScaleU.x, -3.0 * ScaleU.y ) ) * 0.015625; - color += texture2D( textureSource, gl_TexCoord[0].st + vec2(-2.0 * ScaleU.x, -2.0 * ScaleU.y ) ) * 0.09375; - color += texture2D( textureSource, gl_TexCoord[0].st + vec2(-1.0 * ScaleU.x, -1.0 * ScaleU.y ) ) * 0.234375; - color += texture2D( textureSource, gl_TexCoord[0].st + vec2(0.0, 0.0)) * 0.3125; - color += texture2D( textureSource, gl_TexCoord[0].st + vec2(1.0 * ScaleU.x, 1.0 * ScaleU.y ) ) * 0.234375; - color += texture2D( textureSource, gl_TexCoord[0].st + vec2(2.0 * ScaleU.x, 2.0 * ScaleU.y ) ) * 0.09375; - color += texture2D( textureSource, gl_TexCoord[0].st + vec2(3.0 * ScaleU.x, 3.0 * ScaleU.y ) ) * 0.015625; + color += texture2D(textureSource, gl_TexCoord[0].st + vec2(-3.0 * ScaleU.x, -3.0 * ScaleU.y)) * 0.015625; + color += texture2D(textureSource, gl_TexCoord[0].st + vec2(-2.0 * ScaleU.x, -2.0 * ScaleU.y)) * 0.09375; + color += texture2D(textureSource, gl_TexCoord[0].st + vec2(-1.0 * ScaleU.x, -1.0 * ScaleU.y)) * 0.234375; + color += texture2D(textureSource, gl_TexCoord[0].st + vec2(0.0, 0.0)) * 0.3125; + color += texture2D(textureSource, gl_TexCoord[0].st + vec2(1.0 * ScaleU.x, 1.0 * ScaleU.y)) * 0.234375; + color += texture2D(textureSource, gl_TexCoord[0].st + vec2(2.0 * ScaleU.x, 2.0 * ScaleU.y)) * 0.09375; + color += texture2D(textureSource, gl_TexCoord[0].st + vec2(3.0 * ScaleU.x, 3.0 * ScaleU.y)) * 0.015625; gl_FragColor = color; } diff --git a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl index 9bb2e7ad469..5d00108b052 100644 --- a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl @@ -1,6 +1,6 @@ void main() { - gl_Position = ftransform(); - gl_TexCoord[0] = gl_MultiTexCoord0; + gl_Position = ftransform(); + gl_TexCoord[0] = gl_MultiTexCoord0; } diff --git a/source/blender/gpu/shaders/gpu_shader_vertex.glsl b/source/blender/gpu/shaders/gpu_shader_vertex.glsl index 5824d5a80db..9a6537b4f09 100644 --- a/source/blender/gpu/shaders/gpu_shader_vertex.glsl +++ b/source/blender/gpu/shaders/gpu_shader_vertex.glsl @@ -14,6 +14,68 @@ varying vec3 varnormal; varying float gl_ClipDistance[6]; #endif +float srgb_to_linearrgb(float c) +{ + if (c < 0.04045) + return (c < 0.0) ? 0.0 : c * (1.0 / 12.92); + else + return pow((c + 0.055) * (1.0 / 1.055), 2.4); +} + +void srgb_to_linearrgb(vec3 col_from, out vec3 col_to) +{ + col_to.r = srgb_to_linearrgb(col_from.r); + col_to.g = srgb_to_linearrgb(col_from.g); + col_to.b = srgb_to_linearrgb(col_from.b); +} + +void srgb_to_linearrgb(vec4 col_from, out vec4 col_to) +{ + col_to.r = srgb_to_linearrgb(col_from.r); + col_to.g = srgb_to_linearrgb(col_from.g); + col_to.b = srgb_to_linearrgb(col_from.b); + col_to.a = col_from.a; +} + +bool is_srgb(int info) +{ +#ifdef USE_NEW_SHADING + return (info == 1)? true: false; +#else + return false; +#endif +} + +void set_var_from_attr(float attr, int info, out float var) +{ + var = attr; +} + +void set_var_from_attr(vec2 attr, int info, out vec2 var) +{ + var = attr; +} + +void set_var_from_attr(vec3 attr, int info, out vec3 var) +{ + if (is_srgb(info)) { + srgb_to_linearrgb(attr, var); + } + else { + var = attr; + } +} + +void set_var_from_attr(vec4 attr, int info, out vec4 var) +{ + if (is_srgb(info)) { + srgb_to_linearrgb(attr, var); + } + else { + var = attr; + } +} + void main() { #ifndef USE_OPENSUBDIV diff --git a/source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl b/source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl index 4838289ff9e..3761bf350eb 100644 --- a/source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl @@ -15,7 +15,7 @@ void main() // Adjusting moments using partial derivative float dx = dFdx(depth); float dy = dFdy(depth); - moment2 += 0.25*(dx*dx+dy*dy); + moment2 += 0.25 * (dx * dx + dy * dy); gl_FragColor = vec4(moment1, moment2, 0.0, 0.0); } diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h index f4763883489..d89393b9903 100644 --- a/source/blender/imbuf/intern/IMB_anim.h +++ b/source/blender/imbuf/intern/IMB_anim.h @@ -83,18 +83,10 @@ # include <libswscale/swscale.h> #endif -/* actually hard coded endianness */ -#define GET_BIG_LONG(x) (((uchar *) (x))[0] << 24 | ((uchar *) (x))[1] << 16 | ((uchar *) (x))[2] << 8 | ((uchar *) (x))[3]) -#define GET_LITTLE_LONG(x) (((uchar *) (x))[3] << 24 | ((uchar *) (x))[2] << 16 | ((uchar *) (x))[1] << 8 | ((uchar *) (x))[0]) -#define SWAP_L(x) (((x << 24) & 0xff000000) | ((x << 8) & 0xff0000) | ((x >> 8) & 0xff00) | ((x >> 24) & 0xff)) -#define SWAP_S(x) (((x << 8) & 0xff00) | ((x >> 8) & 0xff)) - /* more endianness... should move to a separate file... */ #ifdef __BIG_ENDIAN__ -# define GET_ID GET_BIG_LONG # define LITTLE_LONG SWAP_LONG #else -# define GET_ID GET_LITTLE_LONG # define LITTLE_LONG ENDIAN_NOP #endif diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index 321ff26f68f..5b533d1ec48 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -298,7 +298,7 @@ typedef struct View3D { #define RV3D_VIEW_CAMERA 8 #define RV3D_VIEW_IS_AXIS(view) \ - ((view >= RV3D_VIEW_FRONT) && (view <= RV3D_VIEW_BOTTOM)) + (((view) >= RV3D_VIEW_FRONT) && ((view) <= RV3D_VIEW_BOTTOM)) /* View3d->flag2 (short) */ #define V3D_RENDER_OVERRIDE (1 << 2) diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 09f4ea1cf02..f623416f673 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -955,6 +955,7 @@ bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, struct ListBas char *RNA_path_from_ID_to_struct(PointerRNA *ptr); char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop); +char *RNA_path_from_ID_to_property_index(PointerRNA *ptr, PropertyRNA *prop, int array_dim, int index); char *RNA_path_resolve_from_type_to_property( struct PointerRNA *ptr, struct PropertyRNA *prop, diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 97c71715349..c49a6197a4e 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -4642,7 +4642,47 @@ char *RNA_path_from_ID_to_struct(PointerRNA *ptr) return ptrpath; } -char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop) +static void rna_path_array_multi_from_flat_index( + const int dimsize[RNA_MAX_ARRAY_LENGTH], const int totdims, + const int index_dim, int index, + int r_index_multi[RNA_MAX_ARRAY_LENGTH]) +{ + int dimsize_step[RNA_MAX_ARRAY_LENGTH + 1]; + int i = totdims - 1; + dimsize_step[i + 1] = 1; + dimsize_step[i] = dimsize[i]; + while (--i != -1) { + dimsize_step[i] = dimsize[i] * dimsize_step[i + 1]; + } + while (++i != index_dim) { + int index_round = index / dimsize_step[i + 1]; + r_index_multi[i] = index_round; + index -= (index_round * dimsize_step[i + 1]); + } + BLI_assert(index == 0); +} + +static void rna_path_array_multi_string_from_flat_index( + PointerRNA *ptr, PropertyRNA *prop, int index_dim, int index, + char *index_str, int index_str_len) +{ + int dimsize[RNA_MAX_ARRAY_LENGTH]; + int totdims = RNA_property_array_dimension(ptr, prop, dimsize); + int index_multi[RNA_MAX_ARRAY_LENGTH]; + + rna_path_array_multi_from_flat_index(dimsize, totdims, index_dim, index, index_multi); + + for (int i = 0, offset = 0; (i < index_dim) && (offset < index_str_len); i++) { + offset += BLI_snprintf_rlen(&index_str[offset], index_str_len - offset, "[%d]", index_multi[i]); + } +} + +/** + * \param index_dim: The dimensiuon to show, 0 disables. 1 for 1d array, 2 for 2d. etc. + * \param index: The *flattened* index to use when \a ``index_dim > 0``, + * this is expanded when used with multi-dimensional arrays. + */ +char *RNA_path_from_ID_to_property_index(PointerRNA *ptr, PropertyRNA *prop, int index_dim, int index) { const bool is_rna = (prop->magic == RNA_MAGIC); const char *propname; @@ -4656,25 +4696,36 @@ char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop) propname = RNA_property_identifier(prop); + /* support indexing w/ multi-dimensional arrays */ + char index_str[RNA_MAX_ARRAY_LENGTH * 12 + 1]; + if (index_dim == 0) { + index_str[0] = '\0'; + } + else { + rna_path_array_multi_string_from_flat_index( + ptr, prop, index_dim, index, + index_str, sizeof(index_str)); + } + if (ptrpath) { if (is_rna) { - path = BLI_sprintfN("%s.%s", ptrpath, propname); + path = BLI_sprintfN("%s.%s%s", ptrpath, propname, index_str); } else { char propname_esc[MAX_IDPROP_NAME * 2]; BLI_strescape(propname_esc, propname, sizeof(propname_esc)); - path = BLI_sprintfN("%s[\"%s\"]", ptrpath, propname_esc); + path = BLI_sprintfN("%s[\"%s\"]%s", ptrpath, propname_esc, index_str); } MEM_freeN(ptrpath); } else if (RNA_struct_is_ID(ptr->type)) { if (is_rna) { - path = BLI_strdup(propname); + path = BLI_sprintfN("%s%s", propname, index_str); } else { char propname_esc[MAX_IDPROP_NAME * 2]; BLI_strescape(propname_esc, propname, sizeof(propname_esc)); - path = BLI_sprintfN("[\"%s\"]", propname_esc); + path = BLI_sprintfN("[\"%s\"]%s", propname_esc, index_str); } } else { @@ -4684,6 +4735,11 @@ char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop) return path; } +char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop) +{ + return RNA_path_from_ID_to_property_index(ptr, prop, 0, -1); +} + /** * \return the path to given ptr/prop from the closest ancestor of given type, if any (else return NULL). */ diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c index dcb4d65f3f9..678b0ac8f1f 100644 --- a/source/blender/makesrna/intern/rna_camera.c +++ b/source/blender/makesrna/intern/rna_camera.c @@ -131,8 +131,8 @@ static void rna_def_camera_stereo_data(BlenderRNA *brna) RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); prop = RNA_def_property(srna, "interocular_distance", PROP_FLOAT, PROP_DISTANCE); - RNA_def_property_range(prop, 0.0f, 100.0f); - RNA_def_property_ui_range(prop, 0.0f, 1.f, 1, 3); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.0f, 1e4f, 1, 3); RNA_def_property_ui_text(prop, "Interocular Distance", "Set the distance between the eyes - the stereo plane distance / 30 should be fine"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c index d28dd8f7607..cb7a40a9238 100644 --- a/source/blender/makesrna/intern/rna_curve.c +++ b/source/blender/makesrna/intern/rna_curve.c @@ -1009,13 +1009,15 @@ static void rna_def_font(BlenderRNA *UNUSED(brna), StructRNA *srna) prop = RNA_def_property(srna, "offset_x", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "xof"); - RNA_def_property_range(prop, -50.0f, 50.0f); + RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); + RNA_def_property_ui_range(prop, -50.0f, 50.0f, 10, 3); RNA_def_property_ui_text(prop, "X Offset", "Horizontal offset from the object origin"); RNA_def_property_update(prop, 0, "rna_Curve_update_data"); prop = RNA_def_property(srna, "offset_y", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "yof"); - RNA_def_property_range(prop, -50.0f, 50.0f); + RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); + RNA_def_property_ui_range(prop, -50.0f, 50.0f, 10, 3); RNA_def_property_ui_text(prop, "Y Offset", "Vertical offset from the object origin"); RNA_def_property_update(prop, 0, "rna_Curve_update_data"); @@ -1117,25 +1119,29 @@ static void rna_def_textbox(BlenderRNA *brna) /* number values */ prop = RNA_def_property(srna, "x", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "x"); - RNA_def_property_range(prop, -50.0f, 50.0f); + RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); + RNA_def_property_ui_range(prop, -50.0f, 50.0f, 10, 3); RNA_def_property_ui_text(prop, "Textbox X Offset", ""); RNA_def_property_update(prop, 0, "rna_Curve_update_data"); prop = RNA_def_property(srna, "y", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "y"); - RNA_def_property_range(prop, -50.0f, 50.0f); + RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); + RNA_def_property_ui_range(prop, -50.0f, 50.0f, 10, 3); RNA_def_property_ui_text(prop, "Textbox Y Offset", ""); RNA_def_property_update(prop, 0, "rna_Curve_update_data"); prop = RNA_def_property(srna, "width", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "w"); - RNA_def_property_range(prop, 0.0f, 50.0f); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.0f, 50.0f, 10, 3); RNA_def_property_ui_text(prop, "Textbox Width", ""); RNA_def_property_update(prop, 0, "rna_Curve_update_data"); prop = RNA_def_property(srna, "height", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "h"); - RNA_def_property_range(prop, 0.0f, 50.0f); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.0f, 50.0f, 10, 3); RNA_def_property_ui_text(prop, "Textbox Height", ""); RNA_def_property_update(prop, 0, "rna_Curve_update_data"); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index bd14f206665..dffdd7fe6c7 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -802,6 +802,7 @@ static bNodeLink *rna_NodeTree_link_new(bNodeTree *ntree, ReportList *reports, ntreeUpdateTree(G.main, ntree); + ED_node_tag_update_nodetree(G.main, ntree, ret->tonode); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } return ret; diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 26cfc396cca..84360ba4386 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -649,7 +649,7 @@ void RNA_api_object(StructRNA *srna) #endif /* NDEBUG */ func = RNA_def_function(srna, "update_from_editmode", "rna_Object_update_from_editmode"); - RNA_def_function_ui_description(func, "Load the objects edit-mode data intp the object data"); + RNA_def_function_ui_description(func, "Load the objects edit-mode data into the object data"); parm = RNA_def_boolean(func, "result", 0, "", "Success"); RNA_def_function_return(func, parm); diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index 74fb4a08eda..e1216e3c85f 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -196,6 +196,7 @@ static void rna_Scene_collada_export( int use_ngons, int use_object_instantiation, + int use_blender_profile, int sort_by_name, int export_transformation_type, int open_sim) @@ -203,7 +204,7 @@ static void rna_Scene_collada_export( collada_export(scene, filepath, apply_modifiers, export_mesh_type, selected, include_children, include_armatures, include_shapekeys, deform_bones_only, active_uv_only, include_uv_textures, include_material_textures, - use_texture_copies, use_ngons, use_object_instantiation, sort_by_name, export_transformation_type, open_sim); + use_texture_copies, use_ngons, use_object_instantiation, use_blender_profile, sort_by_name, export_transformation_type, open_sim); } #endif @@ -286,6 +287,7 @@ void RNA_api_scene(StructRNA *srna) parm = RNA_def_boolean(func, "use_ngons", 1, "Use NGons", "Keep NGons in Export"); parm = RNA_def_boolean(func, "use_object_instantiation", 1, "Use Object Instances", "Instantiate multiple Objects from same Data"); + parm = RNA_def_boolean(func, "use_blender_profile", 1, "Use Blender Profile", "Export additional Blender specific information (for material, shaders, bones, etc.)"); parm = RNA_def_boolean(func, "sort_by_name", 0, "Sort by Object name", "Sort exported data by Object name"); parm = RNA_def_boolean(func, "open_sim", 0, "Export for SL/OpenSim", "Compatibility mode for SL, OpenSim and similar online worlds"); diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 68d4f7f7e51..c3a66058888 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -2327,6 +2327,7 @@ static void rna_def_text(StructRNA *srna) prop = RNA_def_property(srna, "font_size", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "text_size"); RNA_def_property_ui_text(prop, "Size", "Size of the text"); + RNA_def_property_range(prop, 0.0, 2000); RNA_def_property_ui_range(prop, 0.0f, 1000, 1, -1); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update"); diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c index 41ebd865720..df94975e274 100644 --- a/source/blender/modifiers/intern/MOD_screw.c +++ b/source/blender/modifiers/intern/MOD_screw.c @@ -73,7 +73,7 @@ typedef struct ScrewVertIter { #define SV_UNUSED (UINT_MAX) #define SV_INVALID ((UINT_MAX) - 1) -#define SV_IS_VALID(v) (v < SV_INVALID) +#define SV_IS_VALID(v) ((v) < SV_INVALID) static void screwvert_iter_init(ScrewVertIter *iter, ScrewVertConnect *array, unsigned int v_init, unsigned int dir) { diff --git a/source/blender/nodes/shader/nodes/node_shader_camera.c b/source/blender/nodes/shader/nodes/node_shader_camera.c index 49ebb15d7a4..3bdb5c36d69 100644 --- a/source/blender/nodes/shader/nodes/node_shader_camera.c +++ b/source/blender/nodes/shader/nodes/node_shader_camera.c @@ -54,7 +54,15 @@ static void node_shader_exec_camera(void *data, int UNUSED(thread), bNode *UNUSE static int gpu_shader_camera(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { - return GPU_stack_link(mat, "camera", in, out, GPU_builtin(GPU_VIEW_POSITION)); + GPUNodeLink *viewvec; + + viewvec = GPU_builtin(GPU_VIEW_POSITION); + + /* Blender has negative Z, Cycles positive Z convention */ + if (GPU_material_use_new_shading_nodes(mat)) + GPU_link(mat, "invert_z", viewvec, &viewvec); + + return GPU_stack_link(mat, "camera", in, out, viewvec); } void register_node_type_sh_camera(void) diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.c b/source/blender/nodes/shader/nodes/node_shader_normal_map.c index d2695609a88..85e2c77662d 100644 --- a/source/blender/nodes/shader/nodes/node_shader_normal_map.c +++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.c @@ -133,29 +133,33 @@ static int gpu_shader_normal_map(GPUMaterial *mat, bNode *node, bNodeExecData *U /* **************** CYCLES ******************** */ - GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm); - switch (nm->space) { case SHD_NORMAL_MAP_TANGENT: GPU_link(mat, "color_to_normal_new_shading", realnorm, &realnorm); GPU_link(mat, "node_normal_map", GPU_attribute(CD_TANGENT, nm->uv_map), negnorm, realnorm, &realnorm); - break; + GPU_link(mat, "vec_math_mix", strength, realnorm, GPU_builtin(GPU_VIEW_NORMAL), &out[0].link); + /* for uniform scale this is sufficient to match Cycles */ + GPU_link(mat, "direction_transform_m4v3", out[0].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[0].link); + GPU_link(mat, "vect_normalize", out[0].link, &out[0].link); + return true; case SHD_NORMAL_MAP_OBJECT: + GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm); GPU_link(mat, "color_to_normal_new_shading", realnorm, &realnorm); GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_OBJECT_MATRIX), &realnorm); break; case SHD_NORMAL_MAP_BLENDER_OBJECT: + GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm); GPU_link(mat, "color_to_blender_normal_new_shading", realnorm, &realnorm); GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_OBJECT_MATRIX), &realnorm); break; case SHD_NORMAL_MAP_WORLD: + GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm); GPU_link(mat, "color_to_normal_new_shading", realnorm, &realnorm); break; case SHD_NORMAL_MAP_BLENDER_WORLD: + GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm); GPU_link(mat, "color_to_blender_normal_new_shading", realnorm, &realnorm); break; - - GPU_link(mat, "vect_normalize", realnorm, &realnorm); } } else { diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.c b/source/blender/nodes/shader/nodes/node_shader_tex_image.c index f0a8cda045e..71200dfe9d3 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c @@ -59,17 +59,49 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, bNode *node, bNodeExecDat Image *ima = (Image *)node->id; ImageUser *iuser = NULL; NodeTexImage *tex = node->storage; + + GPUNodeLink *norm; + int isdata = tex->color_space == SHD_COLORSPACE_NONE; + float blend = tex->projection_blend; if (!ima) return GPU_stack_link(mat, "node_tex_image_empty", in, out); - + if (!in[0].link) in[0].link = GPU_attribute(CD_MTFACE, ""); node_shader_gpu_tex_mapping(mat, node, in, out); - GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata)); + switch (tex->projection) { + case SHD_PROJ_FLAT: + GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata)); + break; + case SHD_PROJ_BOX: + GPU_link(mat, "direction_transform_m4v3", GPU_builtin(GPU_VIEW_NORMAL), + GPU_builtin(GPU_INVERSE_VIEW_MATRIX), + &norm); + GPU_link(mat, "direction_transform_m4v3", norm, + GPU_builtin(GPU_INVERSE_OBJECT_MATRIX), + &norm); + GPU_link(mat, "node_tex_image_box", in[0].link, + norm, + GPU_image(ima, iuser, isdata), + GPU_uniform(&blend), + &out[0].link, + &out[1].link); + break; + case SHD_PROJ_SPHERE: + GPU_link(mat, "point_texco_remap_square", in[0].link, &in[0].link); + GPU_link(mat, "point_map_to_sphere", in[0].link, &in[0].link); + GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata)); + break; + case SHD_PROJ_TUBE: + GPU_link(mat, "point_texco_remap_square", in[0].link, &in[0].link); + GPU_link(mat, "point_map_to_tube", in[0].link, &in[0].link); + GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata)); + break; + } ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL); if ((tex->color_space == SHD_COLORSPACE_COLOR) && diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 33ac58dadb1..49b806347d6 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -973,7 +973,9 @@ static PyObject *pyrna_prop_str(BPy_PropertyRNA *self) RNA_property_identifier(self->prop)); } -static PyObject *pyrna_prop_repr(BPy_PropertyRNA *self) +static PyObject *pyrna_prop_repr_ex( + BPy_PropertyRNA *self, + const int index_dim, const int index) { ID *id = self->ptr.id.data; PyObject *tmp_str; @@ -987,7 +989,8 @@ static PyObject *pyrna_prop_repr(BPy_PropertyRNA *self) tmp_str = PyUnicode_FromString(id->name + 2); - path = RNA_path_from_ID_to_property(&self->ptr, self->prop); + path = RNA_path_from_ID_to_property_index(&self->ptr, self->prop, index_dim, index); + if (path) { const char *data_delim = (path[0] == '[') ? "" : "."; if (GS(id->name) == ID_NT) { /* nodetree paths are not accurate */ @@ -1015,6 +1018,15 @@ static PyObject *pyrna_prop_repr(BPy_PropertyRNA *self) return ret; } +static PyObject *pyrna_prop_repr(BPy_PropertyRNA *self) +{ + return pyrna_prop_repr_ex(self, 0, -1); +} + +static PyObject *pyrna_prop_array_repr(BPy_PropertyArrayRNA *self) +{ + return pyrna_prop_repr_ex((BPy_PropertyRNA *)self, self->arraydim, self->arrayoffset); +} static PyObject *pyrna_func_repr(BPy_FunctionRNA *self) { @@ -5841,7 +5853,7 @@ PyTypeObject pyrna_prop_array_Type = { NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ NULL, /* tp_compare */ /* DEPRECATED in python 3.0! */ - NULL, /* subclassed */ /* tp_repr */ + (reprfunc)pyrna_prop_array_repr, /* tp_repr */ /* Method suites for standard classes */ diff --git a/source/blender/python/mathutils/mathutils_Matrix.h b/source/blender/python/mathutils/mathutils_Matrix.h index 9ae5a4bd61d..542a0e349c7 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.h +++ b/source/blender/python/mathutils/mathutils_Matrix.h @@ -41,7 +41,7 @@ extern PyTypeObject matrix_access_Type; # define MATRIX_ITEM_ASSERT(_mat, _row, _col) (void)0 #endif -#define MATRIX_ITEM_INDEX_NUMROW(_totrow, _row, _col) ((_totrow * (_col)) + (_row)) +#define MATRIX_ITEM_INDEX_NUMROW(_totrow, _row, _col) (((_totrow) * (_col)) + (_row)) #define MATRIX_ITEM_INDEX(_mat, _row, _col) (MATRIX_ITEM_ASSERT(_mat, _row, _col),(((_mat)->num_row * (_col)) + (_row))) #define MATRIX_ITEM_PTR( _mat, _row, _col) ((_mat)->matrix + MATRIX_ITEM_INDEX(_mat, _row, _col)) #define MATRIX_ITEM( _mat, _row, _col) ((_mat)->matrix [MATRIX_ITEM_INDEX(_mat, _row, _col)]) diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index db2547e4fbe..388837af67a 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -220,6 +220,7 @@ void WM_event_timer_sleep(struct wmWindowManager *wm, struct wmWindow *wi /* invoke callback, uses enum property named "type" */ void WM_operator_view3d_unit_defaults(struct bContext *C, struct wmOperator *op); int WM_operator_smooth_viewtx_get(const struct wmOperator *op); +int WM_menu_invoke_ex(struct bContext *C, struct wmOperator *op, int opcontext); int WM_menu_invoke (struct bContext *C, struct wmOperator *op, const struct wmEvent *event); int WM_enum_search_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event); /* invoke callback, confirm menu + exec */ diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 6ef8965a408..b4295bb2607 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -1068,7 +1068,7 @@ int WM_operator_smooth_viewtx_get(const wmOperator *op) } /* invoke callback, uses enum property named "type" */ -int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +int WM_menu_invoke_ex(bContext *C, wmOperator *op, int opcontext) { PropertyRNA *prop = op->type->prop; uiPopupMenu *pup; @@ -1090,8 +1090,8 @@ int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) pup = UI_popup_menu_begin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE); layout = UI_popup_menu_layout(pup); /* set this so the default execution context is the same as submenus */ - uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_REGION_WIN); - uiItemsFullEnumO(layout, op->type->idname, RNA_property_identifier(prop), op->ptr->data, WM_OP_EXEC_REGION_WIN, 0); + uiLayoutSetOperatorContext(layout, opcontext); + uiItemsFullEnumO(layout, op->type->idname, RNA_property_identifier(prop), op->ptr->data, opcontext, 0); UI_popup_menu_end(C, pup); return OPERATOR_INTERFACE; } @@ -1099,6 +1099,11 @@ int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) return OPERATOR_CANCELLED; } +int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + return WM_menu_invoke_ex(C, op, WM_OP_INVOKE_REGION_WIN); +} + /* generic enum search invoke popup */ static uiBlock *wm_enum_search_menu(bContext *C, ARegion *ar, void *arg_op) diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index 449612bc5fd..e2b95da29a1 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -343,37 +343,38 @@ enum { /* *********** wmEvent.type helpers. ********** */ /* test whether the event is timer event */ -#define ISTIMER(event_type) (event_type >= TIMER && event_type <= TIMERF) +#define ISTIMER(event_type) ((event_type) >= TIMER && (event_type) <= TIMERF) /* for event checks */ /* only used for KM_TEXTINPUT, so assume that we want all user-inputtable ascii codes included */ /* UNUSED - see wm_eventmatch - BUG [#30479] */ -/* #define ISTEXTINPUT(event_type) (event_type >= ' ' && event_type <= 255) */ +/* #define ISTEXTINPUT(event_type) ((event_type) >= ' ' && (event_type) <= 255) */ /* note, an alternative could be to check 'event->utf8_buf' */ /* test whether the event is a key on the keyboard */ #define ISKEYBOARD(event_type) \ - ((event_type >= 0x0020 && event_type <= 0x00ff) || \ - (event_type >= 0x012c && event_type <= 0x013f)) + (((event_type) >= 0x0020 && (event_type) <= 0x00ff) || \ + ((event_type) >= 0x012c && (event_type) <= 0x013f)) /* test whether the event is a modifier key */ -#define ISKEYMODIFIER(event_type) ((event_type >= LEFTCTRLKEY && event_type <= LEFTSHIFTKEY) || event_type == OSKEY) +#define ISKEYMODIFIER(event_type) \ + (((event_type) >= LEFTCTRLKEY && (event_type) <= LEFTSHIFTKEY) || (event_type) == OSKEY) /* test whether the event is a mouse button */ -#define ISMOUSE(event_type) (event_type >= LEFTMOUSE && event_type <= BUTTON7MOUSE) +#define ISMOUSE(event_type) ((event_type) >= LEFTMOUSE && (event_type) <= BUTTON7MOUSE) /* test whether the event is tweak event */ -#define ISTWEAK(event_type) (event_type >= EVT_TWEAK_L && event_type <= EVT_GESTURE) +#define ISTWEAK(event_type) ((event_type) >= EVT_TWEAK_L && (event_type) <= EVT_GESTURE) /* test whether the event is a NDOF event */ -#define ISNDOF(event_type) (event_type >= NDOF_MOTION && event_type < NDOF_LAST) +#define ISNDOF(event_type) ((event_type) >= NDOF_MOTION && (event_type) < NDOF_LAST) /* test whether event type is acceptable as hotkey, excluding modifiers */ #define ISHOTKEY(event_type) \ ((ISKEYBOARD(event_type) || ISMOUSE(event_type) || ISNDOF(event_type)) && \ - (event_type != ESCKEY) && \ - (event_type >= LEFTCTRLKEY && event_type <= LEFTSHIFTKEY) == false && \ - (event_type >= UNKNOWNKEY && event_type <= GRLESSKEY) == false) + ((event_type) != ESCKEY) && \ + ((event_type) >= LEFTCTRLKEY && (event_type) <= LEFTSHIFTKEY) == false && \ + ((event_type) >= UNKNOWNKEY && (event_type) <= GRLESSKEY) == false) /* internal helpers*/ #define _VA_IS_EVENT_MOD2(v, a) (CHECK_TYPE_INLINE(v, wmEvent *), \ diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index eb0289e6909..6762e6752b0 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -707,6 +707,7 @@ int collada_export(struct Scene *sce, int triangulate, int use_object_instantiation, + int use_blender_profile, int sort_by_name, BC_export_transformation_type export_transformation_type, int open_sim) RET_ZERO diff --git a/tests/gtests/blenlib/BLI_array_store_test.cc b/tests/gtests/blenlib/BLI_array_store_test.cc new file mode 100644 index 00000000000..33fb454ec2f --- /dev/null +++ b/tests/gtests/blenlib/BLI_array_store_test.cc @@ -0,0 +1,815 @@ +/* Apache License, Version 2.0 */ + +#include "testing/testing.h" + +extern "C" { +#include "BLI_array_store.h" + +#include "MEM_guardedalloc.h" +#include "BLI_sys_types.h" +#include "BLI_utildefines.h" +#include "BLI_listbase.h" +#include "BLI_array_utils.h" +#include "BLI_string.h" +#include "BLI_rand.h" +#include "BLI_ressource_strings.h" +} + +/* print memory savings */ +// #define DEBUG_PRINT + + +/* -------------------------------------------------------------------- */ +/* Helper functions */ + +#ifdef DEBUG_PRINT +static void print_mem_saved(const char *id, const BArrayStore *bs) +{ + const double size_real = BLI_array_store_calc_size_compacted_get(bs); + const double size_expand = BLI_array_store_calc_size_expanded_get(bs); + const double percent = size_expand ? ((size_real / size_expand) * 100.0) : -1.0; + printf("%s: %.8f%%\n", id, percent); +} +#endif + + +/* -------------------------------------------------------------------- */ +/* Test Chunks (building data from list of chunks) */ + +typedef struct TestChunnk { + struct TestChunnk *next, *prev; + const void *data; + size_t data_len; +} TestChunnk; + +static TestChunnk *testchunk_list_add(ListBase *lb, const void *data, size_t data_len) +{ + TestChunnk *tc = (TestChunnk *)MEM_mallocN(sizeof(*tc), __func__); + tc->data = data; + tc->data_len = data_len; + BLI_addtail(lb, tc); + + return tc; +} + +#if 0 +static TestChunnk *testchunk_list_add_copydata(ListBase *lb, const void *data, size_t data_len) +{ + void *data_copy = MEM_mallocN(data_len, __func__); + memcpy(data_copy, data, data_len); + return testchunk_list_add(lb, data_copy, data_len); +} +#endif + +static void testchunk_list_free(ListBase *lb) +{ + for (TestChunnk *tc = (TestChunnk *)lb->first, *tb_next; tc; tc = tb_next) { + tb_next = tc->next; + MEM_freeN((void *)tc->data); + MEM_freeN(tc); + } + BLI_listbase_clear(lb); +} + +#if 0 +static char *testchunk_as_data( + ListBase *lb, + size_t *r_data_len) +{ + size_t data_len = 0; + for (TestChunnk *tc = (TestChunnk *)lb->first; tc; tc = tc->next) { + data_len += tc->data_len; + } + char *data = (char *)MEM_mallocN(data_len, __func__); + size_t i = 0; + for (TestChunnk *tc = (TestChunnk *)lb->first; tc; tc = tc->next) { + memcpy(&data[i], tc->data, tc->data_len); + data_len += tc->data_len; + i += tc->data_len; + } + if (r_data_len) { + *r_data_len = i; + } + return data; +} +#endif + +static char *testchunk_as_data_array( + TestChunnk **tc_array, int tc_array_len, + size_t *r_data_len) +{ + size_t data_len = 0; + for (int tc_index = 0; tc_index < tc_array_len; tc_index++) { + data_len += tc_array[tc_index]->data_len; + } + char *data = (char *)MEM_mallocN(data_len, __func__); + size_t i = 0; + for (int tc_index = 0; tc_index < tc_array_len; tc_index++) { + TestChunnk *tc = tc_array[tc_index]; + memcpy(&data[i], tc->data, tc->data_len); + i += tc->data_len; + } + if (r_data_len) { + *r_data_len = i; + } + return data; +} + + +/* -------------------------------------------------------------------- */ +/* Test Buffer */ + +/* API to handle local allocation of data so we can compare it with the data in the array_store */ +typedef struct TestBuffer { + struct TestBuffer *next, *prev; + const void *data; + size_t data_len; + + /* for reference */ + BArrayState *state; +} TestBuffer; + +static TestBuffer *testbuffer_list_add(ListBase *lb, const void *data, size_t data_len) +{ + TestBuffer *tb = (TestBuffer *)MEM_mallocN(sizeof(*tb), __func__); + tb->data = data; + tb->data_len = data_len; + tb->state = NULL; + BLI_addtail(lb, tb); + return tb; +} + +static TestBuffer *testbuffer_list_add_copydata(ListBase *lb, const void *data, size_t data_len) +{ + void *data_copy = MEM_mallocN(data_len, __func__); + memcpy(data_copy, data, data_len); + return testbuffer_list_add(lb, data_copy, data_len); +} + +static void testbuffer_list_state_from_data( + ListBase *lb, + const char *data, const size_t data_len) +{ + testbuffer_list_add_copydata(lb, (const void *)data, data_len); +} + +/** + * A version of testbuffer_list_state_from_data that expand data by stride, + * handy so we can test data at different strides. + */ +static void testbuffer_list_state_from_data__stride_expand( + ListBase *lb, + const char *data, const size_t data_len, + const size_t stride) +{ + if (stride == 1) { + testbuffer_list_state_from_data(lb, data, data_len); + } + else { + const size_t data_stride_len = data_len * stride; + char *data_stride = (char *)MEM_mallocN(data_stride_len, __func__); + + for (size_t i = 0, i_stride = 0; i < data_len; i += 1, i_stride += stride) { + memset(&data_stride[i_stride], data[i], stride); + } + + testbuffer_list_add(lb, (const void *)data_stride, data_stride_len); + } +} + +#define testbuffer_list_state_from_string_array(lb, data_array) \ +{ \ + unsigned int i_ = 0; \ + const char *data; \ + while ((data = data_array[i_++])) { \ + testbuffer_list_state_from_data(lb, data, strlen(data)); \ + } \ +} ((void)0) + +// + +#define TESTBUFFER_STRINGS_CREATE(lb, ...) \ +{ \ + BLI_listbase_clear(lb); \ + const char *data_array[] = {__VA_ARGS__ NULL}; \ + testbuffer_list_state_from_string_array((lb), data_array); \ +} ((void)0) + +/* test in both directions */ +#define TESTBUFFER_STRINGS_EX(bs, ...) \ +{ \ + ListBase lb; \ + TESTBUFFER_STRINGS_CREATE(&lb, __VA_ARGS__); \ + \ + testbuffer_run_tests(bs, &lb); \ + \ + testbuffer_list_free(&lb); \ +} ((void)0) + +#define TESTBUFFER_STRINGS(stride, chunk_count, ...) \ +{ \ + ListBase lb; \ + TESTBUFFER_STRINGS_CREATE(&lb, __VA_ARGS__); \ + \ + testbuffer_run_tests_simple(&lb, stride, chunk_count); \ + \ + testbuffer_list_free(&lb); \ +} ((void)0) + +static bool testbuffer_item_validate(TestBuffer *tb) +{ + size_t data_state_len; + bool ok = true; + void *data_state = BLI_array_store_state_data_get_alloc(tb->state, &data_state_len); + if (tb->data_len != data_state_len) { + ok = false; + } + else if (memcmp(data_state, tb->data, data_state_len) != 0) { + ok = false; + } + MEM_freeN(data_state); + return ok; +} + +static bool testbuffer_list_validate(const ListBase *lb) +{ + for (TestBuffer *tb = (TestBuffer *)lb->first; tb; tb = tb->next) { + if (!testbuffer_item_validate(tb)) { + return false; + } + } + + return true; +} + +static void testbuffer_list_data_randomize(ListBase *lb, unsigned int random_seed) +{ + for (TestBuffer *tb = (TestBuffer *)lb->first; tb; tb = tb->next) { + BLI_array_randomize((void *)tb->data, 1, tb->data_len, random_seed++); + } +} + +static void testbuffer_list_store_populate( + BArrayStore *bs, ListBase *lb) +{ + for (TestBuffer *tb = (TestBuffer *)lb->first, *tb_prev = NULL; tb; tb_prev = tb, tb = tb->next) { + tb->state = BLI_array_store_state_add(bs, tb->data, tb->data_len, (tb_prev ? tb_prev->state : NULL)); + } +} + +static void testbuffer_list_store_clear( + BArrayStore *bs, ListBase *lb) +{ + for (TestBuffer *tb = (TestBuffer *)lb->first; tb; tb = tb->next) { + BLI_array_store_state_remove(bs, tb->state); + tb->state = NULL; + } +} + +static void testbuffer_list_free(ListBase *lb) +{ + for (TestBuffer *tb = (TestBuffer *)lb->first, *tb_next; tb; tb = tb_next) { + tb_next = tb->next; + MEM_freeN((void *)tb->data); + MEM_freeN(tb); + } + BLI_listbase_clear(lb); +} + +static void testbuffer_run_tests_single( + BArrayStore *bs, ListBase *lb) +{ + testbuffer_list_store_populate(bs, lb); + EXPECT_EQ(true, testbuffer_list_validate(lb)); + EXPECT_EQ(true, BLI_array_store_is_valid(bs)); +#ifdef DEBUG_PRINT + print_mem_saved("data", bs); +#endif +} + +/* avoid copy-paste code to run tests */ +static void testbuffer_run_tests( + BArrayStore *bs, ListBase *lb) +{ + /* forwards */ + testbuffer_run_tests_single(bs, lb); + testbuffer_list_store_clear(bs, lb); + + BLI_listbase_reverse(lb); + + /* backwards */ + testbuffer_run_tests_single(bs, lb); + testbuffer_list_store_clear(bs, lb); +} + +static void testbuffer_run_tests_simple( + ListBase *lb, + const int stride, const int chunk_count) +{ + BArrayStore *bs = BLI_array_store_create(stride, chunk_count); + testbuffer_run_tests(bs, lb); + BLI_array_store_destroy(bs); +} + + +/* -------------------------------------------------------------------- */ +/* Basic Tests */ + +TEST(array_store, Nop) +{ + BArrayStore *bs = BLI_array_store_create(1, 32); + BLI_array_store_destroy(bs); +} + +TEST(array_store, NopState) +{ + BArrayStore *bs = BLI_array_store_create(1, 32); + const unsigned char data[] = "test"; + BArrayState *state = BLI_array_store_state_add(bs, data, sizeof(data) - 1, NULL); + EXPECT_EQ(sizeof(data) - 1, BLI_array_store_state_size_get(state)); + BLI_array_store_state_remove(bs, state); + BLI_array_store_destroy(bs); +} + +TEST(array_store, Single) +{ + BArrayStore *bs = BLI_array_store_create(1, 32); + const char data_src[] = "test"; + const char *data_dst; + BArrayState *state = BLI_array_store_state_add(bs, data_src, sizeof(data_src), NULL); + size_t data_dst_len; + data_dst = (char *)BLI_array_store_state_data_get_alloc(state, &data_dst_len); + EXPECT_STREQ(data_src, data_dst); + EXPECT_EQ(sizeof(data_src), data_dst_len); + BLI_array_store_destroy(bs); + MEM_freeN((void *)data_dst); +} + +TEST(array_store, DoubleNop) +{ + BArrayStore *bs = BLI_array_store_create(1, 32); + const char data_src[] = "test"; + const char *data_dst; + + BArrayState *state_a = BLI_array_store_state_add(bs, data_src, sizeof(data_src), NULL); + BArrayState *state_b = BLI_array_store_state_add(bs, data_src, sizeof(data_src), state_a); + + EXPECT_EQ(sizeof(data_src), BLI_array_store_calc_size_compacted_get(bs)); + EXPECT_EQ(sizeof(data_src) * 2, BLI_array_store_calc_size_expanded_get(bs)); + + size_t data_dst_len; + + data_dst = (char *)BLI_array_store_state_data_get_alloc(state_a, &data_dst_len); + EXPECT_STREQ(data_src, data_dst); + MEM_freeN((void *)data_dst); + + data_dst = (char *)BLI_array_store_state_data_get_alloc(state_b, &data_dst_len); + EXPECT_STREQ(data_src, data_dst); + MEM_freeN((void *)data_dst); + + EXPECT_EQ(sizeof(data_src), data_dst_len); + BLI_array_store_destroy(bs); +} + +TEST(array_store, DoubleDiff) +{ + BArrayStore *bs = BLI_array_store_create(1, 32); + const char data_src_a[] = "test"; + const char data_src_b[] = "####"; + const char *data_dst; + + BArrayState *state_a = BLI_array_store_state_add(bs, data_src_a, sizeof(data_src_a), NULL); + BArrayState *state_b = BLI_array_store_state_add(bs, data_src_b, sizeof(data_src_b), state_a); + size_t data_dst_len; + + EXPECT_EQ(sizeof(data_src_a) * 2, BLI_array_store_calc_size_compacted_get(bs)); + EXPECT_EQ(sizeof(data_src_a) * 2, BLI_array_store_calc_size_expanded_get(bs)); + + data_dst = (char *)BLI_array_store_state_data_get_alloc(state_a, &data_dst_len); + EXPECT_STREQ(data_src_a, data_dst); + MEM_freeN((void *)data_dst); + + data_dst = (char *)BLI_array_store_state_data_get_alloc(state_b, &data_dst_len); + EXPECT_STREQ(data_src_b, data_dst); + MEM_freeN((void *)data_dst); + + BLI_array_store_destroy(bs); +} + +TEST(array_store, TextMixed) +{ + TESTBUFFER_STRINGS(1, 4, "",); + TESTBUFFER_STRINGS(1, 4, "test",); + TESTBUFFER_STRINGS(1, 4, "", "test",); + TESTBUFFER_STRINGS(1, 4, "test", "",); + TESTBUFFER_STRINGS(1, 4, "test", "", "test",); + TESTBUFFER_STRINGS(1, 4, "", "test", "",); +} + +TEST(array_store, TextDupeIncreaseDecrease) +{ + ListBase lb; + +#define D "#1#2#3#4" + TESTBUFFER_STRINGS_CREATE( + &lb, + D, + D D, + D D D, + D D D D, + ); + + BArrayStore *bs = BLI_array_store_create(1, 8); + + /* forward */ + testbuffer_list_store_populate(bs, &lb); + EXPECT_EQ(true, testbuffer_list_validate(&lb)); + EXPECT_EQ(true, BLI_array_store_is_valid(bs)); + EXPECT_EQ(strlen(D), BLI_array_store_calc_size_compacted_get(bs)); + + testbuffer_list_store_clear(bs, &lb); + BLI_listbase_reverse(&lb); + + /* backwards */ + testbuffer_list_store_populate(bs, &lb); + EXPECT_EQ(true, testbuffer_list_validate(&lb)); + EXPECT_EQ(true, BLI_array_store_is_valid(bs)); + /* larger since first block doesn't de-duplicate */ + EXPECT_EQ(strlen(D) * 4, BLI_array_store_calc_size_compacted_get(bs)); + +#undef D + testbuffer_list_free(&lb); \ + + BLI_array_store_destroy(bs); +} + + +/* -------------------------------------------------------------------- */ +/* Plain Text Tests */ + +/** + * Test that uses text input with different params for the array-store + * to ensure no corner cases fail. + */ +static void plain_text_helper( + const char *words, int words_len, const char word_delim, + const int stride, const int chunk_count, const int random_seed) +{ + + ListBase lb; + BLI_listbase_clear(&lb); + + for (int i = 0, i_prev = 0; i < words_len; i++) { + if (ELEM(words[i], word_delim, '\0')) { + if (i != i_prev) { + testbuffer_list_state_from_data__stride_expand(&lb, &words[i_prev], i - i_prev, stride); + } + i_prev = i; + } + } + + if (random_seed) { + testbuffer_list_data_randomize(&lb, random_seed); + } + + testbuffer_run_tests_simple(&lb, stride, chunk_count); + + testbuffer_list_free(&lb); +} + +/* split by '.' (multiple words) */ +#define WORDS words10k, sizeof(words10k) +TEST(array_store, TextSentences_Chunk1) { plain_text_helper(WORDS, '.', 1, 1, 0); } +TEST(array_store, TextSentences_Chunk2) { plain_text_helper(WORDS, '.', 1, 2, 0); } +TEST(array_store, TextSentences_Chunk8) { plain_text_helper(WORDS, '.', 1, 8, 0); } +TEST(array_store, TextSentences_Chunk32) { plain_text_helper(WORDS, '.', 1, 32, 0); } +TEST(array_store, TextSentences_Chunk128) { plain_text_helper(WORDS, '.', 1, 128, 0); } +TEST(array_store, TextSentences_Chunk1024) { plain_text_helper(WORDS, '.', 1, 1024, 0); } +/* odd numbers */ +TEST(array_store, TextSentences_Chunk3) { plain_text_helper(WORDS, '.', 1, 3, 0); } +TEST(array_store, TextSentences_Chunk13) { plain_text_helper(WORDS, '.', 1, 13, 0); } +TEST(array_store, TextSentences_Chunk131) { plain_text_helper(WORDS, '.', 1, 131, 0); } + +/* split by ' ', individual words */ +TEST(array_store, TextWords_Chunk1) { plain_text_helper(WORDS, ' ', 1, 1, 0); } +TEST(array_store, TextWords_Chunk2) { plain_text_helper(WORDS, ' ', 1, 2, 0); } +TEST(array_store, TextWords_Chunk8) { plain_text_helper(WORDS, ' ', 1, 8, 0); } +TEST(array_store, TextWords_Chunk32) { plain_text_helper(WORDS, ' ', 1, 32, 0); } +TEST(array_store, TextWords_Chunk128) { plain_text_helper(WORDS, ' ', 1, 128, 0); } +TEST(array_store, TextWords_Chunk1024) { plain_text_helper(WORDS, ' ', 1, 1024, 0); } +/* odd numbers */ +TEST(array_store, TextWords_Chunk3) { plain_text_helper(WORDS, ' ', 1, 3, 0); } +TEST(array_store, TextWords_Chunk13) { plain_text_helper(WORDS, ' ', 1, 13, 0); } +TEST(array_store, TextWords_Chunk131) { plain_text_helper(WORDS, ' ', 1, 131, 0); } + +/* various tests with different strides & randomizing */ +TEST(array_store, TextSentencesRandom_Stride3_Chunk3) { plain_text_helper(WORDS, 'q', 3, 3, 7337); } +TEST(array_store, TextSentencesRandom_Stride8_Chunk8) { plain_text_helper(WORDS, 'n', 8, 8, 5667); } +TEST(array_store, TextSentencesRandom_Stride32_Chunk1) { plain_text_helper(WORDS, 'a', 1, 32, 1212); } +TEST(array_store, TextSentencesRandom_Stride12_Chunk512) { plain_text_helper(WORDS, 'g', 12, 512, 9999); } +TEST(array_store, TextSentencesRandom_Stride128_Chunk6) { plain_text_helper(WORDS, 'b', 20, 6, 1000); } + +#undef WORDS + + +/* -------------------------------------------------------------------- */ +/* Random Data Tests */ + +static unsigned int rand_range_i(RNG *rng, unsigned int min_i, unsigned int max_i, unsigned int step) +{ + if (min_i == max_i) { + return min_i; + } + BLI_assert(min_i <= max_i); + BLI_assert(((min_i % step) == 0) && ((max_i % step) == 0)); + unsigned int range = (max_i - min_i); + unsigned int value = BLI_rng_get_uint(rng) % range; + value = (value / step) * step; + return min_i + value; +} + +static void rand_bytes(RNG *rng, char *data, int data_len) +{ + BLI_assert(data_len != 0); + while (data_len--) { + *data = BLI_rng_get_uint(rng) % 256; + data++; + } +} + +static void testbuffer_list_state_random_data( + ListBase *lb, + const size_t stride, + const size_t data_min_len, const size_t data_max_len, + + const unsigned int mutate, RNG *rng) +{ + size_t data_len = rand_range_i(rng, data_min_len, data_max_len + stride, stride); + char *data = (char *)MEM_mallocN(data_len, __func__); + + if (lb->last == NULL) { + rand_bytes(rng, data, data_len); + } + else { + TestBuffer *tb_last = (TestBuffer *)lb->last; + if (tb_last->data_len >= data_len) { + memcpy(data, tb_last->data, data_len); + } + else { + memcpy(data, tb_last->data, tb_last->data_len); + rand_bytes(rng, &data[tb_last->data_len], data_len - tb_last->data_len); + } + + /* perform multiple small mutations to the array. */ + for (int i = 0; i < mutate; i++) { + enum { + MUTATE_NOP = 0, + MUTATE_ADD, + MUTATE_REMOVE, + MUTATE_ROTATE, + MUTATE_RANDOMIZE, + MUTATE_TOTAL, + }; + + switch ((BLI_rng_get_uint(rng) % MUTATE_TOTAL)) { + case MUTATE_NOP: + { + break; + } + case MUTATE_ADD: + { + const unsigned int offset = rand_range_i(rng, 0, data_len, stride); + if (data_len < data_max_len) { + data_len += stride; + data = (char *)MEM_reallocN((void *)data, data_len); + memmove(&data[offset + stride], &data[offset], data_len - (offset + stride)); + rand_bytes(rng, &data[offset], stride); + } + break; + } + case MUTATE_REMOVE: + { + const unsigned int offset = rand_range_i(rng, 0, data_len, stride); + if (data_len > data_min_len) { + memmove(&data[offset], &data[offset + stride], data_len - (offset + stride)); + data_len -= stride; + } + break; + } + case MUTATE_ROTATE: + { + int items = data_len / stride; + if (items > 1) { + _bli_array_wrap(data, items, stride, (BLI_rng_get_uint(rng) % 2) ? -1 : 1); + } + break; + } + case MUTATE_RANDOMIZE: + { + if (data_len > 0) { + const unsigned int offset = rand_range_i(rng, 0, data_len - stride, stride); + rand_bytes(rng, &data[offset], stride); + } + break; + } + default: + BLI_assert(0); + } + } + } + + testbuffer_list_add(lb, (const void *)data, data_len); +} + +static void random_data_mutate_helper( + const int items_size_min, const int items_size_max, const int items_total, + const int stride, const int chunk_count, + const int random_seed, const int mutate) +{ + + + ListBase lb; + BLI_listbase_clear(&lb); + + const size_t data_min_len = items_size_min * stride; + const size_t data_max_len = items_size_max * stride; + + { + RNG *rng = BLI_rng_new(random_seed); + for (int i = 0; i < items_total; i++) { + testbuffer_list_state_random_data(&lb, stride, data_min_len, data_max_len, mutate, rng); + } + BLI_rng_free(rng); + } + + testbuffer_run_tests_simple(&lb, stride, chunk_count); + + testbuffer_list_free(&lb); +} + +TEST(array_store, TestData_Stride1_Chunk32_Mutate2) { random_data_mutate_helper(0, 100, 400, 1, 32, 9779, 2); } +TEST(array_store, TestData_Stride8_Chunk512_Mutate2) { random_data_mutate_helper(0, 128, 400, 8, 512, 1001, 2); } +TEST(array_store, TestData_Stride12_Chunk48_Mutate2) { random_data_mutate_helper(200, 256, 400, 12, 48, 1331, 2); } +TEST(array_store, TestData_Stride32_Chunk64_Mutate1) { random_data_mutate_helper(0, 256, 200, 32, 64, 3112, 1); } +TEST(array_store, TestData_Stride32_Chunk64_Mutate8) { random_data_mutate_helper(0, 256, 200, 32, 64, 7117, 8); } + + +/* -------------------------------------------------------------------- */ +/* Randomized Chunks Test */ + +static void random_chunk_generate( + ListBase *lb, + const int chunks_per_buffer, + const int stride, const int chunk_count, + const int random_seed) +{ + RNG *rng = BLI_rng_new(random_seed); + const size_t chunk_size_bytes = stride * chunk_count; + for (int i = 0; i < chunks_per_buffer; i++) { + char *data_chunk = (char *)MEM_mallocN(chunk_size_bytes, __func__); + rand_bytes(rng, data_chunk, chunk_size_bytes); + testchunk_list_add(lb, data_chunk, chunk_size_bytes); + } + BLI_rng_free(rng); +} + +/** + * Add random chunks, then re-order them to ensure chunk de-duplication is working. + */ +static void random_chunk_mutate_helper( + const int chunks_per_buffer, const int items_total, + const int stride, const int chunk_count, + const int random_seed) +{ + /* generate random chunks */ + + ListBase random_chunks; + BLI_listbase_clear(&random_chunks); + random_chunk_generate(&random_chunks, chunks_per_buffer, stride, chunk_count, random_seed); + TestChunnk **chunks_array = (TestChunnk **)MEM_mallocN(chunks_per_buffer * sizeof(TestChunnk *), __func__); + { + TestChunnk *tc = (TestChunnk *)random_chunks.first; + for (int i = 0; i < chunks_per_buffer; i++, tc = tc->next) { + chunks_array[i] = tc; + } + } + + /* add and re-order each time */ + ListBase lb; + BLI_listbase_clear(&lb); + + { + RNG *rng = BLI_rng_new(random_seed); + for (int i = 0; i < items_total; i++) { + BLI_rng_shuffle_array(rng, chunks_array, sizeof(TestChunnk *), chunks_per_buffer); + size_t data_len; + char *data = testchunk_as_data_array(chunks_array, chunks_per_buffer, &data_len); + BLI_assert(data_len == chunks_per_buffer * chunk_count * stride); + testbuffer_list_add(&lb, (const void *)data, data_len); + } + BLI_rng_free(rng); + } + + testchunk_list_free(&random_chunks); + MEM_freeN(chunks_array); + + BArrayStore *bs = BLI_array_store_create(stride, chunk_count); + testbuffer_run_tests_single(bs, &lb); + + size_t expected_size = chunks_per_buffer * chunk_count * stride; + EXPECT_EQ(expected_size, BLI_array_store_calc_size_compacted_get(bs)); + + BLI_array_store_destroy(bs); + + testbuffer_list_free(&lb); + +} + +TEST(array_store, TestChunk_Rand8_Stride1_Chunk64) { random_chunk_mutate_helper(8, 100, 1, 64, 9779); } +TEST(array_store, TestChunk_Rand32_Stride1_Chunk64) { random_chunk_mutate_helper(32, 100, 1, 64, 1331); } +TEST(array_store, TestChunk_Rand64_Stride8_Chunk32) { random_chunk_mutate_helper(64, 100, 8, 32, 2772); } +TEST(array_store, TestChunk_Rand31_Stride11_Chunk21) { random_chunk_mutate_helper(31, 100, 11, 21, 7117); } + + +#if 0 +/* -------------------------------------------------------------------- */ + +/* Test From Files (disabled, keep for local tests.) */ + +void *file_read_binary_as_mem(const char *filepath, size_t pad_bytes, size_t *r_size) +{ + FILE *fp = fopen(filepath, "rb"); + void *mem = NULL; + + if (fp) { + long int filelen_read; + fseek(fp, 0L, SEEK_END); + const long int filelen = ftell(fp); + if (filelen == -1) { + goto finally; + } + fseek(fp, 0L, SEEK_SET); + + mem = MEM_mallocN(filelen + pad_bytes, __func__); + if (mem == NULL) { + goto finally; + } + + filelen_read = fread(mem, 1, filelen, fp); + if ((filelen_read != filelen) || ferror(fp)) { + MEM_freeN(mem); + mem = NULL; + goto finally; + } + + *r_size = filelen_read; + +finally: + fclose(fp); + } + + return mem; +} + + +TEST(array_store, PlainTextFiles) +{ ListBase lb; + BLI_listbase_clear(&lb); + BArrayStore *bs = BLI_array_store_create(1, 128); + + for (int i = 0; i < 629; i++) { + char str[512]; + BLI_snprintf(str, sizeof(str), "/src/py_array_cow/test_data/xz_data/%04d.c.xz", i); + // BLI_snprintf(str, sizeof(str), "/src/py_array_cow/test_data/c_code/%04d.c", i); + // printf("%s\n", str); + size_t data_len; + void *data; + data = file_read_binary_as_mem(str, 0, &data_len); + + testbuffer_list_add(&lb, (const void *)data, data_len); + } + + /* forwards */ + testbuffer_list_store_populate(bs, &lb); + EXPECT_EQ(true, testbuffer_list_validate(&lb)); + EXPECT_EQ(true, BLI_array_store_is_valid(bs)); +#ifdef DEBUG_PRINT + print_mem_saved("source code forward", bs); +#endif + + testbuffer_list_store_clear(bs, &lb); + BLI_listbase_reverse(&lb); + + /* backwards */ + testbuffer_list_store_populate(bs, &lb); + EXPECT_EQ(true, testbuffer_list_validate(&lb)); + EXPECT_EQ(true, BLI_array_store_is_valid(bs)); +#ifdef DEBUG_PRINT + print_mem_saved("source code backwards", bs); +#endif + + + testbuffer_list_free(&lb); + BLI_array_store_destroy(bs); +} +#endif diff --git a/tests/gtests/blenlib/BLI_ghash_performance_test.cc b/tests/gtests/blenlib/BLI_ghash_performance_test.cc index 709302db021..fb32cb3f0a5 100644 --- a/tests/gtests/blenlib/BLI_ghash_performance_test.cc +++ b/tests/gtests/blenlib/BLI_ghash_performance_test.cc @@ -21,6 +21,12 @@ extern "C" { /* Resizing the hash has a huge cost over global filling operation! */ //#define GHASH_RESERVE +/* Run the longest tests! */ +//#define GHASH_RUN_BIG + +/* Size of 'small case' ghash (number of entries). */ +#define TESTCASE_SIZE_SMALL 17 + #define PRINTF_GHASH_STATS(_gh) \ { \ double q, lf, var, pempty, poverloaded; \ @@ -32,7 +38,6 @@ extern "C" { BLI_ghash_size(_gh), q, var, lf, pempty * 100.0, poverloaded * 100.0, bigb); \ } void (0) - /* Str: whole text, lines and words from a 'corpus' text. */ static void str_ghash_tests(GHash *ghash, const char *id) @@ -223,12 +228,14 @@ TEST(ghash, IntGHash12000) int_ghash_tests(ghash, "IntGHash - GHash - 12000", 12000); } +#ifdef GHASH_RUN_BIG TEST(ghash, IntGHash100000000) { GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__); int_ghash_tests(ghash, "IntGHash - GHash - 100000000", 100000000); } +#endif TEST(ghash, IntMurmur2a12000) { @@ -237,13 +244,14 @@ TEST(ghash, IntMurmur2a12000) int_ghash_tests(ghash, "IntGHash - Murmur - 12000", 12000); } +#ifdef GHASH_RUN_BIG TEST(ghash, IntMurmur2a100000000) { GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p_murmur, BLI_ghashutil_intcmp, __func__); int_ghash_tests(ghash, "IntGHash - Murmur - 100000000", 100000000); } - +#endif /* Int: random 50M integers. */ @@ -302,12 +310,14 @@ TEST(ghash, IntRandGHash12000) randint_ghash_tests(ghash, "RandIntGHash - GHash - 12000", 12000); } +#ifdef GHASH_RUN_BIG TEST(ghash, IntRandGHash50000000) { GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__); randint_ghash_tests(ghash, "RandIntGHash - GHash - 50000000", 50000000); } +#endif TEST(ghash, IntRandMurmur2a12000) { @@ -316,12 +326,14 @@ TEST(ghash, IntRandMurmur2a12000) randint_ghash_tests(ghash, "RandIntGHash - Murmur - 12000", 12000); } +#ifdef GHASH_RUN_BIG TEST(ghash, IntRandMurmur2a50000000) { GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p_murmur, BLI_ghashutil_intcmp, __func__); randint_ghash_tests(ghash, "RandIntGHash - Murmur - 50000000", 50000000); } +#endif static unsigned int ghashutil_tests_nohash_p(const void *p) { @@ -340,13 +352,14 @@ TEST(ghash, Int4NoHash12000) randint_ghash_tests(ghash, "RandIntGHash - No Hash - 12000", 12000); } +#ifdef GHASH_RUN_BIG TEST(ghash, Int4NoHash50000000) { GHash *ghash = BLI_ghash_new(ghashutil_tests_nohash_p, ghashutil_tests_cmp_p, __func__); randint_ghash_tests(ghash, "RandIntGHash - No Hash - 50000000", 50000000); } - +#endif /* Int_v4: 20M of randomly-generated integer vectors. */ @@ -409,12 +422,14 @@ TEST(ghash, Int4GHash2000) int4_ghash_tests(ghash, "Int4GHash - GHash - 2000", 2000); } +#ifdef GHASH_RUN_BIG TEST(ghash, Int4GHash20000000) { GHash *ghash = BLI_ghash_new(BLI_ghashutil_uinthash_v4_p, BLI_ghashutil_uinthash_v4_cmp, __func__); int4_ghash_tests(ghash, "Int4GHash - GHash - 20000000", 20000000); } +#endif TEST(ghash, Int4Murmur2a2000) { @@ -423,9 +438,99 @@ TEST(ghash, Int4Murmur2a2000) int4_ghash_tests(ghash, "Int4GHash - Murmur - 2000", 2000); } +#ifdef GHASH_RUN_BIG TEST(ghash, Int4Murmur2a20000000) { GHash *ghash = BLI_ghash_new(BLI_ghashutil_uinthash_v4_p_murmur, BLI_ghashutil_uinthash_v4_cmp, __func__); int4_ghash_tests(ghash, "Int4GHash - Murmur - 20000000", 20000000); } +#endif + +/* MultiSmall: create and manipulate a lot of very small ghashes (90% < 10 items, 9% < 100 items, 1% < 1000 items). */ + +static void multi_small_ghash_tests_one(GHash *ghash, RNG *rng, const unsigned int nbr) +{ + unsigned int *data = (unsigned int *)MEM_mallocN(sizeof(*data) * (size_t)nbr, __func__); + unsigned int *dt; + unsigned int i; + + for (i = nbr, dt = data; i--; dt++) { + *dt = BLI_rng_get_uint(rng); + } + +#ifdef GHASH_RESERVE + BLI_ghash_reserve(ghash, nbr); +#endif + + for (i = nbr, dt = data; i--; dt++) { + BLI_ghash_insert(ghash, SET_UINT_IN_POINTER(*dt), SET_UINT_IN_POINTER(*dt)); + } + + for (i = nbr, dt = data; i--; dt++) { + void *v = BLI_ghash_lookup(ghash, SET_UINT_IN_POINTER(*dt)); + EXPECT_EQ(*dt, GET_UINT_FROM_POINTER(v)); + } + + BLI_ghash_clear(ghash, NULL, NULL); +} + +static void multi_small_ghash_tests(GHash *ghash, const char *id, const unsigned int nbr) +{ + printf("\n========== STARTING %s ==========\n", id); + + RNG *rng = BLI_rng_new(0); + + TIMEIT_START(multi_small_ghash); + + unsigned int i = nbr; + while (i--) { + const int nbr = 1 + (BLI_rng_get_int(rng) % TESTCASE_SIZE_SMALL) * (!(i % 100) ? 100 : (!(i % 10) ? 10 : 1)); + multi_small_ghash_tests_one(ghash, rng, nbr); + } + + TIMEIT_END(multi_small_ghash); + + TIMEIT_START(multi_small2_ghash); + + unsigned int i = nbr; + while (i--) { + const int nbr = 1 + (BLI_rng_get_int(rng) % TESTCASE_SIZE_SMALL) / 2 * (!(i % 100) ? 100 : (!(i % 10) ? 10 : 1)); + multi_small_ghash_tests_one(ghash, rng, nbr); + } + + TIMEIT_END(multi_small2_ghash); + + BLI_ghash_free(ghash, NULL, NULL); + BLI_rng_free(rng); + + printf("========== ENDED %s ==========\n\n", id); +} + +TEST(ghash, MultiRandIntGHash2000) +{ + GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__); + + multi_small_ghash_tests(ghash, "MultiSmall RandIntGHash - GHash - 2000", 2000); +} + +TEST(ghash, MultiRandIntGHash200000) +{ + GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__); + + multi_small_ghash_tests(ghash, "MultiSmall RandIntGHash - GHash - 200000", 200000); +} + +TEST(ghash, MultiRandIntMurmur2a2000) +{ + GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p_murmur, BLI_ghashutil_intcmp, __func__); + + multi_small_ghash_tests(ghash, "MultiSmall RandIntGHash - Murmur2a - 2000", 2000); +} + +TEST(ghash, MultiRandIntMurmur2a200000) +{ + GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p_murmur, BLI_ghashutil_intcmp, __func__); + + multi_small_ghash_tests(ghash, "MultiSmall RandIntGHash - Murmur2a - 200000", 200000); +} diff --git a/tests/gtests/blenlib/CMakeLists.txt b/tests/gtests/blenlib/CMakeLists.txt index 5e6bddcdeab..12112e7a481 100644 --- a/tests/gtests/blenlib/CMakeLists.txt +++ b/tests/gtests/blenlib/CMakeLists.txt @@ -35,6 +35,7 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_LINKFLAGS}") set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${PLATFORM_LINKFLAGS_DEBUG}") +BLENDER_TEST(BLI_array_store "bf_blenlib") BLENDER_TEST(BLI_array_utils "bf_blenlib") BLENDER_TEST(BLI_stack "bf_blenlib") BLENDER_TEST(BLI_math_color "bf_blenlib") |