Revert "Cleanup: remove legacy mesh save support"

Fixes T62793. Leave this in the blender2.7 branch for those that still rely
on it, but it will remain removed in master.
This commit is contained in:
Brecht Van Lommel 2019-03-22 18:16:46 +01:00
parent 8e6f765964
commit 9e3e92a908
Notes: blender-bot 2023-02-14 11:21:40 +01:00
Referenced by issue #62793, Legacy Mesh Format in 2.79
6 changed files with 236 additions and 6 deletions

View File

@ -182,12 +182,12 @@ enum {
/* On write, make backup `.blend1`, `.blend2` ... files, when the users preference is enabled */
#define G_FILE_HISTORY (1 << 25)
/* BMesh option to save as older mesh format */
// #define G_FILE_MESH_COMPAT (1 << 26)
#define G_FILE_MESH_COMPAT (1 << 26)
/* On write, restore paths after editing them (G_FILE_RELATIVE_REMAP) */
#define G_FILE_SAVE_COPY (1 << 27)
#define G_FILE_GLSL_NO_ENV_LIGHTING (1 << 28)
#define G_FILE_FLAGS_RUNTIME (G_FILE_NO_UI | G_FILE_RELATIVE_REMAP | G_FILE_SAVE_COPY)
#define G_FILE_FLAGS_RUNTIME (G_FILE_NO_UI | G_FILE_RELATIVE_REMAP | G_FILE_MESH_COMPAT | G_FILE_SAVE_COPY)
/* ENDIAN_ORDER: indicates what endianness the platform where the file was
* written had. */

View File

@ -339,6 +339,9 @@ void BKE_mesh_recalc_looptri(
const struct MVert *mvert,
int totloop, int totpoly,
struct MLoopTri *mlooptri);
int BKE_mesh_mpoly_to_mface(
struct CustomData *fdata, struct CustomData *ldata,
struct CustomData *pdata, int totface, int totloop, int totpoly);
void BKE_mesh_convert_mfaces_to_mpolys(struct Mesh *mesh);
void BKE_mesh_do_versions_convert_mfaces_to_mpolys(struct Mesh *mesh);
void BKE_mesh_convert_mfaces_to_mpolys_ex(

View File

@ -3165,9 +3165,130 @@ void BKE_mesh_recalc_looptri(
#undef ML_TO_MLT
}
static void bm_corners_to_loops_ex(
ID *id, CustomData *fdata, CustomData *ldata, CustomData *pdata,
MFace *mface, int totloop, int findex, int loopstart, int numTex, int numCol)
/* -------------------------------------------------------------------- */
#ifdef USE_BMESH_SAVE_AS_COMPAT
/**
* This function recreates a tessellation.
* returns number of tessellation faces.
*
* for forwards compat only quad->tri polys to mface, skip ngons.
*/
int BKE_mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata,
struct CustomData *pdata, int totface, int UNUSED(totloop), int totpoly)
{
MLoop *mloop;
unsigned int lindex[4];
int i;
int k;
MPoly *mp, *mpoly;
MFace *mface, *mf;
const int numTex = CustomData_number_of_layers(pdata, CD_MTEXPOLY);
const int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
const bool hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL);
const bool hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP);
const bool hasLNor = CustomData_has_layer(ldata, CD_NORMAL);
/* over-alloc, ngons will be skipped */
mface = MEM_malloc_arrayN((size_t)totpoly, sizeof(*mface), __func__);
mpoly = CustomData_get_layer(pdata, CD_MPOLY);
mloop = CustomData_get_layer(ldata, CD_MLOOP);
mp = mpoly;
k = 0;
for (i = 0; i < totpoly; i++, mp++) {
if (ELEM(mp->totloop, 3, 4)) {
const unsigned int mp_loopstart = (unsigned int)mp->loopstart;
mf = &mface[k];
mf->mat_nr = mp->mat_nr;
mf->flag = mp->flag;
mf->v1 = mp_loopstart + 0;
mf->v2 = mp_loopstart + 1;
mf->v3 = mp_loopstart + 2;
mf->v4 = (mp->totloop == 4) ? (mp_loopstart + 3) : 0;
/* abuse edcode for temp storage and clear next loop */
mf->edcode = (char)mp->totloop; /* only ever 3 or 4 */
k++;
}
}
CustomData_free(fdata, totface);
totface = k;
CustomData_add_layer(fdata, CD_MFACE, CD_ASSIGN, mface, totface);
CustomData_from_bmeshpoly(fdata, pdata, ldata, totface);
mp = mpoly;
k = 0;
for (i = 0; i < totpoly; i++, mp++) {
if (ELEM(mp->totloop, 3, 4)) {
mf = &mface[k];
if (mf->edcode == 3) {
/* sort loop indices to ensure winding is correct */
/* NO SORT - looks like we can skip this */
lindex[0] = mf->v1;
lindex[1] = mf->v2;
lindex[2] = mf->v3;
lindex[3] = 0; /* unused */
/* transform loop indices to vert indices */
mf->v1 = mloop[mf->v1].v;
mf->v2 = mloop[mf->v2].v;
mf->v3 = mloop[mf->v3].v;
BKE_mesh_loops_to_mface_corners(fdata, ldata, pdata,
lindex, k, i, 3,
numTex, numCol, hasPCol, hasOrigSpace, hasLNor);
test_index_face(mf, fdata, k, 3);
}
else {
/* sort loop indices to ensure winding is correct */
/* NO SORT - looks like we can skip this */
lindex[0] = mf->v1;
lindex[1] = mf->v2;
lindex[2] = mf->v3;
lindex[3] = mf->v4;
/* transform loop indices to vert indices */
mf->v1 = mloop[mf->v1].v;
mf->v2 = mloop[mf->v2].v;
mf->v3 = mloop[mf->v3].v;
mf->v4 = mloop[mf->v4].v;
BKE_mesh_loops_to_mface_corners(fdata, ldata, pdata,
lindex, k, i, 4,
numTex, numCol, hasPCol, hasOrigSpace, hasLNor);
test_index_face(mf, fdata, k, 4);
}
mf->edcode = 0;
k++;
}
}
return k;
}
#endif /* USE_BMESH_SAVE_AS_COMPAT */
static void bm_corners_to_loops_ex(ID *id, CustomData *fdata, CustomData *ldata, CustomData *pdata,
MFace *mface, int totloop, int findex, int loopstart, int numTex, int numCol)
{
MTFace *texface;
MTexPoly *texpoly;

View File

@ -332,6 +332,10 @@ typedef struct {
* Will be NULL for UNDO.
*/
WriteWrap *ww;
#ifdef USE_BMESH_SAVE_AS_COMPAT
bool use_mesh_compat; /* option to save with older mesh format */
#endif
} WriteData;
static WriteData *writedata_new(WriteWrap *ww)
@ -2181,6 +2185,12 @@ static void write_customdata(
static void write_mesh(WriteData *wd, Mesh *mesh)
{
#ifdef USE_BMESH_SAVE_AS_COMPAT
const bool save_for_old_blender = wd->use_mesh_compat; /* option to save with older mesh format */
#else
const bool save_for_old_blender = false;
#endif
CustomDataLayer *vlayers = NULL, vlayers_buff[CD_TEMP_CHUNK_SIZE];
CustomDataLayer *elayers = NULL, elayers_buff[CD_TEMP_CHUNK_SIZE];
CustomDataLayer *flayers = NULL, flayers_buff[CD_TEMP_CHUNK_SIZE];
@ -2189,17 +2199,19 @@ static void write_mesh(WriteData *wd, Mesh *mesh)
if (mesh->id.us > 0 || wd->use_memfile) {
/* write LibData */
{
if (!save_for_old_blender) {
/* write a copy of the mesh, don't modify in place because it is
* not thread safe for threaded renders that are reading this */
Mesh *old_mesh = mesh;
Mesh copy_mesh = *mesh;
mesh = &copy_mesh;
#ifdef USE_BMESH_SAVE_WITHOUT_MFACE
/* cache only - don't write */
mesh->mface = NULL;
mesh->totface = 0;
memset(&mesh->fdata, 0, sizeof(mesh->fdata));
#endif /* USE_BMESH_SAVE_WITHOUT_MFACE */
/**
* Those calls:
@ -2210,7 +2222,11 @@ static void write_mesh(WriteData *wd, Mesh *mesh)
*/
CustomData_file_write_prepare(&mesh->vdata, &vlayers, vlayers_buff, ARRAY_SIZE(vlayers_buff));
CustomData_file_write_prepare(&mesh->edata, &elayers, elayers_buff, ARRAY_SIZE(elayers_buff));
#ifndef USE_BMESH_SAVE_WITHOUT_MFACE /* Do not copy org fdata in this case!!! */
CustomData_file_write_prepare(&mesh->fdata, &flayers, flayers_buff, ARRAY_SIZE(flayers_buff));
#else
flayers = flayers_buff;
#endif
CustomData_file_write_prepare(&mesh->ldata, &llayers, llayers_buff, ARRAY_SIZE(llayers_buff));
CustomData_file_write_prepare(&mesh->pdata, &players, players_buff, ARRAY_SIZE(players_buff));
@ -2235,6 +2251,73 @@ static void write_mesh(WriteData *wd, Mesh *mesh)
/* restore pointer */
mesh = old_mesh;
}
else {
#ifdef USE_BMESH_SAVE_AS_COMPAT
/* write a copy of the mesh, don't modify in place because it is
* not thread safe for threaded renders that are reading this */
Mesh *old_mesh = mesh;
Mesh copy_mesh = *mesh;
mesh = &copy_mesh;
mesh->mpoly = NULL;
mesh->mface = NULL;
mesh->totface = 0;
mesh->totpoly = 0;
mesh->totloop = 0;
CustomData_reset(&mesh->fdata);
CustomData_reset(&mesh->pdata);
CustomData_reset(&mesh->ldata);
mesh->edit_btmesh = NULL;
/* now fill in polys to mfaces */
/* XXX This breaks writing design, by using temp allocated memory, which will likely generate
* duplicates in stored 'old' addresses.
* This is very bad, but do not see easy way to avoid this, aside from generating those data
* outside of save process itself.
* Maybe we can live with this, though?
*/
mesh->totface = BKE_mesh_mpoly_to_mface(
&mesh->fdata, &old_mesh->ldata, &old_mesh->pdata,
mesh->totface, old_mesh->totloop, old_mesh->totpoly);
BKE_mesh_update_customdata_pointers(mesh, false);
CustomData_file_write_prepare(&mesh->vdata, &vlayers, vlayers_buff, ARRAY_SIZE(vlayers_buff));
CustomData_file_write_prepare(&mesh->edata, &elayers, elayers_buff, ARRAY_SIZE(elayers_buff));
CustomData_file_write_prepare(&mesh->fdata, &flayers, flayers_buff, ARRAY_SIZE(flayers_buff));
#if 0
CustomData_file_write_prepare(&mesh->ldata, &llayers, llayers_buff, ARRAY_SIZE(llayers_buff));
CustomData_file_write_prepare(&mesh->pdata, &players, players_buff, ARRAY_SIZE(players_buff));
#endif
writestruct_at_address(wd, ID_ME, Mesh, 1, old_mesh, mesh);
write_iddata(wd, &mesh->id);
/* direct data */
if (mesh->adt) {
write_animdata(wd, mesh->adt);
}
writedata(wd, DATA, sizeof(void *) * mesh->totcol, mesh->mat);
/* writedata(wd, DATA, sizeof(MSelect) * mesh->totselect, mesh->mselect); */ /* pre-bmesh NULL's */
write_customdata(wd, &mesh->id, mesh->totvert, &mesh->vdata, vlayers, -1, 0);
write_customdata(wd, &mesh->id, mesh->totedge, &mesh->edata, elayers, -1, 0);
write_customdata(wd, &mesh->id, mesh->totface, &mesh->fdata, flayers, -1, 0);
/* harmless for older blender versioins but _not_ writing these keeps file size down */
#if 0
write_customdata(wd, &mesh->id, mesh->totloop, &mesh->ldata, llayers, -1, 0);
write_customdata(wd, &mesh->id, mesh->totpoly, &mesh->pdata, players, -1, 0);
#endif
CustomData_free(&mesh->fdata, mesh->totface);
flayers = NULL;
/* restore pointer */
mesh = old_mesh;
#endif /* USE_BMESH_SAVE_AS_COMPAT */
}
}
if (vlayers && vlayers != vlayers_buff) {
@ -3756,6 +3839,10 @@ static bool write_file_handle(
wd = mywrite_begin(ww, compare, current);
#ifdef USE_BMESH_SAVE_AS_COMPAT
wd->use_mesh_compat = (write_flags & G_FILE_MESH_COMPAT) != 0;
#endif
#ifdef USE_NODE_COMPAT_CUSTOMNODES
/* don't write compatibility data on undo */
if (!current) {

View File

@ -224,6 +224,9 @@ enum {
/* this is so we can save bmesh files that load in trunk, ignoring NGons
* will eventually be removed */
#define USE_BMESH_SAVE_AS_COMPAT
#define USE_BMESH_SAVE_WITHOUT_MFACE
/* enable this so meshes get tessfaces calculated by default */
/* #define USE_TESSFACE_DEFAULT */

View File

@ -58,6 +58,7 @@
#include "BLF_api.h"
#include "DNA_mesh_types.h" /* only for USE_BMESH_SAVE_AS_COMPAT */
#include "DNA_object_types.h"
#include "DNA_space_types.h"
#include "DNA_userdef_types.h"
@ -2127,6 +2128,16 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op)
RNA_boolean_get(op->ptr, "copy")),
G_FILE_SAVE_COPY);
#ifdef USE_BMESH_SAVE_AS_COMPAT
SET_FLAG_FROM_TEST(
fileflags,
(RNA_struct_find_property(op->ptr, "use_mesh_compat") &&
RNA_boolean_get(op->ptr, "use_mesh_compat")),
G_FILE_MESH_COMPAT);
#else
# error "don't remove by accident"
#endif
const bool ok = wm_file_write(C, path, fileflags, op->reports);
if ((op->flag & OP_IS_INVOKE) == 0) {
@ -2186,6 +2197,11 @@ void WM_OT_save_as_mainfile(wmOperatorType *ot)
prop = RNA_def_boolean(ot->srna, "copy", false, "Save Copy",
"Save a copy of the actual working state but does not make saved file active");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
#ifdef USE_BMESH_SAVE_AS_COMPAT
RNA_def_boolean(ot->srna, "use_mesh_compat", false, "Legacy Mesh Format",
"Save using legacy mesh format (no ngons) - WARNING: only saves tris and quads, other ngons will "
"be lost (no implicit triangulation)");
#endif
}
static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))