Got rid of old multires code, brought in multires modifier from

soc-2008-nicholasbishop branch.

Note: any old code with multires_test() or multires_level1_test() can 
just be deleted, not needed by the multires modifier.
This commit is contained in:
Nicholas Bishop
2009-01-06 18:59:03 +00:00
parent 02003021a6
commit 25e5765f47
27 changed files with 2317 additions and 1982 deletions

View File

@@ -27,42 +27,58 @@
* ***** END GPL LICENSE BLOCK *****
*/
struct CustomData;
struct EditMesh;
struct Multires;
struct MultiresLevel;
struct DerivedMesh;
struct Mesh;
struct MFace;
struct MultiresModifierData;
struct Object;
/* Level access */
struct MultiresLevel *current_level(struct Multires *mr);
struct MultiresLevel *multires_level_n(struct Multires *mr, int n);
typedef struct MultiresSubsurf {
struct MultiresModifierData *mmd;
struct Mesh *me;
} MultiresSubsurf;
/* Level control */
void multires_add_level(struct Object *ob, struct Mesh *me, const char subdiv_type);
void multires_set_level(struct Object *ob, struct Mesh *me, const int render);
void multires_free_level(struct MultiresLevel *lvl);
typedef struct IndexNode {
struct IndexNode *next, *prev;
int index;
} IndexNode;
void multires_edge_level_update(struct Object *ob, struct Mesh *me);
void create_vert_face_map(ListBase **map, IndexNode **mem, const struct MFace *mface,
const int totvert, const int totface);
void create_vert_edge_map(ListBase **map, IndexNode **mem, const struct MEdge *medge,
const int totvert, const int totedge);
void multires_free(struct Multires *mr);
struct Multires *multires_copy(struct Multires *orig);
void multires_create(struct Object *ob, struct Mesh *me);
/* MultiresDM */
struct Mesh *MultiresDM_get_mesh(struct DerivedMesh *dm);
struct DerivedMesh *MultiresDM_new(struct MultiresSubsurf *, struct DerivedMesh*, int, int, int);
void *MultiresDM_get_vertnorm(struct DerivedMesh *);
void *MultiresDM_get_orco(struct DerivedMesh *);
struct MVert *MultiresDM_get_subco(struct DerivedMesh *);
struct ListBase *MultiresDM_get_vert_face_map(struct DerivedMesh *);
struct ListBase *MultiresDM_get_vert_edge_map(struct DerivedMesh *);
int *MultiresDM_get_face_offsets(struct DerivedMesh *);
int MultiresDM_get_totlvl(struct DerivedMesh *);
int MultiresDM_get_lvl(struct DerivedMesh *);
void MultiresDM_set_update(struct DerivedMesh *, void (*)(struct DerivedMesh*));
int *MultiresDM_get_flags(struct DerivedMesh *);
/* CustomData */
void multires_delete_layer(struct Object *ob, struct CustomData *cd, const int type, int n);
void multires_add_layer(struct Object *ob, struct CustomData *cd, const int type, const int n);
void multires_del_lower_customdata(struct Multires *mr, struct MultiresLevel *cr_lvl);
void multires_to_mcol(struct MultiresColFace *f, MCol mcol[4]);
/* After adding or removing vcolor layers, run this */
void multires_load_cols(struct Mesh *me);
#define MULTIRES_DM_UPDATE_BLOCK 1
#define MULTIRES_DM_UPDATE_ALWAYS 2
/* Private (used in multires-firstlevel.c) */
void multires_level_to_mesh(struct Object *ob, struct Mesh *me, const int render);
void multires_update_levels(struct Mesh *me, const int render);
void multires_update_first_level(struct Mesh *me, struct EditMesh *em);
void multires_update_customdata(struct MultiresLevel *lvl1, struct EditMesh *em, struct CustomData *src,
struct CustomData *dst, const int type);
void multires_customdata_to_mesh(struct Mesh *me, struct EditMesh *em,
struct MultiresLevel *lvl, struct CustomData *src,
struct CustomData *dst, const int type);
void multires_force_update(struct Object *ob);
struct DerivedMesh *multires_dm_create_from_derived(struct MultiresModifierData*, struct DerivedMesh*,
struct Mesh *, int, int);
int multiresModifier_switch_level(struct Object *, const int);
void multiresModifier_join(struct Object *);
void multiresModifier_del_levels(struct MultiresModifierData *, struct Object *, int direction);
void multiresModifier_subdivide(struct MultiresModifierData *mmd, struct Object *ob, int distance,
int updateblock, int simple);
void multiresModifier_setLevel(void *mmd_v, void *ob_v);
int multiresModifier_reshape(struct MultiresModifierData *mmd, struct Object *dst, struct Object *src);
/* Related to the old multires */
struct Multires;
void multires_load_old(struct DerivedMesh *, struct Multires *);
void multires_free(struct Multires*);

View File

@@ -30,6 +30,8 @@
#ifndef BKE_SCULPT_H
#define BKE_SCULPT_H
struct MFace;
struct MVert;
struct NumInput;
struct RadialControl;
struct Scene;
@@ -40,6 +42,13 @@ typedef struct SculptSession {
struct ProjVert *projverts;
struct bglMats *mats;
int multires;
int totvert;
int totface;
struct MVert *mvert;
struct MFace *mface;
float *face_normals;
/* An array of lists; array is sized as
large as the number of verts in the mesh,

View File

@@ -32,6 +32,7 @@ struct Mesh;
struct Object;
struct DerivedMesh;
struct EditMesh;
struct MultiresSubsurf;
struct SubsurfModifierData;
struct DerivedMesh *subsurf_make_derived_from_derived(
@@ -40,6 +41,13 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
int useRenderParams, float (*vertCos)[3],
int isFinalCalc, int editMode);
struct DerivedMesh *subsurf_make_derived_from_derived_with_multires(
struct DerivedMesh *dm,
struct SubsurfModifierData *smd,
struct MultiresSubsurf *ms,
int useRenderParams, float (*vertCos)[3],
int isFinalCalc, int editMode);
void subsurf_calculate_limit_positions(Mesh *me, float (*positions_r)[3]);
#endif

View File

@@ -71,7 +71,6 @@
#include "BKE_material.h"
#include "BKE_modifier.h"
#include "BKE_mesh.h"
#include "BKE_multires.h"
#include "BKE_object.h"
#include "BKE_subsurf.h"
#include "BKE_texture.h"
@@ -83,8 +82,6 @@
#include "BIF_gl.h"
#include "BIF_glutil.h"
//XXX #include "multires.h"
//
#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_material.h"
@@ -1448,6 +1445,9 @@ CustomDataMask get_viewedit_datamask()
if(G.f & G_VERTEXPAINT || G.f & G_WEIGHTPAINT)
mask |= CD_MASK_MCOL;
if(G.f & G_SCULPTMODE)
mask |= CD_MASK_MDISPS;
return mask;
#endif
return 0;
@@ -2210,93 +2210,11 @@ DerivedMesh *mesh_get_derived_deform(Scene *scene, Object *ob, CustomDataMask da
return ob->derivedDeform;
}
/* Move to multires Pin level, returns a copy of the original vertex coords. */
float *multires_render_pin(Object *ob, Mesh *me, int *orig_lvl)
{
float *vert_copy= NULL;
if(me->mr && !(me->mr->flag & MULTIRES_NO_RENDER)) {
MultiresLevel *lvl= NULL;
int i;
/* Make sure all mesh edits are properly stored in the multires data*/
//XXX multires_update_levels(me, 1);
/* Copy the highest level of multires verts */
*orig_lvl= me->mr->current;
//XXX lvl= multires_level_n(me->mr, BLI_countlist(&me->mr->levels));
vert_copy= MEM_callocN(sizeof(float)*3*lvl->totvert, "multires vert_copy");
for(i=0; i<lvl->totvert; ++i)
VecCopyf(&vert_copy[i*3], me->mr->verts[i].co);
/* Goto the pin level for multires */
me->mr->newlvl= me->mr->pinlvl;
//XXX multires_set_level(ob, me, 1);
}
return vert_copy;
}
/* Propagate the changes to render level - fails if mesh topology changed */
void multires_render_final(Object *ob, Mesh *me, DerivedMesh **dm, float *vert_copy,
const int orig_lvl, CustomDataMask dataMask)
{
if(me->mr && !(me->mr->flag & MULTIRES_NO_RENDER)) {
if((*dm)->getNumVerts(*dm) == me->totvert &&
(*dm)->getNumFaces(*dm) == me->totface) {
//XXX MultiresLevel *lvl= multires_level_n(me->mr, BLI_countlist(&me->mr->levels));
DerivedMesh *old= NULL;
MVert *vertdup= NULL;
int i;
/* Copy the verts into the mesh */
vertdup= (*dm)->dupVertArray(*dm);
(*dm)->release(*dm);
for(i=0; i<me->totvert; ++i)
me->mvert[i]= vertdup[i];
/* Free vertdup after use*/
MEM_freeN(vertdup);
/* Go to the render level */
me->mr->newlvl= me->mr->renderlvl;
//XXX multires_set_level(ob, me, 1);
(*dm)= getMeshDerivedMesh(me, ob, NULL);
/* Some of the data in dm is referenced externally, so make a copy */
old= *dm;
(*dm)= CDDM_copy(old);
old->release(old);
if(dataMask & CD_MASK_ORCO)
add_orco_dm(ob, NULL, *dm, NULL);
/* Restore the original verts */
me->mr->newlvl= BLI_countlist(&me->mr->levels);
//XXX multires_set_level(ob, me, 1);
//XXX for(i=0; i<lvl->totvert; ++i)
//XXX VecCopyf(me->mvert[i].co, &vert_copy[i*3]);
}
if(vert_copy)
MEM_freeN(vert_copy);
me->mr->newlvl= orig_lvl;
//XXX multires_set_level(ob, me, 1);
}
}
/* Multires note - if mesh has multires enabled, mesh is first set to the Pin level,
where all modifiers are applied, then if the topology hasn't changed, the changes
from modifiers are propagated up to the Render level. */
DerivedMesh *mesh_create_derived_render(Scene *scene, Object *ob, CustomDataMask dataMask)
{
DerivedMesh *final;
Mesh *me= get_mesh(ob);
float *vert_copy= NULL;
int orig_lvl= 0;
vert_copy= multires_render_pin(ob, me, &orig_lvl);
mesh_calc_modifiers(scene, ob, NULL, NULL, &final, 1, 1, 0, dataMask, -1);
multires_render_final(ob, me, &final, vert_copy, orig_lvl, dataMask);
return final;
}
@@ -2304,13 +2222,8 @@ DerivedMesh *mesh_create_derived_render(Scene *scene, Object *ob, CustomDataMask
DerivedMesh *mesh_create_derived_index_render(Scene *scene, Object *ob, CustomDataMask dataMask, int index)
{
DerivedMesh *final;
Mesh *me= get_mesh(ob);
float *vert_copy= NULL;
int orig_lvl= 0;
vert_copy= multires_render_pin(ob, me, &orig_lvl);
mesh_calc_modifiers(scene, ob, NULL, NULL, &final, 1, 1, 0, dataMask, index);
multires_render_final(ob, me, &final, vert_copy, orig_lvl, dataMask);
return final;
}
@@ -2339,13 +2252,8 @@ DerivedMesh *mesh_create_derived_no_deform_render(Scene *scene, Object *ob,
CustomDataMask dataMask)
{
DerivedMesh *final;
Mesh *me= get_mesh(ob);
float *vert_copy= NULL;
int orig_lvl= 0;
vert_copy= multires_render_pin(ob, me, &orig_lvl);
mesh_calc_modifiers(scene, ob, vertCos, NULL, &final, 1, 0, 0, dataMask, -1);
multires_render_final(ob, me, &final, vert_copy, orig_lvl, dataMask);
return final;
}

View File

@@ -42,6 +42,7 @@
#include "BKE_displist.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
#include "BKE_multires.h"
#include "BKE_utildefines.h"
#include "BLI_arithb.h"
@@ -52,6 +53,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_fluidsim.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -64,6 +66,7 @@
#include <string.h>
#include <limits.h>
#include <math.h>
typedef struct {
DerivedMesh dm;
@@ -885,6 +888,7 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *ob)
{
CDDerivedMesh *cddm = cdDM_create("CDDM_from_mesh dm");
DerivedMesh *dm = &cddm->dm;
CustomDataMask mask = CD_MASK_MESH & (~CD_MASK_MDISPS);
int i, *index, alloctype;
/* this does a referenced copy, the only new layers being ORIGINDEX,
@@ -900,11 +904,11 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *ob)
alloctype= CD_REFERENCE;
CustomData_merge(&mesh->vdata, &dm->vertData, CD_MASK_MESH, alloctype,
CustomData_merge(&mesh->vdata, &dm->vertData, mask, alloctype,
mesh->totvert);
CustomData_merge(&mesh->edata, &dm->edgeData, CD_MASK_MESH, alloctype,
CustomData_merge(&mesh->edata, &dm->edgeData, mask, alloctype,
mesh->totedge);
CustomData_merge(&mesh->fdata, &dm->faceData, CD_MASK_MESH, alloctype,
CustomData_merge(&mesh->fdata, &dm->faceData, mask, alloctype,
mesh->totface);
cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
@@ -1282,3 +1286,192 @@ MFace *CDDM_get_faces(DerivedMesh *dm)
return ((CDDerivedMesh*)dm)->mface;
}
/* Multires DerivedMesh, extends CDDM */
typedef struct MultiresDM {
CDDerivedMesh cddm;
MultiresModifierData *mmd;
int lvl, totlvl;
float (*orco)[3];
MVert *subco;
ListBase *vert_face_map, *vert_edge_map;
IndexNode *vert_face_map_mem, *vert_edge_map_mem;
int *face_offsets;
Mesh *me;
int flags;
void (*update)(DerivedMesh*);
} MultiresDM;
static void MultiresDM_release(DerivedMesh *dm)
{
MultiresDM *mrdm = (MultiresDM*)dm;
int mvert_layer;
/* Before freeing, need to update the displacement map */
if(dm->needsFree && !(mrdm->flags & MULTIRES_DM_UPDATE_BLOCK))
mrdm->update(dm);
/* If the MVert data is being used as the sculpt undo store, don't free it */
mvert_layer = CustomData_get_layer_index(&dm->vertData, CD_MVERT);
if(mvert_layer != -1) {
CustomDataLayer *cd = &dm->vertData.layers[mvert_layer];
if(cd->data == mrdm->mmd->undo_verts)
cd->flag |= CD_FLAG_NOFREE;
}
if(DM_release(dm)) {
MEM_freeN(mrdm->subco);
MEM_freeN(mrdm->orco);
if(mrdm->vert_face_map)
MEM_freeN(mrdm->vert_face_map);
if(mrdm->vert_face_map_mem)
MEM_freeN(mrdm->vert_face_map_mem);
if(mrdm->vert_edge_map)
MEM_freeN(mrdm->vert_edge_map);
if(mrdm->vert_edge_map_mem)
MEM_freeN(mrdm->vert_edge_map_mem);
if(mrdm->face_offsets)
MEM_freeN(mrdm->face_offsets);
MEM_freeN(mrdm);
}
}
DerivedMesh *MultiresDM_new(MultiresSubsurf *ms, DerivedMesh *orig, int numVerts, int numEdges, int numFaces)
{
MultiresDM *mrdm = MEM_callocN(sizeof(MultiresDM), "MultiresDM");
CDDerivedMesh *cddm = cdDM_create("MultiresDM CDDM");
DerivedMesh *dm = NULL;
mrdm->cddm = *cddm;
MEM_freeN(cddm);
dm = &mrdm->cddm.dm;
mrdm->mmd = ms->mmd;
mrdm->me = ms->me;
if(dm) {
MDisps *disps;
MVert *mvert;
int i;
DM_from_template(dm, orig, numVerts, numEdges, numFaces);
CustomData_free_layers(&dm->faceData, CD_MDISPS, numFaces);
disps = CustomData_get_layer(&orig->faceData, CD_MDISPS);
if(disps)
CustomData_add_layer(&dm->faceData, CD_MDISPS, CD_REFERENCE, disps, numFaces);
mvert = CustomData_get_layer(&orig->vertData, CD_MVERT);
mrdm->orco = MEM_callocN(sizeof(float) * 3 * orig->getNumVerts(orig), "multires orco");
for(i = 0; i < orig->getNumVerts(orig); ++i)
VecCopyf(mrdm->orco[i], mvert[i].co);
}
else
DM_init(dm, numVerts, numEdges, numFaces);
CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts);
CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numFaces);
mrdm->cddm.mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
mrdm->cddm.medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
mrdm->cddm.mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
mrdm->lvl = ms->mmd->lvl;
mrdm->totlvl = ms->mmd->totlvl;
mrdm->subco = MEM_callocN(sizeof(MVert)*numVerts, "multires subdivided verts");
mrdm->flags = 0;
dm->release = MultiresDM_release;
return dm;
}
Mesh *MultiresDM_get_mesh(DerivedMesh *dm)
{
return ((MultiresDM*)dm)->me;
}
void *MultiresDM_get_orco(DerivedMesh *dm)
{
return ((MultiresDM*)dm)->orco;
}
MVert *MultiresDM_get_subco(DerivedMesh *dm)
{
return ((MultiresDM*)dm)->subco;
}
int MultiresDM_get_totlvl(DerivedMesh *dm)
{
return ((MultiresDM*)dm)->totlvl;
}
int MultiresDM_get_lvl(DerivedMesh *dm)
{
return ((MultiresDM*)dm)->lvl;
}
void MultiresDM_set_orco(DerivedMesh *dm, float (*orco)[3])
{
((MultiresDM*)dm)->orco = orco;
}
void MultiresDM_set_update(DerivedMesh *dm, void (*update)(DerivedMesh*))
{
((MultiresDM*)dm)->update = update;
}
ListBase *MultiresDM_get_vert_face_map(DerivedMesh *dm)
{
MultiresDM *mrdm = (MultiresDM*)dm;
if(!mrdm->vert_face_map)
create_vert_face_map(&mrdm->vert_face_map, &mrdm->vert_face_map_mem, mrdm->me->mface,
mrdm->me->totvert, mrdm->me->totface);
return mrdm->vert_face_map;
}
ListBase *MultiresDM_get_vert_edge_map(DerivedMesh *dm)
{
MultiresDM *mrdm = (MultiresDM*)dm;
if(!mrdm->vert_edge_map)
create_vert_edge_map(&mrdm->vert_edge_map, &mrdm->vert_edge_map_mem, mrdm->me->medge,
mrdm->me->totvert, mrdm->me->totedge);
return mrdm->vert_edge_map;
}
int *MultiresDM_get_face_offsets(DerivedMesh *dm)
{
MultiresDM *mrdm = (MultiresDM*)dm;
int i, accum = 0;
if(!mrdm->face_offsets) {
int len = (int)pow(2, mrdm->lvl - 2) - 1;
int area = len * len;
int t = 1 + len * 3 + area * 3, q = t + len + area;
mrdm->face_offsets = MEM_callocN(sizeof(int) * mrdm->me->totface, "mrdm face offsets");
for(i = 0; i < mrdm->me->totface; ++i) {
mrdm->face_offsets[i] = accum;
accum += (mrdm->me->mface[i].v4 ? q : t);
}
}
return mrdm->face_offsets;
}
int *MultiresDM_get_flags(DerivedMesh *dm)
{
return &((MultiresDM*)dm)->flags;
}

View File

@@ -34,6 +34,7 @@
#include "BKE_customdata.h"
#include "BLI_arithb.h"
#include "BLI_blenlib.h"
#include "BLI_linklist.h"
#include "BLI_mempool.h"
@@ -44,6 +45,7 @@
#include "MEM_guardedalloc.h"
#include <math.h>
#include <string.h>
/* number of layers to add when growing a CustomData object */
@@ -378,6 +380,156 @@ static void layerDefault_origspace_face(void *data, int count)
for(i = 0; i < count; i++)
osf[i] = default_osf;
}
/* Adapted from sculptmode.c */
static void mdisps_bilinear(float out[3], float (*disps)[3], int st, float u, float v)
{
int x, y, x2, y2;
const int st_max = st - 1;
float urat, vrat, uopp;
float d[4][3], d2[2][3];
if(u < 0)
u = 0;
else if(u >= st)
u = st_max;
if(v < 0)
v = 0;
else if(v >= st)
v = st_max;
x = floor(u);
y = floor(v);
x2 = x + 1;
y2 = y + 1;
if(x2 >= st) x2 = st_max;
if(y2 >= st) y2 = st_max;
urat = u - x;
vrat = v - y;
uopp = 1 - urat;
VecCopyf(d[0], disps[y * st + x]);
VecCopyf(d[1], disps[y * st + x2]);
VecCopyf(d[2], disps[y2 * st + x]);
VecCopyf(d[3], disps[y2 * st + x2]);
VecMulf(d[0], uopp);
VecMulf(d[1], urat);
VecMulf(d[2], uopp);
VecMulf(d[3], urat);
VecAddf(d2[0], d[0], d[1]);
VecAddf(d2[1], d[2], d[3]);
VecMulf(d2[0], 1 - vrat);
VecMulf(d2[1], vrat);
VecAddf(out, d2[0], d2[1]);
}
static void layerSwap_mdisps(void *data, int *ci)
{
MDisps *s = data;
float (*d)[3] = NULL;
int x, y, st;
if(!(ci[0] == 2 && ci[1] == 3 && ci[2] == 0 && ci[3] == 1)) return;
d = MEM_callocN(sizeof(float) * 3 * s->totdisp, "mdisps swap");
st = sqrt(s->totdisp);
for(y = 0; y < st; ++y) {
for(x = 0; x < st; ++x) {
VecCopyf(d[(st - y - 1) * st + (st - x - 1)], s->disps[y * st + x]);
}
}
if(s->disps)
MEM_freeN(s->disps);
s->disps = d;
}
static void layerInterp_mdisps(void **sources, float *weights, float *sub_weights,
int count, void *dest)
{
MDisps *d = dest;
MDisps *s = NULL;
int st, stl;
int i, x, y;
float crn[4][2];
float (*sw)[4] = NULL;
/* Initialize the destination */
for(i = 0; i < d->totdisp; ++i) {
float z[3] = {0,0,0};
VecCopyf(d->disps[i], z);
}
/* For now, some restrictions on the input */
if(count != 1 || !sub_weights) return;
st = sqrt(d->totdisp);
stl = st - 1;
sw = (void*)sub_weights;
for(i = 0; i < 4; ++i) {
crn[i][0] = 0 * sw[i][0] + stl * sw[i][1] + stl * sw[i][2] + 0 * sw[i][3];
crn[i][1] = 0 * sw[i][0] + 0 * sw[i][1] + stl * sw[i][2] + stl * sw[i][3];
}
s = sources[0];
for(y = 0; y < st; ++y) {
for(x = 0; x < st; ++x) {
/* One suspects this code could be cleaner. */
float xl = (float)x / (st - 1);
float yl = (float)y / (st - 1);
float mid1[2] = {crn[0][0] * (1 - xl) + crn[1][0] * xl,
crn[0][1] * (1 - xl) + crn[1][1] * xl};
float mid2[2] = {crn[3][0] * (1 - xl) + crn[2][0] * xl,
crn[3][1] * (1 - xl) + crn[2][1] * xl};
float mid3[2] = {mid1[0] * (1 - yl) + mid2[0] * yl,
mid1[1] * (1 - yl) + mid2[1] * yl};
float srcdisp[3];
mdisps_bilinear(srcdisp, s->disps, st, mid3[0], mid3[1]);
VecCopyf(d->disps[y * st + x], srcdisp);
}
}
}
static void layerCopy_mdisps(const void *source, void *dest, int count)
{
int i;
const MDisps *s = source;
MDisps *d = dest;
for(i = 0; i < count; ++i) {
if(s[i].disps) {
d[i].disps = MEM_dupallocN(s[i].disps);
d[i].totdisp = s[i].totdisp;
}
else {
d[i].disps = NULL;
d[i].totdisp = 0;
}
}
}
static void layerFree_mdisps(void *data, int count, int size)
{
int i;
MDisps *d = data;
for(i = 0; i < count; ++i) {
if(d[i].disps)
MEM_freeN(d[i].disps);
d[i].disps = NULL;
d[i].totdisp = 0;
}
}
/* --------- */
static void layerDefault_mloopcol(void *data, int count)
@@ -553,23 +705,26 @@ const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
{sizeof(MTexPoly), "MTexPoly", 1, "Face Texture", NULL, NULL, NULL, NULL, NULL},
{sizeof(MLoopUV), "MLoopUV", 1, "UV coord", NULL, NULL, layerInterp_mloopuv, NULL, NULL},
{sizeof(MLoopCol), "MLoopCol", 1, "Col", NULL, NULL, layerInterp_mloopcol, NULL, layerDefault_mloopcol},
{sizeof(float)*3*4, "", 0, NULL, NULL, NULL, NULL, NULL, NULL}
{sizeof(float)*3*4, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
{sizeof(MDisps), "MDisps", 1, NULL, layerCopy_mdisps,
layerFree_mdisps, layerInterp_mdisps, layerSwap_mdisps, NULL}
};
const char *LAYERTYPENAMES[CD_NUMTYPES] = {
"CDMVert", "CDMSticky", "CDMDeformVert", "CDMEdge", "CDMFace", "CDMTFace",
"CDMCol", "CDOrigIndex", "CDNormal", "CDFlags","CDMFloatProperty",
"CDMIntProperty","CDMStringProperty", "CDOrigSpace", "CDOrco", "CDMTexPoly", "CDMLoopUV", "CDMloopCol", "CDTangent"};
"CDMIntProperty","CDMStringProperty", "CDOrigSpace", "CDOrco", "CDMTexPoly", "CDMLoopUV",
"CDMloopCol", "CDTangent", "CDMDisps"};
const CustomDataMask CD_MASK_BAREMESH =
CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE;
const CustomDataMask CD_MASK_MESH =
CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE |
CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE | CD_MASK_MCOL |
CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR;
CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS;
const CustomDataMask CD_MASK_EDITMESH =
CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE |
CD_MASK_MCOL|CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR;
CD_MASK_MCOL|CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS;
const CustomDataMask CD_MASK_DERIVEDMESH =
CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE |
CD_MASK_MCOL | CD_MASK_ORIGINDEX | CD_MASK_PROP_FLT | CD_MASK_PROP_INT |

