static PyObject *bpy_bmlayercollection_subscript_str(BPy_BMLayerCollection *self, const char *keyname) { CustomData *data; int index; BPY_BM_CHECK_OBJ(self); data = bpy_bm_customdata_get(self->bm, self->htype); index = CustomData_get_named_layer(data, self->type, keyname); /* type relative */ if (index != -1) { return BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, index); } else { PyErr_Format(PyExc_KeyError, "BMLayerCollection[key]: key \"%.200s\" not found", keyname); return NULL; } }
static PyObject *bpy_bmlayercollection_get(BPy_BMLayerCollection *self, PyObject *args) { const char *key; PyObject *def = Py_None; BPY_BM_CHECK_OBJ(self); if (!PyArg_ParseTuple(args, "s|O:get", &key, &def)) { return NULL; } else { CustomData *data; int index; data = bpy_bm_customdata_get(self->bm, self->htype); index = CustomData_get_named_layer(data, self->type, key); /* type relative */ if (index != -1) { return BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, index); } } return Py_INCREF_RET(def); }
static int bake( Render *re, Main *bmain, Scene *scene, Object *ob_low, ListBase *selected_objects, ReportList *reports, const ScenePassType pass_type, const int margin, const BakeSaveMode save_mode, const bool is_clear, const bool is_split_materials, const bool is_automatic_name, const bool is_selected_to_active, const bool is_cage, const float cage_extrusion, const int normal_space, const BakeNormalSwizzle normal_swizzle[], const char *custom_cage, const char *filepath, const int width, const int height, const char *identifier, ScrArea *sa, const char *uv_layer) { int op_result = OPERATOR_CANCELLED; bool ok = false; Object *ob_cage = NULL; BakeHighPolyData *highpoly = NULL; int tot_highpoly = 0; char restrict_flag_low = ob_low->restrictflag; char restrict_flag_cage = 0; Mesh *me_low = NULL; Mesh *me_cage = NULL; float *result = NULL; BakePixel *pixel_array_low = NULL; BakePixel *pixel_array_high = NULL; const bool is_save_internal = (save_mode == R_BAKE_SAVE_INTERNAL); const bool is_noncolor = is_noncolor_pass(pass_type); const int depth = RE_pass_depth(pass_type); BakeImages bake_images = {NULL}; size_t num_pixels; int tot_materials; RE_bake_engine_set_engine_parameters(re, bmain, scene); if (!RE_bake_has_engine(re)) { BKE_report(reports, RPT_ERROR, "Current render engine does not support baking"); goto cleanup; } tot_materials = ob_low->totcol; if (uv_layer && uv_layer[0] != '\0') { Mesh *me = (Mesh *)ob_low->data; if (CustomData_get_named_layer(&me->ldata, CD_MLOOPUV, uv_layer) == -1) { BKE_reportf(reports, RPT_ERROR, "No UV layer named \"%s\" found in the object \"%s\"", uv_layer, ob_low->id.name + 2); goto cleanup; } } if (tot_materials == 0) { if (is_save_internal) { BKE_report(reports, RPT_ERROR, "No active image found, add a material or bake to an external file"); goto cleanup; } else if (is_split_materials) { BKE_report(reports, RPT_ERROR, "No active image found, add a material or bake without the Split Materials option"); goto cleanup; } else { /* baking externally without splitting materials */ tot_materials = 1; } } /* we overallocate in case there is more materials than images */ bake_images.data = MEM_mallocN(sizeof(BakeImage) * tot_materials, "bake images dimensions (width, height, offset)"); bake_images.lookup = MEM_mallocN(sizeof(int) * tot_materials, "bake images lookup (from material to BakeImage)"); build_image_lookup(bmain, ob_low, &bake_images); if (is_save_internal) { num_pixels = initialize_internal_images(&bake_images, reports); if (num_pixels == 0) { goto cleanup; } } else { /* when saving extenally always use the size specified in the UI */ num_pixels = (size_t)width * (size_t)height * bake_images.size; for (int i = 0; i < bake_images.size; i++) { bake_images.data[i].width = width; bake_images.data[i].height = height; bake_images.data[i].offset = (is_split_materials ? num_pixels : 0); bake_images.data[i].image = NULL; } if (!is_split_materials) { /* saving a single image */ for (int i = 0; i < tot_materials; i++) { bake_images.lookup[i] = 0; } } } if (is_selected_to_active) { CollectionPointerLink *link; tot_highpoly = 0; for (link = selected_objects->first; link; link = link->next) { Object *ob_iter = link->ptr.data; if (ob_iter == ob_low) continue; tot_highpoly ++; } if (is_cage && custom_cage[0] != '\0') { ob_cage = BLI_findstring(&bmain->object, custom_cage, offsetof(ID, name) + 2); if (ob_cage == NULL || ob_cage->type != OB_MESH) { BKE_report(reports, RPT_ERROR, "No valid cage object"); goto cleanup; } else { restrict_flag_cage = ob_cage->restrictflag; ob_cage->restrictflag |= OB_RESTRICT_RENDER; } } } pixel_array_low = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels low poly"); pixel_array_high = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels high poly"); result = MEM_callocN(sizeof(float) * depth * num_pixels, "bake return pixels"); /* get the mesh as it arrives in the renderer */ me_low = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0); BKE_mesh_split_faces(me_low); /* populate the pixel array with the face data */ if ((is_selected_to_active && (ob_cage == NULL) && is_cage) == false) RE_bake_pixels_populate(me_low, pixel_array_low, num_pixels, &bake_images, uv_layer); /* else populate the pixel array with the 'cage' mesh (the smooth version of the mesh) */ if (is_selected_to_active) { CollectionPointerLink *link; ModifierData *md, *nmd; ListBase modifiers_tmp, modifiers_original; int i = 0; /* prepare cage mesh */ if (ob_cage) { me_cage = BKE_mesh_new_from_object(bmain, scene, ob_cage, 1, 2, 0, 0); BKE_mesh_split_faces(me_cage); if ((me_low->totpoly != me_cage->totpoly) || (me_low->totloop != me_cage->totloop)) { BKE_report(reports, RPT_ERROR, "Invalid cage object, the cage mesh must have the same number " "of faces as the active object"); goto cleanup; } } else if (is_cage) { modifiers_original = ob_low->modifiers; BLI_listbase_clear(&modifiers_tmp); for (md = ob_low->modifiers.first; md; md = md->next) { /* Edge Split cannot be applied in the cage, * the cage is supposed to have interpolated normals * between the faces unless the geometry is physically * split. So we create a copy of the low poly mesh without * the eventual edge split.*/ if (md->type == eModifierType_EdgeSplit) continue; nmd = modifier_new(md->type); BLI_strncpy(nmd->name, md->name, sizeof(nmd->name)); modifier_copyData(md, nmd); BLI_addtail(&modifiers_tmp, nmd); } /* temporarily replace the modifiers */ ob_low->modifiers = modifiers_tmp; /* get the cage mesh as it arrives in the renderer */ me_cage = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0); BKE_mesh_split_faces(me_cage); RE_bake_pixels_populate(me_cage, pixel_array_low, num_pixels, &bake_images, uv_layer); } highpoly = MEM_callocN(sizeof(BakeHighPolyData) * tot_highpoly, "bake high poly objects"); /* populate highpoly array */ for (link = selected_objects->first; link; link = link->next) { TriangulateModifierData *tmd; Object *ob_iter = link->ptr.data; if (ob_iter == ob_low) continue; /* initialize highpoly_data */ highpoly[i].ob = ob_iter; highpoly[i].restrict_flag = ob_iter->restrictflag; /* triangulating so BVH returns the primitive_id that will be used for rendering */ highpoly[i].tri_mod = ED_object_modifier_add( reports, bmain, scene, highpoly[i].ob, "TmpTriangulate", eModifierType_Triangulate); tmd = (TriangulateModifierData *)highpoly[i].tri_mod; tmd->quad_method = MOD_TRIANGULATE_QUAD_FIXED; tmd->ngon_method = MOD_TRIANGULATE_NGON_EARCLIP; highpoly[i].me = BKE_mesh_new_from_object(bmain, scene, highpoly[i].ob, 1, 2, 0, 0); highpoly[i].ob->restrictflag &= ~OB_RESTRICT_RENDER; BKE_mesh_split_faces(highpoly[i].me); /* lowpoly to highpoly transformation matrix */ copy_m4_m4(highpoly[i].obmat, highpoly[i].ob->obmat); invert_m4_m4(highpoly[i].imat, highpoly[i].obmat); highpoly[i].is_flip_object = is_negative_m4(highpoly[i].ob->obmat); i++; } BLI_assert(i == tot_highpoly); ob_low->restrictflag |= OB_RESTRICT_RENDER; /* populate the pixel arrays with the corresponding face data for each high poly object */ if (!RE_bake_pixels_populate_from_objects( me_low, pixel_array_low, pixel_array_high, highpoly, tot_highpoly, num_pixels, ob_cage != NULL, cage_extrusion, ob_low->obmat, (ob_cage ? ob_cage->obmat : ob_low->obmat), me_cage)) { BKE_report(reports, RPT_ERROR, "Error handling selected objects"); goto cage_cleanup; } /* the baking itself */ for (i = 0; i < tot_highpoly; i++) { ok = RE_bake_engine(re, highpoly[i].ob, i, pixel_array_high, num_pixels, depth, pass_type, result); if (!ok) { BKE_reportf(reports, RPT_ERROR, "Error baking from object \"%s\"", highpoly[i].ob->id.name + 2); goto cage_cleanup; } } cage_cleanup: /* reverting data back */ if ((ob_cage == NULL) && is_cage) { ob_low->modifiers = modifiers_original; while ((md = BLI_pophead(&modifiers_tmp))) { modifier_free(md); } } if (!ok) { goto cleanup; } } else { /* make sure low poly renders */ ob_low->restrictflag &= ~OB_RESTRICT_RENDER; if (RE_bake_has_engine(re)) { ok = RE_bake_engine(re, ob_low, 0, pixel_array_low, num_pixels, depth, pass_type, result); } else { BKE_report(reports, RPT_ERROR, "Current render engine does not support baking"); goto cleanup; } } /* normal space conversion * the normals are expected to be in world space, +X +Y +Z */ if (ok && pass_type == SCE_PASS_NORMAL) { switch (normal_space) { case R_BAKE_SPACE_WORLD: { /* Cycles internal format */ if ((normal_swizzle[0] == R_BAKE_POSX) && (normal_swizzle[1] == R_BAKE_POSY) && (normal_swizzle[2] == R_BAKE_POSZ)) { break; } else { RE_bake_normal_world_to_world(pixel_array_low, num_pixels, depth, result, normal_swizzle); } break; } case R_BAKE_SPACE_OBJECT: { RE_bake_normal_world_to_object(pixel_array_low, num_pixels, depth, result, ob_low, normal_swizzle); break; } case R_BAKE_SPACE_TANGENT: { if (is_selected_to_active) { RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_low, normal_swizzle, ob_low->obmat); } else { /* from multiresolution */ Mesh *me_nores = NULL; ModifierData *md = NULL; int mode; md = modifiers_findByType(ob_low, eModifierType_Multires); if (md) { mode = md->mode; md->mode &= ~eModifierMode_Render; } me_nores = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0); BKE_mesh_split_faces(me_nores); RE_bake_pixels_populate(me_nores, pixel_array_low, num_pixels, &bake_images, uv_layer); RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_nores, normal_swizzle, ob_low->obmat); BKE_libblock_free(bmain, me_nores); if (md) md->mode = mode; } break; } default: break; } } if (!ok) { BKE_reportf(reports, RPT_ERROR, "Problem baking object \"%s\"", ob_low->id.name + 2); op_result = OPERATOR_CANCELLED; } else { /* save the results */ for (int i = 0; i < bake_images.size; i++) { BakeImage *bk_image = &bake_images.data[i]; if (is_save_internal) { ok = write_internal_bake_pixels( bk_image->image, pixel_array_low + bk_image->offset, result + bk_image->offset * depth, bk_image->width, bk_image->height, margin, is_clear, is_noncolor); /* might be read by UI to set active image for display */ bake_update_image(sa, bk_image->image); if (!ok) { BKE_reportf(reports, RPT_ERROR, "Problem saving the bake map internally for object \"%s\"", ob_low->id.name + 2); op_result = OPERATOR_CANCELLED; } else { BKE_report(reports, RPT_INFO, "Baking map saved to internal image, save it externally or pack it"); op_result = OPERATOR_FINISHED; } } /* save externally */ else { BakeData *bake = &scene->r.bake; char name[FILE_MAX]; BKE_image_path_from_imtype(name, filepath, bmain->name, 0, bake->im_format.imtype, true, false, NULL); if (is_automatic_name) { BLI_path_suffix(name, FILE_MAX, ob_low->id.name + 2, "_"); BLI_path_suffix(name, FILE_MAX, identifier, "_"); } if (is_split_materials) { if (bk_image->image) { BLI_path_suffix(name, FILE_MAX, bk_image->image->id.name + 2, "_"); } else { if (ob_low->mat[i]) { BLI_path_suffix(name, FILE_MAX, ob_low->mat[i]->id.name + 2, "_"); } else if (me_low->mat[i]) { BLI_path_suffix(name, FILE_MAX, me_low->mat[i]->id.name + 2, "_"); } else { /* if everything else fails, use the material index */ char tmp[4]; sprintf(tmp, "%d", i % 1000); BLI_path_suffix(name, FILE_MAX, tmp, "_"); } } } /* save it externally */ ok = write_external_bake_pixels( name, pixel_array_low + bk_image->offset, result + bk_image->offset * depth, bk_image->width, bk_image->height, margin, &bake->im_format, is_noncolor); if (!ok) { BKE_reportf(reports, RPT_ERROR, "Problem saving baked map in \"%s\"", name); op_result = OPERATOR_CANCELLED; } else { BKE_reportf(reports, RPT_INFO, "Baking map written to \"%s\"", name); op_result = OPERATOR_FINISHED; } if (!is_split_materials) { break; } } } } if (is_save_internal) refresh_images(&bake_images); cleanup: if (highpoly) { int i; for (i = 0; i < tot_highpoly; i++) { highpoly[i].ob->restrictflag = highpoly[i].restrict_flag; if (highpoly[i].tri_mod) ED_object_modifier_remove(reports, bmain, highpoly[i].ob, highpoly[i].tri_mod); if (highpoly[i].me) BKE_libblock_free(bmain, highpoly[i].me); } MEM_freeN(highpoly); } ob_low->restrictflag = restrict_flag_low; if (ob_cage) ob_cage->restrictflag = restrict_flag_cage; if (pixel_array_low) MEM_freeN(pixel_array_low); if (pixel_array_high) MEM_freeN(pixel_array_high); if (bake_images.data) MEM_freeN(bake_images.data); if (bake_images.lookup) MEM_freeN(bake_images.lookup); if (result) MEM_freeN(result); if (me_low) BKE_libblock_free(bmain, me_low); if (me_cage) BKE_libblock_free(bmain, me_cage); return op_result; }
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; }
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); }
bool BKE_mesh_uv_cdlayer_rename(Mesh *me, const char *old_name, const char *new_name, bool do_tessface) { CustomData *pdata, *ldata, *fdata; if (me->edit_btmesh) { pdata = &me->edit_btmesh->bm->pdata; ldata = &me->edit_btmesh->bm->ldata; /* No tessellated data in BMesh! */ fdata = NULL; do_tessface = false; } else { pdata = &me->pdata; ldata = &me->ldata; fdata = &me->fdata; do_tessface = (do_tessface && fdata->totlayer); } { const int pidx_start = CustomData_get_layer_index(pdata, CD_MTEXPOLY); const int lidx_start = CustomData_get_layer_index(ldata, CD_MLOOPUV); const int fidx_start = do_tessface ? CustomData_get_layer_index(fdata, CD_MTFACE) : -1; int pidx = CustomData_get_named_layer(pdata, CD_MTEXPOLY, old_name); int lidx = CustomData_get_named_layer(ldata, CD_MLOOPUV, old_name); int fidx = do_tessface ? CustomData_get_named_layer(fdata, CD_MTFACE, old_name) : -1; /* None of those cases should happen, in theory! * Note this assume we have the same number of mtexpoly, mloopuv and mtface layers! */ if (pidx == -1) { if (lidx == -1) { if (fidx == -1) { /* No layer found with this name! */ return false; } else { lidx = fidx; } } pidx = lidx; } else { if (lidx == -1) { lidx = pidx; } if (fidx == -1 && do_tessface) { fidx = pidx; } } #if 0 /* For now, we do not consider mismatch in indices (i.e. same name leading to (relative) different indices). */ else if (pidx != lidx) { lidx = pidx; } #endif /* Go back to absolute indices! */ pidx += pidx_start; lidx += lidx_start; if (fidx != -1) fidx += fidx_start; return BKE_mesh_uv_cdlayer_rename_index(me, pidx, lidx, fidx, new_name, do_tessface); }