Files
test/source/blender/src/multires.c
Nicholas Bishop 55d49ed63b == Multires ==
Fixed a crash on adding a UV layer to a multires mesh while in editmode.
2007-12-27 07:27:03 +00:00

432 lines
10 KiB
C

/*
* $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 *****
*
* Implements the multiresolution modeling tools.
*
* multires.h
*
*/
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
#include "BLI_arithb.h"
#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_scene_types.h"
#include "DNA_vec_types.h"
#include "DNA_view3d_types.h"
#include "BKE_customdata.h"
#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_key.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
#include "BKE_object.h"
#include "BIF_editmesh.h"
#include "BIF_screen.h"
#include "BIF_space.h"
#include "BIF_toolbox.h"
#include "BDR_editobject.h"
#include "BDR_sculptmode.h"
#include "BLI_editVert.h"
#include "BSE_edit.h"
#include "BSE_view.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "blendef.h"
#include "editmesh.h"
#include "multires.h"
#include "mydevice.h"
#include "parametrizer.h"
#include <math.h>
void multires_calc_temp_data(struct MultiresLevel *lvl);
int multires_test()
{
Mesh *me= get_mesh(OBACT);
if(me && me->mr) {
error("Unable to complete action with multires enabled.");
return 1;
}
return 0;
}
int multires_level1_test()
{
Mesh *me= get_mesh(OBACT);
if(me && me->mr && me->mr->current != 1) {
error("Operation only available for multires level 1.");
return 1;
}
return 0;
}
/* Sculptmode */
void multires_check_state()
{
if(G.f & G_SCULPTMODE && !G.obedit)
sculptmode_correct_state();
}
static void medge_flag_to_eed(const short flag, const char crease, EditEdge *eed)
{
if(!eed) return;
if(flag & ME_SEAM) eed->seam= 1;
if(flag & ME_SHARP) eed->sharp = 1;
if(flag & SELECT) eed->f |= SELECT;
if(flag & ME_FGON) eed->h= EM_FGON;
if(flag & ME_HIDE) eed->h |= 1;
eed->crease= ((float)crease)/255.0;
}
void multires_level_to_editmesh(Object *ob, Mesh *me, const int render)
{
MultiresLevel *lvl= BLI_findlink(&me->mr->levels,me->mr->current-1);
int i;
EditMesh *em= (!render && G.obedit) ? G.editMesh : NULL;
EditVert **eves= NULL;
EditEdge *eed= NULL;
if(em) {
/* Remove editmesh elements */
free_editMesh(em);
eves= MEM_callocN(sizeof(EditVert*)*lvl->totvert, "editvert pointers");
/* Vertices/Edges/Faces */
for(i=0; i<lvl->totvert; ++i) {
eves[i]= addvertlist(me->mr->verts[i].co, NULL);
if(me->mr->verts[i].flag & 1) eves[i]->f |= SELECT;
if(me->mr->verts[i].flag & ME_HIDE) eves[i]->h= 1;
eves[i]->data= NULL;
}
for(i=0; i<lvl->totedge; ++i) {
addedgelist(eves[lvl->edges[i].v[0]], eves[lvl->edges[i].v[1]], NULL);
}
for(i=0; i<lvl->totface; ++i) {
EditVert *eve4= lvl->faces[i].v[3] ? eves[lvl->faces[i].v[3]] : NULL;
EditFace *efa= addfacelist(eves[lvl->faces[i].v[0]], eves[lvl->faces[i].v[1]],
eves[lvl->faces[i].v[2]], eve4, NULL, NULL);
efa->flag= lvl->faces[i].flag & ~ME_HIDE;
efa->mat_nr= lvl->faces[i].mat_nr;
if(lvl->faces[i].flag & ME_FACE_SEL)
efa->f |= SELECT;
if(lvl->faces[i].flag & ME_HIDE) efa->h= 1;
efa->data= NULL;
}
/* Edge flags */
eed= em->edges.first;
if(lvl==me->mr->levels.first) {
for(i=0; i<lvl->totedge; ++i) {
medge_flag_to_eed(me->mr->edge_flags[i], me->mr->edge_creases[i], eed);
eed= eed->next;
}
} 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);
medge_flag_to_eed(me->mr->edge_flags[ndx], me->mr->edge_creases[ndx], eed);
eed= eed->next;
}
}
eed= em->edges.first;
for(i=0, eed= em->edges.first; i<lvl->totedge; ++i, eed= eed->next) {
eed->h= me->mr->verts[lvl->edges[i].v[0]].flag & ME_HIDE ||
me->mr->verts[lvl->edges[i].v[1]].flag & ME_HIDE;
}
EM_select_flush();
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) {
MCol c[4];
EditFace *efa= NULL;
CustomData *src= &em->fdata;
if(me->mr->use_col) EM_add_data_layer(src, CD_MCOL);
efa= em->faces.first;
for(i=0; i<lvl->totface; ++i) {
if(me->mr->use_col) {
multires_to_mcol(&lvl->colfaces[i], c);
CustomData_em_set(src, efa->data, CD_MCOL, c);
}
efa= efa->next;
}
}
mesh_update_customdata_pointers(me);
MEM_freeN(eves);
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
recalc_editnormals();
}
}
void multires_make(void *ob, void *me_v)
{
Mesh *me= me_v;
Key *key;
/* Check for shape keys */
key= me->key;
if(key) {
int ret= okee("Adding multires will delete all shape keys, proceed?");
if(ret) {
free_key(key);
me->key= NULL;
} else
return;
}
waitcursor(1);
multires_check_state();
multires_create(ob, me);
allqueue(REDRAWBUTSEDIT, 0);
BIF_undo_push("Make multires");
waitcursor(0);
}
void multires_delete(void *ob, void *me_v)
{
Mesh *me= me_v;
multires_free(me->mr);
me->mr= NULL;
multires_check_state();
allqueue(REDRAWBUTSEDIT, 0);
BIF_undo_push("Apply multires");
}
/* Make sure that all level indices are clipped to [1, mr->level_count] */
void multires_clip_levels(Multires *mr)
{
if(mr) {
const int cnt = mr->level_count;
if(mr->current < 1) mr->current = 1;
if(mr->edgelvl < 1) mr->edgelvl = 1;
if(mr->pinlvl < 1) mr->pinlvl = 1;
if(mr->renderlvl < 1) mr->renderlvl = 1;
if(mr->current > cnt) mr->current = cnt;
if(mr->edgelvl > cnt) mr->edgelvl = cnt;
if(mr->pinlvl > cnt) mr->pinlvl = cnt;
if(mr->renderlvl > cnt) mr->renderlvl = cnt;
}
}
/* Delete all multires levels beneath current level. Subdivide special
first-level data up to the new lowest level. */
void multires_del_lower(void *ob, void *me)
{
Multires *mr= ((Mesh*)me)->mr;
MultiresLevel *lvl1= mr->levels.first, *cr_lvl= current_level(mr);
MultiresLevel *lvl= NULL, *lvlprev= NULL;
short *edgeflags= NULL;
char *edgecreases= NULL;
int i, last;
if(cr_lvl == lvl1) return;
multires_check_state();
/* Subdivide the edge flags to the current level */
edgeflags= MEM_callocN(sizeof(short)*current_level(mr)->totedge, "Multires Edge Flags");
edgecreases= MEM_callocN(sizeof(char)*current_level(mr)->totedge, "Multires Edge Creases");
last= lvl1->totedge * pow(2, mr->current-1);
for(i=0; i<last; ++i) {
edgeflags[i] = mr->edge_flags[(int)(i / pow(2, mr->current-1))];
edgecreases[i] = mr->edge_creases[(int)(i / pow(2, mr->current-1))];
}
MEM_freeN(mr->edge_flags);
MEM_freeN(mr->edge_creases);
mr->edge_flags= edgeflags;
mr->edge_creases= edgecreases;
multires_del_lower_customdata(mr, cr_lvl);
lvl= cr_lvl->prev;
while(lvl) {
lvlprev= lvl->prev;
multires_free_level(lvl);
BLI_freelinkN(&mr->levels, lvl);
mr->current-= 1;
mr->level_count-= 1;
lvl= lvlprev;
}
mr->newlvl= mr->current;
multires_clip_levels(mr);
allqueue(REDRAWBUTSEDIT, 0);
BIF_undo_push("Multires delete lower");
}
void multires_del_higher(void *ob, void *me)
{
Multires *mr= ((Mesh*)me)->mr;
MultiresLevel *lvl= BLI_findlink(&mr->levels,mr->current-1);
MultiresLevel *lvlnext;
multires_check_state();
lvl= lvl->next;
while(lvl) {
lvlnext= lvl->next;
multires_free_level(lvl);
BLI_freelinkN(&mr->levels,lvl);
mr->level_count-= 1;
lvl= lvlnext;
}
multires_clip_levels(mr);
allqueue(REDRAWBUTSEDIT, 0);
BIF_undo_push("Multires delete higher");
}
void multires_finish_mesh_update(Object *ob)
{
/* friendly check for background render */
if(G.background==0) {
object_handle_update(ob);
countall();
if(G.vd && G.vd->depths) G.vd->depths->damaged= 1;
allqueue(REDRAWVIEW3D, 0);
allqueue(REDRAWIMAGE, 0);
}
}
void multires_subdivide(void *ob_v, void *me_v)
{
Mesh *me = me_v;
multires_check_state();
if(CustomData_number_of_layers(G.obedit ? &G.editMesh->fdata : &me->fdata, CD_MCOL) > 1) {
int ret= okee("Adding a level will delete all but the active vertex color layer, proceed?");
if(!ret)
return;
}
waitcursor(1);
multires_add_level(ob_v, me, G.scene->toolsettings->multires_subdiv_type);
multires_level_to_editmesh(ob_v, me, 0);
multires_finish_mesh_update(ob_v);
allqueue(REDRAWBUTSEDIT, 0);
BIF_undo_push("Add multires level");
waitcursor(0);
}
void multires_set_level_cb(void *ob, void *me)
{
waitcursor(1);
multires_check_state();
multires_set_level(ob, me, 0);
multires_level_to_editmesh(ob, me, 0);
multires_finish_mesh_update(ob);
if(G.obedit || G.f & G_SCULPTMODE)
BIF_undo_push("Multires set level");
allqueue(REDRAWBUTSEDIT, 0);
waitcursor(0);
}
void multires_edge_level_update_cb(void *ob_v, void *me_v)
{
multires_edge_level_update(ob_v, me_v);
allqueue(REDRAWVIEW3D, 0);
}
int multires_modifier_warning()
{
ModifierData *md;
for(md= modifiers_getVirtualModifierList(OBACT); md; md= md->next) {
if(md->mode & eModifierMode_Render) {
switch(md->type) {
case eModifierType_Subsurf:
case eModifierType_Build:
case eModifierType_Mirror:
case eModifierType_Decimate:
case eModifierType_Boolean:
case eModifierType_Array:
case eModifierType_EdgeSplit:
return 1;
}
}
}
return 0;
}