View File

@@ -56,7 +56,6 @@
#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
#include "BKE_multires.h"
#include "BKE_subsurf.h"
#include "BKE_displist.h"
#include "BKE_library.h"
@@ -137,8 +136,6 @@ void free_mesh(Mesh *me)
if(me->bb) MEM_freeN(me->bb);
if(me->mselect) MEM_freeN(me->mselect);
if(me->edit_mesh) MEM_freeN(me->edit_mesh);
if(me->mr) multires_free(me->mr);
}
void copy_dverts(MDeformVert *dst, MDeformVert *src, int copycount)
@@ -222,9 +219,6 @@ Mesh *copy_mesh(Mesh *me)
}
}
if(me->mr)
men->mr= multires_copy(me->mr);
men->mselect= NULL;
men->bb= MEM_dupallocN(men->bb);

View File

@@ -86,6 +86,7 @@
#include "BKE_displist.h"
#include "BKE_fluidsim.h"
#include "BKE_global.h"
#include "BKE_multires.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
#include "BKE_material.h"
@@ -6173,7 +6174,6 @@ static void particleSystemModifier_deformVerts(
DerivedMesh *dm = derivedData;
ParticleSystemModifierData *psmd= (ParticleSystemModifierData*) md;
ParticleSystem * psys=0;
Mesh *me;
int needsFree=0;
if(ob->particlesystem.first)
@@ -6181,14 +6181,6 @@ static void particleSystemModifier_deformVerts(
else
return;
/* multires check */
if(ob->type == OB_MESH) {
me= (Mesh*)ob->data;
if(me->mr && me->mr->current != 1)
modifier_setError(md,
"Particles only supported on first multires level.");
}
if(!psys_check_enabled(ob, psys))
return;
@@ -7738,6 +7730,58 @@ static void meshdeformModifier_deformVertsEM(
dm->release(dm);
}
/* Multires */
static void multiresModifier_initData(ModifierData *md)
{
MultiresModifierData *mmd = (MultiresModifierData*)md;
mmd->lvl = mmd->totlvl = 1;
}
static void multiresModifier_freeData(ModifierData *md)
{
MultiresModifierData *mmd = (MultiresModifierData*)md;
if(mmd->undo_verts)
MEM_freeN(mmd->undo_verts);
}
static void multiresModifier_copyData(ModifierData *md, ModifierData *target)
{
MultiresModifierData *mmd = (MultiresModifierData*) md;
MultiresModifierData *tmmd = (MultiresModifierData*) target;
tmmd->totlvl = mmd->totlvl;
tmmd->lvl = mmd->lvl;
}
static DerivedMesh *multiresModifier_applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm,
int useRenderParams, int isFinalCalc)
{
MultiresModifierData *mmd = (MultiresModifierData*)md;
Mesh *me = get_mesh(ob);
DerivedMesh *final;
/* TODO: for now just skip a level1 mesh */
if(mmd->lvl == 1)
return dm;
final = multires_dm_create_from_derived(mmd, dm, me, useRenderParams, isFinalCalc);
if(mmd->undo_signal && mmd->undo_verts && mmd->undo_verts_tot == final->getNumVerts(final)) {
int i;
MVert *dst = CDDM_get_verts(final);
for(i = 0; i < mmd->undo_verts_tot; ++i) {
VecCopyf(dst[i].co, mmd->undo_verts[i].co);
}
CDDM_calc_normals(final);
MEM_freeN(mmd->undo_verts);
mmd->undo_signal = 0;
mmd->undo_verts = NULL;
}
return final;
}
/* Shrinkwrap */
@@ -8338,6 +8382,14 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type)
mti->foreachObjectLink = simpledeformModifier_foreachObjectLink;
mti->updateDepgraph = simpledeformModifier_updateDepgraph;
mti = INIT_TYPE(Multires);
mti->type = eModifierTypeType_Constructive;
mti->flags = eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_RequiresOriginalData;
mti->initData = multiresModifier_initData;
mti->freeData = multiresModifier_freeData;
mti->copyData = multiresModifier_copyData;
mti->applyModifier = multiresModifier_applyModifier;
typeArrInit = 0;
#undef INIT_TYPE
}

View File

@@ -1,411 +0,0 @@
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) 2006 by Nicholas Bishop
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*
* Deals with the first-level data in multires (edge flags, weights, and UVs)
*
* multires.h
*
*/
#include "DNA_customdata_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
//XXX #include "BIF_editmesh.h"
#include "BKE_customdata.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
#include "BKE_multires.h"
#include "BLI_editVert.h"
#include "MEM_guardedalloc.h"
#include <string.h>
MDeformVert *subdivide_dverts(MDeformVert *src, MultiresLevel *lvl);
MTFace *subdivide_mtfaces(MTFace *src, MultiresLevel *lvl);
void multires_update_edge_flags(Mesh *me, EditMesh *em);
void eed_to_medge_flag(EditEdge *eed, short *flag, char *crease);
/*********** Generic ***********/
CustomDataMask cdmask(const int type)
{
if(type == CD_MDEFORMVERT)
return CD_MASK_MDEFORMVERT;
else if(type == CD_MTFACE)
return CD_MASK_MTFACE;
return -1;
}
char type_ok(const int type)
{
return (type == CD_MDEFORMVERT) || (type == CD_MTFACE);
}
/* Copy vdata or fdata from Mesh or EditMesh to Multires. */
void multires_update_customdata(MultiresLevel *lvl1, EditMesh *em, CustomData *src, CustomData *dst, const int type)
{
if(src && dst && type_ok(type)) {
const int tot= (type == CD_MDEFORMVERT ? lvl1->totvert : lvl1->totface);
int i;
CustomData_free(dst, tot);
if(CustomData_has_layer(src, type)) {
if(em) {
EditVert *eve= em->verts.first;
EditFace *efa= em->faces.first;
CustomData_copy(src, dst, cdmask(type), CD_CALLOC, tot);
for(i=0; i<tot; ++i) {
if(type == CD_MDEFORMVERT) {
CustomData_from_em_block(&em->vdata, dst, eve->data, i);
eve= eve->next;
}
else if(type == CD_MTFACE) {
CustomData_from_em_block(&em->fdata, dst, efa->data, i);
efa= efa->next;
}
}
}
else
CustomData_copy(src, dst, cdmask(type), CD_DUPLICATE, tot);
}
}
}
/* Uses subdivide_dverts or subdivide_mtfaces to subdivide src to match lvl_end. Does not free src. */
void *subdivide_customdata_to_level(void *src, MultiresLevel *lvl_start,
MultiresLevel *lvl_end, const int type)
{
if(src && lvl_start && lvl_end && type_ok(type)) {
MultiresLevel *lvl;
void *cr_data= NULL, *pr_data= NULL;
pr_data= src;
for(lvl= lvl_start; lvl && lvl != lvl_end; lvl= lvl->next) {
if(type == CD_MDEFORMVERT)
cr_data= subdivide_dverts(pr_data, lvl);
else if(type == CD_MTFACE)
cr_data= subdivide_mtfaces(pr_data, lvl);
/* Free previous subdivision level's data */
if(lvl != lvl_start) {
if(type == CD_MDEFORMVERT)
free_dverts(pr_data, lvl->totvert);
else if(type == CD_MTFACE)
MEM_freeN(pr_data);
}
pr_data= cr_data;
cr_data= NULL;
}
return pr_data;
}
return NULL;
}
/* Directly copy src into dst (handles both Mesh and EditMesh) */
void customdata_to_mesh(Mesh *me, EditMesh *em, CustomData *src, CustomData *dst, const int tot, const int type)
{
if(me && me->mr && src && dst && type_ok(type)) {
if(em) {
int i;
EditVert *eve= em->verts.first;
EditFace *efa= em->faces.first;
CustomData_copy(src, dst, cdmask(type), CD_CALLOC, 0);
for(i=0; i<tot; ++i) {
if(type == CD_MDEFORMVERT) {
CustomData_to_em_block(src, dst, i, &eve->data);
eve= eve->next;
}
else if(type == CD_MTFACE) {
CustomData_to_em_block(src, dst, i, &efa->data);
efa= efa->next;
}
}
} else {
CustomData_merge(src, dst, cdmask(type), CD_DUPLICATE, tot);
}
}
}
/* Subdivide vdata or fdata from Multires into either Mesh or EditMesh. */
void multires_customdata_to_mesh(Mesh *me, EditMesh *em, MultiresLevel *lvl, CustomData *src,
CustomData *dst, const int type)
{
if(me && me->mr && lvl && src && dst && type_ok(type) &&
CustomData_has_layer(src, type)) {
const int tot= (type == CD_MDEFORMVERT ? lvl->totvert : lvl->totface);
if(lvl == me->mr->levels.first) {
customdata_to_mesh(me, em, src, dst, tot, type);
}
else {
CustomData cdf;
const int count = CustomData_number_of_layers(src, type);
int i;
/* Construct a new CustomData containing the subdivided data */
CustomData_copy(src, &cdf, cdmask(type), CD_ASSIGN, tot);
for(i=0; i<count; ++i) {
void *layer= CustomData_get_layer_n(&cdf, type, i);
CustomData_set_layer_n(&cdf, type, i,
subdivide_customdata_to_level(layer, me->mr->levels.first, lvl, type));
}
customdata_to_mesh(me, em, &cdf, dst, tot, type);
CustomData_free(&cdf, tot);
}
}
}
/* Subdivide the first-level customdata up to cr_lvl, then delete the original data */
void multires_del_lower_customdata(Multires *mr, MultiresLevel *cr_lvl)
{
MultiresLevel *lvl1= mr->levels.first;
MDeformVert *dverts= NULL;
CustomData cdf;
int i;
/* dverts */
dverts= subdivide_customdata_to_level(CustomData_get(&mr->vdata, 0, CD_MDEFORMVERT),
lvl1, cr_lvl, CD_MDEFORMVERT);
if(dverts) {
CustomData_free_layers(&mr->vdata, CD_MDEFORMVERT, lvl1->totvert);
CustomData_add_layer(&mr->vdata, CD_MDEFORMVERT, CD_ASSIGN, dverts, cr_lvl->totvert);
}
/* mtfaces */
CustomData_copy(&mr->fdata, &cdf, CD_MASK_MTFACE, CD_ASSIGN, cr_lvl->totface);
for(i=0; i<CustomData_number_of_layers(&mr->fdata, CD_MTFACE); ++i) {
MTFace *mtfaces=
subdivide_customdata_to_level(CustomData_get_layer_n(&mr->fdata, CD_MTFACE, i),
lvl1, cr_lvl, CD_MTFACE);
if(mtfaces)
CustomData_set_layer_n(&cdf, CD_MTFACE, i, mtfaces);
}
CustomData_free(&mr->fdata, lvl1->totface);
mr->fdata= cdf;
}
/* Update all special first-level data, if the first-level is active */
void multires_update_first_level(Mesh *me, EditMesh *em)
{
if(me && me->mr && me->mr->current == 1) {
multires_update_customdata(me->mr->levels.first, em, em ? &em->vdata : &me->vdata,
&me->mr->vdata, CD_MDEFORMVERT);
multires_update_customdata(me->mr->levels.first, em, em ? &em->fdata : &me->fdata,
&me->mr->fdata, CD_MTFACE);
multires_update_edge_flags(me, em);
}
}
/*********** Multires.edge_flags ***********/
void multires_update_edge_flags(Mesh *me, EditMesh *em)
{
MultiresLevel *lvl= me->mr->levels.first;
EditEdge *eed= NULL;
int i;
if(em) eed= em->edges.first;
for(i=0; i<lvl->totedge; ++i) {
if(em) {
me->mr->edge_flags[i]= 0;
eed_to_medge_flag(eed, &me->mr->edge_flags[i], &me->mr->edge_creases[i]);
eed= eed->next;
}
else {
me->mr->edge_flags[i]= me->medge[i].flag;
me->mr->edge_creases[i]= me->medge[i].crease;
}
}
}
/*********** Multires.vdata ***********/
/* MDeformVert */
/* Add each weight from in to out. Scale each weight by w. */
void multires_add_dvert(MDeformVert *out, const MDeformVert *in, const float w)
{
if(out && in) {
int i, j;
char found;
for(i=0; i<in->totweight; ++i) {
found= 0;
for(j=0; j<out->totweight; ++j) {
if(out->dw[j].def_nr==in->dw[i].def_nr) {
out->dw[j].weight += in->dw[i].weight * w;
found= 1;
}
}
if(!found) {
MDeformWeight *newdw= MEM_callocN(sizeof(MDeformWeight)*(out->totweight+1),
"multires dvert");
if(out->dw) {
memcpy(newdw, out->dw, sizeof(MDeformWeight)*out->totweight);
MEM_freeN(out->dw);
}
out->dw= newdw;
out->dw[out->totweight].weight= in->dw[i].weight * w;
out->dw[out->totweight].def_nr= in->dw[i].def_nr;
++out->totweight;
}
}
}
}
/* Takes an input array of dverts and subdivides them (linear) using the topology of lvl */
MDeformVert *subdivide_dverts(MDeformVert *src, MultiresLevel *lvl)
{
if(lvl && lvl->next) {
MDeformVert *out = MEM_callocN(sizeof(MDeformVert)*lvl->next->totvert, "dvert prop array");
int i, j;
/* Copy lower level */
for(i=0; i<lvl->totvert; ++i)
multires_add_dvert(&out[i], &src[i], 1);
/* Edge verts */
for(i=0; i<lvl->totedge; ++i) {
for(j=0; j<2; ++j)
multires_add_dvert(&out[lvl->totvert+i], &src[lvl->edges[i].v[j]],0.5);
}
/* Face verts */
for(i=0; i<lvl->totface; ++i) {
for(j=0; j<(lvl->faces[i].v[3]?4:3); ++j)
multires_add_dvert(&out[lvl->totvert + lvl->totedge + i],
&src[lvl->faces[i].v[j]],
lvl->faces[i].v[3]?0.25:(1.0f/3.0f));
}
return out;
}
return NULL;
}
/*********** Multires.fdata ***********/
/* MTFace */
void multires_uv_avg2(float out[2], const float a[2], const float b[2])
{
int i;
for(i=0; i<2; ++i)
out[i] = (a[i] + b[i]) / 2.0f;
}
/* Takes an input array of mtfaces and subdivides them (linear) using the topology of lvl */
MTFace *subdivide_mtfaces(MTFace *src, MultiresLevel *lvl)
{
if(lvl && lvl->next) {
MTFace *out= MEM_callocN(sizeof(MultiresColFace)*lvl->next->totface,"Multirescolfaces");
int i, j, curf;
for(i=0, curf=0; i<lvl->totface; ++i) {
const char sides= lvl->faces[i].v[3]?4:3;
float cntr[2]= {0, 0};
/* Find average uv coord of the current face */
for(j=0; j<sides; ++j) {
cntr[0]+= src[i].uv[j][0];
cntr[1]+= src[i].uv[j][1];
}
cntr[0]/= sides;
cntr[1]/= sides;
for(j=0; j<sides; ++j, ++curf) {
out[curf]= src[i];
multires_uv_avg2(out[curf].uv[0], src[i].uv[j], src[i].uv[j==0?sides-1:j-1]);
out[curf].uv[1][0]= src[i].uv[j][0];
out[curf].uv[1][1]= src[i].uv[j][1];
multires_uv_avg2(out[curf].uv[2], src[i].uv[j], src[i].uv[j==sides-1?0:j+1]);
out[curf].uv[3][0]= cntr[0];
out[curf].uv[3][1]= cntr[1];
}
}
return out;
}
return NULL;
}
void multires_delete_layer(Object *ob, CustomData *cd, const int type, int n)
{
Mesh *me= ob->data;
if(me && me->mr && cd) {
MultiresLevel *lvl1= me->mr->levels.first;
multires_update_levels(me, 0);
CustomData_set_layer_active(cd, type, n);
CustomData_free_layer_active(cd, type, lvl1->totface);
multires_level_to_mesh(ob, me, 0);
}
}
void multires_add_layer(Object *ob, CustomData *cd, const int type, const int n)
{
Mesh *me= ob->data;
if(me && me->mr && cd) {
multires_update_levels(me, 0);
if(CustomData_has_layer(cd, type))
CustomData_add_layer(cd, type, CD_DUPLICATE, CustomData_get_layer(cd, type),
current_level(me->mr)->totface);
else
CustomData_add_layer(cd, type, CD_DEFAULT, NULL, current_level(me->mr)->totface);
CustomData_set_layer_active(cd, type, n);
multires_level_to_mesh(ob, me, 0);
}
}

View File

