/*! init triangle divisions */ void calcTriangleDivs(Object *ob, MVert *verts, int numverts, MFace *faces, int numfaces, int numtris, int **tridivs, float cell_len) { // mTriangleDivs1.resize( faces.size() ); // mTriangleDivs2.resize( faces.size() ); // mTriangleDivs3.resize( faces.size() ); size_t i = 0, facecounter = 0; float maxscale[3] = {1,1,1}; // = channelFindMaxVf(mcScale); float maxpart = ABS(maxscale[0]); float scaleFac = 0; float fsTri = 0; if(ABS(maxscale[1])>maxpart) maxpart = ABS(maxscale[1]); if(ABS(maxscale[2])>maxpart) maxpart = ABS(maxscale[2]); scaleFac = 1.0 / maxpart; // featureSize = mLevel[mMaxRefine].nodeSize fsTri = cell_len * 0.5 * scaleFac; if(*tridivs) MEM_freeN(*tridivs); *tridivs = MEM_callocN(sizeof(int) * numtris * 3, "Smoke_Tridivs"); for(i = 0, facecounter = 0; i < numfaces; i++) { float p0[3], p1[3], p2[3]; float side1[3]; float side2[3]; float side3[3]; int divs1=0, divs2=0, divs3=0; VECCOPY(p0, verts[faces[i].v1].co); Mat4MulVecfl (ob->obmat, p0); VECCOPY(p1, verts[faces[i].v2].co); Mat4MulVecfl (ob->obmat, p1); VECCOPY(p2, verts[faces[i].v3].co); Mat4MulVecfl (ob->obmat, p2); VECSUB(side1, p1, p0); VECSUB(side2, p2, p0); VECSUB(side3, p1, p2); if(INPR(side1, side1) > fsTri*fsTri) { float tmp = Normalize(side1); divs1 = (int)ceil(tmp/fsTri); } if(INPR(side2, side2) > fsTri*fsTri) { float tmp = Normalize(side2); divs2 = (int)ceil(tmp/fsTri); /* // debug if(i==0) printf("b tmp: %f, fsTri: %f, divs2: %d\n", tmp, fsTri, divs2); */ } (*tridivs)[3 * facecounter + 0] = divs1; (*tridivs)[3 * facecounter + 1] = divs2; (*tridivs)[3 * facecounter + 2] = divs3; // TODO quad case if(faces[i].v4) { divs1=0, divs2=0, divs3=0; facecounter++; VECCOPY(p0, verts[faces[i].v3].co); Mat4MulVecfl (ob->obmat, p0); VECCOPY(p1, verts[faces[i].v4].co); Mat4MulVecfl (ob->obmat, p1); VECCOPY(p2, verts[faces[i].v1].co); Mat4MulVecfl (ob->obmat, p2); VECSUB(side1, p1, p0); VECSUB(side2, p2, p0); VECSUB(side3, p1, p2); if(INPR(side1, side1) > fsTri*fsTri) { float tmp = Normalize(side1); divs1 = (int)ceil(tmp/fsTri); } if(INPR(side2, side2) > fsTri*fsTri) { float tmp = Normalize(side2); divs2 = (int)ceil(tmp/fsTri); } (*tridivs)[3 * facecounter + 0] = divs1; (*tridivs)[3 * facecounter + 1] = divs2; (*tridivs)[3 * facecounter + 2] = divs3; } facecounter++; } }
/* only creates a table for a single channel in CurveMapping */ static void curvemap_make_table(CurveMap *cuma, rctf *clipr) { CurveMapPoint *cmp= cuma->curve; BezTriple *bezt; float *fp, *allpoints, *lastpoint, curf, range; int a, totpoint; if(cuma->curve==NULL) return; /* default rect also is table range */ cuma->mintable= clipr->xmin; cuma->maxtable= clipr->xmax; /* hrmf... we now rely on blender ipo beziers, these are more advanced */ bezt= MEM_callocN(cuma->totpoint*sizeof(BezTriple), "beztarr"); for(a=0; a<cuma->totpoint; a++) { cuma->mintable= MIN2(cuma->mintable, cmp[a].x); cuma->maxtable= MAX2(cuma->maxtable, cmp[a].x); bezt[a].vec[1][0]= cmp[a].x; bezt[a].vec[1][1]= cmp[a].y; if(cmp[a].flag & CUMA_VECTOR) bezt[a].h1= bezt[a].h2= HD_VECT; else bezt[a].h1= bezt[a].h2= HD_AUTO; } for(a=0; a<cuma->totpoint; a++) { if(a==0) calchandle_curvemap(bezt, NULL, bezt+1, 0); else if(a==cuma->totpoint-1) calchandle_curvemap(bezt+a, bezt+a-1, NULL, 0); else calchandle_curvemap(bezt+a, bezt+a-1, bezt+a+1, 0); } /* first and last handle need correction, instead of pointing to center of next/prev, we let it point to the closest handle */ if(cuma->totpoint>2) { float hlen, nlen, vec[3]; if(bezt[0].h2==HD_AUTO) { hlen= len_v3v3(bezt[0].vec[1], bezt[0].vec[2]); /* original handle length */ /* clip handle point */ VECCOPY(vec, bezt[1].vec[0]); if(vec[0] < bezt[0].vec[1][0]) vec[0]= bezt[0].vec[1][0]; sub_v3_v3(vec, bezt[0].vec[1]); nlen= len_v3(vec); if(nlen>FLT_EPSILON) { mul_v3_fl(vec, hlen/nlen); add_v3_v3v3(bezt[0].vec[2], vec, bezt[0].vec[1]); sub_v3_v3v3(bezt[0].vec[0], bezt[0].vec[1], vec); } } a= cuma->totpoint-1; if(bezt[a].h2==HD_AUTO) { hlen= len_v3v3(bezt[a].vec[1], bezt[a].vec[0]); /* original handle length */ /* clip handle point */ VECCOPY(vec, bezt[a-1].vec[2]); if(vec[0] > bezt[a].vec[1][0]) vec[0]= bezt[a].vec[1][0]; sub_v3_v3(vec, bezt[a].vec[1]); nlen= len_v3(vec); if(nlen>FLT_EPSILON) { mul_v3_fl(vec, hlen/nlen); add_v3_v3v3(bezt[a].vec[0], vec, bezt[a].vec[1]); sub_v3_v3v3(bezt[a].vec[2], bezt[a].vec[1], vec); } } } /* make the bezier curve */ if(cuma->table) MEM_freeN(cuma->table); totpoint= (cuma->totpoint-1)*CM_RESOL; fp= allpoints= MEM_callocN(totpoint*2*sizeof(float), "table"); for(a=0; a<cuma->totpoint-1; a++, fp += 2*CM_RESOL) { correct_bezpart(bezt[a].vec[1], bezt[a].vec[2], bezt[a+1].vec[0], bezt[a+1].vec[1]); forward_diff_bezier(bezt[a].vec[1][0], bezt[a].vec[2][0], bezt[a+1].vec[0][0], bezt[a+1].vec[1][0], fp, CM_RESOL-1, 2*sizeof(float)); forward_diff_bezier(bezt[a].vec[1][1], bezt[a].vec[2][1], bezt[a+1].vec[0][1], bezt[a+1].vec[1][1], fp+1, CM_RESOL-1, 2*sizeof(float)); } /* store first and last handle for extrapolation, unit length */ cuma->ext_in[0]= bezt[0].vec[0][0] - bezt[0].vec[1][0]; cuma->ext_in[1]= bezt[0].vec[0][1] - bezt[0].vec[1][1]; range= sqrt(cuma->ext_in[0]*cuma->ext_in[0] + cuma->ext_in[1]*cuma->ext_in[1]); cuma->ext_in[0]/= range; cuma->ext_in[1]/= range; a= cuma->totpoint-1; cuma->ext_out[0]= bezt[a].vec[1][0] - bezt[a].vec[2][0]; cuma->ext_out[1]= bezt[a].vec[1][1] - bezt[a].vec[2][1]; range= sqrt(cuma->ext_out[0]*cuma->ext_out[0] + cuma->ext_out[1]*cuma->ext_out[1]); cuma->ext_out[0]/= range; cuma->ext_out[1]/= range; /* cleanup */ MEM_freeN(bezt); range= CM_TABLEDIV*(cuma->maxtable - cuma->mintable); cuma->range= 1.0f/range; /* now make a table with CM_TABLE equal x distances */ fp= allpoints; lastpoint= allpoints + 2*(totpoint-1); cmp= MEM_callocN((CM_TABLE+1)*sizeof(CurveMapPoint), "dist table"); for(a=0; a<=CM_TABLE; a++) { curf= cuma->mintable + range*(float)a; cmp[a].x= curf; /* get the first x coordinate larger than curf */ while(curf >= fp[0] && fp!=lastpoint) { fp+=2; } if(fp==allpoints || (curf >= fp[0] && fp==lastpoint)) cmp[a].y= curvemap_calc_extend(cuma, curf, allpoints, lastpoint); else { float fac1= fp[0] - fp[-2]; float fac2= fp[0] - curf; if(fac1 > FLT_EPSILON) fac1= fac2/fac1; else fac1= 0.0f; cmp[a].y= fac1*fp[-1] + (1.0f-fac1)*fp[1]; } } MEM_freeN(allpoints); cuma->table= cmp; }
/* PolyFill function, uses Blenders scanfill to fill multiple poly lines */ static PyObject *M_Geometry_tesselate_polygon(PyObject *UNUSED(self), PyObject *polyLineSeq) { PyObject *tri_list; /*return this list of tri's */ PyObject *polyLine, *polyVec; int i, len_polylines, len_polypoints, ls_error= 0; /* display listbase */ ListBase dispbase={NULL, NULL}; DispList *dl; float *fp; /*pointer to the array of malloced dl->verts to set the points from the vectors */ int index, *dl_face, totpoints=0; if(!PySequence_Check(polyLineSeq)) { PyErr_SetString(PyExc_TypeError, "expected a sequence of poly lines"); return NULL; } len_polylines= PySequence_Size(polyLineSeq); for(i= 0; i < len_polylines; ++i) { polyLine= PySequence_GetItem(polyLineSeq, i); if (!PySequence_Check(polyLine)) { freedisplist(&dispbase); Py_XDECREF(polyLine); /* may be null so use Py_XDECREF*/ PyErr_SetString(PyExc_TypeError, "One or more of the polylines is not a sequence of mathutils.Vector's"); return NULL; } len_polypoints= PySequence_Size(polyLine); if (len_polypoints>0) { /* dont bother adding edges as polylines */ #if 0 if (EXPP_check_sequence_consistency(polyLine, &vector_Type) != 1) { freedisplist(&dispbase); Py_DECREF(polyLine); PyErr_SetString(PyExc_TypeError, "A point in one of the polylines is not a mathutils.Vector type"); return NULL; } #endif dl= MEM_callocN(sizeof(DispList), "poly disp"); BLI_addtail(&dispbase, dl); dl->type= DL_INDEX3; dl->nr= len_polypoints; dl->type= DL_POLY; dl->parts= 1; /* no faces, 1 edge loop */ dl->col= 0; /* no material */ dl->verts= fp= MEM_callocN(sizeof(float)*3*len_polypoints, "dl verts"); dl->index= MEM_callocN(sizeof(int)*3*len_polypoints, "dl index"); for(index= 0; index<len_polypoints; ++index, fp+=3) { polyVec= PySequence_GetItem(polyLine, index); if(VectorObject_Check(polyVec)) { if(BaseMath_ReadCallback((VectorObject *)polyVec) == -1) ls_error= 1; fp[0]= ((VectorObject *)polyVec)->vec[0]; fp[1]= ((VectorObject *)polyVec)->vec[1]; if(((VectorObject *)polyVec)->size > 2) fp[2]= ((VectorObject *)polyVec)->vec[2]; else fp[2]= 0.0f; /* if its a 2d vector then set the z to be zero */ } else { ls_error= 1; } totpoints++; Py_DECREF(polyVec); } } Py_DECREF(polyLine); } if(ls_error) { freedisplist(&dispbase); /* possible some dl was allocated */ PyErr_SetString(PyExc_TypeError, "A point in one of the polylines " "is not a mathutils.Vector type"); return NULL; } else if (totpoints) { /* now make the list to return */ filldisplist(&dispbase, &dispbase, 0); /* The faces are stored in a new DisplayList thats added to the head of the listbase */ dl= dispbase.first; tri_list= PyList_New(dl->parts); if(!tri_list) { freedisplist(&dispbase); PyErr_SetString(PyExc_RuntimeError, "failed to make a new list"); return NULL; } index= 0; dl_face= dl->index; while(index < dl->parts) { PyList_SET_ITEM(tri_list, index, Py_BuildValue("iii", dl_face[0], dl_face[1], dl_face[2])); dl_face+= 3; index++; } freedisplist(&dispbase); } else { /* no points, do this so scripts dont barf */ freedisplist(&dispbase); /* possible some dl was allocated */ tri_list= PyList_New(0); } return tri_list; }
/* calculate a curve-deform path for a curve * - only called from displist.c -> do_makeDispListCurveTypes */ void calc_curvepath(Object *ob) { BevList *bl; BevPoint *bevp, *bevpn, *bevpfirst, *bevplast; PathPoint *pp; Curve *cu; Nurb *nu; Path *path; float *fp, *dist, *maxdist, xyz[3]; float fac, d = 0, fac1, fac2; int a, tot, cycl = 0; ListBase *nurbs; /* in a path vertices are with equal differences: path->len = number of verts */ /* NOW WITH BEVELCURVE!!! */ if (ob == NULL || ob->type != OB_CURVE) return; cu = ob->data; nurbs = BKE_curve_nurbs_get(cu); nu = nurbs->first; if (cu->path) free_path(cu->path); cu->path = NULL; bl = cu->bev.first; if (bl == NULL || !bl->nr) return; cu->path = path = MEM_callocN(sizeof(Path), "calc_curvepath"); /* if POLY: last vertice != first vertice */ cycl = (bl->poly != -1); if (cycl) tot = bl->nr; else tot = bl->nr - 1; path->len = tot + 1; /* exception: vector handle paths and polygon paths should be subdivided at least a factor resolu */ if (path->len < nu->resolu * SEGMENTSU(nu)) path->len = nu->resolu * SEGMENTSU(nu); dist = (float *)MEM_mallocN((tot + 1) * 4, "calcpathdist"); /* all lengths in *dist */ bevp = bevpfirst = (BevPoint *)(bl + 1); fp = dist; *fp = 0; for (a = 0; a < tot; a++) { fp++; if (cycl && a == tot - 1) sub_v3_v3v3(xyz, bevpfirst->vec, bevp->vec); else sub_v3_v3v3(xyz, (bevp + 1)->vec, bevp->vec); *fp = *(fp - 1) + len_v3(xyz); bevp++; } path->totdist = *fp; /* the path verts in path->data */ /* now also with TILT value */ pp = path->data = (PathPoint *)MEM_callocN(sizeof(PathPoint) * path->len, "pathdata"); bevp = bevpfirst; bevpn = bevp + 1; bevplast = bevpfirst + (bl->nr - 1); fp = dist + 1; maxdist = dist + tot; fac = 1.0f / ((float)path->len - 1.0f); fac = fac * path->totdist; for (a = 0; a < path->len; a++) { d = ((float)a) * fac; /* we're looking for location (distance) 'd' in the array */ while ((d >= *fp) && fp < maxdist) { fp++; if (bevp < bevplast) bevp++; bevpn = bevp + 1; if (bevpn > bevplast) { if (cycl) bevpn = bevpfirst; else bevpn = bevplast; } } fac1 = *(fp) - *(fp - 1); fac2 = *(fp) - d; fac1 = fac2 / fac1; fac2 = 1.0f - fac1; interp_v3_v3v3(pp->vec, bevp->vec, bevpn->vec, fac2); pp->vec[3] = fac1 * bevp->alfa + fac2 * bevpn->alfa; pp->radius = fac1 * bevp->radius + fac2 * bevpn->radius; pp->weight = fac1 * bevp->weight + fac2 * bevpn->weight; interp_qt_qtqt(pp->quat, bevp->quat, bevpn->quat, fac2); normalize_qt(pp->quat); pp++; } MEM_freeN(dist); }
static int get_sequence_len(char *filename, int *ofs) { int frame; int numdigit; if (!BLI_path_frame_get(filename, &frame, &numdigit)) { return 1; } char path[FILE_MAX]; BLI_path_abs(filename, BKE_main_blendfile_path_from_global()); BLI_split_dir_part(filename, path, FILE_MAX); if (path[0] == '\0') { /* The filename had no path, so just use the blend file path. */ BLI_split_dir_part(BKE_main_blendfile_path_from_global(), path, FILE_MAX); } DIR *dir = opendir(path); if (dir == NULL) { fprintf(stderr, "Error opening directory '%s': %s\n", path, errno ? strerror(errno) : "unknown error"); return -1; } const char *ext = ".abc"; const char *basename = BLI_path_basename(filename); const int len = strlen(basename) - (numdigit + strlen(ext)); ListBase frames; BLI_listbase_clear(&frames); struct dirent *fname; while ((fname = readdir(dir)) != NULL) { /* do we have the right extension? */ if (!strstr(fname->d_name, ext)) { continue; } if (!STREQLEN(basename, fname->d_name, len)) { continue; } CacheFrame *cache_frame = MEM_callocN(sizeof(CacheFrame), "abc_frame"); BLI_path_frame_get(fname->d_name, &cache_frame->framenr, &numdigit); BLI_addtail(&frames, cache_frame); } closedir(dir); BLI_listbase_sort(&frames, cmp_frame); CacheFrame *cache_frame = frames.first; if (cache_frame) { int frame_curr = cache_frame->framenr; (*ofs) = frame_curr; while (cache_frame && (cache_frame->framenr == frame_curr)) { ++frame_curr; cache_frame = cache_frame->next; } BLI_freelistN(&frames); return frame_curr - (*ofs); } return 1; }
static void mesh_calc_edges_mdata( MVert *UNUSED(allvert), MFace *allface, MLoop *allloop, MPoly *allpoly, int UNUSED(totvert), int totface, int UNUSED(totloop), int totpoly, const bool use_old, MEdge **r_medge, int *r_totedge) { MPoly *mpoly; MFace *mface; MEdge *medge, *med; EdgeHash *hash; struct EdgeSort *edsort, *ed; int a, totedge = 0; unsigned int totedge_final = 0; unsigned int edge_index; /* we put all edges in array, sort them, and detect doubles that way */ for (a = totface, mface = allface; a > 0; a--, mface++) { if (mface->v4) totedge += 4; else if (mface->v3) totedge += 3; else totedge += 1; } if (totedge == 0) { /* flag that mesh has edges */ (*r_medge) = MEM_callocN(0, __func__); (*r_totedge) = 0; return; } ed = edsort = MEM_mallocN(totedge * sizeof(struct EdgeSort), "EdgeSort"); for (a = totface, mface = allface; a > 0; a--, mface++) { to_edgesort(ed++, mface->v1, mface->v2, !mface->v3, mface->edcode & ME_V1V2); if (mface->v4) { to_edgesort(ed++, mface->v2, mface->v3, 0, mface->edcode & ME_V2V3); to_edgesort(ed++, mface->v3, mface->v4, 0, mface->edcode & ME_V3V4); to_edgesort(ed++, mface->v4, mface->v1, 0, mface->edcode & ME_V4V1); } else if (mface->v3) { to_edgesort(ed++, mface->v2, mface->v3, 0, mface->edcode & ME_V2V3); to_edgesort(ed++, mface->v3, mface->v1, 0, mface->edcode & ME_V3V1); } } qsort(edsort, totedge, sizeof(struct EdgeSort), vergedgesort); /* count final amount */ for (a = totedge, ed = edsort; a > 1; a--, ed++) { /* edge is unique when it differs from next edge, or is last */ if (ed->v1 != (ed + 1)->v1 || ed->v2 != (ed + 1)->v2) totedge_final++; } totedge_final++; medge = MEM_callocN(sizeof(MEdge) * totedge_final, __func__); for (a = totedge, med = medge, ed = edsort; a > 1; a--, ed++) { /* edge is unique when it differs from next edge, or is last */ if (ed->v1 != (ed + 1)->v1 || ed->v2 != (ed + 1)->v2) { med->v1 = ed->v1; med->v2 = ed->v2; if (use_old == false || ed->is_draw) med->flag = ME_EDGEDRAW | ME_EDGERENDER; if (ed->is_loose) med->flag |= ME_LOOSEEDGE; /* order is swapped so extruding this edge as a surface wont flip face normals * with cyclic curves */ if (ed->v1 + 1 != ed->v2) { SWAP(unsigned int, med->v1, med->v2); } med++; }
static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], ParticleSystem *psys, int level, int animated) { GroupObject *go; Object *ob = NULL, **oblist = NULL, obcopy, *obcopylist = NULL; DupliObject *dob; ParticleDupliWeight *dw; ParticleSettings *part; ParticleData *pa; ChildParticle *cpa = NULL; ParticleKey state; ParticleCacheKey *cache; float ctime, pa_time, scale = 1.0f; float tmat[4][4], mat[4][4], pamat[4][4], vec[3], size = 0.0; float (*obmat)[4], (*oldobmat)[4]; int a, b, counter, hair = 0; int totpart, totchild, totgroup = 0 /*, pa_num */; int no_draw_flag = PARS_UNEXIST; if (psys == NULL) return; /* simple preventing of too deep nested groups */ if (level > MAX_DUPLI_RECUR) return; part = psys->part; if (part == NULL) return; if (!psys_check_enabled(par, psys)) return; if (G.rendering == 0) no_draw_flag |= PARS_NO_DISP; ctime = BKE_scene_frame_get(scene); /* NOTE: in old animsys, used parent object's timeoffset... */ totpart = psys->totpart; totchild = psys->totchild; BLI_srandom(31415926 + psys->seed); if ((psys->renderdata || part->draw_as == PART_DRAW_REND) && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) { ParticleSimulationData sim = {NULL}; sim.scene = scene; sim.ob = par; sim.psys = psys; sim.psmd = psys_get_modifier(par, psys); /* make sure emitter imat is in global coordinates instead of render view coordinates */ invert_m4_m4(par->imat, par->obmat); /* first check for loops (particle system object used as dupli object) */ if (part->ren_as == PART_DRAW_OB) { if (ELEM(part->dup_ob, NULL, par)) return; } else { /*PART_DRAW_GR */ if (part->dup_group == NULL || part->dup_group->gobject.first == NULL) return; for (go = part->dup_group->gobject.first; go; go = go->next) if (go->ob == par) return; } /* if we have a hair particle system, use the path cache */ if (part->type == PART_HAIR) { if (psys->flag & PSYS_HAIR_DONE) hair = (totchild == 0 || psys->childcache) && psys->pathcache; if (!hair) return; /* we use cache, update totchild according to cached data */ totchild = psys->totchildcache; totpart = psys->totcached; } psys_check_group_weights(part); psys->lattice = psys_get_lattice(&sim); /* gather list of objects or single object */ if (part->ren_as == PART_DRAW_GR) { group_handle_recalc_and_update(scene, par, part->dup_group); if (part->draw & PART_DRAW_COUNT_GR) { for (dw = part->dupliweights.first; dw; dw = dw->next) totgroup += dw->count; } else { for (go = part->dup_group->gobject.first; go; go = go->next) totgroup++; } /* we also copy the actual objects to restore afterwards, since * BKE_object_where_is_calc_time will change the object which breaks transform */ oblist = MEM_callocN(totgroup * sizeof(Object *), "dupgroup object list"); obcopylist = MEM_callocN(totgroup * sizeof(Object), "dupgroup copy list"); if (part->draw & PART_DRAW_COUNT_GR && totgroup) { dw = part->dupliweights.first; for (a = 0; a < totgroup; dw = dw->next) { for (b = 0; b < dw->count; b++, a++) { oblist[a] = dw->ob; obcopylist[a] = *dw->ob; } } } else { go = part->dup_group->gobject.first; for (a = 0; a < totgroup; a++, go = go->next) { oblist[a] = go->ob; obcopylist[a] = *go->ob; } } } else { ob = part->dup_ob; obcopy = *ob; } if (totchild == 0 || part->draw & PART_DRAW_PARENT) a = 0; else a = totpart; for (pa = psys->particles, counter = 0; a < totpart + totchild; a++, pa++, counter++) { if (a < totpart) { /* handle parent particle */ if (pa->flag & no_draw_flag) continue; /* pa_num = pa->num; */ /* UNUSED */ pa_time = pa->time; size = pa->size; } else { /* handle child particle */ cpa = &psys->child[a - totpart]; /* pa_num = a; */ /* UNUSED */ pa_time = psys->particles[cpa->parent].time; size = psys_get_child_size(psys, cpa, ctime, NULL); } /* some hair paths might be non-existent so they can't be used for duplication */ if (hair && ((a < totpart && psys->pathcache[a]->steps < 0) || (a >= totpart && psys->childcache[a - totpart]->steps < 0))) { continue; } if (part->ren_as == PART_DRAW_GR) { /* prevent divide by zero below [#28336] */ if (totgroup == 0) continue; /* for groups, pick the object based on settings */ if (part->draw & PART_DRAW_RAND_GR) b = BLI_rand() % totgroup; else b = a % totgroup; ob = oblist[b]; obmat = oblist[b]->obmat; oldobmat = obcopylist[b].obmat; } else { obmat = ob->obmat; oldobmat = obcopy.obmat; } if (hair) { /* hair we handle separate and compute transform based on hair keys */ if (a < totpart) { cache = psys->pathcache[a]; psys_get_dupli_path_transform(&sim, pa, NULL, cache, pamat, &scale); } else { cache = psys->childcache[a - totpart]; psys_get_dupli_path_transform(&sim, NULL, cpa, cache, pamat, &scale); } copy_v3_v3(pamat[3], cache->co); pamat[3][3] = 1.0f; } else { /* first key */ state.time = ctime; if (psys_get_particle_state(&sim, a, &state, 0) == 0) { continue; } else { float tquat[4]; normalize_qt_qt(tquat, state.rot); quat_to_mat4(pamat, tquat); copy_v3_v3(pamat[3], state.co); pamat[3][3] = 1.0f; } } if (part->ren_as == PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) { for (go = part->dup_group->gobject.first, b = 0; go; go = go->next, b++) { copy_m4_m4(tmat, oblist[b]->obmat); /* apply particle scale */ mul_mat3_m4_fl(tmat, size * scale); mul_v3_fl(tmat[3], size * scale); /* group dupli offset, should apply after everything else */ if (!is_zero_v3(part->dup_group->dupli_ofs)) sub_v3_v3v3(tmat[3], tmat[3], part->dup_group->dupli_ofs); /* individual particle transform */ mult_m4_m4m4(tmat, pamat, tmat); if (par_space_mat) mult_m4_m4m4(mat, par_space_mat, tmat); else copy_m4_m4(mat, tmat); dob = new_dupli_object(lb, go->ob, mat, par->lay, counter, OB_DUPLIPARTS, animated); copy_m4_m4(dob->omat, obcopylist[b].obmat); if (G.rendering) psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); } } else { /* to give ipos in object correct offset */ BKE_object_where_is_calc_time(scene, ob, ctime - pa_time); copy_v3_v3(vec, obmat[3]); obmat[3][0] = obmat[3][1] = obmat[3][2] = 0.0f; /* particle rotation uses x-axis as the aligned axis, so pre-rotate the object accordingly */ if ((part->draw & PART_DRAW_ROTATE_OB) == 0) { float xvec[3], q[4]; xvec[0] = -1.f; xvec[1] = xvec[2] = 0; vec_to_quat(q, xvec, ob->trackflag, ob->upflag); quat_to_mat4(obmat, q); obmat[3][3] = 1.0f; } /* Normal particles and cached hair live in global space so we need to * remove the real emitter's transformation before 2nd order duplication. */ if (par_space_mat && GS(id->name) != ID_GR) mult_m4_m4m4(mat, psys->imat, pamat); else copy_m4_m4(mat, pamat); mult_m4_m4m4(tmat, mat, obmat); mul_mat3_m4_fl(tmat, size * scale); if (par_space_mat) mult_m4_m4m4(mat, par_space_mat, tmat); else copy_m4_m4(mat, tmat); if (part->draw & PART_DRAW_GLOBAL_OB) add_v3_v3v3(mat[3], mat[3], vec); dob = new_dupli_object(lb, ob, mat, ob->lay, counter, GS(id->name) == ID_GR ? OB_DUPLIGROUP : OB_DUPLIPARTS, animated); copy_m4_m4(dob->omat, oldobmat); if (G.rendering) psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); } } /* restore objects since they were changed in BKE_object_where_is_calc_time */ if (part->ren_as == PART_DRAW_GR) { for (a = 0; a < totgroup; a++) *(oblist[a]) = obcopylist[a]; } else *ob = obcopy; } /* clean up */ if (oblist) MEM_freeN(oblist); if (obcopylist) MEM_freeN(obcopylist); if (psys->lattice) { end_latt_deform(psys->lattice); psys->lattice = NULL; } }
static int delete_exec(bContext *C, wmOperator *UNUSED(op)) { Mask *mask = CTX_data_edit_mask(C); MaskLayer *masklay; for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { MaskSpline *spline; int mask_layer_shape_ofs = 0; if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) { continue; } spline = masklay->splines.first; while (spline) { const int tot_point_orig = spline->tot_point; int i, count = 0; MaskSpline *next_spline = spline->next; /* count unselected points */ for (i = 0; i < spline->tot_point; i++) { MaskSplinePoint *point = &spline->points[i]; if (!MASKPOINT_ISSEL_ANY(point)) count++; } if (count == 0) { /* delete the whole spline */ BLI_remlink(&masklay->splines, spline); BKE_mask_spline_free(spline); if (spline == masklay->act_spline) { masklay->act_spline = NULL; masklay->act_point = NULL; } BKE_mask_layer_shape_changed_remove(masklay, mask_layer_shape_ofs, tot_point_orig); } else { MaskSplinePoint *new_points; int j; new_points = MEM_callocN(count * sizeof(MaskSplinePoint), "deleteMaskPoints"); for (i = 0, j = 0; i < tot_point_orig; i++) { MaskSplinePoint *point = &spline->points[i]; if (!MASKPOINT_ISSEL_ANY(point)) { if (point == masklay->act_point) masklay->act_point = &new_points[j]; delete_feather_points(point); new_points[j] = *point; j++; } else { if (point == masklay->act_point) masklay->act_point = NULL; BKE_mask_point_free(point); spline->tot_point--; BKE_mask_layer_shape_changed_remove(masklay, mask_layer_shape_ofs + j, 1); } } mask_layer_shape_ofs += spline->tot_point; MEM_freeN(spline->points); spline->points = new_points; ED_mask_select_flush_all(mask); } spline = next_spline; } /* not essential but confuses users when there are keys with no data! * assume if they delete all data from the layer they also dont care about keys */ if (masklay->splines.first == NULL) { BKE_mask_layer_free_shapes(masklay); } } /* TODO: only update edited splines */ BKE_mask_update_display(mask, CTX_data_scene(C)->r.cfra); WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask); return OPERATOR_FINISHED; }
/* read .bobj.gz file into a fluidsimDerivedMesh struct */ static DerivedMesh *fluidsim_read_obj(const char *filename) { int wri = 0,i; int gotBytes; gzFile gzf; int numverts = 0, numfaces = 0; DerivedMesh *dm = NULL; MFace *mf; MVert *mv; short *normals, *no_s; float no[3]; // ------------------------------------------------ // get numverts + numfaces first // ------------------------------------------------ gzf = gzopen(filename, "rb"); if (!gzf) { return NULL; } // read numverts gotBytes = gzread(gzf, &wri, sizeof(wri)); numverts = wri; // skip verts gotBytes = gzseek(gzf, numverts * 3 * sizeof(float), SEEK_CUR) != -1; // read number of normals if(gotBytes) gotBytes = gzread(gzf, &wri, sizeof(wri)); // skip normals gotBytes = gzseek(gzf, numverts * 3 * sizeof(float), SEEK_CUR) != -1; /* get no. of triangles */ if(gotBytes) gotBytes = gzread(gzf, &wri, sizeof(wri)); numfaces = wri; gzclose( gzf ); // ------------------------------------------------ if(!numfaces || !numverts || !gotBytes) return NULL; gzf = gzopen(filename, "rb"); if (!gzf) { return NULL; } dm = CDDM_new(numverts, 0, numfaces); if(!dm) { gzclose( gzf ); return NULL; } // read numverts gotBytes = gzread(gzf, &wri, sizeof(wri)); // read vertex position from file mv = CDDM_get_verts(dm); for(i=0; i<numverts; i++, mv++) gotBytes = gzread(gzf, mv->co, sizeof(float) * 3); // should be the same as numverts gotBytes = gzread(gzf, &wri, sizeof(wri)); if(wri != numverts) { if(dm) dm->release(dm); gzclose( gzf ); return NULL; } normals = MEM_callocN(sizeof(short) * numverts * 3, "fluid_tmp_normals" ); if(!normals) { if(dm) dm->release(dm); gzclose( gzf ); return NULL; } // read normals from file (but don't save them yet) for(i=numverts, no_s= normals; i>0; i--, no_s += 3) { gotBytes = gzread(gzf, no, sizeof(float) * 3); normal_float_to_short_v3(no_s, no); } /* read no. of triangles */ gotBytes = gzread(gzf, &wri, sizeof(wri)); if(wri!=numfaces) { printf("Fluidsim: error in reading data from file.\n"); if(dm) dm->release(dm); gzclose( gzf ); MEM_freeN(normals); return NULL; } // read triangles from file mf = CDDM_get_faces(dm); for(i=numfaces; i>0; i--, mf++) { int face[3]; gotBytes = gzread(gzf, face, sizeof(int) * 3); // check if 3rd vertex has index 0 (not allowed in blender) if(face[2]) { mf->v1 = face[0]; mf->v2 = face[1]; mf->v3 = face[2]; } else { mf->v1 = face[1]; mf->v2 = face[2]; mf->v3 = face[0]; } mf->v4 = 0; test_index_face(mf, NULL, 0, 3); } gzclose( gzf ); CDDM_calc_edges(dm); CDDM_apply_vert_normals(dm, (short (*)[3])normals); MEM_freeN(normals); // CDDM_calc_normals(result); return dm; }
void get_texture_coords(MappingInfoModifierData *dmd, Object *ob, DerivedMesh *dm, float (*co)[3], float (*texco)[3], int numVerts) { int i; int texmapping = dmd->texmapping; float mapob_imat[4][4]; if(texmapping == MOD_DISP_MAP_OBJECT) { if(dmd->map_object) invert_m4_m4(mapob_imat, dmd->map_object->obmat); else /* if there is no map object, default to local */ texmapping = MOD_DISP_MAP_LOCAL; } /* UVs need special handling, since they come from faces */ if(texmapping == MOD_DISP_MAP_UV) { if(CustomData_has_layer(&dm->faceData, CD_MTFACE)) { MFace *mface = dm->getFaceArray(dm); MFace *mf; char *done = MEM_callocN(sizeof(*done) * numVerts, "get_texture_coords done"); int numFaces = dm->getNumFaces(dm); char uvname[32]; MTFace *tf; validate_layer_name(&dm->faceData, CD_MTFACE, dmd->uvlayer_name, uvname); tf = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, uvname); /* verts are given the UV from the first face that uses them */ for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tf) { if(!done[mf->v1]) { texco[mf->v1][0] = tf->uv[0][0]; texco[mf->v1][1] = tf->uv[0][1]; texco[mf->v1][2] = 0; done[mf->v1] = 1; } if(!done[mf->v2]) { texco[mf->v2][0] = tf->uv[1][0]; texco[mf->v2][1] = tf->uv[1][1]; texco[mf->v2][2] = 0; done[mf->v2] = 1; } if(!done[mf->v3]) { texco[mf->v3][0] = tf->uv[2][0]; texco[mf->v3][1] = tf->uv[2][1]; texco[mf->v3][2] = 0; done[mf->v3] = 1; } if(!done[mf->v4]) { texco[mf->v4][0] = tf->uv[3][0]; texco[mf->v4][1] = tf->uv[3][1]; texco[mf->v4][2] = 0; done[mf->v4] = 1; } } /* remap UVs from [0, 1] to [-1, 1] */ for(i = 0; i < numVerts; ++i) { texco[i][0] = texco[i][0] * 2 - 1; texco[i][1] = texco[i][1] * 2 - 1; } MEM_freeN(done); return; } else /* if there are no UVs, default to local */ texmapping = MOD_DISP_MAP_LOCAL; } for(i = 0; i < numVerts; ++i, ++co, ++texco) { switch(texmapping) { case MOD_DISP_MAP_LOCAL: copy_v3_v3(*texco, *co); break; case MOD_DISP_MAP_GLOBAL: mul_v3_m4v3(*texco, ob->obmat, *co); break; case MOD_DISP_MAP_OBJECT: mul_v3_m4v3(*texco, ob->obmat, *co); mul_m4_v3(mapob_imat, *texco); break; } } }
static void *slide_point_customdata(bContext *C, wmOperator *op, wmEvent *event) { ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); Mask *mask = CTX_data_edit_mask(C); SlidePointData *customdata = NULL; MaskLayer *masklay, *cv_masklay, *feather_masklay; MaskSpline *spline, *cv_spline, *feather_spline; MaskSplinePoint *point, *cv_point, *feather_point; MaskSplinePointUW *uw = NULL; int is_handle = FALSE, width, height, action = SLIDE_ACTION_NONE; int slide_feather = RNA_boolean_get(op->ptr, "slide_feather"); float co[2], cv_score, feather_score; const float threshold = 19; ED_mask_mouse_pos(sa, ar, event, co); ED_mask_get_size(sa, &width, &height); cv_point = ED_mask_point_find_nearest(C, mask, co, threshold, &cv_masklay, &cv_spline, &is_handle, &cv_score); if (ED_mask_feather_find_nearest(C, mask, co, threshold, &feather_masklay, &feather_spline, &feather_point, &uw, &feather_score)) { if (slide_feather || !cv_point || feather_score < cv_score) { action = SLIDE_ACTION_FEATHER; masklay = feather_masklay; spline = feather_spline; point = feather_point; } } if (cv_point && action == SLIDE_ACTION_NONE) { if (is_handle) action = SLIDE_ACTION_HANDLE; else action = SLIDE_ACTION_POINT; masklay = cv_masklay; spline = cv_spline; point = cv_point; } if (action != SLIDE_ACTION_NONE) { customdata = MEM_callocN(sizeof(SlidePointData), "mask slide point data"); customdata->mask = mask; customdata->masklay = masklay; customdata->spline = spline; customdata->point = point; customdata->width = width; customdata->height = height; customdata->action = action; customdata->uw = uw; if (uw) { float co[2]; float weight_scalar = BKE_mask_point_weight_scalar(spline, point, uw->u); customdata->weight = uw->w; customdata->weight_scalar = weight_scalar; BKE_mask_point_segment_co(spline, point, uw->u, co); BKE_mask_point_normal(spline, point, uw->u, customdata->no); madd_v2_v2v2fl(customdata->feather, co, customdata->no, uw->w * weight_scalar); } else { BezTriple *bezt = &point->bezt; customdata->weight = bezt->weight; customdata->weight_scalar = 1.0f; BKE_mask_point_normal(spline, point, 0.0f, customdata->no); madd_v2_v2v2fl(customdata->feather, bezt->vec[1], customdata->no, bezt->weight); } if (customdata->action == SLIDE_ACTION_FEATHER) customdata->initial_feather = slide_point_check_initial_feather(spline); copy_m3_m3(customdata->vec, point->bezt.vec); if (BKE_mask_point_has_handle(point)) BKE_mask_point_handle(point, customdata->handle); ED_mask_mouse_pos(sa, ar, event, customdata->co); } return customdata; }
void BKE_lattice_resize(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb) { BPoint *bp; int i, u, v, w; float fu, fv, fw, uc, vc, wc, du = 0.0, dv = 0.0, dw = 0.0; float *co, (*vertexCos)[3] = NULL; /* vertex weight groups are just freed all for now */ if (lt->dvert) { BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); lt->dvert = NULL; } while (uNew * vNew * wNew > 32000) { if (uNew >= vNew && uNew >= wNew) uNew--; else if (vNew >= uNew && vNew >= wNew) vNew--; else wNew--; } vertexCos = MEM_mallocN(sizeof(*vertexCos) * uNew * vNew * wNew, "tmp_vcos"); calc_lat_fudu(lt->flag, uNew, &fu, &du); calc_lat_fudu(lt->flag, vNew, &fv, &dv); calc_lat_fudu(lt->flag, wNew, &fw, &dw); /* If old size is different then resolution changed in interface, * try to do clever reinit of points. Pretty simply idea, we just * deform new verts by old lattice, but scaling them to match old * size first. */ if (ltOb) { if (uNew != 1 && lt->pntsu != 1) { fu = lt->fu; du = (lt->pntsu - 1) * lt->du / (uNew - 1); } if (vNew != 1 && lt->pntsv != 1) { fv = lt->fv; dv = (lt->pntsv - 1) * lt->dv / (vNew - 1); } if (wNew != 1 && lt->pntsw != 1) { fw = lt->fw; dw = (lt->pntsw - 1) * lt->dw / (wNew - 1); } } co = vertexCos[0]; for (w = 0, wc = fw; w < wNew; w++, wc += dw) { for (v = 0, vc = fv; v < vNew; v++, vc += dv) { for (u = 0, uc = fu; u < uNew; u++, co += 3, uc += du) { co[0] = uc; co[1] = vc; co[2] = wc; } } } if (ltOb) { float mat[4][4]; int typeu = lt->typeu, typev = lt->typev, typew = lt->typew; /* works best if we force to linear type (endpoints match) */ lt->typeu = lt->typev = lt->typew = KEY_LINEAR; /* prevent using deformed locations */ BKE_displist_free(<Ob->curve_cache->disp); copy_m4_m4(mat, ltOb->obmat); unit_m4(ltOb->obmat); lattice_deform_verts(ltOb, NULL, NULL, vertexCos, uNew * vNew * wNew, NULL, 1.0f); copy_m4_m4(ltOb->obmat, mat); lt->typeu = typeu; lt->typev = typev; lt->typew = typew; } lt->fu = fu; lt->fv = fv; lt->fw = fw; lt->du = du; lt->dv = dv; lt->dw = dw; lt->pntsu = uNew; lt->pntsv = vNew; lt->pntsw = wNew; lt->actbp = LT_ACTBP_NONE; MEM_freeN(lt->def); lt->def = MEM_callocN(lt->pntsu * lt->pntsv * lt->pntsw * sizeof(BPoint), "lattice bp"); bp = lt->def; for (i = 0; i < lt->pntsu * lt->pntsv * lt->pntsw; i++, bp++) { copy_v3_v3(bp->vec, vertexCos[i]); } MEM_freeN(vertexCos); }
static void sss_create_tree_mat(Render *re, Material *mat) { SSSPoints *p; RenderResult *rr; ListBase points; float (*co)[3] = NULL, (*color)[3] = NULL, *area = NULL; int totpoint = 0, osa, osaflag, partsdone; if (re->test_break(re->tbh)) return; points.first= points.last= NULL; /* TODO: this is getting a bit ugly, copying all those variables and * setting them back, maybe we need to create our own Render? */ /* do SSS preprocessing render */ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); rr= re->result; osa= re->osa; osaflag= re->r.mode & R_OSA; partsdone= re->i.partsdone; re->osa= 0; re->r.mode &= ~R_OSA; re->sss_points= &points; re->sss_mat= mat; re->i.partsdone = FALSE; if (!(re->r.scemode & R_PREVIEWBUTS)) re->result= NULL; BLI_rw_mutex_unlock(&re->resultmutex); RE_TileProcessor(re); BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); if (!(re->r.scemode & R_PREVIEWBUTS)) { RE_FreeRenderResult(re->result); re->result= rr; } BLI_rw_mutex_unlock(&re->resultmutex); re->i.partsdone= partsdone; re->sss_mat= NULL; re->sss_points= NULL; re->osa= osa; if (osaflag) re->r.mode |= R_OSA; /* no points? no tree */ if (!points.first) return; /* merge points together into a single buffer */ if (!re->test_break(re->tbh)) { for (totpoint=0, p=points.first; p; p=p->next) totpoint += p->totpoint; co= MEM_mallocN(sizeof(*co)*totpoint, "SSSCo"); color= MEM_mallocN(sizeof(*color)*totpoint, "SSSColor"); area= MEM_mallocN(sizeof(*area)*totpoint, "SSSArea"); for (totpoint=0, p=points.first; p; p=p->next) { memcpy(co+totpoint, p->co, sizeof(*co)*p->totpoint); memcpy(color+totpoint, p->color, sizeof(*color)*p->totpoint); memcpy(area+totpoint, p->area, sizeof(*area)*p->totpoint); totpoint += p->totpoint; } } /* free points */ for (p=points.first; p; p=p->next) { MEM_freeN(p->co); MEM_freeN(p->color); MEM_freeN(p->area); } BLI_freelistN(&points); /* build tree */ if (!re->test_break(re->tbh)) { SSSData *sss= MEM_callocN(sizeof(*sss), "SSSData"); float ior= mat->sss_ior, cfac= mat->sss_colfac; float *radius= mat->sss_radius; float fw= mat->sss_front, bw= mat->sss_back; float error = mat->sss_error; error= get_render_aosss_error(&re->r, error); if ((re->r.scemode & R_PREVIEWBUTS) && error < 0.5f) error= 0.5f; sss->ss[0]= scatter_settings_new(mat->sss_col[0], radius[0], ior, cfac, fw, bw); sss->ss[1]= scatter_settings_new(mat->sss_col[1], radius[1], ior, cfac, fw, bw); sss->ss[2]= scatter_settings_new(mat->sss_col[2], radius[2], ior, cfac, fw, bw); sss->tree= scatter_tree_new(sss->ss, mat->sss_scale, error, co, color, area, totpoint); MEM_freeN(co); MEM_freeN(color); MEM_freeN(area); scatter_tree_build(sss->tree); BLI_ghash_insert(re->sss_hash, mat, sss); } else { if (co) MEM_freeN(co); if (color) MEM_freeN(color); if (area) MEM_freeN(area); } }
void smokeModifier_createType(struct SmokeModifierData *smd) { if(smd) { if(smd->type & MOD_SMOKE_TYPE_DOMAIN) { if(smd->domain) smokeModifier_freeDomain(smd); smd->domain = MEM_callocN(sizeof(SmokeDomainSettings), "SmokeDomain"); smd->domain->smd = smd; smd->domain->point_cache[0] = BKE_ptcache_add(&(smd->domain->ptcaches[0])); smd->domain->point_cache[0]->flag |= PTCACHE_DISK_CACHE; smd->domain->point_cache[0]->step = 1; smd->domain->point_cache[1] = BKE_ptcache_add(&(smd->domain->ptcaches[1])); smd->domain->point_cache[1]->flag |= PTCACHE_DISK_CACHE; smd->domain->point_cache[1]->step = 1; /* set some standard values */ smd->domain->fluid = NULL; smd->domain->wt = NULL; smd->domain->eff_group = NULL; smd->domain->fluid_group = NULL; smd->domain->coll_group = NULL; smd->domain->maxres = 32; smd->domain->amplify = 1; smd->domain->omega = 1.0; smd->domain->alpha = -0.001; smd->domain->beta = 0.1; smd->domain->flags = MOD_SMOKE_DISSOLVE_LOG; smd->domain->strength = 2.0; smd->domain->noise = MOD_SMOKE_NOISEWAVE; smd->domain->diss_speed = 5; // init 3dview buffer smd->domain->viewsettings = 0; smd->domain->effector_weights = BKE_add_effector_weights(NULL); } else if(smd->type & MOD_SMOKE_TYPE_FLOW) { if(smd->flow) smokeModifier_freeFlow(smd); smd->flow = MEM_callocN(sizeof(SmokeFlowSettings), "SmokeFlow"); smd->flow->smd = smd; /* set some standard values */ smd->flow->density = 1.0; smd->flow->temp = 1.0; smd->flow->psys = NULL; } else if(smd->type & MOD_SMOKE_TYPE_COLL) { if(smd->coll) smokeModifier_freeCollision(smd); smd->coll = MEM_callocN(sizeof(SmokeCollSettings), "SmokeColl"); smd->coll->smd = smd; smd->coll->points = NULL; smd->coll->numpoints = 0; smd->coll->bvhtree = NULL; smd->coll->dm = NULL; } } }
/* Edge-Length Weighted Smoothing */ static void smooth_iter__length_weight( CorrectiveSmoothModifierData *csmd, DerivedMesh *dm, float (*vertexCos)[3], unsigned int numVerts, const float *smooth_weights, unsigned int iterations) { const float eps = FLT_EPSILON * 10.0f; const unsigned int numEdges = (unsigned int)dm->getNumEdges(dm); /* note: the way this smoothing method works, its approx half as strong as the simple-smooth, * and 2.0 rarely spikes, double the value for consistent behavior. */ const float lambda = csmd->lambda * 2.0f; const MEdge *edges = dm->getEdgeArray(dm); float *vertex_edge_count; unsigned int i; struct SmoothingData_Weighted { float delta[3]; float edge_length_sum; } *smooth_data = MEM_callocN((size_t)numVerts * sizeof(*smooth_data), __func__); /* calculate as floats to avoid int->float conversion in #smooth_iter */ vertex_edge_count = MEM_callocN((size_t)numVerts * sizeof(float), __func__); for (i = 0; i < numEdges; i++) { vertex_edge_count[edges[i].v1] += 1.0f; vertex_edge_count[edges[i].v2] += 1.0f; } /* -------------------------------------------------------------------- */ /* Main Smoothing Loop */ while (iterations--) { for (i = 0; i < numEdges; i++) { struct SmoothingData_Weighted *sd_v1; struct SmoothingData_Weighted *sd_v2; float edge_dir[3]; float edge_dist; sub_v3_v3v3(edge_dir, vertexCos[edges[i].v2], vertexCos[edges[i].v1]); edge_dist = len_v3(edge_dir); /* weight by distance */ mul_v3_fl(edge_dir, edge_dist); sd_v1 = &smooth_data[edges[i].v1]; sd_v2 = &smooth_data[edges[i].v2]; add_v3_v3(sd_v1->delta, edge_dir); sub_v3_v3(sd_v2->delta, edge_dir); sd_v1->edge_length_sum += edge_dist; sd_v2->edge_length_sum += edge_dist; } if (smooth_weights == NULL) { /* fast-path */ for (i = 0; i < numVerts; i++) { struct SmoothingData_Weighted *sd = &smooth_data[i]; /* divide by sum of all neighbour distances (weighted) and amount of neighbors, (mean average) */ const float div = sd->edge_length_sum * vertex_edge_count[i]; if (div > eps) { #if 0 /* first calculate the new location */ mul_v3_fl(sd->delta, 1.0f / div); /* then interpolate */ madd_v3_v3fl(vertexCos[i], sd->delta, lambda); #else /* do this in one step */ madd_v3_v3fl(vertexCos[i], sd->delta, lambda / div); #endif } /* zero for the next iteration (saves memset on entire array) */ memset(sd, 0, sizeof(*sd)); } } else { for (i = 0; i < numVerts; i++) { struct SmoothingData_Weighted *sd = &smooth_data[i]; const float div = sd->edge_length_sum * vertex_edge_count[i]; if (div > eps) { const float lambda_w = lambda * smooth_weights[i]; madd_v3_v3fl(vertexCos[i], sd->delta, lambda_w / div); } memset(sd, 0, sizeof(*sd)); } } } MEM_freeN(vertex_edge_count); MEM_freeN(smooth_data); }
void fluidsim_init(FluidsimModifierData *fluidmd) { #ifdef WITH_MOD_FLUID if(fluidmd) { FluidsimSettings *fss = MEM_callocN(sizeof(FluidsimSettings), "fluidsimsettings"); fluidmd->fss = fss; if(!fss) return; fss->fmd = fluidmd; fss->type = OB_FLUIDSIM_ENABLE; fss->show_advancedoptions = 0; fss->resolutionxyz = 65; fss->previewresxyz = 45; fss->realsize = 0.5; fss->guiDisplayMode = 2; // preview fss->renderDisplayMode = 3; // render fss->viscosityMode = 2; // default to water fss->viscosityValue = 1.0; fss->viscosityExponent = 6; fss->grav[0] = 0.0; fss->grav[1] = 0.0; fss->grav[2] = -9.81; fss->animStart = 0.0; fss->animEnd = 4.0; fss->animRate = 1.0; fss->gstar = 0.005; // used as normgstar fss->maxRefine = -1; // maxRefine is set according to resolutionxyz during bake // fluid/inflow settings // fss->iniVel --> automatically set to 0 modifier_path_init(fss->surfdataPath, sizeof(fss->surfdataPath), "cache_fluid"); // first init of bounding box // no bounding box needed // todo - reuse default init from elbeem! fss->typeFlags = OB_FSBND_PARTSLIP | OB_FSSG_NOOBS; fss->domainNovecgen = 0; fss->volumeInitType = 1; // volume fss->partSlipValue = 0.2; fss->generateTracers = 0; fss->generateParticles = 0.0; fss->surfaceSmoothing = 1.0; fss->surfaceSubdivs = 0.0; fss->particleInfSize = 0.0; fss->particleInfAlpha = 0.0; // init fluid control settings fss->attractforceStrength = 0.2; fss->attractforceRadius = 0.75; fss->velocityforceStrength = 0.2; fss->velocityforceRadius = 0.75; fss->cpsTimeStart = fss->animStart; fss->cpsTimeEnd = fss->animEnd; fss->cpsQuality = 10.0; // 1.0 / 10.0 => means 0.1 width /* BAD TODO: this is done in buttons_object.c in the moment Mesh *mesh = ob->data; // calculate bounding box fluid_get_bb(mesh->mvert, mesh->totvert, ob->obmat, fss->bbStart, fss->bbSize); */ fss->meshVelocities = NULL; fss->lastgoodframe = -1; fss->flag |= OB_FLUIDSIM_ACTIVE; } #else (void)fluidmd; /* unused */ #endif return; }
static void correctivesmooth_modifier_do( ModifierData *md, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], unsigned int numVerts, struct BMEditMesh *em) { CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md; const bool force_delta_cache_update = /* XXX, take care! if mesh data its self changes we need to forcefully recalculate deltas */ ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO) && (((ID *)ob->data)->tag & LIB_TAG_ID_RECALC)); bool use_only_smooth = (csmd->flag & MOD_CORRECTIVESMOOTH_ONLY_SMOOTH) != 0; MDeformVert *dvert = NULL; int defgrp_index; modifier_get_vgroup(ob, dm, csmd->defgrp_name, &dvert, &defgrp_index); /* if rest bind_coords not are defined, set them (only run during bind) */ if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) && /* signal to recalculate, whoever sets MUST also free bind coords */ (csmd->bind_coords_num == (unsigned int)-1)) { BLI_assert(csmd->bind_coords == NULL); csmd->bind_coords = MEM_dupallocN(vertexCos); csmd->bind_coords_num = numVerts; BLI_assert(csmd->bind_coords != NULL); } if (UNLIKELY(use_only_smooth)) { smooth_verts(csmd, dm, dvert, defgrp_index, vertexCos, numVerts); return; } if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) && (csmd->bind_coords == NULL)) { modifier_setError(md, "Bind data required"); goto error; } /* If the number of verts has changed, the bind is invalid, so we do nothing */ if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) { if (csmd->bind_coords_num != numVerts) { modifier_setError(md, "Bind vertex count mismatch: %u to %u", csmd->bind_coords_num, numVerts); goto error; } } else { /* MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO */ if (ob->type != OB_MESH) { modifier_setError(md, "Object is not a mesh"); goto error; } else { unsigned int me_numVerts = (unsigned int)((em) ? em->bm->totvert : ((Mesh *)ob->data)->totvert); if (me_numVerts != numVerts) { modifier_setError(md, "Original vertex count mismatch: %u to %u", me_numVerts, numVerts); goto error; } } } /* check to see if our deltas are still valid */ if (!csmd->delta_cache || (csmd->delta_cache_num != numVerts) || force_delta_cache_update) { const float (*rest_coords)[3]; bool is_rest_coords_alloc = false; if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) { /* caller needs to do sanity check here */ csmd->bind_coords_num = numVerts; rest_coords = (const float (*)[3])csmd->bind_coords; } else { int me_numVerts; rest_coords = (const float (*)[3]) ((em) ? BKE_editmesh_vertexCos_get_orco(em, &me_numVerts) : BKE_mesh_vertexCos_get(ob->data, &me_numVerts)); BLI_assert((unsigned int)me_numVerts == numVerts); is_rest_coords_alloc = true; } #ifdef DEBUG_TIME TIMEIT_START(corrective_smooth_deltas); #endif calc_deltas(csmd, dm, dvert, defgrp_index, rest_coords, numVerts); #ifdef DEBUG_TIME TIMEIT_END(corrective_smooth_deltas); #endif if (is_rest_coords_alloc) { MEM_freeN((void *)rest_coords); } } if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) { /* this could be a check, but at this point it _must_ be valid */ BLI_assert(csmd->bind_coords_num == numVerts && csmd->delta_cache); } #ifdef DEBUG_TIME TIMEIT_START(corrective_smooth); #endif /* do the actual delta mush */ smooth_verts(csmd, dm, dvert, defgrp_index, vertexCos, numVerts); { unsigned int i; float (*tangent_spaces)[3][3]; /* calloc, since values are accumulated */ tangent_spaces = MEM_callocN((size_t)numVerts * sizeof(float[3][3]), __func__); calc_tangent_spaces(dm, vertexCos, tangent_spaces); for (i = 0; i < numVerts; i++) { float delta[3]; #ifdef USE_TANGENT_CALC_INLINE calc_tangent_ortho(tangent_spaces[i]); #endif mul_v3_m3v3(delta, tangent_spaces[i], csmd->delta_cache[i]); add_v3_v3(vertexCos[i], delta); } MEM_freeN(tangent_spaces); } #ifdef DEBUG_TIME TIMEIT_END(corrective_smooth); #endif return; /* when the modifier fails to execute */ error: MEM_SAFE_FREE(csmd->delta_cache); csmd->delta_cache_num = 0; }
ThreadRWMutex *BLI_rw_mutex_alloc(void) { ThreadRWMutex *mutex = MEM_callocN(sizeof(ThreadRWMutex), "ThreadRWMutex"); BLI_rw_mutex_init(mutex); return mutex; }
/** * Validate the mesh, \a do_fixes requires \a mesh to be non-null. * * \return false if no changes needed to be made. */ bool BKE_mesh_validate_arrays(Mesh *mesh, MVert *mverts, unsigned int totvert, MEdge *medges, unsigned int totedge, MFace *mfaces, unsigned int totface, MLoop *mloops, unsigned int totloop, MPoly *mpolys, unsigned int totpoly, MDeformVert *dverts, /* assume totvert length */ const bool do_verbose, const bool do_fixes, bool *r_change) { # define REMOVE_EDGE_TAG(_me) { _me->v2 = _me->v1; do_edge_free = true; } (void)0 # define IS_REMOVED_EDGE(_me) (_me->v2 == _me->v1) # define REMOVE_LOOP_TAG(_ml) { _ml->e = INVALID_LOOP_EDGE_MARKER; do_polyloop_free = true; } (void)0 # define REMOVE_POLY_TAG(_mp) { _mp->totloop *= -1; do_polyloop_free = true; } (void)0 MVert *mv = mverts; MEdge *me; MLoop *ml; MPoly *mp; unsigned int i, j; int *v; bool is_valid = true; bool do_edge_free = false; bool do_face_free = false; bool do_polyloop_free = false; /* This regroups loops and polys! */ bool verts_fixed = false; bool vert_weights_fixed = false; bool msel_fixed = false; bool do_edge_recalc = false; EdgeHash *edge_hash = BLI_edgehash_new_ex(__func__, totedge); BLI_assert(!(do_fixes && mesh == NULL)); PRINT_MSG("%s: verts(%u), edges(%u), loops(%u), polygons(%u)\n", __func__, totvert, totedge, totloop, totpoly); if (totedge == 0 && totpoly != 0) { PRINT_ERR("\tLogical error, %u polygons and 0 edges\n", totpoly); do_edge_recalc = do_fixes; } for (i = 1; i < totvert; i++, mv++) { int fix_normal = TRUE; for (j = 0; j < 3; j++) { if (!finite(mv->co[j])) { PRINT_ERR("\tVertex %u: has invalid coordinate\n", i); if (do_fixes) { zero_v3(mv->co); verts_fixed = TRUE; } } if (mv->no[j] != 0) fix_normal = FALSE; } if (fix_normal) { PRINT_ERR("\tVertex %u: has zero normal, assuming Z-up normal\n", i); if (do_fixes) { mv->no[2] = SHRT_MAX; verts_fixed = TRUE; } } } for (i = 0, me = medges; i < totedge; i++, me++) { int remove = FALSE; if (me->v1 == me->v2) { PRINT_ERR("\tEdge %u: has matching verts, both %u\n", i, me->v1); remove = do_fixes; } if (me->v1 >= totvert) { PRINT_ERR("\tEdge %u: v1 index out of range, %u\n", i, me->v1); remove = do_fixes; } if (me->v2 >= totvert) { PRINT_ERR("\tEdge %u: v2 index out of range, %u\n", i, me->v2); remove = do_fixes; } if (BLI_edgehash_haskey(edge_hash, me->v1, me->v2)) { PRINT_ERR("\tEdge %u: is a duplicate of %d\n", i, GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, me->v1, me->v2))); remove = do_fixes; } if (remove == FALSE) { BLI_edgehash_insert(edge_hash, me->v1, me->v2, SET_INT_IN_POINTER(i)); } else { REMOVE_EDGE_TAG(me); } } if (mfaces && !mpolys) { # define REMOVE_FACE_TAG(_mf) { _mf->v3 = 0; do_face_free = TRUE; } (void)0 # define CHECK_FACE_VERT_INDEX(a, b) \ if (mf->a == mf->b) { \ PRINT_ERR(" face %u: verts invalid, " STRINGIFY(a) "/" STRINGIFY(b) " both %u\n", i, mf->a); \ remove = do_fixes; \ } (void)0 # define CHECK_FACE_EDGE(a, b) \ if (!BLI_edgehash_haskey(edge_hash, mf->a, mf->b)) { \ PRINT_ERR(" face %u: edge " STRINGIFY(a) "/" STRINGIFY(b) \ " (%u,%u) is missing edge data\n", i, mf->a, mf->b); \ do_edge_recalc = TRUE; \ } (void)0 MFace *mf; MFace *mf_prev; SortFace *sort_faces = MEM_callocN(sizeof(SortFace) * totface, "search faces"); SortFace *sf; SortFace *sf_prev; unsigned int totsortface = 0; PRINT_ERR("No Polys, only tesselated Faces\n"); for (i = 0, mf = mfaces, sf = sort_faces; i < totface; i++, mf++) { int remove = FALSE; int fidx; unsigned int fv[4]; fidx = mf->v4 ? 3 : 2; do { fv[fidx] = *(&(mf->v1) + fidx); if (fv[fidx] >= totvert) { PRINT_ERR("\tFace %u: 'v%d' index out of range, %u\n", i, fidx + 1, fv[fidx]); remove = do_fixes; } } while (fidx--); if (remove == FALSE) { if (mf->v4) { CHECK_FACE_VERT_INDEX(v1, v2); CHECK_FACE_VERT_INDEX(v1, v3); CHECK_FACE_VERT_INDEX(v1, v4); CHECK_FACE_VERT_INDEX(v2, v3); CHECK_FACE_VERT_INDEX(v2, v4); CHECK_FACE_VERT_INDEX(v3, v4); } else { CHECK_FACE_VERT_INDEX(v1, v2); CHECK_FACE_VERT_INDEX(v1, v3); CHECK_FACE_VERT_INDEX(v2, v3); } if (remove == FALSE) { if (totedge) { if (mf->v4) { CHECK_FACE_EDGE(v1, v2); CHECK_FACE_EDGE(v2, v3); CHECK_FACE_EDGE(v3, v4); CHECK_FACE_EDGE(v4, v1); } else { CHECK_FACE_EDGE(v1, v2); CHECK_FACE_EDGE(v2, v3); CHECK_FACE_EDGE(v3, v1); } } sf->index = i; if (mf->v4) { edge_store_from_mface_quad(sf->es, mf); qsort(sf->es, 4, sizeof(int64_t), int64_cmp); } else { edge_store_from_mface_tri(sf->es, mf); qsort(sf->es, 3, sizeof(int64_t), int64_cmp); } totsortface++; sf++; } } if (remove) { REMOVE_FACE_TAG(mf); } } qsort(sort_faces, totsortface, sizeof(SortFace), search_face_cmp); sf = sort_faces; sf_prev = sf; sf++; for (i = 1; i < totsortface; i++, sf++) { int remove = FALSE; /* on a valid mesh, code below will never run */ if (memcmp(sf->es, sf_prev->es, sizeof(sf_prev->es)) == 0) { mf = mfaces + sf->index; if (do_verbose) { mf_prev = mfaces + sf_prev->index; if (mf->v4) { PRINT_ERR("\tFace %u & %u: are duplicates (%u,%u,%u,%u) (%u,%u,%u,%u)\n", sf->index, sf_prev->index, mf->v1, mf->v2, mf->v3, mf->v4, mf_prev->v1, mf_prev->v2, mf_prev->v3, mf_prev->v4); } else { PRINT_ERR("\tFace %u & %u: are duplicates (%u,%u,%u) (%u,%u,%u)\n", sf->index, sf_prev->index, mf->v1, mf->v2, mf->v3, mf_prev->v1, mf_prev->v2, mf_prev->v3); } } remove = do_fixes; } else { sf_prev = sf; } if (remove) { REMOVE_FACE_TAG(mf); } } MEM_freeN(sort_faces); # undef REMOVE_FACE_TAG # undef CHECK_FACE_VERT_INDEX # undef CHECK_FACE_EDGE } /* Checking loops and polys is a bit tricky, as they are quite intricated... * * Polys must have: * - a valid loopstart value. * - a valid totloop value (>= 3 and loopstart+totloop < me.totloop). * * Loops must have: * - a valid v value. * - a valid e value (corresponding to the edge it defines with the next loop in poly). * * Also, loops not used by polys can be discarded. * And "intersecting" loops (i.e. loops used by more than one poly) are invalid, * so be sure to leave at most one poly per loop! */ { SortPoly *sort_polys = MEM_callocN(sizeof(SortPoly) * totpoly, "mesh validate's sort_polys"); SortPoly *prev_sp, *sp = sort_polys; int prev_end; for (i = 0, mp = mpolys; i < totpoly; i++, mp++, sp++) { sp->index = i; if (mp->loopstart < 0 || mp->totloop < 3) { /* Invalid loop data. */ PRINT_ERR("\tPoly %u is invalid (loopstart: %u, totloop: %u)\n", sp->index, mp->loopstart, mp->totloop); sp->invalid = TRUE; } else if (mp->loopstart + mp->totloop > totloop) { /* Invalid loop data. */ PRINT_ERR("\tPoly %u uses loops out of range (loopstart: %u, loopend: %u, max nbr of loops: %u)\n", sp->index, mp->loopstart, mp->loopstart + mp->totloop - 1, totloop - 1); sp->invalid = TRUE; } else { /* Poly itself is valid, for now. */ int v1, v2; /* v1 is prev loop vert idx, v2 is current loop one. */ sp->invalid = FALSE; sp->verts = v = MEM_mallocN(sizeof(int) * mp->totloop, "Vert idx of SortPoly"); sp->numverts = mp->totloop; sp->loopstart = mp->loopstart; /* Test all poly's loops' vert idx. */ for (j = 0, ml = &mloops[sp->loopstart]; j < mp->totloop; j++, ml++, v++) { if (ml->v >= totvert) { /* Invalid vert idx. */ PRINT_ERR("\tLoop %u has invalid vert reference (%u)\n", sp->loopstart + j, ml->v); sp->invalid = TRUE; } mverts[ml->v].flag |= ME_VERT_TMP_TAG; *v = ml->v; } /* is the same vertex used more than once */ if (!sp->invalid) { v = sp->verts; for (j = 0; j < mp->totloop; j++, v++) { if ((mverts[*v].flag & ME_VERT_TMP_TAG) == 0) { PRINT_ERR("\tPoly %u has duplicate vert reference at corner (%u)\n", i, j); sp->invalid = TRUE; } mverts[*v].flag &= ~ME_VERT_TMP_TAG; } } if (sp->invalid) continue; /* Test all poly's loops. */ for (j = 0, ml = &mloops[sp->loopstart]; j < mp->totloop; j++, ml++) { v1 = ml->v; v2 = mloops[sp->loopstart + (j + 1) % mp->totloop].v; if (!BLI_edgehash_haskey(edge_hash, v1, v2)) { /* Edge not existing. */ PRINT_ERR("\tPoly %u needs missing edge (%u, %u)\n", sp->index, v1, v2); if (do_fixes) do_edge_recalc = TRUE; else sp->invalid = TRUE; } else if (ml->e >= totedge) { /* Invalid edge idx. * We already know from previous text that a valid edge exists, use it (if allowed)! */ if (do_fixes) { int prev_e = ml->e; ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, v1, v2)); PRINT_ERR("\tLoop %u has invalid edge reference (%u), fixed using edge %u\n", sp->loopstart + j, prev_e, ml->e); } else { PRINT_ERR("\tLoop %u has invalid edge reference (%u)\n", sp->loopstart + j, ml->e); sp->invalid = TRUE; } } else { me = &medges[ml->e]; if (IS_REMOVED_EDGE(me) || !((me->v1 == v1 && me->v2 == v2) || (me->v1 == v2 && me->v2 == v1))) { /* The pointed edge is invalid (tagged as removed, or vert idx mismatch), * and we already know from previous test that a valid one exists, use it (if allowed)! */ if (do_fixes) { int prev_e = ml->e; ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, v1, v2)); PRINT_ERR("\tPoly %u has invalid edge reference (%u), fixed using edge %u\n", sp->index, prev_e, ml->e); } else { PRINT_ERR("\tPoly %u has invalid edge reference (%u)\n", sp->index, ml->e); sp->invalid = TRUE; } } } } /* Now check that that poly does not use a same vertex more than once! */ if (!sp->invalid) { int *prev_v = v = sp->verts; j = sp->numverts; qsort(sp->verts, j, sizeof(int), int_cmp); for (j--, v++; j; j--, v++) { if (*v != *prev_v) { int dlt = v - prev_v; if (dlt > 1) { PRINT_ERR("\tPoly %u is invalid, it multi-uses vertex %u (%u times)\n", sp->index, *prev_v, dlt); sp->invalid = TRUE; } prev_v = v; } } if (v - prev_v > 1) { /* Don't forget final verts! */ PRINT_ERR("\tPoly %u is invalid, it multi-uses vertex %u (%u times)\n", sp->index, *prev_v, (int)(v - prev_v)); sp->invalid = TRUE; } } } } /* Second check pass, testing polys using the same verts. */ qsort(sort_polys, totpoly, sizeof(SortPoly), search_poly_cmp); sp = prev_sp = sort_polys; sp++; for (i = 1; i < totpoly; i++, sp++) { int p1_nv = sp->numverts, p2_nv = prev_sp->numverts; int *p1_v = sp->verts, *p2_v = prev_sp->verts; short p1_sub = TRUE, p2_sub = TRUE; if (sp->invalid) break; /* Test same polys. */ #if 0 /* NOTE: This performs a sub-set test. */ /* XXX This (and the sort of verts list) is better than systematic * search of all verts of one list into the other if lists have * a fair amount of elements. * Not sure however it's worth it in this case? * But as we also need sorted vert list to check verts multi-used * (in first pass of checks)... */ /* XXX If we consider only "equal" polys (i.e. using exactly same set of verts) * as invalid, better to replace this by a simple memory cmp... */ while ((p1_nv && p2_nv) && (p1_sub || p2_sub)) { if (*p1_v < *p2_v) { if (p1_sub) p1_sub = FALSE; p1_nv--; p1_v++; } else if (*p2_v < *p1_v) { if (p2_sub) p2_sub = FALSE; p2_nv--; p2_v++; } else { /* Equality, both next verts. */ p1_nv--; p2_nv--; p1_v++; p2_v++; } } if (p1_nv && p1_sub) p1_sub = FALSE; else if (p2_nv && p2_sub) p2_sub = FALSE; if (p1_sub && p2_sub) { PRINT("\tPolys %u and %u use same vertices, considering poly %u as invalid.\n", prev_sp->index, sp->index, sp->index); sp->invalid = TRUE; } /* XXX In fact, these might be valid? :/ */ else if (p1_sub) { PRINT("\t%u is a sub-poly of %u, considering it as invalid.\n", sp->index, prev_sp->index); sp->invalid = TRUE; } else if (p2_sub) { PRINT("\t%u is a sub-poly of %u, considering it as invalid.\n", prev_sp->index, sp->index); prev_sp->invalid = TRUE; prev_sp = sp; /* sp is new reference poly. */ } #else if (0) { p1_sub += 0; p2_sub += 0; } if ((p1_nv == p2_nv) && (memcmp(p1_v, p2_v, p1_nv * sizeof(*p1_v)) == 0)) { if (do_verbose) { PRINT_ERR("\tPolys %u and %u use same vertices (%u", prev_sp->index, sp->index, *p1_v); for (j = 1; j < p1_nv; j++) PRINT_ERR(", %u", p1_v[j]); PRINT_ERR("), considering poly %u as invalid.\n", sp->index); } else { is_valid = false; } sp->invalid = TRUE; } #endif else { prev_sp = sp; } } /* Third check pass, testing loops used by none or more than one poly. */ qsort(sort_polys, totpoly, sizeof(SortPoly), search_polyloop_cmp); sp = sort_polys; prev_sp = NULL; prev_end = 0; for (i = 0; i < totpoly; i++, sp++) { /* Free this now, we don't need it anymore, and avoid us another loop! */ if (sp->verts) MEM_freeN(sp->verts); /* Note above prev_sp: in following code, we make sure it is always valid poly (or NULL). */ if (sp->invalid) { if (do_fixes) { REMOVE_POLY_TAG((&mpolys[sp->index])); /* DO NOT REMOVE ITS LOOPS!!! * As already invalid polys are at the end of the SortPoly list, the loops they * were the only users have already been tagged as "to remove" during previous * iterations, and we don't want to remove some loops that may be used by * another valid poly! */ } } /* Test loops users. */ else { /* Unused loops. */ if (prev_end < sp->loopstart) { for (j = prev_end, ml = &mloops[prev_end]; j < sp->loopstart; j++, ml++) { PRINT_ERR("\tLoop %u is unused.\n", j); if (do_fixes) REMOVE_LOOP_TAG(ml); } prev_end = sp->loopstart + sp->numverts; prev_sp = sp; } /* Multi-used loops. */ else if (prev_end > sp->loopstart) { PRINT_ERR("\tPolys %u and %u share loops from %u to %u, considering poly %u as invalid.\n", prev_sp->index, sp->index, sp->loopstart, prev_end, sp->index); if (do_fixes) { REMOVE_POLY_TAG((&mpolys[sp->index])); /* DO NOT REMOVE ITS LOOPS!!! * They might be used by some next, valid poly! * Just not updating prev_end/prev_sp vars is enough to ensure the loops * effectively no more needed will be marked as "to be removed"! */ } } else { prev_end = sp->loopstart + sp->numverts; prev_sp = sp; } } } /* We may have some remaining unused loops to get rid of! */ if (prev_end < totloop) { for (j = prev_end, ml = &mloops[prev_end]; j < totloop; j++, ml++) { PRINT_ERR("\tLoop %u is unused.\n", j); if (do_fixes) REMOVE_LOOP_TAG(ml); } } MEM_freeN(sort_polys); } BLI_edgehash_free(edge_hash, NULL); /* fix deform verts */ if (dverts) { MDeformVert *dv; for (i = 0, dv = dverts; i < totvert; i++, dv++) { MDeformWeight *dw; for (j = 0, dw = dv->dw; j < dv->totweight; j++, dw++) { /* note, greater then max defgroups is accounted for in our code, but not < 0 */ if (!finite(dw->weight)) { PRINT_ERR("\tVertex deform %u, group %d has weight: %f\n", i, dw->def_nr, dw->weight); if (do_fixes) { dw->weight = 0.0f; vert_weights_fixed = TRUE; } } else if (dw->weight < 0.0f || dw->weight > 1.0f) { PRINT_ERR("\tVertex deform %u, group %d has weight: %f\n", i, dw->def_nr, dw->weight); if (do_fixes) { CLAMP(dw->weight, 0.0f, 1.0f); vert_weights_fixed = TRUE; } } if (dw->def_nr < 0) { PRINT_ERR("\tVertex deform %u, has invalid group %d\n", i, dw->def_nr); if (do_fixes) { defvert_remove_group(dv, dw); if (dv->dw) { /* re-allocated, the new values compensate for stepping * within the for loop and may not be valid */ j--; dw = dv->dw + j; vert_weights_fixed = TRUE; } else { /* all freed */ break; } } } } } } # undef REMOVE_EDGE_TAG # undef IS_REMOVED_EDGE # undef REMOVE_LOOP_TAG # undef REMOVE_POLY_TAG if (mesh) { if (do_face_free) { BKE_mesh_strip_loose_faces(mesh); } if (do_polyloop_free) { BKE_mesh_strip_loose_polysloops(mesh); } if (do_edge_free) { BKE_mesh_strip_loose_edges(mesh); } if (do_edge_recalc) { BKE_mesh_calc_edges(mesh, true, false); } } if (mesh && mesh->mselect) { MSelect *msel; int free_msel = FALSE; for (i = 0, msel = mesh->mselect; i < mesh->totselect; i++, msel++) { int tot_elem = 0; if (msel->index < 0) { PRINT_ERR("\tMesh select element %d type %d index is negative, " "resetting selection stack.\n", i, msel->type); free_msel = TRUE; break; } switch (msel->type) { case ME_VSEL: tot_elem = mesh->totvert; break; case ME_ESEL: tot_elem = mesh->totedge; break; case ME_FSEL: tot_elem = mesh->totface; break; } if (msel->index > tot_elem) { PRINT_ERR("\tMesh select element %d type %d index %d is larger than data array size %d, " "resetting selection stack.\n", i, msel->type, msel->index, tot_elem); free_msel = TRUE; break; } } if (free_msel) { MEM_freeN(mesh->mselect); mesh->mselect = NULL; mesh->totselect = 0; } } PRINT_MSG("%s: finished\n\n", __func__); *r_change = (verts_fixed || vert_weights_fixed || do_polyloop_free || do_edge_free || do_edge_recalc || msel_fixed); return is_valid; }
/* Selects all visible keyframes in the same frames as the specified elements */ static void columnselect_graph_keys(bAnimContext *ac, short mode) { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; int filter; Scene *scene = ac->scene; CfraElem *ce; KeyframeEditFunc select_cb, ok_cb; KeyframeEditData ked; /* initialize keyframe editing data */ memset(&ked, 0, sizeof(KeyframeEditData)); /* build list of columns */ switch (mode) { case GRAPHKEYS_COLUMNSEL_KEYS: /* list of selected keys */ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS); ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); for (ale = anim_data.first; ale; ale = ale->next) ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_to_cfraelem, NULL); ANIM_animdata_freelist(&anim_data); break; case GRAPHKEYS_COLUMNSEL_CFRA: /* current frame */ /* make a single CfraElem for storing this */ ce = MEM_callocN(sizeof(CfraElem), "cfraElem"); BLI_addtail(&ked.list, ce); ce->cfra = (float)CFRA; break; case GRAPHKEYS_COLUMNSEL_MARKERS_COLUMN: /* list of selected markers */ ED_markers_make_cfra_list(ac->markers, &ked.list, SELECT); break; default: /* invalid option */ return; } /* set up BezTriple edit callbacks */ select_cb = ANIM_editkeyframes_select(SELECT_ADD); ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAME); /* loop through all of the keys and select additional keyframes * based on the keys found to be selected above */ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS); ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); for (ale = anim_data.first; ale; ale = ale->next) { AnimData *adt = ANIM_nla_mapping_get(ac, ale); /* loop over cfraelems (stored in the KeyframeEditData->list) * - we need to do this here, as we can apply fewer NLA-mapping conversions */ for (ce = ked.list.first; ce; ce = ce->next) { /* set frame for validation callback to refer to */ ked.f1 = BKE_nla_tweakedit_remap(adt, ce->cfra, NLATIME_CONVERT_UNMAP); /* select elements with frame number matching cfraelem */ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); } } /* free elements */ BLI_freelistN(&ked.list); ANIM_animdata_freelist(&anim_data); }
/* Setup motion paths for the given data * - Only used when explicitly calculating paths on bones which may/may not be consider already * * < scene: current scene (for frame ranges, etc.) * < ob: object to add paths for (must be provided) * < pchan: posechannel to add paths for (optional; if not provided, object-paths are assumed) */ bMotionPath *animviz_verify_motionpaths(ReportList *reports, Scene *scene, Object *ob, bPoseChannel *pchan) { bAnimVizSettings *avs; bMotionPath *mpath, **dst; /* sanity checks */ if (ELEM(NULL, scene, ob)) return NULL; /* get destination data */ if (pchan) { /* paths for posechannel - assume that posechannel belongs to the object */ avs = &ob->pose->avs; dst = &pchan->mpath; } else { /* paths for object */ avs = &ob->avs; dst = &ob->mpath; } /* avoid 0 size allocs */ if (avs->path_sf >= avs->path_ef) { BKE_reportf(reports, RPT_ERROR, "Motion Path frame extents invalid for %s (%d to %d).%s\n", (pchan) ? pchan->name : ob->id.name, avs->path_sf, avs->path_ef, (avs->path_sf == avs->path_ef) ? " Cannot have single-frame paths." : ""); return NULL; } /* if there is already a motionpath, just return that, * provided it's settings are ok (saves extra free+alloc) */ if (*dst != NULL) { int expected_length = avs->path_ef - avs->path_sf; mpath = *dst; /* path is "valid" if length is valid, but must also be of the same length as is being requested */ if ((mpath->start_frame != mpath->end_frame) && (mpath->length > 0)) { /* outer check ensures that we have some curve data for this path */ if (mpath->length == expected_length) { /* return/use this as it is already valid length */ return mpath; } else { /* clear the existing path (as the range has changed), and reallocate below */ animviz_free_motionpath_cache(mpath); } } } else { /* create a new motionpath, and assign it */ mpath = MEM_callocN(sizeof(bMotionPath), "bMotionPath"); *dst = mpath; } /* set settings from the viz settings */ mpath->start_frame = avs->path_sf; mpath->end_frame = avs->path_ef; mpath->length = mpath->end_frame - mpath->start_frame; if (avs->path_bakeflag & MOTIONPATH_BAKE_HEADS) mpath->flag |= MOTIONPATH_FLAG_BHEAD; else mpath->flag &= ~MOTIONPATH_FLAG_BHEAD; /* allocate a cache */ mpath->points = MEM_callocN(sizeof(bMotionPathVert) * mpath->length, "bMotionPathVerts"); /* tag viz settings as currently having some path(s) which use it */ avs->path_bakeflag |= MOTIONPATH_BAKE_HAS_PATHS; /* return it */ return mpath; }
/* name can be a dynamic string */ void BKE_write_undo(bContext *C, const char *name) { uintptr_t maxmem, totmem, memused; int nr, success; UndoElem *uel; if( (U.uiflag & USER_GLOBALUNDO)==0) return; if( U.undosteps==0) return; /* remove all undos after (also when curundo==NULL) */ while(undobase.last != curundo) { uel= undobase.last; BLI_remlink(&undobase, uel); BLO_free_memfile(&uel->memfile); MEM_freeN(uel); } /* make new */ curundo= uel= MEM_callocN(sizeof(UndoElem), "undo file"); strncpy(uel->name, name, MAXUNDONAME-1); BLI_addtail(&undobase, uel); /* and limit amount to the maximum */ nr= 0; uel= undobase.last; while(uel) { nr++; if(nr==U.undosteps) break; uel= uel->prev; } if(uel) { while(undobase.first!=uel) { UndoElem *first= undobase.first; BLI_remlink(&undobase, first); /* the merge is because of compression */ BLO_merge_memfile(&first->memfile, &first->next->memfile); MEM_freeN(first); } } /* disk save version */ if(UNDO_DISK) { static int counter= 0; char filepath[FILE_MAXDIR+FILE_MAXFILE]; char numstr[32]; int fileflags = G.fileflags & ~(G_FILE_HISTORY); /* don't do file history on undo */ /* calculate current filepath */ counter++; counter= counter % U.undosteps; BLI_snprintf(numstr, sizeof(numstr), "%d.blend", counter); BLI_make_file_string("/", filepath, btempdir, numstr); success= BLO_write_file(CTX_data_main(C), filepath, fileflags, NULL, NULL); BLI_strncpy(curundo->str, filepath, sizeof(curundo->str)); } else { MemFile *prevfile=NULL; if(curundo->prev) prevfile= &(curundo->prev->memfile); memused= MEM_get_memory_in_use(); success= BLO_write_file_mem(CTX_data_main(C), prevfile, &curundo->memfile, G.fileflags); curundo->undosize= MEM_get_memory_in_use() - memused; } if(U.undomemory != 0) { /* limit to maximum memory (afterwards, we can't know in advance) */ totmem= 0; maxmem= ((uintptr_t)U.undomemory)*1024*1024; /* keep at least two (original + other) */ uel= undobase.last; while(uel && uel->prev) { totmem+= uel->undosize; if(totmem>maxmem) break; uel= uel->prev; } if(uel) { if(uel->prev && uel->prev->prev) uel= uel->prev; while(undobase.first!=uel) { UndoElem *first= undobase.first; BLI_remlink(&undobase, first); /* the merge is because of compression */ BLO_merge_memfile(&first->memfile, &first->next->memfile); MEM_freeN(first); } } } }
BMBVHTree *BKE_bmbvh_new(BMEditMesh *em, int flag, const float (*cos_cage)[3], const bool cos_cage_free) { /* could become argument */ const float epsilon = FLT_EPSILON * 2.0f; struct BMLoop *(*looptris)[3] = em->looptris; BMBVHTree *bmtree = MEM_callocN(sizeof(*bmtree), "BMBVHTree"); float cos[3][3]; int i; int tottri; /* BKE_editmesh_tessface_calc() must be called already */ BLI_assert(em->tottri != 0 || em->bm->totface == 0); if (cos_cage) { BM_mesh_elem_index_ensure(em->bm, BM_VERT); } bmtree->em = em; bmtree->bm = em->bm; bmtree->cos_cage = cos_cage; bmtree->cos_cage_free = cos_cage_free; bmtree->flag = flag; if (flag & (BMBVH_RESPECT_SELECT)) { tottri = 0; for (i = 0; i < em->tottri; i++) { if (BM_elem_flag_test(looptris[i][0]->f, BM_ELEM_SELECT)) { tottri++; } } } else if (flag & (BMBVH_RESPECT_HIDDEN)) { tottri = 0; for (i = 0; i < em->tottri; i++) { if (!BM_elem_flag_test(looptris[i][0]->f, BM_ELEM_HIDDEN)) { tottri++; } } } else { tottri = em->tottri; } bmtree->tree = BLI_bvhtree_new(tottri, epsilon, 8, 8); for (i = 0; i < em->tottri; i++) { if (flag & BMBVH_RESPECT_SELECT) { /* note, the arrays wont align now! take care */ if (!BM_elem_flag_test(em->looptris[i][0]->f, BM_ELEM_SELECT)) { continue; } } else if (flag & BMBVH_RESPECT_HIDDEN) { /* note, the arrays wont align now! take care */ if (BM_elem_flag_test(looptris[i][0]->f, BM_ELEM_HIDDEN)) { continue; } } if (cos_cage) { copy_v3_v3(cos[0], cos_cage[BM_elem_index_get(looptris[i][0]->v)]); copy_v3_v3(cos[1], cos_cage[BM_elem_index_get(looptris[i][1]->v)]); copy_v3_v3(cos[2], cos_cage[BM_elem_index_get(looptris[i][2]->v)]); } else { copy_v3_v3(cos[0], looptris[i][0]->v->co); copy_v3_v3(cos[1], looptris[i][1]->v->co); copy_v3_v3(cos[2], looptris[i][2]->v->co); } BLI_bvhtree_insert(bmtree->tree, i, (float *)cos, 3); } BLI_bvhtree_balance(bmtree->tree); return bmtree; }
/* reading without uifont will create one */ void uiStyleInit(void) { uiFont *font; uiStyle *style = U.uistyles.first; int monofont_size = datatoc_bmonofont_ttf_size; uchar *monofont_ttf = (uchar *)datatoc_bmonofont_ttf; /* recover from uninitialized dpi */ if (U.dpi == 0) { U.dpi = 72; } CLAMP(U.dpi, 48, 144); for (font = U.uifonts.first; font; font = font->next) { BLF_unload_id(font->blf_id); } if (blf_mono_font != -1) { BLF_unload_id(blf_mono_font); blf_mono_font = -1; } if (blf_mono_font_render != -1) { BLF_unload_id(blf_mono_font_render); blf_mono_font_render = -1; } font = U.uifonts.first; /* default builtin */ if (font == NULL) { font = MEM_callocN(sizeof(uiFont), "ui font"); BLI_addtail(&U.uifonts, font); } if (U.font_path_ui[0]) { BLI_strncpy(font->filename, U.font_path_ui, sizeof(font->filename)); font->uifont_id = UIFONT_CUSTOM1; } else { BLI_strncpy(font->filename, "default", sizeof(font->filename)); font->uifont_id = UIFONT_DEFAULT; } for (font = U.uifonts.first; font; font = font->next) { if (font->uifont_id == UIFONT_DEFAULT) { #ifdef WITH_INTERNATIONAL int font_size = datatoc_bfont_ttf_size; uchar *font_ttf = (uchar *)datatoc_bfont_ttf; static int last_font_size = 0; /* use unicode font for translation */ if (U.transopts & USER_DOTRANSLATE) { font_ttf = BLF_get_unifont(&font_size); if (!font_ttf) { /* fall back if not found */ font_size = datatoc_bfont_ttf_size; font_ttf = (uchar *)datatoc_bfont_ttf; } } /* relload only if needed */ if (last_font_size != font_size) { BLF_unload("default"); last_font_size = font_size; } font->blf_id = BLF_load_mem("default", font_ttf, font_size); #else font->blf_id = BLF_load_mem("default", (uchar *)datatoc_bfont_ttf, datatoc_bfont_ttf_size); #endif } else { font->blf_id = BLF_load(font->filename); if (font->blf_id == -1) { font->blf_id = BLF_load_mem("default", (uchar *)datatoc_bfont_ttf, datatoc_bfont_ttf_size); } } BLF_default_set(font->blf_id); if (font->blf_id == -1) { if (G.debug & G_DEBUG) { printf("%s: error, no fonts available\n", __func__); } } else { /* ? just for speed to initialize? * Yes, this build the glyph cache and create * the texture. */ BLF_size(font->blf_id, 11 * U.pixelsize, U.dpi); BLF_size(font->blf_id, 12 * U.pixelsize, U.dpi); BLF_size(font->blf_id, 14 * U.pixelsize, U.dpi); } } if (style == NULL) { ui_style_new(&U.uistyles, "Default Style", UIFONT_DEFAULT); } #ifdef WITH_INTERNATIONAL /* use unicode font for text editor and interactive console */ if (U.transopts & USER_DOTRANSLATE) { monofont_ttf = BLF_get_unifont_mono(&monofont_size); if (!monofont_ttf) { /* fall back if not found */ monofont_size = datatoc_bmonofont_ttf_size; monofont_ttf = (uchar *)datatoc_bmonofont_ttf; } } #endif /* XXX, this should be moved into a style, * but for now best only load the monospaced font once. */ BLI_assert(blf_mono_font == -1); if (U.font_path_ui_mono[0]) { blf_mono_font = BLF_load_unique(U.font_path_ui_mono); } if (blf_mono_font == -1) { blf_mono_font = BLF_load_mem_unique("monospace", monofont_ttf, monofont_size); } BLF_size(blf_mono_font, 12 * U.pixelsize, 72); /* Set default flags based on UI preferences (not render fonts) */ { int flag_disable = (BLF_MONOCHROME | BLF_HINTING_NONE | BLF_HINTING_SLIGHT | BLF_HINTING_FULL); int flag_enable = 0; if (U.text_render & USER_TEXT_HINTING_NONE) { flag_enable |= BLF_HINTING_NONE; } else if (U.text_render & USER_TEXT_HINTING_SLIGHT) { flag_enable |= BLF_HINTING_SLIGHT; } else if (U.text_render & USER_TEXT_HINTING_FULL) { flag_enable |= BLF_HINTING_FULL; } if (U.text_render & USER_TEXT_DISABLE_AA) { flag_enable |= BLF_MONOCHROME; } for (font = U.uifonts.first; font; font = font->next) { if (font->blf_id != -1) { BLF_disable(font->blf_id, flag_disable); BLF_enable(font->blf_id, flag_enable); } } if (blf_mono_font != -1) { BLF_disable(blf_mono_font, flag_disable); BLF_enable(blf_mono_font, flag_enable); } } /** * Second for rendering else we get threading problems, * * \note This isn't good that the render font depends on the preferences, * keep for now though, since without this there is no way to display many unicode chars. */ if (blf_mono_font_render == -1) { blf_mono_font_render = BLF_load_mem_unique("monospace", monofont_ttf, monofont_size); } BLF_size(blf_mono_font_render, 12 * U.pixelsize, 72); }
void curvemap_reset(CurveMap *cuma, rctf *clipr, int preset, int slope) { if(cuma->curve) MEM_freeN(cuma->curve); switch(preset) { case CURVE_PRESET_LINE: cuma->totpoint= 2; break; case CURVE_PRESET_SHARP: cuma->totpoint= 4; break; case CURVE_PRESET_SMOOTH: cuma->totpoint= 4; break; case CURVE_PRESET_MAX: cuma->totpoint= 2; break; case CURVE_PRESET_MID9: cuma->totpoint= 9; break; case CURVE_PRESET_ROUND: cuma->totpoint= 4; break; case CURVE_PRESET_ROOT: cuma->totpoint= 4; break; } cuma->curve= MEM_callocN(cuma->totpoint*sizeof(CurveMapPoint), "curve points"); switch(preset) { case CURVE_PRESET_LINE: cuma->curve[0].x= clipr->xmin; cuma->curve[0].y= clipr->ymax; cuma->curve[0].flag= 0; cuma->curve[1].x= clipr->xmax; cuma->curve[1].y= clipr->ymin; cuma->curve[1].flag= 0; break; case CURVE_PRESET_SHARP: cuma->curve[0].x= 0; cuma->curve[0].y= 1; cuma->curve[1].x= 0.25; cuma->curve[1].y= 0.50; cuma->curve[2].x= 0.75; cuma->curve[2].y= 0.04; cuma->curve[3].x= 1; cuma->curve[3].y= 0; break; case CURVE_PRESET_SMOOTH: cuma->curve[0].x= 0; cuma->curve[0].y= 1; cuma->curve[1].x= 0.25; cuma->curve[1].y= 0.94; cuma->curve[2].x= 0.75; cuma->curve[2].y= 0.06; cuma->curve[3].x= 1; cuma->curve[3].y= 0; break; case CURVE_PRESET_MAX: cuma->curve[0].x= 0; cuma->curve[0].y= 1; cuma->curve[1].x= 1; cuma->curve[1].y= 1; break; case CURVE_PRESET_MID9: { int i; for (i=0; i < cuma->totpoint; i++) { cuma->curve[i].x= i / ((float)cuma->totpoint-1); cuma->curve[i].y= 0.5; } } break; case CURVE_PRESET_ROUND: cuma->curve[0].x= 0; cuma->curve[0].y= 1; cuma->curve[1].x= 0.5; cuma->curve[1].y= 0.90; cuma->curve[2].x= 0.86; cuma->curve[2].y= 0.5; cuma->curve[3].x= 1; cuma->curve[3].y= 0; break; case CURVE_PRESET_ROOT: cuma->curve[0].x= 0; cuma->curve[0].y= 1; cuma->curve[1].x= 0.25; cuma->curve[1].y= 0.95; cuma->curve[2].x= 0.75; cuma->curve[2].y= 0.44; cuma->curve[3].x= 1; cuma->curve[3].y= 0; break; } /* mirror curve in x direction to have positive slope * rather than default negative slope */ if (slope == CURVEMAP_SLOPE_POSITIVE) { int i, last=cuma->totpoint-1; CurveMapPoint *newpoints= MEM_dupallocN(cuma->curve); for (i=0; i<cuma->totpoint; i++) { newpoints[i].y = cuma->curve[last-i].y; } MEM_freeN(cuma->curve); cuma->curve = newpoints; } if(cuma->table) { MEM_freeN(cuma->table); cuma->table= NULL; } }
int WM_init_game(bContext *C) { wmWindowManager *wm= CTX_wm_manager(C); wmWindow* win; ScrArea *sa; ARegion *ar= NULL; Scene *scene= CTX_data_scene(C); if (!scene) { // XXX, this should not be needed. Main *bmain = CTX_data_main(C); scene= bmain->scene.first; } win = wm->windows.first; //first to get a valid window if(win) CTX_wm_window_set(C, win); sa = biggest_view3d(C); ar= BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); // if we have a valid 3D view if (sa && ar) { ARegion *arhide; CTX_wm_area_set(C, sa); CTX_wm_region_set(C, ar); /* disable quad view */ if(ar->alignment == RGN_ALIGN_QSPLIT) WM_operator_name_call(C, "SCREEN_OT_region_quadview", WM_OP_EXEC_DEFAULT, NULL); /* toolbox, properties panel and header are hidden */ for(arhide=sa->regionbase.first; arhide; arhide=arhide->next) { if(arhide->regiontype != RGN_TYPE_WINDOW) { if(!(arhide->flag & RGN_FLAG_HIDDEN)) { ED_region_toggle_hidden(C, arhide); } } } /* full screen the area */ if(!sa->full) { ED_screen_full_toggle(C, win, sa); } /* Fullscreen */ if(scene->gm.fullscreen) { WM_operator_name_call(C, "WM_OT_window_fullscreen_toggle", WM_OP_EXEC_DEFAULT, NULL); wm_get_screensize(&ar->winrct.xmax, &ar->winrct.ymax); ar->winx = ar->winrct.xmax + 1; ar->winy = ar->winrct.ymax + 1; } else { GHOST_RectangleHandle rect = GHOST_GetClientBounds(win->ghostwin); ar->winrct.ymax = GHOST_GetHeightRectangle(rect); ar->winrct.xmax = GHOST_GetWidthRectangle(rect); ar->winx = ar->winrct.xmax + 1; ar->winy = ar->winrct.ymax + 1; GHOST_DisposeRectangle(rect); } WM_operator_name_call(C, "VIEW3D_OT_game_start", WM_OP_EXEC_DEFAULT, NULL); return 1; } else { ReportTimerInfo *rti; BKE_report(&wm->reports, RPT_ERROR, "No valid 3D View found. Game auto start is not possible."); /* After adding the report to the global list, reset the report timer. */ WM_event_remove_timer(wm, NULL, wm->reports.reporttimer); /* Records time since last report was added */ wm->reports.reporttimer = WM_event_add_timer(wm, CTX_wm_window(C), TIMER, 0.02); rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo"); wm->reports.reporttimer->customdata = rti; } return 0; }
void scopes_update(Scopes *scopes, ImBuf *ibuf, int use_color_management) { int x, y, c; unsigned int n, nl; double div, divl; float *rf=NULL; unsigned char *rc=NULL; unsigned int *bin_r, *bin_g, *bin_b, *bin_lum; int savedlines, saveline; float rgb[3], ycc[3], luma; int ycc_mode=-1; const short is_float = (ibuf->rect_float != 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; } /* temp table to count pix value for histo */ bin_r = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins"); bin_g = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins"); bin_b = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins"); bin_lum = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins"); /* convert to number of lines with logarithmic scale */ scopes->sample_lines = (scopes->accuracy*0.01f) * (scopes->accuracy*0.01f) * ibuf->y; if (scopes->sample_full) scopes->sample_lines = ibuf->y; /* scan the image */ savedlines=0; for (c=0; c<3; c++) { scopes->minmax[c][0]=25500.0f; scopes->minmax[c][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 (is_float) rf = ibuf->rect_float; else rc = (unsigned char *)ibuf->rect; for (y = 0; y < ibuf->y; y++) { if (savedlines<scopes->sample_lines && y>=((savedlines)*ibuf->y)/(scopes->sample_lines+1)) { saveline=1; } else saveline=0; for (x = 0; x < ibuf->x; x++) { if (is_float) { if (use_color_management) linearrgb_to_srgb_v3_v3(rgb, rf); else copy_v3_v3(rgb, rf); } else { for (c=0; c<3; c++) rgb[c] = rc[c] * INV_255; } /* we still need luma for histogram */ luma = 0.299f * rgb[0] + 0.587f * rgb[1] + 0.114f * rgb[2]; /* check for min max */ if(ycc_mode == -1 ) { for (c=0; c<3; c++) { if (rgb[c] < scopes->minmax[c][0]) scopes->minmax[c][0] = rgb[c]; if (rgb[c] > scopes->minmax[c][1]) scopes->minmax[c][1] = rgb[c]; } } else { rgb_to_ycc(rgb[0],rgb[1],rgb[2],&ycc[0],&ycc[1],&ycc[2], ycc_mode); for (c=0; c<3; c++) { ycc[c] *=INV_255; if (ycc[c] < scopes->minmax[c][0]) scopes->minmax[c][0] = ycc[c]; if (ycc[c] > scopes->minmax[c][1]) scopes->minmax[c][1] = ycc[c]; } } /* increment count for histo*/ bin_r[ get_bin_float(rgb[0]) ] += 1; bin_g[ get_bin_float(rgb[1]) ] += 1; bin_b[ get_bin_float(rgb[2]) ] += 1; bin_lum[ get_bin_float(luma) ] += 1; /* save sample if needed */ if(saveline) { const float fx = (float)x / (float)ibuf->x; const int idx = 2*(ibuf->x*savedlines+x); save_sample_line(scopes, idx, fx, rgb, ycc); } rf+= ibuf->channels; rc+= ibuf->channels; } if (saveline) savedlines +=1; } /* convert hist data to float (proportional to max count) */ n=0; nl=0; for (x=0; x<256; x++) { if (bin_r[x] > n) n = bin_r[x]; if (bin_g[x] > n) n = bin_g[x]; if (bin_b[x] > n) n = bin_b[x]; if (bin_lum[x] > nl) nl = bin_lum[x]; } div = 1.0/(double)n; divl = 1.0/(double)nl; for (x=0; x<256; x++) { scopes->hist.data_r[x] = bin_r[x] * div; scopes->hist.data_g[x] = bin_g[x] * div; scopes->hist.data_b[x] = bin_b[x] * div; scopes->hist.data_luma[x] = bin_lum[x] * divl; } MEM_freeN(bin_r); MEM_freeN(bin_g); MEM_freeN(bin_b); MEM_freeN(bin_lum); scopes->ok = 1; }
/* Simple Weighted Smoothing * * (average of surrounding verts) */ static void smooth_iter__simple( CorrectiveSmoothModifierData *csmd, DerivedMesh *dm, float (*vertexCos)[3], unsigned int numVerts, const float *smooth_weights, unsigned int iterations) { const float lambda = csmd->lambda; unsigned int i; const unsigned int numEdges = (unsigned int)dm->getNumEdges(dm); const MEdge *edges = dm->getEdgeArray(dm); float *vertex_edge_count_div; struct SmoothingData_Simple { float delta[3]; } *smooth_data = MEM_callocN((size_t)numVerts * sizeof(*smooth_data), __func__); vertex_edge_count_div = MEM_callocN((size_t)numVerts * sizeof(float), __func__); /* calculate as floats to avoid int->float conversion in #smooth_iter */ for (i = 0; i < numEdges; i++) { vertex_edge_count_div[edges[i].v1] += 1.0f; vertex_edge_count_div[edges[i].v2] += 1.0f; } /* a little confusing, but we can include 'lambda' and smoothing weight * here to avoid multiplying for every iteration */ if (smooth_weights == NULL) { for (i = 0; i < numVerts; i++) { vertex_edge_count_div[i] = lambda * (vertex_edge_count_div[i] ? (1.0f / vertex_edge_count_div[i]) : 1.0f); } } else { for (i = 0; i < numVerts; i++) { vertex_edge_count_div[i] = smooth_weights[i] * lambda * (vertex_edge_count_div[i] ? (1.0f / vertex_edge_count_div[i]) : 1.0f); } } /* -------------------------------------------------------------------- */ /* Main Smoothing Loop */ while (iterations--) { for (i = 0; i < numEdges; i++) { struct SmoothingData_Simple *sd_v1; struct SmoothingData_Simple *sd_v2; float edge_dir[3]; sub_v3_v3v3(edge_dir, vertexCos[edges[i].v2], vertexCos[edges[i].v1]); sd_v1 = &smooth_data[edges[i].v1]; sd_v2 = &smooth_data[edges[i].v2]; add_v3_v3(sd_v1->delta, edge_dir); sub_v3_v3(sd_v2->delta, edge_dir); } for (i = 0; i < numVerts; i++) { struct SmoothingData_Simple *sd = &smooth_data[i]; madd_v3_v3fl(vertexCos[i], sd->delta, vertex_edge_count_div[i]); /* zero for the next iteration (saves memset on entire array) */ memset(sd, 0, sizeof(*sd)); } } MEM_freeN(vertex_edge_count_div); MEM_freeN(smooth_data); }
static void fcm_generator_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime) { FMod_Generator *data= (FMod_Generator *)fcm->data; /* behavior depends on mode * NOTE: the data in its default state is fine too */ switch (data->mode) { case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */ { /* we overwrite cvalue with the sum of the polynomial */ float *powers = MEM_callocN(sizeof(float)*data->arraysize, "Poly Powers"); float value= 0.0f; unsigned int i; /* for each x^n, precalculate value based on previous one first... this should be * faster that calling pow() for each entry */ for (i=0; i < data->arraysize; i++) { /* first entry is x^0 = 1, otherwise, calculate based on previous */ if (i) powers[i]= powers[i-1] * evaltime; else powers[0]= 1; } /* for each coefficient, add to value, which we'll write to *cvalue in one go */ for (i=0; i < data->arraysize; i++) value += data->coefficients[i] * powers[i]; /* only if something changed, write *cvalue in one go */ if (data->poly_order) { if (data->flag & FCM_GENERATOR_ADDITIVE) *cvalue += value; else *cvalue= value; } /* cleanup */ if (powers) MEM_freeN(powers); } break; case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* Factorized polynomial */ { float value= 1.0f, *cp=NULL; unsigned int i; /* for each coefficient pair, solve for that bracket before accumulating in value by multiplying */ for (cp=data->coefficients, i=0; (cp) && (i < (unsigned int)data->poly_order); cp+=2, i++) value *= (cp[0]*evaltime + cp[1]); /* only if something changed, write *cvalue in one go */ if (data->poly_order) { if (data->flag & FCM_GENERATOR_ADDITIVE) *cvalue += value; else *cvalue= value; } } break; } }
static void fill_scs_points(Object *ob, DerivedMesh *dm, SmokeCollSettings *scs) { MVert *mvert = dm->getVertArray(dm); MFace *mface = dm->getFaceArray(dm); int i = 0, divs = 0; int *tridivs = NULL; float cell_len = 1.0 / 50.0; // for res = 50 int newdivs = 0; int quads = 0, facecounter = 0; // count quads for(i = 0; i < dm->getNumFaces(dm); i++) { if(mface[i].v4) quads++; } calcTriangleDivs(ob, mvert, dm->getNumVerts(dm), mface, dm->getNumFaces(dm), dm->getNumFaces(dm) + quads, &tridivs, cell_len); // count triangle divisions for(i = 0; i < dm->getNumFaces(dm) + quads; i++) { divs += (tridivs[3 * i] + 1) * (tridivs[3 * i + 1] + 1) * (tridivs[3 * i + 2] + 1); } // printf("divs: %d\n", divs); scs->points = MEM_callocN(sizeof(float) * (dm->getNumVerts(dm) + divs) * 3, "SmokeCollPoints"); for(i = 0; i < dm->getNumVerts(dm); i++) { float tmpvec[3]; VECCOPY(tmpvec, mvert[i].co); Mat4MulVecfl (ob->obmat, tmpvec); VECCOPY(&scs->points[i * 3], tmpvec); } for(i = 0, facecounter = 0; i < dm->getNumFaces(dm); i++) { int again = 0; do { int j, k; int divs1 = tridivs[3 * facecounter + 0]; int divs2 = tridivs[3 * facecounter + 1]; //int divs3 = tridivs[3 * facecounter + 2]; float side1[3], side2[3], trinormorg[3], trinorm[3]; if(again == 1 && mface[i].v4) { VECSUB(side1, mvert[ mface[i].v3 ].co, mvert[ mface[i].v1 ].co); VECSUB(side2, mvert[ mface[i].v4 ].co, mvert[ mface[i].v1 ].co); } else { VECSUB(side1, mvert[ mface[i].v2 ].co, mvert[ mface[i].v1 ].co); VECSUB(side2, mvert[ mface[i].v3 ].co, mvert[ mface[i].v1 ].co); } Crossf(trinormorg, side1, side2); Normalize(trinormorg); VECCOPY(trinorm, trinormorg); VecMulf(trinorm, 0.25 * cell_len); for(j = 0; j <= divs1; j++) { for(k = 0; k <= divs2; k++) { float p1[3], p2[3], p3[3], p[3]={0,0,0}; const float uf = (float)(j + TRI_UVOFFSET) / (float)(divs1 + 0.0); const float vf = (float)(k + TRI_UVOFFSET) / (float)(divs2 + 0.0); float tmpvec[3]; if(uf+vf > 1.0) { // printf("bigger - divs1: %d, divs2: %d\n", divs1, divs2); continue; } VECCOPY(p1, mvert[ mface[i].v1 ].co); if(again == 1 && mface[i].v4) { VECCOPY(p2, mvert[ mface[i].v3 ].co); VECCOPY(p3, mvert[ mface[i].v4 ].co); } else { VECCOPY(p2, mvert[ mface[i].v2 ].co); VECCOPY(p3, mvert[ mface[i].v3 ].co); } VecMulf(p1, (1.0-uf-vf)); VecMulf(p2, uf); VecMulf(p3, vf); VECADD(p, p1, p2); VECADD(p, p, p3); if(newdivs > divs) printf("mem problem\n"); // mMovPoints.push_back(p + trinorm); VECCOPY(tmpvec, p); VECADD(tmpvec, tmpvec, trinorm); Mat4MulVecfl (ob->obmat, tmpvec); VECCOPY(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], tmpvec); newdivs++; if(newdivs > divs) printf("mem problem\n"); // mMovPoints.push_back(p - trinorm); VECCOPY(tmpvec, p); VECSUB(tmpvec, tmpvec, trinorm); Mat4MulVecfl (ob->obmat, tmpvec); VECCOPY(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], tmpvec); newdivs++; } } if(again == 0 && mface[i].v4) again++; else again = 0; facecounter++; } while(again!=0); } scs->numpoints = dm->getNumVerts(dm) + newdivs; MEM_freeN(tridivs); }