static void remap_uvs_23(DerivedMesh *dm, DerivedMesh *split, int numlayer, int i, int cur, int c0, int c1, int c2) { MTFace *mf, *df1, *df2; int l; for (l = 0; l < numlayer; l++) { mf = CustomData_get_layer_n(&split->faceData, CD_MTFACE, l); df1 = mf + cur; df2 = df1 + 1; mf = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, l); mf += i; copy_v2_v2(df1->uv[0], mf->uv[c0]); INT_UV(df1->uv[1], c0, c1); INT_UV(df1->uv[2], c1, c2); INT_UV(df1->uv[3], c0, c2); INT_UV(df2->uv[0], c0, c1); copy_v2_v2(df2->uv[1], mf->uv[c1]); INT_UV(df2->uv[2], c1, c2); INT_UV(df2->uv[0], c0, c2); INT_UV(df2->uv[1], c1, c2); copy_v2_v2(df2->uv[2], mf->uv[c2]); } }
static void remap_uvs_7_11_13_14( Mesh *mesh, Mesh *split, int numlayer, int i, int cur, int c0, int c1, int c2, int c3) { MTFace *mf, *df1, *df2, *df3; int l; for (l = 0; l < numlayer; l++) { mf = CustomData_get_layer_n(&split->fdata, CD_MTFACE, l); df1 = mf + cur; df2 = df1 + 1; df3 = df1 + 2; mf = CustomData_get_layer_n(&mesh->fdata, CD_MTFACE, l); mf += i; copy_v2_v2(df1->uv[0], mf->uv[c0]); INT_UV(df1->uv[1], c0, c1); INT_UV(df1->uv[2], c1, c2); INT_UV(df1->uv[3], c0, c3); INT_UV(df2->uv[0], c0, c1); copy_v2_v2(df2->uv[1], mf->uv[c1]); INT_UV(df2->uv[2], c1, c2); INT_UV(df3->uv[0], c0, c3); INT_UV(df3->uv[1], c1, c2); copy_v2_v2(df3->uv[2], mf->uv[c2]); copy_v2_v2(df3->uv[3], mf->uv[c3]); } }
/* This is a Mesh-based copy of the same function in DerivedMesh.c */ static void shapekey_layers_to_keyblocks(Mesh *mesh_src, Mesh *mesh_dst, int actshape_uid) { KeyBlock *kb; int i, j, tot; if (!mesh_dst->key) { return; } tot = CustomData_number_of_layers(&mesh_src->vdata, CD_SHAPEKEY); for (i = 0; i < tot; i++) { CustomDataLayer *layer = &mesh_src->vdata.layers[CustomData_get_layer_index_n(&mesh_src->vdata, CD_SHAPEKEY, i)]; float(*cos)[3], (*kbcos)[3]; for (kb = mesh_dst->key->block.first; kb; kb = kb->next) { if (kb->uid == layer->uid) { break; } } if (!kb) { kb = BKE_keyblock_add(mesh_dst->key, layer->name); kb->uid = layer->uid; } if (kb->data) { MEM_freeN(kb->data); } cos = CustomData_get_layer_n(&mesh_src->vdata, CD_SHAPEKEY, i); kb->totelem = mesh_src->totvert; kb->data = kbcos = MEM_malloc_arrayN(kb->totelem, 3 * sizeof(float), __func__); if (kb->uid == actshape_uid) { MVert *mvert = mesh_src->mvert; for (j = 0; j < mesh_src->totvert; j++, kbcos++, mvert++) { copy_v3_v3(*kbcos, mvert->co); } } else { for (j = 0; j < kb->totelem; j++, cos++, kbcos++) { copy_v3_v3(*kbcos, *cos); } } } for (kb = mesh_dst->key->block.first; kb; kb = kb->next) { if (kb->totelem != mesh_src->totvert) { if (kb->data) { MEM_freeN(kb->data); } kb->totelem = mesh_src->totvert; kb->data = MEM_calloc_arrayN(kb->totelem, 3 * sizeof(float), __func__); CLOG_ERROR(&LOG, "lost a shapekey layer: '%s'! (bmesh internal error)", kb->name); } } }
/*merge these functions*/ static void BME_DMcorners_to_loops(BME_Mesh *bm, CustomData *facedata, int index, BME_Poly *f, int numCol, int numTex){ int i, j; BME_Loop *l; MTFace *texface; MTexPoly *texpoly; MCol *mcol; MLoopCol *mloopcol; MLoopUV *mloopuv; for(i=0; i< numTex; i++){ texface = CustomData_get_layer_n(facedata, CD_MTFACE, i); texpoly = CustomData_bmesh_get_n(&bm->pdata, f->data, CD_MTEXPOLY, i); texpoly->tpage = texface[index].tpage; texpoly->flag = texface[index].flag; texpoly->transp = texface[index].transp; texpoly->mode = texface[index].mode; texpoly->tile = texface[index].tile; texpoly->unwrap = texface[index].unwrap; j = 0; l = f->loopbase; do{ mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPUV, i); mloopuv->uv[0] = texface[index].uv[j][0]; mloopuv->uv[1] = texface[index].uv[j][1]; j++; l = l->next; }while(l!=f->loopbase); } for(i=0; i < numCol; i++){ mcol = CustomData_get_layer_n(facedata, CD_MCOL, i); j = 0; l = f->loopbase; do{ mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPCOL, i); mloopcol->r = mcol[(index*4)+j].r; mloopcol->g = mcol[(index*4)+j].g; mloopcol->b = mcol[(index*4)+j].b; mloopcol->a = mcol[(index*4)+j].a; j++; l = l->next; }while(l!=f->loopbase); } }
//creates <source> for texcoords void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me) { #if 0 int totfaces = dm->getNumFaces(dm); MFace *mfaces = dm->getFaceArray(dm); #endif int totfaces = me->totface; MFace *mfaces = me->mface; int totuv = 0; int i; // count totuv for (i = 0; i < totfaces; i++) { MFace *f = &mfaces[i]; if (f->v4 == 0) { totuv+=3; } else { totuv+=4; } } int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE); // write <source> for each layer // each <source> will get id like meshName + "map-channel-1" for (int a = 0; a < num_layers; a++) { MTFace *tface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, a); // char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, a); COLLADASW::FloatSourceF source(mSW); std::string layer_id = makeTexcoordSourceId(geom_id, a); source.setId(layer_id); source.setArrayId(layer_id + ARRAY_ID_SUFFIX); source.setAccessorCount(totuv); source.setAccessorStride(2); COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); param.push_back("S"); param.push_back("T"); source.prepareToAppendValues(); for (i = 0; i < totfaces; i++) { MFace *f = &mfaces[i]; for (int j = 0; j < (f->v4 == 0 ? 3 : 4); j++) { source.appendValues(tface[i].uv[j][0], tface[i].uv[j][1]); } } source.finish(); } }
void GeometryExporter::createVertexColorSource(std::string geom_id, Mesh *me) { /* Find number of vertex color layers */ int totlayer_mcol = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL); if (totlayer_mcol == 0) return; int map_index = 0; for (int a = 0; a < totlayer_mcol; a++) { map_index++; MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_n(&me->ldata, CD_MLOOPCOL, a); COLLADASW::FloatSourceF source(mSW); char *layer_name = bc_CustomData_get_layer_name(&me->ldata, CD_MLOOPCOL, a); std::string layer_id = makeVertexColorSourceId(geom_id, layer_name); source.setId(layer_id); source.setNodeName(layer_name); source.setArrayId(layer_id + ARRAY_ID_SUFFIX); source.setAccessorCount(me->totloop); source.setAccessorStride(3); COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); param.push_back("R"); param.push_back("G"); param.push_back("B"); source.prepareToAppendValues(); MPoly *mpoly; int i; for (i = 0, mpoly = me->mpoly; i < me->totpoly; i++, mpoly++) { MLoopCol *mlc = mloopcol + mpoly->loopstart; for (int j = 0; j < mpoly->totloop; j++, mlc++) { source.appendValues( mlc->r / 255.0f, mlc->g / 255.0f, mlc->b / 255.0f ); } } source.finish(); } }
//creates <source> for texcoords void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me) { int totpoly = me->totpoly; int totuv = me->totloop; MPoly *mpolys = me->mpoly; int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV); // write <source> for each layer // each <source> will get id like meshName + "map-channel-1" int active_uv_index = CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV); for (int a = 0; a < num_layers; a++) { if (!this->export_settings->active_uv_only || a == active_uv_index) { MLoopUV *mloops = (MLoopUV *)CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, a); COLLADASW::FloatSourceF source(mSW); std::string layer_id = makeTexcoordSourceId(geom_id, a, this->export_settings->active_uv_only); source.setId(layer_id); source.setArrayId(layer_id + ARRAY_ID_SUFFIX); source.setAccessorCount(totuv); source.setAccessorStride(2); COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); param.push_back("S"); param.push_back("T"); source.prepareToAppendValues(); for (int index = 0; index < totpoly; index++) { MPoly *mpoly = mpolys+index; MLoopUV *mloop = mloops+mpoly->loopstart; for (int j = 0; j < mpoly->totloop; j++) { source.appendValues(mloop[j].uv[0], mloop[j].uv[1]); } } source.finish(); } } }
static void make_duplis_faces(const DupliContext *ctx) { Scene *scene = ctx->scene; Object *parent = ctx->object; bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW); FaceDupliData fdd; fdd.use_scale = ((parent->transflag & OB_DUPLIFACES_SCALE) != 0); /* gather mesh info */ { BMEditMesh *em = BKE_editmesh_from_object(parent); CustomDataMask dm_mask = (use_texcoords ? CD_MASK_BAREMESH | CD_MASK_ORCO | CD_MASK_MLOOPUV : CD_MASK_BAREMESH); if (em) fdd.dm = editbmesh_get_derived_cage(scene, parent, em, dm_mask); else fdd.dm = mesh_get_derived_final(scene, parent, dm_mask); if (use_texcoords) { CustomData *ml_data = fdd.dm->getLoopDataLayout(fdd.dm); const int uv_idx = CustomData_get_render_layer(ml_data, CD_MLOOPUV); fdd.orco = fdd.dm->getVertDataArray(fdd.dm, CD_ORCO); fdd.mloopuv = CustomData_get_layer_n(ml_data, CD_MLOOPUV, uv_idx); } else { fdd.orco = NULL; fdd.mloopuv = NULL; } fdd.totface = fdd.dm->getNumPolys(fdd.dm); fdd.mpoly = fdd.dm->getPolyArray(fdd.dm); fdd.mloop = fdd.dm->getLoopArray(fdd.dm); fdd.mvert = fdd.dm->getVertArray(fdd.dm); } make_child_duplis(ctx, &fdd, make_child_duplis_faces); fdd.dm->release(fdd.dm); }
bool ImagesExporter::hasImages(Scene *sce) { LinkNode *node; for (node = this->export_settings->export_set; node; node = node->next) { Object *ob = (Object *)node->link; int a; for (a = 0; a < ob->totcol; a++) { Material *ma = give_current_material(ob, a + 1); // no material, but check all of the slots if (!ma) continue; int b; for (b = 0; b < MAX_MTEX; b++) { MTex *mtex = ma->mtex[b]; if (mtex && mtex->tex && mtex->tex->ima) return true; } } if (ob->type == OB_MESH) { Mesh *me = (Mesh *) ob->data; BKE_mesh_tessface_ensure(me); bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE); if (has_uvs) { int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE); for (int a = 0; a < num_layers; a++) { MTFace *tface = (MTFace *)CustomData_get_layer_n(&me->fdata, CD_MTFACE, a); Image *img = tface->tpage; if (img) return true; } } } } return false; }
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; MTFace *mtface; MFace *mface; /* 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')) { mtface = CustomData_get_layer(&me->fdata, CD_MTFACE); } else { int uv_id = CustomData_get_named_layer(&me->fdata, CD_MTFACE, uv_layer); mtface = CustomData_get_layer_n(&me->fdata, CD_MTFACE, uv_id); } mface = CustomData_get_layer(&me->fdata, CD_MFACE); if (mtface == NULL) return; p_id = -1; for (i = 0; i < me->totface; i++) { float vec[4][2]; MTFace *mtf = &mtface[i]; MFace *mf = &mface[i]; int mat_nr = mf->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 < 4; a++) { /* 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] = mtf->uv[a][0] * (float)bd.bk_image->width - (0.5f + 0.001f); vec[a][1] = mtf->uv[a][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); /* 4 vertices in the face */ if (mf->v4 != 0) { bd.primitive_id = ++p_id; bake_differentials(&bd, vec[0], vec[2], vec[3]); zspan_scanconvert(&bd.zspan[image_id], (void *)&bd, vec[0], vec[2], vec[3], store_bake_pixel); } } for (i = 0; i < bake_images->size; i++) { zbuf_free_span(&bd.zspan[i]); } MEM_freeN(bd.zspan); }
static bool data_transfer_layersmapping_cdlayers( ListBase *r_map, const int cddata_type, const int mix_mode, const float mix_factor, const float *mix_weights, const int num_elem_dst, const bool use_create, const bool use_delete, CustomData *cd_src, CustomData *cd_dst, const bool use_dupref_dst, const int fromlayers, const int tolayers) { int idx_src, idx_dst; void *data_src, *data_dst = NULL; if (CustomData_layertype_is_singleton(cddata_type)) { if (!(data_src = CustomData_get_layer(cd_src, cddata_type))) { if (use_delete) { CustomData_free_layer(cd_dst, cddata_type, num_elem_dst, 0); } return true; } data_dst = CustomData_get_layer(cd_dst, cddata_type); if (!data_dst) { if (!use_create) { return true; } data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst); } else if (use_dupref_dst && r_map) { /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */ data_dst = CustomData_duplicate_referenced_layer(cd_dst, cddata_type, num_elem_dst); } if (r_map) { data_transfer_layersmapping_add_item_cd(r_map, cddata_type, mix_mode, mix_factor, mix_weights, data_src, data_dst); } } else if (fromlayers == DT_LAYERS_ACTIVE_SRC || fromlayers >= 0) { /* Note: use_delete has not much meaning in this case, ignored. */ if (fromlayers >= 0) { /* Real-layer index */ idx_src = fromlayers; } else { if ((idx_src = CustomData_get_active_layer(cd_src, cddata_type)) == -1) { return true; } } data_src = CustomData_get_layer_n(cd_src, cddata_type, idx_src); if (!data_src) { return true; } if (tolayers >= 0) { /* Real-layer index */ idx_dst = tolayers; /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */ if (use_dupref_dst && r_map) { data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst); } else { data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst); } } else if (tolayers == DT_LAYERS_ACTIVE_DST) { if ((idx_dst = CustomData_get_active_layer(cd_dst, cddata_type)) == -1) { if (!use_create) { return true; } data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst); } else { /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */ if (use_dupref_dst && r_map) { data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst); } else { data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst); } } } else if (tolayers == DT_LAYERS_INDEX_DST) { int num = CustomData_number_of_layers(cd_dst, cddata_type); idx_dst = idx_src; if (num <= idx_dst) { if (!use_create) { return true; } /* Create as much data layers as necessary! */ for (; num <= idx_dst; num++) { CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst); } } /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */ if (use_dupref_dst && r_map) { data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst); } else { data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst); } } else if (tolayers == DT_LAYERS_NAME_DST) { const char *name = CustomData_get_layer_name(cd_src, cddata_type, idx_src); if ((idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name)) == -1) { if (!use_create) { return true; } CustomData_add_layer_named(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst, name); idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name); } /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */ if (use_dupref_dst && r_map) { data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst); } else { data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst); } } else { return false; } if (!data_dst) { return false; } if (r_map) { data_transfer_layersmapping_add_item_cd( r_map, cddata_type, mix_mode, mix_factor, mix_weights, data_src, data_dst); } } else if (fromlayers == DT_LAYERS_ALL_SRC) { int num_src = CustomData_number_of_layers(cd_src, cddata_type); bool *use_layers_src = num_src ? MEM_mallocN(sizeof(*use_layers_src) * (size_t)num_src, __func__) : NULL; bool ret; if (use_layers_src) { memset(use_layers_src, true, sizeof(*use_layers_src) * num_src); } ret = data_transfer_layersmapping_cdlayers_multisrc_to_dst( r_map, cddata_type, mix_mode, mix_factor, mix_weights, num_elem_dst, use_create, use_delete, cd_src, cd_dst, use_dupref_dst, tolayers, use_layers_src, num_src); if (use_layers_src) { MEM_freeN(use_layers_src); } return ret; } else { return false; } return true; }
static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst( ListBase *r_map, const int cddata_type, const int mix_mode, const float mix_factor, const float *mix_weights, const int num_elem_dst, const bool use_create, const bool use_delete, CustomData *cd_src, CustomData *cd_dst, const bool use_dupref_dst, const int tolayers, bool *use_layers_src, const int num_layers_src) { void *data_src, *data_dst = NULL; int idx_src = num_layers_src; int idx_dst, tot_dst = CustomData_number_of_layers(cd_dst, cddata_type); bool *data_dst_to_delete = NULL; if (!use_layers_src) { /* No source at all, we can only delete all dest if requested... */ if (use_delete) { idx_dst = tot_dst; while (idx_dst--) { CustomData_free_layer(cd_dst, cddata_type, num_elem_dst, idx_dst); } } return true; } switch (tolayers) { case DT_LAYERS_INDEX_DST: idx_dst = tot_dst; /* Find last source actually used! */ while (idx_src-- && !use_layers_src[idx_src]); idx_src++; if (idx_dst < idx_src) { if (!use_create) { return true; } /* Create as much data layers as necessary! */ for (; idx_dst < idx_src; idx_dst++) { CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst); } } else if (use_delete && idx_dst > idx_src) { while (idx_dst-- > idx_src) { CustomData_free_layer(cd_dst, cddata_type, num_elem_dst, idx_dst); } } if (r_map) { while (idx_src--) { if (!use_layers_src[idx_src]) { continue; } data_src = CustomData_get_layer_n(cd_src, cddata_type, idx_src); /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */ if (use_dupref_dst) { data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_src, num_elem_dst); } else { data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_src); } data_transfer_layersmapping_add_item_cd(r_map, cddata_type, mix_mode, mix_factor, mix_weights, data_src, data_dst); } } break; case DT_LAYERS_NAME_DST: if (use_delete) { if (tot_dst) { data_dst_to_delete = MEM_mallocN(sizeof(*data_dst_to_delete) * (size_t)tot_dst, __func__); memset(data_dst_to_delete, true, sizeof(*data_dst_to_delete) * (size_t)tot_dst); } } while (idx_src--) { const char *name; if (!use_layers_src[idx_src]) { continue; } name = CustomData_get_layer_name(cd_src, cddata_type, idx_src); data_src = CustomData_get_layer_n(cd_src, cddata_type, idx_src); if ((idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name)) == -1) { if (!use_create) { if (r_map) { BLI_freelistN(r_map); } return true; } CustomData_add_layer_named(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst, name); idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name); } else if (data_dst_to_delete) { data_dst_to_delete[idx_dst] = false; } if (r_map) { /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */ if (use_dupref_dst) { data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst); } else { data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst); } data_transfer_layersmapping_add_item_cd(r_map, cddata_type, mix_mode, mix_factor, mix_weights, data_src, data_dst); } } if (data_dst_to_delete) { /* Note: This won't affect newly created layers, if any, since tot_dst has not been updated! * Also, looping backward ensures us we do not suffer from index shifting when deleting a layer. */ for (idx_dst = tot_dst; idx_dst--;) { if (data_dst_to_delete[idx_dst]) { CustomData_free_layer(cd_dst, cddata_type, num_elem_dst, idx_dst); } } MEM_freeN(data_dst_to_delete); } break; default: return false; } return true; }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, ModifierApplyFlag flag) { DerivedMesh *dm = derivedData; DerivedMesh *result; ScrewModifierData *ltmd = (ScrewModifierData *) md; const int useRenderParams = flag & MOD_APPLY_RENDER; int *origindex; int mpoly_index = 0; unsigned int step; unsigned int i, j; unsigned int i1, i2; unsigned int step_tot = useRenderParams ? ltmd->render_steps : ltmd->steps; const bool do_flip = ltmd->flag & MOD_SCREW_NORMAL_FLIP ? 1 : 0; const int quad_ord[4] = { do_flip ? 3 : 0, do_flip ? 2 : 1, do_flip ? 1 : 2, do_flip ? 0 : 3, }; const int quad_ord_ofs[4] = { do_flip ? 2 : 0, do_flip ? 1 : 1, do_flip ? 0 : 2, do_flip ? 3 : 3, }; unsigned int maxVerts = 0, maxEdges = 0, maxPolys = 0; const unsigned int totvert = (unsigned int)dm->getNumVerts(dm); const unsigned int totedge = (unsigned int)dm->getNumEdges(dm); const unsigned int totpoly = (unsigned int)dm->getNumPolys(dm); unsigned int *edge_poly_map = NULL; /* orig edge to orig poly */ unsigned int *vert_loop_map = NULL; /* orig vert to orig loop */ /* UV Coords */ const unsigned int mloopuv_layers_tot = (unsigned int)CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV); MLoopUV **mloopuv_layers = BLI_array_alloca(mloopuv_layers, mloopuv_layers_tot); float uv_u_scale; float uv_v_minmax[2] = {FLT_MAX, -FLT_MAX}; float uv_v_range_inv; float uv_axis_plane[4]; char axis_char = 'X'; bool close; float angle = ltmd->angle; float screw_ofs = ltmd->screw_ofs; float axis_vec[3] = {0.0f, 0.0f, 0.0f}; float tmp_vec1[3], tmp_vec2[3]; float mat3[3][3]; float mtx_tx[4][4]; /* transform the coords by an object relative to this objects transformation */ float mtx_tx_inv[4][4]; /* inverted */ float mtx_tmp_a[4][4]; unsigned int vc_tot_linked = 0; short other_axis_1, other_axis_2; const float *tmpf1, *tmpf2; unsigned int edge_offset; MPoly *mpoly_orig, *mpoly_new, *mp_new; MLoop *mloop_orig, *mloop_new, *ml_new; MEdge *medge_orig, *med_orig, *med_new, *med_new_firstloop, *medge_new; MVert *mvert_new, *mvert_orig, *mv_orig, *mv_new, *mv_new_base; ScrewVertConnect *vc, *vc_tmp, *vert_connect = NULL; const char mpoly_flag = (ltmd->flag & MOD_SCREW_SMOOTH_SHADING) ? ME_SMOOTH : 0; /* don't do anything? */ if (!totvert) return CDDM_from_template(dm, 0, 0, 0, 0, 0); switch (ltmd->axis) { case 0: other_axis_1 = 1; other_axis_2 = 2; break; case 1: other_axis_1 = 0; other_axis_2 = 2; break; default: /* 2, use default to quiet warnings */ other_axis_1 = 0; other_axis_2 = 1; break; } axis_vec[ltmd->axis] = 1.0f; if (ltmd->ob_axis) { /* calc the matrix relative to the axis object */ invert_m4_m4(mtx_tmp_a, ob->obmat); copy_m4_m4(mtx_tx_inv, ltmd->ob_axis->obmat); mul_m4_m4m4(mtx_tx, mtx_tmp_a, mtx_tx_inv); /* calc the axis vec */ mul_mat3_m4_v3(mtx_tx, axis_vec); /* only rotation component */ normalize_v3(axis_vec); /* screw */ if (ltmd->flag & MOD_SCREW_OBJECT_OFFSET) { /* find the offset along this axis relative to this objects matrix */ float totlen = len_v3(mtx_tx[3]); if (totlen != 0.0f) { float zero[3] = {0.0f, 0.0f, 0.0f}; float cp[3]; screw_ofs = closest_to_line_v3(cp, mtx_tx[3], zero, axis_vec); } else { screw_ofs = 0.0f; } } /* angle */ #if 0 /* cant incluide this, not predictable enough, though quite fun. */ if (ltmd->flag & MOD_SCREW_OBJECT_ANGLE) { float mtx3_tx[3][3]; copy_m3_m4(mtx3_tx, mtx_tx); float vec[3] = {0, 1, 0}; float cross1[3]; float cross2[3]; cross_v3_v3v3(cross1, vec, axis_vec); mul_v3_m3v3(cross2, mtx3_tx, cross1); { float c1[3]; float c2[3]; float axis_tmp[3]; cross_v3_v3v3(c1, cross2, axis_vec); cross_v3_v3v3(c2, axis_vec, c1); angle = angle_v3v3(cross1, c2); cross_v3_v3v3(axis_tmp, cross1, c2); normalize_v3(axis_tmp); if (len_v3v3(axis_tmp, axis_vec) > 1.0f) angle = -angle; } } #endif } else { /* exis char is used by i_rotate*/ axis_char = (char)(axis_char + ltmd->axis); /* 'X' + axis */ /* useful to be able to use the axis vec in some cases still */ zero_v3(axis_vec); axis_vec[ltmd->axis] = 1.0f; } /* apply the multiplier */ angle *= (float)ltmd->iter; screw_ofs *= (float)ltmd->iter; uv_u_scale = 1.0f / (float)(step_tot); /* multiplying the steps is a bit tricky, this works best */ step_tot = ((step_tot + 1) * ltmd->iter) - (ltmd->iter - 1); /* will the screw be closed? * Note! smaller then FLT_EPSILON * 100 gives problems with float precision so its never closed. */ if (fabsf(screw_ofs) <= (FLT_EPSILON * 100.0f) && fabsf(fabsf(angle) - ((float)M_PI * 2.0f)) <= (FLT_EPSILON * 100.0f)) { close = 1; step_tot--; if (step_tot < 3) step_tot = 3; maxVerts = totvert * step_tot; /* -1 because we're joining back up */ maxEdges = (totvert * step_tot) + /* these are the edges between new verts */ (totedge * step_tot); /* -1 because vert edges join */ maxPolys = totedge * step_tot; screw_ofs = 0.0f; } else { close = 0; if (step_tot < 3) step_tot = 3; maxVerts = totvert * step_tot; /* -1 because we're joining back up */ maxEdges = (totvert * (step_tot - 1)) + /* these are the edges between new verts */ (totedge * step_tot); /* -1 because vert edges join */ maxPolys = totedge * (step_tot - 1); } if ((ltmd->flag & MOD_SCREW_UV_STRETCH_U) == 0) { uv_u_scale = (uv_u_scale / (float)ltmd->iter) * (angle / ((float)M_PI * 2.0f)); } result = CDDM_from_template(dm, (int)maxVerts, (int)maxEdges, 0, (int)maxPolys * 4, (int)maxPolys); /* copy verts from mesh */ mvert_orig = dm->getVertArray(dm); medge_orig = dm->getEdgeArray(dm); mvert_new = result->getVertArray(result); mpoly_new = result->getPolyArray(result); mloop_new = result->getLoopArray(result); medge_new = result->getEdgeArray(result); if (!CustomData_has_layer(&result->polyData, CD_ORIGINDEX)) { CustomData_add_layer(&result->polyData, CD_ORIGINDEX, CD_CALLOC, NULL, (int)maxPolys); } origindex = CustomData_get_layer(&result->polyData, CD_ORIGINDEX); DM_copy_vert_data(dm, result, 0, 0, (int)totvert); /* copy first otherwise this overwrites our own vertex normals */ if (mloopuv_layers_tot) { float zero_co[3] = {0}; plane_from_point_normal_v3(uv_axis_plane, zero_co, axis_vec); } if (mloopuv_layers_tot) { unsigned int uv_lay; for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) { mloopuv_layers[uv_lay] = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, (int)uv_lay); } if (ltmd->flag & MOD_SCREW_UV_STRETCH_V) { for (i = 0, mv_orig = mvert_orig; i < totvert; i++, mv_orig++) { const float v = dist_squared_to_plane_v3(mv_orig->co, uv_axis_plane); uv_v_minmax[0] = min_ff(v, uv_v_minmax[0]); uv_v_minmax[1] = max_ff(v, uv_v_minmax[1]); } uv_v_minmax[0] = sqrtf_signed(uv_v_minmax[0]); uv_v_minmax[1] = sqrtf_signed(uv_v_minmax[1]); } uv_v_range_inv = uv_v_minmax[1] - uv_v_minmax[0]; uv_v_range_inv = uv_v_range_inv ? 1.0f / uv_v_range_inv : 0.0f; } /* Set the locations of the first set of verts */ mv_new = mvert_new; mv_orig = mvert_orig; /* Copy the first set of edges */ med_orig = medge_orig; med_new = medge_new; for (i = 0; i < totedge; i++, med_orig++, med_new++) { med_new->v1 = med_orig->v1; med_new->v2 = med_orig->v2; med_new->crease = med_orig->crease; med_new->flag = med_orig->flag & ~ME_LOOSEEDGE; } /* build polygon -> edge map */ if (totpoly) { MPoly *mp_orig; mpoly_orig = dm->getPolyArray(dm); mloop_orig = dm->getLoopArray(dm); edge_poly_map = MEM_mallocN(sizeof(*edge_poly_map) * totedge, __func__); memset(edge_poly_map, 0xff, sizeof(*edge_poly_map) * totedge); vert_loop_map = MEM_mallocN(sizeof(*vert_loop_map) * totvert, __func__); memset(vert_loop_map, 0xff, sizeof(*vert_loop_map) * totvert); for (i = 0, mp_orig = mpoly_orig; i < totpoly; i++, mp_orig++) { unsigned int loopstart = (unsigned int)mp_orig->loopstart; unsigned int loopend = loopstart + (unsigned int)mp_orig->totloop; MLoop *ml_orig = &mloop_orig[loopstart]; unsigned int k; for (k = loopstart; k < loopend; k++, ml_orig++) { edge_poly_map[ml_orig->e] = i; vert_loop_map[ml_orig->v] = k; /* also order edges based on faces */ if (medge_new[ml_orig->e].v1 != ml_orig->v) { SWAP(unsigned int, medge_new[ml_orig->e].v1, medge_new[ml_orig->e].v2); } } } }
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; #ifdef USE_MFACE_WORKAROUND unsigned int mpoly_prev_testindex = UINT_MAX; #endif /* we can't bake in edit mode */ if (me->edit_btmesh) return; 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; 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); } 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; #ifdef USE_MFACE_WORKAROUND if (lt->poly != mpoly_prev_testindex) { test_index_face_looptri(mp, me->mloop, &looptri[i]); mpoly_prev_testindex = lt->poly; } #endif 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); }
// ================================================================= // Return the number of faces by summing up // the facecounts of the parts. // hint: This is done because mesh->getFacesCount() does // count loose edges as extra faces, which is not what we want here. // ================================================================= void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me) { COLLADAFW::MeshPrimitiveArray& prim_arr = collada_mesh->getMeshPrimitives(); int total_poly_count = 0; int total_loop_count = 0; // collect edge_count and face_count from all parts for (int i = 0; i < prim_arr.getCount(); i++) { COLLADAFW::MeshPrimitive *mp = prim_arr[i]; int type = mp->getPrimitiveType(); switch (type) { case COLLADAFW::MeshPrimitive::TRIANGLES: case COLLADAFW::MeshPrimitive::TRIANGLE_FANS: case COLLADAFW::MeshPrimitive::POLYLIST: case COLLADAFW::MeshPrimitive::POLYGONS: { COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons *)mp; size_t prim_poly_count = mpvc->getFaceCount(); size_t prim_loop_count = 0; for (int index=0; index < prim_poly_count; index++) { prim_loop_count += get_vertex_count(mpvc, index); } total_poly_count += prim_poly_count; total_loop_count += prim_loop_count; break; } default: break; } } // Add the data containers if (total_poly_count > 0) { me->totpoly = total_poly_count; me->totloop = total_loop_count; me->mpoly = (MPoly *)CustomData_add_layer(&me->pdata, CD_MPOLY, CD_CALLOC, NULL, me->totpoly); me->mloop = (MLoop *)CustomData_add_layer(&me->ldata, CD_MLOOP, CD_CALLOC, NULL, me->totloop); unsigned int totuvset = collada_mesh->getUVCoords().getInputInfosArray().getCount(); for (int i = 0; i < totuvset; i++) { if (collada_mesh->getUVCoords().getLength(i) == 0) { totuvset = 0; break; } } if (totuvset > 0) { for (int i = 0; i < totuvset; i++) { COLLADAFW::MeshVertexData::InputInfos *info = collada_mesh->getUVCoords().getInputInfosArray()[i]; COLLADAFW::String &uvname = info->mName; // Allocate space for UV_data CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DEFAULT, NULL, me->totpoly, uvname.c_str()); CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DEFAULT, NULL, me->totloop, uvname.c_str()); } // activate the first uv map me->mtpoly = (MTexPoly *)CustomData_get_layer_n(&me->pdata, CD_MTEXPOLY, 0); me->mloopuv = (MLoopUV *) CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, 0); } int totcolset = collada_mesh->getColors().getInputInfosArray().getCount(); if (totcolset > 0) { for (int i = 0; i < totcolset; i++) { COLLADAFW::MeshVertexData::InputInfos *info = collada_mesh->getColors().getInputInfosArray()[i]; COLLADAFW::String colname = extract_vcolname(info->mName); CustomData_add_layer_named(&me->ldata,CD_MLOOPCOL,CD_DEFAULT,NULL,me->totloop, colname.c_str()); } me->mloopcol = (MLoopCol *) CustomData_get_layer_n(&me->ldata, CD_MLOOPCOL, 0); } } }
static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, Object *ob, DerivedMesh *dm, int axis) { const float tolerance_sq = mmd->tolerance * mmd->tolerance; const int do_vtargetmap = !(mmd->flag & MOD_MIR_NO_MERGE); int is_vtargetmap = FALSE; /* true when it should be used */ DerivedMesh *result; const int maxVerts = dm->getNumVerts(dm); const int maxEdges = dm->getNumEdges(dm); const int maxLoops = dm->getNumLoops(dm); const int maxPolys = dm->getNumPolys(dm); MVert *mv, *mv_prev; MEdge *me; MLoop *ml; MPoly *mp; float mtx[4][4]; int i, j; int a, totshape; int *vtargetmap = NULL, *vtmap_a = NULL, *vtmap_b = NULL; /* mtx is the mirror transformation */ unit_m4(mtx); mtx[axis][axis] = -1.0f; if (mmd->mirror_ob) { float tmp[4][4]; float itmp[4][4]; /* tmp is a transform from coords relative to the object's own origin, * to coords relative to the mirror object origin */ invert_m4_m4(tmp, mmd->mirror_ob->obmat); mult_m4_m4m4(tmp, tmp, ob->obmat); /* itmp is the reverse transform back to origin-relative coordinates */ invert_m4_m4(itmp, tmp); /* combine matrices to get a single matrix that translates coordinates into * mirror-object-relative space, does the mirror, and translates back to * origin-relative space */ mult_m4_m4m4(mtx, mtx, tmp); mult_m4_m4m4(mtx, itmp, mtx); } result = CDDM_from_template(dm, maxVerts * 2, maxEdges * 2, 0, maxLoops * 2, maxPolys * 2); /*copy customdata to original geometry*/ DM_copy_vert_data(dm, result, 0, 0, maxVerts); DM_copy_edge_data(dm, result, 0, 0, maxEdges); DM_copy_loop_data(dm, result, 0, 0, maxLoops); DM_copy_poly_data(dm, result, 0, 0, maxPolys); /* 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, CDDM_get_verts(result)); } 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)); } /* copy customdata to new geometry, * copy from its self because this data may have been created in the checks above */ DM_copy_vert_data(result, result, 0, maxVerts, maxVerts); DM_copy_edge_data(result, result, 0, maxEdges, maxEdges); /* loops are copied later */ DM_copy_poly_data(result, result, 0, maxPolys, maxPolys); if (do_vtargetmap) { /* second half is filled with -1 */ vtargetmap = MEM_mallocN(sizeof(int) * maxVerts * 2, "MOD_mirror tarmap"); vtmap_a = vtargetmap; vtmap_b = vtargetmap + maxVerts; } /* mirror vertex coordinates */ mv_prev = CDDM_get_verts(result); mv = mv_prev + maxVerts; for (i = 0; i < maxVerts; i++, mv++, mv_prev++) { mul_m4_v3(mtx, mv->co); if (do_vtargetmap) { /* compare location of the original and mirrored vertex, to see if they * should be mapped for merging */ if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) { *vtmap_a = maxVerts + i; is_vtargetmap = TRUE; } else { *vtmap_a = -1; } *vtmap_b = -1; /* fill here to avoid 2x loops */ vtmap_a++; vtmap_b++; } } /* handle shape keys */ totshape = CustomData_number_of_layers(&result->vertData, CD_SHAPEKEY); for (a = 0; a < totshape; a++) { float (*cos)[3] = CustomData_get_layer_n(&result->vertData, CD_SHAPEKEY, a); for (i = maxVerts; i < result->numVertData; i++) { mul_m4_v3(mtx, cos[i]); } } /* adjust mirrored edge vertex indices */ me = CDDM_get_edges(result) + maxEdges; for (i = 0; i < maxEdges; i++, me++) { me->v1 += maxVerts; me->v2 += maxVerts; } /* adjust mirrored poly loopstart indices, and reverse loop order (normals) */ mp = CDDM_get_polys(result) + maxPolys; ml = CDDM_get_loops(result); for (i = 0; i < maxPolys; i++, mp++) { MLoop *ml2; int e; /* reverse the loop, but we keep the first vertex in the face the same, * to ensure that quads are split the same way as on the other side */ DM_copy_loop_data(result, result, mp->loopstart, mp->loopstart + maxLoops, 1); for (j = 1; j < mp->totloop; j++) DM_copy_loop_data(result, result, mp->loopstart + j, mp->loopstart + maxLoops + mp->totloop - j, 1); ml2 = ml + mp->loopstart + maxLoops; e = ml2[0].e; for (j = 0; j < mp->totloop - 1; j++) { ml2[j].e = ml2[j + 1].e; } ml2[mp->totloop - 1].e = e; mp->loopstart += maxLoops; } /* adjust mirrored loop vertex and edge indices */ ml = CDDM_get_loops(result) + maxLoops; for (i = 0; i < maxLoops; i++, ml++) { ml->v += maxVerts; ml->e += maxEdges; } /* handle uvs, * let tessface recalc handle updating the MTFace data */ if (mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V)) { const int do_mirr_u = (mmd->flag & MOD_MIR_MIRROR_U) != 0; const int do_mirr_v = (mmd->flag & MOD_MIR_MIRROR_V) != 0; const int totuv = CustomData_number_of_layers(&result->loopData, CD_MLOOPUV); for (a = 0; a < totuv; a++) { MLoopUV *dmloopuv = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, a); int j = maxLoops; dmloopuv += j; /* second set of loops only */ for (; j-- > 0; dmloopuv++) { if (do_mirr_u) dmloopuv->uv[0] = 1.0f - dmloopuv->uv[0]; if (do_mirr_v) dmloopuv->uv[1] = 1.0f - dmloopuv->uv[1]; } } } /* handle vgroup stuff */ if ((mmd->flag & MOD_MIR_VGROUP) && CustomData_has_layer(&result->vertData, CD_MDEFORMVERT)) { MDeformVert *dvert = (MDeformVert *) CustomData_get_layer(&result->vertData, CD_MDEFORMVERT) + maxVerts; int *flip_map = NULL, flip_map_len = 0; flip_map = defgroup_flip_map(ob, &flip_map_len, FALSE); if (flip_map) { for (i = 0; i < maxVerts; dvert++, i++) { /* merged vertices get both groups, others get flipped */ if (do_vtargetmap && (vtargetmap[i] != -1)) defvert_flip_merged(dvert, flip_map, flip_map_len); else defvert_flip(dvert, flip_map, flip_map_len); } MEM_freeN(flip_map); } } if (do_vtargetmap) { /* slow - so only call if one or more merge verts are found, * users may leave this on and not realize there is nothing to merge - campbell */ if (is_vtargetmap) { result = CDDM_merge_verts(result, vtargetmap); } MEM_freeN(vtargetmap); } return result; }
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); 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; int *vgroup_start_cap_remap = NULL; int vgroup_start_cap_remap_len = 0; int *vgroup_end_cap_remap = NULL; int vgroup_end_cap_remap_len = 0; 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) { vgroup_start_cap_remap = BKE_object_defgroup_index_map_create(amd->start_cap, ob, &vgroup_start_cap_remap_len); 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) { vgroup_end_cap_remap = BKE_object_defgroup_index_map_create(amd->end_cap, ob, &vgroup_end_cap_remap_len); 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_v3(offset[3], amd->offset); } if (amd->offset_type & MOD_ARR_OFF_RELATIVE) { float min[3], max[3]; const MVert *src_mv; INIT_MINMAX(min, max); for (src_mv = src_mvert, j = chunk_nverts; j--; src_mv++) { minmax_v3v3_v3(min, max, src_mv->co); } for (j = 3; j--; ) { offset[3][j] += amd->scale[j] * (max[j] - min[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_fac = mat4_to_scale(amd->curve_ob->obmat); length = scale_fac * 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 + 1; } 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_malloc_arrayN(result_nverts, sizeof(int), "mod array doubles map"); copy_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 won't have mesh data in the custom data arrays. * now add mvert/medge/mpoly 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 */ while (target != -1 && !ELEM(full_doubles_map[target], -1, target)) { /* If target is already mapped, we only follow that mapping if final target remains * close enough from current vert (otherwise no mapping at all). */ if (compare_len_v3v3(result_dm_verts[this_chunk_index].co, result_dm_verts[full_doubles_map[target]].co, amd->merge_dist)) { target = full_doubles_map[target]; } else { 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); } } } /* handle UVs */ if (chunk_nloops > 0 && is_zero_v2(amd->uv_offset) == false) { const int totuv = CustomData_number_of_layers(&result->loopData, CD_MLOOPUV); for (i = 0; i < totuv; i++) { MLoopUV *dmloopuv = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, i); dmloopuv += chunk_nloops; for (c = 1; c < count; c++) { const float uv_offset[2] = { amd->uv_offset[0] * (float)c, amd->uv_offset[1] * (float)c, }; int l_index = chunk_nloops; for (; l_index-- != 0; dmloopuv++) { dmloopuv->uv[0] += uv_offset[0]; dmloopuv->uv[1] += uv_offset[1]; } } } } 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); } /* 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, vgroup_start_cap_remap, vgroup_start_cap_remap_len); /* 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); } } 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, vgroup_end_cap_remap, vgroup_end_cap_remap_len); /* 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); } } /* done capping */ /* Handle merging */ tot_doubles = 0; if (use_merge) { for (i = 0; i < result_nverts; i++) { int new_i = full_doubles_map[i]; if (new_i != -1) { /* We have to follow chains of doubles (merge start/end especially is likely to create some), * those are not supported at all by CDDM_merge_verts! */ while (!ELEM(full_doubles_map[new_i], -1, new_i)) { new_i = full_doubles_map[new_i]; } if (i == new_i) { full_doubles_map[i] = -1; } else { full_doubles_map[i] = new_i; 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; } if (vgroup_start_cap_remap) { MEM_freeN(vgroup_start_cap_remap); } if (vgroup_end_cap_remap) { MEM_freeN(vgroup_end_cap_remap); } return result; }
/** * Copies data from loop/poly to face (assumes all triangles or quads, as generated by most subdivisions) */ static void loops_to_customdata_corners(DerivedMesh *output) { int i, numPolys, numTex, numCol, hasPCol; MPoly *polys; //if (!CustomData_get_layer_n(&output->loopData, CD_MLOOPCOL, n)) { // Not sure how this works with "n" ? // CustomData_add_layer(&output->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, output->numVertData); //} numCol = CustomData_number_of_layers(&output->loopData, CD_MLOOPCOL); numTex = CustomData_number_of_layers(&output->loopData, CD_MLOOPUV); hasPCol = CustomData_has_layer(&output->loopData, CD_PREVIEW_MLOOPCOL); polys = output->getPolyArray(output); numPolys = output->getNumPolys(output); for (i = 0; i < numTex; i++) { int k; MTexPoly *texpoly = CustomData_get_layer_n(&output->polyData, CD_MTEXPOLY, i); MLoopUV *mloopuv = CustomData_get_layer_n(&output->loopData, CD_MLOOPUV, i); MTFace *texface = CustomData_get_layer_n(&output->faceData, CD_MTFACE, i); if (!texface) { texface = CustomData_add_layer(&output->faceData, CD_MTFACE, CD_CALLOC, NULL, numPolys); } for (k = 0; k < numPolys; k++) { int j; MPoly *poly = &polys[k]; MLoopUV *ml = &mloopuv[poly->loopstart]; ME_MTEXFACE_CPY(&texface[k], &texpoly[k]); for (j = 0; j < poly->totloop; j++) { copy_v2_v2(texface[k].uv[j], ml[j].uv); } } } for (i = 0; i < numCol; i++) { int k; MLoopCol *mloopcol = CustomData_get_layer_n(&output->loopData, CD_MLOOPCOL, i); MCol *mcol = CustomData_get_layer_n(&output->faceData, CD_MCOL, i); if (!mcol) { mcol = CustomData_add_layer(&output->faceData, CD_MCOL, CD_CALLOC, NULL, numPolys * 4); } for (k = 0; k < numPolys; k++) { int j; MPoly *poly = &polys[k]; MLoopCol *ml = &mloopcol[poly->loopstart]; for (j = 0; j < poly->totloop; j++) { MESH_MLOOPCOL_TO_MCOL(&ml[j], &mcol[j]); } mcol += 4; } } if (hasPCol) { int k; MLoopCol *mloopcol = CustomData_get_layer(&output->loopData, CD_PREVIEW_MLOOPCOL); MCol *mcol = CustomData_get_layer(&output->faceData, CD_PREVIEW_MCOL); if (!mcol) { mcol = CustomData_add_layer(&output->faceData, CD_MCOL, CD_CALLOC, NULL, numPolys * 4); } for (k = 0; k < numPolys; k++) { int j; MPoly *poly = &polys[k]; MLoopCol *ml = &mloopcol[poly->loopstart]; for (j = 0; j < poly->totloop; j++) { MESH_MLOOPCOL_TO_MCOL(&ml[j], &mcol[j]); } mcol += 4; } } }
// ======================================================================= // Read all faces from TRIANGLES, TRIANGLE_FANS, POLYLIST, POLYGON // Important: This function MUST be called before read_lines() // Otherwise we will loose all edges from faces (see read_lines() above) // // TODO: import uv set names // ======================================================================== void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me) { unsigned int i; allocate_poly_data(collada_mesh, me); UVDataWrapper uvs(collada_mesh->getUVCoords()); MPoly *mpoly = me->mpoly; MLoop *mloop = me->mloop; int loop_index = 0; MaterialIdPrimitiveArrayMap mat_prim_map; COLLADAFW::MeshPrimitiveArray& prim_arr = collada_mesh->getMeshPrimitives(); COLLADAFW::MeshVertexData& nor = collada_mesh->getNormals(); for (i = 0; i < prim_arr.getCount(); i++) { COLLADAFW::MeshPrimitive *mp = prim_arr[i]; // faces size_t prim_totpoly = mp->getFaceCount(); unsigned int *position_indices = mp->getPositionIndices().getData(); unsigned int *normal_indices = mp->getNormalIndices().getData(); bool mp_has_normals = primitive_has_useable_normals(mp); bool mp_has_faces = primitive_has_faces(mp); int collada_meshtype = mp->getPrimitiveType(); // since we cannot set mpoly->mat_nr here, we store a portion of me->mpoly in Primitive Primitive prim = {mpoly, 0}; COLLADAFW::IndexListArray& index_list_array = mp->getUVCoordIndicesArray(); // If MeshPrimitive is TRIANGLE_FANS we split it into triangles // The first trifan vertex will be the first vertex in every triangle // XXX The proper function of TRIANGLE_FANS is not tested!!! // XXX In particular the handling of the normal_indices looks very wrong to me if (collada_meshtype == COLLADAFW::MeshPrimitive::TRIANGLE_FANS) { unsigned grouped_vertex_count = mp->getGroupedVertexElementsCount(); for (unsigned int group_index = 0; group_index < grouped_vertex_count; group_index++) { unsigned int first_vertex = position_indices[0]; // Store first trifan vertex unsigned int first_normal = normal_indices[0]; // Store first trifan vertex normal unsigned int vertex_count = mp->getGroupedVerticesVertexCount(group_index); for (unsigned int vertex_index = 0; vertex_index < vertex_count - 2; vertex_index++) { // For each triangle store indeces of its 3 vertices unsigned int triangle_vertex_indices[3] = {first_vertex, position_indices[1], position_indices[2]}; set_poly_indices(mpoly, mloop, loop_index, triangle_vertex_indices, 3); if (mp_has_normals) { // vertex normals, same inplementation as for the triangles // the same for vertces normals unsigned int vertex_normal_indices[3] = {first_normal, normal_indices[1], normal_indices[2]}; if (!is_flat_face(vertex_normal_indices, nor, 3)) mpoly->flag |= ME_SMOOTH; normal_indices++; } mpoly++; mloop += 3; loop_index += 3; prim.totpoly++; } // Moving cursor to the next triangle fan. if (mp_has_normals) normal_indices += 2; position_indices += 2; } } if (collada_meshtype == COLLADAFW::MeshPrimitive::POLYLIST || collada_meshtype == COLLADAFW::MeshPrimitive::POLYGONS || collada_meshtype == COLLADAFW::MeshPrimitive::TRIANGLES) { COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons *)mp; unsigned int start_index = 0; for (unsigned int j = 0; j < prim_totpoly; j++) { // Vertices in polygon: int vcount = get_vertex_count(mpvc, j); set_poly_indices(mpoly, mloop, loop_index, position_indices, vcount); for (unsigned int l = 0; l < index_list_array.getCount(); l++) { int uvset_index = index_list_array[l]->getSetIndex(); // get mtface by face index and uv set index MLoopUV *mloopuv = (MLoopUV *)CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, uvset_index); set_face_uv(mloopuv+loop_index, uvs, start_index, *index_list_array[l], vcount); } if (mp_has_normals) { if (!is_flat_face(normal_indices, nor, vcount)) mpoly->flag |= ME_SMOOTH; } mpoly++; mloop += vcount; loop_index += vcount; start_index += vcount; prim.totpoly++; if (mp_has_normals) normal_indices += vcount; position_indices += vcount; } } else if (collada_meshtype == COLLADAFW::MeshPrimitive::LINES) { continue; // read the lines later after all the rest is done } if (mp_has_faces) mat_prim_map[mp->getMaterialId()].push_back(prim); } geom_uid_mat_mapping_map[collada_mesh->getUniqueId()] = mat_prim_map; }