diff options
author | Lukas Tönne <lukas.toenne@gmail.com> | 2015-06-04 13:05:11 +0300 |
---|---|---|
committer | Lukas Tönne <lukas.toenne@gmail.com> | 2015-06-04 13:05:11 +0300 |
commit | 343c4fb54a514b55a9d0e01fc1275fa66bf1fbca (patch) | |
tree | 78ab1fd1f77af1c467e98cc31e940845e0737aee | |
parent | 44276743cfb31996f90a19c6d98839bea3cc1ce4 (diff) | |
parent | cf7a5e93f8d89d8b5382b07834dd0e9fc694254b (diff) |
Merge branch 'master' into gooseberry
Conflicts:
intern/cycles/kernel/svm/svm.h
112 files changed, 2064 insertions, 841 deletions
diff --git a/build_files/scons/tools/Blender.py b/build_files/scons/tools/Blender.py index 03ca5e9c0ae..eeaa0d27379 100644 --- a/build_files/scons/tools/Blender.py +++ b/build_files/scons/tools/Blender.py @@ -664,7 +664,7 @@ def WinPyBundle(target=None, source=None, env=None): py_tar+= '/release/python' + env['BF_PYTHON_VERSION'].replace('.','') + '.tar.gz' py_target = env.subst(env['BF_INSTALLDIR']).lstrip("#") - py_target = os.path.join(py_target, VERSION, 'python', 'lib') + py_target = os.path.join(py_target, VERSION, 'python') def printexception(func,path,ex): if os.path.exists(path): #do not report if path does not exist. eg on a fresh build. print str(func) + ' failed on ' + str(path) diff --git a/extern/bullet2/src/Bullet-C-Api.h b/extern/bullet2/src/Bullet-C-Api.h index 2eabf3840e1..5d00f7e3ac3 100644 --- a/extern/bullet2/src/Bullet-C-Api.h +++ b/extern/bullet2/src/Bullet-C-Api.h @@ -171,6 +171,7 @@ extern "C" { /* Convex Hull */ PL_DECLARE_HANDLE(plConvexHull); plConvexHull plConvexHullCompute(float (*coords)[3], int count); + void plConvexHullDelete(plConvexHull hull); int plConvexHullNumVertices(plConvexHull hull); int plConvexHullNumFaces(plConvexHull hull); void plConvexHullGetVertex(plConvexHull hull, int n, float coords[3], int *original_index); diff --git a/extern/bullet2/src/BulletDynamics/Dynamics/Bullet-C-API.cpp b/extern/bullet2/src/BulletDynamics/Dynamics/Bullet-C-API.cpp index 21f0aa93220..e1f69afe101 100644 --- a/extern/bullet2/src/BulletDynamics/Dynamics/Bullet-C-API.cpp +++ b/extern/bullet2/src/BulletDynamics/Dynamics/Bullet-C-API.cpp @@ -413,6 +413,12 @@ plConvexHull plConvexHullCompute(float (*coords)[3], int count) return reinterpret_cast<plConvexHull>(computer); } +void plConvexHullDelete(plConvexHull hull) +{ + btConvexHullComputer *computer(reinterpret_cast< btConvexHullComputer* >(hull)); + delete computer; +} + int plConvexHullNumVertices(plConvexHull hull) { btConvexHullComputer *computer(reinterpret_cast< btConvexHullComputer* >(hull)); diff --git a/intern/cycles/app/cycles_standalone.cpp b/intern/cycles/app/cycles_standalone.cpp index 8f39c5126f5..3980ca547c2 100644 --- a/intern/cycles/app/cycles_standalone.cpp +++ b/intern/cycles/app/cycles_standalone.cpp @@ -21,6 +21,7 @@ #include "device.h" #include "scene.h" #include "session.h" +#include "integrator.h" #include "util_args.h" #include "util_foreach.h" @@ -296,6 +297,7 @@ static void keyboard(unsigned char key) else if(key == 'i') options.interactive = !(options.interactive); + /* Navigation */ else if(options.interactive && (key == 'w' || key == 'a' || key == 's' || key == 'd')) { Transform matrix = options.session->scene->camera->matrix; float3 translate; @@ -318,6 +320,25 @@ static void keyboard(unsigned char key) options.session->reset(session_buffer_params(), options.session_params.samples); } + + /* Set Max Bounces */ + else if(options.interactive && (key == '0' || key == '1' || key == '2' || key == '3')) { + int bounce; + switch(key) { + case '0': bounce = 0; break; + case '1': bounce = 1; break; + case '2': bounce = 2; break; + case '3': bounce = 3; break; + default: bounce = 0; break; + } + + options.session->scene->integrator->max_bounce = bounce; + + /* Update and Reset */ + options.session->scene->integrator->need_update = true; + + options.session->reset(session_buffer_params(), options.session_params.samples); + } } #endif diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp index 06fc6a33953..d53ab67621e 100644 --- a/intern/cycles/app/cycles_xml.cpp +++ b/intern/cycles/app/cycles_xml.cpp @@ -394,6 +394,10 @@ static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pug for(pugi::xml_node node = graph_node.first_child(); node; node = node.next_sibling()) { ShaderNode *snode = NULL; + /* ToDo: Add missing nodes + * RGBCurvesNode, VectorCurvesNode, RGBRampNode and ConvertNode (RGB -> BW). + */ + if(string_iequals(node.name(), "image_texture")) { ImageTextureNode *img = new ImageTextureNode(); @@ -404,6 +408,8 @@ static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pug xml_read_enum(&img->projection, ImageTextureNode::projection_enum, node, "projection"); xml_read_float(&img->projection_blend, node, "projection_blend"); + /* ToDo: Interpolation */ + snode = img; } else if(string_iequals(node.name(), "environment_texture")) { @@ -516,6 +522,11 @@ static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pug xml_read_float3(&normal->direction, node, "direction"); snode = normal; } + else if(string_iequals(node.name(), "bump")) { + BumpNode *bump = new BumpNode(); + xml_read_bool(&bump->invert, node, "invert"); + snode = bump; + } else if(string_iequals(node.name(), "mapping")) { snode = new MappingNode(); } @@ -570,6 +581,9 @@ static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pug else if(string_iequals(node.name(), "background")) { snode = new BackgroundNode(); } + else if(string_iequals(node.name(), "holdout")) { + snode = new HoldoutNode(); + } else if(string_iequals(node.name(), "absorption_volume")) { snode = new AbsorptionVolumeNode(); } @@ -578,7 +592,14 @@ static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pug } else if(string_iequals(node.name(), "subsurface_scattering")) { SubsurfaceScatteringNode *sss = new SubsurfaceScatteringNode(); - //xml_read_enum(&sss->falloff, SubsurfaceScatteringNode::falloff_enum, node, "falloff"); + + string falloff; + xml_read_string(&falloff, node, "falloff"); + if(falloff == "cubic") + sss->closure = CLOSURE_BSSRDF_CUBIC_ID; + else + sss->closure = CLOSURE_BSSRDF_GAUSSIAN_ID; + snode = sss; } else if(string_iequals(node.name(), "geometry")) { @@ -622,6 +643,7 @@ static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pug snode = new InvertNode(); } 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_bool(&mix->use_clamp, node, "use_clamp"); diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 9f48600161d..6c54149164d 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -926,7 +926,7 @@ static void add_nodes(Scene *scene, output_map[b_output->ptr.data] = proxy->outputs[0]; } - if (b_group_ntree) { + if(b_group_ntree) { add_nodes(scene, b_engine, b_data, diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp index d69244a07bd..0a4802c2c90 100644 --- a/intern/cycles/device/device.cpp +++ b/intern/cycles/device/device.cpp @@ -94,7 +94,7 @@ void Device::draw_pixels(device_memory& rgba, int y, int w, int h, int dx, int d } if(GLEW_VERSION_1_5) { - if (!vertex_buffer) + if(!vertex_buffer) glGenBuffers(1, &vertex_buffer); glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); @@ -110,7 +110,7 @@ void Device::draw_pixels(device_memory& rgba, int y, int w, int h, int dx, int d vp = vbuffer; } - if (vp) { + if(vp) { /* texture coordinate - vertex pair */ vp[0] = 0.0f; vp[1] = 0.0f; @@ -132,7 +132,7 @@ void Device::draw_pixels(device_memory& rgba, int y, int w, int h, int dx, int d vp[14] = dx; vp[15] = (float)height + dy; - if (vertex_buffer) + if(vertex_buffer) glUnmapBuffer(GL_ARRAY_BUFFER); } diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index 8d690466c07..80a2dda22c4 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -919,7 +919,7 @@ public: draw_params.bind_display_space_shader_cb(); } - if (!vertex_buffer) + if(!vertex_buffer) glGenBuffers(1, &vertex_buffer); glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); @@ -928,7 +928,7 @@ public: vpointer = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); - if (vpointer) { + if(vpointer) { /* texture coordinate - vertex pair */ vpointer[0] = 0.0f; vpointer[1] = 0.0f; diff --git a/intern/cycles/device/device_opencl.cpp b/intern/cycles/device/device_opencl.cpp index 72224d3f027..87d4ee91919 100644 --- a/intern/cycles/device/device_opencl.cpp +++ b/intern/cycles/device/device_opencl.cpp @@ -640,8 +640,11 @@ public: clGetProgramBuildInfo(*kernel_program, cdDevice, CL_PROGRAM_BUILD_LOG, ret_val_size, &build_log[0], NULL); build_log[ret_val_size] = '\0'; - fprintf(stderr, "OpenCL kernel build output:\n"); - fprintf(stderr, "%s\n", &build_log[0]); + /* Skip meaningless empty output from the NVidia compiler. */ + if(!(ret_val_size == 2 && build_log[0] == '\n')) { + fprintf(stderr, "OpenCL kernel build output:\n"); + fprintf(stderr, "%s\n", &build_log[0]); + } } if(ciErr != CL_SUCCESS) { @@ -676,6 +679,10 @@ public: double starttime = time_dt(); printf("Compiling OpenCL kernel ...\n"); + /* TODO(sergey): Report which kernel is being compiled + * as well (megakernel or which of split kernels etc..). + */ + printf("Build flags: %s\n", custom_kernel_build_options.c_str()); if(!build_kernel(kernel_program, custom_kernel_build_options, debug_src)) return false; diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h index db83d2ec024..e9b36dd1f39 100644 --- a/intern/cycles/kernel/svm/svm.h +++ b/intern/cycles/kernel/svm/svm.h @@ -184,7 +184,7 @@ CCL_NAMESPACE_END CCL_NAMESPACE_BEGIN #define NODES_GROUP(group) ((group) <= __NODES_MAX_GROUP__) -#define NODES_FEATURE(feature) (__NODES_FEATURES__ & (feature) != 0) +#define NODES_FEATURE(feature) ((__NODES_FEATURES__ & (feature)) != 0) /* Main Interpreter Loop */ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ShaderType type, int path_flag) @@ -213,17 +213,6 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, Shade case NODE_CLOSURE_BACKGROUND: svm_node_closure_background(sd, stack, node); break; - case NODE_CLOSURE_HOLDOUT: - svm_node_closure_holdout(sd, stack, node); - break; - case NODE_CLOSURE_AMBIENT_OCCLUSION: - svm_node_closure_ambient_occlusion(sd, stack, node); - break; -#if NODES_FEATURE(NODE_FEATURE_VOLUME) - case NODE_CLOSURE_VOLUME: - svm_node_closure_volume(kg, sd, stack, node, path_flag); - break; -#endif /* NODES_FEATURE(NODE_FEATURE_VOLUME) */ case NODE_CLOSURE_SET_WEIGHT: svm_node_closure_set_weight(sd, node.y, node.z, node.w); break; @@ -236,7 +225,6 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, Shade case NODE_MIX_CLOSURE: svm_node_mix_closure(sd, stack, node); break; -#endif /* NODES_GROUP(NODE_GROUP_LEVEL_0) */ case NODE_JUMP_IF_ZERO: if(stack_load_float(stack, node.z) == 0.0f) offset += node.y; @@ -245,13 +233,137 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, Shade if(stack_load_float(stack, node.z) == 1.0f) offset += node.y; break; -#ifdef __TEXTURES__ + case NODE_GEOMETRY: + svm_node_geometry(kg, sd, stack, node.y, node.z); + break; + case NODE_CONVERT: + svm_node_convert(sd, stack, node.y, node.z, node.w); + break; + case NODE_TEX_COORD: + svm_node_tex_coord(kg, sd, path_flag, stack, node, &offset); + break; + case NODE_VALUE_F: + svm_node_value_f(kg, sd, stack, node.y, node.z); + break; + case NODE_VALUE_V: + svm_node_value_v(kg, sd, stack, node.y, &offset); + break; + case NODE_ATTR: + svm_node_attr(kg, sd, stack, node); + break; +# if NODES_FEATURE(NODE_FEATURE_BUMP) + case NODE_GEOMETRY_BUMP_DX: + svm_node_geometry_bump_dx(kg, sd, stack, node.y, node.z); + break; + case NODE_GEOMETRY_BUMP_DY: + svm_node_geometry_bump_dy(kg, sd, stack, node.y, node.z); + break; + case NODE_SET_DISPLACEMENT: + svm_node_set_displacement(sd, stack, node.y); + break; +# endif /* NODES_FEATURE(NODE_FEATURE_BUMP) */ +# ifdef __TEXTURES__ case NODE_TEX_IMAGE: svm_node_tex_image(kg, sd, stack, node); break; case NODE_TEX_IMAGE_BOX: svm_node_tex_image_box(kg, sd, stack, node); break; + case NODE_TEX_NOISE: + svm_node_tex_noise(kg, sd, stack, node, &offset); + break; +# endif /* __TEXTURES__ */ +# ifdef __EXTRA_NODES__ +# if NODES_FEATURE(NODE_FEATURE_BUMP) + case NODE_SET_BUMP: + svm_node_set_bump(kg, sd, stack, node); + break; + case NODE_ATTR_BUMP_DX: + svm_node_attr_bump_dx(kg, sd, stack, node); + break; + case NODE_ATTR_BUMP_DY: + svm_node_attr_bump_dy(kg, sd, stack, node); + break; + case NODE_TEX_COORD_BUMP_DX: + svm_node_tex_coord_bump_dx(kg, sd, path_flag, stack, node, &offset); + break; + case NODE_TEX_COORD_BUMP_DY: + svm_node_tex_coord_bump_dy(kg, sd, path_flag, stack, node, &offset); + break; + case NODE_CLOSURE_SET_NORMAL: + svm_node_set_normal(kg, sd, stack, node.y, node.z); + break; +# endif /* NODES_FEATURE(NODE_FEATURE_BUMP) */ + case NODE_HSV: + svm_node_hsv(kg, sd, stack, node.y, node.z, node.w, &offset); + break; +# endif /* __EXTRA_NODES__ */ +#endif /* NODES_GROUP(NODE_GROUP_LEVEL_0) */ + +#if NODES_GROUP(NODE_GROUP_LEVEL_1) + case NODE_CLOSURE_HOLDOUT: + svm_node_closure_holdout(sd, stack, node); + break; + case NODE_CLOSURE_AMBIENT_OCCLUSION: + svm_node_closure_ambient_occlusion(sd, stack, node); + break; + case NODE_FRESNEL: + svm_node_fresnel(sd, stack, node.y, node.z, node.w); + break; + case NODE_LAYER_WEIGHT: + svm_node_layer_weight(sd, stack, node); + break; +# if NODES_FEATURE(NODE_FEATURE_VOLUME) + case NODE_CLOSURE_VOLUME: + svm_node_closure_volume(kg, sd, stack, node, path_flag); + break; +# endif /* NODES_FEATURE(NODE_FEATURE_VOLUME) */ +# ifdef __EXTRA_NODES__ + case NODE_MATH: + svm_node_math(kg, sd, stack, node.y, node.z, node.w, &offset); + break; + case NODE_VECTOR_MATH: + svm_node_vector_math(kg, sd, stack, node.y, node.z, node.w, &offset); + break; + case NODE_RGB_RAMP: + svm_node_rgb_ramp(kg, sd, stack, node, &offset); + break; + case NODE_GAMMA: + svm_node_gamma(sd, stack, node.y, node.z, node.w); + break; + case NODE_BRIGHTCONTRAST: + svm_node_brightness(sd, stack, node.y, node.z, node.w); + break; + case NODE_LIGHT_PATH: + svm_node_light_path(sd, stack, node.y, node.z, path_flag); + break; + case NODE_OBJECT_INFO: + svm_node_object_info(kg, sd, stack, node.y, node.z); + break; + case NODE_PARTICLE_INFO: + svm_node_particle_info(kg, sd, stack, node.y, node.z); + break; +# ifdef __HAIR__ +# if NODES_FEATURE(NODE_FEATURE_HAIR) + case NODE_HAIR_INFO: + svm_node_hair_info(kg, sd, stack, node.y, node.z); + break; +# endif /* NODES_FEATURE(NODE_FEATURE_HAIR) */ +# endif /* __HAIR__ */ +# endif /* __EXTRA_NODES__ */ +#endif /* NODES_GROUP(NODE_GROUP_LEVEL_1) */ + +#if NODES_GROUP(NODE_GROUP_LEVEL_2) + case NODE_MAPPING: + svm_node_mapping(kg, sd, stack, node.y, node.z, &offset); + break; + case NODE_MIN_MAX: + svm_node_min_max(kg, sd, stack, node.y, node.z, &offset); + break; + case NODE_CAMERA: + svm_node_camera(kg, sd, stack, node.y, node.z, node.w); + break; +# ifdef __TEXTURES__ case NODE_TEX_ENVIRONMENT: svm_node_tex_environment(kg, sd, stack, node); break; @@ -261,9 +373,6 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, Shade case NODE_TEX_GRADIENT: svm_node_tex_gradient(sd, stack, node); break; - case NODE_TEX_NOISE: - svm_node_tex_noise(kg, sd, stack, node, &offset); - break; case NODE_TEX_VORONOI: svm_node_tex_voronoi(kg, sd, stack, node, &offset); break; @@ -282,57 +391,37 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, Shade case NODE_TEX_BRICK: svm_node_tex_brick(kg, sd, stack, node, &offset); break; -#endif /* __TEXTURES__ */ - case NODE_CAMERA: - svm_node_camera(kg, sd, stack, node.y, node.z, node.w); - break; - case NODE_GEOMETRY: - svm_node_geometry(kg, sd, stack, node.y, node.z); - break; -#ifdef __EXTRA_NODES__ - case NODE_GEOMETRY_BUMP_DX: - svm_node_geometry_bump_dx(kg, sd, stack, node.y, node.z); - break; - case NODE_GEOMETRY_BUMP_DY: - svm_node_geometry_bump_dy(kg, sd, stack, node.y, node.z); - break; - case NODE_LIGHT_PATH: - svm_node_light_path(sd, stack, node.y, node.z, path_flag); - break; - case NODE_OBJECT_INFO: - svm_node_object_info(kg, sd, stack, node.y, node.z); + case NODE_TEX_VOXEL: + svm_node_tex_voxel(kg, sd, stack, node, &offset); break; - case NODE_PARTICLE_INFO: - svm_node_particle_info(kg, sd, stack, node.y, node.z); +# endif /* __TEXTURES__ */ +# ifdef __EXTRA_NODES__ + case NODE_NORMAL: + svm_node_normal(kg, sd, stack, node.y, node.z, node.w, &offset); break; -#ifdef __HAIR__ -# if NODES_FEATURE(NODE_FEATURE_HAIR) - case NODE_HAIR_INFO: - svm_node_hair_info(kg, sd, stack, node.y, node.z); + case NODE_LIGHT_FALLOFF: + svm_node_light_falloff(sd, stack, node); break; -# endif /* NODES_FEATURE(NODE_FEATURE_HAIR) */ -#endif /* __HAIR__ */ +# endif /* __EXTRA_NODES__ */ +#endif /* NODES_GROUP(NODE_GROUP_LEVEL_2) */ -#endif /* __EXTRA_NODES__ */ - case NODE_CONVERT: - svm_node_convert(sd, stack, node.y, node.z, node.w); +#if NODES_GROUP(NODE_GROUP_LEVEL_3) + case NODE_RGB_CURVES: + svm_node_rgb_curves(kg, sd, stack, node, &offset); break; - case NODE_VALUE_F: - svm_node_value_f(kg, sd, stack, node.y, node.z); + case NODE_VECTOR_CURVES: + svm_node_vector_curves(kg, sd, stack, node, &offset); break; - case NODE_VALUE_V: - svm_node_value_v(kg, sd, stack, node.y, &offset); + case NODE_TANGENT: + svm_node_tangent(kg, sd, stack, node); + break; + case NODE_NORMAL_MAP: + svm_node_normal_map(kg, sd, stack, node); break; -#ifdef __EXTRA_NODES__ +# ifdef __EXTRA_NODES__ case NODE_INVERT: svm_node_invert(sd, stack, node.y, node.z, node.w); break; - case NODE_GAMMA: - svm_node_gamma(sd, stack, node.y, node.z, node.w); - break; - case NODE_BRIGHTCONTRAST: - svm_node_brightness(sd, stack, node.y, node.z, node.w); - break; case NODE_MIX: svm_node_mix(kg, sd, stack, node.y, node.z, node.w, &offset); break; @@ -348,28 +437,9 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, Shade case NODE_COMBINE_HSV: svm_node_combine_hsv(kg, sd, stack, node.y, node.z, node.w, &offset); break; - case NODE_HSV: - svm_node_hsv(kg, sd, stack, node.y, node.z, node.w, &offset); - break; -#endif /* __EXTRA_NODES__ */ - case NODE_ATTR: - svm_node_attr(kg, sd, stack, node); - break; -#ifdef __EXTRA_NODES__ - case NODE_ATTR_BUMP_DX: - svm_node_attr_bump_dx(kg, sd, stack, node); - break; - case NODE_ATTR_BUMP_DY: - svm_node_attr_bump_dy(kg, sd, stack, node); - break; -#endif /* __EXTRA_NODES__ */ - case NODE_FRESNEL: - svm_node_fresnel(sd, stack, node.y, node.z, node.w); - break; - case NODE_LAYER_WEIGHT: - svm_node_layer_weight(sd, stack, node); + case NODE_VECTOR_TRANSFORM: + svm_node_vector_transform(kg, sd, stack, node); break; -#ifdef __EXTRA_NODES__ case NODE_WIREFRAME: svm_node_wireframe(kg, sd, stack, node); break; @@ -379,68 +449,12 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, Shade case NODE_BLACKBODY: svm_node_blackbody(kg, sd, stack, node.y, node.z); break; - case NODE_SET_DISPLACEMENT: - svm_node_set_displacement(sd, stack, node.y); - break; - case NODE_SET_BUMP: - svm_node_set_bump(kg, sd, stack, node); - break; - case NODE_MATH: - svm_node_math(kg, sd, stack, node.y, node.z, node.w, &offset); - break; - case NODE_VECTOR_MATH: - svm_node_vector_math(kg, sd, stack, node.y, node.z, node.w, &offset); - break; - case NODE_VECTOR_TRANSFORM: - svm_node_vector_transform(kg, sd, stack, node); - break; - case NODE_NORMAL: - svm_node_normal(kg, sd, stack, node.y, node.z, node.w, &offset); - break; -#endif /* __EXTRA_NODES__ */ - case NODE_MAPPING: - svm_node_mapping(kg, sd, stack, node.y, node.z, &offset); - break; - case NODE_MIN_MAX: - svm_node_min_max(kg, sd, stack, node.y, node.z, &offset); - break; - case NODE_TEX_COORD: - svm_node_tex_coord(kg, sd, path_flag, stack, node, &offset); - break; -#ifdef __EXTRA_NODES__ - case NODE_TEX_COORD_BUMP_DX: - svm_node_tex_coord_bump_dx(kg, sd, path_flag, stack, node, &offset); - break; - case NODE_TEX_COORD_BUMP_DY: - svm_node_tex_coord_bump_dy(kg, sd, path_flag, stack, node, &offset); - break; - case NODE_CLOSURE_SET_NORMAL: - svm_node_set_normal(kg, sd, stack, node.y, node.z ); - break; - case NODE_RGB_RAMP: - svm_node_rgb_ramp(kg, sd, stack, node, &offset); - break; - case NODE_RGB_CURVES: - svm_node_rgb_curves(kg, sd, stack, node, &offset); - break; - case NODE_VECTOR_CURVES: - svm_node_vector_curves(kg, sd, stack, node, &offset); - break; - case NODE_LIGHT_FALLOFF: - svm_node_light_falloff(sd, stack, node); - break; -#endif /* __EXTRA_NODES__ */ - case NODE_TANGENT: - svm_node_tangent(kg, sd, stack, node); - break; - case NODE_NORMAL_MAP: - svm_node_normal_map(kg, sd, stack, node); - break; - case NODE_TEX_VOXEL: - svm_node_tex_voxel(kg, sd, stack, node, &offset); - break; +# endif /* __EXTRA_NODES__ */ +#endif /* NODES_GROUP(NODE_GROUP_LEVEL_3) */ case NODE_END: + return; default: + kernel_assert(!"Unknown node type was passed to the SVM machine"); return; } } diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index eff6cd2c223..641d30a5737 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -39,11 +39,17 @@ CCL_NAMESPACE_BEGIN #define NODE_GROUP_LEVEL_0 0 #define NODE_GROUP_LEVEL_1 1 #define NODE_GROUP_LEVEL_2 2 -#define NODE_GROUP_LEVEL_MAX NODE_GROUP_LEVEL_2 +#define NODE_GROUP_LEVEL_3 3 +#define NODE_GROUP_LEVEL_MAX NODE_GROUP_LEVEL_3 #define NODE_FEATURE_VOLUME (1 << 0) #define NODE_FEATURE_HAIR (1 << 1) -#define NODE_FEATURE_ALL (NODE_FEATURE_VOLUME|NODE_FEATURE_HAIR) +#define NODE_FEATURE_BUMP (1 << 2) +/* TODO(sergey): Consider using something like ((uint)(-1)). + * Need to ceck carefully operand types around usage of this + * define first. + */ +#define NODE_FEATURE_ALL (NODE_FEATURE_VOLUME|NODE_FEATURE_HAIR|NODE_FEATURE_BUMP) typedef enum NodeType { NODE_END = 0, diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h index 1a17909bddc..93341b56d99 100644 --- a/intern/cycles/render/graph.h +++ b/intern/cycles/render/graph.h @@ -225,7 +225,7 @@ public: * so it's possible to disable huge nodes inside of the required * nodes group. */ - virtual int get_feature() { return 0; } + virtual int get_feature() { return bump == SHADER_BUMP_NONE ? 0 : NODE_FEATURE_BUMP; } }; diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index 884186c5914..4f99bfc1520 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -1231,6 +1231,7 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen /* Update images needed for true displacement. */ bool need_displacement_images = false; + bool old_need_object_flags_update = false; foreach(Mesh *mesh, scene->meshes) { if(mesh->need_update && mesh->displacement_method != Mesh::DISPLACE_BUMP) @@ -1242,6 +1243,12 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen if(need_displacement_images) { VLOG(1) << "Updating images used for true displacement."; device_update_displacement_images(device, dscene, scene, progress); + old_need_object_flags_update = scene->object_manager->need_flags_update; + scene->object_manager->device_update_flags(device, + dscene, + scene, + progress, + false); } /* device update */ @@ -1327,6 +1334,16 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen } need_update = false; + + if(need_displacement_images) { + /* Re-tag flags for update, so they're re-evaluated + * for meshes with correct bounding boxes. + * + * This wouldn't cause wrong results, just true + * displacement might be less optimal ot calculate. + */ + scene->object_manager->need_flags_update = old_need_object_flags_update; + } } void MeshManager::device_free(Device *device, DeviceScene *dscene) diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 56d21716f3b..4961cd4aebb 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -105,6 +105,7 @@ public: ~EnvironmentTextureNode(); ShaderNode *clone() const; void attributes(Shader *shader, AttributeRequestSet *attributes); + virtual int get_group() { return NODE_GROUP_LEVEL_2; } ImageManager *image_manager; int is_float; @@ -124,6 +125,8 @@ class SkyTextureNode : public TextureNode { public: SHADER_NODE_CLASS(SkyTextureNode) + virtual int get_group() { return NODE_GROUP_LEVEL_2; } + float3 sun_direction; float turbidity; float ground_albedo; @@ -141,6 +144,8 @@ class GradientTextureNode : public TextureNode { public: SHADER_NODE_CLASS(GradientTextureNode) + virtual int get_group() { return NODE_GROUP_LEVEL_2; } + ustring type; static ShaderEnum type_enum; }; @@ -154,6 +159,8 @@ class VoronoiTextureNode : public TextureNode { public: SHADER_NODE_CLASS(VoronoiTextureNode) + virtual int get_group() { return NODE_GROUP_LEVEL_2; } + ustring coloring; static ShaderEnum coloring_enum; @@ -163,6 +170,8 @@ class MusgraveTextureNode : public TextureNode { public: SHADER_NODE_CLASS(MusgraveTextureNode) + virtual int get_group() { return NODE_GROUP_LEVEL_2; } + ustring type; static ShaderEnum type_enum; @@ -172,6 +181,8 @@ class WaveTextureNode : public TextureNode { public: SHADER_NODE_CLASS(WaveTextureNode) + virtual int get_group() { return NODE_GROUP_LEVEL_2; } + ustring type; static ShaderEnum type_enum; }; @@ -180,12 +191,16 @@ class MagicTextureNode : public TextureNode { public: SHADER_NODE_CLASS(MagicTextureNode) + virtual int get_group() { return NODE_GROUP_LEVEL_2; } + int depth; }; class CheckerTextureNode : public TextureNode { public: SHADER_NODE_CLASS(CheckerTextureNode) + + virtual int get_group() { return NODE_GROUP_LEVEL_2; } }; class BrickTextureNode : public TextureNode { @@ -194,6 +209,8 @@ public: float offset, squash; int offset_frequency, squash_frequency; + + virtual int get_group() { return NODE_GROUP_LEVEL_2; } }; class PointDensityTextureNode : public ShaderNode { @@ -222,6 +239,7 @@ public: class MappingNode : public ShaderNode { public: SHADER_NODE_CLASS(MappingNode) + virtual int get_group() { return NODE_GROUP_LEVEL_2; } TextureMapping tex_mapping; }; @@ -344,6 +362,7 @@ public: class HoldoutNode : public ShaderNode { public: SHADER_NODE_CLASS(HoldoutNode) + virtual int get_group() { return NODE_GROUP_LEVEL_1; } }; class AmbientOcclusionNode : public ShaderNode { @@ -351,6 +370,7 @@ public: SHADER_NODE_CLASS(AmbientOcclusionNode) bool has_spatial_varying() { return true; } + virtual int get_group() { return NODE_GROUP_LEVEL_1; } }; class VolumeNode : public ShaderNode { @@ -358,6 +378,7 @@ public: SHADER_NODE_CLASS(VolumeNode) void compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2); + virtual int get_group() { return NODE_GROUP_LEVEL_1; } ClosureType closure; }; @@ -405,6 +426,7 @@ public: SHADER_NODE_CLASS(UVMapNode) void attributes(Shader *shader, AttributeRequestSet *attributes); bool has_spatial_varying() { return true; } + virtual int get_group() { return NODE_GROUP_LEVEL_1; } ustring attribute; bool from_dupli; @@ -413,6 +435,7 @@ public: class LightPathNode : public ShaderNode { public: SHADER_NODE_CLASS(LightPathNode) + virtual int get_group() { return NODE_GROUP_LEVEL_1; } }; class LightFalloffNode : public ShaderNode { @@ -424,12 +447,14 @@ public: class ObjectInfoNode : public ShaderNode { public: SHADER_NODE_CLASS(ObjectInfoNode) + virtual int get_group() { return NODE_GROUP_LEVEL_1; } }; class ParticleInfoNode : public ShaderNode { public: SHADER_NODE_CLASS(ParticleInfoNode) void attributes(Shader *shader, AttributeRequestSet *attributes); + virtual int get_group() { return NODE_GROUP_LEVEL_1; } }; class HairInfoNode : public ShaderNode { @@ -438,7 +463,10 @@ public: void attributes(Shader *shader, AttributeRequestSet *attributes); bool has_spatial_varying() { return true; } - virtual int get_feature() { return NODE_FEATURE_HAIR; } + virtual int get_group() { return NODE_GROUP_LEVEL_1; } + virtual int get_feature() { + return ShaderNode::get_feature() | NODE_FEATURE_HAIR; + } }; class ValueNode : public ShaderNode { @@ -473,12 +501,16 @@ public: class InvertNode : public ShaderNode { public: SHADER_NODE_CLASS(InvertNode) + + virtual int get_group() { return NODE_GROUP_LEVEL_3; } }; class MixNode : public ShaderNode { public: SHADER_NODE_CLASS(MixNode) + virtual int get_group() { return NODE_GROUP_LEVEL_3; } + bool use_clamp; ustring type; @@ -488,41 +520,55 @@ public: class CombineRGBNode : public ShaderNode { public: SHADER_NODE_CLASS(CombineRGBNode) + + virtual int get_group() { return NODE_GROUP_LEVEL_3; } }; class CombineHSVNode : public ShaderNode { public: SHADER_NODE_CLASS(CombineHSVNode) + + virtual int get_group() { return NODE_GROUP_LEVEL_3; } }; class CombineXYZNode : public ShaderNode { public: SHADER_NODE_CLASS(CombineXYZNode) + + virtual int get_group() { return NODE_GROUP_LEVEL_3; } }; class GammaNode : public ShaderNode { public: SHADER_NODE_CLASS(GammaNode) + virtual int get_group() { return NODE_GROUP_LEVEL_1; } }; class BrightContrastNode : public ShaderNode { public: SHADER_NODE_CLASS(BrightContrastNode) + virtual int get_group() { return NODE_GROUP_LEVEL_1; } }; class SeparateRGBNode : public ShaderNode { public: SHADER_NODE_CLASS(SeparateRGBNode) + + virtual int get_group() { return NODE_GROUP_LEVEL_3; } }; class SeparateHSVNode : public ShaderNode { public: SHADER_NODE_CLASS(SeparateHSVNode) + + virtual int get_group() { return NODE_GROUP_LEVEL_3; } }; class SeparateXYZNode : public ShaderNode { public: SHADER_NODE_CLASS(SeparateXYZNode) + + virtual int get_group() { return NODE_GROUP_LEVEL_3; } }; class HSVNode : public ShaderNode { @@ -549,18 +595,21 @@ class FresnelNode : public ShaderNode { public: SHADER_NODE_CLASS(FresnelNode) bool has_spatial_varying() { return true; } + virtual int get_group() { return NODE_GROUP_LEVEL_1; } }; class LayerWeightNode : public ShaderNode { public: SHADER_NODE_CLASS(LayerWeightNode) bool has_spatial_varying() { return true; } + virtual int get_group() { return NODE_GROUP_LEVEL_1; } }; class WireframeNode : public ShaderNode { public: SHADER_NODE_CLASS(WireframeNode) bool has_spatial_varying() { return true; } + virtual int get_group() { return NODE_GROUP_LEVEL_3; } bool use_pixel_size; }; @@ -568,16 +617,21 @@ public: class WavelengthNode : public ShaderNode { public: SHADER_NODE_CLASS(WavelengthNode) + + virtual int get_group() { return NODE_GROUP_LEVEL_3; } }; class BlackbodyNode : public ShaderNode { public: SHADER_NODE_CLASS(BlackbodyNode) + + virtual int get_group() { return NODE_GROUP_LEVEL_3; } }; class MathNode : public ShaderNode { public: SHADER_NODE_CLASS(MathNode) + virtual int get_group() { return NODE_GROUP_LEVEL_1; } bool use_clamp; @@ -588,6 +642,7 @@ public: class NormalNode : public ShaderNode { public: SHADER_NODE_CLASS(NormalNode) + virtual int get_group() { return NODE_GROUP_LEVEL_2; } float3 direction; }; @@ -595,6 +650,7 @@ public: class VectorMathNode : public ShaderNode { public: SHADER_NODE_CLASS(VectorMathNode) + virtual int get_group() { return NODE_GROUP_LEVEL_1; } ustring type; static ShaderEnum type_enum; @@ -604,6 +660,8 @@ class VectorTransformNode : public ShaderNode { public: SHADER_NODE_CLASS(VectorTransformNode) + virtual int get_group() { return NODE_GROUP_LEVEL_3; } + ustring type; ustring convert_from; ustring convert_to; @@ -616,6 +674,10 @@ class BumpNode : public ShaderNode { public: SHADER_NODE_CLASS(BumpNode) bool has_spatial_varying() { return true; } + virtual int get_feature() { + /* TODO(sergey): Check for incoming links. */ + return NODE_FEATURE_BUMP; + } bool invert; }; @@ -623,12 +685,18 @@ public: class RGBCurvesNode : public ShaderNode { public: SHADER_NODE_CLASS(RGBCurvesNode) + + virtual int get_group() { return NODE_GROUP_LEVEL_3; } + float4 curves[RAMP_TABLE_SIZE]; }; class VectorCurvesNode : public ShaderNode { public: SHADER_NODE_CLASS(VectorCurvesNode) + + virtual int get_group() { return NODE_GROUP_LEVEL_3; } + float4 curves[RAMP_TABLE_SIZE]; }; @@ -637,6 +705,7 @@ public: SHADER_NODE_CLASS(RGBRampNode) float4 ramp[RAMP_TABLE_SIZE]; bool interpolate; + virtual int get_group() { return NODE_GROUP_LEVEL_1; } }; class SetNormalNode : public ShaderNode { @@ -665,6 +734,7 @@ public: SHADER_NODE_CLASS(NormalMapNode) void attributes(Shader *shader, AttributeRequestSet *attributes); bool has_spatial_varying() { return true; } + virtual int get_group() { return NODE_GROUP_LEVEL_3; } ustring space; static ShaderEnum space_enum; @@ -677,6 +747,7 @@ public: SHADER_NODE_CLASS(TangentNode) void attributes(Shader *shader, AttributeRequestSet *attributes); bool has_spatial_varying() { return true; } + virtual int get_group() { return NODE_GROUP_LEVEL_3; } ustring direction_type; static ShaderEnum direction_type_enum; diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index da9bc23ccc4..ae72d728c8c 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -410,7 +410,8 @@ void ObjectManager::device_update(Device *device, DeviceScene *dscene, Scene *sc void ObjectManager::device_update_flags(Device *device, DeviceScene *dscene, Scene *scene, - Progress& /*progress*/) + Progress& /*progress*/, + bool bounds_valid) { if(!need_update && !need_flags_update) return; @@ -425,9 +426,13 @@ void ObjectManager::device_update_flags(Device *device, uint *object_flag = dscene->object_flag.get_data(); vector<Object *> volume_objects; + bool has_volume_objects = false; foreach(Object *object, scene->objects) { if(object->mesh->has_volume) { - volume_objects.push_back(object); + if(bounds_valid) { + volume_objects.push_back(object); + } + has_volume_objects = true; } } @@ -440,15 +445,23 @@ void ObjectManager::device_update_flags(Device *device, object_flag[object_index] &= ~SD_OBJECT_HAS_VOLUME; } - foreach(Object *volume_object, volume_objects) { - if(object == volume_object) { - continue; - } - if(object->bounds.intersects(volume_object->bounds)) { - object_flag[object_index] |= SD_OBJECT_INTERSECTS_VOLUME; - break; + if(bounds_valid) { + foreach(Object *volume_object, volume_objects) { + if(object == volume_object) { + continue; + } + if(object->bounds.intersects(volume_object->bounds)) { + object_flag[object_index] |= SD_OBJECT_INTERSECTS_VOLUME; + break; + } } } + else if(has_volume_objects) { + /* Not really valid, but can't make more reliable in the case + * of bounds not being up to date. + */ + object_flag[object_index] |= SD_OBJECT_INTERSECTS_VOLUME; + } ++object_index; } diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h index acc08a0e204..379d1748cdd 100644 --- a/intern/cycles/render/object.h +++ b/intern/cycles/render/object.h @@ -77,7 +77,11 @@ public: void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); void device_update_transforms(Device *device, DeviceScene *dscene, Scene *scene, uint *object_flag, Progress& progress); - void device_update_flags(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); + void device_update_flags(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress& progress, + bool bounds_valid = true); void device_free(Device *device, DeviceScene *dscene); void tag_update(Scene *scene); diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index b880a62f4de..a9a03e54cf7 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -608,7 +608,7 @@ DeviceRequestedFeatures Session::get_requested_device_features() requested_features.experimental = params.experimental; if(!params.background) { requested_features.max_closure = 64; - requested_features.max_nodes_group = NODE_GROUP_LEVEL_2; + requested_features.max_nodes_group = NODE_GROUP_LEVEL_MAX; requested_features.nodes_features = NODE_FEATURE_ALL; } else { diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp index 667279360c3..31be2a3d3f4 100644 --- a/intern/cycles/render/shader.cpp +++ b/intern/cycles/render/shader.cpp @@ -481,21 +481,42 @@ void ShaderManager::add_default(Scene *scene) } } -void ShaderManager::get_requested_features(Scene *scene, int& max_group, int& features) +/* NOTE: Expects max_group and features to be initialized in the callee. */ +void ShaderManager::get_requested_graph_features(ShaderGraph *graph, + int& max_group, + int& features) +{ + foreach(ShaderNode *node, graph->nodes) { + max_group = max(max_group, node->get_group()); + features |= node->get_feature(); + if(node->special_type == SHADER_SPECIAL_TYPE_CLOSURE) { + BsdfNode *bsdf_node = static_cast<BsdfNode*>(node); + if(CLOSURE_IS_VOLUME(bsdf_node->closure)) { + features |= NODE_FEATURE_VOLUME; + } + } + } +} + +void ShaderManager::get_requested_features(Scene *scene, + int& max_group, + int& features) { max_group = NODE_GROUP_LEVEL_0; features = 0; for(int i = 0; i < scene->shaders.size(); i++) { Shader *shader = scene->shaders[i]; - foreach(ShaderNode *node, shader->graph->nodes) { - max_group = min(max_group, node->get_group()); - features |= node->get_feature(); - if(node->special_type == SHADER_SPECIAL_TYPE_CLOSURE) { - BsdfNode *bsdf_node = static_cast<BsdfNode*>(node); - if(CLOSURE_IS_VOLUME(bsdf_node->closure)) { - features |= NODE_FEATURE_VOLUME; - } - } + /* Gather requested features from all the nodes from the graph nodes. */ + get_requested_graph_features(shader->graph, max_group, features); + /* Gather requested features from the graph itself. */ + if(shader->graph_bump) { + get_requested_graph_features(shader->graph_bump, + max_group, + features); + } + ShaderNode *output_node = shader->graph->output(); + if(output_node->input("Displacement")->link != NULL) { + features |= NODE_FEATURE_BUMP; } } } diff --git a/intern/cycles/render/shader.h b/intern/cycles/render/shader.h index 27b239601d0..64d45635ef1 100644 --- a/intern/cycles/render/shader.h +++ b/intern/cycles/render/shader.h @@ -166,7 +166,9 @@ public: static void add_default(Scene *scene); /* Selective nodes compilation. */ - void get_requested_features(Scene *scene, int& max_group, int& features); + void get_requested_features(Scene *scene, + int& max_group, + int& features); protected: ShaderManager(); @@ -178,6 +180,10 @@ protected: static vector<float> beckmann_table; size_t beckmann_table_offset; + + void get_requested_graph_features(ShaderGraph *graph, + int& max_group, + int& features); }; CCL_NAMESPACE_END diff --git a/intern/cycles/util/util_atomic.h b/intern/cycles/util/util_atomic.h index 85a82d38275..1d1e2963348 100644 --- a/intern/cycles/util/util_atomic.h +++ b/intern/cycles/util/util_atomic.h @@ -53,9 +53,9 @@ ccl_device_inline void atomic_add_float(volatile ccl_global float *source, do { prev_value.float_value = *source; new_value.float_value = prev_value.float_value + operand; - } while (atomic_cmpxchg((volatile ccl_global unsigned int *)source, - prev_value.int_value, - new_value.int_value) != prev_value.int_value); + } while(atomic_cmpxchg((volatile ccl_global unsigned int *)source, + prev_value.int_value, + new_value.int_value) != prev_value.int_value); } #endif /* __KERNEL_OPENCL__ */ diff --git a/intern/cycles/util/util_view.cpp b/intern/cycles/util/util_view.cpp index 0c11316417b..9b5cd22fb4a 100644 --- a/intern/cycles/util/util_view.cpp +++ b/intern/cycles/util/util_view.cpp @@ -110,6 +110,7 @@ void view_display_help() view_display_text(x1+20, y2-230, "Left mouse: Move camera"); view_display_text(x1+20, y2-250, "Right mouse: Rotate camera"); view_display_text(x1+20, y2-270, "W/A/S/D: Move camera"); + view_display_text(x1+20, y2-290, "0/1/2/3: Set max bounces"); glColor3f(1.0f, 1.0f, 1.0f); } diff --git a/release/scripts/freestyle/modules/freestyle/functions.py b/release/scripts/freestyle/modules/freestyle/functions.py index 48d9b2e2b39..426d344e8ab 100644 --- a/release/scripts/freestyle/modules/freestyle/functions.py +++ b/release/scripts/freestyle/modules/freestyle/functions.py @@ -189,11 +189,13 @@ class CurveMaterialF0D(UnaryFunction0DMaterial): priority is used to pick one of the two materials at material boundaries. - Note: expects instances of CurvePoint to be iterated over + Notes: expects instances of CurvePoint to be iterated over + can return None if no fedge can be found """ def __call__(self, inter): fe = inter.object.fedge - assert(fe is not None), "CurveMaterialF0D: fe is None" + if fe is None: + return None if fe.is_smooth: return fe.material else: diff --git a/release/scripts/freestyle/modules/freestyle/predicates.py b/release/scripts/freestyle/modules/freestyle/predicates.py index 2439cb0cf97..5cbe577b956 100644 --- a/release/scripts/freestyle/modules/freestyle/predicates.py +++ b/release/scripts/freestyle/modules/freestyle/predicates.py @@ -43,6 +43,7 @@ __all__ = ( "FalseUP0D", "FalseUP1D", "Length2DBP1D", + "MaterialBP1D", "NotBP1D", "NotUP1D", "ObjectNamesUP1D", @@ -150,12 +151,13 @@ from freestyle.functions import ( pyViewMapGradientNormF1D, ) +from freestyle.utils import material_from_fedge + import random # -- Unary predicates for 0D elements (vertices) -- # - class pyHigherCurvature2DAngleUP0D(UnaryPredicate0D): def __init__(self, a): UnaryPredicate0D.__init__(self) @@ -234,9 +236,10 @@ class AndUP1D(UnaryPredicate1D): def __init__(self, *predicates): UnaryPredicate1D.__init__(self) self.predicates = predicates - # there are cases in which only one predicate is supplied (in the parameter editor) - if len(self.predicates) < 1: - raise ValueError("Expected one or more UnaryPredicate1D, got ", len(predicates)) + correct_types = all(isinstance(p, UnaryPredicate1D) for p in self.predicates) + if not (correct_types and predicates): + raise TypeError("%s: Expected one or more UnaryPredicate1D, got %r" % + (self.__class__.__name__, self.predicates)) def __call__(self, inter): return all(pred(inter) for pred in self.predicates) @@ -246,9 +249,10 @@ class OrUP1D(UnaryPredicate1D): def __init__(self, *predicates): UnaryPredicate1D.__init__(self) self.predicates = predicates - # there are cases in which only one predicate is supplied (in the parameter editor) - if len(self.predicates) < 1: - raise ValueError("Expected one or more UnaryPredicate1D, got ", len(predicates)) + correct_types = all(isinstance(p, UnaryPredicate1D) for p in self.predicates) + if not (correct_types and predicates): + raise TypeError("%s: Expected one or more UnaryPredicate1D, got %r" % + (self.__class__.__name__, self.predicates)) def __call__(self, inter): return any(pred(inter) for pred in self.predicates) @@ -257,10 +261,10 @@ class OrUP1D(UnaryPredicate1D): class NotUP1D(UnaryPredicate1D): def __init__(self, pred): UnaryPredicate1D.__init__(self) - self.__pred = pred + self.predicate = pred def __call__(self, inter): - return not self.__pred(inter) + return not self.predicate(inter) class ObjectNamesUP1D(UnaryPredicate1D): @@ -563,32 +567,36 @@ class pyClosedCurveUP1D(UnaryPredicate1D): class AndBP1D(BinaryPredicate1D): def __init__(self, *predicates): BinaryPredicate1D.__init__(self) - self._predicates = predicates - if len(predicates) < 2: - raise ValueError("Expected two or more BinaryPredicate1D, got ", len(predictates)) + self.predicates = tuple(predicates) + correct_types = all(isinstance(p, BinaryPredicate1D) for p in self.predicates) + if not (correct_types and predicates): + raise TypeError("%s: Expected one or more BinaryPredicate1D, got %r" % + (self.__class__.__name__, self.predicates)) def __call__(self, i1, i2): - return all(pred(i1, i2) for pred in self._predicates) + return all(pred(i1, i2) for pred in self.predicates) class OrBP1D(BinaryPredicate1D): def __init__(self, *predicates): BinaryPredicate1D.__init__(self) - self._predicates = predicates - if len(predicates) < 2: - raise ValueError("Expected two or more BinaryPredicate1D, got ", len(predictates)) + self.predicates = tuple(predicates) + correct_types = all(isinstance(p, BinaryPredicate1D) for p in self.predicates) + if not (correct_types and predicates): + raise TypeError("%s: Expected one or more BinaryPredicate1D, got %r" % + (self.__class__.__name__, self.predicates)) def __call__(self, i1, i2): - return any(pred(i1, i2) for pred in self._predicates) + return any(pred(i1, i2) for pred in self.predicates) class NotBP1D(BinaryPredicate1D): def __init__(self, predicate): BinaryPredicate1D.__init__(self) - self._predicate = predicate + self.predicate = predicate def __call__(self, i1, i2): - return (not self._predicate(i1, i2)) + return (not self.predicate(i1, i2)) class pyZBP1D(BinaryPredicate1D): @@ -663,3 +671,10 @@ class pyShuffleBP1D(BinaryPredicate1D): def __call__(self, inter1, inter2): return (random.uniform(0, 1) < random.uniform(0, 1)) + +class MaterialBP1D(BinaryPredicate1D): + """Checks whether the two supplied ViewEdges have the same material.""" + def __call__(self, i1, i2): + fedges = (fe for ve in (i1, i2) for fe in (ve.first_fedge, ve.last_fedge)) + materials = {material_from_fedge(fe) for fe in fedges} + return len(materials) < 2 diff --git a/release/scripts/freestyle/modules/freestyle/shaders.py b/release/scripts/freestyle/modules/freestyle/shaders.py index 61365e8dd87..127db3fcd4b 100644 --- a/release/scripts/freestyle/modules/freestyle/shaders.py +++ b/release/scripts/freestyle/modules/freestyle/shaders.py @@ -138,7 +138,7 @@ from freestyle.predicates import ( from freestyle.utils import ( bound, - bounding_box, + BoundingBox, phase_to_direction, ) @@ -865,7 +865,7 @@ class pyBluePrintCirclesShader(StrokeShader): def shade(self, stroke): # get minimum and maximum coordinates - p_min, p_max = bounding_box(stroke) + p_min, p_max = BoundingBox.from_sequence(svert.point for svert in stroke).corners stroke.resample(32 * self.__turns) sv_nb = len(stroke) // self.__turns @@ -917,7 +917,7 @@ class pyBluePrintEllipsesShader(StrokeShader): self.__random_radius = random_radius def shade(self, stroke): - p_min, p_max = bounding_box(stroke) + p_min, p_max = BoundingBox.from_sequence(svert.point for svert in stroke).corners stroke.resample(32 * self.__turns) sv_nb = len(stroke) // self.__turns @@ -964,7 +964,7 @@ class pyBluePrintSquaresShader(StrokeShader): return # get minimum and maximum coordinates - p_min, p_max = bounding_box(stroke) + p_min, p_max = BoundingBox.from_sequence(svert.point for svert in stroke).corners stroke.resample(32 * self.__turns) num_segments = len(stroke) // self.__turns diff --git a/release/scripts/freestyle/modules/freestyle/utils.py b/release/scripts/freestyle/modules/freestyle/utils.py index 224734d5bfb..41d2297f723 100644 --- a/release/scripts/freestyle/modules/freestyle/utils.py +++ b/release/scripts/freestyle/modules/freestyle/utils.py @@ -22,24 +22,29 @@ writing. """ __all__ = ( - "ContextFunctions", "bound", - "bounding_box", + "BoundingBox", + "ContextFunctions", "find_matching_vertex", - "getCurrentScene", "get_chain_length", + "get_object_name", + "get_strokes", "get_test_stroke", + "getCurrentScene", "integrate", + "is_poly_clockwise", "iter_distance_along_stroke", "iter_distance_from_camera", "iter_distance_from_object", "iter_material_value", "iter_t2d_along_stroke", + "material_from_fedge", "pairwise", "phase_to_direction", "rgb_to_bw", "stroke_curvature", "stroke_normal", + "StrokeCollector", "tripplewise", ) @@ -55,6 +60,7 @@ from _freestyle import ( from freestyle.types import ( Interface0DIterator, Stroke, + StrokeShader, StrokeVertexIterator, ) @@ -79,12 +85,38 @@ def bound(lower, x, higher): return (lower if x <= lower else higher if x >= higher else x) -def bounding_box(stroke): - """ - Returns the maximum and minimum coordinates (the bounding box) of the stroke's vertices - """ - x, y = zip(*(svert.point for svert in stroke)) - return (Vector((min(x), min(y))), Vector((max(x), max(y)))) +def get_strokes(): + """Get all strokes that are currently available""" + return tuple(map(Operators().get_stroke_from_index, range(Operators().get_strokes_size()))) + + +def is_poly_clockwise(stroke): + """True if the stroke is orientated in a clockwise way, False otherwise""" + v = sum((v2.point.x - v1.point.x) * (v1.point.y + v2.point.y) for v1, v2 in pairwise(stroke)) + v1, v2 = stroke[0], stroke[-1] + if (v1.point - v2.point).length > 1e-3: + v += (v2.point.x - v1.point.x) * (v1.point.y + v2.point.y) + return v > 0 + + +def get_object_name(stroke): + """Returns the name of the object that this stroke is drawn on.""" + fedge = stroke[0].fedge + if fedge is None: + return None + return fedge.viewedge.viewshape.name + + +def material_from_fedge(fe): + "get the diffuse rgba color from an FEdge" + if fe is None: + return None + if fe.is_smooth: + material = fe.material + else: + right, left = fe.material_right, fe.material_left + material = right if (right.priority > left.priority) else left + return material # -- General helper functions -- # @@ -106,6 +138,54 @@ def phase_to_direction(length): # lower bound (e.g., thickness, range and certain values) BoundedProperty = namedtuple("BoundedProperty", ["min", "max", "delta"]) + +class BoundingBox: + """Object representing a bounding box consisting out of 2 2D vectors""" + + __slots__ = ( + "minimum", + "maximum", + "size", + "corners", + ) + + def __init__(self, minimum: Vector, maximum: Vector): + self.minimum = minimum + self.maximum = maximum + if len(minimum) != len(maximum): + raise TypeError("Expected two vectors of size 2, got", minimum, maximum) + self.size = len(minimum) + self.corners = (minimum, maximum) + + def __repr__(self): + return "BoundingBox(%r, %r)" % (self.minimum, self.maximum) + + @classmethod + def from_sequence(cls, sequence): + """BoundingBox from sequence of 2D or 3D Vector objects""" + x, y = zip(*sequence) + mini = Vector((min(x), min(y))) + maxi = Vector((max(x), max(y))) + return cls(mini, maxi) + + def inside(self, other): + """True if self inside other, False otherwise""" + if self.size != other.size: + raise TypeError("Expected two BoundingBox of the same size, got", self, other) + return (self.minimum.x >= other.minimum.x and self.minimum.y >= other.minimum.y and + self.maximum.x <= other.maximum.x and self.maximum.y <= other.maximum.y) + + +class StrokeCollector(StrokeShader): + "Collects and Stores stroke objects" + def __init__(self): + StrokeShader.__init__(self) + self.strokes = [] + + def shade(self, stroke): + self.strokes.append(stroke) + + # -- helper functions for chaining -- # def get_chain_length(ve, orientation): @@ -147,6 +227,7 @@ def find_matching_vertex(id, it): """Finds the matching vertex, or returns None.""" return next((ve for ve in it if ve.id == id), None) + # -- helper functions for iterating -- # def pairwise(iterable, types={Stroke, StrokeVertexIterator}): @@ -210,7 +291,7 @@ def iter_distance_from_object(stroke, location, range_min, range_max, normfac): def iter_material_value(stroke, func, attribute): - "Yields a specific material attribute from the vertex' underlying material." + """Yields a specific material attribute from the vertex' underlying material.""" it = Interface0DIterator(stroke) for svert in it: material = func(it) @@ -252,8 +333,9 @@ def iter_material_value(stroke, func, attribute): raise ValueError("unexpected material attribute: " + attribute) yield (svert, value) + def iter_distance_along_stroke(stroke): - "Yields the absolute distance along the stroke up to the current vertex." + """Yields the absolute distance along the stroke up to the current vertex.""" distance = 0.0 # the positions need to be copied, because they are changed in the calling function points = tuple(svert.point.copy() for svert in stroke) @@ -295,6 +377,7 @@ def stroke_curvature(it): yield abs(K) + def stroke_normal(stroke): """ Compute the 2D normal at the stroke vertex pointed by the iterator @@ -304,7 +387,7 @@ def stroke_normal(stroke): The returned normals are dynamic: they update when the vertex position (and therefore the vertex normal) changes. - for use in geometry modifiers it is advised to + for use in geometry modifiers it is advised to cast this generator function to a tuple or list """ n = len(stroke) - 1 @@ -323,12 +406,13 @@ def stroke_normal(stroke): n2 = Vector((e2[1], -e2[0])).normalized() yield (n1 + n2).normalized() + def get_test_stroke(): """Returns a static stroke object for testing """ from freestyle.types import Stroke, Interface0DIterator, StrokeVertexIterator, SVertex, Id, StrokeVertex # points for our fake stroke points = (Vector((1.0, 5.0, 3.0)), Vector((1.0, 2.0, 9.0)), - Vector((6.0, 2.0, 3.0)), Vector((7.0, 2.0, 3.0)), + Vector((6.0, 2.0, 3.0)), Vector((7.0, 2.0, 3.0)), Vector((2.0, 6.0, 3.0)), Vector((2.0, 8.0, 3.0))) ids = (Id(0, 0), Id(1, 1), Id(2, 2), Id(3, 3), Id(4, 4), Id(5, 5)) diff --git a/release/scripts/modules/addon_utils.py b/release/scripts/modules/addon_utils.py index 8c86f31022c..11aeebb8a43 100644 --- a/release/scripts/modules/addon_utils.py +++ b/release/scripts/modules/addon_utils.py @@ -416,19 +416,21 @@ def reset_all(reload_scripts=False): disable(mod_name) -def module_bl_info(mod, info_basis={"name": "", - "author": "", - "version": (), - "blender": (), - "location": "", - "description": "", - "wiki_url": "", - "support": 'COMMUNITY', - "category": "", - "warning": "", - "show_expanded": False, - } - ): +def module_bl_info(mod, info_basis=None): + if info_basis is None: + info_basis = { + "name": "", + "author": "", + "version": (), + "blender": (), + "location": "", + "description": "", + "wiki_url": "", + "support": 'COMMUNITY', + "category": "", + "warning": "", + "show_expanded": False, + } addon_info = getattr(mod, "bl_info", {}) diff --git a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py index 580753482c2..43a09a1acbd 100644 --- a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py +++ b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py @@ -925,18 +925,18 @@ def main(): return import sys - back_argv = sys.argv + import argparse + # Get rid of Blender args! - sys.argv = sys.argv[sys.argv.index("--") + 1:] + argv = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [] - import argparse parser = argparse.ArgumentParser(description="Process UI messages from inside Blender.") parser.add_argument('-c', '--no_checks', default=True, action="store_false", help="No checks over UI messages.") parser.add_argument('-m', '--no_messages', default=True, action="store_false", help="No export of UI messages.") parser.add_argument('-o', '--output', default=None, help="Output POT file path.") parser.add_argument('-s', '--settings', default=None, help="Override (some) default settings. Either a JSon file name, or a JSon string.") - args = parser.parse_args() + args = parser.parse_args(argv) settings = settings_i18n.I18nSettings() settings.from_json(args.settings) @@ -946,8 +946,6 @@ def main(): dump_messages(do_messages=args.no_messages, do_checks=args.no_checks, settings=settings) - sys.argv = back_argv - if __name__ == "__main__": print("\n\n *** Running {} *** \n".format(__file__)) diff --git a/release/scripts/modules/bl_i18n_utils/utils.py b/release/scripts/modules/bl_i18n_utils/utils.py index 524fef909e8..d472621029e 100644 --- a/release/scripts/modules/bl_i18n_utils/utils.py +++ b/release/scripts/modules/bl_i18n_utils/utils.py @@ -162,7 +162,7 @@ def get_po_files_from_dir(root_dir, langs=set()): yield uid, po_file -def enable_addons(addons={}, support={}, disable=False, check_only=False): +def enable_addons(addons=None, support=None, disable=False, check_only=False): """ Enable (or disable) addons based either on a set of names, or a set of 'support' types. Returns the list of all affected addons (as fake modules)! @@ -170,6 +170,11 @@ def enable_addons(addons={}, support={}, disable=False, check_only=False): """ import addon_utils + if addons is None: + addons = {} + if support is None: + support = {} + userpref = bpy.context.user_preferences used_ext = {ext.module for ext in userpref.addons} @@ -212,13 +217,13 @@ class I18nMessage: __slots__ = ("msgctxt_lines", "msgid_lines", "msgstr_lines", "comment_lines", "is_fuzzy", "is_commented", "settings") - def __init__(self, msgctxt_lines=[], msgid_lines=[], msgstr_lines=[], comment_lines=[], + def __init__(self, msgctxt_lines=None, msgid_lines=None, msgstr_lines=None, comment_lines=None, is_commented=False, is_fuzzy=False, settings=settings): self.settings = settings - self.msgctxt_lines = msgctxt_lines - self.msgid_lines = msgid_lines - self.msgstr_lines = msgstr_lines - self.comment_lines = comment_lines + self.msgctxt_lines = msgctxt_lines or [] + self.msgid_lines = msgid_lines or [] + self.msgstr_lines = msgstr_lines or [] + self.comment_lines = comment_lines or [] self.is_fuzzy = is_fuzzy self.is_commented = is_commented diff --git a/release/scripts/modules/nodeitems_utils.py b/release/scripts/modules/nodeitems_utils.py index ff2100916fc..2f69ea84386 100644 --- a/release/scripts/modules/nodeitems_utils.py +++ b/release/scripts/modules/nodeitems_utils.py @@ -43,7 +43,11 @@ class NodeCategory: class NodeItem: - def __init__(self, nodetype, label=None, settings={}, poll=None): + def __init__(self, nodetype, label=None, settings=None, poll=None): + + if settings is None: + settings = {} + self.nodetype = nodetype self._label = label self.settings = settings diff --git a/release/scripts/startup/bl_operators/object_align.py b/release/scripts/startup/bl_operators/object_align.py index 7fb0924add5..3c84e5dc553 100644 --- a/release/scripts/startup/bl_operators/object_align.py +++ b/release/scripts/startup/bl_operators/object_align.py @@ -72,7 +72,6 @@ def GlobalBB_HQ(obj): me = obj.to_mesh(scene=bpy.context.scene, apply_modifiers=True, settings='PREVIEW') verts = me.vertices - bpy.data.meshes.remove(me) val = matrix_world * verts[-1].co @@ -113,6 +112,8 @@ def GlobalBB_HQ(obj): if val > up: up = val + bpy.data.meshes.remove(me) + return Vector((left, front, up)), Vector((right, back, down)) diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py index f315c947009..d1f7c0f5e40 100644 --- a/release/scripts/startup/bl_ui/properties_paint_common.py +++ b/release/scripts/startup/bl_ui/properties_paint_common.py @@ -133,7 +133,7 @@ def brush_texpaint_common(panel, context, layout, brush, settings, projpaint=Fal else: row = col.row(align=True) panel.prop_unified_color(row, context, brush, "color", text="") - if brush.image_tool == 'FILL': + if brush.image_tool == 'FILL' and not projpaint: col.prop(brush, "fill_threshold") else: panel.prop_unified_color(row, context, brush, "secondary_color", text="") @@ -216,7 +216,9 @@ def brush_texpaint_common(panel, context, layout, brush, settings, projpaint=Fal col = layout.column(align=True) col.prop(brush, "use_accumulate") - col.prop(brush, "use_alpha") + if projpaint: + col.prop(brush, "use_alpha") + col.prop(brush, "use_gradient") col.separator() diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 1391e18748c..2057b0f6bbf 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -286,10 +286,9 @@ void blf_font_buffer(FontBLF *font, const char *str) (unsigned char)(buf_info->col[2] * 255), (unsigned char)(buf_info->col[3] * 255)}; - unsigned char *cbuf; int chx, chy; int y, x; - float a, *fbuf; + float a; BLF_KERNING_VARS(font, has_kerning, kern_mode); @@ -349,8 +348,12 @@ void blf_font_buffer(FontBLF *font, const char *str) a = *(g->bitmap + x + (yb * g->pitch)) / 255.0f; if (a > 0.0f) { + const size_t buf_ofs = ( + ((size_t)(chx + x) + ((size_t)(pen_y + y) * (size_t)buf_info->w)) * + (size_t)buf_info->ch); + float *fbuf = buf_info->fbuf + buf_ofs; float alphatest; - fbuf = buf_info->fbuf + buf_info->ch * ((chx + x) + ((pen_y + y) * buf_info->w)); + if (a >= 1.0f) { fbuf[0] = b_col_float[0]; fbuf[1] = b_col_float[1]; @@ -380,8 +383,12 @@ void blf_font_buffer(FontBLF *font, const char *str) a = *(g->bitmap + x + (yb * g->pitch)) / 255.0f; if (a > 0.0f) { + const size_t buf_ofs = ( + ((size_t)(chx + x) + ((size_t)(pen_y + y) * (size_t)buf_info->w)) * + (size_t)buf_info->ch); + unsigned char *cbuf = buf_info->cbuf + buf_ofs; int alphatest; - cbuf = buf_info->cbuf + buf_info->ch * ((chx + x) + ((pen_y + y) * buf_info->w)); + if (a >= 1.0f) { cbuf[0] = b_col_char[0]; cbuf[1] = b_col_char[1]; @@ -667,6 +674,28 @@ float blf_font_fixed_width(FontBLF *font) return g->advance; } +int blf_font_count_missing_chars(FontBLF *font, const char *str, const size_t len, int *r_tot_chars) +{ + int missing = 0; + size_t i = 0; + + *r_tot_chars = 0; + while (i < len) { + unsigned int c; + + if ((c = str[i]) < 0x80) { + i++; + } + else if ((c = BLI_str_utf8_as_unicode_step(str, &i)) != BLI_UTF8_ERR) { + if (FT_Get_Char_Index((font)->face, c) == 0) { + missing++; + } + } + (*r_tot_chars)++; + } + return missing; +} + void blf_font_free(FontBLF *font) { GlyphCacheBLF *gc; diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h index 39b3e3397be..85410a4d856 100644 --- a/source/blender/blenfont/intern/blf_internal.h +++ b/source/blender/blenfont/intern/blf_internal.h @@ -62,6 +62,9 @@ void blf_font_width_and_height(struct FontBLF *font, const char *str, size_t len float blf_font_width(struct FontBLF *font, const char *str, size_t len); float blf_font_height(struct FontBLF *font, const char *str, size_t len); float blf_font_fixed_width(struct FontBLF *font); + +int blf_font_count_missing_chars(struct FontBLF *font, const char *str, const size_t len, int *r_tot_chars); + void blf_font_free(struct FontBLF *font); struct GlyphCacheBLF *blf_glyph_cache_find(struct FontBLF *font, unsigned int size, unsigned int dpi); diff --git a/source/blender/blenfont/intern/blf_thumbs.c b/source/blender/blenfont/intern/blf_thumbs.c index 7c0a43e09ee..4b7a568b8b0 100644 --- a/source/blender/blenfont/intern/blf_thumbs.c +++ b/source/blender/blenfont/intern/blf_thumbs.c @@ -90,6 +90,10 @@ void BLF_thumb_preview( font_size_curr = font_size; for (i = 0; i < draw_str_lines; i++) { + const char *draw_str_i18n = BLF_translate_do(BLF_I18NCONTEXT_DEFAULT, draw_str[i]); + const size_t draw_str_i18n_len = strlen(draw_str_i18n); + int draw_str_i18n_nbr = 0; + blf_font_size(font, (unsigned int)MAX2(font_size_min, font_size_curr), dpi); /* decrease font size each time */ @@ -98,7 +102,19 @@ void BLF_thumb_preview( font->pos[1] -= font->glyph_cache->ascender * 1.1f; - blf_font_buffer(font, BLF_translate_do(BLF_I18NCONTEXT_DEFAULT, draw_str[i])); + /* We fallback to default english strings in case not enough chars are available in current font for given + * translated string (useful in non-latin i18n context, like chinese, since many fonts will then show + * nothing but ugly 'missing char' in their preview). + * Does not handle all cases, but much better than nothing. + */ + if (blf_font_count_missing_chars( + font, draw_str_i18n, draw_str_i18n_len, &draw_str_i18n_nbr) > (draw_str_i18n_nbr / 2)) + { + blf_font_buffer(font, draw_str[i]); + } + else { + blf_font_buffer(font, draw_str_i18n); + } } blf_font_free(font); diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 7502db21132..0465a354f9f 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -53,11 +53,11 @@ void BKE_object_workob_clear(struct Object *workob); void BKE_object_workob_calc_parent(struct Scene *scene, struct Object *ob, struct Object *workob); void BKE_object_transform_copy(struct Object *ob_tar, const struct Object *ob_src); -struct SoftBody *copy_softbody(struct SoftBody *sb, bool copy_caches); +struct SoftBody *copy_softbody(const struct SoftBody *sb, bool copy_caches); struct BulletSoftBody *copy_bulletsoftbody(struct BulletSoftBody *sb); struct ParticleSystem *BKE_object_copy_particlesystem(struct ParticleSystem *psys); -void BKE_object_copy_particlesystems(struct Object *obn, struct Object *ob); -void BKE_object_copy_softbody(struct Object *obn, struct Object *ob); +void BKE_object_copy_particlesystems(struct Object *ob_dst, const struct Object *ob_src); +void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src); void BKE_object_free_particlesystems(struct Object *ob); void BKE_object_free_softbody(struct Object *ob); void BKE_object_free_bulletsoftbody(struct Object *ob); @@ -73,7 +73,7 @@ void BKE_object_modifier_hook_reset(struct Object *ob, struct HookModifierData * bool BKE_object_support_modifier_type_check(struct Object *ob, int modifier_type); -void BKE_object_link_modifiers(struct Object *ob, struct Object *from); +void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src); void BKE_object_free_modifiers(struct Object *ob); void BKE_object_make_proxy(struct Object *ob, struct Object *target, struct Object *gob); diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h index 4584568d4b9..3d67b91d767 100644 --- a/source/blender/blenkernel/BKE_pointcache.h +++ b/source/blender/blenkernel/BKE_pointcache.h @@ -301,7 +301,7 @@ struct PointCache *BKE_ptcache_add(struct ListBase *ptcaches); void BKE_ptcache_free_mem(struct ListBase *mem_cache); void BKE_ptcache_free(struct PointCache *cache); void BKE_ptcache_free_list(struct ListBase *ptcaches); -struct PointCache *BKE_ptcache_copy_list(struct ListBase *ptcaches_new, struct ListBase *ptcaches_old, bool copy_data); +struct PointCache *BKE_ptcache_copy_list(struct ListBase *ptcaches_new, const struct ListBase *ptcaches_old, bool copy_data); /********************** Baking *********************/ diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c index 3f69618b591..b1b32e75f59 100644 --- a/source/blender/blenkernel/intern/appdir.c +++ b/source/blender/blenkernel/intern/appdir.c @@ -632,6 +632,7 @@ bool BKE_appdir_program_python_search( ) { is_found = true; + break; } } } diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index d98dd186977..c850216f5ef 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -1626,7 +1626,7 @@ void rename_id(ID *id, const char *name) void name_uiprefix_id(char *name, const ID *id) { name[0] = id->lib ? 'L' : ' '; - name[1] = id->flag & LIB_FAKEUSER ? 'F' : (id->us == 0) ? '0' : ' '; + name[1] = (id->flag & LIB_FAKEUSER) ? 'F' : ((id->us == 0) ? '0' : ' '); name[2] = ' '; strcpy(name + 3, id->name + 2); diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c index 080a8cead7b..e8418e876bb 100644 --- a/source/blender/blenkernel/intern/mball_tessellate.c +++ b/source/blender/blenkernel/intern/mball_tessellate.c @@ -1233,14 +1233,9 @@ static void init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *scen copy_v3_v3(new_ml->bb->vec[6], tempmax); /* add new_ml to mainb[] */ - if (process->totelem == process->mem) { - MetaElem **newelem; + if (UNLIKELY(process->totelem == process->mem)) { process->mem = process->mem * 2 + 10; - newelem = MEM_mallocN(sizeof(MetaElem *) * process->mem, "metaballs"); - - memcpy(newelem, process->mainb, sizeof(MetaElem *) * process->totelem); - if (process->mainb) MEM_freeN(process->mainb); - process->mainb = newelem; + process->mainb = MEM_reallocN(process->mainb, sizeof(MetaElem *) * process->mem); } process->mainb[process->totelem++] = new_ml; } diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index 302d85e8128..d17ca751c5e 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -372,6 +372,10 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space, const float lnor[3], /* If vec_ref or vec_other are too much aligned with lnor, we can't build lnor space, * tag it as invalid and abort. */ lnor_space->ref_alpha = lnor_space->ref_beta = 0.0f; + + if (edge_vectors) { + BLI_stack_clear(edge_vectors); + } return; } diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index ba62404e88f..5595d824ed0 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -252,7 +252,7 @@ bool BKE_object_support_modifier_type_check(Object *ob, int modifier_type) return true; } -void BKE_object_link_modifiers(struct Object *ob_dst, struct Object *ob_src) +void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src) { ModifierData *md; BKE_object_free_modifiers(ob_dst); @@ -268,8 +268,6 @@ void BKE_object_link_modifiers(struct Object *ob_dst, struct Object *ob_src) if (ELEM(md->type, eModifierType_Hook, - eModifierType_Softbody, - eModifierType_ParticleInstance, eModifierType_Collision)) { continue; @@ -277,10 +275,15 @@ void BKE_object_link_modifiers(struct Object *ob_dst, struct Object *ob_src) if (!BKE_object_support_modifier_type_check(ob_dst, md->type)) continue; - - if (md->type == eModifierType_Skin) { - /* ensure skin-node customdata exists */ - BKE_mesh_ensure_skin_customdata(ob_dst->data); + + switch (md->type) { + case eModifierType_Softbody: + BKE_object_copy_softbody(ob_dst, ob_src); + break; + case eModifierType_Skin: + /* ensure skin-node customdata exists */ + BKE_mesh_ensure_skin_customdata(ob_dst->data); + break; } nmd = modifier_new(md->type); @@ -297,7 +300,6 @@ void BKE_object_link_modifiers(struct Object *ob_dst, struct Object *ob_src) } BKE_object_copy_particlesystems(ob_dst, ob_src); - BKE_object_copy_softbody(ob_dst, ob_src); /* TODO: smoke?, cloth? */ } @@ -1243,7 +1245,7 @@ struct Object *BKE_object_lod_matob_get(Object *ob, Scene *scene) #endif /* WITH_GAMEENGINE */ -SoftBody *copy_softbody(SoftBody *sb, bool copy_caches) +SoftBody *copy_softbody(const SoftBody *sb, bool copy_caches) { SoftBody *sbn; @@ -1363,24 +1365,24 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys) return psysn; } -void BKE_object_copy_particlesystems(Object *obn, Object *ob) +void BKE_object_copy_particlesystems(Object *ob_dst, const Object *ob_src) { ParticleSystem *psys, *npsys; ModifierData *md; - if (obn->type != OB_MESH) { + if (ob_dst->type != OB_MESH) { /* currently only mesh objects can have soft body */ return; } - BLI_listbase_clear(&obn->particlesystem); - for (psys = ob->particlesystem.first; psys; psys = psys->next) { + BLI_listbase_clear(&ob_dst->particlesystem); + for (psys = ob_src->particlesystem.first; psys; psys = psys->next) { npsys = BKE_object_copy_particlesystem(psys); - BLI_addtail(&obn->particlesystem, npsys); + BLI_addtail(&ob_dst->particlesystem, npsys); /* need to update particle modifiers too */ - for (md = obn->modifiers.first; md; md = md->next) { + for (md = ob_dst->modifiers.first; md; md = md->next) { if (md->type == eModifierType_ParticleSystem) { ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md; if (psmd->psys == psys) @@ -1408,10 +1410,12 @@ void BKE_object_copy_particlesystems(Object *obn, Object *ob) } } -void BKE_object_copy_softbody(Object *obn, Object *ob) +void BKE_object_copy_softbody(Object *ob_dst, const Object *ob_src) { - if (ob->soft) - obn->soft = copy_softbody(ob->soft, false); + if (ob_src->soft) { + ob_dst->softflag = ob_src->softflag; + ob_dst->soft = copy_softbody(ob_src->soft, false); + } } static void copy_object_pose(Object *obn, Object *ob) @@ -2151,7 +2155,7 @@ static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4]) } /* vec: 4 items! */ - if (where_on_path(par, ctime, vec, dir, cu->flag & CU_FOLLOW ? quat : NULL, &radius, NULL)) { + if (where_on_path(par, ctime, vec, dir, (cu->flag & CU_FOLLOW) ? quat : NULL, &radius, NULL)) { if (cu->flag & CU_FOLLOW) { #if 0 diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 01bc4a1c237..4711a5900f0 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -3063,7 +3063,7 @@ static PointCache *ptcache_copy(PointCache *cache, bool copy_data) } /* returns first point cache */ -PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new, ListBase *ptcaches_old, bool copy_data) +PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new, const ListBase *ptcaches_old, bool copy_data) { PointCache *cache = ptcaches_old->first; diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index f73b556e412..16f218d5fb6 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -4074,7 +4074,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived( SubsurfFlags flags) { int useSimple = (smd->subdivType == ME_SIMPLE_SUBSURF) ? CCG_SIMPLE_SUBDIV : 0; - CCGFlags useAging = smd->flags & eSubsurfModifierFlag_DebugIncr ? CCG_USE_AGING : 0; + CCGFlags useAging = (smd->flags & eSubsurfModifierFlag_DebugIncr) ? CCG_USE_AGING : 0; int useSubsurfUv = smd->flags & eSubsurfModifierFlag_SubsurfUv; int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges); CCGDerivedMesh *result; diff --git a/source/blender/blenlib/BLI_stack.h b/source/blender/blenlib/BLI_stack.h index a8c4478c450..6d41e5feb88 100644 --- a/source/blender/blenlib/BLI_stack.h +++ b/source/blender/blenlib/BLI_stack.h @@ -48,6 +48,7 @@ void BLI_stack_pop(BLI_Stack *stack, void *dst) ATTR_NONNULL(); void *BLI_stack_peek(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void BLI_stack_discard(BLI_Stack *stack) ATTR_NONNULL(); +void BLI_stack_clear(BLI_Stack *stack) ATTR_NONNULL(); size_t BLI_stack_count(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index b079478f397..9cf360a77e3 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -57,6 +57,7 @@ # include <shlobj.h> # include "BLI_winstuff.h" # include "MEM_guardedalloc.h" +# include "BLI_alloca.h" #else # include "unistd.h" #endif /* WIN32 */ @@ -1033,31 +1034,36 @@ bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen) type = BLI_exists(name); if ((type == 0) || S_ISDIR(type)) { - char filename[FILE_MAX]; - char ext[FILE_MAX]; - const char *extensions = getenv("PATHEXT"); - if (extensions) { - const char *temp; - do { - strcpy(filename, name); - temp = strchr(extensions, ';'); - if (temp) { - strncpy(ext, extensions, temp - extensions); - ext[temp - extensions] = 0; - extensions = temp + 1; - strcat(filename, ext); - } - else { - strcat(filename, extensions); - } + /* typically 3-5, ".EXE", ".BAT"... etc */ + const int ext_max = 12; + const char *ext = getenv("PATHEXT"); + if (ext) { + const int name_len = strlen(name); + char *filename = alloca(name_len + ext_max); + char *filename_ext; + const char *ext_next; + + /* null terminated in the loop */ + memcpy(filename, name, name_len); + filename_ext = filename + name_len; - type = BLI_exists(filename); - if (type && (!S_ISDIR(type))) { - retval = true; - BLI_strncpy(name, filename, maxlen); - break; + do { + int ext_len; + ext_next = strchr(ext, ';'); + ext_len = ext_next ? ((ext_next++) - ext) : strlen(ext); + + if (LIKELY(ext_len < ext_max)) { + memcpy(filename_ext, ext, ext_len); + filename_ext[ext_len] = '\0'; + + type = BLI_exists(filename); + if (type && (!S_ISDIR(type))) { + retval = true; + BLI_strncpy(name, filename, maxlen); + break; + } } - } while (temp); + } while ((ext = ext_next)); } } else { diff --git a/source/blender/blenlib/intern/stack.c b/source/blender/blenlib/intern/stack.c index 2d3a2f77a3e..3c9e1a52cda 100644 --- a/source/blender/blenlib/intern/stack.c +++ b/source/blender/blenlib/intern/stack.c @@ -216,6 +216,41 @@ void BLI_stack_discard(BLI_Stack *stack) } } +/** + * Discards all elements without freeing. + */ +void BLI_stack_clear(BLI_Stack *stack) +{ +#ifdef USE_TOTELEM + if (UNLIKELY(stack->totelem == 0)) { + return; + } + stack->totelem = 0; +#else + if (UNLIKELY(stack->chunk_curr == NULL)) { + return; + } +#endif + + stack->chunk_index = stack->chunk_elem_max - 1; + + if (stack->chunk_free) { + if (stack->chunk_curr) { + /* move all used chunks into tail of free list */ + struct StackChunk *chunk_free_last = stack->chunk_free; + while (chunk_free_last->next) { + chunk_free_last = chunk_free_last->next; + } + chunk_free_last->next = stack->chunk_curr; + stack->chunk_curr = NULL; + } + } + else { + stack->chunk_free = stack->chunk_curr; + stack->chunk_curr = NULL; + } +} + size_t BLI_stack_count(const BLI_Stack *stack) { #ifdef USE_TOTELEM diff --git a/source/blender/blenlib/intern/threads.c b/source/blender/blenlib/intern/threads.c index a404f46a6e2..50295954192 100644 --- a/source/blender/blenlib/intern/threads.c +++ b/source/blender/blenlib/intern/threads.c @@ -199,6 +199,7 @@ void BLI_init_threads(ListBase *threadbase, void *(*do_thread)(void *), int tot) } } + BLI_spin_lock(&_malloc_lock); if (thread_levels == 0) { MEM_set_lock_callback(BLI_lock_malloc_thread, BLI_unlock_malloc_thread); @@ -211,6 +212,7 @@ void BLI_init_threads(ListBase *threadbase, void *(*do_thread)(void *), int tot) } thread_levels++; + BLI_spin_unlock(&_malloc_lock); } /* amount of available threads */ @@ -329,9 +331,11 @@ void BLI_end_threads(ListBase *threadbase) BLI_freelistN(threadbase); } + BLI_spin_lock(&_malloc_lock); thread_levels--; if (thread_levels == 0) MEM_set_lock_callback(NULL, NULL); + BLI_spin_unlock(&_malloc_lock); } /* System Information */ diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c index 95440158277..20ec27a1f4b 100644 --- a/source/blender/blenloader/intern/readblenentry.c +++ b/source/blender/blenloader/intern/readblenentry.c @@ -176,26 +176,38 @@ LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *to prv = BLO_library_read_struct(fd, bhead, "PreviewImage"); if (prv) { memcpy(new_prv, prv, sizeof(PreviewImage)); - if (prv->rect[0]) { + if (prv->rect[0] && prv->w[0] && prv->h[0]) { unsigned int *rect = NULL; - new_prv->rect[0] = MEM_callocN(new_prv->w[0] * new_prv->h[0] * sizeof(unsigned int), "prvrect"); + size_t len = new_prv->w[0] * new_prv->h[0] * sizeof(unsigned int); + new_prv->rect[0] = MEM_callocN(len, __func__); bhead = blo_nextbhead(fd, bhead); rect = (unsigned int *)(bhead + 1); - memcpy(new_prv->rect[0], rect, bhead->len); + BLI_assert(len == bhead->len); + memcpy(new_prv->rect[0], rect, len); } else { + /* This should not be needed, but can happen in 'broken' .blend files, + * better handle this gracefully than crashing. */ + BLI_assert(prv->rect[0] == NULL && prv->w[0] == 0 && prv->h[0] == 0); new_prv->rect[0] = NULL; + new_prv->w[0] = new_prv->h[0] = 0; } - if (prv->rect[1]) { + if (prv->rect[1] && prv->w[1] && prv->h[1]) { unsigned int *rect = NULL; - new_prv->rect[1] = MEM_callocN(new_prv->w[1] * new_prv->h[1] * sizeof(unsigned int), "prvrect"); + size_t len = new_prv->w[1] * new_prv->h[1] * sizeof(unsigned int); + new_prv->rect[1] = MEM_callocN(len, __func__); bhead = blo_nextbhead(fd, bhead); rect = (unsigned int *)(bhead + 1); - memcpy(new_prv->rect[1], rect, bhead->len); + BLI_assert(len == bhead->len); + memcpy(new_prv->rect[1], rect, len); } else { + /* This should not be needed, but can happen in 'broken' .blend files, + * better handle this gracefully than crashing. */ + BLI_assert(prv->rect[1] == NULL && prv->w[1] == 0 && prv->h[1] == 0); new_prv->rect[1] = NULL; + new_prv->w[1] = new_prv->h[1] = 0; } MEM_freeN(prv); } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index c7d0cf99904..1edd694f935 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -1539,6 +1539,10 @@ void blo_make_packed_pointer_map(FileData *fd, Main *oldmain) for (ima = oldmain->image.first; ima; ima = ima->id.next) { ImagePackedFile *imapf; + + if (ima->packedfile) + insert_packedmap(fd, ima->packedfile); + for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) if (imapf->packedfile) insert_packedmap(fd, imapf->packedfile); @@ -1577,6 +1581,9 @@ void blo_end_packed_pointer_map(FileData *fd, Main *oldmain) for (ima = oldmain->image.first; ima; ima = ima->id.next) { ImagePackedFile *imapf; + + ima->packedfile = newpackedadr(fd, ima->packedfile); + for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) imapf->packedfile = newpackedadr(fd, imapf->packedfile); } @@ -2081,7 +2088,7 @@ static void direct_link_cache_library(FileData *fd, CacheLibrary *cachelib) static PackedFile *direct_link_packedfile(FileData *fd, PackedFile *oldpf) { PackedFile *pf = newpackedadr(fd, oldpf); - + if (pf) { pf->data = newpackedadr(fd, pf->data); } @@ -3528,13 +3535,17 @@ static void direct_link_image(FileData *fd, Image *ima) link_list(fd, &(ima->views)); link_list(fd, &(ima->packedfiles)); - ima->packedfile = NULL; - for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) { - imapf->packedfile = direct_link_packedfile(fd, imapf->packedfile); + if (ima->packedfiles.first) { + for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) { + imapf->packedfile = direct_link_packedfile(fd, imapf->packedfile); + } + ima->packedfile = NULL; + } + else { + ima->packedfile = direct_link_packedfile(fd, ima->packedfile); } ima->anims.first = ima->anims.last = NULL; - ima->packedfile = direct_link_packedfile(fd, ima->packedfile); ima->preview = direct_link_preview_image(fd, ima->preview); ima->stereo3d_format = newdataadr(fd, ima->stereo3d_format); ima->ok = 1; diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index 274fc474ade..2727f3a3965 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -766,7 +766,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) bSoundActuator *sAct = (bSoundActuator*) act->data; if (sAct->sound) { sound = blo_do_versions_newlibadr(fd, lib, sAct->sound); - sAct->flag = sound->flags & SOUND_FLAGS_3D ? ACT_SND_3D_SOUND : 0; + sAct->flag = (sound->flags & SOUND_FLAGS_3D) ? ACT_SND_3D_SOUND : 0; sAct->pitch = sound->pitch; sAct->volume = sound->volume; sAct->sound3D.reference_distance = sound->distance; diff --git a/source/blender/bmesh/operators/bmo_hull.c b/source/blender/bmesh/operators/bmo_hull.c index fe4a0204335..2dfad5a1f47 100644 --- a/source/blender/bmesh/operators/bmo_hull.c +++ b/source/blender/bmesh/operators/bmo_hull.c @@ -537,6 +537,9 @@ static void hull_from_bullet( } BLI_array_free(fvi); + + plConvexHullDelete(hull); + MEM_freeN(hull_verts); MEM_freeN(coords); MEM_freeN(input_verts); diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 252c16e8919..5e4b25128f7 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -57,6 +57,9 @@ /* happens far too often, uncomment for development */ // #define BEVEL_ASSERT_PROJECT +/* will likely remove the code enabled by this soon, when sure that it is not needed */ +// #define PRE_275_ALGORITHM + /* for testing */ // #pragma GCC diagnostic error "-Wpadded" @@ -187,7 +190,7 @@ typedef struct BevelParams { bool limit_offset; /* should offsets be limited by collisions? */ const struct MDeformVert *dvert; /* vertex group array, maybe set if vertex_only */ int vertex_group; /* vertex group index, maybe set if vertex_only */ - int mat_nr; /* if >= 0, material number for bevel; else material comes from adjacent faces */ + int mat_nr; /* if >= 0, material number for bevel; else material comes from adjacent faces */ } BevelParams; // #pragma GCC diagnostic ignored "-Wpadded" @@ -484,8 +487,7 @@ static bool contig_ldata_across_edge(BMesh *bm, BMEdge *e, BMFace *f1, BMFace *f } /** - * Like #bev_create_quad_tri, but when verts straddle an old edge. - * + * Like bev_create_quad_tri, but when verts straddle an old edge. * <pre> * e * | @@ -593,10 +595,42 @@ static bool is_outside_edge(EdgeHalf *e, const float co[3], BMVert **ret_closer_ } } +/* co should be approximately on the plane between e1 and e2, which share common vert v + * and common face f (which cannot be NULL). + * Is it between those edges, sweeping CCW? */ +static bool point_between_edges(float co[3], BMVert *v, BMFace *f, EdgeHalf *e1, EdgeHalf *e2) +{ + BMVert *v1, *v2; + float dir1[3], dir2[3], dirco[3], no[3]; + float ang11, ang1co; + + v1 = BM_edge_other_vert(e1->e, v); + v2 = BM_edge_other_vert(e2->e, v); + sub_v3_v3v3(dir1, v->co, v1->co); + sub_v3_v3v3(dir2, v->co, v2->co); + sub_v3_v3v3(dirco, v->co, co); + normalize_v3(dir1); + normalize_v3(dir2); + normalize_v3(dirco); + ang11 = angle_normalized_v3v3(dir1, dir2); + ang1co = angle_normalized_v3v3(dir1, dirco); + /* angles are in [0,pi]. need to compare cross product with normal to see if they are reflex */ + cross_v3_v3v3(no, dir1, dir2); + if (dot_v3v3(no, f->no) < 0.0f) + ang11 = (float)(M_PI * 2.0) - ang11; + cross_v3_v3v3(no, dir1, dirco); + if (dot_v3v3(no, f->no) < 0.0f) + ang1co = (float)(M_PI * 2.0) - ang1co; + return (ang11 - ang1co > -BEVEL_EPSILON_BIG); +} + /* * Calculate the meeting point between the offset edges for e1 and e2, putting answer in meetco. * e1 and e2 share vertex v and face f (may be NULL) and viewed from the normal side of * the bevel vertex, e1 precedes e2 in CCW order. + * Except: if edges_between is true, there are edges between e1 and e2 in CCW order so they + * don't share a common face. We want the meeting point to be on an existing face so it + * should be dropped onto one of the intermediate faces, if possible. * Offset edge is on right of both edges, where e1 enters v and e2 leave it. * When offsets are equal, the new point is on the edge bisector, with length offset/sin(angle/2), * but if the offsets are not equal (allowing for this, as bevel modifier has edge weights that may @@ -605,16 +639,27 @@ static bool is_outside_edge(EdgeHalf *e, const float co[3], BMVert **ret_closer_ * record the change in offset_l (or offset_r); later we can tell that a change has happened because * the offset will differ from its original value in offset_l_spec (or offset_r_spec). */ -static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, float meetco[3]) +static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, bool edges_between, float meetco[3]) { - float dir1[3], dir2[3], norm_v[3], norm_perp1[3], norm_perp2[3], - off1a[3], off1b[3], off2a[3], off2b[3], isect2[3], ang, d; + float dir1[3], dir2[3], dir1n[3], dir2p[3], norm_v[3], norm_v1[3], norm_v2[3], + norm_perp1[3], norm_perp2[3], off1a[3], off1b[3], off2a[3], off2b[3], + isect2[3], dropco[3], plane[4], ang, d; BMVert *closer_v; + EdgeHalf *e, *e1next, *e2prev; + BMFace *ff; + int isect_kind; /* get direction vectors for two offset lines */ sub_v3_v3v3(dir1, v->co, BM_edge_other_vert(e1->e, v)->co); sub_v3_v3v3(dir2, BM_edge_other_vert(e2->e, v)->co, v->co); + if (edges_between) { + e1next = e1->next; + e2prev = e2->prev; + sub_v3_v3v3(dir1n, BM_edge_other_vert(e1next->e, v)->co, v->co); + sub_v3_v3v3(dir2p, v->co, BM_edge_other_vert(e2prev->e, v)->co); + } + ang = angle_v3v3(dir1, dir2); if (ang < BEVEL_EPSILON_BIG) { /* special case: e1 and e2 are parallel; put offset point perp to both, from v. @@ -654,14 +699,31 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, float * If e1-v-e2 is a reflex angle (viewed from vertex normal side), need to flip. * Use f->no to figure out which side to look at angle from, as even if * f is non-planar, will be more accurate than vertex normal */ - cross_v3_v3v3(norm_v, dir2, dir1); - normalize_v3(norm_v); - if (dot_v3v3(norm_v, f ? f->no : v->no) < 0.0f) - negate_v3(norm_v); + if (!edges_between) { + cross_v3_v3v3(norm_v1, dir2, dir1); + normalize_v3(norm_v1); + if (dot_v3v3(norm_v1, f ? f->no : v->no) < 0.0f) + negate_v3(norm_v1); + copy_v3_v3(norm_v2, norm_v1); + } + else { + /* separate faces; get face norms at corners for each separately */ + cross_v3_v3v3(norm_v1, dir1n, dir1); + normalize_v3(norm_v1); + f = e1->fnext; + if (dot_v3v3(norm_v1, f ? f->no : v->no) < 0.0f) + negate_v3(norm_v1); + cross_v3_v3v3(norm_v2, dir2, dir2p); + normalize_v3(norm_v2); + f = e2->fprev; + if (dot_v3v3(norm_v2, f ? f->no : v->no) < 0.0f) + negate_v3(norm_v2); + } + /* get vectors perp to each edge, perp to norm_v, and pointing into face */ - cross_v3_v3v3(norm_perp1, dir1, norm_v); - cross_v3_v3v3(norm_perp2, dir2, norm_v); + cross_v3_v3v3(norm_perp1, dir1, norm_v1); + cross_v3_v3v3(norm_perp2, dir2, norm_v2); normalize_v3(norm_perp1); normalize_v3(norm_perp2); @@ -673,11 +735,10 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, float madd_v3_v3fl(off2a, norm_perp2, e2->offset_l); add_v3_v3v3(off2b, off2a, dir2); - /* intersect the lines; by construction they should be on the same plane and not parallel */ - if (!isect_line_line_v3(off1a, off1b, off2a, off2b, meetco, isect2)) { -#ifdef BEVEL_ASSERT_PROJECT - BLI_assert(!"offset_meet failure"); -#endif + /* intersect the lines */ + isect_kind = isect_line_line_v3(off1a, off1b, off2a, off2b, meetco, isect2); + if (isect_kind == 0) { + /* lines are colinear: we already tested for this, but this used a different epsilon */ copy_v3_v3(meetco, off1a); /* just to do something */ d = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e2->e, v)->co); if (fabsf(d - e2->offset_l) > BEVEL_EPSILON) @@ -697,6 +758,26 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, float copy_v3_v3(meetco, closer_v->co); e1->offset_r = len_v3v3(meetco, v->co); } + if (edges_between && e1->offset_r > 0.0 && e2->offset_l > 0.0) { + /* Try to drop meetco to a face between e1 and e2 */ + if (isect_kind == 2) { + /* lines didn't meet in 3d: get average of meetco and isect2 */ + mid_v3_v3v3(meetco, meetco, isect2); + } + for (e = e1; e != e2; e = e->next) { + ff = e->fnext; + if (!ff) + continue; + plane_from_point_normal_v3(plane, v->co, ff->no); + closest_to_plane_v3(dropco, plane, meetco); + if (point_between_edges(dropco, v, ff, e, e->next)) { + copy_v3_v3(meetco, dropco); + break; + } + } + e1->offset_r = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e1->e, v)->co); + e2->offset_l = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e2->e, v)->co); + } } } } @@ -740,6 +821,17 @@ static bool offset_meet_edge(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, float meetc return true; } +/* Return true if it will look good to put the meeting point where offset_on_edge_between + * would put it. This means that neither side sees a reflex angle */ +static bool good_offset_on_edge_between(EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid, BMVert *v) +{ + float ang; + float meet[3]; + + return offset_meet_edge(e1, emid, v, meet, &ang) && + offset_meet_edge(emid, e2, v, meet, &ang); +} + /* Calculate the best place for a meeting point for the offsets from edges e1 and e2 * on the in-between edge emid. Viewed from the vertex normal side, the CCW * order of these edges is e1, emid, e2. @@ -799,6 +891,7 @@ static void offset_on_edge_between( e2->offset_l = d; } +#ifdef PRE_275_ALGORITHM /* Calculate the best place for a meeting point for the offsets from edges e1 and e2 * when there is an in-between edge emid, and we prefer to have a point that may not * be on emid if that does a better job of keeping offsets at the user spec. @@ -874,6 +967,7 @@ static void offset_in_two_planes( /* else iret == 1 and the lines are coplanar so meetco has the intersection */ } } +#endif /* Offset by e->offset in plane with normal plane_no, on left if left==true, * else on right. If no is NULL, choose an arbitrary plane different @@ -1425,6 +1519,323 @@ static void set_bound_vert_seams(BevVert *bv) } while ((v = v->next) != bv->vmesh->boundstart); } +#ifndef PRE_275_ALGORITHM +/* Is e between two planes where angle between is 180? */ +static bool eh_on_plane(EdgeHalf *e) +{ + float dot; + + if (e->fprev && e->fnext) { + dot = dot_v3v3(e->fprev->no, e->fnext->no); + if (fabsf(dot) <= BEVEL_EPSILON || + fabsf(dot - 1.0f) <= BEVEL_EPSILON) + return true; + } + return false; +} + +/* Calculate the profiles for all the BoundVerts of VMesh vm */ +static void calculate_vm_profiles(BevelParams *bp, BevVert *bv, VMesh *vm) +{ + BoundVert *v; + + v = vm->boundstart; + do { + set_profile_params(bp, bv, v); + calculate_profile(bp, v); + } while ((v = v->next) != vm->boundstart); +} + +/* Implements build_boundary for vertex-only case */ +static void build_boundary_vertex_only(BevelParams *bp, BevVert *bv, bool construct) +{ + VMesh *vm = bv->vmesh; + EdgeHalf *efirst, *e; + BoundVert *v; + float co[3]; + + BLI_assert(bp->vertex_only); + + e = efirst = &bv->edges[0]; + do { + slide_dist(e, bv->v, e->offset_l, co); + if (construct) { + v = add_new_bound_vert(bp->mem_arena, vm, co); + v->efirst = v->elast = e; + e->leftv = v; + } + else { + adjust_bound_vert(e->leftv, co); + } + } while ((e = e->next) != efirst); + + calculate_vm_profiles(bp, bv, vm); + + if (construct) { + set_bound_vert_seams(bv); + if (vm->count == 2) + vm->mesh_kind = M_NONE; + else if (bp->seg == 1) + vm->mesh_kind = M_POLY; + else + vm->mesh_kind = M_ADJ; + } +} + +/* Special case of build_boundary when a single edge is beveled. + * The 'width adjust' part of build_boundary has been done already, and + * efirst is the first beveled edge at vertex bv. */ +static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf *efirst, bool construct) +{ + MemArena *mem_arena = bp->mem_arena; + VMesh *vm = bv->vmesh; + BoundVert *v; + EdgeHalf *e; + const float *no; + float co[3], d; + + e = efirst; + if (bv->edgecount == 2) { + /* only 2 edges in, so terminate the edge with an artificial vertex on the unbeveled edge */ + no = e->fprev ? e->fprev->no : (e->fnext ? e->fnext->no : NULL); + offset_in_plane(e, no, true, co); + if (construct) { + v = add_new_bound_vert(mem_arena, vm, co); + v->efirst = v->elast = v->ebev = e; + e->leftv = v; + } + else { + adjust_bound_vert(e->leftv, co); + } + no = e->fnext ? e->fnext->no : (e->fprev ? e->fprev->no : NULL); + offset_in_plane(e, no, false, co); + if (construct) { + v = add_new_bound_vert(mem_arena, vm, co); + v->efirst = v->elast = e; + e->rightv = v; + } + else { + adjust_bound_vert(e->rightv, co); + } + /* make artifical extra point along unbeveled edge, and form triangle */ + slide_dist(e->next, bv->v, e->offset_l, co); + if (construct) { + v = add_new_bound_vert(mem_arena, vm, co); + v->efirst = v->elast = e->next; + e->next->leftv = e->next->rightv = v; + /* could use M_POLY too, but tri-fan looks nicer)*/ + vm->mesh_kind = M_TRI_FAN; + set_bound_vert_seams(bv); + } + else { + adjust_bound_vert(e->next->leftv, co); + } + } + else { + /* More than 2 edges in. Put on-edge verts on all the other edges + * and join with the beveled edge to make a poly or adj mesh, + * Because e->prev has offset 0, offset_meet will put co on that edge */ + /* TODO: should do something else if angle between e and e->prev > 180 */ + offset_meet(e->prev, e, bv->v, e->fprev, false, co); + if (construct) { + v = add_new_bound_vert(mem_arena, vm, co); + v->efirst = e->prev; + v->elast = v->ebev = e; + e->leftv = v; + e->prev->leftv = v; + } + else { + adjust_bound_vert(e->leftv, co); + } + e = e->next; + offset_meet(e->prev, e, bv->v, e->fprev, false, co); + if (construct) { + v = add_new_bound_vert(mem_arena, vm, co); + v->efirst = e->prev; + v->elast = e; + e->leftv = v; + e->prev->rightv = v; + } + else { + adjust_bound_vert(e->leftv, co); + } + d = len_v3v3(bv->v->co, co); + for (e = e->next; e->next != efirst; e = e->next) { + slide_dist(e, bv->v, d, co); + if (construct) { + v = add_new_bound_vert(mem_arena, vm, co); + v->efirst = v->elast = e; + e->leftv = v; + } + else { + adjust_bound_vert(e->leftv, co); + } + } + } + calculate_vm_profiles(bp, bv, vm); + + if (bv->edgecount >= 3) { + /* special case: snap profile to plane of adjacent two edges */ + v = vm->boundstart; + BLI_assert(v->ebev != NULL); + move_profile_plane(v, v->efirst, v->next->elast); + calculate_profile(bp, v); + } + + if (construct) { + set_bound_vert_seams(bv); + + if (vm->count == 2 && bv->edgecount == 3) { + vm->mesh_kind = M_NONE; + } + else if (vm->count == 3) { + vm->mesh_kind = M_TRI_FAN; + } + else { + vm->mesh_kind = M_POLY; + } + } +} + +/* Make a circular list of BoundVerts for bv, each of which has the coordinates + * of a vertex on the boundary of the beveled vertex bv->v. + * This may adjust some EdgeHalf widths, and there might have to be + * a subsequent pass to make the widths as consistent as possible. + * The first time through, construct will be true and we are making the BoundVerts + * and setting up the BoundVert and EdgeHalf pointers appropriately. + * For a width consistency path, we just recalculate the coordinates of the + * BoundVerts. If the other ends have been (re)built already, then we + * copy the offsets from there to match, else we use the ideal (user-specified) + * widths. + * Also, if construct, decide on the mesh pattern that will be used inside the boundary. + * Doesn't make the actual BMVerts */ +static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) +{ + MemArena *mem_arena = bp->mem_arena; + EdgeHalf *efirst, *e, *e2, *e3, *enip, *eip, *eother; + BoundVert *v; + BevVert *bvother; + VMesh *vm; + float co[3]; + int nip, nnip; + + /* Current bevel does nothing if only one edge into a vertex */ + if (bv->edgecount <= 1) + return; + + if (bp->vertex_only) { + build_boundary_vertex_only(bp, bv, construct); + return; + } + + vm = bv->vmesh; + + /* Find a beveled edge to be efirst. Then for each edge, try matching widths to other end. */ + e = efirst = next_bev(bv, NULL); + BLI_assert(e->is_bev); + do { + eother = find_other_end_edge_half(bp, e, &bvother); + if (eother && bvother->visited && bp->offset_type != BEVEL_AMT_PERCENT) { + /* try to keep bevel even by matching other end offsets */ + e->offset_l = eother->offset_r; + e->offset_r = eother->offset_l; + } + else { + /* reset to user spec */ + e->offset_l = e->offset_l_spec; + e->offset_r = e->offset_r_spec; + } + } while ((e = e->next) != efirst); + + if (bv->selcount == 1) { + /* special case: only one beveled edge in */ + build_boundary_terminal_edge(bp, bv, efirst, construct); + return; + } + + /* Here: there is more than one beveled edge. + * We make BoundVerts to connect the sides of the beveled edges. + * Non-beveled edges in between will just join to the appropriate juncture point. */ + e = efirst; + do { + BLI_assert(e->is_bev); + /* Make the BoundVert for the right side of e; other side will be made + * when the beveled edge to the left of e is handled. + * Analyze edges until next beveled edge. + * They are either "in plane" (preceding and subsequent faces are coplanar) + * or not. The "non-in-plane" edges effect silhouette and we prefer to slide + * along one of those if possible. */ + nip = nnip = 0; /* counts of in-plane / not-in-plane */ + enip = eip = NULL; /* representatives of each */ + for (e2 = e->next; !e2->is_bev; e2 = e2->next) { + if (eh_on_plane(e2)) { + nip++; + eip = e2; + } + else { + nnip++; + enip = e2; + } + } + if (nip == 0 && nnip == 0) { + offset_meet(e, e2, bv->v, e->fnext, false, co); + } + else if (nnip > 0) { + if (nnip == 1 && good_offset_on_edge_between(e, e2, enip, bv->v)) { + offset_on_edge_between(bp, e, e2, enip, bv->v, co); + } + else { + offset_meet(e, e2, bv->v, NULL, true, co); + } + } + else { + /* nip > 0 and nnip == 0 */ + if (nip == 1 && good_offset_on_edge_between(e, e2, eip, bv->v)) { + offset_on_edge_between(bp, e, e2, eip, bv->v, co); + } + else { + offset_meet(e, e2, bv->v, NULL, true, co); + } + } + if (construct) { + v = add_new_bound_vert(mem_arena, vm, co); + v->efirst = e; + v->elast = e2; + v->ebev = e2; + e->rightv = v; + e2->leftv = v; + for (e3 = e->next; e3 != e2; e3 = e3->next) { + e3->leftv = e3->rightv = v; + } + } + else { + adjust_bound_vert(e->rightv, co); + } + e = e2; + } while (e != efirst); + + calculate_vm_profiles(bp, bv, vm); + + if (construct) { + set_bound_vert_seams(bv); + + if (vm->count == 2) { + vm->mesh_kind = M_NONE; + } + else if (efirst->seg == 1) { + vm->mesh_kind = M_POLY; + } + else { + vm->mesh_kind = M_ADJ; + } + } +} +#endif + +#ifdef PRE_275_ALGORITHM +/* This code was used prior to just before the 2.75 Blender release. + * It treated multiple non-beveled edges between beveled ones differently */ + /* Make a circular list of BoundVerts for bv, each of which has the coordinates * of a vertex on the boundary of the beveled vertex bv->v. * This may adjust some EdgeHalf widths, and there might have to be @@ -1519,7 +1930,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) /* handle only left side of beveled edge e here: next iteration should do right side */ if (e->prev->is_bev) { BLI_assert(e->prev != e); /* see: wire edge special case */ - offset_meet(e->prev, e, bv->v, e->fprev, co); + offset_meet(e->prev, e, bv->v, e->fprev, false, co); if (construct) { v = add_new_bound_vert(mem_arena, vm, co); v->efirst = e->prev; @@ -1556,7 +1967,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) } else { /* neither e->prev nor e->prev->prev are beveled: make on-edge on e->prev */ - offset_meet(e->prev, e, bv->v, e->fprev, co); + offset_meet(e->prev, e, bv->v, e->fprev, false, co); if (construct) { v = add_new_bound_vert(mem_arena, vm, co); v->efirst = e->prev; @@ -1580,7 +1991,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) } else if (e->prev->is_bev) { /* on-edge meet between e->prev and e */ - offset_meet(e->prev, e, bv->v, e->fprev, co); + offset_meet(e->prev, e, bv->v, e->fprev, false, co); if (construct) { v = add_new_bound_vert(mem_arena, vm, co); v->efirst = e->prev; @@ -1657,6 +2068,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) } } } +#endif /* Do a global pass to try to make offsets as even as possible. * Consider this graph: diff --git a/source/blender/collada/GeometryExporter.cpp b/source/blender/collada/GeometryExporter.cpp index a0eddadfe78..7c7c57f3305 100644 --- a/source/blender/collada/GeometryExporter.cpp +++ b/source/blender/collada/GeometryExporter.cpp @@ -532,8 +532,8 @@ void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me) // each <source> will get id like meshName + "map-channel-1" int active_uv_index = CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV); for (int a = 0; a < num_layers; a++) { - - if (!this->export_settings->active_uv_only || a == active_uv_index) { + int layer_index = CustomData_get_layer_index_n(&me->ldata, CD_MLOOPUV, a); + if (!this->export_settings->active_uv_only || layer_index == active_uv_index) { MLoopUV *mloops = (MLoopUV *)CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, a); COLLADASW::FloatSourceF source(mSW); diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c index b67ae228b25..a4f5c250b0f 100644 --- a/source/blender/editors/curve/editfont.c +++ b/source/blender/editors/curve/editfont.c @@ -1366,7 +1366,7 @@ static int insert_text_invoke(bContext *C, wmOperator *op, const wmEvent *event) accentcode = 0; } else if (event->utf8_buf[0]) { - BLI_strncpy_wchar_from_utf8(inserted_text, event->utf8_buf, 2); + inserted_text[0] = BLI_str_utf8_as_unicode(event->utf8_buf); ascii = inserted_text[0]; insert_into_textbuf(obedit, ascii); accentcode = 0; diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index c4967da2610..84651134107 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -326,7 +326,7 @@ void UI_draw_widget_scroll(struct uiWidgetColors *wcol, const struct rcti *rect, /* Shortening string helper. */ float UI_text_clip_middle_ex( struct uiFontStyle *fstyle, char *str, float okwidth, const float minwidth, - const size_t max_len, const char *rpart_sep); + const size_t max_len, const char rpart_sep); /* Callbacks * @@ -750,7 +750,7 @@ void UI_panel_category_draw_all(struct ARegion *ar, const * as screen/ if ED_KEYMAP_UI is set, or internally in popup functions. */ void UI_region_handlers_add(struct ListBase *handlers); -void UI_popup_handlers_add(struct bContext *C, struct ListBase *handlers, uiPopupBlockHandle *popup, const bool accept_dbl_click); +void UI_popup_handlers_add(struct bContext *C, struct ListBase *handlers, uiPopupBlockHandle *popup, const char flag); void UI_popup_handlers_remove(struct ListBase *handlers, uiPopupBlockHandle *popup); void UI_popup_handlers_remove_all(struct bContext *C, struct ListBase *handlers); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 1eadd259295..e045db8fdd2 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -83,11 +83,11 @@ #define B_NOP -1 -/* - * a full doc with API notes can be found in bf-blender/trunk/blender/doc/guides/interface_API.txt +/** + * a full doc with API notes can be found in 'blender/doc/guides/interface_API.txt' * - * uiBlahBlah() external function - * ui_blah_blah() internal function + * `uiBlahBlah()` external function. + * `ui_blah_blah()` internal function. */ static void ui_but_free(const bContext *C, uiBut *but); @@ -1100,13 +1100,16 @@ static bool ui_but_event_property_operator_string(const bContext *C, uiBut *but, return found; } -/* this goes in a seemingly weird pattern: +/** + * This goes in a seemingly weird pattern: * + * <pre> * 4 * 5 6 * 1 2 * 7 8 * 3 + * </pre> * * but it's actually quite logical. It's designed to be 'upwards compatible' * for muscle memory so that the menu item locations are fixed and don't move @@ -3098,13 +3101,13 @@ void ui_block_cm_to_scene_linear_v3(uiBlock *block, float pixel[3]) /** * \brief ui_def_but is the function that draws many button types * - * \param x,y The lower left hand corner of the button (X axis) - * \param width,height The size of the button. + * \param x, y: The lower left hand corner of the button (X axis) + * \param width, height: The size of the button. * * for float buttons: - * - \a a1 Click Step (how much to change the value each click) - * - \a a2 Number of decimal point values to display. 0 defaults to 3 (0.000) - * 1,2,3, and a maximum of 4, all greater values will be clamped to 4. + * \param a1: Click Step (how much to change the value each click) + * \param a2: Number of decimal point values to display. 0 defaults to 3 (0.000) + * 1,2,3, and a maximum of 4, all greater values will be clamped to 4. */ static uiBut *ui_def_but( uiBlock *block, int type, int retval, const char *str, @@ -4321,8 +4324,11 @@ uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxle } -/* arg is user value, searchfunc and handlefunc both get it as arg */ -/* if active set, button opens with this item visible and selected */ +/** + * \param sfunc, bfunc: both get it as \a arg. + * \param arg: user value, + * \param active: when set, button opens with this item visible and selected. + */ void UI_but_func_search_set(uiBut *but, uiButSearchFunc sfunc, void *arg, uiButHandleFunc bfunc, void *active) { but->search_func = sfunc; @@ -4391,8 +4397,10 @@ static void operator_enum_call_cb(struct bContext *UNUSED(C), void *but, void *a } } -/* Same parameters as for uiDefSearchBut, with additional operator type and properties, used by callback - * to call again the right op with the right options (properties values). */ +/** + * Same parameters as for uiDefSearchBut, with additional operator type and properties, used by callback + * to call again the right op with the right options (properties values). + */ uiBut *uiDefSearchButO_ptr( uiBlock *block, wmOperatorType *ot, IDProperty *properties, void *arg, int retval, int icon, int maxlen, int x, int y, @@ -4415,7 +4423,8 @@ uiBut *uiDefSearchButO_ptr( return but; } -/* push a new event onto event queue to activate the given button +/** + * push a new event onto event queue to activate the given button * (usually a text-field) upon entering a popup */ void UI_but_focus_on_enter_event(wmWindow *win, uiBut *but) @@ -4448,7 +4457,19 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...) if (type == BUT_GET_LABEL) { if (but->str) { - tmp = BLI_strdup(but->str); + const char *str_sep; + size_t str_len; + + if ((but->flag & UI_BUT_HAS_SEP_CHAR) && + (str_sep = strrchr(but->str, UI_SEP_CHAR))) + { + str_len = (str_sep - but->str); + } + else { + str_len = strlen(but->str); + } + + tmp = BLI_strdupn(but->str, str_len); } else { type = BUT_GET_RNA_LABEL; /* Fail-safe solution... */ diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c index 44e06bab4ab..4f77185fb8f 100644 --- a/source/blender/editors/interface/interface_eyedropper.c +++ b/source/blender/editors/interface/interface_eyedropper.c @@ -379,12 +379,11 @@ void UI_OT_eyedropper_color(wmOperatorType *ot) /* -------------------------------------------------------------------- */ -/* Data Dropper - * - * note: datadropper is only internal name to avoid confusion in this file - */ +/* Data Dropper */ /** \name Eyedropper (ID data-blocks) + * + * \note: datadropper is only internal name to avoid confusion in this file. * \{ */ typedef struct DataDropper { @@ -653,12 +652,11 @@ void UI_OT_eyedropper_id(wmOperatorType *ot) /* -------------------------------------------------------------------- */ -/* Depth Dropper - * - * note: depthdropper is only internal name to avoid confusion in this file - */ +/* Depth Dropper */ /** \name Eyedropper (Depth) + * + * \note: depthdropper is only internal name to avoid confusion in this file. * \{ */ typedef struct DepthDropper { diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 83198ae857e..4ec990bb832 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -198,7 +198,7 @@ static void ui_selectcontext_apply( #define IS_ALLSELECT_EVENT(event) ((event)->alt != 0) -/* just show a tinted color so users know its activated */ +/** just show a tinted color so users know its activated */ #define UI_BUT_IS_SELECT_CONTEXT UI_BUT_NODE_ACTIVE #endif /* USE_ALLSELECT */ @@ -206,15 +206,18 @@ static void ui_selectcontext_apply( #ifdef USE_DRAG_MULTINUM -/* how far to drag before we check for gesture direction (in pixels), +/** + * how far to drag before we check for gesture direction (in pixels), * note: half the height of a button is about right... */ #define DRAG_MULTINUM_THRESHOLD_DRAG_X (UI_UNIT_Y / 4) -/* how far to drag horizontally before we stop checking which buttons the gesture spans (in pixels), +/** + * how far to drag horizontally before we stop checking which buttons the gesture spans (in pixels), * locking down the buttons so we can drag freely without worrying about vertical movement. */ #define DRAG_MULTINUM_THRESHOLD_DRAG_Y (UI_UNIT_Y / 4) -/* how strict to be when detecting a vertical gesture, [0.5 == sloppy], [0.9 == strict], (unsigned dot-product) +/** + * how strict to be when detecting a vertical gesture, [0.5 == sloppy], [0.9 == strict], (unsigned dot-product) * note: we should be quite strict here, since doing a vertical gesture by accident should be avoided, * however with some care a user should be able to do a vertical movement without *missing*. */ #define DRAG_MULTINUM_THRESHOLD_VERTICAL (0.75f) @@ -1626,10 +1629,11 @@ static bool ui_but_drag_init(bContext *C, uiBut *but, uiHandleButtonData *data, ar_prev = CTX_wm_region(C); CTX_wm_region_set(C, data->region); - WM_event_add_ui_handler(C, &data->window->modalhandlers, - ui_handler_region_drag_toggle, - ui_handler_region_drag_toggle_remove, - drag_info, false); + WM_event_add_ui_handler( + C, &data->window->modalhandlers, + ui_handler_region_drag_toggle, + ui_handler_region_drag_toggle_remove, + drag_info, WM_HANDLER_BLOCKING); CTX_wm_region_set(C, ar_prev); } @@ -1942,6 +1946,7 @@ static void ui_apply_but(bContext *C, uiBlock *block, uiBut *but, uiHandleButton if (data->str) MEM_freeN(data->str); data->str = data->origstr; + data->origstr = NULL; data->value = data->origvalue; copy_v3_v3(data->vec, data->origvec); /* postpone clearing origdata */ @@ -2085,7 +2090,6 @@ static void ui_apply_but(bContext *C, uiBlock *block, uiBut *but, uiHandleButton #endif if (data->cancel) { - data->origstr = NULL; data->origvalue = 0.0; zero_v3(data->origvec); } @@ -2350,15 +2354,17 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, } } -/* ************************ password text ****************************** +/** + * Password Text + * ============= * * Functions to convert password strings that should not be displayed - * to asterisk representation (e.g. mysecretpasswd -> *************) + * to asterisk representation (e.g. 'mysecretpasswd' -> '*************') * * It converts every UTF-8 character to an asterisk, and also remaps * the cursor position and selection start/end. * - * Note: remaping is used, because password could contain UTF-8 characters. + * \note: remaping is used, because password could contain UTF-8 characters. * */ @@ -2558,7 +2564,8 @@ static void ui_textedit_set_cursor_select(uiBut *but, uiHandleButtonData *data, ui_but_update(but); } -/* this is used for both utf8 and ascii, its meant to be used for single keys, +/** + * This is used for both utf8 and ascii, its meant to be used for single keys, * notice the buffer is either copied or not, so its not suitable for pasting in * - campbell */ static bool ui_textedit_type_buf( @@ -7540,7 +7547,7 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s if (!(but->block->handle && but->block->handle->popup)) { if (button_modal_state(state)) { if (!button_modal_state(data->state)) - WM_event_add_ui_handler(C, &data->window->modalhandlers, ui_handler_region_menu, NULL, data, false); + WM_event_add_ui_handler(C, &data->window->modalhandlers, ui_handler_region_menu, NULL, data, 0); } else { if (button_modal_state(data->state)) { @@ -8424,13 +8431,14 @@ static void ui_handle_button_return_submenu(bContext *C, const wmEvent *event, u /* ************************* menu handling *******************************/ -/* function used to prevent loosing the open menu when using nested pulldowns, +/** + * Function used to prevent loosing the open menu when using nested pulldowns, * when moving mouse towards the pulldown menu over other buttons that could * steal the highlight from the current button, only checks: * * - while mouse moves in triangular area defined old mouse position and - * left/right side of new menu - * - only for 1 second + * left/right side of new menu. + * - only for 1 second. */ static void ui_mouse_motion_towards_init_ex(uiPopupBlockHandle *menu, const int xy[2], const bool force) @@ -9855,12 +9863,12 @@ static void ui_popup_handler_remove(bContext *C, void *userdata) void UI_region_handlers_add(ListBase *handlers) { WM_event_remove_ui_handler(handlers, ui_region_handler, ui_region_handler_remove, NULL, false); - WM_event_add_ui_handler(NULL, handlers, ui_region_handler, ui_region_handler_remove, NULL, false); + WM_event_add_ui_handler(NULL, handlers, ui_region_handler, ui_region_handler_remove, NULL, 0); } -void UI_popup_handlers_add(bContext *C, ListBase *handlers, uiPopupBlockHandle *popup, const bool accept_dbl_click) +void UI_popup_handlers_add(bContext *C, ListBase *handlers, uiPopupBlockHandle *popup, const char flag) { - WM_event_add_ui_handler(C, handlers, ui_popup_handler, ui_popup_handler_remove, popup, accept_dbl_click); + WM_event_add_ui_handler(C, handlers, ui_popup_handler, ui_popup_handler_remove, popup, flag); } void UI_popup_handlers_remove(ListBase *handlers, uiPopupBlockHandle *popup) diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index f6e0273560e..279d72819be 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -2729,7 +2729,8 @@ uiLayout *uiLayoutBox(uiLayout *layout) return (uiLayout *)ui_layout_box(layout, UI_BTYPE_ROUNDBOX); } -/* Check all buttons defined in this layout, and set any button flagged as UI_BUT_LIST_ITEM as active/selected. +/** + * Check all buttons defined in this layout, and set any button flagged as UI_BUT_LIST_ITEM as active/selected. * Needed to handle correctly text colors of active (selected) list item. */ void ui_layout_list_set_labels_active(uiLayout *layout) diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 770bbc12853..88da91acc36 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -763,10 +763,12 @@ static void UI_OT_editsource(wmOperatorType *ot) } /* ------------------------------------------------------------------------- */ -/* EditTranslation utility funcs and operator, - * Note: this includes utility functions and button matching checks. - * this only works in conjunction with a py operator! */ +/** + * EditTranslation utility funcs and operator, + * \note: this includes utility functions and button matching checks. + * this only works in conjunction with a py operator! + */ static void edittranslation_find_po_file(const char *root, const char *uilng, char *path, const size_t maxlen) { char tstr[32]; /* Should be more than enough! */ diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 4b0585c34b3..665266edb9f 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -210,8 +210,9 @@ static void ui_panel_copy_offset(Panel *pa, Panel *papar) } -/* XXX Disabled paneltab handling for now. Old 2.4x feature, *DO NOT* confuse it with new tool tabs in 2.70. ;) - * See also T41704. +/** + * XXX Disabled paneltab handling for now. Old 2.4x feature, *DO NOT* confuse it with new tool tabs in 2.70. ;) + * See also T41704. */ /* #define UI_USE_PANELTAB */ @@ -568,6 +569,8 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con rcti headrect; rctf itemrect; int ofsx; + const bool is_closed_x = (panel->flag & PNL_CLOSEDX) ? true : false; + const bool is_closed_y = (panel->flag & PNL_CLOSEDY) ? true : false; if (panel->paneltab) return; if (panel->type && (panel->type->flag & PNL_NO_HEADER)) return; @@ -580,7 +583,7 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con { float minx = rect->xmin; - float maxx = rect->xmax; + float maxx = is_closed_x ? (minx + PNL_HEADER / block->aspect) : rect->xmax; float y = headrect.ymax; glEnable(GL_BLEND); @@ -595,8 +598,11 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con } else if (!(panel->runtime_flag & PNL_FIRST)) { /* draw embossed separator */ - minx += 5.0f / block->aspect; - maxx -= 5.0f / block->aspect; + + if (is_closed_x == false) { + minx += 5.0f / block->aspect; + maxx -= 5.0f / block->aspect; + } glColor4f(0.0f, 0.0f, 0.0f, 0.5f); fdrawline(minx, y, maxx, y); @@ -623,7 +629,7 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con } /* horizontal title */ - if (!(panel->flag & PNL_CLOSEDX)) { + if (is_closed_x == false) { ui_draw_aligned_panel_header(style, block, &headrect, 'h'); /* itemrect smaller */ @@ -639,9 +645,10 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con /* if the panel is minimized vertically: * (------) */ - if (panel->flag & PNL_CLOSEDY) { + if (is_closed_y) { + /* skip */ } - else if (panel->flag & PNL_CLOSEDX) { + else if (is_closed_x) { /* draw vertical title */ ui_draw_aligned_panel_header(style, block, &headrect, 'v'); } @@ -688,9 +695,9 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con BLI_rctf_scale(&itemrect, 0.35f); - if (panel->flag & PNL_CLOSEDY) + if (is_closed_y) ui_draw_tria_rect(&itemrect, 'h'); - else if (panel->flag & PNL_CLOSEDX) + else if (is_closed_x) ui_draw_tria_rect(&itemrect, 'h'); else ui_draw_tria_rect(&itemrect, 'v'); @@ -737,11 +744,13 @@ typedef struct PanelSort { Panel *pa, *orig; } PanelSort; -/* note about sorting; +/** + * \note about sorting; * the sortorder has a lower value for new panels being added. * however, that only works to insert a single panel, when more new panels get * added the coordinates of existing panels and the previously stored to-be-inserted - * panels do not match for sorting */ + * panels do not match for sorting + */ static int find_leftmost_panel(const void *a1, const void *a2) { @@ -1285,7 +1294,7 @@ static void ui_panel_drag_collapse_handler_add(const bContext *C, const bool was C, &win->modalhandlers, ui_panel_drag_collapse_handler, ui_panel_drag_collapse_handler_remove, - dragcol_data, false); + dragcol_data, 0); } /* this function is supposed to call general window drawing too */ @@ -2098,7 +2107,7 @@ static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelStat data = MEM_callocN(sizeof(uiHandlePanelData), "uiHandlePanelData"); pa->activedata = data; - WM_event_add_ui_handler(C, &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, pa, false); + WM_event_add_ui_handler(C, &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, pa, 0); } if (ELEM(state, PANEL_STATE_ANIMATION, PANEL_STATE_DRAG)) diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 3f323de131b..9835f0885b6 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -70,8 +70,9 @@ #include "interface_intern.h" -#define MENU_TOP 8 +#define MENU_TOP (int)(8 * UI_DPI_FAC) #define MENU_PADDING (int)(0.2f * UI_UNIT_Y) +#define MENU_BORDER (int)(0.3f * U.widget_unit) static int rna_property_enum_step(const bContext *C, PointerRNA *ptr, PropertyRNA *prop, int direction) { @@ -827,8 +828,8 @@ static void ui_searchbox_butrect(rcti *r_rect, uiSearchboxData *data, int itemnr { /* thumbnail preview */ if (data->preview) { - int butw = BLI_rcti_size_x(&data->bbox) / data->prv_cols; - int buth = (BLI_rcti_size_y(&data->bbox) - 2 * MENU_TOP) / data->prv_rows; + int butw = (BLI_rcti_size_x(&data->bbox) - 2 * MENU_BORDER) / data->prv_cols; + int buth = (BLI_rcti_size_y(&data->bbox) - 2 * MENU_BORDER) / data->prv_rows; int row, col; *r_rect = data->bbox; @@ -836,10 +837,10 @@ static void ui_searchbox_butrect(rcti *r_rect, uiSearchboxData *data, int itemnr col = itemnr % data->prv_cols; row = itemnr / data->prv_cols; - r_rect->xmin += col * butw; + r_rect->xmin += MENU_BORDER + (col * butw); r_rect->xmax = r_rect->xmin + butw; - r_rect->ymax = data->bbox.ymax - MENU_TOP - (row * buth); + r_rect->ymax -= MENU_BORDER + (row * buth); r_rect->ymin = r_rect->ymax - buth; } /* list view */ @@ -1159,25 +1160,27 @@ ARegion *ui_searchbox_create(bContext *C, ARegion *butregion, uiBut *but) /* compute position */ if (but->block->flag & UI_BLOCK_SEARCH_MENU) { - const int margin = UI_POPUP_MARGIN; + const int margin_x = UI_POPUP_MARGIN; + const int margin_y = MENU_TOP; + const int search_but_h = BLI_rctf_size_y(&but->rect) + 10; /* this case is search menu inside other menu */ /* we copy region size */ ar->winrct = butregion->winrct; /* widget rect, in region coords */ - data->bbox.xmin = margin; - data->bbox.xmax = BLI_rcti_size_x(&ar->winrct) - margin; + data->bbox.xmin = margin_x; + data->bbox.xmax = BLI_rcti_size_x(&ar->winrct) - margin_x; /* Do not use shadow width for height, gives insane margin with big shadows, and issue T41548 with small ones */ - data->bbox.ymin = 8 * UI_DPI_FAC; - data->bbox.ymax = BLI_rcti_size_y(&ar->winrct) - 8 * UI_DPI_FAC; + data->bbox.ymin = margin_y; + data->bbox.ymax = BLI_rcti_size_y(&ar->winrct) - margin_y; /* check if button is lower half */ if (but->rect.ymax < BLI_rctf_cent_y(&but->block->rect)) { - data->bbox.ymin += BLI_rctf_size_y(&but->rect); + data->bbox.ymin += search_but_h; } else { - data->bbox.ymax -= BLI_rctf_size_y(&but->rect); + data->bbox.ymax -= search_but_h; } } else { @@ -2617,7 +2620,7 @@ uiPopupBlockHandle *ui_popup_menu_create( if (!but) { handle->popup = true; - UI_popup_handlers_add(C, &window->modalhandlers, handle, false); + UI_popup_handlers_add(C, &window->modalhandlers, handle, 0); WM_event_add_mousemove(C); } @@ -2679,7 +2682,7 @@ void UI_popup_menu_end(bContext *C, uiPopupMenu *pup) menu = ui_popup_block_create(C, NULL, NULL, NULL, ui_block_func_POPUP, pup); menu->popup = true; - UI_popup_handlers_add(C, &window->modalhandlers, menu, false); + UI_popup_handlers_add(C, &window->modalhandlers, menu, 0); WM_event_add_mousemove(C); MEM_freeN(pup); @@ -2805,7 +2808,9 @@ void UI_pie_menu_end(bContext *C, uiPieMenu *pie) menu->popup = true; menu->towardstime = PIL_check_seconds_timer(); - UI_popup_handlers_add(C, &window->modalhandlers, menu, true); + UI_popup_handlers_add( + C, &window->modalhandlers, + menu, WM_HANDLER_ACCEPT_DBL_CLICK); WM_event_add_mousemove(C); MEM_freeN(pie); @@ -2997,7 +3002,7 @@ void UI_popup_block_invoke_ex(bContext *C, uiBlockCreateFunc func, void *arg, co handle->optype = (opname) ? WM_operatortype_find(opname, 0) : NULL; handle->opcontext = opcontext; - UI_popup_handlers_add(C, &window->modalhandlers, handle, false); + UI_popup_handlers_add(C, &window->modalhandlers, handle, 0); WM_event_add_mousemove(C); } @@ -3020,7 +3025,7 @@ void UI_popup_block_ex(bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc po handle->cancel_func = cancel_func; // handle->opcontext = opcontext; - UI_popup_handlers_add(C, &window->modalhandlers, handle, false); + UI_popup_handlers_add(C, &window->modalhandlers, handle, 0); WM_event_add_mousemove(C); } @@ -3039,18 +3044,21 @@ void uiPupBlockOperator(bContext *C, uiBlockCreateFunc func, wmOperator *op, int handle->cancel_func = confirm_cancel_operator; handle->opcontext = opcontext; - UI_popup_handlers_add(C, &window->modalhandlers, handle); + UI_popup_handlers_add(C, &window->modalhandlers, handle, 0); WM_event_add_mousemove(C); } #endif void UI_popup_block_close(bContext *C, uiBlock *block) { - if (block->handle) { - wmWindow *win = CTX_wm_window(C); + wmWindow *win = CTX_wm_window(C); + + /* check window before 'block->handle' incase the + * popup execution closed the window and freed the block. see T44688. */ - /* if loading new .blend while popup is open, window will be NULL */ - if (win) { + /* if loading new .blend while popup is open, window will be NULL */ + if (win) { + if (block->handle) { UI_popup_handlers_remove(&win->modalhandlers, block->handle); ui_popup_block_free(C, block->handle); } diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c index 4b683f3fcc2..10575fcbc54 100644 --- a/source/blender/editors/interface/interface_style.c +++ b/source/blender/editors/interface/interface_style.c @@ -64,7 +64,7 @@ /* style + theme + layout-engine = UI */ -/* +/** * This is a complete set of layout rules, the 'state' of the Layout * Engine. Multiple styles are possible, defined via C or Python. Styles * get a name, and will typically get activated per region type, like diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 7ed3c25768c..e6e8a96dd8d 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -190,10 +190,10 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem) /* preview thumbnails */ if (template.prv_rows > 0 && template.prv_cols > 0) { int w = 4 * U.widget_unit * template.prv_cols; - int h = 4 * U.widget_unit * template.prv_rows + U.widget_unit; + int h = 5 * U.widget_unit * template.prv_rows; /* fake button, it holds space for search items */ - uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 15, w, h, NULL, 0, 0, 0, 0, NULL); + uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 26, w, h, NULL, 0, 0, 0, 0, NULL); but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 0, w, UI_UNIT_Y, template.prv_rows, template.prv_cols, ""); @@ -366,7 +366,8 @@ static const char *template_id_browse_tip(StructRNA *type) return N_("Browse ID data to be linked"); } -/* Return a type-based i18n context, needed e.g. by "New" button. +/** + * \return a type-based i18n context, needed e.g. by "New" button. * In most languages, this adjective takes different form based on gender of type name... */ #ifdef WITH_INTERNATIONAL @@ -692,7 +693,8 @@ void uiTemplateIDPreview( /************************ ID Chooser Template ***************************/ -/* This is for selecting the type of ID-block to use, and then from the relevant type choosing the block to use +/** + * This is for selecting the type of ID-block to use, and then from the relevant type choosing the block to use * * - propname: property identifier for property that ID-pointer gets stored to * - proptypename: property identifier for property used to determine the type of ID-pointer that can be used @@ -752,7 +754,8 @@ void uiTemplateAnyID( /* ---------- */ -/* This is creating/editing RNA-Paths +/** + * This is creating/editing RNA-Paths * * - ptr: struct which holds the path property * - propname: property identifier for property that path gets stored to @@ -1670,7 +1673,7 @@ static uiBlock *ui_icon_view_menu_cb(bContext *C, ARegion *ar, void *arg_litem) int x, y; /* XXX hardcoded size to 5 units */ const int w = UI_UNIT_X * 5; - const int h = args.show_labels ? (int)(6.25f * UI_UNIT_Y) : UI_UNIT_Y * 5; + const int h = args.show_labels ? 6 * UI_UNIT_Y : UI_UNIT_Y * 5; x = (a % 8) * w; y = (a / 8) * h; @@ -2483,10 +2486,10 @@ static void handle_layer_buttons(bContext *C, void *arg1, void *arg2) /* see view3d_header.c */ } -/* TODO: - * - for now, grouping of layers is determined by dividing up the length of - * the array of layer bitflags */ - +/** + * \todo for now, grouping of layers is determined by dividing up the length of + * the array of layer bitflags + */ void uiTemplateLayers( uiLayout *layout, PointerRNA *ptr, const char *propname, PointerRNA *used_ptr, const char *used_propname, int active_layer) @@ -2627,10 +2630,11 @@ void uiTemplateGameStates( /************************* List Template **************************/ -static void uilist_draw_item_default(struct uiList *ui_list, struct bContext *UNUSED(C), struct uiLayout *layout, - struct PointerRNA *UNUSED(dataptr), struct PointerRNA *itemptr, int icon, - struct PointerRNA *UNUSED(active_dataptr), const char *UNUSED(active_propname), - int UNUSED(index), int UNUSED(flt_flag)) +static void uilist_draw_item_default( + struct uiList *ui_list, struct bContext *UNUSED(C), struct uiLayout *layout, + struct PointerRNA *UNUSED(dataptr), struct PointerRNA *itemptr, int icon, + struct PointerRNA *UNUSED(active_dataptr), const char *UNUSED(active_propname), + int UNUSED(index), int UNUSED(flt_flag)) { PropertyRNA *nameprop = RNA_struct_name_property(itemptr->type); diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index fb7b319b720..8190df678e2 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -65,9 +65,9 @@ #define ICON_SIZE_FROM_BUTRECT(rect) (0.8f * BLI_rcti_size_y(rect)) /* ************** widget base functions ************** */ -/* +/** * - in: roundbox codes for corner types and radius - * - return: array of [size][2][x,y] points, the edges of the roundbox, + UV coords + * - return: array of `[size][2][x, y]` points, the edges of the roundbox, + UV coords * * - draw black box with alpha 0 on exact button boundbox * - for every AA step: @@ -100,14 +100,14 @@ typedef struct uiWidgetBase { float inner_v[WIDGET_SIZE_MAX][2]; float inner_uv[WIDGET_SIZE_MAX][2]; - bool inner, outline, emboss, shadedir; + bool draw_inner, draw_outline, draw_emboss, draw_shadedir; uiWidgetTrias tria1; uiWidgetTrias tria2; } uiWidgetBase; -/* uiWidgetType: for time being only for visual appearance, +/** uiWidgetType: for time being only for visual appearance, * later, a handling callback can be added too */ typedef struct uiWidgetType { @@ -237,10 +237,10 @@ static void widget_init(uiWidgetBase *wtb) wtb->tria1.tot = 0; wtb->tria2.tot = 0; - wtb->inner = 1; - wtb->outline = 1; - wtb->emboss = 1; - wtb->shadedir = 1; + wtb->draw_inner = true; + wtb->draw_outline = true; + wtb->draw_emboss = true; + wtb->draw_shadedir = true; } /* helper call, makes shadow rect, with 'sun' above menu, so only shadow to left/right/bottom */ @@ -647,7 +647,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) glEnable(GL_BLEND); /* backdrop non AA */ - if (wtb->inner) { + if (wtb->draw_inner) { if (wcol->shaded == 0) { if (wcol->alpha_check) { float inner_v_half[WIDGET_SIZE_MAX][2]; @@ -713,7 +713,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) glShadeModel(GL_SMOOTH); for (a = 0; a < wtb->totvert; a++, col_pt += 4) { - round_box_shade_col4_r(col_pt, col1, col2, wtb->inner_uv[a][wtb->shadedir]); + round_box_shade_col4_r(col_pt, col1, col2, wtb->inner_uv[a][wtb->draw_shadedir ? 1 : 0]); } glEnableClientState(GL_VERTEX_ARRAY); @@ -729,7 +729,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) } /* for each AA step */ - if (wtb->outline) { + if (wtb->draw_outline) { float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */ float triangle_strip_emboss[WIDGET_SIZE_MAX * 2][2]; /* only for emboss */ @@ -740,7 +740,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) widget_verts_to_triangle_strip(wtb, wtb->totvert, triangle_strip); - if (wtb->emboss) { + if (wtb->draw_emboss) { widget_verts_to_triangle_strip_open(wtb, wtb->halfwayvert, triangle_strip_emboss); } @@ -758,7 +758,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) glDrawArrays(GL_TRIANGLE_STRIP, 0, wtb->totvert * 2 + 2); /* emboss bottom shadow */ - if (wtb->emboss) { + if (wtb->draw_emboss) { UI_GetThemeColor4ubv(TH_WIDGET_EMBOSS, emboss); if (emboss[3]) { @@ -929,7 +929,8 @@ static void ui_text_clip_give_next_off(uiBut *but, const char *str) but->ofs += bytes; } -/* Helper. +/** + * Helper. * This func assumes things like kerning handling have already been handled! * Return the length of modified (right-clipped + ellipsis) string. */ @@ -969,7 +970,7 @@ static void ui_text_clip_right_ex( */ float UI_text_clip_middle_ex( uiFontStyle *fstyle, char *str, float okwidth, const float minwidth, - const size_t max_len, const char *rpart_sep) + const size_t max_len, const char rpart_sep) { float strwidth; @@ -1002,7 +1003,7 @@ float UI_text_clip_middle_ex( size_t final_lpart_len; if (rpart_sep) { - rpart = strstr(str, rpart_sep); + rpart = strrchr(str, rpart_sep); if (rpart) { rpart_len = strlen(rpart); @@ -1084,14 +1085,14 @@ static void ui_text_clip_middle(uiFontStyle *fstyle, uiBut *but, const rcti *rec const float minwidth = (float)(UI_DPI_ICON_SIZE) / but->block->aspect * 2.0f; but->ofs = 0; - but->strwidth = UI_text_clip_middle_ex(fstyle, but->drawstr, okwidth, minwidth, max_len, NULL); + but->strwidth = UI_text_clip_middle_ex(fstyle, but->drawstr, okwidth, minwidth, max_len, '\0'); } /** * Like ui_text_clip_middle(), but protect/preserve at all cost the right part of the string after sep. * Useful for strings with shortcuts (like 'AVeryLongFooBarLabelForMenuEntry|Ctrl O' -> 'AVeryLong...MenuEntry|Ctrl O'). */ -static void ui_text_clip_middle_protect_right(uiFontStyle *fstyle, uiBut *but, const rcti *rect, const char *rsep) +static void ui_text_clip_middle_protect_right(uiFontStyle *fstyle, uiBut *but, const rcti *rect, const char rsep) { /* No margin for labels! */ const int border = ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_MENU) ? 0 : (int)(UI_TEXT_CLIP_MARGIN + 0.5f); @@ -1525,17 +1526,14 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB /* Big previews with optional text label below */ if (but->flag & UI_BUT_ICON_PREVIEW && ui_block_is_menu(but->block)) { const BIFIconID icon = (but->flag & UI_HAS_ICON) ? but->icon + but->iconadd : ICON_NONE; - const int icon_size_i = BLI_rcti_size_y(rect); - float icon_size, text_size; + int icon_size = BLI_rcti_size_y(rect); + int text_size = 0; /* This is a bit britle, but avoids adding an 'UI_BUT_HAS_LABEL' flag to but... */ - if (icon_size_i > BLI_rcti_size_x(rect)) { - icon_size = 0.8f * (float)icon_size_i; - text_size = 0.2f * (float)icon_size_i; - } - else { - icon_size = (float)icon_size_i; - text_size = 0.0f; + if (icon_size > BLI_rcti_size_x(rect)) { + /* button is not square, it has extra height for label */ + text_size = UI_UNIT_Y; + icon_size -= text_size; } /* draw icon in rect above the space reserved for the label */ @@ -1544,9 +1542,12 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB widget_draw_preview(icon, alpha, rect); glDisable(GL_BLEND); - /* offset rect to draw label in*/ + /* offset rect to draw label in */ rect->ymin -= text_size; rect->ymax -= icon_size; + + /* vertically centering text */ + rect->ymin += UI_UNIT_Y / 2; } /* Icons on the left with optional text label on the right */ else if (but->flag & UI_HAS_ICON || show_menu_icon) { @@ -1607,9 +1608,9 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB else if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER)) { ui_text_clip_right_label(fstyle, but, rect); } - else if ((but->block->flag & UI_BLOCK_LOOP) && (but->type == UI_BTYPE_BUT)) { + else if (but->flag & UI_BUT_HAS_SEP_CHAR) { /* Clip middle, but protect in all case right part containing the shortcut, if any. */ - ui_text_clip_middle_protect_right(fstyle, but, rect, "|"); + ui_text_clip_middle_protect_right(fstyle, but, rect, UI_SEP_CHAR); } else { ui_text_clip_middle(fstyle, but, rect); @@ -1626,17 +1627,6 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB /* *********************** widget types ************************************* */ - -/* uiWidgetStateColors - * char inner_anim[4]; - * char inner_anim_sel[4]; - * char inner_key[4]; - * char inner_key_sel[4]; - * char inner_driven[4]; - * char inner_driven_sel[4]; - * float blend; - */ - static struct uiWidgetStateColors wcol_state_colors = { {115, 190, 76, 255}, {90, 166, 51, 255}, @@ -1647,18 +1637,6 @@ static struct uiWidgetStateColors wcol_state_colors = { 0.5f, 0.0f }; -/* uiWidgetColors - * char outline[3]; - * char inner[4]; - * char inner_sel[4]; - * char item[3]; - * char text[3]; - * char text_sel[3]; - * - * short shaded; - * float shadetop, shadedown; - */ - static struct uiWidgetColors wcol_num = { {25, 25, 25, 255}, {180, 180, 180, 255}, @@ -2224,7 +2202,7 @@ static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int dir widget_softshadow(rect, roundboxalign, 0.25f * U.widget_unit); round_box_edges(&wtb, roundboxalign, rect, 0.25f * U.widget_unit); - wtb.emboss = 0; + wtb.draw_emboss = false; widgetbase_draw(&wtb, wcol); glDisable(GL_BLEND); @@ -2762,7 +2740,7 @@ void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *s else rad = 0.5f * BLI_rcti_size_x(rect); - wtb.shadedir = (horizontal) ? 1 : 0; + wtb.draw_shadedir = (horizontal) ? true : false; /* draw back part, colors swapped and shading inverted */ if (horizontal) @@ -2791,11 +2769,11 @@ void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *s } /* draw */ - wtb.emboss = 0; /* only emboss once */ + wtb.draw_emboss = false; /* only emboss once */ /* exception for progress bar */ if (state & UI_SCROLL_NO_OUTLINE) { - SWAP(bool, outline, wtb.outline); + SWAP(bool, outline, wtb.draw_outline); } round_box_edges(&wtb, UI_CNR_ALL, slider, rad); @@ -2818,7 +2796,7 @@ void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *s widgetbase_draw(&wtb, wcol); if (state & UI_SCROLL_NO_OUTLINE) { - SWAP(bool, outline, wtb.outline); + SWAP(bool, outline, wtb.draw_outline); } } } @@ -2945,7 +2923,7 @@ static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int s toffs = offs * 0.75f; round_box_edges(&wtb, roundboxalign, rect, offs); - wtb.outline = 0; + wtb.draw_outline = false; widgetbase_draw(&wtb, wcol); /* draw left/right parts only when not in text editing */ @@ -2970,7 +2948,7 @@ static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int s /* left part of slider, always rounded */ rect1.xmax = rect1.xmin + ceil(offs + U.pixelsize); round_box_edges(&wtb1, roundboxalign & ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT), &rect1, offs); - wtb1.outline = 0; + wtb1.draw_outline = false; widgetbase_draw(&wtb1, wcol); /* right part of slider, interpolate roundness */ @@ -2995,8 +2973,8 @@ static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int s } /* outline */ - wtb.outline = 1; - wtb.inner = 0; + wtb.draw_outline = true; + wtb.draw_inner = false; widgetbase_draw(&wtb, wcol); /* add space at either side of the button so text aligns with numbuttons (which have arrow icons) */ @@ -3088,7 +3066,7 @@ static void widget_icon_has_anim(uiBut *but, uiWidgetColors *wcol, rcti *rect, i float rad; widget_init(&wtb); - wtb.outline = 0; + wtb.draw_outline = false; /* rounded */ rad = 0.5f * BLI_rcti_size_y(rect); @@ -3203,7 +3181,7 @@ static void widget_menu_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(sta widget_init(&wtb); /* not rounded, no outline */ - wtb.outline = 0; + wtb.draw_outline = false; round_box_edges(&wtb, 0, rect, 0.0f); widgetbase_draw(&wtb, wcol); @@ -3217,7 +3195,7 @@ static void widget_menu_radial_itembut(uiBut *but, uiWidgetColors *wcol, rcti *r widget_init(&wtb); - wtb.emboss = 0; + wtb.draw_emboss = false; rad = 0.5f * BLI_rcti_size_y(rect); round_box_edges(&wtb, UI_CNR_ALL, rect, rad); @@ -3240,7 +3218,7 @@ static void widget_list_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(sta widget_init(&wtb); /* rounded, but no outline */ - wtb.outline = 0; + wtb.draw_outline = false; rad = 0.2f * U.widget_unit; round_box_edges(&wtb, UI_CNR_ALL, rect, rad); @@ -3393,8 +3371,8 @@ static void widget_draw_extra_mask(const bContext *C, uiBut *but, uiWidgetType * /* outline */ round_box_edges(&wtb, UI_CNR_ALL, rect, rad); - wtb.outline = 1; - wtb.inner = 0; + wtb.draw_outline = true; + wtb.draw_inner = false; widgetbase_draw(&wtb, &wt->wcol); } @@ -4099,7 +4077,7 @@ void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, const char *name, int ic const float minwidth = (float)(UI_DPI_ICON_SIZE); BLI_strncpy(drawstr, name, sizeof(drawstr)); - UI_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, NULL); + UI_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, '\0'); glColor4ubv((unsigned char *)wt->wcol.text); UI_fontstyle_draw(fstyle, rect, drawstr); @@ -4134,39 +4112,31 @@ void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, const char *name, int ic void ui_draw_preview_item(uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int state) { - rcti trect = *rect, bg_rect; + rcti trect = *rect; + const float text_size = UI_UNIT_Y; float font_dims[2] = {0.0f, 0.0f}; uiWidgetType *wt = widget_type(UI_WTYPE_MENU_ITEM); + /* drawing button background */ wt->state(wt, state); wt->draw(&wt->wcol, rect, 0, 0); + /* draw icon in rect above the space reserved for the label */ + rect->ymin += text_size; glEnable(GL_BLEND); widget_draw_preview(iconid, 1.0f, rect); + glDisable(GL_BLEND); BLF_width_and_height(fstyle->uifont_id, name, BLF_DRAW_STR_DUMMY_MAX, &font_dims[0], &font_dims[1]); /* text rect */ trect.xmin += 0; - trect.xmax = trect.xmin + font_dims[0] + 10; - trect.ymin += 10; + trect.xmax = trect.xmin + font_dims[0] + U.widget_unit / 2; + trect.ymin += U.widget_unit / 2; trect.ymax = trect.ymin + font_dims[1]; if (trect.xmax > rect->xmax - PREVIEW_PAD) trect.xmax = rect->xmax - PREVIEW_PAD; - bg_rect = trect; - bg_rect.xmin = rect->xmin + PREVIEW_PAD; - bg_rect.ymin = rect->ymin + PREVIEW_PAD; - bg_rect.xmax = rect->xmax - PREVIEW_PAD; - bg_rect.ymax += PREVIEW_PAD / 2; - - if (bg_rect.xmax > rect->xmax - PREVIEW_PAD) - bg_rect.xmax = rect->xmax - PREVIEW_PAD; - - glColor4ubv((unsigned char *)wt->wcol_theme->inner_sel); - glRecti(bg_rect.xmin, bg_rect.ymin, bg_rect.xmax, bg_rect.ymax); - glDisable(GL_BLEND); - { char drawstr[UI_MAX_DRAW_STR]; const float okwidth = (float)BLI_rcti_size_x(&trect); @@ -4174,7 +4144,7 @@ void ui_draw_preview_item(uiFontStyle *fstyle, rcti *rect, const char *name, int const float minwidth = (float)(UI_DPI_ICON_SIZE); BLI_strncpy(drawstr, name, sizeof(drawstr)); - UI_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, NULL); + UI_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, '\0'); glColor4ubv((unsigned char *)wt->wcol.text); UI_fontstyle_draw(fstyle, &trect, drawstr); diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index ed61518de6b..617a3e1bdc6 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -824,8 +824,9 @@ static void ui_theme_space_init_handles_color(ThemeSpace *theme_space) rgba_char_args_set(theme_space->act_spline, 0xdb, 0x25, 0x12, 255); } -/* initialize default theme - * Note: when you add new colors, created & saved themes need initialized +/** + * initialize default theme + * \note: when you add new colors, created & saved themes need initialized * use function below, init_userdef_do_versions() */ void ui_theme_init_default(void) diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index 7cdf6078c4f..37b14318c16 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -322,7 +322,7 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy) if (do_init) { float panelzoom = (style) ? style->panelzoom : 1.0f; - float scrolw = v2d->scroll & V2D_SCROLL_RIGHT ? V2D_SCROLL_WIDTH : 0.0f; + float scrolw = (v2d->scroll & V2D_SCROLL_RIGHT) ? V2D_SCROLL_WIDTH : 0.0f; v2d->tot.xmin = 0.0f; v2d->tot.xmax = winx - scrolw; @@ -363,8 +363,9 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy) } -/* Ensure View2D rects remain in a viable configuration - * - cur is not allowed to be: larger than max, smaller than min, or outside of tot +/** + * Ensure View2D rects remain in a viable configuration + * 'cur' is not allowed to be: larger than max, smaller than min, or outside of 'tot' */ // XXX pre2.5 -> this used to be called test_view2d() static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_scrollers) @@ -844,7 +845,8 @@ void UI_view2d_sync(bScreen *screen, ScrArea *area, View2D *v2dcur, int flag) } -/* Restore 'cur' rect to standard orientation (i.e. optimal maximum view of tot) +/** + * Restore 'cur' rect to standard orientation (i.e. optimal maximum view of tot) * This does not take into account if zooming the view on an axis will improve the view (if allowed) */ void UI_view2d_curRect_reset(View2D *v2d) @@ -1100,8 +1102,10 @@ void UI_view2d_view_ortho(View2D *v2d) glLoadIdentity(); } -/* Set view matrices to only use one axis of 'cur' only - * - xaxis = if non-zero, only use cur x-axis, otherwise use cur-yaxis (mostly this will be used for x) +/** + * Set view matrices to only use one axis of 'cur' only + * + * \param xaxis: if non-zero, only use cur x-axis, otherwise use cur-yaxis (mostly this will be used for x) */ void UI_view2d_view_orthoSpecial(ARegion *ar, View2D *v2d, const bool xaxis) { diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index eafc5c1d24c..6fbe8509188 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -63,12 +63,13 @@ static int view2d_poll(bContext *C) /* ********************************************************* */ /* VIEW PANNING OPERATOR */ -/* This group of operators come in several forms: - * 1) Modal 'dragging' with MMB - where movement of mouse dictates amount to pan view by - * 2) Scrollwheel 'steps' - rolling mousewheel by one step moves view by predefined amount +/** + * This group of operators come in several forms: + * -# Modal 'dragging' with MMB - where movement of mouse dictates amount to pan view by + * -# Scrollwheel 'steps' - rolling mousewheel by one step moves view by predefined amount * - * In order to make sure this works, each operator must define the following RNA-Operator Props: - * deltax, deltay - define how much to move view by (relative to zoom-correction factor) + * In order to make sure this works, each operator must define the following RNA-Operator Props: + * - `deltax, deltay` - define how much to move view by (relative to zoom-correction factor) */ /* ------------------ Shared 'core' stuff ---------------------- */ @@ -525,15 +526,18 @@ static void VIEW2D_OT_scroll_up(wmOperatorType *ot) /* ********************************************************* */ /* SINGLE-STEP VIEW ZOOMING OPERATOR */ -/* This group of operators come in several forms: - * 1) Scrollwheel 'steps' - rolling mousewheel by one step zooms view by predefined amount - * 2) Scrollwheel 'steps' + alt + ctrl/shift - zooms view on one axis only (ctrl=x, shift=y) // XXX this could be implemented... - * 3) Pad +/- Keys - pressing each key moves the zooms the view by a predefined amount +/** + * This group of operators come in several forms: + * -# Scrollwheel 'steps' - rolling mousewheel by one step zooms view by predefined amount. + * -# Scrollwheel 'steps' + alt + ctrl/shift - zooms view on one axis only (ctrl=x, shift=y). + * XXX this could be implemented... + * -# Pad +/- Keys - pressing each key moves the zooms the view by a predefined amount. * * In order to make sure this works, each operator must define the following RNA-Operator Props: - * zoomfacx, zoomfacy - These two zoom factors allow for non-uniform scaling. - * It is safe to scale by 0, as these factors are used to determine - * amount to enlarge 'cur' by + * + * - zoomfacx, zoomfacy - These two zoom factors allow for non-uniform scaling. + * It is safe to scale by 0, as these factors are used to determine. + * amount to enlarge 'cur' by. */ /* ------------------ 'Shared' stuff ------------------------ */ @@ -872,10 +876,11 @@ static void VIEW2D_OT_zoom_out(wmOperatorType *ot) /* ********************************************************* */ /* DRAG-ZOOM OPERATOR */ -/* MMB Drag - allows non-uniform scaling by dragging mouse +/** + * MMB Drag - allows non-uniform scaling by dragging mouse * - * In order to make sure this works, each operator must define the following RNA-Operator Props: - * deltax, deltay - amounts to add to each side of the 'cur' rect + * In order to make sure this works, each operator must define the following RNA-Operator Props: + * - `deltax, deltay` - amounts to add to each side of the 'cur' rect */ /* apply transform to view (i.e. adjust 'cur' rect) */ @@ -1192,10 +1197,12 @@ static void VIEW2D_OT_zoom(wmOperatorType *ot) /* ********************************************************* */ /* BORDER-ZOOM */ -/* The user defines a rect using standard borderselect tools, and we use this rect to +/** + * The user defines a rect using standard borderselect tools, and we use this rect to * define the new zoom-level of the view in the following ways: - * 1) LEFTMOUSE - zoom in to view - * 2) RIGHTMOUSE - zoom out of view + * + * -# LEFTMOUSE - zoom in to view + * -# RIGHTMOUSE - zoom out of view * * Currently, these key mappings are hardcoded, but it shouldn't be too important to * have custom keymappings for this... @@ -1534,13 +1541,14 @@ static void VIEW2D_OT_smoothview(wmOperatorType *ot) /* ********************************************************* */ /* SCROLLERS */ -/* Scrollers should behave in the following ways, when clicked on with LMB (and dragged): - * 1) 'Handles' on end of 'bubble' - when the axis that the scroller represents is zoomable, - * enlarge 'cur' rect on the relevant side - * 2) 'Bubble'/'bar' - just drag, and bar should move with mouse (view pans opposite) +/** + * Scrollers should behave in the following ways, when clicked on with LMB (and dragged): + * -# 'Handles' on end of 'bubble' - when the axis that the scroller represents is zoomable, + * enlarge 'cur' rect on the relevant side. + * -# 'Bubble'/'bar' - just drag, and bar should move with mouse (view pans opposite). * - * In order to make sure this works, each operator must define the following RNA-Operator Props: - * deltax, deltay - define how much to move view by (relative to zoom-correction factor) + * In order to make sure this works, each operator must define the following RNA-Operator Props: + * - `deltax, deltay` - define how much to move view by (relative to zoom-correction factor) */ /* customdata for scroller-invoke data */ @@ -1562,10 +1570,12 @@ typedef struct v2dScrollerMove { } v2dScrollerMove; -/* View2DScrollers is typedef'd in UI_view2d.h +/** + * #View2DScrollers is typedef'd in UI_view2d.h * This is a CUT DOWN VERSION of the 'real' version, which is defined in view2d.c, as we only need focus bubble info - * WARNING: the start of this struct must not change, so that it stays in sync with the 'real' version - * For now, we don't need to have a separate (internal) header for structs like this... + * + * \warning: The start of this struct must not change, so that it stays in sync with the 'real' version + * For now, we don't need to have a separate (internal) header for structs like this... */ struct View2DScrollers { /* focus bubbles */ @@ -1584,10 +1594,12 @@ enum { /* ------------------------ */ -/* check if mouse is within scroller handle - * - mouse = relevant mouse coordinate in region space - * - sc_min, sc_max = extents of scroller 'groove' (potential available space for scroller) - * - sh_min, sh_max = positions of scrollbar handles +/** + * Check if mouse is within scroller handle. + * + * \param mouse: relevant mouse coordinate in region space. + * \param sc_min, sc_max: extents of scroller 'groove' (potential available space for scroller). + * \param sh_min, sh_max: positions of scrollbar handles. */ static short mouse_in_scroller_handle(int mouse, int sc_min, int sc_max, int sh_min, int sh_max) { @@ -1791,7 +1803,10 @@ static void scroller_activate_apply(bContext *C, wmOperator *op) UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY); } -/* handle user input for scrollers - calculations of mouse-movement need to be done here, not in the apply callback! */ +/** + * Handle user input for scrollers - calculations of mouse-movement need to be done here, + * not in the apply callback! + */ static int scroller_activate_modal(bContext *C, wmOperator *op, const wmEvent *event) { v2dScrollerMove *vsm = op->customdata; diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 0b9da1efed6..517710405a0 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -777,18 +777,11 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo /* vars from original func */ UvElementMap *element_map; UvElement *buf; - UvElement *islandbuf; - /* island number for faces */ - int *island_number; bool *winding; BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); MLoopUV *luv; - int totverts, totfaces, i, totuv, j, nislands = 0, islandbufsize = 0; - - unsigned int *map; - BMFace **stack; - int stacksize = 0; + int totverts, totfaces, i, totuv, j; const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); @@ -798,9 +791,6 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo totverts = bm->totvert; totuv = 0; - island_number = MEM_mallocN(sizeof(*stack) * totfaces, "uv_island_number_face"); - winding = MEM_callocN(sizeof(*winding) * totfaces, "winding"); - /* generate UvElement array */ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { if (!selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) { @@ -809,26 +799,20 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo } if (totuv == 0) { - MEM_freeN(island_number); return NULL; } + element_map = (UvElementMap *)MEM_callocN(sizeof(*element_map), "UvElementMap"); - if (!element_map) { - MEM_freeN(island_number); - return NULL; - } element_map->totalUVs = totuv; element_map->vert = (UvElement **)MEM_callocN(sizeof(*element_map->vert) * totverts, "UvElementVerts"); buf = element_map->buf = (UvElement *)MEM_callocN(sizeof(*element_map->buf) * totuv, "UvElement"); - if (!element_map->vert || !element_map->buf) { - BM_uv_element_map_free(element_map); - MEM_freeN(island_number); - return NULL; - } + winding = MEM_mallocN(sizeof(*winding) * totfaces, "winding"); BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, j) { - island_number[j] = INVALID_ISLAND; + + winding[j] = false; + if (!selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) { float (*tf_uv)[2] = (float (*)[2])BLI_buffer_resize_data(&tf_uv_buf, vec2f, efa->len); @@ -900,11 +884,24 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo element_map->vert[i] = newvlist; } + MEM_freeN(winding); + if (do_islands) { + unsigned int *map; + BMFace **stack; + int stacksize = 0; + UvElement *islandbuf; + /* island number for faces */ + int *island_number = NULL; + + int nislands = 0, islandbufsize = 0; + /* map holds the map from current vmap->buf to the new, sorted map */ map = MEM_mallocN(sizeof(*map) * totuv, "uvelement_remap"); stack = MEM_mallocN(sizeof(*stack) * bm->totface, "uv_island_face_stack"); islandbuf = MEM_callocN(sizeof(*islandbuf) * totuv, "uvelement_island_buffer"); + island_number = MEM_mallocN(sizeof(*island_number) * totfaces, "uv_island_number_face"); + copy_vn_i(island_number, totfaces, INVALID_ISLAND); /* at this point, every UvElement in vert points to a UvElement sharing the same vertex. Now we should sort uv's in islands. */ for (i = 0; i < totuv; i++) { @@ -953,6 +950,8 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo } } + MEM_freeN(island_number); + /* remap */ for (i = 0; i < bm->totvert; i++) { /* important since we may do selection only. Some of these may be NULL */ @@ -961,14 +960,6 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo } element_map->islandIndices = MEM_callocN(sizeof(*element_map->islandIndices) * nislands, "UvElementMap_island_indices"); - if (!element_map->islandIndices) { - MEM_freeN(islandbuf); - MEM_freeN(stack); - MEM_freeN(map); - BM_uv_element_map_free(element_map); - MEM_freeN(island_number); - } - j = 0; for (i = 0; i < totuv; i++) { UvElement *element = element_map->buf[i].next; @@ -991,8 +982,6 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo MEM_freeN(map); } - MEM_freeN(island_number); - MEM_freeN(winding); BLI_buffer_free(&tf_uv_buf); return element_map; diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c index b9a9f708af7..a2054a5f43c 100644 --- a/source/blender/editors/mesh/mesh_data.c +++ b/source/blender/editors/mesh/mesh_data.c @@ -429,7 +429,7 @@ int ED_mesh_color_add(Mesh *me, const char *name, const bool active_set) /* copy data from active vertex color layer */ if (layernum) { const int layernum_dst = CustomData_get_active_layer(&em->bm->ldata, CD_MLOOPCOL); - BM_data_layer_copy(em->bm, &em->bm->ldata, CD_MLOOPCOL, layernum, layernum_dst); + BM_data_layer_copy(em->bm, &em->bm->ldata, CD_MLOOPCOL, layernum_dst, layernum); } if (active_set || layernum == 0) { CustomData_set_layer_active(&em->bm->ldata, CD_MLOOPCOL, layernum); diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index c88f1257936..ce9693793a4 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -248,7 +248,7 @@ static bool object_has_modifier_cb(Object *ob, void *data) bool ED_object_multires_update_totlevels_cb(Object *ob, void *totlevel_v) { ModifierData *md; - int totlevel = *((int *)totlevel_v); + int totlevel = *((char *)totlevel_v); for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Multires) { diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index 886e4e5ef8c..30ab00a72c2 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -955,21 +955,30 @@ static void paint_cursor_on_hit(UnifiedPaintSettings *ups, Brush *brush, ViewCon } } +static bool ommit_cursor_drawing(Paint *paint, PaintMode mode, Brush *brush) +{ + if (paint->flags & PAINT_SHOW_BRUSH) { + if (ELEM(mode, PAINT_TEXTURE_2D, PAINT_TEXTURE_PROJECTIVE) && brush->imagepaint_tool == PAINT_TOOL_FILL) + return true; + } + return false; +} + static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) { Scene *scene = CTX_data_scene(C); UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; Paint *paint = BKE_paint_get_active_from_context(C); Brush *brush = BKE_paint_brush(paint); + PaintMode mode = BKE_paintmode_get_active_from_context(C); ViewContext vc; - PaintMode mode; float final_radius; float translation[2]; float outline_alpha, *outline_col; float zoomx, zoomy; - + /* check that brush drawing is enabled */ - if (!(paint->flags & PAINT_SHOW_BRUSH)) + if (ommit_cursor_drawing(paint, mode, brush)) return; /* can't use stroke vc here because this will be called during @@ -978,7 +987,6 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) get_imapaint_zoom(C, &zoomx, &zoomy); zoomx = max_ff(zoomx, zoomy); - mode = BKE_paintmode_get_active_from_context(C); /* skip everything and draw brush here */ if (brush->flag & BRUSH_CURVE) { @@ -1018,8 +1026,8 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) /* check if brush is subtracting, use different color then */ /* TODO: no way currently to know state of pen flip or * invert key modifier without starting a stroke */ - if ((!(ups->draw_inverted) ^ - !(brush->flag & BRUSH_DIR_IN)) && + if (((ups->draw_inverted == 0) ^ + ((brush->flag & BRUSH_DIR_IN) == 0)) && ELEM(brush->sculpt_tool, SCULPT_TOOL_DRAW, SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY, SCULPT_TOOL_PINCH, SCULPT_TOOL_CREASE)) diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index a569bf469b3..58f1ebb9eac 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -5085,7 +5085,7 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int ps->blend = brush->blend; /* only check for inversion for the soften tool, elsewhere, a resident brush inversion flag can cause issues */ if (brush->imagepaint_tool == PAINT_TOOL_SOFTEN) { - ps->mode = ((ps->mode == BRUSH_STROKE_INVERT) ^ ((brush->flag & BRUSH_DIR_IN) != 0) ? + ps->mode = (((ps->mode == BRUSH_STROKE_INVERT) ^ ((brush->flag & BRUSH_DIR_IN) != 0)) ? BRUSH_STROKE_INVERT : BRUSH_STROKE_NORMAL); ps->blurkernel = paint_new_blur_kernel(brush, true); diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 0e75a344699..ede90b6e1f1 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -1200,7 +1200,7 @@ static float brush_strength(const Sculpt *sd, const StrokeCache *cache, const fl /* Primary strength input; square it to make lower values more sensitive */ const float root_alpha = BKE_brush_alpha_get(scene, brush); float alpha = root_alpha * root_alpha; - float dir = brush->flag & BRUSH_DIR_IN ? -1 : 1; + float dir = (brush->flag & BRUSH_DIR_IN) ? -1 : 1; float pressure = BKE_brush_use_alpha_pressure(scene, brush) ? cache->pressure : 1; float pen_flip = cache->pen_flip ? -1 : 1; float invert = cache->invert ? -1 : 1; diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 0a9a12efc0b..0e4d8857663 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -310,7 +310,7 @@ static void file_draw_string(int sx, int sy, const char *string, float width, in fs.align = align; BLI_strncpy(fname, string, FILE_MAXFILE); - UI_text_clip_middle_ex(&fs, fname, width, UI_DPI_ICON_SIZE, sizeof(fname), NULL); + UI_text_clip_middle_ex(&fs, fname, width, UI_DPI_ICON_SIZE, sizeof(fname), '\0'); /* no text clipping needed, UI_fontstyle_draw does it but is a bit too strict (for buttons it works) */ rect.xmin = sx; diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c index 8b68ac013c2..a7fd624d2aa 100644 --- a/source/blender/editors/space_node/node_templates.c +++ b/source/blender/editors/space_node/node_templates.c @@ -24,6 +24,7 @@ * \ingroup edinterface */ +#include <stdlib.h> #include <string.h> #include "MEM_guardedalloc.h" @@ -214,8 +215,22 @@ static void node_socket_add_replace(const bContext *C, bNodeTree *ntree, bNode * } else if (!node_from) { node_from = nodeAddStaticNode(C, ntree, type); - node_from->locx = node_to->locx - (node_from->typeinfo->width + 50); - node_from->locy = node_to->locy; + if (node_prev != NULL) { + /* If we're replacing existing node, use it's location. */ + node_from->locx = node_prev->locx; + node_from->locy = node_prev->locy; + node_from->offsetx = node_prev->offsetx; + node_from->offsety = node_prev->offsety; + } + else { + /* Avoid exact intersection of nodes. + * TODO(sergey): Still not ideal, but better than nothing. + */ + int index = BLI_findindex(&node_to->inputs, sock_to); + BLI_assert(index != -1); + node_from->locx = node_to->locx - (node_from->typeinfo->width + 50); + node_from->locy = node_to->locy - (node_from->typeinfo->height * index); + } node_link_item_apply(node_from, item); } diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index c040045b598..2aa57fe1cad 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -6191,7 +6191,7 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit) PTCacheEditPoint *point; PTCacheEditKey *key; ParticleEditSettings *pset = PE_settings(scene); - int i, k, totpoint = edit->totpoint, timed = pset->flag & PE_FADE_TIME ? pset->fade_frames : 0; + int i, k, totpoint = edit->totpoint, timed = (pset->flag & PE_FADE_TIME) ? pset->fade_frames : 0; int totkeys = 1; float sel_col[3]; float nosel_col[3]; @@ -6331,7 +6331,7 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit) glColor3fv(nosel_col); /* has to be like this.. otherwise selection won't work, have try glArrayElement later..*/ glBegin(GL_POINTS); - glVertex3fv(key->flag & PEK_USE_WCO ? key->world_co : key->co); + glVertex3fv((key->flag & PEK_USE_WCO) ? key->world_co : key->co); glEnd(); } } diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index fb98f8b91a7..1d5c2a3a169 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -26,8 +26,6 @@ /* defines VIEW3D_OT_navigate - walk modal operator */ -//#define NDOF_WALK_DEBUG -//#define NDOF_WALK_DRAW_TOOMUCH /* is this needed for ndof? - commented so redraw doesnt thrash - campbell */ #include "DNA_scene_types.h" #include "DNA_object_types.h" @@ -58,6 +56,11 @@ #include "view3d_intern.h" /* own include */ +//#define NDOF_WALK_DEBUG +//#define NDOF_WALK_DRAW_TOOMUCH /* is this needed for ndof? - commented so redraw doesnt thrash - campbell */ + +#define USE_TABLET_SUPPORT + /* prototypes */ static float getVelocityZeroTime(const float gravity, const float velocity); @@ -276,6 +279,14 @@ typedef struct WalkInfo { /* mouse reverse */ bool is_reversed; +#ifdef USE_TABLET_SUPPORT + /* check if we had a cursor event before */ + bool is_cursor_first; + + /* tablet devices (we can't relocate the cursor) */ + bool is_cursor_absolute; +#endif + /* gravity system */ eWalkGravityState gravity_state; float gravity; @@ -519,6 +530,12 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) walk->is_reversed = ((U.walk_navigation.flag & USER_WALK_MOUSE_REVERSE) != 0); +#ifdef USE_TABLET_SUPPORT + walk->is_cursor_first = true; + + walk->is_cursor_absolute = false; +#endif + walk->active_directions = 0; #ifdef NDOF_WALK_DRAW_TOOMUCH @@ -586,10 +603,16 @@ static int walkEnd(bContext *C, WalkInfo *walk) /* restore the cursor */ WM_cursor_modal_restore(win); - /* center the mouse */ - WM_cursor_warp(win, - walk->ar->winrct.xmin + walk->center_mval[0], - walk->ar->winrct.ymin + walk->center_mval[1]); +#ifdef USE_TABLET_SUPPORT + if (walk->is_cursor_absolute == false) +#endif + { + /* center the mouse */ + WM_cursor_warp( + win, + walk->ar->winrct.xmin + walk->center_mval[0], + walk->ar->winrct.ymin + walk->center_mval[1]); + } if (walk->state == WALK_CONFIRM) { MEM_freeN(walk); @@ -617,6 +640,27 @@ static void walkEvent(bContext *C, wmOperator *UNUSED(op), WalkInfo *walk, const } else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { +#ifdef USE_TABLET_SUPPORT + if (walk->is_cursor_first) { + /* wait until we get the 'warp' event */ + if ((walk->center_mval[0] == event->mval[0]) && + (walk->center_mval[1] == event->mval[1])) + { + walk->is_cursor_first = false; + } + return; + } + + if ((walk->is_cursor_absolute == false) && WM_event_is_absolute(event)) { + walk->is_cursor_absolute = true; + copy_v2_v2_int(walk->prev_mval, event->mval); + copy_v2_v2_int(walk->center_mval, event->mval); + /* without this we can't turn 180d */ + CLAMP_MIN(walk->mouse_speed, 4.0f); + } +#endif /* USE_TABLET_SUPPORT */ + + walk->moffset[0] += event->mval[0] - walk->prev_mval[0]; walk->moffset[1] += event->mval[1] - walk->prev_mval[1]; @@ -627,6 +671,12 @@ static void walkEvent(bContext *C, wmOperator *UNUSED(op), WalkInfo *walk, const { walk->redraw = true; +#ifdef USE_TABLET_SUPPORT + if (walk->is_cursor_absolute) { + /* pass */ + } + else +#endif if (wm_event_is_last_mousemove(event)) { wmWindow *win = CTX_wm_window(C); diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index b629a69fc0b..34314e7ff3d 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -6658,6 +6658,10 @@ static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2] /* first get the direction of the original mouse position */ sub_v2_v2v2(dir, imval_fl, mval_fl); ED_view3d_win_to_delta(t->ar, dir, dir, t->zfac); + + invert_m4_m4(t->obedit->imat, t->obedit->obmat); + mul_mat3_m4_v3(t->obedit->imat, dir); + normalize_v3(dir); for (i = 0, sv = sld->sv; i < sld->totsv; i++, sv++) { @@ -7013,6 +7017,10 @@ static void drawVertSlide(TransInfo *t) mval_ofs[1] = t->mval[1] - t->imval[1]; ED_view3d_win_to_delta(t->ar, mval_ofs, co_dest_3d, zfac); + + invert_m4_m4(t->obedit->imat, t->obedit->obmat); + mul_mat3_m4_v3(t->obedit->imat, co_dest_3d); + add_v3_v3(co_dest_3d, curr_sv->co_orig_3d); glLineWidth(1); diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index fea0984001b..667c0f01c18 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -513,7 +513,7 @@ static int calc_manipulator_stats(const bContext *C) for (k = 0, ek = point->keys; k < point->totkey; k++, ek++) { if (ek->flag & PEK_SELECT) { - calc_tw_center(scene, ek->flag & PEK_USE_WCO ? ek->world_co : ek->co); + calc_tw_center(scene, (ek->flag & PEK_USE_WCO) ? ek->world_co : ek->co); totsel++; } } diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index f77f1d3b518..62fa1b5a989 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -849,7 +849,7 @@ static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot) ot->exec = transform_exec; ot->modal = transform_modal; ot->cancel = transform_cancel; - ot->poll = ED_operator_editmesh; + ot->poll = ED_operator_editmesh_region_view3d; RNA_def_float_factor(ot->srna, "value", 0, -10.0f, 10.0f, "Factor", "", -1.0f, 1.0f); @@ -869,7 +869,7 @@ static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot) ot->exec = transform_exec; ot->modal = transform_modal; ot->cancel = transform_cancel; - ot->poll = ED_operator_editmesh; + ot->poll = ED_operator_editmesh_region_view3d; RNA_def_float_factor(ot->srna, "value", 0, -10.0f, 10.0f, "Factor", "", -1.0f, 1.0f); diff --git a/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp b/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp index 4d0d140474a..a36d446fcb7 100644 --- a/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp +++ b/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp @@ -30,6 +30,9 @@ extern "C" { #endif +#include "BLI_hash_mm2a.h" + + /////////////////////////////////////////////////////////////////////////////////////////// //-------------------MODULE INITIALIZATION-------------------------------- @@ -478,6 +481,48 @@ static PyGetSetDef BPy_FrsMaterial_getseters[] = { {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ }; +static PyObject *BPy_FrsMaterial_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type) +{ + const BPy_FrsMaterial *matA = NULL, *matB = NULL; + bool result = 0; + + if (!BPy_FrsMaterial_Check(objectA) || !BPy_FrsMaterial_Check(objectB)) { + if (comparison_type == Py_NE) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } + } + + matA = (BPy_FrsMaterial *)objectA; + matB = (BPy_FrsMaterial *)objectB; + + switch (comparison_type) { + case Py_NE: + result = (*matA->m) != (*matB->m); + break; + case Py_EQ: + result = (*matA->m) == (*matB->m); + break; + default: + PyErr_SetString(PyExc_TypeError, "Material does not support this comparison type"); + return NULL; + } + + if (result == true) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + + +static Py_hash_t FrsMaterial_hash(PyObject *self) +{ + return (Py_uhash_t)BLI_hash_mm2((const unsigned char *)self, sizeof(*self), 0); +} /*-----------------------BPy_FrsMaterial type definition ------------------------------*/ PyTypeObject FrsMaterial_Type = { @@ -494,7 +539,7 @@ PyTypeObject FrsMaterial_Type = { 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ - 0, /* tp_hash */ + (hashfunc)FrsMaterial_hash, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ @@ -504,7 +549,7 @@ PyTypeObject FrsMaterial_Type = { FrsMaterial_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ - 0, /* tp_richcompare */ + (richcmpfunc)BPy_FrsMaterial_richcmpr, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ diff --git a/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp b/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp index 1ef29792d56..9f0660baa9b 100644 --- a/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp +++ b/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp @@ -188,7 +188,10 @@ static PyObject *CurvePoint_fedge_get(BPy_CurvePoint *self, void *UNUSED(closure { SVertex *A = self->cp->A(); Interface0D *B = (Interface0D *)self->cp->B(); - return Any_BPy_Interface1D_from_Interface1D(*(A->getFEdge(*B))); + // B can be NULL under certain circumstances + if (B) + return Any_BPy_Interface1D_from_Interface1D(*(A->getFEdge(*B))); + Py_RETURN_NONE; } PyDoc_STRVAR(CurvePoint_t2d_doc, diff --git a/source/blender/imbuf/IMB_thumbs.h b/source/blender/imbuf/IMB_thumbs.h index 2cb56832a00..f2f75973bcd 100644 --- a/source/blender/imbuf/IMB_thumbs.h +++ b/source/blender/imbuf/IMB_thumbs.h @@ -63,6 +63,11 @@ typedef enum ThumbSource { #define PREVIEW_RENDER_DEFAULT_HEIGHT 128 +/* Note this can also be used as versionning system, + * to force refreshing all thumbnails if e.g. we change some thumb generating code or so. + * Only used by fonts so far. */ +#define THUMB_DEFAULT_HASH "00000000000000000000000000000000" + /* create thumbnail for file and returns new imbuf for thumbnail */ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, ImBuf *ibuf); @@ -84,7 +89,7 @@ void IMB_thumb_overlay_blend(unsigned int *thumb, int width, int height, float /* special function for previewing fonts */ ImBuf *IMB_thumb_load_font(const char *filename, unsigned int x, unsigned int y); -const char *IMB_thumb_load_font_get_language(void); +bool IMB_thumb_load_font_get_hash(char *r_hash); #ifdef __cplusplus } diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index c3c403db9c1..a61204ea850 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -1357,11 +1357,12 @@ static void display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle, float *fp; unsigned char *cp; + const size_t i_last = ((size_t)width) * height; size_t i; /* first convert byte buffer to float, keep in image space */ for (i = 0, fp = linear_buffer, cp = byte_buffer; - i < ((size_t)width) * height; + i != i_last; i++, fp += channels, cp += channels) { if (channels == 3) { @@ -1470,11 +1471,12 @@ static void *do_display_buffer_apply_thread(void *handle_v) memcpy(display_buffer, linear_buffer, ((size_t)width) * height * channels * sizeof(float)); if (is_straight_alpha && channels == 4) { + const size_t i_last = ((size_t)width) * height; size_t i; float *fp; for (i = 0, fp = display_buffer; - i < ((size_t)width) * height; + i != i_last; i++, fp += channels) { straight_to_premul_v4(fp); @@ -1787,8 +1789,10 @@ void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, int width, in if (processor) { OCIO_PackedImageDesc *img; - img = OCIO_createOCIO_PackedImageDesc(buffer, width, height, channels, sizeof(float), - channels * sizeof(float), channels * sizeof(float) * width); + img = OCIO_createOCIO_PackedImageDesc( + buffer, width, height, channels, sizeof(float), + (size_t)channels * sizeof(float), + (size_t)channels * sizeof(float) * width); if (predivide) OCIO_processorApply_predivide(processor, img); @@ -2015,7 +2019,7 @@ unsigned char *IMB_display_buffer_acquire(ImBuf *ibuf, const ColorManagedViewSet const ColorManagedDisplaySettings *display_settings, void **cache_handle) { unsigned char *display_buffer; - int buffer_size; + size_t buffer_size; ColormanageCacheViewSettings cache_view_settings; ColormanageCacheDisplaySettings cache_display_settings; ColorManagedViewSettings default_view_settings; @@ -2113,8 +2117,8 @@ void IMB_display_buffer_transform_apply(unsigned char *display_buffer, float *li float *buffer; ColormanageProcessor *cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings); - buffer = MEM_callocN(channels * width * height * sizeof(float), "display transform temp buffer"); - memcpy(buffer, linear_buffer, channels * width * height * sizeof(float)); + buffer = MEM_mallocN((size_t)channels * width * height * sizeof(float), "display transform temp buffer"); + memcpy(buffer, linear_buffer, (size_t)channels * width * height * sizeof(float)); IMB_colormanagement_processor_apply(cm_processor, buffer, width, height, channels, predivide); @@ -2658,14 +2662,14 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe if (!cm_processor) channels = 4; - display_buffer_float = MEM_callocN(channels * width * height * sizeof(float), "display buffer for dither"); + display_buffer_float = MEM_callocN((size_t)channels * width * height * sizeof(float), "display buffer for dither"); } if (cm_processor) { for (y = ymin; y < ymax; y++) { for (x = xmin; x < xmax; x++) { - int display_index = (y * display_stride + x) * 4; - int linear_index = ((y - linear_offset_y) * linear_stride + (x - linear_offset_x)) * channels; + size_t display_index = ((size_t)y * display_stride + x) * 4; + size_t linear_index = ((size_t)(y - linear_offset_y) * linear_stride + (x - linear_offset_x)) * channels; float pixel[4]; if (linear_buffer) { @@ -2694,7 +2698,7 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe } if (display_buffer_float) { - int index = ((y - ymin) * width + (x - xmin)) * channels; + size_t index = ((size_t)(y - ymin) * width + (x - xmin)) * channels; if (channels == 4) { copy_v4_v4(display_buffer_float + index, pixel); @@ -2737,8 +2741,8 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe int i; for (i = ymin; i < ymax; i++) { - int byte_offset = (linear_stride * i + xmin) * 4; - int display_offset = (display_stride * i + xmin) * 4; + size_t byte_offset = ((size_t)linear_stride * i + xmin) * 4; + size_t display_offset = ((size_t)display_stride * i + xmin) * 4; memcpy(display_buffer + display_offset, byte_buffer + byte_offset, 4 * sizeof(char) * width); } @@ -2746,7 +2750,7 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe } if (display_buffer_float) { - int display_index = (ymin * display_stride + xmin) * channels; + size_t display_index = ((size_t)ymin * display_stride + xmin) * channels; IMB_buffer_byte_from_float(display_buffer + display_index, display_buffer_float, channels, dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB, true, width, height, display_stride, width); @@ -2833,8 +2837,8 @@ void IMB_partial_display_buffer_update(ImBuf *ibuf, const float *linear_buffer, if (copy_display_to_byte_buffer && (unsigned char *) ibuf->rect != display_buffer) { int y; for (y = ymin; y < ymax; y++) { - int index = y * buffer_width * 4; - memcpy((unsigned char *)ibuf->rect + index, display_buffer + index, (xmax - xmin) * 4); + size_t index = (size_t)y * buffer_width * 4; + memcpy((unsigned char *)ibuf->rect + index, display_buffer + index, (size_t)(xmax - xmin) * 4); } } } @@ -2970,8 +2974,10 @@ void IMB_colormanagement_processor_apply(ColormanageProcessor *cm_processor, flo OCIO_PackedImageDesc *img; /* apply OCIO processor */ - img = OCIO_createOCIO_PackedImageDesc(buffer, width, height, channels, sizeof(float), - channels * sizeof(float), channels * sizeof(float) * width); + img = OCIO_createOCIO_PackedImageDesc( + buffer, width, height, channels, sizeof(float), + (size_t)channels * sizeof(float), + (size_t)channels * sizeof(float) * width); if (predivide) OCIO_processorApply_predivide(cm_processor->processor, img); diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index 22c854d6e1b..e805d3dc25c 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -638,7 +638,7 @@ typedef struct ExrHandle { struct ExrHandle *next, *prev; char name[FILE_MAX]; - IFileStream *ifile_stream; + IStream *ifile_stream; MultiPartInputFile *ifile; OFileStream *ofile_stream; @@ -1345,6 +1345,7 @@ void IMB_exr_close(void *handle) delete data->ofile; delete data->mpofile; delete data->ofile_stream; + delete data->multiView; data->ifile = NULL; data->ifile_stream = NULL; @@ -1495,7 +1496,7 @@ static ExrPass *imb_exr_get_pass(ListBase *lb, char *passname) } /* creates channels, makes a hierarchy and assigns memory to channels */ -static ExrHandle *imb_exr_begin_read_mem(MultiPartInputFile& file, int width, int height) +static ExrHandle *imb_exr_begin_read_mem(IStream &file_stream, MultiPartInputFile &file, int width, int height) { ExrLayer *lay; ExrPass *pass; @@ -1504,7 +1505,9 @@ static ExrHandle *imb_exr_begin_read_mem(MultiPartInputFile& file, int width, in int a; char layname[EXR_TOT_MAXNAME], passname[EXR_TOT_MAXNAME]; + data->ifile_stream = &file_stream; data->ifile = &file; + data->width = width; data->height = height; @@ -1855,6 +1858,7 @@ static bool imb_exr_is_multi(MultiPartInputFile& file) struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE]) { struct ImBuf *ibuf = NULL; + Mem_IStream *membuf = NULL; MultiPartInputFile *file = NULL; if (imb_is_a_openexr(mem) == 0) return(NULL); @@ -1863,8 +1867,9 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char try { - Mem_IStream *membuf = new Mem_IStream(mem, size); bool is_multi; + + membuf = new Mem_IStream(mem, size); file = new MultiPartInputFile(*membuf); Box2i dw = file->header(0).dataWindow(); @@ -1914,7 +1919,7 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char if (is_multi && ((flags & IB_thumbnail) == 0)) { /* only enters with IB_multilayer flag set */ /* constructs channels for reading, allocates memory in channels */ - ExrHandle *handle = imb_exr_begin_read_mem(*file, width, height); + ExrHandle *handle = imb_exr_begin_read_mem(*membuf, *file, width, height); if (handle) { IMB_exr_read_channels(handle); ibuf->userdata = handle; /* potential danger, the caller has to check for this! */ @@ -1998,6 +2003,7 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char } /* file is no longer needed */ + delete membuf; delete file; } } @@ -2012,6 +2018,7 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char std::cerr << exc.what() << std::endl; if (ibuf) IMB_freeImBuf(ibuf); delete file; + delete membuf; return (0); } diff --git a/source/blender/imbuf/intern/stereoimbuf.c b/source/blender/imbuf/intern/stereoimbuf.c index cf9c6b388ff..f1608f56c0b 100644 --- a/source/blender/imbuf/intern/stereoimbuf.c +++ b/source/blender/imbuf/intern/stereoimbuf.c @@ -620,7 +620,7 @@ static void imb_stereo3d_squeeze_rectf(float *rectf, Stereo3dFormat *s3d, const width, height, width, width); IMB_scaleImBuf_threaded(ibuf, x, y); - rectf = MEM_dupallocN(ibuf->rect_float); + memcpy(rectf, ibuf->rect_float, x * y * sizeof(float[4])); IMB_freeImBuf(ibuf); } @@ -645,7 +645,7 @@ static void imb_stereo3d_squeeze_rect(int *rect, Stereo3dFormat *s3d, const size width, height, width, width); IMB_scaleImBuf_threaded(ibuf, x, y); - rect = MEM_dupallocN(ibuf->rect); + memcpy(rect, ibuf->rect, x * y * sizeof(unsigned int)); IMB_freeImBuf(ibuf); } diff --git a/source/blender/imbuf/intern/targa.c b/source/blender/imbuf/intern/targa.c index 70b71ec4182..40dcdc9d24a 100644 --- a/source/blender/imbuf/intern/targa.c +++ b/source/blender/imbuf/intern/targa.c @@ -568,7 +568,7 @@ ImBuf *imb_loadtarga(unsigned char *mem, size_t mem_size, int flags, char colors else ibuf = IMB_allocImBuf(tga.xsize, tga.ysize, (tga.pixsize + 0x7) & ~0x7, IB_rect); if (ibuf == NULL) return NULL; - ibuf->ftype = TGA; + ibuf->ftype = (tga.imgtyp < 4) ? RAWTGA : TGA; mem = mem + 18 + tga.numid; cp[0] = 0xff; diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c index 626f02e8ade..7a949b7ffea 100644 --- a/source/blender/imbuf/intern/thumbs.c +++ b/source/blender/imbuf/intern/thumbs.c @@ -200,6 +200,17 @@ static void escape_uri_string(const char *string, char *escaped_string, int esca /** ----- end of adapted code from glib --- */ +static bool thumbhash_from_path(const char *UNUSED(path), ThumbSource source, char *r_hash) +{ + switch (source) { + case THB_SOURCE_FONT: + return IMB_thumb_load_font_get_hash(r_hash); + default: + r_hash[0] = '\0'; + return false; + } +} + static int uri_from_filename(const char *path, char *uri) { char orig_uri[URI_MAX]; @@ -298,7 +309,8 @@ void IMB_thumb_makedirs(void) /* create thumbnail for file and returns new imbuf for thumbnail */ static ImBuf *thumb_create_ex( - const char *file_path, const char *uri, const char *thumb, ThumbSize size, ThumbSource source, ImBuf *img) + const char *file_path, const char *uri, const char *thumb, const bool use_hash, const char *hash, + ThumbSize size, ThumbSource source, ImBuf *img) { char desc[URI_MAX + 22]; char tpath[FILE_MAX]; @@ -420,6 +432,9 @@ static ImBuf *thumb_create_ex( IMB_metadata_change_field(img, "Software", "Blender"); IMB_metadata_change_field(img, "Thumb::URI", uri); IMB_metadata_change_field(img, "Thumb::MTime", mtime); + if (use_hash) { + IMB_metadata_change_field(img, "X-Blender::Hash", hash); + } if (ELEM(source, THB_SOURCE_IMAGE, THB_SOURCE_BLEND, THB_SOURCE_FONT)) { IMB_metadata_change_field(img, "Thumb::Image::Width", cwidth); IMB_metadata_change_field(img, "Thumb::Image::Height", cheight); @@ -439,6 +454,25 @@ static ImBuf *thumb_create_ex( return img; } +static ImBuf *thumb_create_or_fail( + const char *file_path, const char *uri, const char *thumb, const bool use_hash, const char *hash, + ThumbSize size, ThumbSource source) +{ + ImBuf *img = thumb_create_ex(file_path, uri, thumb, use_hash, hash, size, source, NULL); + + if (!img) { + /* thumb creation failed, write fail thumb */ + img = thumb_create_ex(file_path, uri, thumb, use_hash, hash, THB_FAIL, source, NULL); + if (img) { + /* we don't need failed thumb anymore */ + IMB_freeImBuf(img); + img = NULL; + } + } + + return img; +} + ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, ImBuf *img) { char uri[URI_MAX] = ""; @@ -447,7 +481,7 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im uri_from_filename(path, uri); thumbname_from_uri(uri, thumb_name, sizeof(thumb_name)); - return thumb_create_ex(path, uri, thumb_name, size, source, img); + return thumb_create_ex(path, uri, thumb_name, false, THUMB_DEFAULT_HASH, size, source, img); } /* read thumbnail for file and returns new imbuf for thumbnail */ @@ -495,15 +529,10 @@ ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source char uri[URI_MAX]; const char *file_path; const char *path; - char path_buff[FILE_MAX]; BLI_stat_t st; ImBuf *img = NULL; path = file_path = org_path; - if (source == THB_SOURCE_FONT) { - BLI_snprintf(path_buff, sizeof(path_buff), "%s.%s", org_path, IMB_thumb_load_font_get_language()); - path = path_buff; - } if (BLI_stat(file_path, &st) == -1) { return NULL; @@ -531,45 +560,46 @@ ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source else { img = IMB_loadiffname(thumb_path, IB_rect | IB_metadata, NULL); if (img) { + bool regenerate = false; + char mtime[40]; - if (!IMB_metadata_get_field(img, "Thumb::MTime", mtime, 40)) { - /* illegal thumb, forget it! */ - IMB_freeImBuf(img); - img = NULL; + char thumb_hash[33]; + char thumb_hash_curr[33]; + + const bool use_hash = thumbhash_from_path(file_path, source, thumb_hash); + + if (IMB_metadata_get_field(img, "Thumb::MTime", mtime, sizeof(mtime))) { + regenerate = (st.st_mtime != atol(mtime)); } else { - time_t t = atol(mtime); - if (st.st_mtime != t) { - /* recreate all thumbs */ - IMB_freeImBuf(img); - img = NULL; - IMB_thumb_delete(path, THB_NORMAL); - IMB_thumb_delete(path, THB_LARGE); - IMB_thumb_delete(path, THB_FAIL); - img = thumb_create_ex(file_path, uri, thumb_name, size, source, NULL); - if (!img) { - /* thumb creation failed, write fail thumb */ - img = thumb_create_ex(file_path, uri, thumb_name, THB_FAIL, source, NULL); - if (img) { - /* we don't need failed thumb anymore */ - IMB_freeImBuf(img); - img = NULL; - } - } + /* illegal thumb, regenerate it! */ + regenerate = true; + } + + if (use_hash && !regenerate) { + if (IMB_metadata_get_field(img, "X-Blender::Hash", thumb_hash_curr, sizeof(thumb_hash_curr))) { + regenerate = !STREQ(thumb_hash, thumb_hash_curr); + } + else { + regenerate = true; } } + + if (regenerate) { + /* recreate all thumbs */ + IMB_freeImBuf(img); + img = NULL; + IMB_thumb_delete(path, THB_NORMAL); + IMB_thumb_delete(path, THB_LARGE); + IMB_thumb_delete(path, THB_FAIL); + img = thumb_create_or_fail(file_path, uri, thumb_name, use_hash, thumb_hash, size, source); + } } else { - img = thumb_create_ex(file_path, uri, thumb_name, size, source, NULL); - if (!img) { - /* thumb creation failed, write fail thumb */ - img = thumb_create_ex(file_path, uri, thumb_name, THB_FAIL, source, NULL); - if (img) { - /* we don't need failed thumb anymore */ - IMB_freeImBuf(img); - img = NULL; - } - } + char thumb_hash[33]; + const bool use_hash = thumbhash_from_path(file_path, source, thumb_hash); + + img = thumb_create_or_fail(file_path, uri, thumb_name, use_hash, thumb_hash, size, source); } } } diff --git a/source/blender/imbuf/intern/thumbs_font.c b/source/blender/imbuf/intern/thumbs_font.c index 7c94742a187..4b024f3c51b 100644 --- a/source/blender/imbuf/intern/thumbs_font.c +++ b/source/blender/imbuf/intern/thumbs_font.c @@ -25,6 +25,9 @@ */ #include "BLI_utildefines.h" +#include "BLI_string.h" +#include "BLI_fileops.h" +#include "BLI_hash_md5.h" #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" @@ -36,18 +39,18 @@ #include "../../blenfont/BLF_api.h" #include "../../blenfont/BLF_translation.h" /* 'N_' macro and BLF_lang_get()... */ +static const char *thumb_str[] = { + N_("AaBbCc"), + + N_("The quick"), + N_("brown fox"), + N_("jumps over"), + N_("the lazy dog"), +}; struct ImBuf *IMB_thumb_load_font(const char *filename, unsigned int x, unsigned int y) { const int font_size = y / 4; - const char *thumb_str[] = { - N_("AaBbCc"), - - N_("The quick"), - N_("brown fox"), - N_("jumps over"), - N_("the lazy dog"), - }; struct ImBuf *ibuf; float font_color[4]; @@ -72,7 +75,26 @@ struct ImBuf *IMB_thumb_load_font(const char *filename, unsigned int x, unsigned return ibuf; } -const char *IMB_thumb_load_font_get_language(void) +bool IMB_thumb_load_font_get_hash(char *r_hash) { - return BLF_lang_get(); + char buf[1024]; + char *str = buf; + size_t len = 0; + + int draw_str_lines = ARRAY_SIZE(thumb_str); + int i; + + unsigned char digest[16]; + + len += BLI_strncpy_rlen(str + len, THUMB_DEFAULT_HASH, sizeof(buf) - len); + + for (i = 0; (i < draw_str_lines) && (len < sizeof(buf)); i++) { + len += BLI_strncpy_rlen(str + len, BLF_translate_do(BLF_I18NCONTEXT_DEFAULT, thumb_str[i]), sizeof(buf) - len); + } + + BLI_hash_md5_buffer(str, len, digest); + r_hash[0] = '\0'; + BLI_hash_md5_to_hexdigest(digest, r_hash); + + return true; } diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c index fa16ebbb5da..82600421736 100644 --- a/source/blender/modifiers/intern/MOD_explode.c +++ b/source/blender/modifiers/intern/MOD_explode.c @@ -771,7 +771,7 @@ static DerivedMesh *cutEdges(ExplodeModifierData *emd, DerivedMesh *dm) for (i = 0; i < curdupface; i++) { mf = CDDM_get_tessface(splitdm, i); - test_index_face(mf, &splitdm->faceData, i, (mf->flag & ME_FACE_SEL ? 4 : 3)); + test_index_face(mf, &splitdm->faceData, i, ((mf->flag & ME_FACE_SEL) ? 4 : 3)); } BLI_edgehash_free(edgehash, NULL); diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c index 4fa86527334..2e431884845 100644 --- a/source/blender/modifiers/intern/MOD_screw.c +++ b/source/blender/modifiers/intern/MOD_screw.c @@ -148,7 +148,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, unsigned int i, j; unsigned int i1, i2; unsigned int step_tot = use_render_params ? ltmd->render_steps : ltmd->steps; - const bool do_flip = ltmd->flag & MOD_SCREW_NORMAL_FLIP ? 1 : 0; + const bool do_flip = (ltmd->flag & MOD_SCREW_NORMAL_FLIP) != 0; const int quad_ord[4] = { do_flip ? 3 : 0, @@ -158,9 +158,9 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, }; const int quad_ord_ofs[4] = { do_flip ? 2 : 0, - do_flip ? 1 : 1, + 1, do_flip ? 0 : 2, - do_flip ? 3 : 3, + 3, }; unsigned int maxVerts = 0, maxEdges = 0, maxPolys = 0; diff --git a/source/blender/python/intern/bpy_util.c b/source/blender/python/intern/bpy_util.c index 5846ccd8757..e876adfa58e 100644 --- a/source/blender/python/intern/bpy_util.c +++ b/source/blender/python/intern/bpy_util.c @@ -85,7 +85,6 @@ short BPy_reports_to_error(ReportList *reports, PyObject *exception, const bool bool BPy_errors_to_report_ex(ReportList *reports, const bool use_full, const bool use_location) { PyObject *pystring; - const char *cstring; if (!PyErr_Occurred()) return 1; @@ -109,13 +108,12 @@ bool BPy_errors_to_report_ex(ReportList *reports, const bool use_full, const boo return 0; } - cstring = _PyUnicode_AsString(pystring); - if (use_location) { const char *filename; int lineno; PyObject *pystring_format; /* workaround, see below */ + const char *cstring; PyC_FileAndNum(&filename, &lineno); if (filename == NULL) { @@ -123,19 +121,23 @@ bool BPy_errors_to_report_ex(ReportList *reports, const bool use_full, const boo } #if 0 /* ARG!. workaround for a bug in blenders use of vsnprintf */ - BKE_reportf(reports, RPT_ERROR, "%s\nlocation: %s:%d\n", cstring, filename, lineno); + BKE_reportf(reports, RPT_ERROR, "%s\nlocation: %s:%d\n", _PyUnicode_AsString(pystring), filename, lineno); #else - pystring_format = PyUnicode_FromFormat(TIP_("%s\nlocation: %s:%d\n"), cstring, filename, lineno); + pystring_format = PyUnicode_FromFormat( + TIP_("%s\nlocation: %s:%d\n"), + _PyUnicode_AsString(pystring), filename, lineno); + cstring = _PyUnicode_AsString(pystring_format); BKE_report(reports, RPT_ERROR, cstring); - Py_DECREF(pystring_format); /* workaround */ -#endif /* not exactly needed. just for testing */ fprintf(stderr, TIP_("%s\nlocation: %s:%d\n"), cstring, filename, lineno); + + Py_DECREF(pystring_format); /* workaround */ +#endif } else { - BKE_report(reports, RPT_ERROR, cstring); + BKE_report(reports, RPT_ERROR, _PyUnicode_AsString(pystring)); } diff --git a/source/blender/render/intern/raytrace/rayobject_instance.cpp b/source/blender/render/intern/raytrace/rayobject_instance.cpp index 01e592cba0c..d080ddcc375 100644 --- a/source/blender/render/intern/raytrace/rayobject_instance.cpp +++ b/source/blender/render/intern/raytrace/rayobject_instance.cpp @@ -197,7 +197,7 @@ static void RE_rayobject_instance_bb(RayObject *o, float *min, float *max) //There must be a faster way than rotating all the 8 vertexs of the BB for (i = 0; i < 8; i++) { - for (j = 0; j < 3; j++) t[j] = i & (1 << j) ? M[j] : m[j]; + for (j = 0; j < 3; j++) t[j] = (i & (1 << j)) ? M[j] : m[j]; mul_m4_v3(obj->target2global, t); DO_MINMAX(t, min, max); } diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index e81c913bc6f..9d1a5171b9e 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -159,7 +159,7 @@ typedef void (*wmUIHandlerRemoveFunc)(struct bContext *C, void *userdata); struct wmEventHandler *WM_event_add_ui_handler( const struct bContext *C, ListBase *handlers, wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove, - void *userdata, const bool accept_dbl_click); + void *userdata, const char flag); void WM_event_remove_ui_handler( ListBase *handlers, wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove, @@ -173,11 +173,21 @@ void WM_event_free_ui_handler_all( struct wmEventHandler *WM_event_add_modal_handler(struct bContext *C, struct wmOperator *op); void WM_event_remove_handlers(struct bContext *C, ListBase *handlers); +/* handler flag */ +enum { + WM_HANDLER_BLOCKING = (1 << 0), /* after this handler all others are ignored */ + WM_HANDLER_ACCEPT_DBL_CLICK = (1 << 1), /* handler accepts double key press events */ + + /* internal */ + WM_HANDLER_DO_FREE = (1 << 7), /* handler tagged to be freed in wm_handlers_do() */ +}; + struct wmEventHandler *WM_event_add_dropbox_handler(ListBase *handlers, ListBase *dropboxes); /* mouse */ void WM_event_add_mousemove(struct bContext *C); bool WM_modal_tweak_exit(const struct wmEvent *event, int tweak_event); +bool WM_event_is_absolute(const struct wmEvent *event); /* notifiers */ void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *reference); diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c index 68fd32cb450..d84b65847ca 100644 --- a/source/blender/windowmanager/intern/wm_cursors.c +++ b/source/blender/windowmanager/intern/wm_cursors.c @@ -313,21 +313,22 @@ void WM_cursor_time(wmWindow *win, int nr) } -/* ****************************************************************** - * Custom Cursor Description: +/** + * Custom Cursor Description + * ========================= * * Each bit represents a pixel, so 1 byte = 8 pixels, * the bytes go Left to Right. Top to bottom * the bits in a byte go right to left * (ie; 0x01, 0x80 represents a line of 16 pix with the first and last pix set.) * - * A 0 in the bitmap = bg_color, a 1 fg_color - * a 0 in the mask = transparent pix. + * - A 0 in the bitmap = bg_color, a 1 fg_color + * - a 0 in the mask = transparent pix. * * Until 32x32 cursors are supported on all platforms, the size of the * small cursors MUST be 16x16. * - * Large cursors have a MAXSIZE of 32x32. + * Large cursors have a maximum size of 32x32. * * Other than that, the specified size of the cursors is just a guideline, * However, the char array that defines the BM and MASK must be byte aligned. @@ -335,18 +336,20 @@ void WM_cursor_time(wmWindow *win, int nr) * (3 bytes = 17 bits rounded up to nearest whole byte). Pad extra bits * in mask with 0's. * - * Setting big_bm = NULL disables the large version of the cursor. + * Setting `big_bm = NULL` disables the large version of the cursor. * - * ******************************************************************* + * ---- * * There is a nice Python GUI utility that can be used for drawing cursors in * this format in the Blender source distribution, in - * blender/source/tools/MakeCursor.py . Start it with $ python MakeCursor.py - * It will copy its output to the console when you press 'Do it'. + * `./source/tools/utils/make_cursor_gui.py` . * + * Start it with the command `python3 make_cursor_gui.py` + * It will copy its output to the console when you press 'Do it'. */ -/* Because defining a cursor mixes declarations and executable code +/** + * Because defining a cursor mixes declarations and executable code * each cursor needs it's own scoping block or it would be split up * over several hundred lines of code. To enforce/document this better * I define 2 pretty brain-dead macros so it's obvious what the extra "[]" diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index e8e557ae19f..893e05b2093 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -566,10 +566,9 @@ void WM_event_print(const wmEvent *event) RNA_enum_identifier(event_type_items, event->type, &type_id); RNA_enum_identifier(event_value_items, event->val, &val_id); - printf("wmEvent type:%d / %s, val:%d / %s, \n" - " shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d, \n" - " mouse:(%d,%d), ascii:'%c', utf8:'%.*s', " - " keymap_idname:%s, pointer:%p\n", + printf("wmEvent type:%d / %s, val:%d / %s,\n" + " shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d,\n" + " mouse:(%d,%d), ascii:'%c', utf8:'%.*s', keymap_idname:%s, pointer:%p\n", event->type, type_id, event->val, val_id, event->shift, event->ctrl, event->alt, event->oskey, event->keymodifier, event->x, event->y, event->ascii, @@ -579,17 +578,19 @@ void WM_event_print(const wmEvent *event) if (ISNDOF(event->type)) { const wmNDOFMotionData *ndof = event->customdata; if (event->type == NDOF_MOTION) { - printf(" ndof: rot: (%.4f %.4f %.4f),\n" - " tx: (%.4f %.4f %.4f),\n" - " dt: %.4f, progress: %d\n", - UNPACK3(ndof->rvec), - UNPACK3(ndof->tvec), - ndof->dt, ndof->progress); + printf(" ndof: rot: (%.4f %.4f %.4f), tx: (%.4f %.4f %.4f), dt: %.4f, progress: %d\n", + UNPACK3(ndof->rvec), UNPACK3(ndof->tvec), ndof->dt, ndof->progress); } else { /* ndof buttons printed already */ } } + + if (event->tablet_data) { + const wmTabletData *wmtab = event->tablet_data; + printf(" tablet: active: %d, pressure %.4f, tilt: (%.4f %.4f)\n", + wmtab->Active, wmtab->Pressure, wmtab->Xtilt, wmtab->Ytilt); + } } else { printf("wmEvent - NULL\n"); @@ -617,6 +618,11 @@ void WM_report_banner_show(const bContext *C) wm_reports->reporttimer->customdata = rti; } +bool WM_event_is_absolute(const wmEvent *event) +{ + return (event->tablet_data != NULL); +} + static void wm_add_reports(const bContext *C, ReportList *reports) { /* if the caller owns them, handle this */ @@ -702,7 +708,8 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool ca wm_add_reports(C, op->reports); } -/* this function is mainly to check that the rules for freeing +/** + * This function is mainly to check that the rules for freeing * an operator are kept in sync. */ static bool wm_operator_register_check(wmWindowManager *wm, wmOperatorType *ot) @@ -821,23 +828,29 @@ int WM_operator_call(bContext *C, wmOperator *op) return WM_operator_call_ex(C, op, false); } -/* this is intended to be used when an invoke operator wants to call exec on its self +/** + * This is intended to be used when an invoke operator wants to call exec on its self * and is basically like running op->type->exec() directly, no poll checks no freeing, - * since we assume whoever called invoke will take care of that */ + * since we assume whoever called invoke will take care of that + */ int WM_operator_call_notest(bContext *C, wmOperator *op) { return wm_operator_exec_notest(C, op); } -/* do this operator again, put here so it can share above code */ +/** + * Execute this operator again, put here so it can share above code + */ int WM_operator_repeat(bContext *C, wmOperator *op) { return wm_operator_exec(C, op, true, true); } -/* true if WM_operator_repeat can run +/** + * \return true if #WM_operator_repeat can run * simple check for now but may become more involved. - * To be sure the operator can run call WM_operator_poll(C, op->type) also, since this call - * checks if WM_operator_repeat() can run at all, not that it WILL run at any time. */ + * To be sure the operator can run call `WM_operator_poll(C, op->type)` also, since this call + * checks if WM_operator_repeat() can run at all, not that it WILL run at any time. + */ bool WM_operator_repeat_check(const bContext *UNUSED(C), wmOperator *op) { if (op->type->exec != NULL) { @@ -1043,8 +1056,9 @@ bool WM_operator_last_properties_store(wmOperator *UNUSED(op)) #endif -static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, - PointerRNA *properties, ReportList *reports, const bool poll_only) +static int wm_operator_invoke( + bContext *C, wmOperatorType *ot, wmEvent *event, + PointerRNA *properties, ReportList *reports, const bool poll_only) { int retval = OPERATOR_PASS_THROUGH; @@ -1141,7 +1155,7 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, } if (wrap) { - rcti *winrect = NULL; + const rcti *winrect = NULL; ARegion *ar = CTX_wm_region(C); ScrArea *sa = CTX_wm_area(C); @@ -1150,7 +1164,7 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, { winrect = &ar->winrct; } - else if (sa) { + else if (sa && BLI_rcti_isect_pt_v(&sa->totrct, &event->x)) { winrect = &sa->totrct; } @@ -1179,12 +1193,15 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, return retval; } -/* WM_operator_name_call is the main accessor function +/** + * #WM_operator_name_call is the main accessor function * this is for python to access since its done the operator lookup * - * invokes operator in context */ -static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports, - const short context, const bool poll_only) + * invokes operator in context + */ +static int wm_operator_call_internal( + bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports, + const short context, const bool poll_only) { wmEvent *event; @@ -1324,13 +1341,16 @@ int WM_operator_name_call(bContext *C, const char *opstring, short context, Poin return 0; } -/* Similar to WM_operator_name_call called with WM_OP_EXEC_DEFAULT context. - * - wmOperatorType is used instead of operator name since python already has the operator type - * - poll() must be called by python before this runs. - * - reports can be passed to this function (so python can report them as exceptions) +/** + * Similar to #WM_operator_name_call called with #WM_OP_EXEC_DEFAULT context. + * + * - #wmOperatorType is used instead of operator name since python already has the operator type. + * - `poll()` must be called by python before this runs. + * - reports can be passed to this function (so python can report them as exceptions). */ -int WM_operator_call_py(bContext *C, wmOperatorType *ot, short context, - PointerRNA *properties, ReportList *reports, const bool is_undo) +int WM_operator_call_py( + bContext *C, wmOperatorType *ot, short context, + PointerRNA *properties, ReportList *reports, const bool is_undo) { int retval = OPERATOR_CANCELLED; @@ -1607,7 +1627,8 @@ static void wm_event_modalkeymap(const bContext *C, wmOperator *op, wmEvent *eve } } -/* Check whether operator is allowed to run in case interface is locked, +/** + * Check whether operator is allowed to run in case interface is locked, * If interface is unlocked, will always return truth. */ static bool wm_operator_check_locked_interface(bContext *C, wmOperatorType *ot) @@ -2610,11 +2631,12 @@ void WM_event_fileselect_event(wmWindowManager *wm, void *ophandle, int eventval /* operator is supposed to have a filled "path" property */ /* optional property: filetype (XXX enum?) */ -/* Idea is to keep a handler alive on window queue, owning the operator. +/** + * The idea here is to keep a handler alive on window queue, owning the operator. * The filewindow can send event to make it execute, thus ensuring * executing happens outside of lower level queues, with UI refreshed. - * Should also allow multiwin solutions */ - + * Should also allow multiwin solutions + */ void WM_event_add_fileselect(bContext *C, wmOperator *op) { wmEventHandler *handler, *handlernext; @@ -2760,7 +2782,7 @@ void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap) wmEventHandler *WM_event_add_ui_handler( const bContext *C, ListBase *handlers, wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove, - void *userdata, const bool accept_dbl_click) + void *userdata, const char flag) { wmEventHandler *handler = MEM_callocN(sizeof(wmEventHandler), "event ui handler"); handler->ui_handle = ui_handle; @@ -2777,9 +2799,8 @@ wmEventHandler *WM_event_add_ui_handler( handler->ui_menu = NULL; } - if (accept_dbl_click) { - handler->flag |= WM_HANDLER_ACCEPT_DBL_CLICK; - } + BLI_assert((flag & WM_HANDLER_DO_FREE) == 0); + handler->flag = flag; BLI_addhead(handlers, handler); diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c index 6bc858e861a..f8258d18c1a 100644 --- a/source/blender/windowmanager/intern/wm_jobs.c +++ b/source/blender/windowmanager/intern/wm_jobs.c @@ -157,8 +157,8 @@ static void wm_job_main_thread_yield(wmJob *wm_job, bool ending) BLI_ticket_mutex_lock(wm_job->main_thread_mutex); } -/* finds: - * if type or owner, compare for it, otherwise any matching job +/** + * Finds if type or owner, compare for it, otherwise any matching job. */ static wmJob *wm_job_find(wmWindowManager *wm, void *owner, const int job_type) { @@ -185,9 +185,12 @@ static wmJob *wm_job_find(wmWindowManager *wm, void *owner, const int job_type) /* ******************* public API ***************** */ -/* returns current or adds new job, but doesnt run it */ -/* every owner only gets a single job, adding a new one will stop running job and - * when stopped it starts the new one */ +/** + * \return current job or adds new job, but doesnt run it. + * + * \note every owner only gets a single job, + * adding a new one will stop running job and when stopped it starts the new one. + */ wmJob *WM_jobs_get(wmWindowManager *wm, wmWindow *win, void *owner, const char *name, int flag, int job_type) { wmJob *wm_job = wm_job_find(wm, owner, job_type); @@ -375,8 +378,10 @@ static void wm_jobs_test_suspend_stop(wmWindowManager *wm, wmJob *test) // if (suspend) printf("job suspended: %s\n", test->name); } -/* if job running, the same owner gave it a new job */ -/* if different owner starts existing startjob, it suspends itself */ +/** + * if job running, the same owner gave it a new job. + * if different owner starts existing startjob, it suspends itself + */ void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job) { if (wm_job->running) { diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index bdb45712f22..d02b42bd8ed 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -577,12 +577,13 @@ void WM_operator_bl_idname(char *to, const char *from) to[0] = 0; } -/* Print a string representation of the operator, with the args that it runs so python can run it again. +/** + * Print a string representation of the operator, with the args that it runs so python can run it again. * * When calling from an existing wmOperator, better to use simple version: - * WM_operator_pystring(C, op); + * `WM_operator_pystring(C, op);` * - * Note: both op and opptr may be NULL (op is only used for macro operators). + * \note Both \a op and \a opptr may be `NULL` (\a op is only used for macro operators). */ char *WM_operator_pystring_ex(bContext *C, wmOperator *op, const bool all_args, const bool macro_args, wmOperatorType *ot, PointerRNA *opptr) @@ -1722,18 +1723,20 @@ static int wm_operator_props_popup_ex(bContext *C, wmOperator *op, return OPERATOR_RUNNING_MODAL; } -/* Same as WM_operator_props_popup but don't use operator redo. - * just wraps WM_operator_props_dialog_popup. +/** + * Same as #WM_operator_props_popup but don't use operator redo. + * just wraps #WM_operator_props_dialog_popup. */ int WM_operator_props_popup_confirm(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { return wm_operator_props_popup_ex(C, op, false, false); } -/* Same as WM_operator_props_popup but call the operator first, +/** + * Same as #WM_operator_props_popup but call the operator first, * This way - the button values correspond to the result of the operator. - * Without this, first access to a button will make the result jump, - * see [#32452] */ + * Without this, first access to a button will make the result jump, see T32452. + */ int WM_operator_props_popup_call(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { return wm_operator_props_popup_ex(C, op, true, true); @@ -3166,9 +3169,10 @@ void WM_paint_cursor_end(wmWindowManager *wm, void *handle) /* **************** Border gesture *************** */ -/* Border gesture has two types: - * 1) WM_GESTURE_CROSS_RECT: starts a cross, on mouse click it changes to border - * 2) WM_GESTURE_RECT: starts immediate as a border, on mouse click or release it ends +/** + * Border gesture has two types: + * -# #WM_GESTURE_CROSS_RECT: starts a cross, on mouse click it changes to border. + * -# #WM_GESTURE_RECT: starts immediate as a border, on mouse click or release it ends. * * It stores 4 values (xmin, xmax, ymin, ymax) and event it ended with (event_type) */ @@ -4107,12 +4111,15 @@ typedef enum { RC_PROP_REQUIRE_BOOL = 4, } RCPropFlags; -/* attempt to retrieve the rna pointer/property from an rna path; - * returns 0 for failure, 1 for success, and also 1 if property is not - * set */ -static int radial_control_get_path(PointerRNA *ctx_ptr, wmOperator *op, - const char *name, PointerRNA *r_ptr, - PropertyRNA **r_prop, int req_length, RCPropFlags flags) +/** + * Attempt to retrieve the rna pointer/property from an rna path. + * + * \return 0 for failure, 1 for success, and also 1 if property is not set. + */ +static int radial_control_get_path( + PointerRNA *ctx_ptr, wmOperator *op, + const char *name, PointerRNA *r_ptr, + PropertyRNA **r_prop, int req_length, RCPropFlags flags) { PropertyRNA *unused_prop; int len; diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c index 4ce2415e310..d081644fa61 100644 --- a/source/blender/windowmanager/intern/wm_subwindow.c +++ b/source/blender/windowmanager/intern/wm_subwindow.c @@ -54,11 +54,12 @@ #include "WM_api.h" #include "wm_subwindow.h" -/* wmSubWindow stored in wmWindow... but not exposed outside this C file */ -/* it seems a bit redundant (area regions can store it too, but we keep it - * because we can store all kind of future opengl fanciness here */ - -/* we use indices and array because: +/** + * \note #wmSubWindow stored in #wmWindow but not exposed outside this C file, + * it seems a bit redundant (area regions can store it too, but we keep it + * because we can store all kind of future opengl fanciness here. + * + * We use indices and array because: * - index has safety, no pointers from this C file hanging around * - fast lookups of indices with array, list would give overhead * - old code used it this way... diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 6d1bf51902c..f704e985f8f 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -1117,10 +1117,10 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr } -/* This timer system only gives maximum 1 timer event per redraw cycle, +/** + * This timer system only gives maximum 1 timer event per redraw cycle, * to prevent queues to get overloaded. - * Timer handlers should check for delta to decide if they just - * update, or follow real time. + * Timer handlers should check for delta to decide if they just update, or follow real time. * Timer handlers can also set duration to match frames passed */ static int wm_window_timer(const bContext *C) diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h index 061b869f46c..9127d3ec6f0 100644 --- a/source/blender/windowmanager/wm_event_system.h +++ b/source/blender/windowmanager/wm_event_system.h @@ -47,8 +47,8 @@ struct wmWidget; typedef struct wmEventHandler { struct wmEventHandler *next, *prev; - int type; /* WM_HANDLER_DEFAULT, ... */ - int flag; /* WM_HANDLER_BLOCKING, ... */ + char type; /* WM_HANDLER_DEFAULT, ... */ + char flag; /* WM_HANDLER_BLOCKING, ... */ /* keymap handler */ wmKeyMap *keymap; /* pointer to builtin/custom keymaps */ @@ -81,13 +81,6 @@ enum { WM_HANDLER_FILESELECT }; -/* handler flag */ -enum { - WM_HANDLER_BLOCKING = (1 << 0), /* after this handler all others are ignored */ - WM_HANDLER_DO_FREE = (1 << 1), /* handler tagged to be freed in wm_handlers_do() */ - WM_HANDLER_ACCEPT_DBL_CLICK = (1 << 2), /* handler accepts double key press events */ -}; - /* wm_event_system.c */ void wm_event_free_all (wmWindow *win); void wm_event_free (wmEvent *event); diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 09047206694..c4647a86b93 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -651,9 +651,9 @@ elseif(WIN32) execute_process( COMMAND \${CMAKE_COMMAND} -E make_directory - \"\${CMAKE_INSTALL_PREFIX}/${BLENDER_VERSION}/python/lib\" + \"\${CMAKE_INSTALL_PREFIX}/${BLENDER_VERSION}/python\" COMMAND \${CMAKE_COMMAND} -E - chdir \"\${CMAKE_INSTALL_PREFIX}/${BLENDER_VERSION}/python/lib\" + chdir \"\${CMAKE_INSTALL_PREFIX}/${BLENDER_VERSION}/python\" \${CMAKE_COMMAND} -E tar xzfv \"\${PYTHON_ZIP}\" ) diff --git a/source/creator/creator.c b/source/creator/creator.c index 8c4ec595eb3..29fad1352fd 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -680,7 +680,11 @@ LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo) /* If this is a stack overflow then we can't walk the stack, so just show * where the error happened */ if (EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode) { +#ifdef NDEBUG + TerminateProcess(GetCurrentProcess(), SIGSEGV); +#else blender_crash_handler(SIGSEGV); +#endif } return EXCEPTION_EXECUTE_HANDLER; diff --git a/source/gameengine/Expressions/PyObjectPlus.h b/source/gameengine/Expressions/PyObjectPlus.h index 34b814d7416..c3ce98ed27a 100644 --- a/source/gameengine/Expressions/PyObjectPlus.h +++ b/source/gameengine/Expressions/PyObjectPlus.h @@ -111,6 +111,8 @@ typedef struct PyObjectPlus_Proxy { /* Opposite of BGE_PROXY_REF */ #define BGE_PROXY_FROM_REF(_self) (((PyObjectPlus *)_self)->GetProxy()) +/* Same as 'BGE_PROXY_REF' but doesn't incref. */ +#define BGE_PROXY_FROM_REF_BORROW(_self) _bge_proxy_from_ref_borrow((void *)_self) // This must be the first line of each @@ -631,6 +633,17 @@ public: #ifdef WITH_PYTHON PyObject *PyUnicode_From_STR_String(const STR_String& str); + +inline PyObject *_bge_proxy_from_ref_borrow(void *self_v) +{ + PyObject *self_proxy = BGE_PROXY_FROM_REF(self_v); + /* this is typically _very_ bad practice, + * however we know the proxy is owned by 'self_v' */ + self_proxy->ob_refcnt--; + return self_proxy; +} + #endif + #endif /* __PYOBJECTPLUS_H__ */ diff --git a/source/gameengine/GameLogic/SCA_PropertySensor.cpp b/source/gameengine/GameLogic/SCA_PropertySensor.cpp index 6f34f8710c1..6841d2a8ea1 100644 --- a/source/gameengine/GameLogic/SCA_PropertySensor.cpp +++ b/source/gameengine/GameLogic/SCA_PropertySensor.cpp @@ -265,13 +265,8 @@ bool SCA_PropertySensor::CheckPropertyCondition() //the concept of Edge and Level triggering has unwanted effect for KX_PROPSENSOR_CHANGED //see Game Engine bugtracker [ #3809 ] - if (m_checktype != KX_PROPSENSOR_CHANGED) - { - m_recentresult=result; - } else - { - m_recentresult=result;//true; - } + m_recentresult = result; + return result; } diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp index 14a7324d2b9..e77960b99b1 100644 --- a/source/gameengine/Ketsji/KX_GameObject.cpp +++ b/source/gameengine/Ketsji/KX_GameObject.cpp @@ -2530,7 +2530,9 @@ int KX_GameObject::pyattr_set_record_animation(void *self_v, const KX_PYATTRIBUT PyObject *KX_GameObject::pyattr_get_worldPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS - return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_POS_GLOBAL); + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_POS_GLOBAL); #else KX_GameObject* self = static_cast<KX_GameObject*>(self_v); return PyObjectFrom(self->NodeGetWorldPosition()); @@ -2552,7 +2554,9 @@ int KX_GameObject::pyattr_set_worldPosition(void *self_v, const KX_PYATTRIBUTE_D PyObject *KX_GameObject::pyattr_get_localPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS - return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_POS_LOCAL); + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_POS_LOCAL); #else KX_GameObject* self = static_cast<KX_GameObject*>(self_v); return PyObjectFrom(self->NodeGetLocalPosition()); @@ -2574,7 +2578,9 @@ int KX_GameObject::pyattr_set_localPosition(void *self_v, const KX_PYATTRIBUTE_D PyObject *KX_GameObject::pyattr_get_localInertia(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS - return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_INERTIA_LOCAL); + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_INERTIA_LOCAL); #else KX_GameObject* self = static_cast<KX_GameObject*>(self_v); if (self->GetPhysicsController1()) @@ -2586,7 +2592,9 @@ PyObject *KX_GameObject::pyattr_get_localInertia(void *self_v, const KX_PYATTRIB PyObject *KX_GameObject::pyattr_get_worldOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS - return Matrix_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, 3, mathutils_kxgameob_matrix_cb_index, MATHUTILS_MAT_CB_ORI_GLOBAL); + return Matrix_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, 3, + mathutils_kxgameob_matrix_cb_index, MATHUTILS_MAT_CB_ORI_GLOBAL); #else KX_GameObject* self = static_cast<KX_GameObject*>(self_v); return PyObjectFrom(self->NodeGetWorldOrientation()); @@ -2611,7 +2619,9 @@ int KX_GameObject::pyattr_set_worldOrientation(void *self_v, const KX_PYATTRIBUT PyObject *KX_GameObject::pyattr_get_localOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS - return Matrix_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, 3, mathutils_kxgameob_matrix_cb_index, MATHUTILS_MAT_CB_ORI_LOCAL); + return Matrix_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, 3, + mathutils_kxgameob_matrix_cb_index, MATHUTILS_MAT_CB_ORI_LOCAL); #else KX_GameObject* self = static_cast<KX_GameObject*>(self_v); return PyObjectFrom(self->NodeGetLocalOrientation()); @@ -2635,7 +2645,9 @@ int KX_GameObject::pyattr_set_localOrientation(void *self_v, const KX_PYATTRIBUT PyObject *KX_GameObject::pyattr_get_worldScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS - return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_SCALE_GLOBAL); + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_SCALE_GLOBAL); #else KX_GameObject* self = static_cast<KX_GameObject*>(self_v); return PyObjectFrom(self->NodeGetWorldScaling()); @@ -2657,7 +2669,9 @@ int KX_GameObject::pyattr_set_worldScaling(void *self_v, const KX_PYATTRIBUTE_DE PyObject *KX_GameObject::pyattr_get_localScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS - return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_SCALE_LOCAL); + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_SCALE_LOCAL); #else KX_GameObject* self = static_cast<KX_GameObject*>(self_v); return PyObjectFrom(self->NodeGetLocalScaling()); @@ -2759,7 +2773,9 @@ int KX_GameObject::pyattr_set_worldTransform(void *self_v, const KX_PYATTRIBUTE_ PyObject *KX_GameObject::pyattr_get_worldLinearVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS - return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_LINVEL_GLOBAL); + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_LINVEL_GLOBAL); #else KX_GameObject* self = static_cast<KX_GameObject*>(self_v); return PyObjectFrom(GetLinearVelocity(false)); @@ -2781,7 +2797,9 @@ int KX_GameObject::pyattr_set_worldLinearVelocity(void *self_v, const KX_PYATTRI PyObject *KX_GameObject::pyattr_get_localLinearVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS - return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_LINVEL_LOCAL); + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_LINVEL_LOCAL); #else KX_GameObject* self = static_cast<KX_GameObject*>(self_v); return PyObjectFrom(GetLinearVelocity(true)); @@ -2803,7 +2821,9 @@ int KX_GameObject::pyattr_set_localLinearVelocity(void *self_v, const KX_PYATTRI PyObject *KX_GameObject::pyattr_get_worldAngularVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS - return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_ANGVEL_GLOBAL); + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_ANGVEL_GLOBAL); #else KX_GameObject* self = static_cast<KX_GameObject*>(self_v); return PyObjectFrom(GetAngularVelocity(false)); @@ -2825,7 +2845,9 @@ int KX_GameObject::pyattr_set_worldAngularVelocity(void *self_v, const KX_PYATTR PyObject *KX_GameObject::pyattr_get_localAngularVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS - return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_ANGVEL_LOCAL); + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_ANGVEL_LOCAL); #else KX_GameObject* self = static_cast<KX_GameObject*>(self_v); return PyObjectFrom(GetAngularVelocity(true)); @@ -2946,7 +2968,9 @@ PyObject *KX_GameObject::pyattr_get_meshes(void *self_v, const KX_PYATTRIBUTE_DE PyObject *KX_GameObject::pyattr_get_obcolor(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS - return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 4, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_OBJECT_COLOR); + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 4, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_OBJECT_COLOR); #else KX_GameObject* self = static_cast<KX_GameObject*>(self_v); return PyObjectFrom(self->GetObjectColor()); diff --git a/source/gameengine/Ketsji/KX_ObjectActuator.cpp b/source/gameengine/Ketsji/KX_ObjectActuator.cpp index 717d58e0ca7..12abcb250a7 100644 --- a/source/gameengine/Ketsji/KX_ObjectActuator.cpp +++ b/source/gameengine/Ketsji/KX_ObjectActuator.cpp @@ -522,7 +522,9 @@ static Mathutils_Callback mathutils_obactu_vector_cb = { PyObject *KX_ObjectActuator::pyattr_get_linV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxobactu_vector_cb_index, MATHUTILS_VEC_CB_LINV); + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxobactu_vector_cb_index, MATHUTILS_VEC_CB_LINV); } int KX_ObjectActuator::pyattr_set_linV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) @@ -538,7 +540,9 @@ int KX_ObjectActuator::pyattr_set_linV(void *self_v, const KX_PYATTRIBUTE_DEF *a PyObject *KX_ObjectActuator::pyattr_get_angV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxobactu_vector_cb_index, MATHUTILS_VEC_CB_ANGV); + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxobactu_vector_cb_index, MATHUTILS_VEC_CB_ANGV); } int KX_ObjectActuator::pyattr_set_angV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) diff --git a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp index 237f485134a..b42200783e4 100644 --- a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp +++ b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp @@ -87,8 +87,6 @@ PyObject *KX_VehicleWrapper::PyAddWheel(PyObject *args) if (gameOb->GetSGNode()) { - PHY_IMotionState* motionState = new KX_MotionState(gameOb->GetSGNode()); - MT_Vector3 attachPos,attachDir,attachAxle; if(!PyVecTo(pylistPos,attachPos)) { PyErr_SetString(PyExc_AttributeError, @@ -115,6 +113,7 @@ PyObject *KX_VehicleWrapper::PyAddWheel(PyObject *args) return NULL; } + PHY_IMotionState *motionState = new KX_MotionState(gameOb->GetSGNode()); m_vehicle->AddWheel(motionState,attachPos,attachDir,attachAxle,suspensionRestLength,wheelRadius,hasSteering); } diff --git a/source/gameengine/Ketsji/KX_WorldInfo.cpp b/source/gameengine/Ketsji/KX_WorldInfo.cpp index f6caaf03066..8678b058761 100644 --- a/source/gameengine/Ketsji/KX_WorldInfo.cpp +++ b/source/gameengine/Ketsji/KX_WorldInfo.cpp @@ -418,7 +418,9 @@ PyObject *KX_WorldInfo::pyattr_get_mist_typeconst(void *self_v, const KX_PYATTRI PyObject *KX_WorldInfo::pyattr_get_mist_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS - return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_world_vector_cb_index, MATHUTILS_VEC_CB_MIST_COLOR); + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_world_vector_cb_index, MATHUTILS_VEC_CB_MIST_COLOR); #else KX_WorldInfo *self = static_cast<KX_WorldInfo*>(self_v); return PyObjectFrom(MT_Vector3(self->m_mistcolor)); @@ -442,7 +444,9 @@ PyObject *KX_WorldInfo::pyattr_get_back_color(void *self_v, const KX_PYATTRIBUTE { #ifdef USE_MATHUTILS - return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_world_vector_cb_index, MATHUTILS_VEC_CB_BACK_COLOR); + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_world_vector_cb_index, MATHUTILS_VEC_CB_BACK_COLOR); #else KX_WorldInfo *self = static_cast<KX_WorldInfo*>(self_v); return PyObjectFrom(MT_Vector3(self->m_backgroundcolor)); @@ -465,7 +469,9 @@ int KX_WorldInfo::pyattr_set_back_color(void *self_v, const KX_PYATTRIBUTE_DEF * PyObject *KX_WorldInfo::pyattr_get_ambient_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS - return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_world_vector_cb_index, MATHUTILS_VEC_CB_AMBIENT_COLOR); + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_world_vector_cb_index, MATHUTILS_VEC_CB_AMBIENT_COLOR); #else KX_WorldInfo *self = static_cast<KX_WorldInfo*>(self_v); return PyObjectFrom(MT_Vector3(self->m_ambientcolor)); diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp index edc5b91c4c0..8ea2b4f299d 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp @@ -2203,8 +2203,6 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject *gameobj, class RA MFace *mf; MVert *mv; - int flen; - if (CustomData_has_layer(&dm->faceData, CD_MTFACE)) { MTFace *tface = (MTFace *)dm->getTessFaceDataArray(dm, CD_MTFACE); MTFace *tf; @@ -2214,6 +2212,8 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject *gameobj, class RA for (mf = mface, tf = tface, i = 0; i < numpolys; mf++, tf++, i++) { if (tf->mode & TF_DYNAMIC) { + int flen; + if (mf->v4) { tot_bt_tris += 2; flen = 4; @@ -2255,12 +2255,10 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject *gameobj, class RA fv_pt = quad_verts; *poly_index_pt++ = origi; *poly_index_pt++ = origi; - flen = 4; } else { fv_pt = tri_verts; *poly_index_pt++ = origi; - flen = 3; } for (; *fv_pt > -1; fv_pt++) { diff --git a/tests/gtests/blenlib/BLI_stack_test.cc b/tests/gtests/blenlib/BLI_stack_test.cc index 08701356816..44956a589dc 100644 --- a/tests/gtests/blenlib/BLI_stack_test.cc +++ b/tests/gtests/blenlib/BLI_stack_test.cc @@ -11,6 +11,14 @@ extern "C" { #define SIZE 1024 +/* number of items per chunk. use a small value to expose bugs */ +#define STACK_CHUNK_SIZE 8 + +/* Ensure block size is set to #STACK_NEW_EX_ARGS */ +#define BLI_stack_new(esize, descr) \ + BLI_stack_new_ex(esize, descr, esize * STACK_CHUNK_SIZE) + + TEST(stack, Empty) { BLI_Stack *stack; @@ -110,18 +118,60 @@ TEST(stack, Peek) EXPECT_EQ(BLI_stack_is_empty(stack), true); } +/* Check that clearing the stack leaves in it a correct state. */ +TEST(stack, Clear) +{ + const int tot_rerun = 4; + int rerun; + + /* based on range test */ + int tot = SIZE; + BLI_Stack *stack; + int in, out; + + /* use a small chunk size to ensure we test */ + stack = BLI_stack_new(sizeof(in), __func__); + + for (rerun = 0; rerun < tot_rerun; rerun++) { + for (in = 0; in < tot; in++) { + BLI_stack_push(stack, (void *)&in); + } + + BLI_stack_clear(stack); + EXPECT_EQ(BLI_stack_is_empty(stack), true); + + /* and again, this time check its valid */ + for (in = 0; in < tot; in++) { + BLI_stack_push(stack, (void *)&in); + } + + for (in = tot - 1; in >= 0; in--) { + EXPECT_EQ(BLI_stack_is_empty(stack), false); + BLI_stack_pop(stack, (void *)&out); + EXPECT_EQ(in, out); + } + + EXPECT_EQ(BLI_stack_is_empty(stack), true); + + /* without this, we wont test case when mixed free/used */ + tot /= 2; + } + + BLI_stack_free(stack); +} + TEST(stack, Reuse) { const int sizes[] = {3, 11, 81, 400, 999, 12, 1, 9721, 7, 99, 5, 0}; int sizes_test[ARRAY_SIZE(sizes)]; const int *s; - int in, out, i; + int out, i; int sum, sum_test; BLI_Stack *stack; - stack = BLI_stack_new(sizeof(in), __func__); + stack = BLI_stack_new(sizeof(i), __func__); /* add a bunch of numbers, ensure we get same sum out */ sum = 0; |