static bool kdtree2d_isect_tri( struct KDTree2D *tree, const unsigned int ind[3]) { const float *vs[3]; unsigned int i; struct KDRange2D bounds[2] = { {FLT_MAX, -FLT_MAX}, {FLT_MAX, -FLT_MAX}, }; float tri_center[2] = {0.0f, 0.0f}; for (i = 0; i < 3; i++) { vs[i] = tree->coords[ind[i]]; add_v2_v2(tri_center, vs[i]); CLAMP_MAX(bounds[0].min, vs[i][0]); CLAMP_MIN(bounds[0].max, vs[i][0]); CLAMP_MAX(bounds[1].min, vs[i][1]); CLAMP_MIN(bounds[1].max, vs[i][1]); } mul_v2_fl(tri_center, 1.0f / 3.0f); return kdtree2d_isect_tri_recursive(tree, ind, vs, tri_center, bounds, &tree->nodes[tree->root]); }
/** * Apply smooth for thickness to stroke point (use pressure) * \param gps: Stroke to smooth * \param i: Point index * \param inf: Amount of smoothing to apply */ bool gp_smooth_stroke_thickness(bGPDstroke *gps, int i, float inf) { bGPDspoint *ptb = &gps->points[i]; /* Do nothing if not enough points */ if (gps->totpoints <= 2) { return false; } /* Compute theoretical optimal value using distances */ bGPDspoint *pta, *ptc; int before = i - 1; int after = i + 1; CLAMP_MIN(before, 0); CLAMP_MAX(after, gps->totpoints - 1); pta = &gps->points[before]; ptc = &gps->points[after]; /* the optimal value is the corresponding to the interpolation of the pressure * at the distance of point b */ float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x); float optimal = (1.0f - fac) * pta->pressure + fac * ptc->pressure; /* Based on influence factor, blend between original and optimal */ ptb->pressure = (1.0f - inf) * ptb->pressure + inf * optimal; return true; }
static void camera_to_frame_view_cb(const float co[3], void *user_data) { CameraViewFrameData *data = (CameraViewFrameData *)user_data; unsigned int i; for (i = 0; i < CAMERA_VIEWFRAME_NUM_PLANES; i++) { const float nd = dist_signed_squared_to_plane_v3(co, data->plane_tx[i]); CLAMP_MAX(data->dist_vals_sq[i], nd); } if (data->is_ortho) { const float d = dot_v3v3(data->camera_no, co); CLAMP_MAX(data->dist_to_cam, d); } data->tot++; }
/* helper function returns length of the 'value', -1 on error */ int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix) { const int flag = array_max; int size; array_max &= ~MU_ARRAY_FLAGS; #if 1 /* approx 6x speedup for mathutils types */ if ((size = VectorObject_Check(value) ? ((VectorObject *)value)->size : 0) || (size = EulerObject_Check(value) ? 3 : 0) || (size = QuaternionObject_Check(value) ? 4 : 0) || (size = ColorObject_Check(value) ? 3 : 0)) { if (BaseMath_ReadCallback((BaseMathObject *)value) == -1) { return -1; } if (flag & MU_ARRAY_SPILL) { CLAMP_MAX(size, array_max); } if (size > array_max || size < array_min) { if (array_max == array_min) { PyErr_Format(PyExc_ValueError, "%.200s: sequence size is %d, expected %d", error_prefix, size, array_max); } else { PyErr_Format(PyExc_ValueError, "%.200s: sequence size is %d, expected [%d - %d]", error_prefix, size, array_min, array_max); } return -1; } memcpy(array, ((BaseMathObject *)value)->data, size * sizeof(float)); } else #endif { PyObject *value_fast = NULL; /* non list/tuple cases */ if (!(value_fast = PySequence_Fast(value, error_prefix))) { /* PySequence_Fast sets the error */ return -1; } size = PySequence_Fast_GET_SIZE(value_fast); if (flag & MU_ARRAY_SPILL) { CLAMP_MAX(size, array_max); } if (size > array_max || size < array_min) { if (array_max == array_min) { PyErr_Format(PyExc_ValueError, "%.200s: sequence size is %d, expected %d", error_prefix, size, array_max); } else { PyErr_Format(PyExc_ValueError, "%.200s: sequence size is %d, expected [%d - %d]", error_prefix, size, array_min, array_max); } Py_DECREF(value_fast); return -1; } size = mathutils_array_parse_fast(array, size, value_fast, error_prefix); } if (size != -1) { if (flag & MU_ARRAY_ZERO) { int size_left = array_max - size; if (size_left) { memset(&array[size], 0, sizeof(float) * size_left); } } } return size; }
/** * Apply smooth to stroke point * \param gps: Stroke to smooth * \param i: Point index * \param inf: Amount of smoothing to apply * \param affect_pressure: Apply smoothing to pressure values too? */ bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure) { bGPDspoint *pt = &gps->points[i]; float pressure = 0.0f; float sco[3] = {0.0f}; /* Do nothing if not enough points to smooth out */ if (gps->totpoints <= 2) { return false; } /* Only affect endpoints by a fraction of the normal strength, * to prevent the stroke from shrinking too much */ if ((i == 0) || (i == gps->totpoints - 1)) { inf *= 0.1f; } /* Compute smoothed coordinate by taking the ones nearby */ /* XXX: This is potentially slow, and suffers from accumulation error as earlier points are handled before later ones */ { // XXX: this is hardcoded to look at 2 points on either side of the current one (i.e. 5 items total) const int steps = 2; const float average_fac = 1.0f / (float)(steps * 2 + 1); int step; /* add the point itself */ madd_v3_v3fl(sco, &pt->x, average_fac); if (affect_pressure) { pressure += pt->pressure * average_fac; } /* n-steps before/after current point */ // XXX: review how the endpoints are treated by this algorithm // XXX: falloff measures should also introduce some weighting variations, so that further-out points get less weight for (step = 1; step <= steps; step++) { bGPDspoint *pt1, *pt2; int before = i - step; int after = i + step; CLAMP_MIN(before, 0); CLAMP_MAX(after, gps->totpoints - 1); pt1 = &gps->points[before]; pt2 = &gps->points[after]; /* add both these points to the average-sum (s += p[i]/n) */ madd_v3_v3fl(sco, &pt1->x, average_fac); madd_v3_v3fl(sco, &pt2->x, average_fac); #if 0 /* XXX: Disabled because get weird result */ /* do pressure too? */ if (affect_pressure) { pressure += pt1->pressure * average_fac; pressure += pt2->pressure * average_fac; } #endif } } /* Based on influence factor, blend between original and optimal smoothed coordinate */ interp_v3_v3v3(&pt->x, &pt->x, sco, inf); #if 0 /* XXX: Disabled because get weird result */ if (affect_pressure) { pt->pressure = pressure; } #endif return true; }
/** * Evaluate the expression with the given parameters. * The order and number of parameters must match the names given to parse. */ eExprPyLike_EvalStatus BLI_expr_pylike_eval(ExprPyLike_Parsed *expr, const double *param_values, int param_values_len, double *r_result) { *r_result = 0.0; if (!BLI_expr_pylike_is_valid(expr)) { return EXPR_PYLIKE_INVALID; } #define FAIL_IF(condition) \ if (condition) { \ return EXPR_PYLIKE_FATAL_ERROR; \ } \ ((void)0) /* Check the stack requirement is at least remotely sane and allocate on the actual stack. */ FAIL_IF(expr->max_stack <= 0 || expr->max_stack > 1000); double *stack = BLI_array_alloca(stack, expr->max_stack); /* Evaluate expression. */ ExprOp *ops = expr->ops; int sp = 0, pc; feclearexcept(FE_ALL_EXCEPT); for (pc = 0; pc >= 0 && pc < expr->ops_count; pc++) { switch (ops[pc].opcode) { /* Arithmetic */ case OPCODE_CONST: FAIL_IF(sp >= expr->max_stack); stack[sp++] = ops[pc].arg.dval; break; case OPCODE_PARAMETER: FAIL_IF(sp >= expr->max_stack || ops[pc].arg.ival >= param_values_len); stack[sp++] = param_values[ops[pc].arg.ival]; break; case OPCODE_FUNC1: FAIL_IF(sp < 1); stack[sp - 1] = ops[pc].arg.func1(stack[sp - 1]); break; case OPCODE_FUNC2: FAIL_IF(sp < 2); stack[sp - 2] = ops[pc].arg.func2(stack[sp - 2], stack[sp - 1]); sp--; break; case OPCODE_MIN: FAIL_IF(sp < ops[pc].arg.ival); for (int j = 1; j < ops[pc].arg.ival; j++, sp--) { CLAMP_MAX(stack[sp - 2], stack[sp - 1]); } break; case OPCODE_MAX: FAIL_IF(sp < ops[pc].arg.ival); for (int j = 1; j < ops[pc].arg.ival; j++, sp--) { CLAMP_MIN(stack[sp - 2], stack[sp - 1]); } break; /* Jumps */ case OPCODE_JMP: pc += ops[pc].jmp_offset; break; case OPCODE_JMP_ELSE: FAIL_IF(sp < 1); if (!stack[--sp]) { pc += ops[pc].jmp_offset; } break; case OPCODE_JMP_OR: case OPCODE_JMP_AND: FAIL_IF(sp < 1); if (!stack[sp - 1] == !(ops[pc].opcode == OPCODE_JMP_OR)) { pc += ops[pc].jmp_offset; } else { sp--; } break; /* For chaining comparisons, i.e. "a < b < c" as "a < b and b < c" */ case OPCODE_CMP_CHAIN: FAIL_IF(sp < 2); /* If comparison fails, return 0 and jump to end. */ if (!ops[pc].arg.func2(stack[sp - 2], stack[sp - 1])) { stack[sp - 2] = 0.0; pc += ops[pc].jmp_offset; } /* Otherwise keep b on the stack and proceed. */ else { stack[sp - 2] = stack[sp - 1]; } sp--; break; default: return EXPR_PYLIKE_FATAL_ERROR; } } FAIL_IF(sp != 1 || pc != expr->ops_count); #undef FAIL_IF *r_result = stack[0]; /* Detect floating point evaluation errors. */ int flags = fetestexcept(FE_DIVBYZERO | FE_INVALID); if (flags) { return (flags & FE_INVALID) ? EXPR_PYLIKE_MATH_ERROR : EXPR_PYLIKE_DIV_BY_ZERO; } return EXPR_PYLIKE_SUCCESS; }
static GPUTexture *GPU_texture_create_nD( int w, int h, int n, const float *fpixels, int depth, GPUHDRType hdr_type, int components, int samples, char err_out[256]) { GLenum type, format, internalformat; void *pixels = NULL; if (samples) { CLAMP_MAX(samples, GPU_max_color_texture_samples()); } GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); tex->w = w; tex->h = h; tex->number = -1; tex->refcount = 1; tex->target = (n == 1) ? GL_TEXTURE_1D : (samples ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D); tex->target_base = (n == 1) ? GL_TEXTURE_1D : GL_TEXTURE_2D; tex->depth = depth; tex->fb_attachment = -1; glGenTextures(1, &tex->bindcode); if (!tex->bindcode) { if (err_out) { BLI_snprintf(err_out, 256, "GPUTexture: texture create failed: %d", (int)glGetError()); } else { fprintf(stderr, "GPUTexture: texture create failed: %d\n", (int)glGetError()); } GPU_texture_free(tex); return NULL; } if (!GPU_full_non_power_of_two_support()) { tex->w = power_of_2_max_i(tex->w); tex->h = power_of_2_max_i(tex->h); } tex->number = 0; glBindTexture(tex->target, tex->bindcode); if (depth) { type = GL_UNSIGNED_BYTE; format = GL_DEPTH_COMPONENT; internalformat = GL_DEPTH_COMPONENT; } else { type = GL_FLOAT; if (components == 4) { format = GL_RGBA; switch (hdr_type) { case GPU_HDR_NONE: internalformat = GL_RGBA8; break; /* the following formats rely on ARB_texture_float or OpenGL 3.0 */ case GPU_HDR_HALF_FLOAT: internalformat = GL_RGBA16F_ARB; break; case GPU_HDR_FULL_FLOAT: internalformat = GL_RGBA32F_ARB; break; default: break; } } else if (components == 2) { /* these formats rely on ARB_texture_rg or OpenGL 3.0 */ format = GL_RG; switch (hdr_type) { case GPU_HDR_NONE: internalformat = GL_RG8; break; case GPU_HDR_HALF_FLOAT: internalformat = GL_RG16F; break; case GPU_HDR_FULL_FLOAT: internalformat = GL_RG32F; break; default: break; } } if (fpixels && hdr_type == GPU_HDR_NONE) { type = GL_UNSIGNED_BYTE; pixels = GPU_texture_convert_pixels(w * h, fpixels); } } if (tex->target == GL_TEXTURE_1D) { glTexImage1D(tex->target, 0, internalformat, tex->w, 0, format, type, NULL); if (fpixels) { glTexSubImage1D(tex->target, 0, 0, w, format, type, pixels ? pixels : fpixels); if (tex->w > w) { GPU_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, 1); } } } else { if (samples) { glTexImage2DMultisample(tex->target, samples, internalformat, tex->w, tex->h, true); } else { glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0, format, type, NULL); } if (fpixels) { glTexSubImage2D(tex->target, 0, 0, 0, w, h, format, type, pixels ? pixels : fpixels); if (tex->w > w) GPU_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, tex->h); if (tex->h > h) GPU_glTexSubImageEmpty(tex->target, format, 0, h, w, tex->h - h); } } if (pixels) MEM_freeN(pixels); if (depth) { glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); glTexParameteri(tex->target_base, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY); } else { glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } if (tex->target_base != GL_TEXTURE_1D) { glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } else glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); return tex; }