@@ -32,53 +32,1248 @@
#include "DNA_key_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_vec_types.h"
#include "DNA_scene_types.h"
#include "DNA_view3d_types.h"
#include "BLI_arithb.h"
#include "BLI_blenlib.h"
#include "BLI_editVert.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_customdata.h"
#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
//XXX #include "editmesh.h"
#include "BKE_object.h"
#include "BKE_subsurf.h"
#include <math.h>
#include <string.h>
/* Returns the active multires level (currently applied to the mesh) */
MultiresLevel *current_level(Multires *mr)
void create_vert_face_map(ListBase **map, IndexNode **mem, const MFace *mface, const int totvert, const int totface)
{
return BLI_findlink(&mr->levels, mr->current - 1);
}
/* Returns the nth multires level, starting at 1 */
MultiresLevel *multires_level_n(Multires *mr, int n)
{
if(mr)
return BLI_findlink(&mr->levels, n - 1);
else
return NULL;
}
/* Free and clear the temporary connectivity data */
static void multires_free_temp_data(MultiresLevel *lvl)
{
if(lvl) {
if(lvl->edge_boundary_states) MEM_freeN(lvl->edge_boundary_states);
if(lvl->vert_edge_map) MEM_freeN(lvl->vert_edge_map);
if(lvl->vert_face_map) MEM_freeN(lvl->vert_face_map);
if(lvl->map_mem) MEM_freeN(lvl->map_mem);
lvl->edge_boundary_states = NULL;
lvl->vert_edge_map = lvl->vert_face_map = NULL;
lvl->map_mem = NULL;
int i,j;
IndexNode *node = NULL;
(*map) = MEM_callocN(sizeof(ListBase) * totvert, "vert face map");
(*mem) = MEM_callocN(sizeof(IndexNode) * totface*4, "vert face map mem");
node = *mem;
/* Find the users */
for(i = 0; i < totface; ++i){
for(j = 0; j < (mface[i].v4?4:3); ++j, ++node) {
node->index = i;
BLI_addtail(&(*map)[((unsigned int*)(&mface[i]))[j]], node);
}
}
}
void create_vert_edge_map(ListBase **map, IndexNode **mem, const MEdge *medge, const int totvert, const int totedge)
{
int i, j;
IndexNode *node = NULL;
(*map) = MEM_callocN(sizeof(ListBase) * totvert, "vert edge map");
(*mem) = MEM_callocN(sizeof(IndexNode) * totedge * 2, "vert edge map mem");
node = *mem;
/* Find the users */
for(i = 0; i < totedge; ++i){
for(j = 0; j < 2; ++j, ++node) {
node->index = i;
BLI_addtail(&(*map)[((unsigned int*)(&medge[i].v1))[j]], node);
}
}
}
/* MULTIRES MODIFIER */
static const int multires_max_levels = 13;
static const int multires_quad_tot[] = {4, 9, 25, 81, 289, 1089, 4225, 16641, 66049, 263169, 1050625, 4198401, 16785409};
static const int multires_side_tot[] = {2, 3, 5, 9, 17, 33, 65, 129, 257, 513, 1025, 2049, 4097};
int multiresModifier_switch_level(Object *ob, const int distance)
{
ModifierData *md = NULL;
MultiresModifierData *mmd = NULL;
for(md = ob->modifiers.first; md; md = md->next) {
if(md->type == eModifierType_Multires)
mmd = (MultiresModifierData*)md;
}
if(mmd) {
mmd->lvl += distance;
if(mmd->lvl < 1) mmd->lvl = 1;
else if(mmd->lvl > mmd->totlvl) mmd->lvl = mmd->totlvl;
/* XXX: DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
object_handle_update(ob);*/
return 1;
}
else
return 0;
}
/* XXX */
#if 0
void multiresModifier_join(Object *ob)
{
Base *base = NULL;
int highest_lvl = 0;
/* First find the highest level of subdivision */
base = FIRSTBASE;
while(base) {
if(TESTBASELIB_BGMODE(base) && base->object->type==OB_MESH) {
ModifierData *md;
for(md = base->object->modifiers.first; md; md = md->next) {
if(md->type == eModifierType_Multires) {
int totlvl = ((MultiresModifierData*)md)->totlvl;
if(totlvl > highest_lvl)
highest_lvl = totlvl;
/* Ensure that all updates are processed */
multires_force_update(base->object);
}
}
}
base = base->next;
}
/* No multires meshes selected */
if(highest_lvl == 0)
return;
/* Subdivide all the displacements to the highest level */
base = FIRSTBASE;
while(base) {
if(TESTBASELIB_BGMODE(base) && base->object->type==OB_MESH) {
ModifierData *md = NULL;
MultiresModifierData *mmd = NULL;
for(md = base->object->modifiers.first; md; md = md->next) {
if(md->type == eModifierType_Multires)
mmd = (MultiresModifierData*)md;
}
/* If the object didn't have multires enabled, give it a new modifier */
if(!mmd) {
md = base->object->modifiers.first;
while(md && modifierType_getInfo(md->type)->type == eModifierTypeType_OnlyDeform)
md = md->next;
mmd = (MultiresModifierData*)modifier_new(eModifierType_Multires);
BLI_insertlinkbefore(&base->object->modifiers, md, mmd);
}
if(mmd)
multiresModifier_subdivide(mmd, base->object, highest_lvl - mmd->totlvl, 0, 0);
}
base = base->next;
}
}
#endif
/* Returns 0 on success, 1 if the src's totvert doesn't match */
int multiresModifier_reshape(MultiresModifierData *mmd, Object *dst, Object *src)
{
Mesh *src_me = get_mesh(src);
DerivedMesh *mrdm = dst->derivedFinal;
if(mrdm && mrdm->getNumVerts(mrdm) == src_me->totvert) {
MVert *mvert = CDDM_get_verts(mrdm);
int i;
for(i = 0; i < src_me->totvert; ++i)
VecCopyf(mvert[i].co, src_me->mvert[i].co);
mrdm->needsFree = 1;
*MultiresDM_get_flags(mrdm) |= MULTIRES_DM_UPDATE_ALWAYS;
mrdm->release(mrdm);
dst->derivedFinal = NULL;
return 0;
}
return 1;
}
static void Mat3FromColVecs(float mat[][3], float v1[3], float v2[3], float v3[3])
{
VecCopyf(mat[0], v1);
VecCopyf(mat[1], v2);
VecCopyf(mat[2], v3);
}
static DerivedMesh *multires_subdisp_pre(DerivedMesh *mrdm, int distance, int simple)
{
DerivedMesh *final;
SubsurfModifierData smd;
memset(&smd, 0, sizeof(SubsurfModifierData));
smd.levels = distance;
if(simple)
smd.subdivType = ME_SIMPLE_SUBSURF;
final = subsurf_make_derived_from_derived_with_multires(mrdm, &smd, NULL, 0, NULL, 0, 0);
return final;
}
static void VecAddUf(float a[3], float b[3])
{
a[0] += b[0];
a[1] += b[1];
a[2] += b[2];
}
static void multires_subdisp(DerivedMesh *orig, Mesh *me, DerivedMesh *final, int lvl, int totlvl,
int totsubvert, int totsubedge, int totsubface, int addverts)
{
DerivedMesh *mrdm;
MultiresModifierData mmd_sub;
MVert *mvs = CDDM_get_verts(final);
MVert *mvd, *mvd_f1, *mvs_f1, *mvd_f3, *mvd_f4;
MVert *mvd_f2, *mvs_f2, *mvs_e1, *mvd_e1, *mvs_e2;
int totvert;
int slo1 = multires_side_tot[lvl - 1];
int sll = slo1 / 2;
int slo2 = multires_side_tot[totlvl - 2];
int shi2 = multires_side_tot[totlvl - 1];
int skip = multires_side_tot[totlvl - lvl] - 1;
int i, j, k;
mmd_sub.lvl = mmd_sub.totlvl = totlvl;
mrdm = multires_dm_create_from_derived(&mmd_sub, orig, me, 0, 0);
mvd = CDDM_get_verts(mrdm);
/* Need to map from ccg to mrdm */
totvert = mrdm->getNumVerts(mrdm);
if(!addverts) {
for(i = 0; i < totvert; ++i) {
float z[3] = {0,0,0};
VecCopyf(mvd[i].co, z);
}
}
/* Load base verts */
for(i = 0; i < me->totvert; ++i)
VecAddUf(mvd[totvert - me->totvert + i].co, mvs[totvert - me->totvert + i].co);
mvd_f1 = mvd;
mvs_f1 = mvs;
mvd_f2 = mvd;
mvs_f2 = mvs + totvert - totsubvert;
mvs_e1 = mvs + totsubface * (skip-1) * (skip-1);
for(i = 0; i < me->totface; ++i) {
const int end = me->mface[i].v4 ? 4 : 3;
int x, y, x2, y2, mov;
mvd_f1 += 1 + end * (slo2-2); //center+edgecross
mvd_f3 = mvd_f4 = mvd_f1;
for(j = 0; j < end; ++j) {
mvd_f1 += (skip/2 - 1) * (slo2 - 2) + (skip/2 - 1);
/* Update sub faces */
for(y = 0; y < sll; ++y) {
for(x = 0; x < sll; ++x) {
/* Face center */
VecAddUf(mvd_f1->co, mvs_f1->co);
mvs_f1 += 1;
/* Now we hold the center of the subface at mvd_f1
and offset it to the edge cross and face verts */
/* Edge cross */
for(k = 0; k < 4; ++k) {
if(k == 0) mov = -1;
else if(k == 1) mov = slo2 - 2;
else if(k == 2) mov = 1;
else if(k == 3) mov = -(slo2 - 2);
for(x2 = 1; x2 < skip/2; ++x2) {
VecAddUf((mvd_f1 + mov * x2)->co, mvs_f1->co);
++mvs_f1;
}
}
/* Main face verts */
for(k = 0; k < 4; ++k) {
int movx, movy;
if(k == 0) { movx = -1; movy = -(slo2 - 2); }
else if(k == 1) { movx = slo2 - 2; movy = -1; }
else if(k == 2) { movx = 1; movy = slo2 - 2; }
else if(k == 3) { movx = -(slo2 - 2); movy = 1; }
for(y2 = 1; y2 < skip/2; ++y2) {
for(x2 = 1; x2 < skip/2; ++x2) {
VecAddUf((mvd_f1 + movy * y2 + movx * x2)->co, mvs_f1->co);
++mvs_f1;
}
}
}
mvd_f1 += skip;
}
mvd_f1 += (skip - 1) * (slo2 - 2) - 1;
}
mvd_f1 -= (skip - 1) * (slo2 - 2) - 1 + skip;
mvd_f1 += (slo2 - 2) * (skip/2-1) + skip/2-1 + 1;
}
/* update face center verts */
VecAddUf(mvd_f2->co, mvs_f2->co);
mvd_f2 += 1;
mvs_f2 += 1;
/* update face edge verts */
for(j = 0; j < end; ++j) {
MVert *restore;
/* Super-face edge cross */
for(k = 0; k < skip-1; ++k) {
VecAddUf(mvd_f2->co, mvs_e1->co);
mvd_f2++;
mvs_e1++;
}
for(x = 1; x < sll; ++x) {
VecAddUf(mvd_f2->co, mvs_f2->co);
mvd_f2++;
mvs_f2++;
for(k = 0; k < skip-1; ++k) {
VecAddUf(mvd_f2->co, mvs_e1->co);
mvd_f2++;
mvs_e1++;
}
}
restore = mvs_e1;
for(y = 0; y < sll - 1; ++y) {
for(x = 0; x < sll; ++x) {
for(k = 0; k < skip - 1; ++k) {
VecAddUf(mvd_f3[(skip-1)+(y*skip) + (x*skip+k)*(slo2-2)].co,
mvs_e1->co);
++mvs_e1;
}
mvs_e1 += skip-1;
}
}
mvs_e1 = restore + skip - 1;
for(y = 0; y < sll - 1; ++y) {
for(x = 0; x < sll; ++x) {
for(k = 0; k < skip - 1; ++k) {
VecAddUf(mvd_f3[(slo2-2)*(skip-1)+(x*skip)+k + y*skip*(slo2-2)].co,
mvs_e1->co);
++mvs_e1;
}
mvs_e1 += skip - 1;
}
}
mvd_f3 += (slo2-2)*(slo2-2);
mvs_e1 -= skip - 1;
}
/* update base (2) face verts */
for(j = 0; j < end; ++j) {
mvd_f2 += (slo2 - 1) * (skip - 1);
for(y = 0; y < sll - 1; ++y) {
for(x = 0; x < sll - 1; ++x) {
VecAddUf(mvd_f2->co, mvs_f2->co);
mvd_f2 += skip;
++mvs_f2;
}
mvd_f2 += (slo2 - 1) * (skip - 1);
}
mvd_f2 -= (skip - 1);
}
}
/* edges */
mvd_e1 = mvd + totvert - me->totvert - me->totedge * (shi2-2);
mvs_e2 = mvs + totvert - me->totvert - me->totedge * (slo1-2);
for(i = 0; i < me->totedge; ++i) {
for(j = 0; j < skip - 1; ++j) {
VecAddUf(mvd_e1->co, mvs_e1->co);
mvd_e1++;
mvs_e1++;
}
for(j = 0; j < slo1 - 2; j++) {
VecAddUf(mvd_e1->co, mvs_e2->co);
mvd_e1++;
mvs_e2++;
for(k = 0; k < skip - 1; ++k) {
VecAddUf(mvd_e1->co, mvs_e1->co);
mvd_e1++;
mvs_e1++;
}
}
}
final->needsFree = 1;
final->release(final);
mrdm->needsFree = 1;
*MultiresDM_get_flags(mrdm) |= MULTIRES_DM_UPDATE_ALWAYS;
mrdm->release(mrdm);
}
/* direction=1 for delete higher, direction=0 for lower (not implemented yet) */
void multiresModifier_del_levels(struct MultiresModifierData *mmd, struct Object *ob, int direction)
{
Mesh *me = get_mesh(ob);
int distance = mmd->totlvl - mmd->lvl;
MDisps *mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
multires_force_update(ob);
if(mdisps && distance > 0 && direction == 1) {
int skip = multires_side_tot[distance] - 1;
int st = multires_side_tot[mmd->totlvl - 1];
int totdisp = multires_quad_tot[mmd->lvl - 1];
int i, j, x, y;
for(i = 0; i < me->totface; ++i) {
float (*disps)[3] = MEM_callocN(sizeof(float) * 3 * totdisp, "multires del disps");
for(j = 0, y = 0; y < st; y += skip) {
for(x = 0; x < st; x += skip) {
VecCopyf(disps[j], mdisps[i].disps[y * st + x]);
++j;
}
}
MEM_freeN(mdisps[i].disps);
mdisps[i].disps = disps;
mdisps[i].totdisp = totdisp;
}
}
mmd->totlvl = mmd->lvl;
}
void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int distance, int updateblock, int simple)
{
DerivedMesh *final = NULL;
int totsubvert, totsubface, totsubedge;
Mesh *me = get_mesh(ob);
MDisps *mdisps;
int i;
if(distance == 0)
return;
if(mmd->totlvl > multires_max_levels)
mmd->totlvl = multires_max_levels;
if(mmd->lvl > multires_max_levels)
mmd->lvl = multires_max_levels;
multires_force_update(ob);
mmd->lvl = mmd->totlvl;
mmd->totlvl += distance;
mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
if(!mdisps)
mdisps = CustomData_add_layer(&me->fdata, CD_MDISPS, CD_DEFAULT, NULL, me->totface);
if(mdisps->disps && !updateblock && mmd->totlvl > 2) {
DerivedMesh *orig, *mrdm;
MultiresModifierData mmd_sub;
orig = CDDM_from_mesh(me, NULL);
mmd_sub.lvl = mmd_sub.totlvl = mmd->lvl;
mrdm = multires_dm_create_from_derived(&mmd_sub, orig, me, 0, 0);
totsubvert = mrdm->getNumVerts(mrdm);
totsubedge = mrdm->getNumEdges(mrdm);
totsubface = mrdm->getNumFaces(mrdm);
orig->needsFree = 1;
orig->release(orig);
final = multires_subdisp_pre(mrdm, distance, simple);
mrdm->needsFree = 1;
*MultiresDM_get_flags(mrdm) |= MULTIRES_DM_UPDATE_BLOCK;
mrdm->release(mrdm);
}
for(i = 0; i < me->totface; ++i) {
const int totdisp = multires_quad_tot[mmd->totlvl - 1];
float (*disps)[3] = MEM_callocN(sizeof(float) * 3 * totdisp, "multires disps");
if(mdisps[i].disps)
MEM_freeN(mdisps[i].disps);
mdisps[i].disps = disps;
mdisps[i].totdisp = totdisp;
}
if(final) {
DerivedMesh *orig;
orig = CDDM_from_mesh(me, NULL);
multires_subdisp(orig, me, final, mmd->lvl, mmd->totlvl, totsubvert, totsubedge, totsubface, 0);
orig->needsFree = 1;
orig->release(orig);
}
mmd->lvl = mmd->totlvl;
}
typedef struct DisplacerEdges {
/* DerivedMesh index at the start of each edge (using face x/y directions to define the start) */
int base[4];
/* 1 if edge moves in the positive x or y direction, -1 otherwise */
int dir[4];
} DisplacerEdges;
typedef struct DisplacerSpill {
/* Index of face (in base mesh), -1 for none */
int face;
/* Spill flag */
/* 1 = Negative variable axis */
/* 2 = Near fixed axis */
/* 4 = Flip axes */
int f;
/* Neighboring edges */
DisplacerEdges edges;
} DisplacerSpill;
typedef struct MultiresDisplacer {
Mesh *me;
MDisps *grid;
MFace *face;
int dm_first_base_vert_index;
int spacing;
int sidetot, interior_st, disp_st;
int sidendx;
int type;
int invert;
MVert *subco;
int subco_index, face_index;
float weight;
/* Valence for each corner */
int valence[4];
/* Neighboring edges for current face */
DisplacerEdges edges_primary;
/* Neighboring faces */
DisplacerSpill spill_x, spill_y;
int *face_offsets;
int x, y, ax, ay;
} MultiresDisplacer;
static int mface_v(MFace *f, int v)
{
return v == 0 ? f->v1 : v == 1 ? f->v2 : v == 2 ? f->v3 : v == 3 ? f->v4 : -1;
}
/* Get the edges (and their directions) */
static void find_displacer_edges(MultiresDisplacer *d, DerivedMesh *dm, DisplacerEdges *de, MFace *f)
{
ListBase *emap = MultiresDM_get_vert_edge_map(dm);
IndexNode *n;
int i, end = f->v4 ? 4 : 3;
int offset = dm->getNumVerts(dm) - d->me->totvert - d->me->totedge * d->interior_st;
for(i = 0; i < end; ++i) {
int vcur = mface_v(f, i);
int vnext = mface_v(f, i == end - 1 ? 0 : i + 1);
de->dir[i] = 1;
for(n = emap[vcur].first; n; n = n->next) {
MEdge *e = &d->me->medge[n->index];
if(e->v1 == vnext || e->v2 == vnext) {
de->base[i] = n->index * d->interior_st;
if(((i == 0 || i == 1) && e->v1 == vnext) ||
((i == 2 || i == 3) && e->v2 == vnext)) {
de->dir[i] = -1;
de->base[i] += d->interior_st - 1;
}
de->base[i] += offset;
break;
}
}
}
}
/* Returns in out the corners [0-3] that use v1 and v2 */
void find_face_corners(MFace *f, int v1, int v2, int out[2])
{
int i, end = f->v4 ? 4 : 3;
for(i = 0; i < end; ++i) {
int corner = mface_v(f, i);
if(corner == v1)
out[0] = i;
if(corner == v2)
out[1] = i;
}
}
static void multires_displacer_get_spill_faces(MultiresDisplacer *d, DerivedMesh *dm, MFace *mface)
{
ListBase *map = MultiresDM_get_vert_face_map(dm);
IndexNode *n1, *n2;
int v4 = d->face->v4 ? d->face->v4 : d->face->v1;
int crn[2], lv;
memset(&d->spill_x, 0, sizeof(DisplacerSpill));
memset(&d->spill_y, 0, sizeof(DisplacerSpill));
d->spill_x.face = d->spill_y.face = -1;
for(n1 = map[d->face->v3].first; n1; n1 = n1->next) {
if(n1->index == d->face_index)
continue;
for(n2 = map[d->face->v2].first; n2; n2 = n2->next) {
if(n1->index == n2->index)
d->spill_x.face = n1->index;
}
for(n2 = map[v4].first; n2; n2 = n2->next) {
if(n1->index == n2->index)
d->spill_y.face = n1->index;
}
}
if(d->spill_x.face != -1) {
/* Neighbor of v2/v3 found, find flip and orientation */
find_face_corners(&mface[d->spill_x.face], d->face->v2, d->face->v3, crn);
lv = mface[d->spill_x.face].v4 ? 3 : 2;
if(crn[0] == 0 && crn[1] == lv)
d->spill_x.f = 0+2+0;
else if(crn[0] == lv && crn[1] == 0)
d->spill_x.f = 1+2+0;
else if(crn[0] == 1 && crn[1] == 0)
d->spill_x.f = 1+2+4;
else if(crn[0] == 0 && crn[1] == 1)
d->spill_x.f = 0+2+4;
else if(crn[0] == 2 && crn[1] == 1)
d->spill_x.f = 1+0+0;
else if(crn[0] == 1 && crn[1] == 2)
d->spill_x.f = 0+0+0;
else if(crn[0] == 3 && crn[1] == 2)
d->spill_x.f = 0+0+4;
else if(crn[0] == 2 && crn[1] == 3)
d->spill_x.f = 1+0+4;
find_displacer_edges(d, dm, &d->spill_x.edges, &mface[d->spill_x.face]);
}
if(d->spill_y.face != -1) {
/* Neighbor of v3/v4 found, find flip and orientation */
find_face_corners(&mface[d->spill_y.face], d->face->v3, v4, crn);
lv = mface[d->spill_y.face].v4 ? 3 : 2;
if(crn[0] == 1 && crn[1] == 0)
d->spill_y.f = 1+2+0;
else if(crn[0] == 0 && crn[1] == 1)
d->spill_y.f = 0+2+0;
else if(crn[0] == 2 && crn[1] == 1)
d->spill_y.f = 1+0+4;
else if(crn[0] == 1 && crn[1] == 2)
d->spill_y.f = 0+0+4;
else if(crn[0] == 3 && crn[1] == 2)
d->spill_y.f = 0+0+0;
else if(crn[0] == 2 && crn[1] == 3)
d->spill_y.f = 1+0+0;
else if(crn[0] == 0 && crn[1] == lv)
d->spill_y.f = 0+2+4;
else if(crn[0] == lv && crn[1] == 0)
d->spill_y.f = 1+2+4;
find_displacer_edges(d, dm, &d->spill_y.edges, &mface[d->spill_y.face]);
}
}
static void find_corner_valences(MultiresDisplacer *d, DerivedMesh *dm)
{
int i;
d->valence[3] = -1;
/* Set the vertex valence for the corners */
for(i = 0; i < (d->face->v4 ? 4 : 3); ++i)
d->valence[i] = BLI_countlist(&MultiresDM_get_vert_edge_map(dm)[mface_v(d->face, i)]);
}
static void multires_displacer_init(MultiresDisplacer *d, DerivedMesh *dm,
const int face_index, const int invert)
{
Mesh *me = MultiresDM_get_mesh(dm);
d->me = me;
d->face = me->mface + face_index;
d->face_index = face_index;
d->face_offsets = MultiresDM_get_face_offsets(dm);
/* Get the multires grid from customdata */
d->grid = CustomData_get_layer(&me->fdata, CD_MDISPS);
if(d->grid)
d->grid += face_index;
d->spacing = pow(2, MultiresDM_get_totlvl(dm) - MultiresDM_get_lvl(dm));
d->sidetot = multires_side_tot[MultiresDM_get_lvl(dm) - 1];
d->interior_st = d->sidetot - 2;
d->disp_st = multires_side_tot[MultiresDM_get_totlvl(dm) - 1];
d->invert = invert;
multires_displacer_get_spill_faces(d, dm, me->mface);
find_displacer_edges(d, dm, &d->edges_primary, d->face);
find_corner_valences(d, dm);
d->dm_first_base_vert_index = dm->getNumVerts(dm) - me->totvert;
}
static void multires_displacer_weight(MultiresDisplacer *d, const float w)
{
d->weight = w;
}
static void multires_displacer_anchor(MultiresDisplacer *d, const int type, const int side_index)
{
d->sidendx = side_index;
d->x = d->y = d->sidetot / 2;
d->type = type;
if(type == 2) {
if(side_index == 0)
d->y -= 1;
else if(side_index == 1)
d->x += 1;
else if(side_index == 2)
d->y += 1;
else if(side_index == 3)
d->x -= 1;
}
else if(type == 3) {
if(side_index == 0) {
d->x -= 1;
d->y -= 1;
}
else if(side_index == 1) {
d->x += 1;
d->y -= 1;
}
else if(side_index == 2) {
d->x += 1;
d->y += 1;
}
else if(side_index == 3) {
d->x -= 1;
d->y += 1;
}
}
d->ax = d->x;
d->ay = d->y;
}
static void multires_displacer_anchor_edge(MultiresDisplacer *d, int v1, int v2, int x)
{
d->type = 4;
if(v1 == d->face->v1) {
d->x = 0;
d->y = 0;
if(v2 == d->face->v2)
d->x += x;
else if(v2 == d->face->v3) {
if(x < d->sidetot / 2)
d->y = x;
else {
d->x = x;
d->y = d->sidetot - 1;
}
}
else
d->y += x;
}
else if(v1 == d->face->v2) {
d->x = d->sidetot - 1;
d->y = 0;
if(v2 == d->face->v1)
d->x -= x;
else
d->y += x;
}
else if(v1 == d->face->v3) {
d->x = d->sidetot - 1;
d->y = d->sidetot - 1;
if(v2 == d->face->v2)
d->y -= x;
else if(v2 == d->face->v1) {
if(x < d->sidetot / 2)
d->x -= x;
else {
d->x = 0;
d->y -= x;
}
}
else
d->x -= x;
}
else if(v1 == d->face->v4) {
d->x = 0;
d->y = d->sidetot - 1;
if(v2 == d->face->v3)
d->x += x;
else
d->y -= x;
}
}
static void multires_displacer_anchor_vert(MultiresDisplacer *d, const int v)
{
const int e = d->sidetot - 1;
d->type = 5;
d->x = d->y = 0;
if(v == d->face->v2)
d->x = e;
else if(v == d->face->v3)
d->x = d->y = e;
else if(v == d->face->v4)
d->y = e;
}
static void multires_displacer_jump(MultiresDisplacer *d)
{
if(d->sidendx == 0) {
d->x -= 1;
d->y = d->ay;
}
else if(d->sidendx == 1) {
d->x = d->ax;
d->y -= 1;
}
else if(d->sidendx == 2) {
d->x += 1;
d->y = d->ay;
}
else if(d->sidendx == 3) {
d->x = d->ax;
d->y += 1;
}
}
/* Treating v1 as (0,0) and v3 as (st-1,st-1),
returns the index of the vertex at (x,y).
If x or y is >= st, wraps over to the adjacent face,
or if there is no adjacent face, returns -2. */
static int multires_index_at_loc(int face_index, int x, int y, MultiresDisplacer *d, DisplacerEdges *de)
{
int coord_edge = d->sidetot - 1; /* Max value of x/y at edge of grid */
int mid = d->sidetot / 2;
int lim = mid - 1;
int qtot = lim * lim;
int base = d->face_offsets[face_index];
/* Edge spillover */
if(x == d->sidetot || y == d->sidetot) {
int flags, v_axis, f_axis, lx, ly;
if(x == d->sidetot && d->spill_x.face != -1) {
flags = d->spill_x.f;
/* Handle triangle seam between v1 and v3 */
if(!d->me->mface[d->spill_x.face].v4 &&
((flags == 2 && y >= mid) || (flags == 3 && y < mid)))
flags += 2;
v_axis = (flags & 1) ? d->sidetot - 1 - y : y;
f_axis = (flags & 2) ? 1 : d->sidetot - 2;
lx = f_axis, ly = v_axis;
if(flags & 4) {
lx = v_axis;
ly = f_axis;
}
return multires_index_at_loc(d->spill_x.face, lx, ly, d, &d->spill_x.edges);
}
else if(y == d->sidetot && d->spill_y.face != -1) {
flags = d->spill_y.f;
/* Handle triangle seam between v1 and v3 */
if(!d->me->mface[d->spill_y.face].v4 &&
((flags == 6 && x >= mid) || (flags == 7 && x < mid)))
flags = ~flags;
v_axis = (flags & 1) ? x : d->sidetot - 1 - x;
f_axis = (flags & 2) ? 1 : d->sidetot - 2;
lx = v_axis, ly = f_axis;
if(flags & 4) {
lx = f_axis;
ly = v_axis;
}
return multires_index_at_loc(d->spill_y.face, lx, ly, d, &d->spill_y.edges);
}
else
return -2;
}
/* Corners */
else if(x == 0 && y == 0)
return d->dm_first_base_vert_index + d->face->v1;
else if(x == coord_edge && y == 0)
return d->dm_first_base_vert_index + d->face->v2;
else if(x == coord_edge && y == coord_edge)
return d->dm_first_base_vert_index + d->face->v3;
else if(x == 0 && y == coord_edge)
return d->dm_first_base_vert_index + d->face->v4;
/* Edges */
else if(x == 0) {
if(d->face->v4)
return de->base[3] + de->dir[3] * (y - 1);
else
return de->base[2] + de->dir[2] * (y - 1);
}
else if(y == 0)
return de->base[0] + de->dir[0] * (x - 1);
else if(x == d->sidetot - 1)
return de->base[1] + de->dir[1] * (y - 1);
else if(y == d->sidetot - 1)
return de->base[2] + de->dir[2] * (x - 1);
/* Face center */
else if(x == mid && y == mid)
return base;
/* Cross */
else if(x == mid && y < mid)
return base + (mid - y);
else if(y == mid && x > mid)
return base + lim + (x - mid);
else if(x == mid && y > mid)
return base + lim*2 + (y - mid);
else if(y == mid && x < mid) {
if(d->face->v4)
return base + lim*3 + (mid - x);
else
return base + lim*2 + (mid - x);
}
/* Quarters */
else {
int offset = base + lim * (d->face->v4 ? 4 : 3);
if(x < mid && y < mid)
return offset + ((mid - x - 1)*lim + (mid - y));
else if(x > mid && y < mid)
return offset + qtot + ((mid - y - 1)*lim + (x - mid));
else if(x > mid && y > mid)
return offset + qtot*2 + ((x - mid - 1)*lim + (y - mid));
else if(x < mid && y > mid)
return offset + qtot*3 + ((y - mid - 1)*lim + (mid - x));
}
return -1;
}
/* Calculate the TS matrix used for applying displacements.
Uses the undisplaced subdivided mesh's curvature to find a
smoothly normal and tangents. */
static void calc_disp_mat(MultiresDisplacer *d, float mat[3][3])
{
int u = multires_index_at_loc(d->face_index, d->x + 1, d->y, d, &d->edges_primary);
int v = multires_index_at_loc(d->face_index, d->x, d->y + 1, d, &d->edges_primary);
float norm[3], t1[3], t2[3], inv[3][3];
MVert *base = d->subco + d->subco_index;
//printf("f=%d, x=%d, y=%d, i=%d, u=%d, v=%d ", d->face_index, d->x, d->y, d->subco_index, u, v);
norm[0] = base->no[0] / 32767.0f;
norm[1] = base->no[1] / 32767.0f;
norm[2] = base->no[2] / 32767.0f;
/* Special handling for vertices of valence 3 */
if(d->valence[1] == 3 && d->x == d->sidetot - 1 && d->y == 0)
u = -1;
else if(d->valence[2] == 3 && d->x == d->sidetot - 1 && d->y == d->sidetot - 1)
u = v = -1;
else if(d->valence[3] == 3 && d->x == 0 && d->y == d->sidetot - 1)
v = -1;
/* If either u or v is -2, it's on a boundary. In this
case, back up by one row/column and use the same
vector as the preceeding sub-edge. */
if(u < 0) {
u = multires_index_at_loc(d->face_index, d->x - 1, d->y, d, &d->edges_primary);
VecSubf(t1, base->co, d->subco[u].co);
}
else
VecSubf(t1, d->subco[u].co, base->co);
if(v < 0) {
v = multires_index_at_loc(d->face_index, d->x, d->y - 1, d, &d->edges_primary);
VecSubf(t2, base->co, d->subco[v].co);
}
else
VecSubf(t2, d->subco[v].co, base->co);
//printf("uu=%d, vv=%d\n", u, v);
Normalize(t1);
Normalize(t2);
Mat3FromColVecs(mat, t1, t2, norm);
if(d->invert) {
Mat3Inv(inv, mat);
Mat3CpyMat3(mat, inv);
}
}
static void multires_displace(MultiresDisplacer *d, float co[3])
{
float disp[3], mat[3][3];
float *data;
MVert *subco = &d->subco[d->subco_index];
if(!d->grid || !d->grid->disps) return;
data = d->grid->disps[(d->y * d->spacing) * d->disp_st + (d->x * d->spacing)];
if(d->invert)
VecSubf(disp, co, subco->co);
else
VecCopyf(disp, data);
/* Apply ts matrix to displacement */
calc_disp_mat(d, mat);
Mat3MulVecfl(mat, disp);
if(d->invert) {
VecCopyf(data, disp);
}
else {
if(d->type == 4 || d->type == 5)
VecMulf(disp, d->weight);
VecAddf(co, co, disp);
}
if(d->type == 2) {
if(d->sidendx == 0)
d->y -= 1;
else if(d->sidendx == 1)
d->x += 1;
else if(d->sidendx == 2)
d->y += 1;
else if(d->sidendx == 3)
d->x -= 1;
}
else if(d->type == 3) {
if(d->sidendx == 0)
d->y -= 1;
else if(d->sidendx == 1)
d->x += 1;
else if(d->sidendx == 2)
d->y += 1;
else if(d->sidendx == 3)
d->x -= 1;
}
}
static void multiresModifier_disp_run(DerivedMesh *dm, MVert *subco, int invert)
{
const int lvl = MultiresDM_get_lvl(dm);
const int gridFaces = multires_side_tot[lvl - 2] - 1;
const int edgeSize = multires_side_tot[lvl - 1] - 1;
MVert *mvert = CDDM_get_verts(dm);
MEdge *medge = MultiresDM_get_mesh(dm)->medge;
MFace *mface = MultiresDM_get_mesh(dm)->mface;
ListBase *map = MultiresDM_get_vert_face_map(dm);
Mesh *me = MultiresDM_get_mesh(dm);
MultiresDisplacer d;
int i, S, x, y;
d.subco = subco;
d.subco_index = 0;
for(i = 0; i < me->totface; ++i) {
const int numVerts = mface[i].v4 ? 4 : 3;
/* Center */
multires_displacer_init(&d, dm, i, invert);
multires_displacer_anchor(&d, 1, 0);
multires_displace(&d, mvert->co);
++mvert;
++d.subco_index;
/* Cross */
for(S = 0; S < numVerts; ++S) {
multires_displacer_anchor(&d, 2, S);
for(x = 1; x < gridFaces; ++x) {
multires_displace(&d, mvert->co);
++mvert;
++d.subco_index;
}
}
/* Quarters */
for(S = 0; S < numVerts; S++) {
multires_displacer_anchor(&d, 3, S);
for(y = 1; y < gridFaces; y++) {
for(x = 1; x < gridFaces; x++) {
multires_displace(&d, mvert->co);
++mvert;
++d.subco_index;
}
multires_displacer_jump(&d);
}
}
}
for(i = 0; i < me->totedge; ++i) {
const MEdge *e = &medge[i];
for(x = 1; x < edgeSize; ++x) {
IndexNode *n1, *n2;
int numFaces = 0;
for(n1 = map[e->v1].first; n1; n1 = n1->next) {
for(n2 = map[e->v2].first; n2; n2 = n2->next) {
if(n1->index == n2->index)
++numFaces;
}
}
multires_displacer_weight(&d, 1.0f / numFaces);
/* TODO: Better to have these loops outside the x loop */
for(n1 = map[e->v1].first; n1; n1 = n1->next) {
for(n2 = map[e->v2].first; n2; n2 = n2->next) {
if(n1->index == n2->index) {
multires_displacer_init(&d, dm, n1->index, invert);
multires_displacer_anchor_edge(&d, e->v1, e->v2, x);
multires_displace(&d, mvert->co);
}
}
}
++mvert;
++d.subco_index;
}
}
for(i = 0; i < me->totvert; ++i) {
IndexNode *n;
multires_displacer_weight(&d, 1.0f / BLI_countlist(&map[i]));
for(n = map[i].first; n; n = n->next) {
multires_displacer_init(&d, dm, n->index, invert);
multires_displacer_anchor_vert(&d, i);
multires_displace(&d, mvert->co);
}
++mvert;
++d.subco_index;
}
if(!invert)
CDDM_calc_normals(dm);
}
static void multiresModifier_update(DerivedMesh *dm)
{
Mesh *me;
MDisps *mdisps;
if(!(G.f & G_SCULPTMODE) && !(*MultiresDM_get_flags(dm) & MULTIRES_DM_UPDATE_ALWAYS)) return;
me = MultiresDM_get_mesh(dm);
mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
if(mdisps) {
const int lvl = MultiresDM_get_lvl(dm);
const int totlvl = MultiresDM_get_totlvl(dm);
if(lvl < totlvl) {
/* Propagate disps upwards */
DerivedMesh *final, *subco_dm, *orig;
MVert *verts_new = NULL, *cur_lvl_orig_verts = NULL;
MultiresModifierData mmd;
int i;
orig = CDDM_from_mesh(me, NULL);
/* Regenerate the current level's vertex coordinates
(includes older displacements but not new sculpts) */
mmd.totlvl = totlvl;
mmd.lvl = lvl;
subco_dm = multires_dm_create_from_derived(&mmd, orig, me, 0, 0);
*MultiresDM_get_flags(subco_dm) |= MULTIRES_DM_UPDATE_BLOCK;
cur_lvl_orig_verts = CDDM_get_verts(subco_dm);
/* Subtract the original vertex cos from the new vertex cos */
verts_new = CDDM_get_verts(dm);
for(i = 0; i < dm->getNumVerts(dm); ++i)
VecSubf(verts_new[i].co, verts_new[i].co, cur_lvl_orig_verts[i].co);
final = multires_subdisp_pre(dm, totlvl - lvl, 0);
multires_subdisp(orig, me, final, lvl, totlvl, dm->getNumVerts(dm), dm->getNumEdges(dm),
dm->getNumFaces(dm), 1);
subco_dm->release(subco_dm);
orig->release(orig);
}
else
multiresModifier_disp_run(dm, MultiresDM_get_subco(dm), 1);
}
}
void multires_force_update(Object *ob)
{
if(ob->derivedFinal) {
ob->derivedFinal->needsFree =1;
ob->derivedFinal->release(ob->derivedFinal);
ob->derivedFinal = NULL;
}
}
struct DerivedMesh *multires_dm_create_from_derived(MultiresModifierData *mmd, DerivedMesh *dm, Mesh *me,
int useRenderParams, int isFinalCalc)
{
SubsurfModifierData smd;
MultiresSubsurf ms;
DerivedMesh *result;
int i;
ms.mmd = mmd;
ms.me = me;
memset(&smd, 0, sizeof(SubsurfModifierData));
smd.levels = smd.renderLevels = mmd->lvl - 1;
smd.flags |= eSubsurfModifierFlag_SubsurfUv;
result = subsurf_make_derived_from_derived_with_multires(dm, &smd, &ms, useRenderParams, NULL, isFinalCalc, 0);
for(i = 0; i < result->getNumVerts(result); ++i)
MultiresDM_get_subco(result)[i] = CDDM_get_verts(result)[i];
multiresModifier_disp_run(result, MultiresDM_get_subco(result), 0);
MultiresDM_set_update(result, multiresModifier_update);
return result;
}
/**** Old Multires code ****
***************************/
/* Does not actually free lvl itself */
void multires_free_level(MultiresLevel *lvl)
{
@@ -86,8 +1281,6 @@ void multires_free_level(MultiresLevel *lvl)
if(lvl->faces) MEM_freeN(lvl->faces);
if(lvl->edges) MEM_freeN(lvl->edges);
if(lvl->colfaces) MEM_freeN(lvl->colfaces);
multires_free_temp_data(lvl);
}
}
@@ -117,1191 +1310,289 @@ void multires_free(Multires *mr)
}
}
static MultiresLevel *multires_level_copy(MultiresLevel *orig)
static void create_old_vert_face_map(ListBase **map, IndexNode **mem, const MultiresFace *mface,
const int totvert, const int totface)
{
if(orig) {
MultiresLevel *lvl= MEM_dupallocN(orig);
lvl->next= lvl->prev= NULL;
lvl->faces= MEM_dupallocN(orig->faces);
lvl->colfaces= MEM_dupallocN(orig->colfaces);
lvl->edges= MEM_dupallocN(orig->edges);
lvl->edge_boundary_states = NULL;
lvl->vert_edge_map= lvl->vert_face_map= NULL;
lvl->map_mem= NULL;
return lvl;
int i,j;
IndexNode *node = NULL;
(*map) = MEM_callocN(sizeof(ListBase) * totvert, "vert face map");
(*mem) = MEM_callocN(sizeof(IndexNode) * totface*4, "vert face map mem");
node = *mem;
/* Find the users */
for(i = 0; i < totface; ++i){
for(j = 0; j < (mface[i].v[3]?4:3); ++j, ++node) {
node->index = i;
BLI_addtail(&(*map)[mface[i].v[j]], node);
}
}
}
static void create_old_vert_edge_map(ListBase **map, IndexNode **mem, const MultiresEdge *medge,
const int totvert, const int totedge)
{
int i,j;
IndexNode *node = NULL;
(*map) = MEM_callocN(sizeof(ListBase) * totvert, "vert edge map");
(*mem) = MEM_callocN(sizeof(IndexNode) * totedge*2, "vert edge map mem");
node = *mem;
/* Find the users */
for(i = 0; i < totedge; ++i){
for(j = 0; j < 2; ++j, ++node) {
node->index = i;
BLI_addtail(&(*map)[medge[i].v[j]], node);
}
}
}
static MultiresFace *find_old_face(ListBase *map, MultiresFace *faces, int v1, int v2, int v3, int v4)
{
IndexNode *n1;
int v[4] = {v1, v2, v3, v4}, i, j;
for(n1 = map[v1].first; n1; n1 = n1->next) {
int fnd[4] = {0, 0, 0, 0};
for(i = 0; i < 4; ++i) {
for(j = 0; j < 4; ++j) {
if(v[i] == faces[n1->index].v[j])
fnd[i] = 1;
}
}
if(fnd[0] && fnd[1] && fnd[2] && fnd[3])
return &faces[n1->index];
}
return NULL;
}
Multires *multires_copy(Multires *orig)
static MultiresEdge *find_old_edge(ListBase *map, MultiresEdge *edges, int v1, int v2)
{
const CustomDataMask vdata_mask= CD_MASK_MDEFORMVERT;
IndexNode *n1, *n2;
if(orig) {
Multires *mr= MEM_dupallocN(orig);
MultiresLevel *lvl;
mr->levels.first= mr->levels.last= NULL;
for(lvl= orig->levels.first; lvl; lvl= lvl->next)
BLI_addtail(&mr->levels, multires_level_copy(lvl));
mr->verts= MEM_dupallocN(orig->verts);
lvl= mr->levels.first;
if(lvl) {
CustomData_copy(&orig->vdata, &mr->vdata, vdata_mask, CD_DUPLICATE, lvl->totvert);
CustomData_copy(&orig->fdata, &mr->fdata, CD_MASK_MTFACE, CD_DUPLICATE, lvl->totface);
mr->edge_flags= MEM_dupallocN(orig->edge_flags);
mr->edge_creases= MEM_dupallocN(orig->edge_creases);
for(n1 = map[v1].first; n1; n1 = n1->next) {
for(n2 = map[v2].first; n2; n2 = n2->next) {
if(n1->index == n2->index)
return &edges[n1->index];
}
return mr;
}
return NULL;
}
static void multires_get_vert(MVert *out, EditVert *eve, MVert *m, int i)
static void multires_load_old_edges(ListBase **emap, MultiresLevel *lvl, int *vvmap, int dst, int v1, int v2, int mov)
{
if(eve) {
VecCopyf(out->co, eve->co);
out->flag= 0;
if(eve->f & SELECT) out->flag |= 1;
if(eve->h) out->flag |= ME_HIDE;
eve->tmp.l= i;
}
else
*out= *m;
}
int emid = find_old_edge(emap[2], lvl->edges, v1, v2)->mid;
vvmap[dst + mov] = emid;
void eed_to_medge_flag(EditEdge *eed, short *flag, char *crease)
{
if(!eed || !flag) return;
/* Would be nice if EditMesh edge flags could be unified with Mesh flags! */
*flag= (eed->f & SELECT) | ME_EDGERENDER;
if(eed->f2<2) *flag |= ME_EDGEDRAW;
if(eed->f2==0) *flag |= ME_LOOSEEDGE;
if(eed->sharp) *flag |= ME_SHARP;
if(eed->seam) *flag |= ME_SEAM;
//XXX if(eed->h & EM_FGON) *flag |= ME_FGON;
if(eed->h & 1) *flag |= ME_HIDE;
*crease= (char)(255.0*eed->crease);
}
static void multires_get_edge(MultiresEdge *e, EditEdge *eed, MEdge *m, short *flag, char *crease)
{
if(eed) {
e->v[0]= eed->v1->tmp.l;
e->v[1]= eed->v2->tmp.l;
eed_to_medge_flag(eed, flag, crease);
} else {
e->v[0]= m->v1;
e->v[1]= m->v2;
*flag= m->flag;
*crease= m->crease;
if(lvl->next->next) {
multires_load_old_edges(emap + 1, lvl->next, vvmap, dst + mov, v1, emid, mov / 2);
multires_load_old_edges(emap + 1, lvl->next, vvmap, dst + mov, v2, emid, -mov / 2);
}
}
static void multires_get_face(MultiresFace *f, CustomData *fdata, int findex, EditFace *efa, MFace *m)
static void multires_load_old_faces(ListBase **fmap, ListBase **emap, MultiresLevel *lvl, int *vvmap, int dst,
int v1, int v2, int v3, int v4, int st2, int st3)
{
if(efa) {
MFace tmp;
int j;
tmp.v1= efa->v1->tmp.l;
tmp.v2= efa->v2->tmp.l;
tmp.v3= efa->v3->tmp.l;
tmp.v4= 0;
if(efa->v4) tmp.v4= efa->v4->tmp.l;
test_index_face(&tmp, fdata, findex, efa->v4?4:3);
for(j=0; j<4; ++j) f->v[j]= (&tmp.v1)[j];
int fmid;
int emid13, emid14, emid23, emid24;
/* Flags */
f->flag= efa->flag;
if(efa->f & 1) f->flag |= ME_FACE_SEL;
else f->flag &= ~ME_FACE_SEL;
if(efa->h) f->flag |= ME_HIDE;
f->mat_nr= efa->mat_nr;
} else {
f->v[0]= m->v1;
f->v[1]= m->v2;
f->v[2]= m->v3;
f->v[3]= m->v4;
f->flag= m->flag;
f->mat_nr= m->mat_nr;
}
}
if(lvl && lvl->next) {
fmid = find_old_face(fmap[1], lvl->faces, v1, v2, v3, v4)->mid;
vvmap[dst] = fmid;
/* For manipulating vertex colors / uvs */
static void mcol_to_multires(MultiresColFace *mrf, MCol *mcol)
{
char i;
for(i=0; i<4; ++i) {
mrf->col[i].a= mcol[i].a;
mrf->col[i].r= mcol[i].r;
mrf->col[i].g= mcol[i].g;
mrf->col[i].b= mcol[i].b;
}
}
emid13 = find_old_edge(emap[1], lvl->edges, v1, v3)->mid;
emid14 = find_old_edge(emap[1], lvl->edges, v1, v4)->mid;
emid23 = find_old_edge(emap[1], lvl->edges, v2, v3)->mid;
emid24 = find_old_edge(emap[1], lvl->edges, v2, v4)->mid;
/* 1 <= count <= 4 */
static void multires_col_avg(MultiresCol *avg, MultiresCol cols[4], char count)
{
unsigned i;
avg->a= avg->r= avg->g= avg->b= 0;
for(i=0; i<count; ++i) {
avg->a+= cols[i].a;
avg->r+= cols[i].r;
avg->g+= cols[i].g;
avg->b+= cols[i].b;
}
avg->a/= count;
avg->r/= count;
avg->g/= count;
avg->b/= count;
}
static void multires_col_avg2(MultiresCol *avg, MultiresCol *c1, MultiresCol *c2)
{
MultiresCol in[2];
in[0]= *c1;
in[1]= *c2;
multires_col_avg(avg,in,2);
}
multires_load_old_faces(fmap + 1, emap + 1, lvl->next, vvmap, dst + st2 * st3 + st3,
fmid, v2, emid23, emid24, st2, st3 / 2);
void multires_load_cols(Mesh *me)
{
MultiresLevel *lvl= BLI_findlink(&me->mr->levels,me->mr->current-1), *cur;
EditMesh *em= me->edit_mesh;
CustomData *src= em ? &em->fdata : &me->fdata;
EditFace *efa= NULL;
unsigned i,j;
multires_load_old_faces(fmap + 1, emap + 1, lvl->next, vvmap, dst - st2 * st3 + st3,
emid14, emid24, fmid, v4, st2, st3 / 2);
if(!CustomData_has_layer(src, CD_MCOL) && !CustomData_has_layer(src, CD_MTFACE)) return;
multires_load_old_faces(fmap + 1, emap + 1, lvl->next, vvmap, dst + st2 * st3 - st3,
emid13, emid23, v3, fmid, st2, st3 / 2);
/* Add texcol data */
for(cur= me->mr->levels.first; cur; cur= cur->next)
if(!cur->colfaces)
cur->colfaces= MEM_callocN(sizeof(MultiresColFace)*cur->totface,"ColFaces");
multires_load_old_faces(fmap + 1, emap + 1, lvl->next, vvmap, dst - st2 * st3 - st3,
v1, fmid, emid13, emid14, st2, st3 / 2);
me->mr->use_col= CustomData_has_layer(src, CD_MCOL);
if(em) efa= em->faces.first;
for(i=0; i<lvl->totface; ++i) {
MultiresColFace *f= &lvl->colfaces[i];
if(me->mr->use_col)
mcol_to_multires(f, em ? CustomData_em_get(src, efa->data, CD_MCOL) : &me->mcol[i*4]);
if(em) efa= efa->next;
}
/* Update higher levels */
lvl= lvl->next;
while(lvl) {
MultiresColFace *cf= lvl->colfaces;
for(i=0; i<lvl->prev->totface; ++i) {
const char sides= lvl->prev->faces[i].v[3]?4:3;
MultiresCol cntr;
/* Find average color of 4 (or 3 for triangle) verts */
multires_col_avg(&cntr,lvl->prev->colfaces[i].col,sides);
for(j=0; j<sides; ++j) {
MultiresColFace *pf= &lvl->prev->colfaces[i];
multires_col_avg2(&cf->col[0],
&pf->col[j],
&pf->col[j==0?sides-1:j-1]);
cf->col[1]= pf->col[j];
multires_col_avg2(&cf->col[2],
&pf->col[j],
&pf->col[j==sides-1?0:j+1]);
cf->col[3]= cntr;
++cf;
}
if(lvl->next->next) {
multires_load_old_edges(emap, lvl->next, vvmap, dst, emid24, fmid, st3);
multires_load_old_edges(emap, lvl->next, vvmap, dst, emid13, fmid, -st3);
multires_load_old_edges(emap, lvl->next, vvmap, dst, emid14, fmid, -st2 * st3);
multires_load_old_edges(emap, lvl->next, vvmap, dst, emid23, fmid, st2 * st3);
}
lvl= lvl->next;
}
/* Update lower levels */
lvl= me->mr->levels.last;
lvl= lvl->prev;
while(lvl) {
unsigned curf= 0;
for(i=0; i<lvl->totface; ++i) {
MultiresFace *f= &lvl->faces[i];
for(j=0; j<(f->v[3]?4:3); ++j) {
lvl->colfaces[i].col[j]= lvl->next->colfaces[curf].col[1];
++curf;
}
}
lvl= lvl->prev;
}
}
void multires_create(Object *ob, Mesh *me)
/* Loads a multires object stored in the old Multires struct into the new format */
void multires_load_old(DerivedMesh *dm, Multires *mr)
{
MultiresLevel *lvl;
EditMesh *em= me->edit_mesh;
EditVert *eve= NULL;
EditFace *efa= NULL;
EditEdge *eed= NULL;
int i;
lvl= MEM_callocN(sizeof(MultiresLevel), "multires level");
MultiresLevel *lvl, *lvl1;
MVert *vsrc, *vdst;
int src, dst;
int totlvl = MultiresDM_get_totlvl(dm);
int st = multires_side_tot[totlvl - 2] - 1;
int extedgelen = multires_side_tot[totlvl - 1] - 2;
int *vvmap; // inorder for dst, map to src
int crossedgelen;
int i, j, s, x, totvert, tottri, totquad;
if(me->pv) mesh_pmv_off(ob, me);
src = 0;
dst = 0;
vsrc = mr->verts;
vdst = CDDM_get_verts(dm);
totvert = dm->getNumVerts(dm);
vvmap = MEM_callocN(sizeof(int) * totvert, "multires vvmap");
me->mr= MEM_callocN(sizeof(Multires), "multires data");
BLI_addtail(&me->mr->levels,lvl);
me->mr->current= 1;
me->mr->level_count= 1;
me->mr->edgelvl= 1;
me->mr->pinlvl= 1;
me->mr->renderlvl= 1;
/* Load mesh (or editmesh) into multires data */
/* Load vertices and vdata (MDeformVerts) */
lvl->totvert= em ? BLI_countlist(&em->verts) : me->totvert;
me->mr->verts= MEM_callocN(sizeof(MVert)*lvl->totvert,"multires verts");
multires_update_customdata(me->mr->levels.first, em, em ? &em->vdata : &me->vdata,
&me->mr->vdata, CD_MDEFORMVERT);
if(em) eve= em->verts.first;
for(i=0; i<lvl->totvert; ++i) {
multires_get_vert(&me->mr->verts[i], eve, &me->mvert[i], i);
if(em) eve= eve->next;
lvl1 = mr->levels.first;
/* Load base verts */
for(i = 0; i < lvl1->totvert; ++i) {
vvmap[totvert - lvl1->totvert + i] = src;
++src;
}
/* Load faces and fdata (MTFaces) */
lvl->totface= em ? BLI_countlist(&em->faces) : me->totface;
lvl->faces= MEM_callocN(sizeof(MultiresFace)*lvl->totface,"multires faces");
multires_update_customdata(me->mr->levels.first, em, em ? &em->fdata : &me->fdata,
&me->mr->fdata, CD_MTFACE);
if(em) efa= em->faces.first;
for(i=0; i<lvl->totface; ++i) {
multires_get_face(&lvl->faces[i], &me->mr->fdata, i, efa, &me->mface[i]);
if(em) efa= efa->next;
}
/* Original edges */
dst = totvert - lvl1->totvert - extedgelen * lvl1->totedge;
for(i = 0; i < lvl1->totedge; ++i) {
int ldst = dst + extedgelen * i;
int lsrc = src;
lvl = lvl1->next;
/* Load edges and edge_flags */
lvl->totedge= em ? BLI_countlist(&em->edges) : me->totedge;
lvl->edges= MEM_callocN(sizeof(MultiresEdge)*lvl->totedge,"multires edges");
me->mr->edge_flags= MEM_callocN(sizeof(short)*lvl->totedge, "multires edge flags");
me->mr->edge_creases= MEM_callocN(sizeof(short)*lvl->totedge, "multires edge creases");
if(em) eed= em->edges.first;
for(i=0; i<lvl->totedge; ++i) {
multires_get_edge(&lvl->edges[i], eed, &me->medge[i], &me->mr->edge_flags[i], &me->mr->edge_creases[i]);
if(em) eed= eed->next;
}
for(j = 2; j <= mr->level_count; ++j) {
int base = multires_side_tot[totlvl - j] - 2;
int skip = multires_side_tot[totlvl - j + 1] - 1;
int st = multires_side_tot[j - 2] - 1;
multires_load_cols(me);
}
for(x = 0; x < st; ++x)
vvmap[ldst + base + x * skip] = lsrc + st * i + x;
typedef struct MultiresMapNode {
struct MultiresMapNode *next, *prev;
unsigned Index;
} MultiresMapNode;
/* Produces temporary connectivity data for the multires lvl */
static void multires_calc_temp_data(MultiresLevel *lvl)
{
unsigned i, j, emax;
MultiresMapNode *indexnode= NULL;
lvl->map_mem= MEM_mallocN(sizeof(MultiresMapNode)*(lvl->totedge*2 + lvl->totface*4), "map_mem");
indexnode= lvl->map_mem;
/* edge map */
lvl->vert_edge_map= MEM_callocN(sizeof(ListBase)*lvl->totvert,"vert_edge_map");
for(i=0; i<lvl->totedge; ++i) {
for(j=0; j<2; ++j, ++indexnode) {
indexnode->Index= i;
BLI_addtail(&lvl->vert_edge_map[lvl->edges[i].v[j]], indexnode);
lsrc += lvl->totvert - lvl->prev->totvert;
lvl = lvl->next;
}
}
/* face map */
lvl->vert_face_map= MEM_callocN(sizeof(ListBase)*lvl->totvert,"vert_face_map");
for(i=0; i<lvl->totface; ++i){
for(j=0; j<(lvl->faces[i].v[3]?4:3); ++j, ++indexnode) {
indexnode->Index= i;
BLI_addtail(&lvl->vert_face_map[lvl->faces[i].v[j]], indexnode);
}
/* Center points */
dst = 0;
for(i = 0; i < lvl1->totface; ++i) {
int sides = lvl1->faces[i].v[3] ? 4 : 3;
vvmap[dst] = src + lvl1->totedge + i;
dst += 1 + sides * (st - 1) * st;
}
/* edge boundaries */
emax = (lvl->prev ? (lvl->prev->totedge * 2) : lvl->totedge);
lvl->edge_boundary_states= MEM_callocN(sizeof(char)*lvl->totedge, "edge_boundary_states");
for(i=0; i<emax; ++i) {
MultiresMapNode *n1= lvl->vert_face_map[lvl->edges[i].v[0]].first;
unsigned total= 0;
lvl->edge_boundary_states[i] = 1;
while(n1 && lvl->edge_boundary_states[i] == 1) {
MultiresMapNode *n2= lvl->vert_face_map[lvl->edges[i].v[1]].first;
while(n2) {
if(n1->Index == n2->Index) {
++total;
if(total > 1) {
lvl->edge_boundary_states[i] = 0;
break;
/* The rest is only for level 3 and up */
if(lvl1->next && lvl1->next->next) {
ListBase **fmap, **emap;
IndexNode **fmem, **emem;
/* Face edge cross */
tottri = totquad = 0;
crossedgelen = multires_side_tot[totlvl - 2] - 2;
dst = 0;
for(i = 0; i < lvl1->totface; ++i) {
int sides = lvl1->faces[i].v[3] ? 4 : 3;
lvl = lvl1->next->next;
++dst;
for(j = 3; j <= mr->level_count; ++j) {
int base = multires_side_tot[totlvl - j] - 2;
int skip = multires_side_tot[totlvl - j + 1] - 1;
int st = pow(2, j - 2);
int st2 = pow(2, j - 3);
int lsrc = lvl->prev->totvert;
/* Skip exterior edge verts */
lsrc += lvl1->totedge * st;
/* Skip earlier face edge crosses */
lsrc += st2 * (tottri * 3 + totquad * 4);
for(s = 0; s < sides; ++s) {
for(x = 0; x < st2; ++x) {
vvmap[dst + crossedgelen * (s + 1) - base - x * skip - 1] = lsrc;
++lsrc;
}
}
n2= n2->next;
}
n1= n1->next;
}
}
}
/* CATMULL-CLARK
============= */
typedef struct MultiApplyData {
/* Smooth faces */
float *corner1, *corner2, *corner3, *corner4;
char quad;
/* Smooth edges */
char boundary;
float edge_face_neighbor_midpoints_accum[3];
unsigned edge_face_neighbor_midpoints_total;
float *endpoint1, *endpoint2;
/* Smooth verts */
/* uses 'char boundary' */
float *original;
int edge_count;
float vert_face_neighbor_midpoints_average[3];
float vert_edge_neighbor_midpoints_average[3];
float boundary_edges_average[3];
} MultiApplyData;
/* Simply averages the four corners of a polygon. */
static float catmullclark_smooth_face(MultiApplyData *data, const unsigned i)
{
const float total= data->corner1[i]+data->corner2[i]+data->corner3[i];
return data->quad ? (total+data->corner4[i])/4 : total/3;
}
static float catmullclark_smooth_edge(MultiApplyData *data, const unsigned i)
{
float accum= 0;
unsigned count= 2;
accum+= data->endpoint1[i] + data->endpoint2[i];
if(!data->boundary) {
accum+= data->edge_face_neighbor_midpoints_accum[i];
count+= data->edge_face_neighbor_midpoints_total;
}
return accum / count;
}
static float catmullclark_smooth_vert(MultiApplyData *data, const unsigned i)
{
if(data->boundary) {
return data->original[i]*0.75 + data->boundary_edges_average[i]*0.25;
} else {
return (data->vert_face_neighbor_midpoints_average[i] +
2*data->vert_edge_neighbor_midpoints_average[i] +
data->original[i]*(data->edge_count-3))/data->edge_count;
}
}
/* Call func count times, passing in[i] as the input and storing the output in out[i] */
static void multi_apply(float *out, MultiApplyData *data,
const unsigned count, float (*func)(MultiApplyData *, const unsigned))
{
unsigned i;
for(i=0; i<count; ++i)
out[i]= func(data,i);
}
static short multires_vert_is_boundary(MultiresLevel *lvl, unsigned v)
{
MultiresMapNode *node= lvl->vert_edge_map[v].first;
while(node) {
if(lvl->edge_boundary_states[node->Index])
return 1;
node= node->next;
}
return 0;
}
#define GET_FLOAT(array, i, j, stride) (((float*)((char*)(array)+((i)*(stride))))[(j)])
static void edge_face_neighbor_midpoints_accum(MultiApplyData *data, MultiresLevel *lvl,
void *array, const char stride, const MultiresEdge *e)
{
ListBase *neighbors1= &lvl->vert_face_map[e->v[0]];
ListBase *neighbors2= &lvl->vert_face_map[e->v[1]];
MultiresMapNode *n1, *n2;
unsigned j,count= 0;
float *out= data->edge_face_neighbor_midpoints_accum;
out[0]=out[1]=out[2]= 0;
for(n1= neighbors1->first; n1; n1= n1->next) {
for(n2= neighbors2->first; n2; n2= n2->next) {
if(n1->Index == n2->Index) {
for(j=0; j<3; ++j)
out[j]+= GET_FLOAT(array,lvl->faces[n1->Index].mid,j,stride);
++count;
}
}
}
data->edge_face_neighbor_midpoints_total= count;
}
static void vert_face_neighbor_midpoints_average(MultiApplyData *data, MultiresLevel *lvl,
void *array, const char stride, const unsigned i)
{
ListBase *neighbors= &lvl->vert_face_map[i];
MultiresMapNode *n1;
unsigned j,count= 0;
float *out= data->vert_face_neighbor_midpoints_average;
out[0]=out[1]=out[2]= 0;
for(n1= neighbors->first; n1; n1= n1->next) {
for(j=0; j<3; ++j)
out[j]+= GET_FLOAT(array,lvl->faces[n1->Index].mid,j,stride);
++count;
}
for(j=0; j<3; ++j) out[j]/= count;
}
static void vert_edge_neighbor_midpoints_average(MultiApplyData *data, MultiresLevel *lvl,
void *array, const char stride, const unsigned i)
{
ListBase *neighbors= &lvl->vert_edge_map[i];
MultiresMapNode *n1;
unsigned j,count= 0;
float *out= data->vert_edge_neighbor_midpoints_average;
out[0]=out[1]=out[2]= 0;
for(n1= neighbors->first; n1; n1= n1->next) {
for(j=0; j<3; ++j)
out[j]+= (GET_FLOAT(array,lvl->edges[n1->Index].v[0],j,stride) +
GET_FLOAT(array,lvl->edges[n1->Index].v[1],j,stride)) / 2;
++count;
}
for(j=0; j<3; ++j) out[j]/= count;
}
static void boundary_edges_average(MultiApplyData *data, MultiresLevel *lvl,
void *array, const char stride, const unsigned i)
{
ListBase *neighbors= &lvl->vert_edge_map[i];
MultiresMapNode *n1;
unsigned j,count= 0;
float *out= data->boundary_edges_average;
out[0]=out[1]=out[2]= 0;
for(n1= neighbors->first; n1; n1= n1->next) {
const MultiresEdge *e= &lvl->edges[n1->Index];
const unsigned end= e->v[0]==i ? e->v[1] : e->v[0];
if(lvl->edge_boundary_states[n1->Index]) {
for(j=0; j<3; ++j)
out[j]+= GET_FLOAT(array,end,j,stride);
++count;
}
}
for(j=0; j<3; ++j) out[j]/= count;
}
/* END CATMULL-CLARK
================= */
/* Update vertex locations and vertex flags */
static void multires_update_vertices(Mesh *me, EditMesh *em)
{
MultiresLevel *cr_lvl= current_level(me->mr), *pr_lvl= NULL,
*last_lvl= me->mr->levels.last;
vec3f *pr_deltas= NULL, *cr_deltas= NULL, *swap_deltas= NULL;
EditVert *eve= NULL;
MultiApplyData data;
int i, j;
/* XXX added this to prevent crash, but if it works? (ton) */
if(me->mr->verts==NULL)
return;
/* Prepare deltas */
pr_deltas= MEM_callocN(sizeof(vec3f)*last_lvl->totvert, "multires deltas 1");
cr_deltas= MEM_callocN(sizeof(vec3f)*last_lvl->totvert, "multires deltas 2");
/* Calculate initial deltas -- current mesh subtracted from current level*/
if(em) eve= em->verts.first;
for(i=0; i<cr_lvl->totvert; ++i) {
if(em) {
VecSubf(&cr_deltas[i].x, eve->co, me->mr->verts[i].co);
eve= eve->next;
} else
VecSubf(&cr_deltas[i].x, me->mvert[i].co, me->mr->verts[i].co);
}
/* Copy current level's vertex flags and clear the rest */
if(em) eve= em->verts.first;
for(i=0; i < last_lvl->totvert; ++i) {
if(i < cr_lvl->totvert) {
MVert mvflag;
multires_get_vert(&mvflag, eve, &me->mvert[i], i);
if(em) eve= eve->next;
me->mr->verts[i].flag= mvflag.flag;
}
else
me->mr->verts[i].flag= 0;
}
/* If already on the highest level, copy current verts (including flags) into current level */
if(cr_lvl == last_lvl) {
if(em)
eve= em->verts.first;
for(i=0; i<cr_lvl->totvert; ++i) {
multires_get_vert(&me->mr->verts[i], eve, &me->mvert[i], i);
if(em) eve= eve->next;
}
}
/* Update higher levels */
pr_lvl= BLI_findlink(&me->mr->levels,me->mr->current-1);
cr_lvl= pr_lvl->next;
while(cr_lvl) {
multires_calc_temp_data(pr_lvl);
/* Swap the old/new deltas */
swap_deltas= pr_deltas;
pr_deltas= cr_deltas;
cr_deltas= swap_deltas;
/* Calculate and add new deltas
============================ */
for(i=0; i<pr_lvl->totface; ++i) {
const MultiresFace *f= &pr_lvl->faces[i];
data.corner1= &pr_deltas[f->v[0]].x;
data.corner2= &pr_deltas[f->v[1]].x;
data.corner3= &pr_deltas[f->v[2]].x;
data.corner4= &pr_deltas[f->v[3]].x;
data.quad= f->v[3] ? 1 : 0;
multi_apply(&cr_deltas[f->mid].x, &data, 3, catmullclark_smooth_face);
for(j=0; j<(data.quad?4:3); ++j)
me->mr->verts[f->mid].flag |= me->mr->verts[f->v[j]].flag;
}
for(i=0; i<pr_lvl->totedge; ++i) {
const MultiresEdge *e= &pr_lvl->edges[i];
data.boundary= pr_lvl->edge_boundary_states[i];
edge_face_neighbor_midpoints_accum(&data,pr_lvl,cr_deltas,sizeof(vec3f),e);
data.endpoint1= &pr_deltas[e->v[0]].x;
data.endpoint2= &pr_deltas[e->v[1]].x;
multi_apply(&cr_deltas[e->mid].x, &data, 3, catmullclark_smooth_edge);
for(j=0; j<2; ++j)
me->mr->verts[e->mid].flag |= me->mr->verts[e->v[j]].flag;
}
for(i=0; i<pr_lvl->totvert; ++i) {
data.boundary= multires_vert_is_boundary(pr_lvl,i);
data.original= &pr_deltas[i].x;
data.edge_count= BLI_countlist(&pr_lvl->vert_edge_map[i]);
if(data.boundary)
boundary_edges_average(&data,pr_lvl,pr_deltas,sizeof(vec3f),i);
else {
vert_face_neighbor_midpoints_average(&data,pr_lvl,cr_deltas,sizeof(vec3f),i);
vert_edge_neighbor_midpoints_average(&data,pr_lvl,pr_deltas,sizeof(vec3f),i);
}
multi_apply(&cr_deltas[i].x, &data, 3, catmullclark_smooth_vert);
}
/* Apply deltas to vertex locations */
for(i=0; (cr_lvl == last_lvl) && (i < cr_lvl->totvert); ++i) {
VecAddf(me->mr->verts[i].co,
me->mr->verts[i].co,
&cr_deltas[i].x);
}
multires_free_temp_data(pr_lvl);
pr_lvl= pr_lvl->next;
cr_lvl= cr_lvl->next;
}
if(pr_deltas) MEM_freeN(pr_deltas);
if(cr_deltas) MEM_freeN(cr_deltas);
}
static void multires_update_faces(Mesh *me, EditMesh *em)
{
MultiresLevel *cr_lvl= current_level(me->mr), *pr_lvl= NULL,
*last_lvl= me->mr->levels.last;
char *pr_flag_damaged= NULL, *cr_flag_damaged= NULL, *or_flag_damaged= NULL,
*pr_mat_damaged= NULL, *cr_mat_damaged= NULL, *or_mat_damaged= NULL, *swap= NULL;
EditFace *efa= NULL;
unsigned i,j,curf;
/* Find for each face whether flag/mat has changed */
pr_flag_damaged= MEM_callocN(sizeof(char) * last_lvl->totface, "flag_damaged 1");
cr_flag_damaged= MEM_callocN(sizeof(char) * last_lvl->totface, "flag_damaged 1");
pr_mat_damaged= MEM_callocN(sizeof(char) * last_lvl->totface, "mat_damaged 1");
cr_mat_damaged= MEM_callocN(sizeof(char) * last_lvl->totface, "mat_damaged 1");
if(em) efa= em->faces.first;
for(i=0; i<cr_lvl->totface; ++i) {
MultiresFace mftmp;
multires_get_face(&mftmp, &me->mr->fdata, i, efa, &me->mface[i]);
if(cr_lvl->faces[i].flag != mftmp.flag)
cr_flag_damaged[i]= 1;
if(cr_lvl->faces[i].mat_nr != mftmp.mat_nr)
cr_mat_damaged[i]= 1;
/* Update current level */
cr_lvl->faces[i].flag= mftmp.flag;
cr_lvl->faces[i].mat_nr= mftmp.mat_nr;
if(em) efa= efa->next;
}
or_flag_damaged= MEM_dupallocN(cr_flag_damaged);
or_mat_damaged= MEM_dupallocN(cr_mat_damaged);
/* Update lower levels */
cr_lvl= cr_lvl->prev;
while(cr_lvl) {
swap= pr_flag_damaged;
pr_flag_damaged= cr_flag_damaged;
cr_flag_damaged= swap;
swap= pr_mat_damaged;
pr_mat_damaged= cr_mat_damaged;
cr_mat_damaged= swap;
curf= 0;
for(i=0; i<cr_lvl->totface; ++i) {
const int sides= cr_lvl->faces[i].v[3] ? 4 : 3;
/* Check damages */
for(j=0; j<sides; ++j, ++curf) {
if(pr_flag_damaged[curf]) {
cr_lvl->faces[i].flag= cr_lvl->next->faces[curf].flag;
cr_flag_damaged[i]= 1;
}
if(pr_mat_damaged[curf]) {
cr_lvl->faces[i].mat_nr= cr_lvl->next->faces[curf].mat_nr;
cr_mat_damaged[i]= 1;
}
}
}
cr_lvl= cr_lvl->prev;
}
/* Clear to original damages */
if(cr_flag_damaged) MEM_freeN(cr_flag_damaged);
if(cr_mat_damaged) MEM_freeN(cr_mat_damaged);
cr_flag_damaged= or_flag_damaged;
cr_mat_damaged= or_mat_damaged;
/* Update higher levels */
pr_lvl= current_level(me->mr);
cr_lvl= pr_lvl->next;
while(cr_lvl) {
swap= pr_flag_damaged;
pr_flag_damaged= cr_flag_damaged;
cr_flag_damaged= swap;
swap= pr_mat_damaged;
pr_mat_damaged= cr_mat_damaged;
cr_mat_damaged= swap;
/* Update faces */
for(i=0, curf= 0; i<pr_lvl->totface; ++i) {
const int sides= cr_lvl->prev->faces[i].v[3] ? 4 : 3;
for(j=0; j<sides; ++j, ++curf) {
if(pr_flag_damaged[i]) {
cr_lvl->faces[curf].flag= pr_lvl->faces[i].flag;
cr_flag_damaged[curf]= 1;
}
if(pr_mat_damaged[i]) {
cr_lvl->faces[curf].mat_nr= pr_lvl->faces[i].mat_nr;
cr_mat_damaged[curf]= 1;
}
}
}
pr_lvl= pr_lvl->next;
cr_lvl= cr_lvl->next;
}
if(pr_flag_damaged) MEM_freeN(pr_flag_damaged);
if(cr_flag_damaged) MEM_freeN(cr_flag_damaged);
if(pr_mat_damaged) MEM_freeN(pr_mat_damaged);
if(cr_mat_damaged) MEM_freeN(cr_mat_damaged);
}
static void multires_update_colors(Mesh *me, EditMesh *em)
{
MultiresLevel *lvl= BLI_findlink(&me->mr->levels,me->mr->current-1);
MultiresCol *pr_deltas= NULL, *cr_deltas= NULL;
CustomData *src= em ? &em->fdata : &me->fdata;
EditFace *efa= NULL;
unsigned i,j,curf= 0;
if(me->mr->use_col) {
/* Calc initial deltas */
cr_deltas= MEM_callocN(sizeof(MultiresCol)*lvl->totface*4,"initial color/uv deltas");
if(em) efa= em->faces.first;
for(i=0; i<lvl->totface; ++i) {
MCol *col= em ? CustomData_em_get(src, efa->data, CD_MCOL) : &me->mcol[i*4];
for(j=0; j<4; ++j) {
if(me->mr->use_col) {
cr_deltas[i*4+j].a= col[j].a - lvl->colfaces[i].col[j].a;
cr_deltas[i*4+j].r= col[j].r - lvl->colfaces[i].col[j].r;
cr_deltas[i*4+j].g= col[j].g - lvl->colfaces[i].col[j].g;
cr_deltas[i*4+j].b= col[j].b - lvl->colfaces[i].col[j].b;
}
}
if(em) efa= efa->next;
}
/* Update current level */
if(em) efa= em->faces.first;
for(i=0; i<lvl->totface; ++i) {
MultiresColFace *f= &lvl->colfaces[i];
if(me->mr->use_col)
mcol_to_multires(f, em ? CustomData_em_get(src, efa->data, CD_MCOL) : &me->mcol[i*4]);
if(em) efa= efa->next;
}
/* Update higher levels */
lvl= lvl->next;
while(lvl) {
/* Set up new deltas, but keep the ones from the previous level */
if(pr_deltas) MEM_freeN(pr_deltas);
pr_deltas= cr_deltas;
cr_deltas= MEM_callocN(sizeof(MultiresCol)*lvl->totface*4,"color deltas");
curf= 0;
for(i=0; i<lvl->prev->totface; ++i) {
const char sides= lvl->prev->faces[i].v[3]?4:3;
MultiresCol cntr;
/* Find average color of 4 (or 3 for triangle) verts */
multires_col_avg(&cntr,&pr_deltas[i*4],sides);
for(j=0; j<sides; ++j) {
multires_col_avg2(&cr_deltas[curf*4],
&pr_deltas[i*4+j],
&pr_deltas[i*4+(j==0?sides-1:j-1)]);
cr_deltas[curf*4+1]= pr_deltas[i*4+j];
multires_col_avg2(&cr_deltas[curf*4+2],
&pr_deltas[i*4+j],
&pr_deltas[i*4+(j==sides-1?0:j+1)]);
cr_deltas[curf*4+3]= cntr;
++curf;
}
lvl = lvl->next;
}
for(i=0; i<lvl->totface; ++i) {
for(j=0; j<4; ++j) {
lvl->colfaces[i].col[j].a+= cr_deltas[i*4+j].a;
lvl->colfaces[i].col[j].r+= cr_deltas[i*4+j].r;
lvl->colfaces[i].col[j].g+= cr_deltas[i*4+j].g;
lvl->colfaces[i].col[j].b+= cr_deltas[i*4+j].b;
}
dst += sides * (st - 1) * st;
if(sides == 4) ++totquad;
else ++tottri;
}
/* calculate vert to edge/face maps for each level (except the last) */
fmap = MEM_callocN(sizeof(ListBase*) * (mr->level_count-1), "multires fmap");
emap = MEM_callocN(sizeof(ListBase*) * (mr->level_count-1), "multires emap");
fmem = MEM_callocN(sizeof(IndexNode*) * (mr->level_count-1), "multires fmem");
emem = MEM_callocN(sizeof(IndexNode*) * (mr->level_count-1), "multires emem");
lvl = lvl1;
for(i = 0; i < mr->level_count - 1; ++i) {
create_old_vert_face_map(fmap + i, fmem + i, lvl->faces, lvl->totvert, lvl->totface);
create_old_vert_edge_map(emap + i, emem + i, lvl->edges, lvl->totvert, lvl->totedge);
lvl = lvl->next;
}
/* Interior face verts */
lvl = lvl1->next->next;
dst = 0;
for(j = 0; j < lvl1->totface; ++j) {
int sides = lvl1->faces[j].v[3] ? 4 : 3;
int ldst = dst + 1 + sides * (st - 1);
for(s = 0; s < sides; ++s) {
int st2 = multires_side_tot[totlvl - 2] - 2;
int st3 = multires_side_tot[totlvl - 3] - 2;
int st4 = st3 == 0 ? 1 : (st3 + 1) / 2;
int mid = ldst + st2 * st3 + st3;
int cv = lvl1->faces[j].v[s];
int nv = lvl1->faces[j].v[s == sides - 1 ? 0 : s + 1];
int pv = lvl1->faces[j].v[s == 0 ? sides - 1 : s - 1];
multires_load_old_faces(fmap, emap, lvl1->next, vvmap, mid,
vvmap[dst], cv,
find_old_edge(emap[0], lvl1->edges, pv, cv)->mid,
find_old_edge(emap[0], lvl1->edges, cv, nv)->mid,
st2, st4);
ldst += (st - 1) * (st - 1);
}
lvl= lvl->next;
dst = ldst;
}
if(pr_deltas) MEM_freeN(pr_deltas);
if(cr_deltas) MEM_freeN(cr_deltas);
/* Update lower levels */
lvl= me->mr->levels.last;
lvl= lvl->prev;
while(lvl) {
MultiresColFace *nf= lvl->next->colfaces;
for(i=0; i<lvl->totface; ++i) {
MultiresFace *f= &lvl->faces[i];
for(j=0; j<(f->v[3]?4:3); ++j) {
lvl->colfaces[i].col[j]= nf->col[1];
++nf;
}
}
lvl= lvl->prev;
lvl = lvl->next;
for(i = 0; i < mr->level_count - 1; ++i) {
MEM_freeN(fmap[i]);
MEM_freeN(fmem[i]);
MEM_freeN(emap[i]);
MEM_freeN(emem[i]);
}
MEM_freeN(fmap);
MEM_freeN(emap);
MEM_freeN(fmem);
MEM_freeN(emem);
}
}
void multires_update_levels(Mesh *me, const int render)
{
EditMesh *em= render ? NULL : me->edit_mesh;
multires_update_first_level(me, em);
multires_update_vertices(me, em);
multires_update_faces(me, em);
multires_update_colors(me, em);
}
static void check_colors(Mesh *me)
{
CustomData *src= me->edit_mesh ? &me->edit_mesh->fdata : &me->fdata;
const char col= CustomData_has_layer(src, CD_MCOL);
/* Check if vertex colors have been deleted or added */
if(me->mr->use_col && !col)
me->mr->use_col= 0;
else if(!me->mr->use_col && col) {
me->mr->use_col= 1;
multires_load_cols(me);
}
}
static unsigned int find_mid_edge(ListBase *vert_edge_map,
MultiresLevel *lvl,
const unsigned int v1,
const unsigned int v2 )
{
MultiresMapNode *n= vert_edge_map[v1].first;
while(n) {
if(lvl->edges[n->Index].v[0]==v2 ||
lvl->edges[n->Index].v[1]==v2)
return lvl->edges[n->Index].mid;
n= n->next;
}
return -1;
}
static float clamp_component(const float c)
{
if(c<0) return 0;
else if(c>255) return 255;
else return c;
}
void multires_to_mcol(MultiresColFace *f, MCol mcol[4])
{
unsigned char j;
for(j=0; j<4; ++j) {
mcol->a= clamp_component(f->col[j].a);
mcol->r= clamp_component(f->col[j].r);
mcol->g= clamp_component(f->col[j].g);
mcol->b= clamp_component(f->col[j].b);
++mcol;
}
}
void multires_level_to_mesh(Object *ob, Mesh *me, const int render)
{
MultiresLevel *lvl= BLI_findlink(&me->mr->levels,me->mr->current-1);
EditMesh *em= render ? NULL : me->edit_mesh;
int i;
if(em)
return;
CustomData_free_layer_active(&me->vdata, CD_MVERT, me->totvert);
CustomData_free_layer_active(&me->edata, CD_MEDGE, me->totedge);
CustomData_free_layer_active(&me->fdata, CD_MFACE, me->totface);
CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
CustomData_free_layers(&me->fdata, CD_MTFACE, me->totface);
CustomData_free_layers(&me->fdata, CD_MCOL, me->totface);
me->totvert= lvl->totvert;
me->totface= lvl->totface;
me->totedge= lvl->totedge;
CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert);
CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, NULL, me->totedge);
CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, me->totface);
mesh_update_customdata_pointers(me);
/* Vertices/Edges/Faces */
for(i=0; i<lvl->totvert; ++i) {
me->mvert[i]= me->mr->verts[i];
}
for(i=0; i<lvl->totedge; ++i) {
me->medge[i].v1= lvl->edges[i].v[0];
me->medge[i].v2= lvl->edges[i].v[1];
me->medge[i].flag &= ~ME_HIDE;
}
for(i=0; i<lvl->totface; ++i) {
me->mface[i].v1= lvl->faces[i].v[0];
me->mface[i].v2= lvl->faces[i].v[1];
me->mface[i].v3= lvl->faces[i].v[2];
me->mface[i].v4= lvl->faces[i].v[3];
me->mface[i].flag= lvl->faces[i].flag;
me->mface[i].flag &= ~ME_HIDE;
me->mface[i].mat_nr= lvl->faces[i].mat_nr;
}
/* Edge flags */
if(lvl==me->mr->levels.first) {
for(i=0; i<lvl->totedge; ++i) {
me->medge[i].flag= me->mr->edge_flags[i];
me->medge[i].crease= me->mr->edge_creases[i];
}
} else {
MultiresLevel *lvl1= me->mr->levels.first;
const int last= lvl1->totedge * pow(2, me->mr->current-1);
for(i=0; i<last; ++i) {
const int ndx= i / pow(2, me->mr->current-1);
me->medge[i].flag= me->mr->edge_flags[ndx];
me->medge[i].crease= me->mr->edge_creases[ndx];
}
}
multires_customdata_to_mesh(me, em, lvl, &me->mr->vdata, em ? &em->vdata : &me->vdata, CD_MDEFORMVERT);
multires_customdata_to_mesh(me, em, lvl, &me->mr->fdata, em ? &em->fdata : &me->fdata, CD_MTFACE);
/* Colors */
if(me->mr->use_col) {
CustomData *src= &me->fdata;
if(me->mr->use_col) me->mcol= CustomData_add_layer(src, CD_MCOL, CD_CALLOC, NULL, me->totface);
for(i=0; i<lvl->totface; ++i) {
if(me->mr->use_col)
multires_to_mcol(&lvl->colfaces[i], &me->mcol[i*4]);
}
}
mesh_update_customdata_pointers(me);
multires_edge_level_update(ob,me);
// XXX do this in caller DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
}
void multires_add_level(Object *ob, Mesh *me, const char subdiv_type)
{
int i,j, curf, cure;
MultiresLevel *lvl= NULL;
MultiApplyData data;
MVert *oldverts= NULL;
lvl= MEM_callocN(sizeof(MultiresLevel), "multireslevel");
if(me->pv) mesh_pmv_off(ob, me);
check_colors(me);
multires_update_levels(me, 0);
++me->mr->level_count;
BLI_addtail(&me->mr->levels,lvl);
/* Create vertices
=============== */
lvl->totvert= lvl->prev->totvert + lvl->prev->totedge + lvl->prev->totface;
oldverts= me->mr->verts;
me->mr->verts= MEM_callocN(sizeof(MVert)*lvl->totvert, "multitres verts");
/* Copy old verts */
for(i=0; i<lvl->prev->totvert; ++i)
me->mr->verts[i]= oldverts[i];
/* Create new edge verts */
for(i=0; i<lvl->prev->totedge; ++i) {
VecMidf(me->mr->verts[lvl->prev->totvert + i].co,
oldverts[lvl->prev->edges[i].v[0]].co,
oldverts[lvl->prev->edges[i].v[1]].co);
lvl->prev->edges[i].mid= lvl->prev->totvert + i;
}
/* Create new face verts */
for(i=0; i<lvl->prev->totface; ++i) {
lvl->prev->faces[i].mid= lvl->prev->totvert + lvl->prev->totedge + i;
}
multires_calc_temp_data(lvl->prev);
/* Create faces
============ */
/* Allocate all the new faces (each triangle creates three, and
each quad creates four */
lvl->totface= 0;
for(i=0; i<lvl->prev->totface; ++i)
lvl->totface+= lvl->prev->faces[i].v[3] ? 4 : 3;
lvl->faces= MEM_callocN(sizeof(MultiresFace)*lvl->totface,"multires faces");
curf= 0;
for(i=0; i<lvl->prev->totface; ++i) {
const int max= lvl->prev->faces[i].v[3] ? 3 : 2;
for(j=0; j<max+1; ++j) {
lvl->faces[curf].v[0]= find_mid_edge(lvl->prev->vert_edge_map,lvl->prev,
lvl->prev->faces[i].v[j],
lvl->prev->faces[i].v[j==0?max:j-1]);
lvl->faces[curf].v[1]= lvl->prev->faces[i].v[j];
lvl->faces[curf].v[2]= find_mid_edge(lvl->prev->vert_edge_map,lvl->prev,
lvl->prev->faces[i].v[j],
lvl->prev->faces[i].v[j==max?0:j+1]);
lvl->faces[curf].v[3]= lvl->prev->totvert + lvl->prev->totedge + i;
lvl->faces[curf].flag= lvl->prev->faces[i].flag;
lvl->faces[curf].mat_nr= lvl->prev->faces[i].mat_nr;
++curf;
}
}
/* Create edges
============ */
/* Figure out how many edges to allocate */
lvl->totedge= lvl->prev->totedge*2;
for(i=0; i<lvl->prev->totface; ++i)
lvl->totedge+= lvl->prev->faces[i].v[3]?4:3;
lvl->edges= MEM_callocN(sizeof(MultiresEdge)*lvl->totedge,"multires edges");
for(i=0; i<lvl->prev->totedge; ++i) {
lvl->edges[i*2].v[0]= lvl->prev->edges[i].v[0];
lvl->edges[i*2].v[1]= lvl->prev->edges[i].mid;
lvl->edges[i*2+1].v[0]= lvl->prev->edges[i].mid;
lvl->edges[i*2+1].v[1]= lvl->prev->edges[i].v[1];
}
/* Add edges inside of old polygons */
curf= 0;
cure= lvl->prev->totedge*2;
for(i=0; i<lvl->prev->totface; ++i) {
for(j=0; j<(lvl->prev->faces[i].v[3]?4:3); ++j) {
lvl->edges[cure].v[0]= lvl->faces[curf].v[2];
lvl->edges[cure].v[1]= lvl->faces[curf].v[3];
++cure;
++curf;
}
}
/* Smooth vertices
=============== */
for(i=0; i<lvl->prev->totface; ++i) {
const MultiresFace *f= &lvl->prev->faces[i];
data.corner1= oldverts[f->v[0]].co;
data.corner2= oldverts[f->v[1]].co;
data.corner3= oldverts[f->v[2]].co;
data.corner4= oldverts[f->v[3]].co;
data.quad= f->v[3] ? 1 : 0;
multi_apply(me->mr->verts[f->mid].co, &data, 3, catmullclark_smooth_face);
}
if(subdiv_type == 0) {
for(i=0; i<lvl->prev->totedge; ++i) {
const MultiresEdge *e= &lvl->prev->edges[i];
data.boundary= lvl->prev->edge_boundary_states[i];
edge_face_neighbor_midpoints_accum(&data,lvl->prev, me->mr->verts, sizeof(MVert),e);
data.endpoint1= oldverts[e->v[0]].co;
data.endpoint2= oldverts[e->v[1]].co;
multi_apply(me->mr->verts[e->mid].co, &data, 3, catmullclark_smooth_edge);
}
for(i=0; i<lvl->prev->totvert; ++i) {
data.boundary= multires_vert_is_boundary(lvl->prev,i);
data.original= oldverts[i].co;
data.edge_count= BLI_countlist(&lvl->prev->vert_edge_map[i]);
if(data.boundary)
boundary_edges_average(&data,lvl->prev, oldverts, sizeof(MVert),i);
else {
vert_face_neighbor_midpoints_average(&data,lvl->prev, me->mr->verts,
sizeof(MVert),i);
vert_edge_neighbor_midpoints_average(&data,lvl->prev, oldverts,
sizeof(MVert),i);
}
multi_apply(me->mr->verts[i].co, &data, 3, catmullclark_smooth_vert);
}
}
multires_free_temp_data(lvl->prev);
MEM_freeN(oldverts);
/* Vertex Colors
============= */
curf= 0;
if(me->mr->use_col) {
MultiresColFace *cf= MEM_callocN(sizeof(MultiresColFace)*lvl->totface,"Multirescolfaces");
lvl->colfaces= cf;
for(i=0; i<lvl->prev->totface; ++i) {
const char sides= lvl->prev->faces[i].v[3]?4:3;
MultiresCol cntr;
/* Find average color of 4 (or 3 for triangle) verts */
multires_col_avg(&cntr,lvl->prev->colfaces[i].col,sides);
for(j=0; j<sides; ++j) {
multires_col_avg2(&cf->col[0],
&lvl->prev->colfaces[i].col[j],
&lvl->prev->colfaces[i].col[j==0?sides-1:j-1]);
cf->col[1]= lvl->prev->colfaces[i].col[j];
multires_col_avg2(&cf->col[2],
&lvl->prev->colfaces[i].col[j],
&lvl->prev->colfaces[i].col[j==sides-1?0:j+1]);
cf->col[3]= cntr;
++cf;
}
}
}
me->mr->newlvl= me->mr->level_count;
me->mr->current= me->mr->newlvl;
/* Unless the render level has been set to something other than the
highest level (by the user), increment the render level to match
the highest available level */
if(me->mr->renderlvl == me->mr->level_count - 1) me->mr->renderlvl= me->mr->level_count;
multires_level_to_mesh(ob, me, 0);
}
void multires_set_level(Object *ob, Mesh *me, const int render)
{
if(me->pv) mesh_pmv_off(ob, me);
check_colors(me);
multires_update_levels(me, render);
me->mr->current= me->mr->newlvl;
if(me->mr->current<1) me->mr->current= 1;
else if(me->mr->current>me->mr->level_count) me->mr->current= me->mr->level_count;
multires_level_to_mesh(ob, me, render);
}
/* Update the edge visibility flags to only show edges on or below the edgelvl */
void multires_edge_level_update(Object *ob, Mesh *me)
{
if(!me->edit_mesh) {
MultiresLevel *cr_lvl= BLI_findlink(&me->mr->levels,me->mr->current-1);
MultiresLevel *edge_lvl= BLI_findlink(&me->mr->levels,me->mr->edgelvl-1);
const int threshold= edge_lvl->totedge * pow(2, me->mr->current - me->mr->edgelvl);
unsigned i;
for(i=0; i<cr_lvl->totedge; ++i) {
const int ndx= me->pv ? me->pv->edge_map[i] : i;
if(ndx != -1) { /* -1= hidden edge */
if(me->mr->edgelvl >= me->mr->current || i<threshold)
me->medge[ndx].flag |= ME_EDGEDRAW | ME_EDGERENDER;
else
me->medge[ndx].flag &= ~ME_EDGEDRAW & ~ME_EDGERENDER;
}
}
// XXX do this in caller DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
}
/* Transfer verts */
for(i = 0; i < totvert; ++i)
VecCopyf(vdst[i].co, vsrc[vvmap[i]].co);
MEM_freeN(vvmap);
}

View File

@@ -707,7 +707,6 @@ void sculptsession_free(Scene *sce)
}
}
/* Default curve approximates 0.5 * (cos(pi * x) + 1), with 0 <= x <= 1 */
void sculpt_reset_curve(SculptData *sd)
{
CurveMap *cm = NULL;
@@ -719,21 +718,15 @@ void sculpt_reset_curve(SculptData *sd)
if(cm->curve)
MEM_freeN(cm->curve);
cm->curve= MEM_callocN(6*sizeof(CurveMapPoint), "curve points");
cm->curve= MEM_callocN(3*sizeof(CurveMapPoint), "curve points");
cm->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
cm->totpoint= 6;
cm->totpoint= 3;
cm->curve[0].x= 0;
cm->curve[0].y= 1;
cm->curve[1].x= 0.1;
cm->curve[1].y= 0.97553;
cm->curve[2].x= 0.3;
cm->curve[2].y= 0.79389;
cm->curve[3].x= 0.9;
cm->curve[3].y= 0.02447;
cm->curve[4].x= 0.7;
cm->curve[4].y= 0.20611;
cm->curve[5].x= 1;
cm->curve[5].y= 0;
cm->curve[1].x= 0.33;
cm->curve[1].y= 0.33;
cm->curve[2].x= 1;
cm->curve[2].y= 0;
curvemapping_changed(sd->cumap, 0);
}

View File

@@ -48,6 +48,7 @@
#include "BKE_utildefines.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
#include "BKE_multires.h"
#include "BKE_scene.h"
#include "BKE_subsurf.h"
@@ -471,7 +472,7 @@ static void calc_ss_weights(int gridFaces,
static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
int drawInteriorEdges, int useSubsurfUv,
DerivedMesh *dm)
DerivedMesh *dm, MultiresSubsurf *ms)
{
DerivedMesh *result;
int edgeSize = ccgSubSurf_getEdgeSize(ss);
@@ -524,14 +525,21 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
}
ccgFaceIterator_free(fi);
if(dm) {
result = CDDM_from_template(dm, ccgSubSurf_getNumFinalVerts(ss),
ccgSubSurf_getNumFinalEdges(ss),
ccgSubSurf_getNumFinalFaces(ss));
} else {
result = CDDM_new(ccgSubSurf_getNumFinalVerts(ss),
ccgSubSurf_getNumFinalEdges(ss),
ccgSubSurf_getNumFinalFaces(ss));
if(ms) {
result = MultiresDM_new(ms, dm, ccgSubSurf_getNumFinalVerts(ss),
ccgSubSurf_getNumFinalEdges(ss),
ccgSubSurf_getNumFinalFaces(ss));
}
else {
if(dm) {
result = CDDM_from_template(dm, ccgSubSurf_getNumFinalVerts(ss),
ccgSubSurf_getNumFinalEdges(ss),
ccgSubSurf_getNumFinalFaces(ss));
} else {
result = CDDM_new(ccgSubSurf_getNumFinalVerts(ss),
ccgSubSurf_getNumFinalEdges(ss),
ccgSubSurf_getNumFinalFaces(ss));
}
}
// load verts
@@ -557,11 +565,12 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
++mvert;
++origIndex;
i++;
for(S = 0; S < numVerts; S++) {
int prevS = (S - 1 + numVerts) % numVerts;
int nextS = (S + 1) % numVerts;
int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3;
for(x = 1; x < gridFaces; x++) {
float w[4];
w[prevS] = weight[x][0][0];
@@ -571,6 +580,7 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
DM_interp_vert_data(dm, result, vertIdx, w, numVerts, i);
VecCopyf(mvert->co,
ccgSubSurf_getFaceGridEdgeData(ss, f, S, x));
*origIndex = ORIGINDEX_NONE;
++mvert;
++origIndex;
@@ -582,6 +592,7 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
int prevS = (S - 1 + numVerts) % numVerts;
int nextS = (S + 1) % numVerts;
int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3;
for(y = 1; y < gridFaces; y++) {
for(x = 1; x < gridFaces; x++) {
float w[4];
@@ -2565,9 +2576,10 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
/***/
struct DerivedMesh *subsurf_make_derived_from_derived(
struct DerivedMesh *subsurf_make_derived_from_derived_with_multires(
struct DerivedMesh *dm,
struct SubsurfModifierData *smd,
struct MultiresSubsurf *ms,
int useRenderParams, float (*vertCos)[3],
int isFinalCalc, int editMode)
{
@@ -2599,7 +2611,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple);
result = ss_to_cdderivedmesh(ss, 0, drawInteriorEdges,
useSubsurfUv, dm);
useSubsurfUv, dm, ms);
ccgSubSurf_free(ss);
@@ -2630,7 +2642,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
return ss_to_cdderivedmesh(ss, 0, drawInteriorEdges,
useSubsurfUv, dm);
useSubsurfUv, dm, ms);
/*return (DerivedMesh *)getCCGDerivedMesh(smd->mCache,
drawInteriorEdges,
@@ -2650,7 +2662,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
useSubsurfUv, dm);*/
result = ss_to_cdderivedmesh(ss, 0, drawInteriorEdges,
useSubsurfUv, dm);
useSubsurfUv, dm, ms);
ccgSubSurf_free(ss);
@@ -2659,6 +2671,15 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
}
}
struct DerivedMesh *subsurf_make_derived_from_derived(
struct DerivedMesh *dm,
struct SubsurfModifierData *smd,
int useRenderParams, float (*vertCos)[3],
int isFinalCalc, int editMode)
{
return subsurf_make_derived_from_derived_with_multires(dm, smd, NULL, useRenderParams, vertCos, isFinalCalc, editMode);
}
void subsurf_calculate_limit_positions(Mesh *me, float (*positions_r)[3])
{
/* Finds the subsurf limit positions for the verts in a mesh

View File

@@ -125,6 +125,7 @@
#include "BKE_main.h" // for Main
#include "BKE_mesh.h" // for ME_ defines (patching)
#include "BKE_modifier.h"
#include "BKE_multires.h"
#include "BKE_node.h" // for tree type defines
#include "BKE_object.h"
#include "BKE_particle.h"
@@ -2803,6 +2804,19 @@ static void direct_link_dverts(FileData *fd, int count, MDeformVert *mdverts)
}
}
static void direct_link_mdisps(FileData *fd, int count, MDisps *mdisps)
{
if(mdisps) {
int i;
for(i = 0; i < count; ++i) {
mdisps[i].disps = newdataadr(fd, mdisps[i].disps);
if(!mdisps[i].disps)
mdisps[i].totdisp = 0;
}
}
}
static void direct_link_customdata(FileData *fd, CustomData *data, int count)
{
int i = 0;
@@ -2814,6 +2828,8 @@ static void direct_link_customdata(FileData *fd, CustomData *data, int count)
if (CustomData_verify_versions(data, i)) {
layer->data = newdataadr(fd, layer->data);
if(layer->type == CD_MDISPS)
direct_link_mdisps(fd, count, layer->data);
i++;
}
}
@@ -2866,11 +2882,6 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh)
direct_link_dverts(fd, lvl->totvert, CustomData_get(&mesh->mr->vdata, 0, CD_MDEFORMVERT));
direct_link_customdata(fd, &mesh->mr->fdata, lvl->totface);
if(mesh->mr->edge_flags)
mesh->mr->edge_flags= newdataadr(fd, mesh->mr->edge_flags);
if(mesh->mr->edge_creases)
mesh->mr->edge_creases= newdataadr(fd, mesh->mr->edge_creases);
if(!mesh->mr->edge_flags)
mesh->mr->edge_flags= MEM_callocN(sizeof(short)*lvl->totedge, "Multires Edge Flags");
if(!mesh->mr->edge_creases)
@@ -2883,9 +2894,6 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh)
lvl->faces= newdataadr(fd, lvl->faces);
lvl->edges= newdataadr(fd, lvl->edges);
lvl->colfaces= newdataadr(fd, lvl->colfaces);
lvl->edge_boundary_states= NULL;
lvl->vert_face_map = lvl->vert_edge_map = NULL;
lvl->map_mem= NULL;
}
}
@@ -3273,6 +3281,12 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
SWITCH_INT(mmd->dynverts[a])
}
}
else if (md->type==eModifierType_Multires) {
MultiresModifierData *mmd = (MultiresModifierData*) md;
mmd->undo_verts = newdataadr(fd, mmd->undo_verts);
mmd->undo_signal = !!mmd->undo_verts;
}
}
}
@@ -8491,8 +8505,78 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
strcpy(tx->nodetree->id.name, "NTTexture Nodetree");
}
}
/* TODO: should be moved into one of the version blocks once this branch moves to trunk and we can
bump the version (or sub-version.) */
{
Object *ob;
int i;
for(ob = main->object.first; ob; ob = ob->id.next) {
if(ob->type == OB_MESH) {
Mesh *me = newlibadr(fd, lib, ob->data);
void *olddata = ob->data;
ob->data = me;
if(me && me->mr) {
MultiresLevel *lvl;
ModifierData *md;
MultiresModifierData *mmd;
DerivedMesh *dm, *orig;
/* Load original level into the mesh */
lvl = me->mr->levels.first;
CustomData_free_layers(&me->vdata, CD_MVERT, lvl->totvert);
CustomData_free_layers(&me->edata, CD_MEDGE, lvl->totedge);
CustomData_free_layers(&me->fdata, CD_MFACE, lvl->totface);
me->totvert = lvl->totvert;
me->totedge = lvl->totedge;
me->totface = lvl->totface;
me->mvert = CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert);
me->medge = CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, NULL, me->totedge);
me->mface = CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, me->totface);
memcpy(me->mvert, me->mr->verts, sizeof(MVert) * me->totvert);
for(i = 0; i < me->totedge; ++i) {
me->medge[i].v1 = lvl->edges[i].v[0];
me->medge[i].v2 = lvl->edges[i].v[1];
}
for(i = 0; i < me->totface; ++i) {
me->mface[i].v1 = lvl->faces[i].v[0];
me->mface[i].v2 = lvl->faces[i].v[1];
me->mface[i].v3 = lvl->faces[i].v[2];
me->mface[i].v4 = lvl->faces[i].v[3];
}
/* Add a multires modifier to the object */
md = ob->modifiers.first;
while(md && modifierType_getInfo(md->type)->type == eModifierTypeType_OnlyDeform)
md = md->next;
mmd = (MultiresModifierData*)modifier_new(eModifierType_Multires);
BLI_insertlinkbefore(&ob->modifiers, md, mmd);
multiresModifier_subdivide(mmd, ob, me->mr->level_count - 1, 1, 0);
mmd->lvl = mmd->totlvl;
orig = CDDM_from_mesh(me, NULL);
dm = multires_dm_create_from_derived(mmd, orig, me, 0, 0);
multires_load_old(dm, me->mr);
*MultiresDM_get_flags(dm) |= MULTIRES_DM_UPDATE_ALWAYS;
dm->release(dm);
orig->release(orig);
/* Remove the old multires */
multires_free(me->mr);
me->mr = NULL;
}
ob->data = olddata;
}
}
}
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
/* WATCH IT 2!: Userdef struct init has to be in src/usiblender.c! */

View File

@@ -852,7 +852,7 @@ static void write_constraint_channels(WriteData *wd, ListBase *chanbase)
}
static void write_modifiers(WriteData *wd, ListBase *modbase)
static void write_modifiers(WriteData *wd, ListBase *modbase, int write_undo)
{
ModifierData *md;
@@ -903,10 +903,16 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
writestruct(wd, DATA, "MDefInfluence", mmd->totinfluence, mmd->dyninfluences);
writedata(wd, DATA, sizeof(int)*mmd->totvert, mmd->dynverts);
}
else if (md->type==eModifierType_Multires) {
MultiresModifierData *mmd = (MultiresModifierData*) md;
if(mmd->undo_verts && write_undo)
writestruct(wd, DATA, "MVert", mmd->undo_verts_tot, mmd->undo_verts);
}
}
}
static void write_objects(WriteData *wd, ListBase *idbase)
static void write_objects(WriteData *wd, ListBase *idbase, int write_undo)
{
Object *ob;
@@ -940,7 +946,7 @@ static void write_objects(WriteData *wd, ListBase *idbase)
writestruct(wd, DATA, "BulletSoftBody", 1, ob->bsoft);
write_particlesystems(wd, &ob->particlesystem);
write_modifiers(wd, &ob->modifiers);
write_modifiers(wd, &ob->modifiers, write_undo);
}
ob= ob->id.next;
}
@@ -1138,7 +1144,7 @@ static void write_curves(WriteData *wd, ListBase *idbase)
static void write_dverts(WriteData *wd, int count, MDeformVert *dvlist)
{
if (dvlist) {
int i;
int i;
/* Write the dvert list */
writestruct(wd, DATA, "MDeformVert", count, dvlist);
@@ -1151,6 +1157,19 @@ static void write_dverts(WriteData *wd, int count, MDeformVert *dvlist)
}
}
static void write_mdisps(WriteData *wd, int count, MDisps *mdlist)
{
if(mdlist) {
int i;
writestruct(wd, DATA, "MDisps", count, mdlist);
for(i = 0; i < count; ++i) {
if(mdlist[i].disps)
writedata(wd, DATA, sizeof(float)*3*mdlist[i].totdisp, mdlist[i].disps);
}
}
}
static void write_customdata(WriteData *wd, int count, CustomData *data, int partial_type, int partial_count)
{
int i;
@@ -1166,6 +1185,9 @@ static void write_customdata(WriteData *wd, int count, CustomData *data, int par
/* layer types that allocate own memory need special handling */
write_dverts(wd, count, layer->data);
}
else if (layer->type == CD_MDISPS) {
write_mdisps(wd, count, layer->data);
}
else {
CustomData_file_write_info(layer->type, &structname, &structnum);
if (structnum) {
@@ -1186,7 +1208,6 @@ static void write_customdata(WriteData *wd, int count, CustomData *data, int par
static void write_meshs(WriteData *wd, ListBase *idbase)
{
Mesh *mesh;
MultiresLevel *lvl;
mesh= idbase->first;
while(mesh) {
@@ -1212,29 +1233,6 @@ static void write_meshs(WriteData *wd, ListBase *idbase)
write_customdata(wd, mesh->totface, &mesh->fdata, -1, 0);
}
/* Multires data */
writestruct(wd, DATA, "Multires", 1, mesh->mr);
if(mesh->mr) {
lvl= mesh->mr->levels.first;
if(lvl) {
write_customdata(wd, lvl->totvert, &mesh->mr->vdata, -1, 0);
write_customdata(wd, lvl->totface, &mesh->mr->fdata, -1, 0);
writedata(wd, DATA, sizeof(short)*lvl->totedge, mesh->mr->edge_flags);
writedata(wd, DATA, sizeof(char)*lvl->totedge, mesh->mr->edge_creases);
}
for(; lvl; lvl= lvl->next) {
writestruct(wd, DATA, "MultiresLevel", 1, lvl);
writestruct(wd, DATA, "MultiresFace", lvl->totface, lvl->faces);
writestruct(wd, DATA, "MultiresEdge", lvl->totedge, lvl->edges);
writestruct(wd, DATA, "MultiresColFace", lvl->totface, lvl->colfaces);
}
lvl= mesh->mr->levels.last;
if(lvl)
writestruct(wd, DATA, "MVert", lvl->totvert, mesh->mr->verts);
}
/* PMV data */
if(mesh->pv) {
writestruct(wd, DATA, "PartialVisibility", 1, mesh->pv);
@@ -2098,7 +2096,7 @@ static int write_file_handle(Main *mainvar, int handle, MemFile *compare, MemFil
write_groups (wd, &mainvar->group);
write_armatures(wd, &mainvar->armature);
write_actions (wd, &mainvar->action);
write_objects (wd, &mainvar->object);
write_objects (wd, &mainvar->object, (current != NULL));
write_materials(wd, &mainvar->mat);
write_textures (wd, &mainvar->tex);
write_meshs (wd, &mainvar->mesh);

View File

@@ -1,59 +0,0 @@
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) 2006 by Nicholas Bishop
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef MULTIRES_H
#define MULTIRES_H
struct CustomData;
struct EditMesh;
struct Object;
struct MDeformVert;
struct Mesh;
struct MultiresLevel;
struct Multires;
struct uiBlock;
/* For canceling operations that don't work with multires on or on a non-base level */
int multires_test();
int multires_level1_test();
void multires_draw_interface(struct uiBlock *block, unsigned short cx, unsigned short cy);
void multires_make(void *ob, void *me);
void multires_delete(void *ob, void *me);
void multires_level_to_editmesh(struct Object *ob, struct Mesh *me, const int render);
void multires_finish_mesh_update(struct Object *ob);
void multires_subdivide(void *ob, void *me);
void multires_del_lower(void *ob, void *me);
void multires_del_higher(void *ob, void *me);
void multires_set_level_cb(void *ob, void *me);
void multires_edge_level_update_cb(void *ob, void *me);
int multires_modifier_warning();
#endif

View File

@@ -56,7 +56,6 @@
#include "BKE_displist.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
#include "BKE_multires.h"
#include "BKE_object.h"
#include "BKE_texture.h"
#include "BKE_utildefines.h"
@@ -628,14 +627,8 @@ static void make_tfaces(Object *ob)
Mesh *me= ob->data;
if(!me->mtface) {
if(me->mr) {
multires_add_layer(ob, &me->mr->fdata, CD_MTFACE,
CustomData_number_of_layers(&me->fdata, CD_MTFACE));
}
else {
me->mtface= CustomData_add_layer(&me->fdata, CD_MTFACE, CD_DEFAULT,
NULL, me->totface);
}
me->mtface= CustomData_add_layer(&me->fdata, CD_MTFACE, CD_DEFAULT,
NULL, me->totface);
}
}

View File

@@ -66,7 +66,6 @@
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
#include "BKE_object.h"
#include "BKE_pointcache.h"
#include "BKE_softbody.h"
@@ -97,7 +96,6 @@ static void waitcursor() {}
static void error() {}
static int pupmenu() {return 0;}
static void key_to_mesh() {}
static int multires_test() {return 0;}
static void adduplicate() {}
@@ -1443,7 +1441,6 @@ void separate_mesh(Scene *scene, Object *obedit)
ListBase edve, eded, edvl;
if(obedit==NULL) return;
if(multires_test()) return;
waitcursor(1);
@@ -1572,8 +1569,6 @@ void separate_material(Scene *scene, Object *obedit)
EditMesh *em;
unsigned char curr_mat;
if(multires_test()) return;
me= obedit->data;
em= me->edit_mesh;
if(me->key) {
@@ -1620,7 +1615,6 @@ void separate_mesh_loose(Scene *scene, Object *obedit)
return;
}
if(multires_test()) return;
waitcursor(1);
/* we are going to abuse the system as follows:
@@ -1830,11 +1824,6 @@ typedef struct EditSelectionC{
int index;
}EditSelectionC;
typedef struct EM_MultiresUndo {
int users;
Multires *mr;
} EM_MultiresUndo;
typedef struct UndoMesh {
EditVertC *verts;
EditEdgeC *edges;
@@ -1845,7 +1834,6 @@ typedef struct UndoMesh {
RetopoPaintData *retopo_paint_data;
char retopo_mode;
CustomData vdata, edata, fdata;
EM_MultiresUndo *mru;
} UndoMesh;
/* for callbacks */
@@ -1865,14 +1853,6 @@ static void free_undoMesh(void *umv)
CustomData_free(&um->vdata, um->totvert);
CustomData_free(&um->edata, um->totedge);
CustomData_free(&um->fdata, um->totface);
if(um->mru) {
--um->mru->users;
if(um->mru->users==0) {
multires_free(um->mru->mr);
um->mru->mr= NULL;
MEM_freeN(um->mru);
}
}
MEM_freeN(um);
}
@@ -1973,25 +1953,6 @@ static void *editMesh_to_undoMesh(void *emv)
// XXX um->retopo_paint_data= retopo_paint_data_copy(em->retopo_paint_data);
// um->retopo_mode= scene->toolsettings->retopo_mode;
{
Multires *mr= NULL; // XXX old-style multires
UndoMesh *prev= NULL; // XXX undo_editmode_get_prev(obedit);
um->mru= NULL;
if(mr) {
if(prev && prev->mru && prev->mru->mr && prev->mru->mr->current == mr->current) {
um->mru= prev->mru;
++um->mru->users;
}
else {
um->mru= MEM_callocN(sizeof(EM_MultiresUndo), "EM_MultiresUndo");
um->mru->users= 1;
um->mru->mr= multires_copy(mr);
}
}
}
return um;
}
@@ -2101,12 +2062,6 @@ static void undoMesh_to_editMesh(void *umv, void *emv)
// retopo_paint_view_update(G.vd);
// }
{
Mesh *me= NULL; // XXX;
multires_free(me->mr);
me->mr= NULL;
if(um->mru && um->mru->mr) me->mr= multires_copy(um->mru->mr);
}
}
static void *getEditMesh(bContext *C)

View File

@@ -58,7 +58,6 @@
#include "BIF_retopo.h"
#include "ED_mesh.h"
#include "ED_multires.h"
#include "ED_view3d.h"
#include "mesh_intern.h"
@@ -138,8 +137,6 @@ void add_click_mesh(Scene *scene, Object *obedit, EditMesh *em)
float min[3], max[3];
int done= 0;
if(multires_test()) return;
INIT_MINMAX(min, max);
for(v1= em->verts.first;v1; v1=v1->next) {
@@ -610,8 +607,6 @@ void addedgeface_mesh(EditMesh *em)
EditFace *efa;
short amount=0;
if(multires_test()) return;
/* how many selected ? */
if(em->selectmode & SCE_SELECT_EDGE) {
/* in edge mode finding selected vertices means flushing down edge codes... */
@@ -741,8 +736,6 @@ void addedgeface_mesh(EditMesh *em)
void adduplicate_mesh(Scene *scene, Object *obedit, EditMesh *em)
{
if(multires_test()) return;
waitcursor(1);
adduplicateflag(em, SELECT);
@@ -1250,8 +1243,6 @@ void add_primitiveMesh(Scene *scene, View3D *v3d, Object *obedit, EditMesh *em,
/* this function also comes from an info window */
// XXX if ELEM(curarea->spacetype, SPACE_VIEW3D, SPACE_INFO); else return;
if (obedit && obedit->type==OB_MESH && multires_test()) return;
/* if editmode exists for other type, it exits */
check_editmode(OB_MESH);

View File

@@ -79,7 +79,6 @@ editmesh_mods.c, UI level access, no geometry changes
#include "RNA_access.h"
#include "RNA_define.h"
#include "ED_multires.h"
#include "ED_mesh.h"
#include "ED_screen.h"
#include "ED_view3d.h"
@@ -3346,8 +3345,6 @@ void editmesh_mark_seam(EditMesh *em, int clear)
{
EditEdge *eed;
// XXX if(multires_level1_test()) return;
/* auto-enable seams drawing */
if(clear==0) {
if(!(G.f & G_DRAWSEAMS)) {
@@ -3391,8 +3388,6 @@ void editmesh_mark_sharp(EditMesh *em, int set)
}
#endif
// XXX if(multires_level1_test()) return;
if(set) {
eed= em->edges.first;
while(eed) {

View File

@@ -78,7 +78,6 @@ editmesh_tool.c: UI called tools for editmesh, geometry changes here, otherwise
#include "BMF_Api.h"
#include "ED_multires.h"
#include "ED_mesh.h"
#include "ED_view3d.h"
@@ -143,8 +142,6 @@ void convert_to_triface(EditMesh *em, int direction)
EditFace *efa, *efan, *next;
float fac;
if(multires_test()) return;
efa= em->faces.last;
while(efa) {
next= efa->prev;
@@ -196,8 +193,6 @@ int removedoublesflag(EditMesh *em, short flag, short automerge, float limit) /
struct facesort *vlsortblock, *vsb, *vsb1;
int a, b, test, amount;
if(multires_test()) return 0;
/* flag 128 is cleared, count */
@@ -499,8 +494,6 @@ void xsortvert_flag(bContext *C, int flag)
ListBase tbase;
int i, amount;
if(multires_test()) return;
em_setup_viewcontext(C, &vc);
amount = BLI_countlist(&vc.em->verts);
@@ -540,8 +533,6 @@ void hashvert_flag(EditMesh *em, int flag)
ListBase tbase;
int amount, a, b;
if(multires_test()) return;
/* count */
eve= em->verts.first;
amount= 0;
@@ -600,8 +591,6 @@ void extrude_mesh(Object *obedit, EditMesh *em)
float nor[3]= {0.0, 0.0, 0.0};
short nr, transmode= 0;
if(multires_test()) return;
if(em->selectmode & SCE_SELECT_VERTEX) {
if(G.totvertsel==0) nr= 0;
else if(G.totvertsel==1) nr= 4;
@@ -673,8 +662,6 @@ void extrude_mesh(Object *obedit, EditMesh *em)
void split_mesh(EditMesh *em)
{
if(multires_test()) return;
if(okee(" Split ")==0) return;
waitcursor(1);
@@ -698,8 +685,6 @@ void extrude_repeat_mesh(View3D *v3d, Object *obedit, EditMesh *em, int steps, f
float dvec[3], tmat[3][3], bmat[3][3], nor[3]= {0.0, 0.0, 0.0};
short a;
if(multires_test()) return;
/* dvec */
dvec[0]= v3d->persinv[2][0];
dvec[1]= v3d->persinv[2][1];
@@ -737,8 +722,6 @@ void spin_mesh(View3D *v3d, Object *obedit, EditMesh *em, int steps, float degr,
float phi;
short a,ok;
if(multires_test()) return;
/* imat and center and size */
Mat3CpyMat4(bmat, obedit->obmat);
Mat3Inv(imat,bmat);
@@ -821,8 +804,6 @@ void screw_mesh(Object *obedit, EditMesh *em, int steps, int turns)
EditEdge *eed;
float dvec[3], nor[3];
if(multires_test()) return;
/* clear flags */
eve= em->verts.first;
while(eve) {
@@ -933,8 +914,6 @@ void delete_mesh(Object *obedit, EditMesh *em)
int count;
char *str="Erase";
if(multires_test()) return;
event= pupmenu("Erase %t|Vertices%x10|Edges%x1|Faces%x2|All%x3|Edges & Faces%x4|Only Faces%x5|Edge Loop%x6");
if(event<1) return;
@@ -1078,8 +1057,6 @@ void fill_mesh(EditMesh *em)
short ok;
if(em==NULL) return;
if(multires_test()) return;
waitcursor(1);
/* copy all selected vertices */
@@ -2372,8 +2349,6 @@ void esubdivideflag(Object *obedit, EditMesh *em, int flag, float rad, int beaut
ModifierData *md= obedit->modifiers.first;
int ctrl= 0; // XXX
if(multires_test()) return;
//Set faces f1 to 0 cause we need it later
for(ef=em->faces.first;ef;ef = ef->next) ef->f1 = 0;
for(eve=em->verts.first; eve; eve=eve->next) {
@@ -2930,8 +2905,6 @@ void beauty_fill(EditMesh *em)
float len1, len2, len3, len4, len5, len6, opp1, opp2, fac1, fac2;
int totedge, ok, notbeauty=8, onedone, vindex[4];
if(multires_test()) return;
/* - all selected edges with two faces
* - find the faces: store them in edges (using datablock)
* - per edge: - test convex
@@ -3238,9 +3211,6 @@ void join_triangles(EditMesh *em)
float limit = 0.0f; // XXX scene->toolsettings->jointrilimit;
int i, ok, totedge=0, totseledge=0, complexedges, vindex[4];
/*test for multi-resolution data*/
if(multires_test()) return;
/*if we take a long time on very dense meshes we want waitcursor to display*/
waitcursor(1);
@@ -5586,8 +5556,6 @@ int collapseEdges(EditMesh *em)
mergecount = 0;
if(multires_test()) return 0;
build_edgecollection(em, &allcollections);
groupcount = BLI_countlist(&allcollections);
@@ -5646,8 +5614,6 @@ int merge_firstlast(EditMesh *em, int first, int uvmerge)
EditVert *eve,*mergevert;
EditSelection *ese;
if(multires_test()) return 0;
/* do sanity check in mergemenu in edit.c ?*/
if(first == 0){
ese = em->selected.last;
@@ -5681,8 +5647,6 @@ int merge_target(EditMesh *em, int target, int uvmerge)
{
EditVert *eve;
if(multires_test()) return 0;
if(target) snap_sel_to_curs();
else snap_to_center();

View File

@@ -98,7 +98,6 @@
#include "BKE_material.h"
#include "BKE_mball.h"
#include "BKE_mesh.h"
#include "BKE_multires.h"
#include "BKE_nla.h"
#include "BKE_object.h"
#include "BKE_particle.h"
@@ -2285,9 +2284,6 @@ void ED_object_exit_editmode(bContext *C, int flag)
if(freedata) obedit= NULL;
scene->obedit= obedit; // XXX for context
if(ob->type==OB_MESH && get_mesh(ob)->mr)
multires_edge_level_update(ob, get_mesh(ob));
/* also flush ob recalc, doesn't take much overhead, but used for particles */
DAG_object_flush_update(scene, ob, OB_RECALC_OB|OB_RECALC_DATA);

View File

@@ -74,7 +74,8 @@ typedef struct CustomData {
#define CD_MLOOPUV 16
#define CD_MLOOPCOL 17
#define CD_TANGENT 18
#define CD_NUMTYPES 19
#define CD_MDISPS 19
#define CD_NUMTYPES 20
/* fake type, derivedmesh wants CustomDataMask for weightpaint too, is not stored */
#define CD_WEIGHTPAINT 30
@@ -98,6 +99,7 @@ typedef struct CustomData {
#define CD_MASK_MLOOPUV (1 << CD_MLOOPUV)
#define CD_MASK_MLOOPCOL (1 << CD_MLOOPCOL)
#define CD_MASK_TANGENT (1 << CD_TANGENT)
#define CD_MASK_MDISPS (1 << CD_MDISPS)
/* derivedmesh wants CustomDataMask for weightpaint too, is not customdata though */
#define CD_MASK_WEIGHTPAINT (1 << CD_WEIGHTPAINT)

View File

@@ -117,7 +117,14 @@ typedef struct OrigSpaceFace {
float uv[4][2];
} OrigSpaceFace;
/* Multiresolution modeling */
typedef struct MDisps {
/* Strange bug in SDNA: if disps pointer comes first, it fails to see totdisp */
int totdisp;
char pad[4];
float (*disps)[3];
} MDisps;
/** Multires structs kept for compatibility with old files **/
typedef struct MultiresCol {
float a, r, g, b;
} MultiresCol;
@@ -143,15 +150,9 @@ typedef struct MultiresLevel {
MultiresColFace *colfaces;
MultiresEdge *edges;
/* Temporary connectivity data */
char *edge_boundary_states;
struct ListBase *vert_edge_map;
struct ListBase *vert_face_map;
struct MultiresMapNode *map_mem;
unsigned int totvert, totface, totedge, pad;
/* Kept for compatibility with older files */
/* Kept for compatibility with even older files */
MVert *verts;
} MultiresLevel;
@@ -169,6 +170,8 @@ typedef struct Multires {
char *edge_creases;
} Multires;
/** End Multires **/
typedef struct PartialVisibility {
unsigned int *vert_map; /* vert_map[Old Index]= New Index */
int *edge_map; /* edge_map[Old Index]= New Index, -1= hidden */
@@ -266,7 +269,4 @@ typedef struct PartialVisibility {
#define TF_PIN3 64
#define TF_PIN4 128
/* multires->flag */
#define MULTIRES_NO_RENDER 1
#endif

View File

@@ -39,6 +39,7 @@ typedef enum ModifierType {
eModifierType_Fluidsim,
eModifierType_Mask,
eModifierType_SimpleDeform,
eModifierType_Multires,
NUM_MODIFIER_TYPES
} ModifierType;
@@ -517,6 +518,17 @@ typedef struct ExplodeModifierData {
float protect;
} ExplodeModifierData;
typedef struct MultiresModifierData {
ModifierData modifier;
struct MVert *undo_verts; /* Store DerivedMesh vertices for multires undo */
int undo_verts_tot; /* Length of undo_verts array */
char undo_signal; /* If true, signals to replace verts with undo verts */
char lvl, totlvl;
char simple;
} MultiresModifierData;
typedef struct FluidsimModifierData {
ModifierData modifier;

View File

@@ -30,10 +30,194 @@
#include "rna_internal.h"
#include "DNA_action_types.h"
#include "DNA_armature_types.h"
#ifdef RNA_RUNTIME
#endif
static float rna_IK_Min_X_get(PointerRNA *ptr)
{
bPoseChannel *pchan= (bPoseChannel*)ptr->id.data;
return pchan->limitmin[0];
}
static float rna_IK_Min_Y_get(PointerRNA *ptr)
{
bPoseChannel *pchan= (bPoseChannel*)ptr->id.data;
return pchan->limitmin[1];
}
static float rna_IK_Min_Z_get(PointerRNA *ptr)
{
bPoseChannel *pchan= (bPoseChannel*)ptr->id.data;
return pchan->limitmin[2];
}
static void rna_IK_Min_X_set(PointerRNA *ptr, float value)
{
bPoseChannel *pchan= (bPoseChannel*)ptr->id.data;
pchan->limitmin[0] = value;
}
static void rna_IK_Min_Y_set(PointerRNA *ptr, float value)
{
bPoseChannel *pchan= (bPoseChannel*)ptr->id.data;
pchan->limitmin[1] = value;
}
static void rna_IK_Min_Z_set(PointerRNA *ptr, float value)
{
bPoseChannel *pchan= (bPoseChannel*)ptr->id.data;
pchan->limitmin[2] = value;
}
#else
/* users shouldn't be editing pose channel data directly -- better to set ipos and let blender calc pose_channel stuff */
/* it's going to be weird for users to find IK flags and other such here, instead of in bone where they would expect them
-- is there any way to put a doc in bone, pointing them here? */
static void RNA_def_pose_channel(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
static EnumPropertyItem prop_iklimit_items[] = {
{BONE_IK_NO_XDOF, "IKNOXDOF", "No X DoF", "Prevent motion around X axis."},
{BONE_IK_NO_YDOF, "IKNOYDOF", "No Y DoF", "Prevent motion around Y axis."},
{BONE_IK_NO_ZDOF, "IKNOZDOF", "No Z DoF", "Prevent motion around Z axis."},
{BONE_IK_XLIMIT, "IKXLIMIT", "X Limit", "Limit motion around X axis."},
{BONE_IK_YLIMIT, "IKYLIMIT", "Y Limit", "Limit motion around Y axis."},
{BONE_IK_ZLIMIT, "IKZLIMIT", "Z Limit", "Limit motion around Z axis."},
{0, NULL, NULL, NULL}};
srna= RNA_def_struct(brna, "bPoseChannel", NULL);
RNA_def_struct_ui_text(srna, "Pose Channel", "Member of the 'Pose' type.");
/* cosntraints (collection) */
prop= RNA_def_property(srna, "constraints", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "constraints", NULL);
RNA_def_property_struct_type(prop, "bConstraint");
RNA_def_property_ui_text(prop, "Constraints", "Constraints that act on this PoseChannel.");
prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_flag(prop, PROP_NOT_EDITABLE);
RNA_def_property_ui_text(prop, "Name", "");
RNA_def_struct_name_property(srna, prop);
prop= RNA_def_property(srna, "ikflag", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, prop_iklimit_items);
RNA_def_property_ui_text(prop, "IK Limits", "");
prop= RNA_def_property(srna, "selected", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "selectflag", BONE_SELECTED);
RNA_def_property_ui_text(prop, "Selected", "");
prop= RNA_def_property(srna, "protected", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "protectflag", POSE_LOCKED);
RNA_def_property_ui_text(prop, "Protected", "Protect channel from being transformed.");
prop= RNA_def_property(srna, "action_group_index", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "agrp_index");
RNA_def_property_ui_text(prop, "Action Group Index", "Action Group this pose channel belogs to (0=no group).");
prop= RNA_def_property(srna, "path_start_frame", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "pathsf");
RNA_def_property_flag(prop, PROP_NOT_EDITABLE);
RNA_def_property_ui_text(prop, "Bone Paths Calculation Start Frame", "Starting frame of range of frames to use for Bone Path calculations.");
prop= RNA_def_property(srna, "path_end_frame", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "pathef");
RNA_def_property_flag(prop, PROP_NOT_EDITABLE);
RNA_def_property_ui_text(prop, "Bone Paths Calculation End Frame", "End frame of range of frames to use for Bone Path calculations.");
prop= RNA_def_property(srna, "bone", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "Bone");
RNA_def_property_flag(prop, PROP_NOT_EDITABLE);
RNA_def_property_ui_text(prop, "Bone", "Bone associated with this Pose Channel.");
prop= RNA_def_property(srna, "parent", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "bPoseChannel");
RNA_def_property_flag(prop, PROP_NOT_EDITABLE);
RNA_def_property_ui_text(prop, "Parent", "Parent of this pose channel.");
prop= RNA_def_property(srna, "child", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "bPoseChannel");
RNA_def_property_flag(prop, PROP_NOT_EDITABLE);
RNA_def_property_ui_text(prop, "Parent", "Child of this pose channel.");
prop= RNA_def_property(srna, "channel_matrix", PROP_FLOAT, PROP_MATRIX);
RNA_def_property_struct_type(prop, "chan_mat");
RNA_def_property_flag(prop, PROP_NOT_EDITABLE);
RNA_def_property_ui_text(prop, "Channel Matrix", "4x4 matrix, before constraints.");
/* kaito says this should be not user-editable; I disagree; power users should be able to force this in python; he's the boss. */
prop= RNA_def_property(srna, "pose_matrix", PROP_FLOAT, PROP_MATRIX);
RNA_def_property_struct_type(prop, "pose_mat");
RNA_def_property_flag(prop, PROP_NOT_EDITABLE);
RNA_def_property_ui_text(prop, "Pose Matrix", "Final 4x4 matrix for this channel.");
prop= RNA_def_property(srna, "constraint_inverse_matrix", PROP_FLOAT, PROP_MATRIX);
RNA_def_property_struct_type(prop, "constinv");
RNA_def_property_flag(prop, PROP_NOT_EDITABLE);
RNA_def_property_ui_text(prop, "Constraint Inverse Matrix", "4x4 matrix, defines transform from final position to unconstrained position.");
prop= RNA_def_property(srna, "pose_head", PROP_FLOAT, PROP_VECTOR);
RNA_def_property_flag(prop, PROP_NOT_EDITABLE);
RNA_def_property_ui_text(prop, "Pose Head Position", "Location of head of the channel's bone.");
prop= RNA_def_property(srna, "pose_tail", PROP_FLOAT, PROP_VECTOR);
RNA_def_property_flag(prop, PROP_NOT_EDITABLE);
RNA_def_property_ui_text(prop, "Pose Tail Position", "Location of tail of the channel's bone.");
prop= RNA_def_property(srna, "ik_min_x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "limitmin");
RNA_def_property_range(prop, -180.0f, 180.0f);
RNA_def_property_float_funcs(prop, "rna_IK_Min_X_get", "rna_IK_Min_X_set", NULL);
RNA_def_property_ui_text(prop, "IK Minimum Limit X", "Minimum X angle for IK Limit");
prop= RNA_def_property(srna, "ik_min_y", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "limitmin");
RNA_def_property_range(prop, -180.0f, 180.0f);
RNA_def_property_float_funcs(prop, "rna_IK_Min_Y_get", "rna_IK_Min_Y_set", NULL);
RNA_def_property_ui_text(prop, "IK Minimum Limit Y", "Minimum Y angle for IK Limit");
prop= RNA_def_property(srna, "ik_min_z", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "limitmin");
RNA_def_property_range(prop, -180.0f, 180.0f);
RNA_def_property_float_funcs(prop, "rna_IK_Min_Z_get", "rna_IK_Min_Z_set", NULL);
RNA_def_property_ui_text(prop, "IK Minimum Limit Z", "Minimum Z angle for IK Limit");
prop= RNA_def_property(srna, "ik_max_x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "limitmax");
RNA_def_property_range(prop, -180.0f, 180.0f);
RNA_def_property_float_funcs(prop, "rna_IK_Max_X_get", "rna_IK_Max_X_set", NULL);
RNA_def_property_ui_text(prop, "IK Maximum Limit X", "Maximum X angle for IK Limit");
prop= RNA_def_property(srna, "ik_max_y", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "limitmax");
RNA_def_property_range(prop, -180.0f, 180.0f);
RNA_def_property_float_funcs(prop, "rna_IK_Max_Y_get", "rna_IK_Max_Y_set", NULL);
RNA_def_property_ui_text(prop, "IK Maximum Limit Y", "Maximum Y angle for IK Limit");
prop= RNA_def_property(srna, "ik_max_z", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "limitmax");
RNA_def_property_range(prop, -180.0f, 180.0f);
RNA_def_property_float_funcs(prop, "rna_IK_Max_Z_get", "rna_IK_Max_Z_set", NULL);
RNA_def_property_ui_text(prop, "IK Maximum Limit Z", "Maximum Z angle for IK Limit");
// float limitmin[3], limitmax[3]; /* DOF constraint */
// float stiffness[3]; /* DOF stiffness */
// float ikstretch;
// float *path; /* totpath x 3 x float */
// struct Object *custom; /* draws custom object instead of this channel */
};
void RNA_def_action(BlenderRNA *brna)
{
@@ -45,3 +229,5 @@ void RNA_def_action(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Action", "DOC_BROKEN");
}
#endif

View File

@@ -505,7 +505,6 @@ typedef struct LampRen {
#define R_LAMPHALO 8
#define R_GLOB_NOPUNOFLIP 16
#define R_NEED_TANGENT 32
#define R_SKIP_MULTIRES 64
#define R_BAKE_TRACE 128
#define R_BAKING 256

View File

@@ -99,7 +99,6 @@
#include "IMB_imbuf_types.h"
#include "envmap.h"
//XXX #include "multires.h"
#include "occlusion.h"
#include "render_types.h"
#include "rendercore.h"
@@ -3077,13 +3076,6 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
if(need_orco)
mask |= CD_MASK_ORCO;
if(me->mr) {
if(re->flag & R_SKIP_MULTIRES)
me->mr->flag |= MULTIRES_NO_RENDER;
else
me->mr->flag &= ~MULTIRES_NO_RENDER;
}
dm= mesh_create_derived_render(re->scene, ob, mask);
if(dm==NULL) return; /* in case duplicated object fails? */
@@ -5432,8 +5424,6 @@ void RE_Database_Baking(Render *re, Scene *scene, int type, Object *actob)
re->flag |= R_GLOB_NOPUNOFLIP;
re->flag |= R_BAKING;
re->excludeob= actob;
if(type == RE_BAKE_LIGHT)
re->flag |= R_SKIP_MULTIRES;
if(actob)
re->flag |= R_BAKE_TRACE;