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]); }
static void generate_vert_coordinates( DerivedMesh *dm, Object *ob, Object *ob_center, const float offset[3], const int num_verts, float (*r_cos)[3], float r_size[3]) { float min_co[3], max_co[3]; float diff[3]; bool do_diff = false; INIT_MINMAX(min_co, max_co); dm->getVertCos(dm, r_cos); /* Get size (i.e. deformation of the spheroid generating normals), either from target object, or own geometry. */ if (ob_center) { /* Not we are not interested in signs here - they are even troublesome actually, due to security clamping! */ abs_v3_v3(r_size, ob_center->size); } else { minmax_v3v3_v3_array(min_co, max_co, r_cos, num_verts); /* Set size. */ sub_v3_v3v3(r_size, max_co, min_co); } /* Error checks - we do not want one or more of our sizes to be null! */ if (is_zero_v3(r_size)) { r_size[0] = r_size[1] = r_size[2] = 1.0f; } else { CLAMP_MIN(r_size[0], FLT_EPSILON); CLAMP_MIN(r_size[1], FLT_EPSILON); CLAMP_MIN(r_size[2], FLT_EPSILON); } if (ob_center) { float inv_obmat[4][4]; /* Translate our coordinates so that center of ob_center is at (0, 0, 0). */ /* Get ob_center (world) coordinates in ob local coordinates. * No need to take into account ob_center's space here, see T44027. */ invert_m4_m4(inv_obmat, ob->obmat); mul_v3_m4v3(diff, inv_obmat, ob_center->obmat[3]); negate_v3(diff); do_diff = true; } else if (!is_zero_v3(offset)) { negate_v3_v3(diff, offset); do_diff = true; } /* Else, no need to change coordinates! */ if (do_diff) { int i = num_verts; while (i--) { add_v3_v3(r_cos[i], diff); } } }
/* Add one operation and track stack usage. */ static ExprOp *parse_add_op(ExprParseState *state, eOpCode code, int stack_delta) { /* track evaluation stack depth */ state->stack_ptr += stack_delta; CLAMP_MIN(state->stack_ptr, 0); CLAMP_MIN(state->max_stack, state->stack_ptr); /* allocate the new instruction */ ExprOp *op = parse_alloc_ops(state, 1); memset(op, 0, sizeof(ExprOp)); op->opcode = code; return op; }
/** * 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; }
/* cache init */ static GpencilBatchCache *gpencil_batch_cache_init(Object *ob, int cfra) { bGPdata *gpd = (bGPdata *)ob->data; GpencilBatchCache *cache = gpencil_batch_get_element(ob); if (!cache) { cache = MEM_callocN(sizeof(*cache), __func__); ob->runtime.gpencil_cache = cache; } else { memset(cache, 0, sizeof(*cache)); } cache->is_editmode = GPENCIL_ANY_EDIT_MODE(gpd); cache->is_dirty = true; cache->cache_frame = cfra; /* create array of derived frames equal to number of layers */ cache->tot_layers = BLI_listbase_count(&gpd->layers); CLAMP_MIN(cache->tot_layers, 1); cache->derived_array = MEM_callocN(sizeof(struct bGPDframe) * cache->tot_layers, "Derived GPF"); return cache; }
static int getDuplicationFactor(GpencilModifierData *md) { MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md; int factor = 1; /* create a duplication for each axis */ for (int xi = 0; xi < 3; ++xi) { if (mmd->flag & (GP_MIRROR_AXIS_X << xi)) { factor++; } } CLAMP_MIN(factor, 1); return factor; }
/** * \param bounds_rect: Either window or screen bounds. * Used to exclude edges along window/screen edges. */ ScrEdge *screen_geom_area_map_find_active_scredge(const ScrAreaMap *area_map, const rcti *bounds_rect, const int mx, const int my) { int safety = U.widget_unit / 10; CLAMP_MIN(safety, 2); for (ScrEdge *se = area_map->edgebase.first; se; se = se->next) { if (screen_geom_edge_is_horizontal(se)) { if ((se->v1->vec.y > bounds_rect->ymin) && (se->v1->vec.y < (bounds_rect->ymax - 1))) { short min, max; min = MIN2(se->v1->vec.x, se->v2->vec.x); max = MAX2(se->v1->vec.x, se->v2->vec.x); if (abs(my - se->v1->vec.y) <= safety && mx >= min && mx <= max) { return se; } } } else { if ((se->v1->vec.x > bounds_rect->xmin) && (se->v1->vec.x < (bounds_rect->xmax - 1))) { short min, max; min = MIN2(se->v1->vec.y, se->v2->vec.y); max = MAX2(se->v1->vec.y, se->v2->vec.y); if (abs(mx - se->v1->vec.x) <= safety && my >= min && my <= max) { return se; } } } } return NULL; }
/* Tag the bones in the chain formed by the given bone for IK */ static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPoseChannel *pchan_tip) { bPoseChannel *pchan, *pchanRoot = NULL; bPoseChannel *pchanChain[255]; bConstraint *con = NULL; bSplineIKConstraint *ikData = NULL; float boneLengths[255], *jointPoints; float totLength = 0.0f; bool free_joints = 0; int segcount = 0; /* find the SplineIK constraint */ for (con = pchan_tip->constraints.first; con; con = con->next) { if (con->type == CONSTRAINT_TYPE_SPLINEIK) { ikData = con->data; /* target can only be curve */ if ((ikData->tar == NULL) || (ikData->tar->type != OB_CURVE)) continue; /* skip if disabled */ if ((con->enforce == 0.0f) || (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF))) continue; /* otherwise, constraint is ok... */ break; } } if (con == NULL) return; /* make sure that the constraint targets are ok * - this is a workaround for a depsgraph bug... */ if (ikData->tar) { /* note: when creating constraints that follow path, the curve gets the CU_PATH set now, * currently for paths to work it needs to go through the bevlist/displist system (ton) */ /* only happens on reload file, but violates depsgraph still... fix! */ if (ELEM(NULL, ikData->tar->curve_cache, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) { BKE_displist_make_curveTypes(scene, ikData->tar, 0); /* path building may fail in EditMode after removing verts [#33268]*/ if (ELEM(NULL, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) { /* BLI_assert(cu->path != NULL); */ return; } } } /* find the root bone and the chain of bones from the root to the tip * NOTE: this assumes that the bones are connected, but that may not be true... */ for (pchan = pchan_tip; pchan && (segcount < ikData->chainlen); pchan = pchan->parent, segcount++) { /* store this segment in the chain */ pchanChain[segcount] = pchan; /* if performing rebinding, calculate the length of the bone */ boneLengths[segcount] = pchan->bone->length; totLength += boneLengths[segcount]; } if (segcount == 0) return; else pchanRoot = pchanChain[segcount - 1]; /* perform binding step if required */ if ((ikData->flag & CONSTRAINT_SPLINEIK_BOUND) == 0) { float segmentLen = (1.0f / (float)segcount); int i; /* setup new empty array for the points list */ if (ikData->points) MEM_freeN(ikData->points); ikData->numpoints = ikData->chainlen + 1; ikData->points = MEM_mallocN(sizeof(float) * ikData->numpoints, "Spline IK Binding"); /* bind 'tip' of chain (i.e. first joint = tip of bone with the Spline IK Constraint) */ ikData->points[0] = 1.0f; /* perform binding of the joints to parametric positions along the curve based * proportion of the total length that each bone occupies */ for (i = 0; i < segcount; i++) { /* 'head' joints, traveling towards the root of the chain * - 2 methods; the one chosen depends on whether we've got usable lengths */ if ((ikData->flag & CONSTRAINT_SPLINEIK_EVENSPLITS) || (totLength == 0.0f)) { /* 1) equi-spaced joints */ ikData->points[i + 1] = ikData->points[i] - segmentLen; } else { /* 2) to find this point on the curve, we take a step from the previous joint * a distance given by the proportion that this bone takes */ ikData->points[i + 1] = ikData->points[i] - (boneLengths[i] / totLength); } } /* spline has now been bound */ ikData->flag |= CONSTRAINT_SPLINEIK_BOUND; } /* disallow negative values (happens with float precision) */ CLAMP_MIN(ikData->points[segcount], 0.0f); /* apply corrections for sensitivity to scaling on a copy of the bind points, * since it's easier to determine the positions of all the joints beforehand this way */ if ((ikData->flag & CONSTRAINT_SPLINEIK_SCALE_LIMITED) && (totLength != 0.0f)) { float splineLen, maxScale; int i; /* make a copy of the points array, that we'll store in the tree * - although we could just multiply the points on the fly, this approach means that * we can introduce per-segment stretchiness later if it is necessary */ jointPoints = MEM_dupallocN(ikData->points); free_joints = 1; /* get the current length of the curve */ /* NOTE: this is assumed to be correct even after the curve was resized */ splineLen = ikData->tar->curve_cache->path->totdist; /* calculate the scale factor to multiply all the path values by so that the * bone chain retains its current length, such that * maxScale * splineLen = totLength */ maxScale = totLength / splineLen; /* apply scaling correction to all of the temporary points */ /* TODO: this is really not adequate enough on really short chains */ for (i = 0; i < segcount; i++) jointPoints[i] *= maxScale; } else { /* just use the existing points array */ jointPoints = ikData->points; free_joints = 0; } /* make a new Spline-IK chain, and store it in the IK chains */ /* TODO: we should check if there is already an IK chain on this, since that would take precedence... */ { /* make new tree */ tSplineIK_Tree *tree = MEM_callocN(sizeof(tSplineIK_Tree), "SplineIK Tree"); tree->type = CONSTRAINT_TYPE_SPLINEIK; tree->chainlen = segcount; /* copy over the array of links to bones in the chain (from tip to root) */ tree->chain = MEM_mallocN(sizeof(bPoseChannel *) * segcount, "SplineIK Chain"); memcpy(tree->chain, pchanChain, sizeof(bPoseChannel *) * segcount); /* store reference to joint position array */ tree->points = jointPoints; tree->free_points = free_joints; /* store references to different parts of the chain */ tree->root = pchanRoot; tree->con = con; tree->ikData = ikData; /* AND! link the tree to the root */ BLI_addtail(&pchanRoot->siktree, tree); } /* mark root channel having an IK tree */ pchanRoot->flag |= POSE_IKSPLINE; }
static void walkEvent(bContext *C, wmOperator *op, WalkInfo *walk, const wmEvent *event) { if (event->type == TIMER && event->customdata == walk->timer) { walk->redraw = true; } 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; } else { /* note, its possible the system isn't giving us the warp event * ideally we shouldn't have to worry about this, see: T45361 */ wmWindow *win = CTX_wm_window(C); WM_cursor_warp(win, walk->ar->winrct.xmin + walk->center_mval[0], walk->ar->winrct.ymin + walk->center_mval[1]); } 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]; copy_v2_v2_int(walk->prev_mval, event->mval); if ((walk->center_mval[0] != event->mval[0]) || (walk->center_mval[1] != event->mval[1])) { 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); #ifdef __APPLE__ if ((abs(walk->prev_mval[0] - walk->center_mval[0]) > walk->center_mval[0] / 2) || (abs(walk->prev_mval[1] - walk->center_mval[1]) > walk->center_mval[1] / 2)) #endif { WM_cursor_warp(win, walk->ar->winrct.xmin + walk->center_mval[0], walk->ar->winrct.ymin + walk->center_mval[1]); copy_v2_v2_int(walk->prev_mval, walk->center_mval); } } } } else if (event->type == NDOF_MOTION) { /* do these automagically get delivered? yes. */ // puts("ndof motion detected in walk mode!"); // static const char *tag_name = "3D mouse position"; const wmNDOFMotionData *incoming_ndof = event->customdata; switch (incoming_ndof->progress) { case P_STARTING: /* start keeping track of 3D mouse position */ #ifdef NDOF_WALK_DEBUG puts("start keeping track of 3D mouse position"); #endif /* fall-through */ case P_IN_PROGRESS: /* update 3D mouse position */ #ifdef NDOF_WALK_DEBUG putchar('.'); fflush(stdout); #endif if (walk->ndof == NULL) { // walk->ndof = MEM_mallocN(sizeof(wmNDOFMotionData), tag_name); walk->ndof = MEM_dupallocN(incoming_ndof); // walk->ndof = malloc(sizeof(wmNDOFMotionData)); } else { memcpy(walk->ndof, incoming_ndof, sizeof(wmNDOFMotionData)); } break; case P_FINISHING: /* stop keeping track of 3D mouse position */ #ifdef NDOF_WALK_DEBUG puts("stop keeping track of 3D mouse position"); #endif if (walk->ndof) { MEM_freeN(walk->ndof); // free(walk->ndof); walk->ndof = NULL; } /* update the time else the view will jump when 2D mouse/timer resume */ walk->time_lastdraw = PIL_check_seconds_timer(); break; default: break; /* should always be one of the above 3 */ } } /* handle modal keymap first */ else if (event->type == EVT_MODAL_MAP) { switch (event->val) { case WALK_MODAL_CANCEL: walk->state = WALK_CANCEL; break; case WALK_MODAL_CONFIRM: walk->state = WALK_CONFIRM; break; case WALK_MODAL_ACCELERATE: base_speed *= 1.0f + (walk->is_slow ? 0.01f : 0.1f); break; case WALK_MODAL_DECELERATE: base_speed /= 1.0f + (walk->is_slow ? 0.01f : 0.1f); break; /* implement WASD keys */ case WALK_MODAL_DIR_FORWARD: walk->active_directions |= WALK_BIT_FORWARD; break; case WALK_MODAL_DIR_BACKWARD: walk->active_directions |= WALK_BIT_BACKWARD; break; case WALK_MODAL_DIR_LEFT: walk->active_directions |= WALK_BIT_LEFT; break; case WALK_MODAL_DIR_RIGHT: walk->active_directions |= WALK_BIT_RIGHT; break; case WALK_MODAL_DIR_UP: walk->active_directions |= WALK_BIT_UP; break; case WALK_MODAL_DIR_DOWN: walk->active_directions |= WALK_BIT_DOWN; break; case WALK_MODAL_DIR_FORWARD_STOP: walk->active_directions &= ~WALK_BIT_FORWARD; break; case WALK_MODAL_DIR_BACKWARD_STOP: walk->active_directions &= ~WALK_BIT_BACKWARD; break; case WALK_MODAL_DIR_LEFT_STOP: walk->active_directions &= ~WALK_BIT_LEFT; break; case WALK_MODAL_DIR_RIGHT_STOP: walk->active_directions &= ~WALK_BIT_RIGHT; break; case WALK_MODAL_DIR_UP_STOP: walk->active_directions &= ~WALK_BIT_UP; break; case WALK_MODAL_DIR_DOWN_STOP: walk->active_directions &= ~WALK_BIT_DOWN; break; case WALK_MODAL_FAST_ENABLE: walk->is_fast = true; break; case WALK_MODAL_FAST_DISABLE: walk->is_fast = false; break; case WALK_MODAL_SLOW_ENABLE: walk->is_slow = true; break; case WALK_MODAL_SLOW_DISABLE: walk->is_slow = false; break; #define JUMP_SPEED_MIN 1.0f #define JUMP_TIME_MAX 0.2f /* s */ #define JUMP_SPEED_MAX sqrtf(2.0f * walk->gravity * walk->jump_height) case WALK_MODAL_JUMP_STOP: if (walk->gravity_state == WALK_GRAVITY_STATE_JUMP) { float t; /* delta time */ t = (float)(PIL_check_seconds_timer() - walk->teleport.initial_time); /* reduce the veolocity, if JUMP wasn't hold for long enough */ t = min_ff(t, JUMP_TIME_MAX); walk->speed_jump = JUMP_SPEED_MIN + t * (JUMP_SPEED_MAX - JUMP_SPEED_MIN) / JUMP_TIME_MAX; /* when jumping, duration is how long it takes before we start going down */ walk->teleport.duration = getVelocityZeroTime(walk->gravity, walk->speed_jump); /* no more increase of jump speed */ walk->gravity_state = WALK_GRAVITY_STATE_ON; } break; case WALK_MODAL_JUMP: if ((walk->navigation_mode == WALK_MODE_GRAVITY) && (walk->gravity_state == WALK_GRAVITY_STATE_OFF) && (walk->teleport.state == WALK_TELEPORT_STATE_OFF)) { /* no need to check for ground, * walk->gravity wouldn't be off * if we were over a hole */ walk->gravity_state = WALK_GRAVITY_STATE_JUMP; walk->speed_jump = JUMP_SPEED_MAX; walk->teleport.initial_time = PIL_check_seconds_timer(); copy_v3_v3(walk->teleport.origin, walk->rv3d->viewinv[3]); /* using previous vec because WASD keys are not called when SPACE is */ copy_v2_v2(walk->teleport.direction, walk->dvec_prev); /* when jumping, duration is how long it takes before we start going down */ walk->teleport.duration = getVelocityZeroTime(walk->gravity, walk->speed_jump); } break; case WALK_MODAL_TELEPORT: { float loc[3], nor[3]; float distance; bool ret = walk_ray_cast(C, walk->rv3d, walk, loc, nor, &distance); /* in case we are teleporting middle way from a jump */ walk->speed_jump = 0.0f; if (ret) { WalkTeleport *teleport = &walk->teleport; teleport->state = WALK_TELEPORT_STATE_ON; teleport->initial_time = PIL_check_seconds_timer(); teleport->duration = U.walk_navigation.teleport_time; teleport->navigation_mode = walk->navigation_mode; walk_navigation_mode_set(C, op, walk, WALK_MODE_FREE); copy_v3_v3(teleport->origin, walk->rv3d->viewinv[3]); /* stop the camera from a distance (camera height) */ normalize_v3(nor); mul_v3_fl(nor, walk->view_height); add_v3_v3(loc, nor); sub_v3_v3v3(teleport->direction, loc, teleport->origin); } else { walk->teleport.state = WALK_TELEPORT_STATE_OFF; } break; } #undef JUMP_SPEED_MAX #undef JUMP_TIME_MAX #undef JUMP_SPEED_MIN case WALK_MODAL_TOGGLE: if (walk->navigation_mode == WALK_MODE_GRAVITY) { walk_navigation_mode_set(C, op, walk, WALK_MODE_FREE); } else { /* WALK_MODE_FREE */ walk_navigation_mode_set(C, op, walk, WALK_MODE_GRAVITY); } break; } } }
static void node_shader_exec_normal_map( void *data, int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out) { if (data) { ShadeInput *shi = ((ShaderCallData *)data)->shi; NodeShaderNormalMap *nm = node->storage; float strength, vecIn[3]; nodestack_get_vec(&strength, SOCK_FLOAT, in[0]); nodestack_get_vec(vecIn, SOCK_VECTOR, in[1]); vecIn[0] = -2 * (vecIn[0] - 0.5f); vecIn[1] = 2 * (vecIn[1] - 0.5f); vecIn[2] = 2 * (vecIn[2] - 0.5f); CLAMP_MIN(strength, 0.0f); float *N = shi->nmapnorm; int uv_index = 0; switch (nm->space) { case SHD_SPACE_TANGENT: if (nm->uv_map[0]) { /* find uv map by name */ for (int i = 0; i < shi->totuv; i++) { if (STREQ(shi->uv[i].name, nm->uv_map)) { uv_index = i; break; } } } else { uv_index = shi->actuv; } float *T = shi->tangents[uv_index]; float B[3]; cross_v3_v3v3(B, N, T); mul_v3_fl(B, T[3]); for (int j = 0; j < 3; j++) out[0]->vec[j] = vecIn[0] * T[j] + vecIn[1] * B[j] + vecIn[2] * N[j]; interp_v3_v3v3(out[0]->vec, N, out[0]->vec, strength); if (shi->use_world_space_shading) { mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), out[0]->vec); } break; case SHD_SPACE_OBJECT: case SHD_SPACE_BLENDER_OBJECT: if (shi->use_world_space_shading) { mul_mat3_m4_v3((float (*)[4])RE_object_instance_get_matrix(shi->obi, RE_OBJECT_INSTANCE_MATRIX_OB), vecIn); mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), N); } else mul_mat3_m4_v3((float (*)[4])RE_object_instance_get_matrix(shi->obi, RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEW), vecIn); interp_v3_v3v3(out[0]->vec, N, vecIn, strength); break; case SHD_SPACE_WORLD: case SHD_SPACE_BLENDER_WORLD: if (shi->use_world_space_shading) mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), N); else mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), vecIn); interp_v3_v3v3(out[0]->vec, N, vecIn, strength); break; } if (shi->use_world_space_shading) { negate_v3(out[0]->vec); } normalize_v3(out[0]->vec); } }
/** * 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; }
void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings) { int a; unsigned int nl, na, nr, ng, nb; double divl, diva, divr, divg, divb; const unsigned char *display_buffer = NULL; unsigned int bin_lum[256] = {0}, bin_r[256] = {0}, bin_g[256] = {0}, bin_b[256] = {0}, bin_a[256] = {0}; int ycc_mode = -1; void *cache_handle = NULL; struct ColormanageProcessor *cm_processor = NULL; if (ibuf->rect == NULL && ibuf->rect_float == NULL) return; if (scopes->ok == 1) return; if (scopes->hist.ymax == 0.f) scopes->hist.ymax = 1.f; /* hmmmm */ if (!(ELEM(ibuf->channels, 3, 4))) return; scopes->hist.channels = 3; scopes->hist.x_resolution = 256; switch (scopes->wavefrm_mode) { case SCOPES_WAVEFRM_RGB: ycc_mode = -1; break; case SCOPES_WAVEFRM_LUMA: case SCOPES_WAVEFRM_YCC_JPEG: ycc_mode = BLI_YCC_JFIF_0_255; break; case SCOPES_WAVEFRM_YCC_601: ycc_mode = BLI_YCC_ITU_BT601; break; case SCOPES_WAVEFRM_YCC_709: ycc_mode = BLI_YCC_ITU_BT709; break; } /* convert to number of lines with logarithmic scale */ scopes->sample_lines = (scopes->accuracy * 0.01f) * (scopes->accuracy * 0.01f) * ibuf->y; CLAMP_MIN(scopes->sample_lines, 1); if (scopes->sample_full) scopes->sample_lines = ibuf->y; /* scan the image */ for (a = 0; a < 3; a++) { scopes->minmax[a][0] = 25500.0f; scopes->minmax[a][1] = -25500.0f; } scopes->waveform_tot = ibuf->x * scopes->sample_lines; if (scopes->waveform_1) MEM_freeN(scopes->waveform_1); if (scopes->waveform_2) MEM_freeN(scopes->waveform_2); if (scopes->waveform_3) MEM_freeN(scopes->waveform_3); if (scopes->vecscope) MEM_freeN(scopes->vecscope); scopes->waveform_1 = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "waveform point channel 1"); scopes->waveform_2 = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "waveform point channel 2"); scopes->waveform_3 = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "waveform point channel 3"); scopes->vecscope = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "vectorscope point channel"); if (ibuf->rect_float) { cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings); } else { display_buffer = (const unsigned char *)IMB_display_buffer_acquire( ibuf, view_settings, display_settings, &cache_handle); } /* Keep number of threads in sync with the merge parts below. */ ScopesUpdateData data = { .scopes = scopes, . ibuf = ibuf, .cm_processor = cm_processor, .display_buffer = display_buffer, .ycc_mode = ycc_mode, .bin_lum = bin_lum, .bin_r = bin_r, .bin_g = bin_g, .bin_b = bin_b, .bin_a = bin_a, }; ScopesUpdateDataChunk data_chunk = {0}; INIT_MINMAX(data_chunk.min, data_chunk.max); BLI_task_parallel_range_finalize(0, ibuf->y, &data, &data_chunk, sizeof(data_chunk), scopes_update_cb, scopes_update_finalize, ibuf->y > 256, false); /* test for nicer distribution even - non standard, leave it out for a while */ #if 0 for (a = 0; a < 256; a++) { bin_lum[a] = sqrt (bin_lum[a]); bin_r[a] = sqrt(bin_r[a]); bin_g[a] = sqrt(bin_g[a]); bin_b[a] = sqrt(bin_b[a]); bin_a[a] = sqrt(bin_a[a]); } #endif /* convert hist data to float (proportional to max count) */ nl = na = nr = nb = ng = 0; for (a = 0; a < 256; a++) { if (bin_lum[a] > nl) nl = bin_lum[a]; if (bin_r[a] > nr) nr = bin_r[a]; if (bin_g[a] > ng) ng = bin_g[a]; if (bin_b[a] > nb) nb = bin_b[a]; if (bin_a[a] > na) na = bin_a[a]; } divl = nl ? 1.0 / (double)nl : 1.0; diva = na ? 1.0 / (double)na : 1.0; divr = nr ? 1.0 / (double)nr : 1.0; divg = ng ? 1.0 / (double)ng : 1.0; divb = nb ? 1.0 / (double)nb : 1.0; for (a = 0; a < 256; a++) { scopes->hist.data_luma[a] = bin_lum[a] * divl; scopes->hist.data_r[a] = bin_r[a] * divr; scopes->hist.data_g[a] = bin_g[a] * divg; scopes->hist.data_b[a] = bin_b[a] * divb; scopes->hist.data_a[a] = bin_a[a] * diva; } if (cm_processor) IMB_colormanagement_processor_free(cm_processor); if (cache_handle) IMB_display_buffer_release(cache_handle); scopes->ok = 1; }
/* Note: This function uses pixelspace (0, 0, winx, winy), not view2d. * The controls are laid out as follows: * * ------------------------------------------- * | Directory input | execute | * ------------------------------------------- * | Filename input | + | - | cancel | * ------------------------------------------- * * The input widgets will stretch to fill any excess space. * When there isn't enough space for all controls to be shown, they are * hidden in this order: x/-, execute/cancel, input widgets. */ void file_draw_buttons(const bContext *C, ARegion *ar) { /* Button layout. */ const int max_x = ar->winx - 10; const int line1_y = ar->winy - (IMASEL_BUTTONS_HEIGHT / 2 + IMASEL_BUTTONS_MARGIN); const int line2_y = line1_y - (IMASEL_BUTTONS_HEIGHT / 2 + IMASEL_BUTTONS_MARGIN); const int input_minw = 20; const int btn_h = UI_UNIT_Y; const int btn_fn_w = UI_UNIT_X; const int btn_minw = 80; const int btn_margin = 20; const int separator = 4; /* Additional locals. */ char uiblockstr[32]; int loadbutton; int fnumbuttons; int min_x = 10; int chan_offs = 0; int available_w = max_x - min_x; int line1_w = available_w; int line2_w = available_w; uiBut *but; uiBlock *block; SpaceFile *sfile = CTX_wm_space_file(C); FileSelectParams *params = ED_fileselect_get_params(sfile); ARegion *artmp; const bool is_browse_only = (sfile->op == NULL); /* Initialize UI block. */ BLI_snprintf(uiblockstr, sizeof(uiblockstr), "win %p", (void *)ar); block = UI_block_begin(C, ar, uiblockstr, UI_EMBOSS); /* exception to make space for collapsed region icon */ for (artmp = CTX_wm_area(C)->regionbase.first; artmp; artmp = artmp->next) { if (artmp->regiontype == RGN_TYPE_TOOLS && artmp->flag & RGN_FLAG_HIDDEN) { chan_offs = 16; min_x += chan_offs; available_w -= chan_offs; } } /* Is there enough space for the execute / cancel buttons? */ if (is_browse_only) { loadbutton = 0; } else { const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; loadbutton = UI_fontstyle_string_width(fstyle, params->title) + btn_margin; CLAMP_MIN(loadbutton, btn_minw); if (available_w <= loadbutton + separator + input_minw) { loadbutton = 0; } } if (loadbutton) { line1_w -= (loadbutton + separator); line2_w = line1_w; } /* Is there enough space for file number increment/decrement buttons? */ fnumbuttons = 2 * btn_fn_w; if (!loadbutton || line2_w <= fnumbuttons + separator + input_minw) { fnumbuttons = 0; } else { line2_w -= (fnumbuttons + separator); } /* Text input fields for directory and file. */ if (available_w > 0) { const struct direntry *file = sfile->files ? filelist_file(sfile->files, params->active_file) : NULL; int overwrite_alert = file_draw_check_exists(sfile); const bool is_active_dir = file && file->path && BLI_is_dir(file->path); /* callbacks for operator check functions */ UI_block_func_set(block, file_draw_check_cb, NULL, NULL); but = uiDefBut(block, UI_BTYPE_TEXT, -1, "", min_x, line1_y, line1_w - chan_offs, btn_h, params->dir, 0.0, (float)FILE_MAX, 0, 0, TIP_("File path")); UI_but_func_complete_set(but, autocomplete_directory, NULL); UI_but_flag_enable(but, UI_BUT_NO_UTF8); UI_but_flag_disable(but, UI_BUT_UNDO); UI_but_funcN_set(but, file_directory_enter_handle, NULL, but); /* TODO, directory editing is non-functional while a library is loaded * until this is properly supported just disable it. */ if (sfile->files && filelist_lib(sfile->files)) UI_but_flag_enable(but, UI_BUT_DISABLED); if ((params->flag & FILE_DIRSEL_ONLY) == 0) { but = uiDefBut(block, UI_BTYPE_TEXT, -1, "", min_x, line2_y, line2_w - chan_offs, btn_h, is_active_dir ? (char *)"" : params->file, 0.0, (float)FILE_MAXFILE, 0, 0, TIP_(overwrite_alert ? N_("File name, overwrite existing") : N_("File name"))); UI_but_func_complete_set(but, autocomplete_file, NULL); UI_but_flag_enable(but, UI_BUT_NO_UTF8); UI_but_flag_disable(but, UI_BUT_UNDO); /* silly workaround calling NFunc to ensure this does not get called * immediate ui_apply_but_func but only after button deactivates */ UI_but_funcN_set(but, file_filename_enter_handle, NULL, but); /* check if this overrides a file and if the operator option is used */ if (overwrite_alert) { UI_but_flag_enable(but, UI_BUT_REDALERT); } } /* clear func */ UI_block_func_set(block, NULL, NULL, NULL); } /* Filename number increment / decrement buttons. */ if (fnumbuttons && (params->flag & FILE_DIRSEL_ONLY) == 0) { UI_block_align_begin(block); but = uiDefIconButO(block, UI_BTYPE_BUT, "FILE_OT_filenum", 0, ICON_ZOOMOUT, min_x + line2_w + separator - chan_offs, line2_y, btn_fn_w, btn_h, TIP_("Decrement the filename number")); RNA_int_set(UI_but_operator_ptr_get(but), "increment", -1); but = uiDefIconButO(block, UI_BTYPE_BUT, "FILE_OT_filenum", 0, ICON_ZOOMIN, min_x + line2_w + separator + btn_fn_w - chan_offs, line2_y, btn_fn_w, btn_h, TIP_("Increment the filename number")); RNA_int_set(UI_but_operator_ptr_get(but), "increment", 1); UI_block_align_end(block); } /* Execute / cancel buttons. */ if (loadbutton) { const struct direntry *file = filelist_file(sfile->files, params->active_file); const char *str_exec = (file && file->path && BLI_is_dir(file->path)) ? /* params->title is already translated! */ IFACE_("Open Directory") : params->title; uiDefButO(block, UI_BTYPE_BUT, "FILE_OT_execute", WM_OP_EXEC_REGION_WIN, str_exec, max_x - loadbutton, line1_y, loadbutton, btn_h, ""); uiDefButO(block, UI_BTYPE_BUT, "FILE_OT_cancel", WM_OP_EXEC_REGION_WIN, IFACE_("Cancel"), max_x - loadbutton, line2_y, loadbutton, btn_h, ""); } UI_block_end(C, block); UI_block_draw(C, block); }