This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/blenkernel/intern/cdderivedmesh.c
Brecht Van Lommel e4a1eb4e09 Added custom vertex data support to editmode. Only used for vertex groups
now, others can be added later (sticky, shape keys). Beside one small fix
for knife exact vertex group interpolation, is intended to work the same
as before.

Also fixes bug #5200, related to editmode undo and vertex groups. And
corrects the editmode to faceselect mode selection conversion, that was
broken in a previous commit.
2006-11-11 23:23:15 +00:00

1048 lines
28 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 Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Ben Batt <benbatt@gmail.com>
*
* ***** END GPL LICENSE BLOCK *****
*
* Implementation of CDDerivedMesh.
*
* BKE_cdderivedmesh.h contains the function prototypes for this file.
*
*/
/* TODO maybe BIF_gl.h should include string.h? */
#include <string.h>
#include "BIF_gl.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_customdata.h"
#include "BKE_DerivedMesh.h"
#include "BKE_displist.h"
#include "BKE_mesh.h"
#include "BKE_utildefines.h"
#include "BLI_arithb.h"
#include "BLI_blenlib.h"
#include "BLI_edgehash.h"
#include "BLI_editVert.h"
#include "BLI_ghash.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "MEM_guardedalloc.h"
#include <string.h>
#include <limits.h>
/**************** DerivedMesh interface functions ****************/
static int cdDM_getNumVerts(DerivedMesh *dm)
{
return dm->vertData.numElems;
}
static int cdDM_getNumFaces(DerivedMesh *dm)
{
return dm->faceData.numElems;
}
static int cdDM_getNumEdges(DerivedMesh *dm)
{
return dm->edgeData.numElems;
}
static void cdDM_getVert(DerivedMesh *dm, int index, MVert *vert_r)
{
*vert_r = *CDDM_get_vert(dm, index);
}
static void cdDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r)
{
*edge_r = *CDDM_get_edge(dm, index);
}
static void cdDM_getFace(DerivedMesh *dm, int index, MFace *face_r)
{
*face_r = *CDDM_get_face(dm, index);
}
static void cdDM_getVertArray(DerivedMesh *dm, MVert *vert_r)
{
memcpy(vert_r, CDDM_get_verts(dm), sizeof(*vert_r) * dm->getNumVerts(dm));
}
static void cdDM_getEdgeArray(DerivedMesh *dm, MEdge *edge_r)
{
memcpy(edge_r, CDDM_get_edges(dm), sizeof(*edge_r) * dm->getNumEdges(dm));
}
static void cdDM_getFaceArray(DerivedMesh *dm, MFace *face_r)
{
memcpy(face_r, CDDM_get_faces(dm), sizeof(*face_r) * dm->getNumFaces(dm));
}
static void cdDM_foreachMappedVert(
DerivedMesh *dm,
void (*func)(void *userData, int index, float *co,
float *no_f, short *no_s),
void *userData)
{
int i;
int maxVerts = dm->getNumVerts(dm);
MVert *mv = CDDM_get_verts(dm);
int *index = DM_get_vert_data_layer(dm, LAYERTYPE_ORIGINDEX);
for(i = 0; i < maxVerts; i++, mv++, index++) {
if(*index == ORIGINDEX_NONE) continue;
func(userData, *index, mv->co, NULL, mv->no);
}
}
static void cdDM_foreachMappedEdge(
DerivedMesh *dm,
void (*func)(void *userData, int index,
float *v0co, float *v1co),
void *userData)
{
int i;
int maxEdges = dm->getNumEdges(dm);
MEdge *med = CDDM_get_edges(dm);
MVert *mv = CDDM_get_verts(dm);
int *index = DM_get_edge_data_layer(dm, LAYERTYPE_ORIGINDEX);
for(i = 0; i < maxEdges; i++, med++, index++) {
if(*index == ORIGINDEX_NONE) continue;
func(userData, *index, mv[med->v1].co, mv[med->v2].co);
}
}
static void cdDM_foreachMappedFaceCenter(
DerivedMesh *dm,
void (*func)(void *userData, int index,
float *cent, float *no),
void *userData)
{
int i;
int maxFaces = dm->getNumFaces(dm);
MFace *mf = CDDM_get_faces(dm);
MVert *mv = CDDM_get_verts(dm);
int *index = DM_get_face_data_layer(dm, LAYERTYPE_ORIGINDEX);
for(i = 0; i < maxFaces; i++, mf++, index++) {
float cent[3];
float no[3];
if(*index == ORIGINDEX_NONE) continue;
VECCOPY(cent, mv[mf->v1].co);
VecAddf(cent, cent, mv[mf->v2].co);
VecAddf(cent, cent, mv[mf->v3].co);
if (mf->v4) {
CalcNormFloat4(mv[mf->v1].co, mv[mf->v2].co,
mv[mf->v3].co, mv[mf->v4].co, no);
VecAddf(cent, cent, mv[mf->v4].co);
VecMulf(cent, 0.25f);
} else {
CalcNormFloat(mv[mf->v1].co, mv[mf->v2].co,
mv[mf->v3].co, no);
VecMulf(cent, 0.33333333333f);
}
func(userData, *index, cent, no);
}
}
static DispListMesh *cdDM_convertToDispListMesh(DerivedMesh *dm,
int allowShared)
{
DispListMesh *dlm = MEM_callocN(sizeof(*dlm),
"cdDM_convertToDispListMesh dlm");
dlm->totvert = dm->vertData.numElems;
dlm->totedge = dm->edgeData.numElems;
dlm->totface = dm->faceData.numElems;
dlm->mvert = dm->dupVertArray(dm);
dlm->medge = dm->dupEdgeArray(dm);
dlm->mface = dm->dupFaceArray(dm);
dlm->tface = dm->getFaceDataArray(dm, LAYERTYPE_TFACE);
if(dlm->tface)
dlm->tface = MEM_dupallocN(dlm->tface);
dlm->mcol = dm->getFaceDataArray(dm, LAYERTYPE_MCOL);
if(dlm->mcol)
dlm->mcol = MEM_dupallocN(dlm->mcol);
dlm->nors = NULL;
dlm->dontFreeVerts = dlm->dontFreeOther = dlm->dontFreeNors = 0;
return dlm;
}
static void cdDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3])
{
int i;
for(i = 0; i < dm->vertData.numElems; i++) {
DO_MINMAX(CDDM_get_vert(dm, i)->co, min_r, max_r);
}
}
static void cdDM_getVertCo(DerivedMesh *dm, int index, float co_r[3])
{
VECCOPY(co_r, CDDM_get_vert(dm, index)->co);
}
static void cdDM_getVertCos(DerivedMesh *dm, float (*cos_r)[3])
{
int i;
MVert *mv = CDDM_get_verts(dm);
for(i = 0; i < dm->vertData.numElems; i++, mv++)
VECCOPY(cos_r[i], mv->co);
}
static void cdDM_getVertNo(DerivedMesh *dm, int index, float no_r[3])
{
short *no = CDDM_get_vert(dm, index)->no;
no_r[0] = no[0] / 32767.f;
no_r[1] = no[1] / 32767.f;
no_r[2] = no[2] / 32767.f;
}
static void cdDM_drawVerts(DerivedMesh *dm)
{
int i;
MVert *mv = CDDM_get_verts(dm);
glBegin(GL_POINTS);
for(i = 0; i < dm->vertData.numElems; i++, mv++)
glVertex3fv(mv->co);
glEnd();
}
static void cdDM_drawUVEdges(DerivedMesh *dm)
{
int i;
TFace *tf = DM_get_face_data_layer(dm, LAYERTYPE_TFACE);
MFace *mf = CDDM_get_faces(dm);
if(tf) {
glBegin(GL_LINES);
for(i = 0; i < dm->faceData.numElems; i++, tf++, mf++) {
if(!(tf->flag&TF_HIDE)) {
glVertex2fv(tf->uv[0]);
glVertex2fv(tf->uv[1]);
glVertex2fv(tf->uv[1]);
glVertex2fv(tf->uv[2]);
if(!mf->v4) {
glVertex2fv(tf->uv[2]);
glVertex2fv(tf->uv[0]);
} else {
glVertex2fv(tf->uv[2]);
glVertex2fv(tf->uv[3]);
glVertex2fv(tf->uv[3]);
glVertex2fv(tf->uv[0]);
}
}
}
glEnd();
}
}
static void cdDM_drawEdges(DerivedMesh *dm, int drawLooseEdges)
{
int i;
MEdge *medge = CDDM_get_edges(dm);
MVert *mvert = CDDM_get_verts(dm);
glBegin(GL_LINES);
for(i = 0; i < dm->edgeData.numElems; i++, medge++) {
if((medge->flag&ME_EDGEDRAW)
&& (drawLooseEdges || !(medge->flag&ME_LOOSEEDGE))) {
glVertex3fv(mvert[medge->v1].co);
glVertex3fv(mvert[medge->v2].co);
}
}
glEnd();
}
static void cdDM_drawLooseEdges(DerivedMesh *dm)
{
MEdge *medge = CDDM_get_edges(dm);
MVert *mvert = CDDM_get_verts(dm);
int i;
glBegin(GL_LINES);
for(i = 0; i < dm->edgeData.numElems; i++, medge++) {
if(medge->flag&ME_LOOSEEDGE) {
glVertex3fv(mvert[medge->v1].co);
glVertex3fv(mvert[medge->v2].co);
}
}
glEnd();
}
static void cdDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int))
{
int a;
int glmode = -1, shademodel = -1, matnr = -1, drawCurrentMat = 1;
MFace *mface = CDDM_get_faces(dm);
MVert *mvert = CDDM_get_verts(dm);
#define PASSVERT(index) { \
if(shademodel == GL_SMOOTH) { \
short *no = mvert[index].no; \
glNormal3sv(no); \
} \
glVertex3fv(mvert[index].co); \
}
glBegin(glmode = GL_QUADS);
for(a = 0; a < dm->faceData.numElems; a++, mface++) {
int new_glmode, new_matnr, new_shademodel;
new_glmode = mface->v4?GL_QUADS:GL_TRIANGLES;
new_matnr = mface->mat_nr + 1;
new_shademodel = (mface->flag & ME_SMOOTH)?GL_SMOOTH:GL_FLAT;
if(new_glmode != glmode || new_matnr != matnr
|| new_shademodel != shademodel) {
glEnd();
drawCurrentMat = setMaterial(matnr = new_matnr);
glShadeModel(shademodel = new_shademodel);
glBegin(glmode = new_glmode);
}
if(drawCurrentMat) {
/* TODO make this better (cache facenormals as layer?) */
if(shademodel == GL_FLAT) {
float nor[3];
if(mface->v4) {
CalcNormFloat4(mvert[mface->v1].co, mvert[mface->v2].co,
mvert[mface->v3].co, mvert[mface->v4].co,
nor);
} else {
CalcNormFloat(mvert[mface->v1].co, mvert[mface->v2].co,
mvert[mface->v3].co, nor);
}
glNormal3fv(nor);
}
PASSVERT(mface->v1);
PASSVERT(mface->v2);
PASSVERT(mface->v3);
if(mface->v4) {
PASSVERT(mface->v4);
}
}
}
glEnd();
glShadeModel(GL_FLAT);
#undef PASSVERT
}
static void cdDM_drawFacesColored(DerivedMesh *dm, int useTwoSided, unsigned char *col1, unsigned char *col2)
{
int a, glmode;
unsigned char *cp1, *cp2;
MFace *mface = CDDM_get_faces(dm);
MVert *mvert = CDDM_get_verts(dm);
cp1 = col1;
if(col2) {
cp2 = col2;
} else {
cp2 = NULL;
useTwoSided = 0;
}
/* there's a conflict here... twosided colors versus culling...? */
/* defined by history, only texture faces have culling option */
/* we need that as mesh option builtin, next to double sided lighting */
if(col1 && col2)
glEnable(GL_CULL_FACE);
glShadeModel(GL_SMOOTH);
glBegin(glmode = GL_QUADS);
for(a = 0; a < dm->faceData.numElems; a++, mface++, cp1 += 16) {
int new_glmode = mface->v4?GL_QUADS:GL_TRIANGLES;
if(new_glmode != glmode) {
glEnd();
glBegin(glmode = new_glmode);
}
glColor3ub(cp1[3], cp1[2], cp1[1]);
glVertex3fv(mvert[mface->v1].co);
glColor3ub(cp1[7], cp1[6], cp1[5]);
glVertex3fv(mvert[mface->v2].co);
glColor3ub(cp1[11], cp1[10], cp1[9]);
glVertex3fv(mvert[mface->v3].co);
if(mface->v4) {
glColor3ub(cp1[15], cp1[14], cp1[13]);
glVertex3fv(mvert[mface->v4].co);
}
if(useTwoSided) {
glColor3ub(cp2[11], cp2[10], cp2[9]);
glVertex3fv(mvert[mface->v3].co );
glColor3ub(cp2[7], cp2[6], cp2[5]);
glVertex3fv(mvert[mface->v2].co );
glColor3ub(cp2[3], cp2[2], cp2[1]);
glVertex3fv(mvert[mface->v1].co );
if(mface->v4) {
glColor3ub(cp2[15], cp2[14], cp2[13]);
glVertex3fv(mvert[mface->v4].co );
}
}
if(col2) cp2 += 16;
}
glEnd();
glShadeModel(GL_FLAT);
glDisable(GL_CULL_FACE);
}
static void cdDM_drawFacesTex_common(DerivedMesh *dm,
int (*drawParams)(TFace *tface, int matnr),
int (*drawParamsMapped)(void *userData, int index),
void *userData)
{
int i;
MFace *mf = CDDM_get_faces(dm);
TFace *tf = DM_get_face_data_layer(dm, LAYERTYPE_TFACE);
MVert *mv = CDDM_get_verts(dm);
int *index = DM_get_face_data_layer(dm, LAYERTYPE_ORIGINDEX);
for(i = 0; i < dm->faceData.numElems; i++, mf++, index++) {
MVert *mvert;
int flag;
unsigned char *cp = NULL;
if(drawParams)
if(tf) flag = drawParams(&tf[i], mf->mat_nr);
else flag = drawParams(NULL, mf->mat_nr);
else if(*index != ORIGINDEX_NONE)
flag = drawParamsMapped(userData, *index);
else
flag = 0;
if(flag == 0) {
continue;
} else if(flag == 1) {
if(tf) {
cp = (unsigned char *)tf[i].col;
} else {
cp = DM_get_face_data(dm, i, LAYERTYPE_MCOL);
}
}
/* TODO make this better (cache facenormals as layer?) */
if(!(mf->flag&ME_SMOOTH)) {
float nor[3];
if(mf->v4) {
CalcNormFloat4(mv[mf->v1].co, mv[mf->v2].co,
mv[mf->v3].co, mv[mf->v4].co, nor);
} else {
CalcNormFloat(mv[mf->v1].co, mv[mf->v2].co,
mv[mf->v3].co, nor);
}
glNormal3fv(nor);
}
glBegin(mf->v4?GL_QUADS:GL_TRIANGLES);
if(tf) glTexCoord2fv(tf[i].uv[0]);
if(cp) glColor3ub(cp[3], cp[2], cp[1]);
mvert = &mv[mf->v1];
if(mf->flag&ME_SMOOTH) glNormal3sv(mvert->no);
glVertex3fv(mvert->co);
if(tf) glTexCoord2fv(tf[i].uv[1]);
if(cp) glColor3ub(cp[7], cp[6], cp[5]);
mvert = &mv[mf->v2];
if(mf->flag&ME_SMOOTH) glNormal3sv(mvert->no);
glVertex3fv(mvert->co);
if(tf) glTexCoord2fv(tf[i].uv[2]);
if(cp) glColor3ub(cp[11], cp[10], cp[9]);
mvert = &mv[mf->v3];
if(mf->flag&ME_SMOOTH) glNormal3sv(mvert->no);
glVertex3fv(mvert->co);
if(mf->v4) {
if(tf) glTexCoord2fv(tf[i].uv[3]);
if(cp) glColor3ub(cp[15], cp[14], cp[13]);
mvert = &mv[mf->v4];
if(mf->flag&ME_SMOOTH) glNormal3sv(mvert->no);
glVertex3fv(mvert->co);
}
glEnd();
}
}
static void cdDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(TFace *tface, int matnr))
{
cdDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL);
}
static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors)
{
int i;
MFace *mf = CDDM_get_faces(dm);
MVert *mv = CDDM_get_verts(dm);
int *index = DM_get_face_data_layer(dm, LAYERTYPE_ORIGINDEX);
TFace *tf = DM_get_face_data_layer(dm, LAYERTYPE_TFACE);
MCol *mc = DM_get_face_data_layer(dm, LAYERTYPE_MCOL);
for(i = 0; i < dm->faceData.numElems; i++, mf++, index++) {
int drawSmooth = (mf->flag & ME_SMOOTH);
if(setDrawOptions && *index == ORIGINDEX_NONE) continue;
if(!setDrawOptions || setDrawOptions(userData, *index, &drawSmooth)) {
unsigned char *cp = NULL;
if(useColors) {
if(tf) {
cp = (unsigned char *)tf[i].col;
} else if(mc) {
cp = (unsigned char *)&mc[i * 4];
}
}
glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
glBegin(mf->v4?GL_QUADS:GL_TRIANGLES);
if(!drawSmooth) {
/* TODO make this better (cache facenormals as layer?) */
float nor[3];
if(mf->v4) {
CalcNormFloat4(mv[mf->v1].co, mv[mf->v2].co,
mv[mf->v3].co, mv[mf->v4].co, nor);
} else {
CalcNormFloat(mv[mf->v1].co, mv[mf->v2].co,
mv[mf->v3].co, nor);
}
glNormal3fv(nor);
if(cp) glColor3ub(cp[3], cp[2], cp[1]);
glVertex3fv(mv[mf->v1].co);
if(cp) glColor3ub(cp[7], cp[6], cp[5]);
glVertex3fv(mv[mf->v2].co);
if(cp) glColor3ub(cp[11], cp[10], cp[9]);
glVertex3fv(mv[mf->v3].co);
if(mf->v4) {
if(cp) glColor3ub(cp[15], cp[14], cp[13]);
glVertex3fv(mv[mf->v4].co);
}
} else {
if(cp) glColor3ub(cp[3], cp[2], cp[1]);
glNormal3sv(mv[mf->v1].no);
glVertex3fv(mv[mf->v1].co);
if(cp) glColor3ub(cp[7], cp[6], cp[5]);
glNormal3sv(mv[mf->v2].no);
glVertex3fv(mv[mf->v2].co);
if(cp) glColor3ub(cp[11], cp[10], cp[9]);
glNormal3sv(mv[mf->v3].no);
glVertex3fv(mv[mf->v3].co);
if(mf->v4) {
if(cp) glColor3ub(cp[15], cp[14], cp[13]);
glNormal3sv(mv[mf->v4].no);
glVertex3fv(mv[mf->v4].co);
}
}
glEnd();
}
}
}
static void cdDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
{
cdDM_drawFacesTex_common(dm, NULL, setDrawOptions, userData);
}
static void cdDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
{
int i;
int *index = DM_get_edge_data_layer(dm, LAYERTYPE_ORIGINDEX);
MEdge *edge = CDDM_get_edges(dm);
MVert *vert = CDDM_get_verts(dm);
glBegin(GL_LINES);
for(i = 0; i < dm->edgeData.numElems; i++, edge++, index++) {
if(setDrawOptions && *index == ORIGINDEX_NONE) continue;
if(!setDrawOptions || setDrawOptions(userData, *index)) {
glVertex3fv(vert[edge->v1].co);
glVertex3fv(vert[edge->v2].co);
}
}
glEnd();
}
static void cdDM_release(DerivedMesh *dm)
{
CustomData_free(&dm->vertData);
CustomData_free(&dm->edgeData);
CustomData_free(&dm->faceData);
MEM_freeN(dm);
}
/**************** CDDM interface functions ****************/
static DerivedMesh *cdDM_create(const char *desc)
{
DerivedMesh *dm;
dm = MEM_callocN(sizeof(*dm), desc);
dm->getMinMax = cdDM_getMinMax;
dm->convertToDispListMesh = cdDM_convertToDispListMesh;
dm->getNumVerts = cdDM_getNumVerts;
dm->getNumFaces = cdDM_getNumFaces;
dm->getNumEdges = cdDM_getNumEdges;
dm->getVert = cdDM_getVert;
dm->getEdge = cdDM_getEdge;
dm->getFace = cdDM_getFace;
dm->getVertArray = cdDM_getVertArray;
dm->getEdgeArray = cdDM_getEdgeArray;
dm->getFaceArray = cdDM_getFaceArray;
dm->getVertData = DM_get_vert_data;
dm->getEdgeData = DM_get_edge_data;
dm->getFaceData = DM_get_face_data;
dm->getVertDataArray = DM_get_vert_data_layer;
dm->getEdgeDataArray = DM_get_edge_data_layer;
dm->getFaceDataArray = DM_get_face_data_layer;
dm->getVertCos = cdDM_getVertCos;
dm->getVertCo = cdDM_getVertCo;
dm->getVertNo = cdDM_getVertNo;
dm->drawVerts = cdDM_drawVerts;
dm->drawUVEdges = cdDM_drawUVEdges;
dm->drawEdges = cdDM_drawEdges;
dm->drawLooseEdges = cdDM_drawLooseEdges;
dm->drawMappedEdges = cdDM_drawMappedEdges;
dm->drawFacesSolid = cdDM_drawFacesSolid;
dm->drawFacesColored = cdDM_drawFacesColored;
dm->drawFacesTex = cdDM_drawFacesTex;
dm->drawMappedFaces = cdDM_drawMappedFaces;
dm->drawMappedFacesTex = cdDM_drawMappedFacesTex;
dm->foreachMappedVert = cdDM_foreachMappedVert;
dm->foreachMappedEdge = cdDM_foreachMappedEdge;
dm->foreachMappedFaceCenter = cdDM_foreachMappedFaceCenter;
dm->release = cdDM_release;
return dm;
}
DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces)
{
DerivedMesh *dm = cdDM_create("CDDM_new dm");
DM_init(dm, numVerts, numEdges, numFaces);
CustomData_add_layer(&dm->vertData, LAYERTYPE_MVERT, LAYERFLAG_NOCOPY,
NULL);
CustomData_add_layer(&dm->edgeData, LAYERTYPE_MEDGE, LAYERFLAG_NOCOPY,
NULL);
CustomData_add_layer(&dm->faceData, LAYERTYPE_MFACE, LAYERFLAG_NOCOPY,
NULL);
return dm;
}
DerivedMesh *CDDM_from_mesh(Mesh *mesh)
{
DerivedMesh *dm = CDDM_new(mesh->totvert, mesh->totedge, mesh->totface);
int i;
if(mesh->msticky)
CustomData_add_layer(&dm->vertData, LAYERTYPE_MSTICKY, 0, NULL);
if(mesh->dvert)
CustomData_add_layer(&dm->vertData, LAYERTYPE_MDEFORMVERT, 0, NULL);
if(mesh->tface)
CustomData_add_layer(&dm->faceData, LAYERTYPE_TFACE, 0, NULL);
if(mesh->mcol)
CustomData_add_layer(&dm->faceData, LAYERTYPE_MCOL, 0, NULL);
for(i = 0; i < mesh->totvert; ++i) {
DM_set_vert_data(dm, i, LAYERTYPE_MVERT, &mesh->mvert[i]);
if(mesh->msticky)
DM_set_vert_data(dm, i, LAYERTYPE_MSTICKY, &mesh->msticky[i]);
if(mesh->dvert)
DM_set_vert_data(dm, i, LAYERTYPE_MDEFORMVERT, &mesh->dvert[i]);
DM_set_vert_data(dm, i, LAYERTYPE_ORIGINDEX, &i);
}
for(i = 0; i < mesh->totedge; ++i) {
DM_set_edge_data(dm, i, LAYERTYPE_MEDGE, &mesh->medge[i]);
DM_set_edge_data(dm, i, LAYERTYPE_ORIGINDEX, &i);
}
for(i = 0; i < mesh->totface; ++i) {
DM_set_face_data(dm, i, LAYERTYPE_MFACE, &mesh->mface[i]);
if(mesh->tface)
DM_set_face_data(dm, i, LAYERTYPE_TFACE, &mesh->tface[i]);
if(mesh->mcol)
DM_set_face_data(dm, i, LAYERTYPE_MCOL, &mesh->mcol[i * 4]);
DM_set_face_data(dm, i, LAYERTYPE_ORIGINDEX, &i);
}
return dm;
}
DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *me)
{
DerivedMesh *dm = CDDM_new(BLI_countlist(&em->verts),
BLI_countlist(&em->edges),
BLI_countlist(&em->faces));
EditVert *eve;
EditEdge *eed;
EditFace *efa;
MVert *mvert = CDDM_get_verts(dm);
MEdge *medge = CDDM_get_edges(dm);
MFace *mface = CDDM_get_faces(dm);
int i, hassticky = 0, hasdvert = 0, hastface = 0, hasmcol = 0;
int *index;
/* set eve->hash to vert index */
for(i = 0, eve = em->verts.first; eve; eve = eve->next, ++i)
eve->hash = i;
/* check for availability of layers */
if(CustomData_has_layer(&em->vdata, LAYERTYPE_MSTICKY))
hassticky= CustomData_add_layer(&dm->vertData, LAYERTYPE_MSTICKY, 0, NULL);
if(CustomData_has_layer(&em->vdata, LAYERTYPE_MDEFORMVERT))
hasdvert= CustomData_add_layer(&dm->vertData, LAYERTYPE_MDEFORMVERT, 0, NULL);
if(CustomData_has_layer(&em->vdata, LAYERTYPE_TFACE))
hastface= CustomData_add_layer(&dm->vertData, LAYERTYPE_TFACE, 0, NULL);
if(CustomData_has_layer(&em->vdata, LAYERTYPE_MCOL))
hasmcol= CustomData_add_layer(&dm->vertData, LAYERTYPE_MCOL, 0, NULL);
/* Need to be able to mark loose edges */
for(eed = em->edges.first; eed; eed = eed->next) {
eed->f2 = 0;
}
for(efa = em->faces.first; efa; efa = efa->next) {
efa->e1->f2 = 1;
efa->e2->f2 = 1;
efa->e3->f2 = 1;
if(efa->e4) efa->e4->f2 = 1;
}
index = dm->getVertDataArray(dm, LAYERTYPE_ORIGINDEX);
for(i = 0, eve = em->verts.first; i < dm->vertData.numElems;
i++, eve = eve->next, index++) {
MVert *mv = &mvert[i];
VECCOPY(mv->co, eve->co);
mv->no[0] = eve->no[0] * 32767.0;
mv->no[1] = eve->no[1] * 32767.0;
mv->no[2] = eve->no[2] * 32767.0;
mv->mat_nr = 0;
mv->flag = 0;
*index = i;
if(hassticky)
DM_set_vert_data(dm, i, LAYERTYPE_MSTICKY,
CustomData_em_get(&em->vdata, eve->data, LAYERTYPE_MSTICKY));
if(hasdvert)
DM_set_vert_data(dm, i, LAYERTYPE_MDEFORMVERT,
CustomData_em_get(&em->vdata, eve->data, LAYERTYPE_MDEFORMVERT));
}
index = dm->getEdgeDataArray(dm, LAYERTYPE_ORIGINDEX);
for(i = 0, eed = em->edges.first; i < dm->edgeData.numElems;
i++, eed = eed->next, index++) {
MEdge *med = &medge[i];
med->v1 = eed->v1->hash;
med->v2 = eed->v2->hash;
med->crease = (unsigned char) (eed->crease * 255.0f);
med->flag = ME_EDGEDRAW|ME_EDGERENDER;
if(eed->seam) med->flag |= ME_SEAM;
if(eed->sharp) med->flag |= ME_SHARP;
if(!eed->f2) med->flag |= ME_LOOSEEDGE;
*index = i;
}
index = dm->getFaceDataArray(dm, LAYERTYPE_ORIGINDEX);
for(i = 0, efa = em->faces.first; i < dm->faceData.numElems;
i++, efa = efa->next, index++) {
MFace *mf = &mface[i];
mf->v1 = efa->v1->hash;
mf->v2 = efa->v2->hash;
mf->v3 = efa->v3->hash;
mf->v4 = efa->v4 ? efa->v4->hash : 0;
mf->mat_nr = efa->mat_nr;
mf->flag = efa->flag;
test_index_face(mf, NULL, NULL, efa->v4?4:3);
*index = i;
if(hastface)
DM_set_face_data(dm, i, LAYERTYPE_TFACE,
CustomData_em_get(&em->fdata, efa->data, LAYERTYPE_TFACE));
if(hasmcol)
DM_set_face_data(dm, i, LAYERTYPE_MCOL,
CustomData_em_get(&em->fdata, efa->data, LAYERTYPE_MCOL));
}
return dm;
}
DerivedMesh *CDDM_copy(DerivedMesh *source)
{
DerivedMesh *dest = CDDM_from_template(source,
source->vertData.numElems,
source->edgeData.numElems,
source->faceData.numElems);
CustomData_copy_data(&source->vertData, &dest->vertData, 0, 0,
source->vertData.numElems);
CustomData_copy_data(&source->edgeData, &dest->edgeData, 0, 0,
source->edgeData.numElems);
CustomData_copy_data(&source->faceData, &dest->faceData, 0, 0,
source->faceData.numElems);
/* copy vert/face/edge data from source */
source->getVertArray(source, CDDM_get_verts(dest));
source->getEdgeArray(source, CDDM_get_edges(dest));
source->getFaceArray(source, CDDM_get_faces(dest));
return dest;
}
DerivedMesh *CDDM_from_template(DerivedMesh *source,
int numVerts, int numEdges, int numFaces)
{
DerivedMesh *dest = cdDM_create("CDDM_from_template dest");
DM_from_template(dest, source, numVerts, numEdges, numFaces);
/* if no vert/face/edge layers in custom data, add them */
if(!CDDM_get_verts(dest))
CustomData_add_layer(&dest->vertData, LAYERTYPE_MVERT,
LAYERFLAG_NOCOPY, NULL);
if(!CDDM_get_edges(dest))
CustomData_add_layer(&dest->edgeData, LAYERTYPE_MEDGE,
LAYERFLAG_NOCOPY, NULL);
if(!CDDM_get_faces(dest))
CustomData_add_layer(&dest->faceData, LAYERTYPE_MFACE,
LAYERFLAG_NOCOPY, NULL);
return dest;
}
void CDDM_apply_vert_coords(DerivedMesh *dm, float (*vertCoords)[3])
{
int i;
MVert *vert = CDDM_get_verts(dm);
for(i = 0; i < dm->vertData.numElems; ++i, ++vert)
VECCOPY(vert->co, vertCoords[i]);
}
/* adapted from mesh_calc_normals */
void CDDM_calc_normals(DerivedMesh *dm)
{
float (*temp_nors)[3];
float (*face_nors)[3];
int i;
int numVerts = dm->getNumVerts(dm);
int numFaces = dm->getNumFaces(dm);
MFace *mf;
MVert *mv = CDDM_get_verts(dm);
if(!mv) return;
temp_nors = MEM_callocN(numVerts * sizeof(*temp_nors),
"CDDM_calc_normals temp_nors");
face_nors = MEM_mallocN(numFaces * sizeof(*face_nors),
"CDDM_calc_normals face_nors");
mf = CDDM_get_faces(dm);
for(i = 0; i < numFaces; i++, mf++) {
float *f_no = face_nors[i];
if(mf->v4)
CalcNormFloat4(mv[mf->v1].co, mv[mf->v2].co,
mv[mf->v3].co, mv[mf->v4].co, f_no);
else
CalcNormFloat(mv[mf->v1].co, mv[mf->v2].co,
mv[mf->v3].co, f_no);
VecAddf(temp_nors[mf->v1], temp_nors[mf->v1], f_no);
VecAddf(temp_nors[mf->v2], temp_nors[mf->v2], f_no);
VecAddf(temp_nors[mf->v3], temp_nors[mf->v3], f_no);
if(mf->v4)
VecAddf(temp_nors[mf->v4], temp_nors[mf->v4], f_no);
}
for(i = 0; i < numVerts; i++, mv++) {
float *no = temp_nors[i];
if (Normalise(no) == 0.0) {
VECCOPY(no, mv->co);
Normalise(no);
}
mv->no[0] = (short)(no[0] * 32767.0);
mv->no[1] = (short)(no[1] * 32767.0);
mv->no[2] = (short)(no[2] * 32767.0);
}
MEM_freeN(temp_nors);
/* TODO maybe cache face normals here? */
MEM_freeN(face_nors);
}
void CDDM_calc_edges(DerivedMesh *dm)
{
CustomData edgeData;
EdgeHash *eh = BLI_edgehash_new();
EdgeHashIterator *ehi;
int i;
int maxFaces = dm->getNumFaces(dm);
MFace *mf = CDDM_get_faces(dm);
MEdge *med;
for (i = 0; i < maxFaces; i++, mf++) {
if (!BLI_edgehash_haskey(eh, mf->v1, mf->v2))
BLI_edgehash_insert(eh, mf->v1, mf->v2, NULL);
if (!BLI_edgehash_haskey(eh, mf->v2, mf->v3))
BLI_edgehash_insert(eh, mf->v2, mf->v3, NULL);
if (mf->v4) {
if (!BLI_edgehash_haskey(eh, mf->v3, mf->v4))
BLI_edgehash_insert(eh, mf->v3, mf->v4, NULL);
if (!BLI_edgehash_haskey(eh, mf->v4, mf->v1))
BLI_edgehash_insert(eh, mf->v4, mf->v1, NULL);
} else {
if (!BLI_edgehash_haskey(eh, mf->v3, mf->v1))
BLI_edgehash_insert(eh, mf->v3, mf->v1, NULL);
}
}
CustomData_from_template(&dm->edgeData, &edgeData, 0, BLI_edgehash_size(eh));
if(!CustomData_get_layer(&edgeData, LAYERTYPE_MEDGE))
CustomData_add_layer(&edgeData, LAYERTYPE_MEDGE,
LAYERFLAG_NOCOPY, NULL);
ehi = BLI_edgehashIterator_new(eh);
med = CustomData_get_layer(&edgeData, LAYERTYPE_MEDGE);
for(i = 0; !BLI_edgehashIterator_isDone(ehi);
BLI_edgehashIterator_step(ehi), ++i, ++med) {
BLI_edgehashIterator_getKey(ehi, (int*)&med->v1, (int*)&med->v2);
med->flag = ME_EDGEDRAW|ME_EDGERENDER;
}
BLI_edgehashIterator_free(ehi);
CustomData_free(&dm->edgeData);
dm->edgeData = edgeData;
BLI_edgehash_free(eh, NULL);
}
void CDDM_set_num_verts(DerivedMesh *dm, int numVerts)
{
CustomData_set_num_elems(&dm->vertData, numVerts);
}
void CDDM_set_num_edges(DerivedMesh *dm, int numEdges)
{
CustomData_set_num_elems(&dm->edgeData, numEdges);
}
void CDDM_set_num_faces(DerivedMesh *dm, int numFaces)
{
CustomData_set_num_elems(&dm->faceData, numFaces);
}
MVert *CDDM_get_vert(DerivedMesh *dm, int index)
{
return CustomData_get(&dm->vertData, index, LAYERTYPE_MVERT);
}
MEdge *CDDM_get_edge(DerivedMesh *dm, int index)
{
return CustomData_get(&dm->edgeData, index, LAYERTYPE_MEDGE);
}
MFace *CDDM_get_face(DerivedMesh *dm, int index)
{
return CustomData_get(&dm->faceData, index, LAYERTYPE_MFACE);
}
MVert *CDDM_get_verts(DerivedMesh *dm)
{
return CustomData_get_layer(&dm->vertData, LAYERTYPE_MVERT);
}
MEdge *CDDM_get_edges(DerivedMesh *dm)
{
return CustomData_get_layer(&dm->edgeData, LAYERTYPE_MEDGE);
}
MFace *CDDM_get_faces(DerivedMesh *dm)
{
return CustomData_get_layer(&dm->faceData, LAYERTYPE_MFACE);
}