static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int level, int animated) { Object *ob, *ob_iter; Base *base = NULL; DupliObject *dob; DerivedMesh *dm; Mesh *me= par->data; MTFace *mtface; MFace *mface; MVert *mvert; float pmat[4][4], imat[3][3], (*orco)[3] = NULL, w; int lay, oblay, totface, a; Scene *sce = NULL; Group *group = NULL; GroupObject *go = NULL; EditMesh *em; float ob__obmat[4][4]; /* needed for groups where the object matrix needs to be modified */ /* simple preventing of too deep nested groups */ if(level>MAX_DUPLI_RECUR) return; Mat4CpyMat4(pmat, par->obmat); em = BKE_mesh_get_editmesh(me); if(em) { int totvert; dm= editmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH); totface= dm->getNumFaces(dm); mface= MEM_mallocN(sizeof(MFace)*totface, "mface temp"); dm->copyFaceArray(dm, mface); totvert= dm->getNumVerts(dm); mvert= MEM_mallocN(sizeof(MVert)*totvert, "mvert temp"); dm->copyVertArray(dm, mvert); BKE_mesh_end_editmesh(me, em); } else { dm = mesh_get_derived_deform(scene, par, CD_MASK_BAREMESH); totface= dm->getNumFaces(dm); mface= dm->getFaceArray(dm); mvert= dm->getVertArray(dm); } if(G.rendering) { orco= (float(*)[3])get_mesh_orco_verts(par); transform_mesh_orco_verts(me, orco, me->totvert, 0); mtface= me->mtface; } else { orco= NULL; mtface= NULL; } /* having to loop on scene OR group objects is NOT FUN */ if (GS(id->name) == ID_SCE) { sce = (Scene *)id; lay= sce->lay; base= sce->base.first; } else { group = (Group *)id; lay= group->layer; go = group->gobject.first; } /* Start looping on Scene OR Group objects */ while (base || go) { if (sce) { ob_iter= base->object; oblay = base->lay; } else { ob_iter= go->ob; oblay = ob_iter->lay; } if (lay & oblay && scene->obedit!=ob_iter) { ob=ob_iter->parent; while(ob) { if(ob==par) { ob = ob_iter; /* End Scene/Group object loop, below is generic */ /* par_space_mat - only used for groups so we can modify the space dupli's are in when par_space_mat is NULL ob->obmat can be used instead of ob__obmat */ if(par_space_mat) Mat4MulMat4(ob__obmat, ob->obmat, par_space_mat); else Mat4CpyMat4(ob__obmat, ob->obmat); Mat3CpyMat4(imat, ob->parentinv); /* mballs have a different dupli handling */ if(ob->type!=OB_MBALL) ob->flag |= OB_DONE; /* doesnt render */ for(a=0; a<totface; a++) { int mv1 = mface[a].v1; int mv2 = mface[a].v2; int mv3 = mface[a].v3; int mv4 = mface[a].v4; float *v1= mvert[mv1].co; float *v2= mvert[mv2].co; float *v3= mvert[mv3].co; float *v4= (mv4)? mvert[mv4].co: NULL; float cent[3], quat[4], mat[3][3], mat3[3][3], tmat[4][4], obmat[4][4]; /* translation */ if(v4) CalcCent4f(cent, v1, v2, v3, v4); else CalcCent3f(cent, v1, v2, v3); Mat4MulVecfl(pmat, cent); VecSubf(cent, cent, pmat[3]); VecAddf(cent, cent, ob__obmat[3]); Mat4CpyMat4(obmat, ob__obmat); VECCOPY(obmat[3], cent); /* rotation */ triatoquat(v1, v2, v3, quat); QuatToMat3(quat, mat); /* scale */ if(par->transflag & OB_DUPLIFACES_SCALE) { float size= v4?AreaQ3Dfl(v1, v2, v3, v4):AreaT3Dfl(v1, v2, v3); size= sqrt(size) * par->dupfacesca; Mat3MulFloat(mat[0], size); } Mat3CpyMat3(mat3, mat); Mat3MulMat3(mat, imat, mat3); Mat4CpyMat4(tmat, obmat); Mat4MulMat43(obmat, tmat, mat); dob= new_dupli_object(lb, ob, obmat, lay, a, OB_DUPLIFACES, animated); if(G.rendering) { w= (mv4)? 0.25f: 1.0f/3.0f; if(orco) { VECADDFAC(dob->orco, dob->orco, orco[mv1], w); VECADDFAC(dob->orco, dob->orco, orco[mv2], w); VECADDFAC(dob->orco, dob->orco, orco[mv3], w); if(mv4) VECADDFAC(dob->orco, dob->orco, orco[mv4], w); } if(mtface) { dob->uv[0] += w*mtface[a].uv[0][0]; dob->uv[1] += w*mtface[a].uv[0][1]; dob->uv[0] += w*mtface[a].uv[1][0]; dob->uv[1] += w*mtface[a].uv[1][1]; dob->uv[0] += w*mtface[a].uv[2][0]; dob->uv[1] += w*mtface[a].uv[2][1]; if(mv4) { dob->uv[0] += w*mtface[a].uv[3][0]; dob->uv[1] += w*mtface[a].uv[3][1]; } } } if(ob->transflag & OB_DUPLI) { float tmpmat[4][4]; Mat4CpyMat4(tmpmat, ob->obmat); Mat4CpyMat4(ob->obmat, obmat); /* pretend we are really this mat */ object_duplilist_recursive((ID *)id, scene, ob, lb, ob->obmat, level+1, animated); Mat4CpyMat4(ob->obmat, tmpmat); } } break; } ob= ob->parent; } } if (sce) base= base->next; /* scene loop */ else go= go->next; /* group loop */ } if(par->mode & OB_MODE_EDIT) { MEM_freeN(mface); MEM_freeN(mvert); } if(orco) MEM_freeN(orco); dm->release(dm); }
/** * This function populates an array of verts for the triangles of a mesh * Tangent and Normals are also stored */ static TriTessFace *mesh_calc_tri_tessface( Mesh *me, bool tangent, DerivedMesh *dm) { int i; MVert *mvert; TSpace *tspace; float *precomputed_normals = NULL; bool calculate_normal; const int tottri = poly_to_tri_count(me->totpoly, me->totloop); MLoopTri *looptri; TriTessFace *triangles; /* calculate normal for each polygon only once */ unsigned int mpoly_prev = UINT_MAX; float no[3]; mvert = CustomData_get_layer(&me->vdata, CD_MVERT); looptri = MEM_mallocN(sizeof(*looptri) * tottri, __func__); triangles = MEM_mallocN(sizeof(TriTessFace) * tottri, __func__); if (tangent) { DM_ensure_normals(dm); DM_calc_loop_tangents(dm); precomputed_normals = dm->getPolyDataArray(dm, CD_NORMAL); calculate_normal = precomputed_normals ? false : true; tspace = dm->getLoopDataArray(dm, CD_TANGENT); BLI_assert(tspace); } BKE_mesh_recalc_looptri( me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri); for (i = 0; i < tottri; i++) { MLoopTri *lt = &looptri[i]; MPoly *mp = &me->mpoly[lt->poly]; triangles[i].mverts[0] = &mvert[me->mloop[lt->tri[0]].v]; triangles[i].mverts[1] = &mvert[me->mloop[lt->tri[1]].v]; triangles[i].mverts[2] = &mvert[me->mloop[lt->tri[2]].v]; triangles[i].is_smooth = (mp->flag & ME_SMOOTH) != 0; if (tangent) { triangles[i].tspace[0] = &tspace[lt->tri[0]]; triangles[i].tspace[1] = &tspace[lt->tri[1]]; triangles[i].tspace[2] = &tspace[lt->tri[2]]; if (calculate_normal) { if (lt->poly != mpoly_prev) { const MPoly *mp = &me->mpoly[lt->poly]; BKE_mesh_calc_poly_normal(mp, &me->mloop[mp->loopstart], me->mvert, no); mpoly_prev = lt->poly; } copy_v3_v3(triangles[i].normal, no); } else { copy_v3_v3(triangles[i].normal, &precomputed_normals[lt->poly]); } } } MEM_freeN(looptri); return triangles; }
void RE_bake_pixels_populate( Mesh *me, BakePixel pixel_array[], const size_t num_pixels, const BakeImages *bake_images, const char *uv_layer) { BakeDataZSpan bd; size_t i; int a, p_id; const MLoopUV *mloopuv; const int tottri = poly_to_tri_count(me->totpoly, me->totloop); MLoopTri *looptri; /* we can't bake in edit mode */ if (me->edit_btmesh) return; bd.pixel_array = pixel_array; bd.zspan = MEM_callocN(sizeof(ZSpan) * bake_images->size, "bake zspan"); /* initialize all pixel arrays so we know which ones are 'blank' */ for (i = 0; i < num_pixels; i++) { pixel_array[i].primitive_id = -1; } for (i = 0; i < bake_images->size; i++) { zbuf_alloc_span(&bd.zspan[i], bake_images->data[i].width, bake_images->data[i].height, R.clipcrop); } if ((uv_layer == NULL) || (uv_layer[0] == '\0')) { mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV); } else { int uv_id = CustomData_get_named_layer(&me->ldata, CD_MLOOPUV, uv_layer); mloopuv = CustomData_get_layer_n(&me->ldata, CD_MTFACE, uv_id); } if (mloopuv == NULL) return; looptri = MEM_mallocN(sizeof(*looptri) * tottri, __func__); BKE_mesh_recalc_looptri( me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri); p_id = -1; for (i = 0; i < tottri; i++) { const MLoopTri *lt = &looptri[i]; const MPoly *mp = &me->mpoly[lt->poly]; float vec[3][2]; int mat_nr = mp->mat_nr; int image_id = bake_images->lookup[mat_nr]; bd.bk_image = &bake_images->data[image_id]; bd.primitive_id = ++p_id; for (a = 0; a < 3; a++) { const float *uv = mloopuv[lt->tri[a]].uv; /* Note, workaround for pixel aligned UVs which are common and can screw up our intersection tests * where a pixel gets in between 2 faces or the middle of a quad, * camera aligned quads also have this problem but they are less common. * Add a small offset to the UVs, fixes bug #18685 - Campbell */ vec[a][0] = uv[0] * (float)bd.bk_image->width - (0.5f + 0.001f); vec[a][1] = uv[1] * (float)bd.bk_image->height - (0.5f + 0.002f); } bake_differentials(&bd, vec[0], vec[1], vec[2]); zspan_scanconvert(&bd.zspan[image_id], (void *)&bd, vec[0], vec[1], vec[2], store_bake_pixel); } for (i = 0; i < bake_images->size; i++) { zbuf_free_span(&bd.zspan[i]); } MEM_freeN(looptri); MEM_freeN(bd.zspan); }
static void waveModifier_do(WaveModifierData *md, Scene *scene, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { WaveModifierData *wmd = (WaveModifierData *) md; MVert *mvert = NULL; MDeformVert *dvert; int defgrp_index; float ctime = BKE_scene_frame_get(scene); float minfac = (float)(1.0 / exp(wmd->width * wmd->narrow * wmd->width * wmd->narrow)); float lifefac = wmd->height; float (*tex_co)[3] = NULL; const int wmd_axis = wmd->flag & (MOD_WAVE_X | MOD_WAVE_Y); const float falloff = wmd->falloff; float falloff_fac = 1.0f; /* when falloff == 0.0f this stays at 1.0f */ if ((wmd->flag & MOD_WAVE_NORM) && (ob->type == OB_MESH)) mvert = dm->getVertArray(dm); if (wmd->objectcenter) { float mat[4][4]; /* get the control object's location in local coordinates */ invert_m4_m4(ob->imat, ob->obmat); mul_m4_m4m4(mat, ob->imat, wmd->objectcenter->obmat); wmd->startx = mat[3][0]; wmd->starty = mat[3][1]; } /* get the index of the deform group */ modifier_get_vgroup(ob, dm, wmd->defgrp_name, &dvert, &defgrp_index); if (wmd->damp == 0) wmd->damp = 10.0f; if (wmd->lifetime != 0.0f) { float x = ctime - wmd->timeoffs; if (x > wmd->lifetime) { lifefac = x - wmd->lifetime; if (lifefac > wmd->damp) lifefac = 0.0; else lifefac = (float)(wmd->height * (1.0f - sqrtf(lifefac / wmd->damp))); } } if (wmd->texture) { tex_co = MEM_mallocN(sizeof(*tex_co) * numVerts, "waveModifier_do tex_co"); get_texture_coords((MappingInfoModifierData *)wmd, ob, dm, vertexCos, tex_co, numVerts); modifier_init_texture(wmd->modifier.scene, wmd->texture); } if (lifefac != 0.0f) { /* avoid divide by zero checks within the loop */ float falloff_inv = falloff ? 1.0f / falloff : 1.0f; int i; for (i = 0; i < numVerts; i++) { float *co = vertexCos[i]; float x = co[0] - wmd->startx; float y = co[1] - wmd->starty; float amplit = 0.0f; float def_weight = 1.0f; /* get weights */ if (dvert) { def_weight = defvert_find_weight(&dvert[i], defgrp_index); /* if this vert isn't in the vgroup, don't deform it */ if (def_weight == 0.0f) { continue; } } switch (wmd_axis) { case MOD_WAVE_X | MOD_WAVE_Y: amplit = sqrtf(x * x + y * y); break; case MOD_WAVE_X: amplit = x; break; case MOD_WAVE_Y: amplit = y; break; } /* this way it makes nice circles */ amplit -= (ctime - wmd->timeoffs) * wmd->speed; if (wmd->flag & MOD_WAVE_CYCL) { amplit = (float)fmodf(amplit - wmd->width, 2.0f * wmd->width) + wmd->width; } if (falloff != 0.0f) { float dist = 0.0f; switch (wmd_axis) { case MOD_WAVE_X | MOD_WAVE_Y: dist = sqrtf(x * x + y * y); break; case MOD_WAVE_X: dist = fabsf(x); break; case MOD_WAVE_Y: dist = fabsf(y); break; } falloff_fac = (1.0f - (dist * falloff_inv)); CLAMP(falloff_fac, 0.0f, 1.0f); } /* GAUSSIAN */ if ((falloff_fac != 0.0f) && (amplit > -wmd->width) && (amplit < wmd->width)) { amplit = amplit * wmd->narrow; amplit = (float)(1.0f / expf(amplit * amplit) - minfac); /*apply texture*/ if (wmd->texture) { TexResult texres; texres.nor = NULL; BKE_texture_get_value(wmd->modifier.scene, wmd->texture, tex_co[i], &texres, false); amplit *= texres.tin; } /*apply weight & falloff */ amplit *= def_weight * falloff_fac; if (mvert) { /* move along normals */ if (wmd->flag & MOD_WAVE_NORM_X) { co[0] += (lifefac * amplit) * mvert[i].no[0] / 32767.0f; } if (wmd->flag & MOD_WAVE_NORM_Y) { co[1] += (lifefac * amplit) * mvert[i].no[1] / 32767.0f; } if (wmd->flag & MOD_WAVE_NORM_Z) { co[2] += (lifefac * amplit) * mvert[i].no[2] / 32767.0f; } } else { /* move along local z axis */ co[2] += lifefac * amplit; } } } } if (wmd->texture) MEM_freeN(tex_co); }
BLI_mempool *BLI_mempool_create(int esize, int totelem, int pchunk, int flag) { BLI_mempool *pool = NULL; BLI_freenode *lasttail = NULL, *curnode = NULL; int i, j, maxchunks; char *addr; /* allocate the pool structure */ if (flag & BLI_MEMPOOL_SYSMALLOC) { pool = malloc(sizeof(BLI_mempool)); } else { pool = MEM_mallocN(sizeof(BLI_mempool), "memory pool"); } /* set the elem size */ if (esize < MEMPOOL_ELEM_SIZE_MIN) { esize = MEMPOOL_ELEM_SIZE_MIN; } if (flag & BLI_MEMPOOL_ALLOW_ITER) { pool->esize = MAX2(esize, (int)sizeof(BLI_freenode)); } else { pool->esize = esize; } pool->flag = flag; pool->pchunk = pchunk; pool->csize = esize * pchunk; pool->chunks.first = pool->chunks.last = NULL; pool->totalloc = 0; pool->totused = 0; maxchunks = totelem / pchunk + 1; if (maxchunks == 0) { maxchunks = 1; } /* allocate the actual chunks */ for (i = 0; i < maxchunks; i++) { BLI_mempool_chunk *mpchunk; if (flag & BLI_MEMPOOL_SYSMALLOC) { mpchunk = malloc(sizeof(BLI_mempool_chunk)); mpchunk->data = malloc((size_t)pool->csize); } else { mpchunk = MEM_mallocN(sizeof(BLI_mempool_chunk), "BLI_Mempool Chunk"); mpchunk->data = MEM_mallocN((size_t)pool->csize, "BLI Mempool Chunk Data"); } mpchunk->next = mpchunk->prev = NULL; BLI_addtail(&(pool->chunks), mpchunk); if (i == 0) { pool->free = mpchunk->data; /* start of the list */ if (pool->flag & BLI_MEMPOOL_ALLOW_ITER) { pool->free->freeword = FREEWORD; } } /* loop through the allocated data, building the pointer structures */ for (addr = mpchunk->data, j = 0; j < pool->pchunk; j++) { curnode = ((BLI_freenode *)addr); addr += pool->esize; curnode->next = (BLI_freenode *)addr; if (pool->flag & BLI_MEMPOOL_ALLOW_ITER) { if (j != pool->pchunk - 1) curnode->next->freeword = FREEWORD; curnode->freeword = FREEWORD; } } /* final pointer in the previously allocated chunk is wrong */ if (lasttail) { lasttail->next = mpchunk->data; if (pool->flag & BLI_MEMPOOL_ALLOW_ITER) { lasttail->freeword = FREEWORD; } } /* set the end of this chunks memory to the new tail for next iteration */ lasttail = curnode; #ifdef USE_TOTALLOC pool->totalloc += pool->pchunk; #endif } /* terminate the list */ curnode->next = NULL; return pool; }
void render_view3d_draw(RenderEngine *engine, const bContext *C) { Render *re = engine->re; RenderResult rres; char name[32]; render_view3d_do(engine, C); if (re == NULL) { sprintf(name, "View3dPreview %p", (void *)CTX_wm_region(C)); re = RE_GetRender(name); if (re == NULL) return; } RE_AcquireResultImage(re, &rres); if (rres.rectf) { Scene *scene = CTX_data_scene(C); bool force_fallback = false; bool need_fallback = true; float dither = scene->r.dither_intensity; /* Dithering is not supported on GLSL yet */ force_fallback |= dither != 0.0f; /* If user decided not to use GLSL, fallback to glaDrawPixelsAuto */ force_fallback |= (U.image_draw_method != IMAGE_DRAW_METHOD_GLSL); /* Try using GLSL display transform. */ if (force_fallback == false) { if (IMB_colormanagement_setup_glsl_draw(NULL, &scene->display_settings, TRUE)) { glEnable(GL_BLEND); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glaDrawPixelsTex(rres.xof, rres.yof, rres.rectx, rres.recty, GL_RGBA, GL_FLOAT, GL_LINEAR, rres.rectf); glDisable(GL_BLEND); IMB_colormanagement_finish_glsl_draw(); need_fallback = false; } } /* If GLSL failed, use old-school CPU-based transform. */ if (need_fallback) { unsigned char *display_buffer = MEM_mallocN(4 * rres.rectx * rres.recty * sizeof(char), "render_view3d_draw"); IMB_colormanagement_buffer_make_display_space(rres.rectf, display_buffer, rres.rectx, rres.recty, 4, dither, NULL, &scene->display_settings); glEnable(GL_BLEND); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glaDrawPixelsAuto(rres.xof, rres.yof, rres.rectx, rres.recty, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, display_buffer); glDisable(GL_BLEND); MEM_freeN(display_buffer); } } RE_ReleaseResultImage(re); }
/** * Main boxpacking function accessed from other functions * This sets boxes x,y to positive values, sorting from 0,0 outwards. * There is no limit to the space boxes may take, only that they will be packed * tightly into the lower left hand corner (0,0) * * \param boxarray: a pre allocated array of boxes. * only the 'box->x' and 'box->y' are set, 'box->w' and 'box->h' are used, * 'box->index' is not used at all, the only reason its there * is that the box array is sorted by area and programs need to be able * to have some way of writing the boxes back to the original data. * \param len: the number of boxes in the array. * \param r_tot_x, r_tot_y: set so you can normalize the data. * */ void BLI_box_pack_2d(BoxPack *boxarray, const uint len, float *r_tot_x, float *r_tot_y) { uint box_index, verts_pack_len, i, j, k; uint *vertex_pack_indices; /* an array of indices used for sorting verts */ bool isect; float tot_x = 0.0f, tot_y = 0.0f; BoxPack *box, *box_test; /*current box and another for intersection tests*/ BoxVert *vert; /* the current vert */ struct VertSortContext vs_ctx; if (!len) { *r_tot_x = tot_x; *r_tot_y = tot_y; return; } /* Sort boxes, biggest first */ qsort(boxarray, (size_t)len, sizeof(BoxPack), box_areasort); /* add verts to the boxes, these are only used internally */ vert = MEM_mallocN((size_t)len * 4 * sizeof(BoxVert), "BoxPack Verts"); vertex_pack_indices = MEM_mallocN((size_t)len * 3 * sizeof(int), "BoxPack Indices"); vs_ctx.vertarray = vert; for (box = boxarray, box_index = 0, i = 0; box_index < len; box_index++, box++) { vert->blb = vert->brb = vert->tlb = vert->isect_cache[0] = vert->isect_cache[1] = vert->isect_cache[2] = vert->isect_cache[3] = NULL; vert->free = CORNERFLAGS & ~TRF; vert->trb = box; vert->used = false; vert->index = i++; box->v[BL] = vert++; vert->trb = vert->brb = vert->tlb = vert->isect_cache[0] = vert->isect_cache[1] = vert->isect_cache[2] = vert->isect_cache[3] = NULL; vert->free = CORNERFLAGS & ~BLF; vert->blb = box; vert->used = false; vert->index = i++; box->v[TR] = vert++; vert->trb = vert->blb = vert->tlb = vert->isect_cache[0] = vert->isect_cache[1] = vert->isect_cache[2] = vert->isect_cache[3] = NULL; vert->free = CORNERFLAGS & ~BRF; vert->brb = box; vert->used = false; vert->index = i++; box->v[TL] = vert++; vert->trb = vert->blb = vert->brb = vert->isect_cache[0] = vert->isect_cache[1] = vert->isect_cache[2] = vert->isect_cache[3] = NULL; vert->free = CORNERFLAGS & ~TLF; vert->tlb = box; vert->used = false; vert->index = i++; box->v[BR] = vert++; } vert = NULL; /* Pack the First box! * then enter the main box-packing loop */ box = boxarray; /* get the first box */ /* First time, no boxes packed */ box->v[BL]->free = 0; /* Can't use any if these */ box->v[BR]->free &= ~(BLF | BRF); box->v[TL]->free &= ~(BLF | TLF); tot_x = box->w; tot_y = box->h; /* This sets all the vertex locations */ box_xmin_set(box, 0.0f); box_ymin_set(box, 0.0f); box->x = box->y = 0.0f; for (i = 0; i < 4; i++) { box->v[i]->used = true; #ifdef USE_PACK_BIAS vert_bias_update(box->v[i]); #endif } for (i = 0; i < 3; i++) vertex_pack_indices[i] = box->v[i + 1]->index; verts_pack_len = 3; box++; /* next box, needed for the loop below */ /* ...done packing the first box */ /* Main boxpacking loop */ for (box_index = 1; box_index < len; box_index++, box++) { /* These floats are used for sorting re-sorting */ vs_ctx.box_width = box->w; vs_ctx.box_height = box->h; qsort_r(vertex_pack_indices, (size_t)verts_pack_len, sizeof(int), vertex_sort, &vs_ctx); #ifdef USE_FREE_STRIP /* strip free vertices */ i = verts_pack_len - 1; while ((i != 0) && vs_ctx.vertarray[vertex_pack_indices[i]].free == 0) { i--; } verts_pack_len = i + 1; #endif /* Pack the box in with the others */ /* sort the verts */ isect = true; for (i = 0; i < verts_pack_len && isect; i++) { vert = &vs_ctx.vertarray[vertex_pack_indices[i]]; /* printf("\ttesting vert %i %i %i %f %f\n", i, * vert->free, verts_pack_len, vert->x, vert->y); */ /* This vert has a free quadrant * Test if we can place the box here * vert->free & quad_flags[j] - Checks * */ for (j = 0; (j < 4) && isect; j++) { if (vert->free & quad_flag(j)) { switch (j) { case BL: box_xmax_set(box, vert->x); box_ymax_set(box, vert->y); break; case TR: box_xmin_set(box, vert->x); box_ymin_set(box, vert->y); break; case TL: box_xmax_set(box, vert->x); box_ymin_set(box, vert->y); break; case BR: box_xmin_set(box, vert->x); box_ymax_set(box, vert->y); break; } /* Now we need to check that the box intersects * with any other boxes * Assume no intersection... */ isect = false; if ( /* Constrain boxes to positive X/Y values */ box_xmin_get(box) < 0.0f || box_ymin_get(box) < 0.0f || /* check for last intersected */ (vert->isect_cache[j] && box_isect(box, vert->isect_cache[j]))) { /* Here we check that the last intersected * box will intersect with this one using * isect_cache that can store a pointer to a * box for each quadrant * big speedup */ isect = true; } else { /* do a full search for colliding box * this is really slow, some spatially divided * data-structure would be better */ for (box_test = boxarray; box_test != box; box_test++) { if (box_isect(box, box_test)) { /* Store the last intersecting here as cache * for faster checking next time around */ vert->isect_cache[j] = box_test; isect = true; break; } } } if (!isect) { /* maintain the total width and height */ tot_x = max_ff(box_xmax_get(box), tot_x); tot_y = max_ff(box_ymax_get(box), tot_y); /* Place the box */ vert->free &= (signed char)(~quad_flag(j)); switch (j) { case TR: box->v[BL] = vert; vert->trb = box; break; case TL: box->v[BR] = vert; vert->tlb = box; break; case BR: box->v[TL] = vert; vert->brb = box; break; case BL: box->v[TR] = vert; vert->blb = box; break; } /* Mask free flags for verts that are * on the bottom or side so we don't get * boxes outside the given rectangle ares * * We can do an else/if here because only the first * box can be at the very bottom left corner */ if (box_xmin_get(box) <= 0) { box->v[TL]->free &= ~(TLF | BLF); box->v[BL]->free &= ~(TLF | BLF); } else if (box_ymin_get(box) <= 0) { box->v[BL]->free &= ~(BRF | BLF); box->v[BR]->free &= ~(BRF | BLF); } /* The following block of code does a logical * check with 2 adjacent boxes, its possible to * flag verts on one or both of the boxes * as being used by checking the width or * height of both boxes */ if (vert->tlb && vert->trb && (box == vert->tlb || box == vert->trb)) { if (UNLIKELY(fabsf(vert->tlb->h - vert->trb->h) < EPSILON_MERGE)) { #ifdef USE_MERGE # define A (vert->trb->v[TL]) # define B (vert->tlb->v[TR]) # define MASK (BLF | BRF) BLI_assert(A->used != B->used); if (A->used) { A->free &= B->free & ~MASK; B = A; } else { B->free &= A->free & ~MASK; A = B; } BLI_assert((A->free & MASK) == 0); # undef A # undef B # undef MASK #else vert->tlb->v[TR]->free &= ~BLF; vert->trb->v[TL]->free &= ~BRF; #endif } else if (vert->tlb->h > vert->trb->h) { vert->trb->v[TL]->free &= ~(TLF | BLF); } else /* if (vert->tlb->h < vert->trb->h) */ { vert->tlb->v[TR]->free &= ~(TRF | BRF); } } else if (vert->blb && vert->brb && (box == vert->blb || box == vert->brb)) { if (UNLIKELY(fabsf(vert->blb->h - vert->brb->h) < EPSILON_MERGE)) { #ifdef USE_MERGE # define A (vert->blb->v[BR]) # define B (vert->brb->v[BL]) # define MASK (TRF | TLF) BLI_assert(A->used != B->used); if (A->used) { A->free &= B->free & ~MASK; B = A; } else { B->free &= A->free & ~MASK; A = B; } BLI_assert((A->free & MASK) == 0); # undef A # undef B # undef MASK #else vert->blb->v[BR]->free &= ~TRF; vert->brb->v[BL]->free &= ~TLF; #endif } else if (vert->blb->h > vert->brb->h) { vert->brb->v[BL]->free &= ~(TLF | BLF); } else /* if (vert->blb->h < vert->brb->h) */ { vert->blb->v[BR]->free &= ~(TRF | BRF); } } /* Horizontal */ if (vert->tlb && vert->blb && (box == vert->tlb || box == vert->blb)) { if (UNLIKELY(fabsf(vert->tlb->w - vert->blb->w) < EPSILON_MERGE)) { #ifdef USE_MERGE # define A (vert->blb->v[TL]) # define B (vert->tlb->v[BL]) # define MASK (TRF | BRF) BLI_assert(A->used != B->used); if (A->used) { A->free &= B->free & ~MASK; B = A; } else { B->free &= A->free & ~MASK; A = B; } BLI_assert((A->free & MASK) == 0); # undef A # undef B # undef MASK #else vert->blb->v[TL]->free &= ~TRF; vert->tlb->v[BL]->free &= ~BRF; #endif } else if (vert->tlb->w > vert->blb->w) { vert->blb->v[TL]->free &= ~(TLF | TRF); } else /* if (vert->tlb->w < vert->blb->w) */ { vert->tlb->v[BL]->free &= ~(BLF | BRF); } } else if (vert->trb && vert->brb && (box == vert->trb || box == vert->brb)) { if (UNLIKELY(fabsf(vert->trb->w - vert->brb->w) < EPSILON_MERGE)) { #ifdef USE_MERGE # define A (vert->brb->v[TR]) # define B (vert->trb->v[BR]) # define MASK (TLF | BLF) BLI_assert(A->used != B->used); if (A->used) { A->free &= B->free & ~MASK; B = A; } else { B->free &= A->free & ~MASK; A = B; } BLI_assert((A->free & MASK) == 0); # undef A # undef B # undef MASK #else vert->brb->v[TR]->free &= ~TLF; vert->trb->v[BR]->free &= ~BLF; #endif } else if (vert->trb->w > vert->brb->w) { vert->brb->v[TR]->free &= ~(TLF | TRF); } else /* if (vert->trb->w < vert->brb->w) */ { vert->trb->v[BR]->free &= ~(BLF | BRF); } } /* End logical check */ for (k = 0; k < 4; k++) { if (box->v[k]->used == false) { box->v[k]->used = true; #ifdef USE_PACK_BIAS vert_bias_update(box->v[k]); #endif vertex_pack_indices[verts_pack_len] = box->v[k]->index; verts_pack_len++; } } /* The Box verts are only used internally * Update the box x and y since thats what external * functions will see */ box->x = box_xmin_get(box); box->y = box_ymin_get(box); } } } } } *r_tot_x = tot_x; *r_tot_y = tot_y; /* free all the verts, not really needed because they shouldn't be * touched anymore but accessing the pointers would crash blender */ for (box_index = 0; box_index < len; box_index++) { box = boxarray + box_index; box->v[0] = box->v[1] = box->v[2] = box->v[3] = NULL; } MEM_freeN(vertex_pack_indices); MEM_freeN(vs_ctx.vertarray); }
/* get a GPUBuffer of at least `size' bytes; uses one from the buffer pool if possible, otherwise creates a new one */ GPUBuffer *GPU_buffer_alloc(int size) { GPUBufferPool *pool; GPUBuffer *buf; int i, bufsize, bestfit = -1; pool = gpu_get_global_buffer_pool(); /* not sure if this buffer pool code has been profiled much, seems to me that the graphics driver and system memory management might do this stuff anyway. --nicholas */ /* check the global buffer pool for a recently-deleted buffer that is at least as big as the request, but not more than twice as big */ for(i = 0; i < pool->totbuf; i++) { bufsize = pool->buffers[i]->size; /* check for an exact size match */ if(bufsize == size) { bestfit = i; break; } /* smaller buffers won't fit data and buffers at least twice as big are a waste of memory */ else if(bufsize > size && size > (bufsize / 2)) { /* is it closer to the required size than the last appropriate buffer found. try to save memory */ if(bestfit == -1 || pool->buffers[bestfit]->size > bufsize) { bestfit = i; } } } /* if an acceptable buffer was found in the pool, remove it from the pool and return it */ if(bestfit != -1) { buf = pool->buffers[bestfit]; gpu_buffer_pool_remove_index(pool, bestfit); return buf; } /* no acceptable buffer found in the pool, create a new one */ buf = MEM_callocN(sizeof(GPUBuffer), "GPUBuffer"); buf->size = size; if(useVBOs == 1) { /* create a new VBO and initialize it to the requested size */ glGenBuffersARB(1, &buf->id); glBindBufferARB(GL_ARRAY_BUFFER_ARB, buf->id); glBufferDataARB(GL_ARRAY_BUFFER_ARB, size, 0, GL_STATIC_DRAW_ARB); glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); } else { buf->pointer = MEM_mallocN(size, "GPUBuffer.pointer"); /* purpose of this seems to be dealing with out-of-memory errors? looks a bit iffy to me though, at least on Linux I expect malloc() would just overcommit. --nicholas */ while(!buf->pointer && pool->totbuf > 0) { gpu_buffer_pool_delete_last(pool); buf->pointer = MEM_mallocN(size, "GPUBuffer.pointer"); } if(!buf->pointer) return NULL; } return buf; }
static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object, int vector_size, int size, GLenum target, void *user, GPUBufferCopyFunc copy_f) { GPUBufferPool *pool; GPUBuffer *buffer; float *varray; int mat_orig_to_new[MAX_MATERIALS]; int *cur_index_per_mat; int i; int success; GLboolean uploaded; pool = gpu_get_global_buffer_pool(); /* alloc a GPUBuffer; fall back to legacy mode on failure */ if(!(buffer = GPU_buffer_alloc(size))) dm->drawObject->legacy = 1; /* nothing to do for legacy mode */ if(dm->drawObject->legacy) return 0; cur_index_per_mat = MEM_mallocN(sizeof(int)*object->totmaterial, "GPU_buffer_setup.cur_index_per_mat"); for(i = 0; i < object->totmaterial; i++) { /* for each material, the current index to copy data to */ cur_index_per_mat[i] = object->materials[i].start * vector_size; /* map from original material index to new GPUBufferMaterial index */ mat_orig_to_new[object->materials[i].mat_nr] = i; } if(useVBOs) { success = 0; while(!success) { /* bind the buffer and discard previous data, avoids stalling gpu */ glBindBufferARB(target, buffer->id); glBufferDataARB(target, buffer->size, 0, GL_STATIC_DRAW_ARB); /* attempt to map the buffer */ if(!(varray = glMapBufferARB(target, GL_WRITE_ONLY_ARB))) { /* failed to map the buffer; delete it */ GPU_buffer_free(buffer); gpu_buffer_pool_delete_last(pool); buffer= NULL; /* try freeing an entry from the pool and reallocating the buffer */ if(pool->totbuf > 0) { gpu_buffer_pool_delete_last(pool); buffer = GPU_buffer_alloc(size); } /* allocation still failed; fall back to legacy mode */ if(!buffer) { dm->drawObject->legacy = 1; success = 1; } } else { success = 1; } } /* check legacy fallback didn't happen */ if(dm->drawObject->legacy == 0) { uploaded = GL_FALSE; /* attempt to upload the data to the VBO */ while(uploaded == GL_FALSE) { (*copy_f)(dm, varray, cur_index_per_mat, mat_orig_to_new, user); /* glUnmapBuffer returns GL_FALSE if the data store is corrupted; retry in that case */ uploaded = glUnmapBufferARB(target); } } glBindBufferARB(target, 0); } else { /* VBO not supported, use vertex array fallback */ if(buffer->pointer) { varray = buffer->pointer; (*copy_f)(dm, varray, cur_index_per_mat, mat_orig_to_new, user); } else { dm->drawObject->legacy = 1; } } MEM_freeN(cur_index_per_mat); return buffer; }
/* screen can be NULL */ static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, int **thumb_pt) { /* will be scaled down, but gives some nice oversampling */ ImBuf *ibuf; int *thumb; char err_out[256] = "unknown"; /* screen if no camera found */ ScrArea *sa = NULL; ARegion *ar = NULL; View3D *v3d = NULL; *thumb_pt = NULL; /* scene can be NULL if running a script at startup and calling the save operator */ if (G.background || scene == NULL) return NULL; if ((scene->camera == NULL) && (screen != NULL)) { sa = BKE_screen_find_big_area(screen, SPACE_VIEW3D, 0); ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); if (ar) { v3d = sa->spacedata.first; } } if (scene->camera == NULL && v3d == NULL) { return NULL; } /* gets scaled to BLEN_THUMB_SIZE */ if (scene->camera) { ibuf = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera, BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2, IB_rect, OB_SOLID, FALSE, FALSE, R_ADDSKY, err_out); } else { ibuf = ED_view3d_draw_offscreen_imbuf(scene, v3d, ar, BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2, IB_rect, FALSE, R_ADDSKY, err_out); } if (ibuf) { float aspect = (scene->r.xsch * scene->r.xasp) / (scene->r.ysch * scene->r.yasp); /* dirty oversampling */ IMB_scaleImBuf(ibuf, BLEN_THUMB_SIZE, BLEN_THUMB_SIZE); /* add pretty overlay */ IMB_overlayblend_thumb(ibuf->rect, ibuf->x, ibuf->y, aspect); /* first write into thumb buffer */ thumb = MEM_mallocN(((2 + (BLEN_THUMB_SIZE * BLEN_THUMB_SIZE))) * sizeof(int), "write_file thumb"); thumb[0] = BLEN_THUMB_SIZE; thumb[1] = BLEN_THUMB_SIZE; memcpy(thumb + 2, ibuf->rect, BLEN_THUMB_SIZE * BLEN_THUMB_SIZE * sizeof(int)); } else { /* '*thumb_pt' needs to stay NULL to prevent a bad thumbnail from being handled */ fprintf(stderr, "blend_file_thumb failed to create thumbnail: %s\n", err_out); thumb = NULL; } /* must be freed by caller */ *thumb_pt = thumb; return ibuf; }
static void make_prim(Object *obedit, int type, float mat[4][4], int tot, int seg, int subdiv, float dia, float depth, int ext, int fill) { /* * type - for the type of shape * dia - the radius for cone,sphere cylinder etc. * depth - * ext - extrude * fill - end capping, and option to fill in circle * cent[3] - center of the data. * */ EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); EditVert *eve, *v1=NULL, *v2, *v3, *v4=NULL, *vtop, *vdown; float phi, phid, vec[3]; float q[4], cmat[3][3], nor[3]= {0.0, 0.0, 0.0}; short a, b; EM_clear_flag_all(em, SELECT); phid= 2.0f*(float)M_PI/tot; phi= .25f*(float)M_PI; switch(type) { case PRIM_GRID: /* grid */ /* clear flags */ eve= em->verts.first; while(eve) { eve->f= 0; eve= eve->next; } /* one segment first: the X axis */ phi = (2*dia)/(float)(tot-1); phid = (2*dia)/(float)(seg-1); for(a=tot-1;a>=0;a--) { vec[0] = (phi*a) - dia; vec[1]= - dia; vec[2]= 0.0f; eve= addvertlist(em, vec, NULL); eve->f= 1+2+4; if(a < tot -1) addedgelist(em, eve->prev, eve, NULL); } /* extrude and translate */ vec[0]= vec[2]= 0.0; vec[1]= phid; for(a=0;a<seg-1;a++) { extrudeflag_vert(obedit, em, 2, nor, 0); // nor unused translateflag(em, 2, vec); } /* and now do imat */ eve= em->verts.first; while(eve) { if(eve->f & SELECT) { mul_m4_v3(mat,eve->co); } eve= eve->next; } recalc_editnormals(em); break; case PRIM_UVSPHERE: /* UVsphere */ /* clear all flags */ eve= em->verts.first; while(eve) { eve->f= 0; eve= eve->next; } /* one segment first */ phi= 0; phid/=2; for(a=0; a<=tot; a++) { vec[0]= dia*sinf(phi); vec[1]= 0.0; vec[2]= dia*cosf(phi); eve= addvertlist(em, vec, NULL); eve->f= 1+2+4; if(a==0) v1= eve; else addedgelist(em, eve, eve->prev, NULL); phi+= phid; } /* extrude and rotate */ phi= M_PI/seg; q[0]= cos(phi); q[3]= sin(phi); q[1]=q[2]= 0; quat_to_mat3( cmat,q); for(a=0; a<seg; a++) { extrudeflag_vert(obedit, em, 2, nor, 0); // nor unused rotateflag(em, 2, v1->co, cmat); } removedoublesflag(em, 4, 0, 0.0001); /* and now do imat */ eve= em->verts.first; while(eve) { if(eve->f & SELECT) { mul_m4_v3(mat,eve->co); } eve= eve->next; } recalc_editnormals(em); break; case PRIM_ICOSPHERE: /* Icosphere */ { EditVert *eva[12]; EditEdge *eed; /* clear all flags */ eve= em->verts.first; while(eve) { eve->f= 0; eve= eve->next; } dia/=200; for(a=0;a<12;a++) { vec[0]= dia*icovert[a][0]; vec[1]= dia*icovert[a][1]; vec[2]= dia*icovert[a][2]; eva[a]= addvertlist(em, vec, NULL); eva[a]->f= 1+2; } for(a=0;a<20;a++) { EditFace *evtemp; v1= eva[ icoface[a][0] ]; v2= eva[ icoface[a][1] ]; v3= eva[ icoface[a][2] ]; evtemp = addfacelist(em, v1, v2, v3, 0, NULL, NULL); evtemp->e1->f = 1+2; evtemp->e2->f = 1+2; evtemp->e3->f = 1+2; } dia*=200; for(a=1; a<subdiv; a++) esubdivideflag(obedit, em, 2, dia, 0, B_SPHERE,1, SUBDIV_CORNER_PATH, 0); /* and now do imat */ eve= em->verts.first; while(eve) { if(eve->f & 2) { mul_m4_v3(mat,eve->co); } eve= eve->next; } // Clear the flag 2 from the edges for(eed=em->edges.first;eed;eed=eed->next){ if(eed->f & 2){ eed->f &= !2; } } } break; case PRIM_MONKEY: /* Monkey */ { //extern int monkeyo, monkeynv, monkeynf; //extern signed char monkeyf[][4]; //extern signed char monkeyv[][3]; EditVert **tv= MEM_mallocN(sizeof(*tv)*monkeynv*2, "tv"); int i; for (i=0; i<monkeynv; i++) { float v[3]; v[0]= (monkeyv[i][0]+127)/128.0, v[1]= monkeyv[i][1]/128.0, v[2]= monkeyv[i][2]/128.0; tv[i]= addvertlist(em, v, NULL); tv[i]->f |= SELECT; tv[monkeynv+i]= (fabs(v[0]= -v[0])<0.001)?tv[i]:addvertlist(em, v, NULL); tv[monkeynv+i]->f |= SELECT; } for (i=0; i<monkeynf; i++) { addfacelist(em, tv[monkeyf[i][0]+i-monkeyo], tv[monkeyf[i][1]+i-monkeyo], tv[monkeyf[i][2]+i-monkeyo], (monkeyf[i][3]!=monkeyf[i][2])?tv[monkeyf[i][3]+i-monkeyo]:NULL, NULL, NULL); addfacelist(em, tv[monkeynv+monkeyf[i][2]+i-monkeyo], tv[monkeynv+monkeyf[i][1]+i-monkeyo], tv[monkeynv+monkeyf[i][0]+i-monkeyo], (monkeyf[i][3]!=monkeyf[i][2])?tv[monkeynv+monkeyf[i][3]+i-monkeyo]:NULL, NULL, NULL); } MEM_freeN(tv); /* and now do imat */ for(eve= em->verts.first; eve; eve= eve->next) { if(eve->f & SELECT) { mul_m4_v3(mat,eve->co); } } recalc_editnormals(em); } break; default: /* all types except grid, sphere... */ if(type==PRIM_CONE); else if(ext==0) depth= 0.0f; /* first vertex at 0° for circular objects */ if( ELEM3(type, PRIM_CIRCLE,PRIM_CYLINDER,PRIM_CONE) ) phi = 0.0f; vtop= vdown= v1= v2= 0; for(b=0; b<=ext; b++) { for(a=0; a<tot; a++) { vec[0]= dia*sinf(phi); vec[1]= dia*cosf(phi); vec[2]= b?depth:-depth; mul_m4_v3(mat, vec); eve= addvertlist(em, vec, NULL); eve->f= SELECT; if(a==0) { if(b==0) v1= eve; else v2= eve; } phi+=phid; } } /* center vertices */ /* type PRIM_CONE can only have 1 one side filled * if the cone has no capping, dont add vtop */ if(type == PRIM_CONE || (fill && !ELEM(type, PRIM_PLANE, PRIM_CUBE))) { vec[0]= vec[1]= 0.0f; vec[2]= type==PRIM_CONE ? depth : -depth; mul_m4_v3(mat, vec); vdown= addvertlist(em, vec, NULL); if((ext || type==PRIM_CONE) && fill) { vec[0]= vec[1]= 0.0f; vec[2]= type==PRIM_CONE ? -depth : depth; mul_m4_v3(mat,vec); vtop= addvertlist(em, vec, NULL); } } else { vdown= v1; vtop= v2; } if(vtop) vtop->f= SELECT; if(vdown) vdown->f= SELECT; /* top and bottom face */ if(fill || type==PRIM_CONE) { if(tot==4 && ELEM(type, PRIM_PLANE, PRIM_CUBE)) { v3= v1->next->next; if(ext) v4= v2->next->next; addfacelist(em, v3, v1->next, v1, v3->next, NULL, NULL); if(ext) addfacelist(em, v2, v2->next, v4, v4->next, NULL, NULL); } else { v3= v1; v4= v2; for(a=1; a<tot; a++) { addfacelist(em, vdown, v3, v3->next, 0, NULL, NULL); v3= v3->next; if(ext && fill) { addfacelist(em, vtop, v4, v4->next, 0, NULL, NULL); v4= v4->next; } } if(!ELEM(type, PRIM_PLANE, PRIM_CUBE)) { addfacelist(em, vdown, v3, v1, 0, NULL, NULL); if(ext) addfacelist(em, vtop, v4, v2, 0, NULL, NULL); } } } else if(type==PRIM_CIRCLE) { /* we need edges for a circle */ v3= v1; for(a=1;a<tot;a++) { addedgelist(em, v3, v3->next, NULL); v3= v3->next; } addedgelist(em, v3, v1, NULL); } /* side faces */ if(ext) { v3= v1; v4= v2; for(a=1; a<tot; a++) { addfacelist(em, v3, v3->next, v4->next, v4, NULL, NULL); v3= v3->next; v4= v4->next; } addfacelist(em, v3, v1, v2, v4, NULL, NULL); } else if(fill && type==PRIM_CONE) { /* add the bottom flat area of the cone * if capping is disabled dont bother */ v3= v1; for(a=1; a<tot; a++) { addfacelist(em, vtop, v3->next, v3, 0, NULL, NULL); v3= v3->next; } addfacelist(em, vtop, v1, v3, 0, NULL, NULL); } } EM_stats_update(em); /* simple selection flush OK, based on fact it's a single model */ EM_select_flush(em); /* flushes vertex -> edge -> face selection */ if(!ELEM5(type, PRIM_GRID, PRIM_PLANE, PRIM_ICOSPHERE, PRIM_UVSPHERE, PRIM_MONKEY)) EM_recalc_normal_direction(em, FALSE, TRUE); /* otherwise monkey has eyes in wrong direction */ BKE_mesh_end_editmesh(obedit->data, em); }
/* Object Surface Area Heuristic splitter */ int rtbuild_heuristic_object_split(RTBuilder *b, int nchilds) { int size = rtbuild_size(b); assert(nchilds == 2); assert(size > 1); int baxis = -1, boffset = 0; if (size > nchilds) { float bcost = FLT_MAX; baxis = -1, boffset = size / 2; SweepCost *sweep = (SweepCost *)MEM_mallocN(sizeof(SweepCost) * size, "RTBuilder.HeuristicSweep"); for (int axis = 0; axis < 3; axis++) { SweepCost sweep_left; RTBuilder::Object **obj = b->sorted_begin[axis]; // float right_cost = 0; for (int i = size - 1; i >= 0; i--) { if (i == size - 1) { copy_v3_v3(sweep[i].bb, obj[i]->bb); copy_v3_v3(sweep[i].bb + 3, obj[i]->bb + 3); sweep[i].cost = obj[i]->cost; } else { sweep[i].bb[0] = min_ff(obj[i]->bb[0], sweep[i + 1].bb[0]); sweep[i].bb[1] = min_ff(obj[i]->bb[1], sweep[i + 1].bb[1]); sweep[i].bb[2] = min_ff(obj[i]->bb[2], sweep[i + 1].bb[2]); sweep[i].bb[3] = max_ff(obj[i]->bb[3], sweep[i + 1].bb[3]); sweep[i].bb[4] = max_ff(obj[i]->bb[4], sweep[i + 1].bb[4]); sweep[i].bb[5] = max_ff(obj[i]->bb[5], sweep[i + 1].bb[5]); sweep[i].cost = obj[i]->cost + sweep[i + 1].cost; } // right_cost += obj[i]->cost; } sweep_left.bb[0] = obj[0]->bb[0]; sweep_left.bb[1] = obj[0]->bb[1]; sweep_left.bb[2] = obj[0]->bb[2]; sweep_left.bb[3] = obj[0]->bb[3]; sweep_left.bb[4] = obj[0]->bb[4]; sweep_left.bb[5] = obj[0]->bb[5]; sweep_left.cost = obj[0]->cost; // right_cost -= obj[0]->cost; if (right_cost < 0) right_cost = 0; for (int i = 1; i < size; i++) { //Worst case heuristic (cost of each child is linear) float hcost, left_side, right_side; // not using log seems to have no impact on raytracing perf, but // makes tree construction quicker, left out for now to test (brecht) // left_side = bb_area(sweep_left.bb, sweep_left.bb + 3) * (sweep_left.cost + logf((float)i)); // right_side = bb_area(sweep[i].bb, sweep[i].bb + 3) * (sweep[i].cost + logf((float)size - i)); left_side = bb_area(sweep_left.bb, sweep_left.bb + 3) * (sweep_left.cost); right_side = bb_area(sweep[i].bb, sweep[i].bb + 3) * (sweep[i].cost); hcost = left_side + right_side; assert(left_side >= 0); assert(right_side >= 0); if (left_side > bcost) break; //No way we can find a better heuristic in this axis assert(hcost >= 0); // this makes sure the tree built is the same whatever is the order of the sorting axis if (hcost < bcost || (hcost == bcost && axis < baxis)) { bcost = hcost; baxis = axis; boffset = i; } DO_MIN(obj[i]->bb, sweep_left.bb); DO_MAX(obj[i]->bb + 3, sweep_left.bb + 3); sweep_left.cost += obj[i]->cost; // right_cost -= obj[i]->cost; if (right_cost < 0) right_cost = 0; } //assert(baxis >= 0 && baxis < 3); if (!(baxis >= 0 && baxis < 3)) baxis = 0; } MEM_freeN(sweep); } else if (size == 2) { baxis = 0; boffset = 1; } else if (size == 1) { b->child_offset[0] = 0; b->child_offset[1] = 1; return 1; } b->child_offset[0] = 0; b->child_offset[1] = boffset; b->child_offset[2] = size; /* Adjust sorted arrays for childs */ for (int i = 0; i < boffset; i++) b->sorted_begin[baxis][i]->selected = true; for (int i = boffset; i < size; i++) b->sorted_begin[baxis][i]->selected = false; for (int i = 0; i < 3; i++) std::stable_partition(b->sorted_begin[i], b->sorted_end[i], selected_node); return nchilds; }
size_t blf_font_width_to_rstrlen(FontBLF *font, const char *str, size_t len, float width, float *r_width) { unsigned int c; GlyphBLF *g, *g_prev = NULL; FT_Vector delta; int pen_x = 0; size_t i = 0, i_prev; GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table; const int width_i = (int)width + 1; int width_new; bool is_malloc; int (*width_accum)[2]; int width_accum_ofs = 0; BLF_KERNING_VARS(font, has_kerning, kern_mode); /* skip allocs in simple cases */ len = BLI_strnlen(str, len); if (width_i <= 1 || len == 0) { if (r_width) { *r_width = 0.0f; } return len; } if (len < 2048) { width_accum = BLI_array_alloca(width_accum, len); is_malloc = false; } else { width_accum = MEM_mallocN(sizeof(*width_accum) * len, __func__); is_malloc = true; } blf_font_ensure_ascii_table(font); while ((i < len) && str[i]) { BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table); if (UNLIKELY(c == BLI_UTF8_ERR)) break; if (UNLIKELY(g == NULL)) continue; if (has_kerning) BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x); pen_x += g->advance_i; width_accum[width_accum_ofs][0] = (int)i; width_accum[width_accum_ofs][1] = pen_x; width_accum_ofs++; g_prev = g; } if (pen_x > width_i && width_accum_ofs != 0) { const int min_x = pen_x - width_i; /* search backwards */ width_new = pen_x; while (width_accum_ofs-- > 0) { if (min_x > width_accum[width_accum_ofs][1]) { break; } } width_accum_ofs++; width_new = pen_x - width_accum[width_accum_ofs][1]; i_prev = (size_t)width_accum[width_accum_ofs][0]; } else { width_new = pen_x; i_prev = 0; } if (is_malloc) { MEM_freeN(width_accum); } if (r_width) { *r_width = (float)width_new; } return i_prev; }
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; /* 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; if(cu->editnurb) nu= cu->editnurb->first; else nu= cu->nurb.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), "path"); /* 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) VecSubf(xyz, bevpfirst->vec, bevp->vec); else VecSubf(xyz, (bevp+1)->vec, bevp->vec); *fp= *(fp-1)+VecLength(xyz); bevp++; } path->totdist= *fp; /* the path verts in path->data */ /* now also with TILT value */ pp= path->data = (PathPoint *)MEM_callocN(sizeof(PathPoint)*4*path->len, "pathdata"); // XXX - why *4? - in 2.4x each element was 4 and the size was 16, so better leave for now - Campbell 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; VecLerpf(pp->vec, bevp->vec, bevpn->vec, fac2); pp->vec[3]= fac1*bevp->alfa + fac2*bevpn->alfa; pp->radius= fac1*bevp->radius + fac2*bevpn->radius; QuatInterpol(pp->quat, bevp->quat, bevpn->quat, fac2); NormalQuat(pp->quat); pp++; } MEM_freeN(dist); }
static void warpModifier_do(WarpModifierData *wmd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { float obinv[4][4]; float mat_from[4][4]; float mat_from_inv[4][4]; float mat_to[4][4]; float mat_unit[4][4]; float mat_final[4][4]; float tmat[4][4]; float strength = wmd->strength; float fac = 1.0f, weight; int i; int defgrp_index; MDeformVert *dvert, *dv = NULL; float (*tex_co)[3] = NULL; if (!(wmd->object_from && wmd->object_to)) return; modifier_get_vgroup(ob, dm, wmd->defgrp_name, &dvert, &defgrp_index); if (wmd->curfalloff == NULL) /* should never happen, but bad lib linking could cause it */ wmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); if (wmd->curfalloff) { curvemapping_initialize(wmd->curfalloff); } invert_m4_m4(obinv, ob->obmat); mul_m4_m4m4(mat_from, obinv, wmd->object_from->obmat); mul_m4_m4m4(mat_to, obinv, wmd->object_to->obmat); invert_m4_m4(tmat, mat_from); // swap? mul_m4_m4m4(mat_final, tmat, mat_to); invert_m4_m4(mat_from_inv, mat_from); unit_m4(mat_unit); if (strength < 0.0f) { float loc[3]; strength = -strength; /* inverted location is not useful, just use the negative */ copy_v3_v3(loc, mat_final[3]); invert_m4(mat_final); negate_v3_v3(mat_final[3], loc); } weight = strength; if (wmd->texture) { tex_co = MEM_mallocN(sizeof(*tex_co) * numVerts, "warpModifier_do tex_co"); get_texture_coords((MappingInfoModifierData *)wmd, ob, dm, vertexCos, tex_co, numVerts); modifier_init_texture(wmd->modifier.scene, wmd->texture); } for (i = 0; i < numVerts; i++) { float *co = vertexCos[i]; if (wmd->falloff_type == eWarp_Falloff_None || ((fac = len_v3v3(co, mat_from[3])) < wmd->falloff_radius && (fac = (wmd->falloff_radius - fac) / wmd->falloff_radius))) { /* skip if no vert group found */ if (dvert && defgrp_index != -1) { dv = &dvert[i]; if (dv) { weight = defvert_find_weight(dv, defgrp_index) * strength; if (weight <= 0.0f) /* Should never occure... */ continue; } } /* closely match PROP_SMOOTH and similar */ switch (wmd->falloff_type) { case eWarp_Falloff_None: fac = 1.0f; break; case eWarp_Falloff_Curve: fac = curvemapping_evaluateF(wmd->curfalloff, 0, fac); break; case eWarp_Falloff_Sharp: fac = fac * fac; break; case eWarp_Falloff_Smooth: fac = 3.0f * fac * fac - 2.0f * fac * fac * fac; break; case eWarp_Falloff_Root: fac = (float)sqrt(fac); break; case eWarp_Falloff_Linear: /* pass */ break; case eWarp_Falloff_Const: fac = 1.0f; break; case eWarp_Falloff_Sphere: fac = (float)sqrt(2 * fac - fac * fac); break; } fac *= weight; if (tex_co) { TexResult texres; texres.nor = NULL; BKE_texture_get_value(wmd->modifier.scene, wmd->texture, tex_co[i], &texres, false); fac *= texres.tin; } /* into the 'from' objects space */ mul_m4_v3(mat_from_inv, co); if (fac >= 1.0f) { mul_m4_v3(mat_final, co); } else if (fac > 0.0f) { if (wmd->flag & MOD_WARP_VOLUME_PRESERVE) { /* interpolate the matrix for nicer locations */ blend_m4_m4m4(tmat, mat_unit, mat_final, fac); mul_m4_v3(tmat, co); } else { float tvec[3]; mul_v3_m4v3(tvec, mat_final, co); interp_v3_v3v3(co, co, tvec, fac); } } /* out of the 'from' objects space */ mul_m4_v3(mat_from, co); } } if (tex_co) MEM_freeN(tex_co); }
/** * Take as inputs two sets of verts, to be processed for detection of doubles and mapping. * Each set of verts is defined by its start within mverts array and its num_verts; * It builds a mapping for all vertices within source, to vertices within target, or -1 if no double found * The int doubles_map[num_verts_source] array must have been allocated by caller. */ static void dm_mvert_map_doubles( int *doubles_map, const MVert *mverts, const int target_start, const int target_num_verts, const int source_start, const int source_num_verts, const float dist, const bool with_follow) { const float dist3 = ((float)M_SQRT3 + 0.00005f) * dist; /* Just above sqrt(3) */ int i_source, i_target, i_target_low_bound, target_end, source_end; SortVertsElem *sorted_verts_target, *sorted_verts_source; SortVertsElem *sve_source, *sve_target, *sve_target_low_bound; bool target_scan_completed; target_end = target_start + target_num_verts; source_end = source_start + source_num_verts; /* build array of MVerts to be tested for merging */ sorted_verts_target = MEM_mallocN(sizeof(SortVertsElem) * target_num_verts, __func__); sorted_verts_source = MEM_mallocN(sizeof(SortVertsElem) * source_num_verts, __func__); /* Copy target vertices index and cos into SortVertsElem array */ svert_from_mvert(sorted_verts_target, mverts + target_start, target_start, target_end); /* Copy source vertices index and cos into SortVertsElem array */ svert_from_mvert(sorted_verts_source, mverts + source_start, source_start, source_end); /* sort arrays according to sum of vertex coordinates (sumco) */ qsort(sorted_verts_target, target_num_verts, sizeof(SortVertsElem), svert_sum_cmp); qsort(sorted_verts_source, source_num_verts, sizeof(SortVertsElem), svert_sum_cmp); sve_target_low_bound = sorted_verts_target; i_target_low_bound = 0; target_scan_completed = false; /* Scan source vertices, in SortVertsElem sorted array, */ /* all the while maintaining the lower bound of possible doubles in target vertices */ for (i_source = 0, sve_source = sorted_verts_source; i_source < source_num_verts; i_source++, sve_source++) { bool double_found; float sve_source_sumco; /* If source has already been assigned to a target (in an earlier call, with other chunks) */ if (doubles_map[sve_source->vertex_num] != -1) { continue; } /* If target fully scanned already, then all remaining source vertices cannot have a double */ if (target_scan_completed) { doubles_map[sve_source->vertex_num] = -1; continue; } sve_source_sumco = sum_v3(sve_source->co); /* Skip all target vertices that are more than dist3 lower in terms of sumco */ /* and advance the overall lower bound, applicable to all remaining vertices as well. */ while ((i_target_low_bound < target_num_verts) && (sve_target_low_bound->sum_co < sve_source_sumco - dist3)) { i_target_low_bound++; sve_target_low_bound++; } /* If end of target list reached, then no more possible doubles */ if (i_target_low_bound >= target_num_verts) { doubles_map[sve_source->vertex_num] = -1; target_scan_completed = true; continue; } /* Test target candidates starting at the low bound of possible doubles, ordered in terms of sumco */ i_target = i_target_low_bound; sve_target = sve_target_low_bound; /* i_target will scan vertices in the [v_source_sumco - dist3; v_source_sumco + dist3] range */ double_found = false; while ((i_target < target_num_verts) && (sve_target->sum_co <= sve_source_sumco + dist3)) { /* Testing distance for candidate double in target */ /* v_target is within dist3 of v_source in terms of sumco; check real distance */ if (compare_len_v3v3(sve_source->co, sve_target->co, dist)) { /* Double found */ /* If double target is itself already mapped to other vertex, * behavior depends on with_follow option */ int target_vertex = sve_target->vertex_num; if (doubles_map[target_vertex] != -1) { if (with_follow) { /* with_follow option: map to initial target */ target_vertex = doubles_map[target_vertex]; } else { /* not with_follow: if target is mapped, then we do not map source, and stop searching */ break; } } doubles_map[sve_source->vertex_num] = target_vertex; double_found = true; break; } i_target++; sve_target++; } /* End of candidate scan: if none found then no doubles */ if (!double_found) { doubles_map[sve_source->vertex_num] = -1; } } MEM_freeN(sorted_verts_source); MEM_freeN(sorted_verts_target); }
static struct ImageUI_Data *ui_imageuser_data_copy(const struct ImageUI_Data *rnd_pt_src) { struct ImageUI_Data *rnd_pt_dst = MEM_mallocN(sizeof(*rnd_pt_src), __func__); memcpy(rnd_pt_dst, rnd_pt_src, sizeof(*rnd_pt_src)); return rnd_pt_dst; }
static DerivedMesh *arrayModifier_doArray( ArrayModifierData *amd, Scene *scene, Object *ob, DerivedMesh *dm, ModifierApplyFlag flag) { const float eps = 1e-6f; const MVert *src_mvert; MVert *mv, *mv_prev, *result_dm_verts; MEdge *me; MLoop *ml; MPoly *mp; int i, j, c, count; float length = amd->length; /* offset matrix */ float offset[4][4]; float scale[3]; bool offset_has_scale; float current_offset[4][4]; float final_offset[4][4]; int *full_doubles_map = NULL; int tot_doubles; const bool use_merge = (amd->flags & MOD_ARR_MERGE) != 0; const bool use_recalc_normals = (dm->dirty & DM_DIRTY_NORMALS) || use_merge; const bool use_offset_ob = ((amd->offset_type & MOD_ARR_OFF_OBJ) && amd->offset_ob); /* allow pole vertices to be used by many faces */ const bool with_follow = use_offset_ob; int start_cap_nverts = 0, start_cap_nedges = 0, start_cap_npolys = 0, start_cap_nloops = 0; int end_cap_nverts = 0, end_cap_nedges = 0, end_cap_npolys = 0, end_cap_nloops = 0; int result_nverts = 0, result_nedges = 0, result_npolys = 0, result_nloops = 0; int chunk_nverts, chunk_nedges, chunk_nloops, chunk_npolys; int first_chunk_start, first_chunk_nverts, last_chunk_start, last_chunk_nverts; DerivedMesh *result, *start_cap_dm = NULL, *end_cap_dm = NULL; chunk_nverts = dm->getNumVerts(dm); chunk_nedges = dm->getNumEdges(dm); chunk_nloops = dm->getNumLoops(dm); chunk_npolys = dm->getNumPolys(dm); count = amd->count; if (amd->start_cap && amd->start_cap != ob && amd->start_cap->type == OB_MESH) { start_cap_dm = get_dm_for_modifier(amd->start_cap, flag); if (start_cap_dm) { start_cap_nverts = start_cap_dm->getNumVerts(start_cap_dm); start_cap_nedges = start_cap_dm->getNumEdges(start_cap_dm); start_cap_nloops = start_cap_dm->getNumLoops(start_cap_dm); start_cap_npolys = start_cap_dm->getNumPolys(start_cap_dm); } } if (amd->end_cap && amd->end_cap != ob && amd->end_cap->type == OB_MESH) { end_cap_dm = get_dm_for_modifier(amd->end_cap, flag); if (end_cap_dm) { end_cap_nverts = end_cap_dm->getNumVerts(end_cap_dm); end_cap_nedges = end_cap_dm->getNumEdges(end_cap_dm); end_cap_nloops = end_cap_dm->getNumLoops(end_cap_dm); end_cap_npolys = end_cap_dm->getNumPolys(end_cap_dm); } } /* Build up offset array, cumulating all settings options */ unit_m4(offset); src_mvert = dm->getVertArray(dm); if (amd->offset_type & MOD_ARR_OFF_CONST) add_v3_v3v3(offset[3], offset[3], amd->offset); if (amd->offset_type & MOD_ARR_OFF_RELATIVE) { for (j = 0; j < 3; j++) offset[3][j] += amd->scale[j] * vertarray_size(src_mvert, chunk_nverts, j); } if (use_offset_ob) { float obinv[4][4]; float result_mat[4][4]; if (ob) invert_m4_m4(obinv, ob->obmat); else unit_m4(obinv); mul_m4_series(result_mat, offset, obinv, amd->offset_ob->obmat); copy_m4_m4(offset, result_mat); } /* Check if there is some scaling. If scaling, then we will not translate mapping */ mat4_to_size(scale, offset); offset_has_scale = !is_one_v3(scale); if (amd->fit_type == MOD_ARR_FITCURVE && amd->curve_ob) { Curve *cu = amd->curve_ob->data; if (cu) { #ifdef CYCLIC_DEPENDENCY_WORKAROUND if (amd->curve_ob->curve_cache == NULL) { BKE_displist_make_curveTypes(scene, amd->curve_ob, false); } #endif if (amd->curve_ob->curve_cache && amd->curve_ob->curve_cache->path) { float scale = mat4_to_scale(amd->curve_ob->obmat); length = scale * amd->curve_ob->curve_cache->path->totdist; } } } /* calculate the maximum number of copies which will fit within the * prescribed length */ if (amd->fit_type == MOD_ARR_FITLENGTH || amd->fit_type == MOD_ARR_FITCURVE) { float dist = len_v3(offset[3]); if (dist > eps) { /* this gives length = first copy start to last copy end * add a tiny offset for floating point rounding errors */ count = (length + eps) / dist; } else { /* if the offset has no translation, just make one copy */ count = 1; } } if (count < 1) count = 1; /* The number of verts, edges, loops, polys, before eventually merging doubles */ result_nverts = chunk_nverts * count + start_cap_nverts + end_cap_nverts; result_nedges = chunk_nedges * count + start_cap_nedges + end_cap_nedges; result_nloops = chunk_nloops * count + start_cap_nloops + end_cap_nloops; result_npolys = chunk_npolys * count + start_cap_npolys + end_cap_npolys; /* Initialize a result dm */ result = CDDM_from_template(dm, result_nverts, result_nedges, 0, result_nloops, result_npolys); result_dm_verts = CDDM_get_verts(result); if (use_merge) { /* Will need full_doubles_map for handling merge */ full_doubles_map = MEM_mallocN(sizeof(int) * result_nverts, "mod array doubles map"); fill_vn_i(full_doubles_map, result_nverts, -1); } /* copy customdata to original geometry */ DM_copy_vert_data(dm, result, 0, 0, chunk_nverts); DM_copy_edge_data(dm, result, 0, 0, chunk_nedges); DM_copy_loop_data(dm, result, 0, 0, chunk_nloops); DM_copy_poly_data(dm, result, 0, 0, chunk_npolys); /* subsurf for eg wont have mesh data in the * now add mvert/medge/mface layers */ if (!CustomData_has_layer(&dm->vertData, CD_MVERT)) { dm->copyVertArray(dm, result_dm_verts); } if (!CustomData_has_layer(&dm->edgeData, CD_MEDGE)) { dm->copyEdgeArray(dm, CDDM_get_edges(result)); } if (!CustomData_has_layer(&dm->polyData, CD_MPOLY)) { dm->copyLoopArray(dm, CDDM_get_loops(result)); dm->copyPolyArray(dm, CDDM_get_polys(result)); } /* Remember first chunk, in case of cap merge */ first_chunk_start = 0; first_chunk_nverts = chunk_nverts; unit_m4(current_offset); for (c = 1; c < count; c++) { /* copy customdata to new geometry */ DM_copy_vert_data(result, result, 0, c * chunk_nverts, chunk_nverts); DM_copy_edge_data(result, result, 0, c * chunk_nedges, chunk_nedges); DM_copy_loop_data(result, result, 0, c * chunk_nloops, chunk_nloops); DM_copy_poly_data(result, result, 0, c * chunk_npolys, chunk_npolys); mv_prev = result_dm_verts; mv = mv_prev + c * chunk_nverts; /* recalculate cumulative offset here */ mul_m4_m4m4(current_offset, current_offset, offset); /* apply offset to all new verts */ for (i = 0; i < chunk_nverts; i++, mv++, mv_prev++) { mul_m4_v3(current_offset, mv->co); /* We have to correct normals too, if we do not tag them as dirty! */ if (!use_recalc_normals) { float no[3]; normal_short_to_float_v3(no, mv->no); mul_mat3_m4_v3(current_offset, no); normalize_v3(no); normal_float_to_short_v3(mv->no, no); } } /* adjust edge vertex indices */ me = CDDM_get_edges(result) + c * chunk_nedges; for (i = 0; i < chunk_nedges; i++, me++) { me->v1 += c * chunk_nverts; me->v2 += c * chunk_nverts; } mp = CDDM_get_polys(result) + c * chunk_npolys; for (i = 0; i < chunk_npolys; i++, mp++) { mp->loopstart += c * chunk_nloops; } /* adjust loop vertex and edge indices */ ml = CDDM_get_loops(result) + c * chunk_nloops; for (i = 0; i < chunk_nloops; i++, ml++) { ml->v += c * chunk_nverts; ml->e += c * chunk_nedges; } /* Handle merge between chunk n and n-1 */ if (use_merge && (c >= 1)) { if (!offset_has_scale && (c >= 2)) { /* Mapping chunk 3 to chunk 2 is a translation of mapping 2 to 1 * ... that is except if scaling makes the distance grow */ int k; int this_chunk_index = c * chunk_nverts; int prev_chunk_index = (c - 1) * chunk_nverts; for (k = 0; k < chunk_nverts; k++, this_chunk_index++, prev_chunk_index++) { int target = full_doubles_map[prev_chunk_index]; if (target != -1) { target += chunk_nverts; /* translate mapping */ if (full_doubles_map[target] != -1) { if (with_follow) { target = full_doubles_map[target]; } else { /* The rule here is to not follow mapping to chunk N-2, which could be too far * so if target vertex was itself mapped, then this vertex is not mapped */ target = -1; } } } full_doubles_map[this_chunk_index] = target; } } else { dm_mvert_map_doubles( full_doubles_map, result_dm_verts, (c - 1) * chunk_nverts, chunk_nverts, c * chunk_nverts, chunk_nverts, amd->merge_dist, with_follow); } } } last_chunk_start = (count - 1) * chunk_nverts; last_chunk_nverts = chunk_nverts; copy_m4_m4(final_offset, current_offset); if (use_merge && (amd->flags & MOD_ARR_MERGEFINAL) && (count > 1)) { /* Merge first and last copies */ dm_mvert_map_doubles( full_doubles_map, result_dm_verts, last_chunk_start, last_chunk_nverts, first_chunk_start, first_chunk_nverts, amd->merge_dist, with_follow); } /* start capping */ if (start_cap_dm) { float start_offset[4][4]; int start_cap_start = result_nverts - start_cap_nverts - end_cap_nverts; invert_m4_m4(start_offset, offset); dm_merge_transform( result, start_cap_dm, start_offset, result_nverts - start_cap_nverts - end_cap_nverts, result_nedges - start_cap_nedges - end_cap_nedges, result_nloops - start_cap_nloops - end_cap_nloops, result_npolys - start_cap_npolys - end_cap_npolys, start_cap_nverts, start_cap_nedges, start_cap_nloops, start_cap_npolys); /* Identify doubles with first chunk */ if (use_merge) { dm_mvert_map_doubles( full_doubles_map, result_dm_verts, first_chunk_start, first_chunk_nverts, start_cap_start, start_cap_nverts, amd->merge_dist, false); } } if (end_cap_dm) { float end_offset[4][4]; int end_cap_start = result_nverts - end_cap_nverts; mul_m4_m4m4(end_offset, current_offset, offset); dm_merge_transform( result, end_cap_dm, end_offset, result_nverts - end_cap_nverts, result_nedges - end_cap_nedges, result_nloops - end_cap_nloops, result_npolys - end_cap_npolys, end_cap_nverts, end_cap_nedges, end_cap_nloops, end_cap_npolys); /* Identify doubles with last chunk */ if (use_merge) { dm_mvert_map_doubles( full_doubles_map, result_dm_verts, last_chunk_start, last_chunk_nverts, end_cap_start, end_cap_nverts, amd->merge_dist, false); } } /* done capping */ /* Handle merging */ tot_doubles = 0; if (use_merge) { for (i = 0; i < result_nverts; i++) { if (full_doubles_map[i] != -1) { if (i == full_doubles_map[i]) { full_doubles_map[i] = -1; } else { tot_doubles++; } } } if (tot_doubles > 0) { result = CDDM_merge_verts(result, full_doubles_map, tot_doubles, CDDM_MERGE_VERTS_DUMP_IF_EQUAL); } MEM_freeN(full_doubles_map); } /* In case org dm has dirty normals, or we made some merging, mark normals as dirty in new dm! * TODO: we may need to set other dirty flags as well? */ if (use_recalc_normals) { result->dirty |= DM_DIRTY_NORMALS; } return result; }
/* render call to fill in strands */ int zbuffer_strands_abuf(Render *re, RenderPart *pa, APixstrand *apixbuf, ListBase *apsmbase, unsigned int lay, int UNUSED(negzmask), float winmat[][4], int winx, int winy, int UNUSED(sample), float (*jit)[2], float clipcrop, int shadow, StrandShadeCache *cache) { ObjectRen *obr; ObjectInstanceRen *obi; ZSpan zspan; StrandRen *strand=0; StrandVert *svert; StrandBound *sbound; StrandPart spart; StrandSegment sseg; StrandSortSegment *sortsegments = NULL, *sortseg, *firstseg; MemArena *memarena; float z[4], bounds[4], obwinmat[4][4]; int a, b, c, i, totsegment, clip[4]; if (re->test_break(re->tbh)) return 0; if (re->totstrand == 0) return 0; /* setup StrandPart */ memset(&spart, 0, sizeof(spart)); spart.re= re; spart.rectx= pa->rectx; spart.recty= pa->recty; spart.apixbuf= apixbuf; spart.zspan= &zspan; spart.rectdaps= pa->rectdaps; spart.rectz= pa->rectz; spart.rectmask= pa->rectmask; spart.cache= cache; spart.shadow= shadow; spart.jit= jit; zbuf_alloc_span(&zspan, pa->rectx, pa->recty, clipcrop); /* needed for transform from hoco to zbuffer co */ zspan.zmulx= ((float)winx)/2.0f; zspan.zmuly= ((float)winy)/2.0f; zspan.zofsx= -pa->disprect.xmin; zspan.zofsy= -pa->disprect.ymin; /* to center the sample position */ if (!shadow) { zspan.zofsx -= 0.5f; zspan.zofsy -= 0.5f; } zspan.apsmbase= apsmbase; /* clipping setup */ bounds[0]= (2*pa->disprect.xmin - winx-1)/(float)winx; bounds[1]= (2*pa->disprect.xmax - winx+1)/(float)winx; bounds[2]= (2*pa->disprect.ymin - winy-1)/(float)winy; bounds[3]= (2*pa->disprect.ymax - winy+1)/(float)winy; memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "strand sort arena"); firstseg= NULL; totsegment= 0; /* for all object instances */ for (obi=re->instancetable.first, i=0; obi; obi=obi->next, i++) { Material *ma; float widthx, widthy; obr= obi->obr; if (!obr->strandbuf || !(obr->strandbuf->lay & lay)) continue; /* compute matrix and try clipping whole object */ if (obi->flag & R_TRANSFORMED) mult_m4_m4m4(obwinmat, winmat, obi->mat); else copy_m4_m4(obwinmat, winmat); /* test if we should skip it */ ma = obr->strandbuf->ma; if (shadow && !(ma->mode & MA_SHADBUF)) continue; else if (!shadow && (ma->mode & MA_ONLYCAST)) continue; if (clip_render_object(obi->obr->boundbox, bounds, obwinmat)) continue; widthx= obr->strandbuf->maxwidth*obwinmat[0][0]; widthy= obr->strandbuf->maxwidth*obwinmat[1][1]; /* for each bounding box containing a number of strands */ sbound= obr->strandbuf->bound; for (c=0; c<obr->strandbuf->totbound; c++, sbound++) { if (clip_render_object(sbound->boundbox, bounds, obwinmat)) continue; /* for each strand in this bounding box */ for (a=sbound->start; a<sbound->end; a++) { strand= RE_findOrAddStrand(obr, a); svert= strand->vert; /* keep clipping and z depth for 4 control points */ clip[1]= strand_test_clip(obwinmat, &zspan, bounds, svert->co, &z[1], widthx, widthy); clip[2]= strand_test_clip(obwinmat, &zspan, bounds, (svert+1)->co, &z[2], widthx, widthy); clip[0]= clip[1]; z[0]= z[1]; for (b=0; b<strand->totvert-1; b++, svert++) { /* compute 4th point clipping and z depth */ if (b < strand->totvert-2) { clip[3]= strand_test_clip(obwinmat, &zspan, bounds, (svert+2)->co, &z[3], widthx, widthy); } else { clip[3]= clip[2]; z[3]= z[2]; } /* check clipping and add to sortsegments buffer */ if (!(clip[0] & clip[1] & clip[2] & clip[3])) { sortseg= BLI_memarena_alloc(memarena, sizeof(StrandSortSegment)); sortseg->obi= i; sortseg->strand= strand->index; sortseg->segment= b; sortseg->z= 0.5f*(z[1] + z[2]); sortseg->next= firstseg; firstseg= sortseg; totsegment++; } /* shift clipping and z depth */ clip[0]= clip[1]; z[0]= z[1]; clip[1]= clip[2]; z[1]= z[2]; clip[2]= clip[3]; z[2]= z[3]; } } } } if (!re->test_break(re->tbh)) { /* convert list to array and sort */ sortsegments= MEM_mallocN(sizeof(StrandSortSegment)*totsegment, "StrandSortSegment"); for (a=0, sortseg=firstseg; a<totsegment; a++, sortseg=sortseg->next) sortsegments[a]= *sortseg; qsort(sortsegments, totsegment, sizeof(StrandSortSegment), compare_strand_segment); } BLI_memarena_free(memarena); spart.totapixbuf= MEM_callocN(sizeof(int)*pa->rectx*pa->recty, "totapixbuf"); if (!re->test_break(re->tbh)) { /* render segments in sorted order */ sortseg= sortsegments; for (a=0; a<totsegment; a++, sortseg++) { if (re->test_break(re->tbh)) break; obi= &re->objectinstance[sortseg->obi]; obr= obi->obr; sseg.obi= obi; sseg.strand= RE_findOrAddStrand(obr, sortseg->strand); sseg.buffer= sseg.strand->buffer; sseg.sqadaptcos= sseg.buffer->adaptcos; sseg.sqadaptcos *= sseg.sqadaptcos; svert= sseg.strand->vert + sortseg->segment; sseg.v[0]= (sortseg->segment > 0)? (svert-1): svert; sseg.v[1]= svert; sseg.v[2]= svert+1; sseg.v[3]= (sortseg->segment < sseg.strand->totvert-2)? svert+2: svert+1; sseg.shaded= 0; spart.segment= &sseg; render_strand_segment(re, winmat, &spart, &zspan, 1, &sseg); } } if (sortsegments) MEM_freeN(sortsegments); MEM_freeN(spart.totapixbuf); zbuf_free_span(&zspan); return totsegment; }
static int preprocess_include(char *maindata, int len) { int a, newlen, comment = 0; char *cp, *temp, *md; /* note: len + 1, last character is a dummy to prevent * comparisons using uninitialized memory */ temp = MEM_mallocN(len + 1, "preprocess_include"); temp[len] = ' '; memcpy(temp, maindata, len); /* remove all c++ comments */ /* replace all enters/tabs/etc with spaces */ cp = temp; a = len; comment = 0; while (a--) { if (cp[0] == '/' && cp[1] == '/') { comment = 1; } else if (*cp < 32) { comment = 0; } if (comment || *cp < 32 || *cp > 128) *cp = 32; cp++; } /* data from temp copy to maindata, remove comments and double spaces */ cp = temp; md = maindata; newlen = 0; comment = 0; a = len; while (a--) { if (cp[0] == '/' && cp[1] == '*') { comment = 1; cp[0] = cp[1] = 32; } if (cp[0] == '*' && cp[1] == '/') { comment = 0; cp[0] = cp[1] = 32; } /* do not copy when: */ if (comment) { /* pass */ } else if (cp[0] == ' ' && cp[1] == ' ') { /* pass */ } else if (cp[-1] == '*' && cp[0] == ' ') { /* pointers with a space */ } /* skip special keywords */ else if (strncmp("DNA_DEPRECATED", cp, 14) == 0) { /* single values are skipped already, so decrement 1 less */ a -= 13; cp += 13; } else { md[0] = cp[0]; md++; newlen++; } cp++; } MEM_freeN(temp); return newlen; }
static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob), DerivedMesh *derivedData, ModifierApplyFlag UNUSED(flag)) { DerivedMesh *dm = derivedData; DerivedMesh *result; BuildModifierData *bmd = (BuildModifierData *) md; int i, j, k; int numFaces_dst, numEdges_dst, numLoops_dst = 0; int *vertMap, *edgeMap, *faceMap; float frac; MPoly *mpoly_dst; MLoop *ml_dst, *ml_src /*, *mloop_dst */; GHashIterator *hashIter; /* maps vert indices in old mesh to indices in new mesh */ GHash *vertHash = BLI_ghash_int_new("build ve apply gh"); /* maps edge indices in new mesh to indices in old mesh */ GHash *edgeHash = BLI_ghash_int_new("build ed apply gh"); GHash *edgeHash2 = BLI_ghash_int_new("build ed apply gh"); const int numVert_src = dm->getNumVerts(dm); const int numEdge_src = dm->getNumEdges(dm); const int numPoly_src = dm->getNumPolys(dm); MPoly *mpoly_src = dm->getPolyArray(dm); MLoop *mloop_src = dm->getLoopArray(dm); MEdge *medge_src = dm->getEdgeArray(dm); MVert *mvert_src = dm->getVertArray(dm); vertMap = MEM_mallocN(sizeof(*vertMap) * numVert_src, "build modifier vertMap"); edgeMap = MEM_mallocN(sizeof(*edgeMap) * numEdge_src, "build modifier edgeMap"); faceMap = MEM_mallocN(sizeof(*faceMap) * numPoly_src, "build modifier faceMap"); #pragma omp parallel sections if (numVert_src + numEdge_src + numPoly_src >= DM_OMP_LIMIT) { #pragma omp section { range_vn_i(vertMap, numVert_src, 0); } #pragma omp section { range_vn_i(edgeMap, numEdge_src, 0); } #pragma omp section { range_vn_i(faceMap, numPoly_src, 0); } } frac = (BKE_scene_frame_get(md->scene) - bmd->start) / bmd->length; CLAMP(frac, 0.0f, 1.0f); numFaces_dst = numPoly_src * frac; numEdges_dst = numEdge_src * frac; /* if there's at least one face, build based on faces */ if (numFaces_dst) { MPoly *mpoly, *mp; MLoop *ml, *mloop; MEdge *medge; if (bmd->randomize) { BLI_array_randomize(faceMap, sizeof(*faceMap), numPoly_src, bmd->seed); } /* get the set of all vert indices that will be in the final mesh, * mapped to the new indices */ mpoly = mpoly_src; mloop = mloop_src; for (i = 0; i < numFaces_dst; i++) { mp = mpoly + faceMap[i]; ml = mloop + mp->loopstart; for (j = 0; j < mp->totloop; j++, ml++) { if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(ml->v))) BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(ml->v), SET_INT_IN_POINTER(BLI_ghash_size(vertHash))); } numLoops_dst += mp->totloop; } /* get the set of edges that will be in the new mesh (i.e. all edges * that have both verts in the new mesh) */ medge = medge_src; for (i = 0; i < numEdge_src; i++) { MEdge *me = medge + i; if (BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me->v1)) && BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me->v2))) { j = BLI_ghash_size(edgeHash); BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(j), SET_INT_IN_POINTER(i)); BLI_ghash_insert(edgeHash2, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(j)); } } } else if (numEdges_dst) { MEdge *medge, *me; if (bmd->randomize) BLI_array_randomize(edgeMap, sizeof(*edgeMap), numEdge_src, bmd->seed); /* get the set of all vert indices that will be in the final mesh, * mapped to the new indices */ medge = medge_src; for (i = 0; i < numEdges_dst; i++) { me = medge + edgeMap[i]; if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me->v1))) { BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(me->v1), SET_INT_IN_POINTER(BLI_ghash_size(vertHash))); } if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me->v2))) { BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(me->v2), SET_INT_IN_POINTER(BLI_ghash_size(vertHash))); } } /* get the set of edges that will be in the new mesh */ for (i = 0; i < numEdges_dst; i++) { j = BLI_ghash_size(edgeHash); BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(j), SET_INT_IN_POINTER(edgeMap[i])); BLI_ghash_insert(edgeHash2, SET_INT_IN_POINTER(edgeMap[i]), SET_INT_IN_POINTER(j)); } } else { int numVerts = numVert_src * frac; if (bmd->randomize) { BLI_array_randomize(vertMap, sizeof(*vertMap), numVert_src, bmd->seed); } /* get the set of all vert indices that will be in the final mesh, * mapped to the new indices */ for (i = 0; i < numVerts; i++) { BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(vertMap[i]), SET_INT_IN_POINTER(i)); } } /* now we know the number of verts, edges and faces, we can create * the mesh */ result = CDDM_from_template(dm, BLI_ghash_size(vertHash), BLI_ghash_size(edgeHash), 0, numLoops_dst, numFaces_dst); /* copy the vertices across */ for (hashIter = BLI_ghashIterator_new(vertHash); !BLI_ghashIterator_isDone(hashIter); BLI_ghashIterator_step(hashIter) ) { MVert source; MVert *dest; int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter)); int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter)); source = mvert_src[oldIndex]; dest = CDDM_get_vert(result, newIndex); DM_copy_vert_data(dm, result, oldIndex, newIndex, 1); *dest = source; } BLI_ghashIterator_free(hashIter); /* copy the edges across, remapping indices */ for (i = 0; i < BLI_ghash_size(edgeHash); i++) { MEdge source; MEdge *dest; int oldIndex = GET_INT_FROM_POINTER(BLI_ghash_lookup(edgeHash, SET_INT_IN_POINTER(i))); source = medge_src[oldIndex]; dest = CDDM_get_edge(result, i); source.v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v1))); source.v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v2))); DM_copy_edge_data(dm, result, oldIndex, i, 1); *dest = source; } mpoly_dst = CDDM_get_polys(result); /* mloop_dst = */ ml_dst = CDDM_get_loops(result); /* copy the faces across, remapping indices */ k = 0; for (i = 0; i < numFaces_dst; i++) { MPoly *source; MPoly *dest; source = mpoly_src + faceMap[i]; dest = mpoly_dst + i; DM_copy_poly_data(dm, result, faceMap[i], i, 1); *dest = *source; dest->loopstart = k; DM_copy_loop_data(dm, result, source->loopstart, dest->loopstart, dest->totloop); ml_src = mloop_src + source->loopstart; for (j = 0; j < source->totloop; j++, k++, ml_src++, ml_dst++) { ml_dst->v = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(ml_src->v))); ml_dst->e = GET_INT_FROM_POINTER(BLI_ghash_lookup(edgeHash2, SET_INT_IN_POINTER(ml_src->e))); } } BLI_ghash_free(vertHash, NULL, NULL); BLI_ghash_free(edgeHash, NULL, NULL); BLI_ghash_free(edgeHash2, NULL, NULL); MEM_freeN(vertMap); MEM_freeN(edgeMap); MEM_freeN(faceMap); return result; }
void *BKE_frameserver_context_create(void) { FrameserverContext *context = MEM_mallocN(sizeof(FrameserverContext), "Frameserver Context"); return context; }
/** * Allocate an array from the mempool. */ void *BLI_mempool_as_arrayN(BLI_mempool *pool, const char *allocstr) { void *data = MEM_mallocN((size_t)(BLI_mempool_count(pool) * pool->esize), allocstr); BLI_mempool_as_array(pool, data); return data; }
static void build_pict_list(PlayState *ps, char *first, int totframes, int fstep, int fontid) { char *mem, filepath[FILE_MAX]; // short val; PlayAnimPict *picture = NULL; struct ImBuf *ibuf = NULL; char str[32 + FILE_MAX]; struct anim *anim; if (IMB_isanim(first)) { /* OCIO_TODO: support different input color space */ anim = IMB_open_anim(first, IB_rect, 0, NULL); if (anim) { int pic; ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE); if (ibuf) { playanim_toscreen(ps, NULL, ibuf, fontid, fstep); IMB_freeImBuf(ibuf); } for (pic = 0; pic < IMB_anim_get_duration(anim, IMB_TC_NONE); pic++) { picture = (PlayAnimPict *)MEM_callocN(sizeof(PlayAnimPict), "Pict"); picture->anim = anim; picture->frame = pic; picture->IB_flags = IB_rect; BLI_snprintf(str, sizeof(str), "%s : %4.d", first, pic + 1); picture->name = strdup(str); BLI_addtail(&picsbase, picture); } } else { printf("couldn't open anim %s\n", first); } } else { int count = 0; BLI_strncpy(filepath, first, sizeof(filepath)); pupdate_time(); ptottime = 1.0; /* O_DIRECT * * If set, all reads and writes on the resulting file descriptor will * be performed directly to or from the user program buffer, provided * appropriate size and alignment restrictions are met. Refer to the * F_SETFL and F_DIOINFO commands in the fcntl(2) manual entry for * information about how to determine the alignment constraints. * O_DIRECT is a Silicon Graphics extension and is only supported on * local EFS and XFS file systems. */ while (IMB_ispic(filepath) && totframes) { size_t size; int file; file = open(filepath, O_BINARY | O_RDONLY, 0); if (file < 0) { /* print errno? */ return; } picture = (PlayAnimPict *)MEM_callocN(sizeof(PlayAnimPict), "picture"); if (picture == NULL) { printf("Not enough memory for pict struct '%s'\n", filepath); close(file); return; } size = BLI_file_descriptor_size(file); if (size < 1) { close(file); MEM_freeN(picture); return; } picture->size = size; picture->IB_flags = IB_rect; if (fromdisk == FALSE) { mem = (char *)MEM_mallocN(size, "build pic list"); if (mem == NULL) { printf("Couldn't get memory\n"); close(file); MEM_freeN(picture); return; } if (read(file, mem, size) != size) { printf("Error while reading %s\n", filepath); close(file); MEM_freeN(picture); MEM_freeN(mem); return; } } else { mem = NULL; } picture->mem = mem; picture->name = strdup(filepath); close(file); BLI_addtail(&picsbase, picture); count++; pupdate_time(); if (ptottime > 1.0) { /* OCIO_TODO: support different input color space */ if (picture->mem) { ibuf = IMB_ibImageFromMemory((unsigned char *)picture->mem, picture->size, picture->IB_flags, NULL, picture->name); } else { ibuf = IMB_loadiffname(picture->name, picture->IB_flags, NULL); } if (ibuf) { playanim_toscreen(ps, picture, ibuf, fontid, fstep); IMB_freeImBuf(ibuf); } pupdate_time(); ptottime = 0.0; } BLI_newname(filepath, +fstep); #if 0 // XXX25 while (qtest()) { switch (qreadN(&val)) { case ESCKEY: if (val) return; break; } } #endif totframes--; } } return; }
/** * This function populates pixel_array and returns TRUE if things are correct */ static bool cast_ray_highpoly( BVHTreeFromMesh *treeData, TriTessFace *triangles[], BakePixel *pixel_array, BakeHighPolyData *highpoly, const float co[3], const float dir[3], const int pixel_id, const int tot_highpoly, const float du_dx, const float du_dy, const float dv_dx, const float dv_dy) { int i; int primitive_id = -1; float uv[2]; int hit_mesh = -1; float hit_distance = FLT_MAX; BVHTreeRayHit *hits; hits = MEM_mallocN(sizeof(BVHTreeRayHit) * tot_highpoly, "Bake Highpoly to Lowpoly: BVH Rays"); for (i = 0; i < tot_highpoly; i++) { float co_high[3], dir_high[3]; hits[i].index = -1; /* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */ hits[i].dist = 10000.0f; /* transform the ray from the world space to the highpoly space */ mul_v3_m4v3(co_high, highpoly[i].imat, co); /* rotates */ mul_v3_mat3_m4v3(dir_high, highpoly[i].imat, dir); normalize_v3(dir_high); /* cast ray */ if (treeData[i].tree) { BLI_bvhtree_ray_cast(treeData[i].tree, co_high, dir_high, 0.0f, &hits[i], treeData[i].raycast_callback, &treeData[i]); } if (hits[i].index != -1) { /* cull backface */ const float dot = dot_v3v3(dir_high, hits[i].no); if (dot < 0.0f) { float distance; float hit_world[3]; /* distance comparison in world space */ mul_v3_m4v3(hit_world, highpoly[i].obmat, hits[i].co); distance = len_squared_v3v3(hit_world, co); if (distance < hit_distance) { hit_mesh = i; hit_distance = distance; } } } } if (hit_mesh != -1) { calc_barycentric_from_point(triangles[hit_mesh], hits[hit_mesh].index, hits[hit_mesh].co, &primitive_id, uv); pixel_array[pixel_id].primitive_id = primitive_id; pixel_array[pixel_id].object_id = hit_mesh; copy_v2_v2(pixel_array[pixel_id].uv, uv); /* the differentials are relative to the UV/image space, so the highpoly differentials * are the same as the low poly differentials */ pixel_array[pixel_id].du_dx = du_dx; pixel_array[pixel_id].du_dy = du_dy; pixel_array[pixel_id].dv_dx = dv_dx; pixel_array[pixel_id].dv_dy = dv_dy; } else { pixel_array[pixel_id].primitive_id = -1; pixel_array[pixel_id].object_id = -1; } MEM_freeN(hits); return hit_mesh != -1; }
static void meshcache_do( MeshCacheModifierData *mcmd, Object *ob, DerivedMesh *UNUSED(dm), float (*vertexCos_Real)[3], int numVerts) { const bool use_factor = mcmd->factor < 1.0f; float (*vertexCos_Store)[3] = (use_factor || (mcmd->deform_mode == MOD_MESHCACHE_DEFORM_INTEGRATE)) ? MEM_mallocN(sizeof(*vertexCos_Store) * numVerts, __func__) : NULL; float (*vertexCos)[3] = vertexCos_Store ? vertexCos_Store : vertexCos_Real; Scene *scene = mcmd->modifier.scene; const float fps = FPS; char filepath[FILE_MAX]; const char *err_str = NULL; bool ok; float time; /* -------------------------------------------------------------------- */ /* Interpret Time (the reading functions also do some of this ) */ if (mcmd->play_mode == MOD_MESHCACHE_PLAY_CFEA) { const float cfra = BKE_scene_frame_get(scene); switch (mcmd->time_mode) { case MOD_MESHCACHE_TIME_FRAME: { time = cfra; break; } case MOD_MESHCACHE_TIME_SECONDS: { time = cfra / fps; break; } case MOD_MESHCACHE_TIME_FACTOR: default: { time = cfra / fps; break; } } /* apply offset and scale */ time = (mcmd->frame_scale * time) - mcmd->frame_start; } else { /* if (mcmd->play_mode == MOD_MESHCACHE_PLAY_EVAL) { */ switch (mcmd->time_mode) { case MOD_MESHCACHE_TIME_FRAME: { time = mcmd->eval_frame; break; } case MOD_MESHCACHE_TIME_SECONDS: { time = mcmd->eval_time; break; } case MOD_MESHCACHE_TIME_FACTOR: default: { time = mcmd->eval_factor; break; } } } /* -------------------------------------------------------------------- */ /* Read the File (or error out when the file is bad) */ /* would be nice if we could avoid doing this _every_ frame */ BLI_strncpy(filepath, mcmd->filepath, sizeof(filepath)); BLI_path_abs(filepath, ID_BLEND_PATH(G.main, (ID *)ob)); switch (mcmd->type) { case MOD_MESHCACHE_TYPE_MDD: ok = MOD_meshcache_read_mdd_times(filepath, vertexCos, numVerts, mcmd->interp, time, fps, mcmd->time_mode, &err_str); break; case MOD_MESHCACHE_TYPE_PC2: ok = MOD_meshcache_read_pc2_times(filepath, vertexCos, numVerts, mcmd->interp, time, fps, mcmd->time_mode, &err_str); break; default: ok = false; break; } /* -------------------------------------------------------------------- */ /* tricky shape key integration (slow!) */ if (mcmd->deform_mode == MOD_MESHCACHE_DEFORM_INTEGRATE) { Mesh *me = ob->data; /* we could support any object type */ if (UNLIKELY(ob->type != OB_MESH)) { modifier_setError(&mcmd->modifier, "'Integrate' only valid for Mesh objects"); } else if (UNLIKELY(me->totvert != numVerts)) { modifier_setError(&mcmd->modifier, "'Integrate' original mesh vertex mismatch"); } else if (UNLIKELY(me->totpoly == 0)) { modifier_setError(&mcmd->modifier, "'Integrate' requires faces"); } else { /* the moons align! */ int i; float (*vertexCos_Source)[3] = MEM_mallocN(sizeof(*vertexCos_Source) * numVerts, __func__); float (*vertexCos_New)[3] = MEM_mallocN(sizeof(*vertexCos_New) * numVerts, __func__); MVert *mv = me->mvert; for (i = 0; i < numVerts; i++, mv++) { copy_v3_v3(vertexCos_Source[i], mv->co); } BKE_mesh_calc_relative_deform( me->mpoly, me->totpoly, me->mloop, me->totvert, (const float (*)[3])vertexCos_Source, /* from the original Mesh*/ (const float (*)[3])vertexCos_Real, /* the input we've been given (shape keys!) */ (const float (*)[3])vertexCos, /* the result of this modifier */ vertexCos_New /* the result of this function */ ); /* write the corrected locations back into the result */ memcpy(vertexCos, vertexCos_New, sizeof(*vertexCos) * numVerts); MEM_freeN(vertexCos_Source); MEM_freeN(vertexCos_New); } } /* -------------------------------------------------------------------- */ /* Apply the transformation matrix (if needed) */ if (UNLIKELY(err_str)) { modifier_setError(&mcmd->modifier, "%s", err_str); } else if (ok) { bool use_matrix = false; float mat[3][3]; unit_m3(mat); if (mat3_from_axis_conversion(mcmd->forward_axis, mcmd->up_axis, 1, 2, mat)) { use_matrix = true; } if (mcmd->flip_axis) { float tmat[3][3]; unit_m3(tmat); if (mcmd->flip_axis & (1 << 0)) tmat[0][0] = -1.0f; if (mcmd->flip_axis & (1 << 1)) tmat[1][1] = -1.0f; if (mcmd->flip_axis & (1 << 2)) tmat[2][2] = -1.0f; mul_m3_m3m3(mat, tmat, mat); use_matrix = true; } if (use_matrix) { int i; for (i = 0; i < numVerts; i++) { mul_m3_v3(mat, vertexCos[i]); } } } if (vertexCos_Store) { if (ok) { if (use_factor) { interp_vn_vn(*vertexCos_Real, *vertexCos_Store, mcmd->factor, numVerts * 3); } else { memcpy(vertexCos_Real, vertexCos_Store, sizeof(*vertexCos_Store) * numVerts); } } MEM_freeN(vertexCos_Store); } }
bool RE_bake_pixels_populate_from_objects( struct Mesh *me_low, BakePixel pixel_array_from[], BakePixel pixel_array_to[], BakeHighPolyData highpoly[], const int tot_highpoly, const size_t num_pixels, const bool is_custom_cage, const float cage_extrusion, float mat_low[4][4], float mat_cage[4][4], struct Mesh *me_cage) { size_t i; int primitive_id; float u, v; float imat_low[4][4]; bool is_cage = me_cage != NULL; bool result = true; DerivedMesh *dm_low = NULL; DerivedMesh **dm_highpoly; BVHTreeFromMesh *treeData; /* Note: all coordinates are in local space */ TriTessFace *tris_low = NULL; TriTessFace *tris_cage = NULL; TriTessFace **tris_high; /* assume all lowpoly tessfaces can be quads */ tris_high = MEM_callocN(sizeof(TriTessFace *) * tot_highpoly, "MVerts Highpoly Mesh Array"); /* assume all highpoly tessfaces are triangles */ dm_highpoly = MEM_mallocN(sizeof(DerivedMesh *) * tot_highpoly, "Highpoly Derived Meshes"); treeData = MEM_callocN(sizeof(BVHTreeFromMesh) * tot_highpoly, "Highpoly BVH Trees"); if (!is_cage) { dm_low = CDDM_from_mesh(me_low); tris_low = mesh_calc_tri_tessface(me_low, true, dm_low); } else if (is_custom_cage) { tris_low = mesh_calc_tri_tessface(me_low, false, NULL); tris_cage = mesh_calc_tri_tessface(me_cage, false, NULL); } else { tris_cage = mesh_calc_tri_tessface(me_cage, false, NULL); } invert_m4_m4(imat_low, mat_low); for (i = 0; i < tot_highpoly; i++) { tris_high[i] = mesh_calc_tri_tessface(highpoly[i].me, false, NULL); dm_highpoly[i] = CDDM_from_mesh(highpoly[i].me); DM_ensure_tessface(dm_highpoly[i]); if (dm_highpoly[i]->getNumTessFaces(dm_highpoly[i]) != 0) { /* Create a bvh-tree for each highpoly object */ bvhtree_from_mesh_faces(&treeData[i], dm_highpoly[i], 0.0, 2, 6); if (treeData[i].tree == NULL) { printf("Baking: out of memory while creating BHVTree for object \"%s\"\n", highpoly[i].ob->id.name + 2); result = false; goto cleanup; } } } for (i = 0; i < num_pixels; i++) { float co[3]; float dir[3]; primitive_id = pixel_array_from[i].primitive_id; if (primitive_id == -1) { pixel_array_to[i].primitive_id = -1; continue; } u = pixel_array_from[i].uv[0]; v = pixel_array_from[i].uv[1]; /* calculate from low poly mesh cage */ if (is_custom_cage) { calc_point_from_barycentric_cage(tris_low, tris_cage, mat_low, mat_cage, primitive_id, u, v, co, dir); } else if (is_cage) { calc_point_from_barycentric_extrusion(tris_cage, mat_low, imat_low, primitive_id, u, v, cage_extrusion, co, dir, true); } else { calc_point_from_barycentric_extrusion(tris_low, mat_low, imat_low, primitive_id, u, v, cage_extrusion, co, dir, false); } /* cast ray */ if (!cast_ray_highpoly(treeData, tris_high, pixel_array_to, highpoly, co, dir, i, tot_highpoly, pixel_array_from[i].du_dx, pixel_array_from[i].du_dy, pixel_array_from[i].dv_dx, pixel_array_from[i].dv_dy)) { /* if it fails mask out the original pixel array */ pixel_array_from[i].primitive_id = -1; } } /* garbage collection */ cleanup: for (i = 0; i < tot_highpoly; i++) { free_bvhtree_from_mesh(&treeData[i]); if (dm_highpoly[i]) { dm_highpoly[i]->release(dm_highpoly[i]); } if (tris_high[i]) { MEM_freeN(tris_high[i]); } } MEM_freeN(tris_high); MEM_freeN(treeData); MEM_freeN(dm_highpoly); if (dm_low) { dm_low->release(dm_low); } if (tris_low) { MEM_freeN(tris_low); } if (tris_cage) { MEM_freeN(tris_cage); } return result; }
/** * Checks if name is a fully qualified filename to an executable. * If not it searches $PATH for the file. On Windows it also * adds the correct extension (.com .exe etc) from * $PATHEXT if necessary. Also on Windows it translates * the name to its 8.3 version to prevent problems with * spaces and stuff. Final result is returned in fullname. * * \param fullname The full path and full name of the executable * (must be FILE_MAX minimum) * \param name The name of the executable (usually argv[0]) to be checked */ static void bli_where_am_i(char *fullname, const size_t maxlen, const char *name) { char filename[FILE_MAX]; const char *path = NULL, *temp; #ifdef _WIN32 const char *separator = ";"; #else const char *separator = ":"; #endif #ifdef WITH_BINRELOC /* linux uses binreloc since argv[0] is not reliable, call br_init( NULL ) first */ path = br_find_exe(NULL); if (path) { BLI_strncpy(fullname, path, maxlen); free((void *)path); return; } #endif #ifdef _WIN32 wchar_t *fullname_16 = MEM_mallocN(maxlen * sizeof(wchar_t), "ProgramPath"); if (GetModuleFileNameW(0, fullname_16, maxlen)) { conv_utf_16_to_8(fullname_16, fullname, maxlen); if (!BLI_exists(fullname)) { printf("path can't be found: \"%.*s\"\n", (int)maxlen, fullname); MessageBox(NULL, "path contains invalid characters or is too long (see console)", "Error", MB_OK); } MEM_freeN(fullname_16); return; } MEM_freeN(fullname_16); #endif /* unix and non linux */ if (name && name[0]) { BLI_strncpy(fullname, name, maxlen); if (name[0] == '.') { char wdir[FILE_MAX] = ""; BLI_current_working_dir(wdir, sizeof(wdir)); /* backup cwd to restore after */ // not needed but avoids annoying /./ in name if (name[1] == SEP) BLI_join_dirfile(fullname, maxlen, wdir, name + 2); else BLI_join_dirfile(fullname, maxlen, wdir, name); add_win32_extension(fullname); /* XXX, doesnt respect length */ } else if (BLI_last_slash(name)) { // full path BLI_strncpy(fullname, name, maxlen); add_win32_extension(fullname); } else { // search for binary in $PATH path = getenv("PATH"); if (path) { do { temp = strstr(path, separator); if (temp) { strncpy(filename, path, temp - path); filename[temp - path] = 0; path = temp + 1; } else { strncpy(filename, path, sizeof(filename)); } BLI_path_append(fullname, maxlen, name); if (add_win32_extension(filename)) { BLI_strncpy(fullname, filename, maxlen); break; } } while (temp); } } #if defined(DEBUG) if (!STREQ(name, fullname)) { printf("guessing '%s' == '%s'\n", name, fullname); } #endif } }
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= 0; if(!(re->r.scemode & R_PREVIEWBUTS)) re->result= NULL; BLI_rw_mutex_unlock(&re->resultmutex); RE_TileProcessor(re, 0, 1); 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 col[3], *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; if (re->r.color_mgt_flag & R_COLOR_MANAGEMENT) color_manage_linearize(col, mat->sss_col); else VECCOPY(col, mat->sss_col); sss->ss[0]= scatter_settings_new(col[0], radius[0], ior, cfac, fw, bw); sss->ss[1]= scatter_settings_new(col[1], radius[1], ior, cfac, fw, bw); sss->ss[2]= scatter_settings_new(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); } }
/* Adds the geometry found in dm to bm */ BME_Mesh *BME_derivedmesh_to_bmesh(DerivedMesh *dm) { BME_Mesh *bm; int allocsize[4] = {512,512,2048,512}; MVert *mvert, *mv; MEdge *medge, *me; MFace *mface, *mf; int totface,totedge,totvert,i,len, numTex, numCol; BME_Vert *v1=NULL,*v2=NULL, **vert_array; BME_Edge *e=NULL; BME_Poly *f=NULL; EdgeHash *edge_hash = BLI_edgehash_new(); bm = BME_make_mesh(allocsize); /*copy custom data layout*/ CustomData_copy(&dm->vertData, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0); CustomData_copy(&dm->edgeData, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0); CustomData_copy(&dm->faceData, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0); /*copy face corner data*/ CustomData_to_bmeshpoly(&dm->faceData, &bm->pdata, &bm->ldata); /*initialize memory pools*/ CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]); CustomData_bmesh_init_pool(&bm->edata, allocsize[1]); CustomData_bmesh_init_pool(&bm->ldata, allocsize[2]); CustomData_bmesh_init_pool(&bm->pdata, allocsize[3]); /*needed later*/ numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY); numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL); totvert = dm->getNumVerts(dm); totedge = dm->getNumEdges(dm); totface = dm->getNumFaces(dm); mvert = dm->getVertArray(dm); medge = dm->getEdgeArray(dm); mface = dm->getFaceArray(dm); vert_array = MEM_mallocN(sizeof(*vert_array)*totvert,"BME_derivedmesh_to_bmesh BME_Vert* array"); BME_model_begin(bm); /*add verts*/ for(i=0,mv = mvert; i < totvert;i++,mv++){ v1 = BME_MV(bm,mv->co); vert_array[i] = v1; v1->flag = mv->flag; v1->bweight = mv->bweight/255.0f; CustomData_to_bmesh_block(&dm->vertData, &bm->vdata, i, &v1->data); } /*add edges*/ for(i=0,me = medge; i < totedge;i++,me++){ v1 = vert_array[me->v1]; v2 = vert_array[me->v2]; e = BME_ME(bm, v1, v2); e->crease = me->crease/255.0f; e->bweight = me->bweight/255.0f; e->flag = (unsigned char)me->flag; BLI_edgehash_insert(edge_hash,me->v1,me->v2,e); CustomData_to_bmesh_block(&dm->edgeData, &bm->edata, i, &e->data); } /*add faces.*/ for(i=0,mf = mface; i < totface;i++,mf++){ BME_Edge *edar[4]; if(mf->v4) len = 4; else len = 3; edar[0] = BLI_edgehash_lookup(edge_hash,mf->v1,mf->v2); edar[1] = BLI_edgehash_lookup(edge_hash,mf->v2,mf->v3); if(len == 4){ edar[2] = BLI_edgehash_lookup(edge_hash,mf->v3,mf->v4); edar[3] = BLI_edgehash_lookup(edge_hash,mf->v4,mf->v1); } else edar[2] = BLI_edgehash_lookup(edge_hash,mf->v3,mf->v1); /*find v1 and v2*/ v1 = vert_array[mf->v1]; v2 = vert_array[mf->v2]; f = BME_MF(bm,v1,v2,edar,len); f->mat_nr = mf->mat_nr; f->flag = mf->flag; CustomData_to_bmesh_block(&dm->faceData,&bm->pdata,i,&f->data); BME_DMcorners_to_loops(bm, &dm->faceData,i,f, numCol,numTex); } BME_model_end(bm); BLI_edgehash_free(edge_hash, NULL); MEM_freeN(vert_array); return bm; }