Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2011-12-02 06:18:29 +0400
committerCampbell Barton <ideasman42@gmail.com>2011-12-02 06:18:29 +0400
commit583b1182176a31faaa3891c960dd87b821caa034 (patch)
tree353302bfee94d33d3011f1ee126e1a86bce27060 /source/blender/blenkernel/intern/editderivedmesh.c
parent15ad39e6848ea54da8a3f36b867f8b09a7b8b163 (diff)
file rename, will do the same in trunk to make merges less of a hassle
Diffstat (limited to 'source/blender/blenkernel/intern/editderivedmesh.c')
-rw-r--r--source/blender/blenkernel/intern/editderivedmesh.c1729
1 files changed, 1729 insertions, 0 deletions
diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c
new file mode 100644
index 00000000000..888ebb801d7
--- /dev/null
+++ b/source/blender/blenkernel/intern/editderivedmesh.c
@@ -0,0 +1,1729 @@
+/*
+ * ***** 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 Tbmple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "PIL_time.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_effect_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_key_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_object_fluidsim.h" // N_T
+#include "DNA_scene_types.h" // N_T
+#include "DNA_texture_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_particle_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_editVert.h"
+#include "BLI_edgehash.h"
+#include "BLI_linklist.h"
+#include "BLI_memarena.h"
+#include "BLI_scanfill.h"
+#include "BLI_ghash.h"
+#include "BLI_array.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_customdata.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_deform.h"
+#include "BKE_displist.h"
+#include "BKE_effect.h"
+#include "BKE_fluidsim.h"
+#include "BKE_global.h"
+#include "BKE_key.h"
+#include "BKE_material.h"
+#include "BKE_modifier.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_subsurf.h"
+#include "BKE_texture.h"
+#include "BKE_particle.h"
+#include "BKE_tessmesh.h"
+
+#include "BLO_sys_types.h" // for intptr_t support
+
+#include "GL/glew.h"
+
+#include "GPU_draw.h"
+#include "GPU_extensions.h"
+#include "GPU_material.h"
+
+#include "bmesh.h"
+
+extern GLubyte stipple_quarttone[128]; /* glutil.c, bad level data */
+
+
+BMEditMesh *BMEdit_Create(BMesh *bm)
+{
+ BMEditMesh *tm = MEM_callocN(sizeof(BMEditMesh), __func__);
+
+ tm->bm = bm;
+
+ BMEdit_RecalcTesselation(tm);
+
+ return tm;
+}
+
+BMEditMesh *BMEdit_Copy(BMEditMesh *tm)
+{
+ BMEditMesh *tm2 = MEM_callocN(sizeof(BMEditMesh), __func__);
+ *tm2 = *tm;
+
+ tm2->derivedCage = tm2->derivedFinal = NULL;
+
+ tm2->bm = BM_Copy_Mesh(tm->bm);
+
+ /*The tesselation is NOT calculated on the copy here,
+ because currently all the callers of this function use
+ it to make a backup copy of the BMEditMesh to restore
+ it in the case of errors in an operation. For perf
+ reasons, in that case it makes more sense to do the
+ tesselation only when/if that copy ends up getting
+ used.*/
+ tm2->looptris = NULL;
+
+ tm2->vert_index = NULL;
+ tm2->edge_index = NULL;
+ tm2->face_index = NULL;
+
+ return tm2;
+}
+
+static void BMEdit_RecalcTesselation_intern(BMEditMesh *tm)
+{
+ /* use this to avoid locking pthread for _every_ polygon
+ * and calling the fill function */
+#define USE_TESSFACE_SPEEDUP
+
+ BMesh *bm = tm->bm;
+ BMLoop *(*looptris)[3]= NULL;
+ BLI_array_declare(looptris);
+ BMIter iter, liter;
+ BMFace *f;
+ BMLoop *l;
+ int i = 0, j;
+
+ if (tm->looptris) MEM_freeN(tm->looptris);
+
+ f = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL);
+ for ( ; f; f=BMIter_Step(&iter)) {
+ /*don't consider two-edged faces*/
+ if (f->len < 3) {
+ /* do nothing */
+ }
+
+#ifdef USE_TESSFACE_SPEEDUP
+
+ /* no need to ensure the loop order, we know its ok */
+
+ else if (f->len == 3) {
+ BLI_array_growone(looptris);
+ l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
+ for (j=0; l; l=BMIter_Step(&liter), j++) {
+ looptris[i][j] = l;
+ }
+ i += 1;
+ }
+ else if (f->len == 4) {
+ BMLoop *ltmp[4];
+ BLI_array_growitems(looptris, 2);
+
+ l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
+ for (j=0; l; l=BMIter_Step(&liter), j++) {
+ ltmp[j] = l;
+ }
+
+ looptris[i][0] = ltmp[0];
+ looptris[i][1] = ltmp[1];
+ looptris[i][2] = ltmp[2];
+ i += 1;
+
+ looptris[i][0] = ltmp[0];
+ looptris[i][1] = ltmp[2];
+ looptris[i][2] = ltmp[3];
+ i += 1;
+ }
+
+#endif /* USE_TESSFACE_SPEEDUP */
+
+ else {
+ EditVert *v, *lastv=NULL, *firstv=NULL;
+ EditEdge *e;
+ EditFace *efa;
+
+ BLI_begin_edgefill();
+ /*scanfill time*/
+ l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
+ for (j=0; l; l=BMIter_Step(&liter), j++) {
+ /*mark order*/
+ l->_index = j;
+
+ v = BLI_addfillvert(l->v->co);
+ v->tmp.p = l;
+
+ if (lastv) {
+ e = BLI_addfilledge(lastv, v);
+ }
+
+ lastv = v;
+ if (firstv==NULL) firstv = v;
+ }
+
+ /*complete the loop*/
+ BLI_addfilledge(firstv, v);
+
+ BLI_edgefill(2);
+
+ for (efa = fillfacebase.first; efa; efa=efa->next) {
+ BMLoop *l1= efa->v1->tmp.p;
+ BMLoop *l2= efa->v2->tmp.p;
+ BMLoop *l3= efa->v3->tmp.p;
+
+ BLI_array_growone(looptris);
+
+ if (l1->_index > l2->_index) { SWAP(BMLoop*, l1, l2); }
+ if (l2->_index > l3->_index) { SWAP(BMLoop*, l2, l3); }
+ if (l1->_index > l2->_index) { SWAP(BMLoop*, l1, l2); }
+
+ looptris[i][0] = l1;
+ looptris[i][1] = l2;
+ looptris[i][2] = l3;
+ i += 1;
+ }
+
+ BLI_end_edgefill();
+ }
+ }
+
+ tm->tottri = i;
+ tm->looptris = looptris;
+
+#undef USE_TESSFACE_SPEEDUP
+
+}
+
+void BMEdit_RecalcTesselation(BMEditMesh *em)
+{
+ BMEdit_RecalcTesselation_intern(em);
+
+ if (em->derivedFinal && em->derivedFinal == em->derivedCage) {
+ if (em->derivedFinal->recalcTesselation)
+ em->derivedFinal->recalcTesselation(em->derivedFinal);
+ } else if (em->derivedFinal) {
+ if (em->derivedCage->recalcTesselation)
+ em->derivedCage->recalcTesselation(em->derivedCage);
+ if (em->derivedFinal->recalcTesselation)
+ em->derivedFinal->recalcTesselation(em->derivedFinal);
+ }
+}
+
+void BMEdit_UpdateLinkedCustomData(BMEditMesh *em)
+{
+ BMesh *bm = em->bm;
+ int act;
+
+ if (CustomData_has_layer(&bm->pdata, CD_MTEXPOLY)) {
+ act = CustomData_get_active_layer(&bm->pdata, CD_MTEXPOLY);
+ CustomData_set_layer_active(&bm->ldata, CD_MLOOPUV, act);
+
+ act = CustomData_get_render_layer(&bm->pdata, CD_MTEXPOLY);
+ CustomData_set_layer_render(&bm->ldata, CD_MLOOPUV, act);
+
+ act = CustomData_get_clone_layer(&bm->pdata, CD_MTEXPOLY);
+ CustomData_set_layer_clone(&bm->ldata, CD_MLOOPUV, act);
+
+ act = CustomData_get_stencil_layer(&bm->pdata, CD_MTEXPOLY);
+ CustomData_set_layer_stencil(&bm->ldata, CD_MLOOPUV, act);
+ }
+}
+
+/*does not free the BMEditMesh struct itself*/
+void BMEdit_Free(BMEditMesh *em)
+{
+ if(em->derivedFinal) {
+ if (em->derivedFinal!=em->derivedCage) {
+ em->derivedFinal->needsFree= 1;
+ em->derivedFinal->release(em->derivedFinal);
+ }
+ em->derivedFinal= NULL;
+ }
+ if(em->derivedCage) {
+ em->derivedCage->needsFree= 1;
+ em->derivedCage->release(em->derivedCage);
+ em->derivedCage= NULL;
+ }
+
+ em->retopo_paint_data= NULL;
+
+ if (em->looptris) MEM_freeN(em->looptris);
+
+ if (em->vert_index) MEM_freeN(em->vert_index);
+ if (em->edge_index) MEM_freeN(em->edge_index);
+ if (em->face_index) MEM_freeN(em->face_index);
+
+ if (em->bm)
+ BM_Free_Mesh(em->bm);
+}
+
+/*
+ok, basic design:
+
+the bmesh derivedmesh exposes the mesh as triangles. it stores pointers
+to three loops per triangle. the derivedmesh stores a cache of tesselations
+for each face. this cache will smartly update as needed (though at first
+it'll simply be more brute force). keeping track of face/edge counts may
+be a small problbm.
+
+this won't be the most efficient thing, considering that internal edges and
+faces of tesselations are exposed. looking up an edge by index in particular
+is likely to be a little slow.
+*/
+
+typedef struct EditDerivedBMesh {
+ DerivedMesh dm;
+
+ Object *ob;
+ BMEditMesh *tc;
+
+ float (*vertexCos)[3];
+ float (*vertexNos)[3];
+ float (*faceNos)[3];
+
+ /*lookup caches; these are rebuilt on dm->RecalcTesselation()
+ (or when the derivedmesh is created, of course)*/
+ GHash *vhash, *ehash, *fhash;
+ BMVert **vtable;
+ BMEdge **etable;
+ BMFace **ftable;
+
+ /*private variables, for number of verts/edges/faces
+ within the above hash/table members*/
+ int tv, te, tf;
+} EditDerivedBMesh;
+
+static void bmdm_recalc_lookups(EditDerivedBMesh *bmdm)
+{
+ BMIter iter;
+ BMHeader *h;
+ int a, i, iters[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
+
+ bmdm->tv = bmdm->tc->bm->totvert;
+ bmdm->te = bmdm->tc->bm->totedge;
+ bmdm->tf = bmdm->tc->bm->totface;
+
+ if (bmdm->vhash) BLI_ghash_free(bmdm->vhash, NULL, NULL);
+ if (bmdm->ehash) BLI_ghash_free(bmdm->ehash, NULL, NULL);
+ if (bmdm->fhash) BLI_ghash_free(bmdm->fhash, NULL, NULL);
+
+ bmdm->vhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh derived");
+ bmdm->ehash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh derived");
+ bmdm->fhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh derived");
+
+ if (bmdm->vtable) MEM_freeN(bmdm->vtable);
+ if (bmdm->etable) MEM_freeN(bmdm->etable);
+ if (bmdm->ftable) MEM_freeN(bmdm->ftable);
+
+ if (bmdm->tc->bm->totvert)
+ bmdm->vtable = MEM_mallocN(sizeof(void**)*bmdm->tc->bm->totvert, "bmdm->vtable");
+ else bmdm->vtable = NULL;
+
+ if (bmdm->tc->bm->totedge)
+ bmdm->etable = MEM_mallocN(sizeof(void**)*bmdm->tc->bm->totedge, "bmdm->etable");
+ else bmdm->etable = NULL;
+
+ if (bmdm->tc->bm->totface)
+ bmdm->ftable = MEM_mallocN(sizeof(void**)*bmdm->tc->bm->totface, "bmdm->ftable");
+ else bmdm->ftable = NULL;
+
+ for (a=0; a<3; a++) {
+ h = BMIter_New(&iter, bmdm->tc->bm, iters[a], NULL);
+ for (i=0; h; h=BMIter_Step(&iter), i++) {
+ switch (a) {
+ case 0:
+ bmdm->vtable[i] = (BMVert*) h;
+ BLI_ghash_insert(bmdm->vhash, h, SET_INT_IN_POINTER(i));
+ break;
+ case 1:
+ bmdm->etable[i] = (BMEdge*) h;
+ BLI_ghash_insert(bmdm->ehash, h, SET_INT_IN_POINTER(i));
+ break;
+ case 2:
+ bmdm->ftable[i] = (BMFace*) h;
+ BLI_ghash_insert(bmdm->fhash, h, SET_INT_IN_POINTER(i));
+ break;
+
+ }
+ }
+ }
+}
+
+static void bmDM_calcNormals(DerivedMesh *UNUSED(dm))
+{
+ /* Nothing to do: normals are already calculated and stored on the
+ BMVerts and BMFaces */
+}
+
+static void bmDM_recalcTesselation(DerivedMesh *UNUSED(dm))
+{
+ //EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+
+ //bmdm_recalc_lookups(bmdm);
+}
+
+static void bmDM_foreachMappedVert(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no_f, short *no_s), void *userData)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMVert *eve;
+ BMIter iter;
+ int i;
+
+ eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; i++, eve=BMIter_Step(&iter)) {
+ if (bmdm->vertexCos) {
+ func(userData, i, bmdm->vertexCos[i], bmdm->vertexNos[i], NULL);
+ } else {
+ func(userData, i, eve->co, eve->no, NULL);
+ }
+ }
+}
+static void bmDM_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData, int index, float *v0co, float *v1co), void *userData)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMEdge *eed;
+ BMIter iter;
+ int i;
+
+ if (bmdm->vertexCos) {
+
+ BM_ElemIndex_Ensure(bmdm->tc->bm, BM_VERT);
+
+ eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
+ for(i=0; eed; i++,eed=BMIter_Step(&iter))
+ func(userData, i,
+ bmdm->vertexCos[BM_GetIndex(eed->v1)],
+ bmdm->vertexCos[BM_GetIndex(eed->v2)]);
+ } else {
+ eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
+ for(i=0; eed; i++,eed=BMIter_Step(&iter))
+ func(userData, i, eed->v1->co, eed->v2->co);
+ }
+
+}
+
+static void bmDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMEdge *eed;
+ BMIter iter;
+ int i;
+
+ if (bmdm->vertexCos) {
+
+ BM_ElemIndex_Ensure(bmdm->tc->bm, BM_VERT);
+
+ glBegin(GL_LINES);
+ eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
+ for(i=0; eed; i++,eed=BMIter_Step(&iter)) {
+ if(!setDrawOptions || setDrawOptions(userData, i)) {
+ glVertex3fv(bmdm->vertexCos[BM_GetIndex(eed->v1)]);
+ glVertex3fv(bmdm->vertexCos[BM_GetIndex(eed->v2)]);
+ }
+ }
+ glEnd();
+
+ } else {
+ glBegin(GL_LINES);
+ eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
+ for(i=0; eed; i++,eed=BMIter_Step(&iter)) {
+ if(!setDrawOptions || setDrawOptions(userData, i)) {
+ glVertex3fv(eed->v1->co);
+ glVertex3fv(eed->v2->co);
+ }
+ }
+ glEnd();
+ }
+}
+
+static void bmDM_drawEdges(DerivedMesh *dm, int UNUSED(drawLooseEdges), int UNUSED(drawAllEdges))
+{
+ bmDM_drawMappedEdges(dm, NULL, NULL);
+}
+
+static void bmDM_drawMappedEdgesInterp(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void (*setDrawInterpOptions)(void *userData, int index, float t), void *userData)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMEdge *eed;
+ BMIter iter;
+ int i;
+
+ if (bmdm->vertexCos) {
+
+ BM_ElemIndex_Ensure(bmdm->tc->bm, BM_VERT);
+
+ glBegin(GL_LINES);
+ eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
+ for(i=0; eed; i++,eed=BMIter_Step(&iter)) {
+ if(!setDrawOptions || setDrawOptions(userData, i)) {
+ setDrawInterpOptions(userData, i, 0.0);
+ glVertex3fv(bmdm->vertexCos[(int) BM_GetIndex(eed->v1)]);
+ setDrawInterpOptions(userData, i, 1.0);
+ glVertex3fv(bmdm->vertexCos[(int) BM_GetIndex(eed->v2)]);
+ }
+ }
+ glEnd();
+ } else {
+ glBegin(GL_LINES);
+ eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
+ for(i=0; eed; i++,eed=BMIter_Step(&iter)) {
+ if(!setDrawOptions || setDrawOptions(userData, i)) {
+ setDrawInterpOptions(userData, i, 0.0);
+ glVertex3fv(eed->v1->co);
+ setDrawInterpOptions(userData, i, 1.0);
+ glVertex3fv(eed->v2->co);
+ }
+ }
+ glEnd();
+ }
+}
+
+static void bmDM_drawUVEdges(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMEditMesh *em = bmdm->tc;
+ BMFace *efa;
+ BMIter iter;
+
+ glBegin(GL_LINES);
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ BMIter liter;
+ BMLoop *l;
+ MLoopUV *lastluv = NULL, *firstluv = NULL;
+
+ if (BM_TestHFlag(efa, BM_HIDDEN))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+ if (luv) {
+ if (lastluv)
+ glVertex2fv(luv->uv);
+ glVertex2fv(luv->uv);
+
+ lastluv = luv;
+ if (!firstluv)
+ firstluv = luv;
+ }
+ }
+
+ if (lastluv) {
+ glVertex2fv(lastluv->uv);
+ glVertex2fv(firstluv->uv);
+ }
+ }
+ glEnd();
+}
+
+static void bmDM__calcFaceCent(BMesh *bm, BMFace *efa, float cent[3],
+ float (*vertexCos)[3])
+{
+ BMIter iter;
+ BMLoop *l;
+ int tot = 0;
+
+ zero_v3(cent);
+
+ /*simple (and stupid) median (average) based method :/ */
+
+ if (vertexCos) {
+ l = BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, efa);
+ for (; l; l=BMIter_Step(&iter)) {
+ add_v3_v3(cent, vertexCos[BM_GetIndex(l->v)]);
+ tot++;
+ }
+ } else {
+ l = BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, efa);
+ for (; l; l=BMIter_Step(&iter)) {
+ add_v3_v3(cent, l->v->co);
+ tot++;
+ }
+ }
+
+ if (tot==0) return;
+ mul_v3_fl(cent, 1.0f/(float)tot);
+}
+
+static void bmDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no), void *userData)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMFace *efa;
+ BMIter iter;
+ float cent[3];
+ int i;
+
+ if (bmdm->vertexCos) {
+ BM_ElemIndex_Ensure(bmdm->tc->bm, BM_VERT);
+ }
+
+ efa = BMIter_New(&iter, bmdm->tc->bm, BM_FACES_OF_MESH, NULL);
+ for (i=0; efa; efa=BMIter_Step(&iter), i++) {
+ bmDM__calcFaceCent(bmdm->tc->bm, efa, cent, bmdm->vertexCos);
+ func(userData, i, cent, bmdm->vertexCos?bmdm->faceNos[i]:efa->no);
+ }
+}
+
+static void bmDM_drawMappedFaces(DerivedMesh *dm,
+ int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r),
+ int (*setMaterial)(int, void *attribs),
+ int (*compareDrawOptions)(void *userData, int cur_index, int next_index),
+ void *userData, int UNUSED(useColors))
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMFace *efa;
+ int i, draw;
+
+ const int skip_normals= !glIsEnabled(GL_LIGHTING); /* could be passed as an arg */
+
+ /* GL_ZERO is used to detect if drawing has started or not */
+ GLenum poly_prev= GL_ZERO;
+ GLenum shade_prev= GL_ZERO;
+
+ (void)setMaterial; /* UNUSED */
+
+ /* currently unused -- each original face is handled separately */
+ (void)compareDrawOptions;
+
+ if (bmdm->vertexCos) {
+ /* add direct access */
+ float (*vertexCos)[3]= bmdm->vertexCos;
+ float (*vertexNos)[3]= bmdm->vertexNos;
+ float (*faceNos)[3]= bmdm->faceNos;
+
+ BM_ElemIndex_Ensure(bmdm->tc->bm, BM_VERT | BM_FACE);
+
+ for (i=0; i<bmdm->tc->tottri; i++) {
+ BMLoop **l = bmdm->tc->looptris[i];
+ int drawSmooth;
+
+ efa = l[0]->f;
+ drawSmooth= BM_TestHFlag(efa, BM_SMOOTH);
+
+ draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, BM_GetIndex(efa), &drawSmooth);
+ if(draw) {
+ const GLenum poly_type= GL_TRIANGLES; /* BMESH NOTE, this is odd but keep it for now to match trunk */
+ if (draw==2) { /* enabled with stipple */
+
+ if(poly_prev != GL_ZERO) glEnd();
+ poly_prev= GL_ZERO; /* force glBegin */
+
+ glEnable(GL_POLYGON_STIPPLE);
+ glPolygonStipple(stipple_quarttone);
+ }
+
+ if(skip_normals) {
+ if(poly_type != poly_prev) {
+ if(poly_prev != GL_ZERO) glEnd();
+ glBegin((poly_prev= poly_type)); /* BMesh: will always be GL_TRIANGLES */
+ }
+ glVertex3fv(vertexCos[(int) BM_GetIndex(l[0]->v)]);
+ glVertex3fv(vertexCos[(int) BM_GetIndex(l[1]->v)]);
+ glVertex3fv(vertexCos[(int) BM_GetIndex(l[2]->v)]);
+ }
+ else {
+ const GLenum shade_type= drawSmooth ? GL_SMOOTH : GL_FLAT;
+ if (shade_type != shade_prev) {
+ if(poly_prev != GL_ZERO) glEnd();
+ glShadeModel((shade_prev= shade_type)); /* same as below but switch shading */
+ glBegin((poly_prev= poly_type)); /* BMesh: will always be GL_TRIANGLES */
+ }
+ if(poly_type != poly_prev) {
+ if(poly_prev != GL_ZERO) glEnd();
+ glBegin((poly_prev= poly_type)); /* BMesh: will always be GL_TRIANGLES */
+ }
+
+ if (!drawSmooth) {
+ glNormal3fv(faceNos[i]);
+ glVertex3fv(vertexCos[(int) BM_GetIndex(l[0]->v)]);
+ glVertex3fv(vertexCos[(int) BM_GetIndex(l[1]->v)]);
+ glVertex3fv(vertexCos[(int) BM_GetIndex(l[2]->v)]);
+ } else {
+ glNormal3fv(vertexNos[(int) BM_GetIndex(l[0]->v)]);
+ glVertex3fv(vertexCos[(int) BM_GetIndex(l[0]->v)]);
+ glNormal3fv(vertexNos[(int) BM_GetIndex(l[1]->v)]);
+ glVertex3fv(vertexCos[(int) BM_GetIndex(l[1]->v)]);
+ glNormal3fv(vertexNos[(int) BM_GetIndex(l[2]->v)]);
+ glVertex3fv(vertexCos[(int) BM_GetIndex(l[2]->v)]);
+ }
+ }
+
+ if (draw==2) {
+ glEnd();
+ poly_prev= GL_ZERO; /* force glBegin */
+
+ glDisable(GL_POLYGON_STIPPLE);
+ }
+ }
+ }
+ } else {
+ BM_ElemIndex_Ensure(bmdm->tc->bm, BM_FACE);
+
+ for (i=0; i<bmdm->tc->tottri; i++) {
+ BMLoop **l = bmdm->tc->looptris[i];
+ int drawSmooth;
+
+ efa = l[0]->f;
+ drawSmooth= BM_TestHFlag(efa, BM_SMOOTH);
+
+ draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, BM_GetIndex(efa), &drawSmooth);
+ if(draw) {
+ const GLenum poly_type= GL_TRIANGLES; /* BMESH NOTE, this is odd but keep it for now to match trunk */
+ if (draw==2) { /* enabled with stipple */
+
+ if(poly_prev != GL_ZERO) glEnd();
+ poly_prev= GL_ZERO; /* force glBegin */
+
+ glEnable(GL_POLYGON_STIPPLE);
+ glPolygonStipple(stipple_quarttone);
+ }
+
+ if(skip_normals) {
+ if(poly_type != poly_prev) {
+ if(poly_prev != GL_ZERO) glEnd();
+ glBegin((poly_prev= poly_type)); /* BMesh: will always be GL_TRIANGLES */
+ }
+ glVertex3fv(l[0]->v->co);
+ glVertex3fv(l[1]->v->co);
+ glVertex3fv(l[2]->v->co);
+ }
+ else {
+ const GLenum shade_type= drawSmooth ? GL_SMOOTH : GL_FLAT;
+ if (shade_type != shade_prev) {
+ if(poly_prev != GL_ZERO) glEnd();
+ glShadeModel((shade_prev= shade_type)); /* same as below but switch shading */
+ glBegin((poly_prev= poly_type)); /* BMesh: will always be GL_TRIANGLES */
+ }
+ if(poly_type != poly_prev) {
+ if(poly_prev != GL_ZERO) glEnd();
+ glBegin((poly_prev= poly_type)); /* BMesh: will always be GL_TRIANGLES */
+ }
+
+ if (!drawSmooth) {
+ glNormal3fv(efa->no);
+ glVertex3fv(l[0]->v->co);
+ glVertex3fv(l[1]->v->co);
+ glVertex3fv(l[2]->v->co);
+ } else {
+ glNormal3fv(l[0]->v->no);
+ glVertex3fv(l[0]->v->co);
+ glNormal3fv(l[1]->v->no);
+ glVertex3fv(l[1]->v->co);
+ glNormal3fv(l[2]->v->no);
+ glVertex3fv(l[2]->v->co);
+ }
+ }
+ if (draw==2) {
+ glEnd();
+ poly_prev= GL_ZERO; /* force glBegin */
+
+ glDisable(GL_POLYGON_STIPPLE);
+ }
+ }
+ }
+ }
+
+ /* if non zero we know a face was rendered */
+ if(poly_prev != GL_ZERO) glEnd();
+}
+
+static void bmdm_get_tri_tex(BMesh *bm, BMLoop **ls, MLoopUV *luv[3], MLoopCol *lcol[3],
+ int has_uv, int has_col)
+{
+ if (has_uv) {
+ luv[0] = CustomData_bmesh_get(&bm->ldata, ls[0]->head.data, CD_MLOOPUV);
+ luv[1] = CustomData_bmesh_get(&bm->ldata, ls[1]->head.data, CD_MLOOPUV);
+ luv[2] = CustomData_bmesh_get(&bm->ldata, ls[2]->head.data, CD_MLOOPUV);
+ }
+
+ if (has_col) {
+ lcol[0] = CustomData_bmesh_get(&bm->ldata, ls[0]->head.data, CD_MLOOPCOL);
+ lcol[1] = CustomData_bmesh_get(&bm->ldata, ls[1]->head.data, CD_MLOOPCOL);
+ lcol[2] = CustomData_bmesh_get(&bm->ldata, ls[2]->head.data, CD_MLOOPCOL);
+ }
+
+
+}
+
+static void bmDM_drawFacesTex_common(DerivedMesh *dm,
+ int (*drawParams)(MTFace *tface, int has_vcol, int matnr),
+ int (*drawParamsMapped)(void *userData, int index),
+ int (*compareDrawOptions)(void *userData, int cur_index, int next_index),
+ void *userData)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMEditMesh *em = bmdm->tc;
+ BMesh *bm= bmdm->tc->bm;
+ float (*vertexCos)[3]= bmdm->vertexCos;
+ float (*vertexNos)[3]= bmdm->vertexNos;
+ BMFace *efa;
+ MLoopUV *luv[3], dummyluv = {{0}};
+ MLoopCol *lcol[3], dummylcol = {0};
+ int i, has_vcol = CustomData_has_layer(&bm->ldata, CD_MLOOPCOL);
+ int has_uv = CustomData_has_layer(&bm->pdata, CD_MTEXPOLY);
+
+ (void) compareDrawOptions;
+
+ luv[0] = luv[1] = luv[2] = &dummyluv;
+ lcol[0] = lcol[1] = lcol[2] = &dummylcol;
+
+ dummylcol.a = dummylcol.r = dummylcol.g = dummylcol.b = 255;
+
+ /* always use smooth shading even for flat faces, else vertex colors wont interpolate */
+ glShadeModel(GL_SMOOTH);
+
+ BM_ElemIndex_Ensure(bm, BM_FACE);
+
+ if (vertexCos) {
+ BM_ElemIndex_Ensure(bm, BM_VERT);
+
+ glBegin(GL_TRIANGLES);
+ for (i=0; i<em->tottri; i++) {
+ BMLoop **ls = em->looptris[i];
+ MTexPoly *tp= CustomData_bmesh_get(&bm->pdata, ls[0]->f->head.data, CD_MTEXPOLY);
+ MTFace mtf = {{{0}}};
+ /*unsigned char *cp= NULL;*/ /*UNUSED*/
+ int drawSmooth= BM_TestHFlag(ls[0]->f, BM_SMOOTH);
+ int flag;
+
+ efa = ls[0]->f;
+
+ if (has_uv) {
+ mtf.flag = tp->flag;
+ mtf.tpage = tp->tpage;
+ mtf.transp = tp->transp;
+ mtf.mode = tp->mode;
+ mtf.tile = tp->tile;
+ mtf.unwrap = tp->unwrap;
+ }
+
+ if(drawParams)
+ flag= drawParams(&mtf, has_vcol, efa->mat_nr);
+ else if(drawParamsMapped)
+ flag= drawParamsMapped(userData, BM_GetIndex(efa));
+ else
+ flag= 1;
+
+ if(flag != 0) { /* flag 0 == the face is hidden or invisible */
+
+ /* we always want smooth here since otherwise vertex colors dont interpolate */
+ if (!has_vcol) {
+ glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
+ }
+
+ if (!drawSmooth) {
+ glNormal3fv(bmdm->faceNos[i]);
+
+ bmdm_get_tri_tex(bm, ls, luv, lcol, has_uv, has_vcol);
+
+ glTexCoord2fv(luv[0]->uv);
+ glColor3ub(lcol[0]->b, lcol[0]->g, lcol[0]->r);
+ glVertex3fv(vertexCos[BM_GetIndex(ls[0]->v)]);
+
+ glTexCoord2fv(luv[1]->uv);
+ glColor3ub(lcol[1]->b, lcol[1]->g, lcol[1]->r);
+ glVertex3fv(vertexCos[BM_GetIndex(ls[1]->v)]);
+
+ glTexCoord2fv(luv[2]->uv);
+ glColor3ub(lcol[2]->b, lcol[2]->g, lcol[2]->r);
+ glVertex3fv(vertexCos[BM_GetIndex(ls[2]->v)]);
+ } else {
+ bmdm_get_tri_tex(bm, ls, luv, lcol, has_uv, has_vcol);
+
+ glTexCoord2fv(luv[0]->uv);
+ glColor3ub(lcol[0]->b, lcol[0]->g, lcol[0]->r);
+ glNormal3fv(vertexNos[BM_GetIndex(ls[0]->v)]);
+ glVertex3fv(vertexCos[BM_GetIndex(ls[0]->v)]);
+
+ glTexCoord2fv(luv[1]->uv);
+ glColor3ub(lcol[1]->b, lcol[1]->g, lcol[1]->r);
+ glNormal3fv(vertexNos[BM_GetIndex(ls[1]->v)]);
+ glVertex3fv(vertexCos[BM_GetIndex(ls[1]->v)]);
+
+ glTexCoord2fv(luv[2]->uv);
+ glColor3ub(lcol[2]->b, lcol[2]->g, lcol[2]->r);
+ glNormal3fv(vertexNos[BM_GetIndex(ls[2]->v)]);
+ glVertex3fv(vertexCos[BM_GetIndex(ls[2]->v)]);
+ }
+ }
+ }
+ glEnd();
+ } else {
+ BM_ElemIndex_Ensure(bm, BM_VERT);
+
+ for (i=0; i<em->tottri; i++) {
+ BMLoop **ls = em->looptris[i];
+ MTexPoly *tp= CustomData_bmesh_get(&bm->pdata, ls[0]->f->head.data, CD_MTEXPOLY);
+ MTFace mtf = {{{0}}};
+ /*unsigned char *cp= NULL;*/ /*UNUSED*/
+ int drawSmooth= BM_TestHFlag(ls[0]->f, BM_SMOOTH);
+ int flag;
+
+ efa = ls[0]->f;
+
+ if (has_uv) {
+ mtf.flag = tp->flag;
+ mtf.tpage = tp->tpage;
+ mtf.transp = tp->transp;
+ mtf.mode = tp->mode;
+ mtf.tile = tp->tile;
+ mtf.unwrap = tp->unwrap;
+ }
+
+ if(drawParams)
+ flag= drawParams(&mtf, has_vcol, efa->mat_nr);
+ else if(drawParamsMapped)
+ flag= drawParamsMapped(userData, BM_GetIndex(efa));
+ else
+ flag= 1;
+
+ if(flag != 0) { /* flag 0 == the face is hidden or invisible */
+
+ /* we always want smooth here since otherwise vertex colors dont interpolate */
+ if (!has_vcol) {
+ glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
+ }
+
+ glBegin(GL_TRIANGLES);
+ if (!drawSmooth) {
+ glNormal3fv(efa->no);
+
+ bmdm_get_tri_tex(bm, ls, luv, lcol, has_uv, has_vcol);
+
+ if (luv[0])
+ glTexCoord2fv(luv[0]->uv);
+ if (lcol[0])
+ glColor3ub(lcol[0]->b, lcol[0]->g, lcol[0]->r);
+ else glColor3ub(0, 0, 0);
+ glVertex3fv(ls[0]->v->co);
+
+ if (luv[1])
+ glTexCoord2fv(luv[1]->uv);
+ if (lcol[1])
+ glColor3ub(lcol[1]->b, lcol[1]->g, lcol[1]->r);
+ else glColor3ub(0, 0, 0);
+ glVertex3fv(ls[1]->v->co);
+
+ if (luv[2])
+ glTexCoord2fv(luv[2]->uv);
+ if (lcol[2])
+ glColor3ub(lcol[2]->b, lcol[2]->g, lcol[2]->r);
+ else glColor3ub(0, 0, 0);
+ glVertex3fv(ls[2]->v->co);
+ } else {
+ bmdm_get_tri_tex(bm, ls, luv, lcol, has_uv, has_vcol);
+
+ if (luv[0])
+ glTexCoord2fv(luv[0]->uv);
+ if (lcol[0])
+ glColor3ub(lcol[0]->b, lcol[0]->g, lcol[0]->r);
+ else glColor3ub(0, 0, 0);
+ glNormal3fv(ls[0]->v->no);
+ glVertex3fv(ls[0]->v->co);
+
+ if (luv[1])
+ glTexCoord2fv(luv[1]->uv);
+ if (lcol[1])
+ glColor3ub(lcol[1]->b, lcol[1]->g, lcol[1]->r);
+ else glColor3ub(0, 0, 0);
+ glNormal3fv(ls[1]->v->no);
+ glVertex3fv(ls[1]->v->co);
+
+ if (luv[2])
+ glTexCoord2fv(luv[2]->uv);
+ if (lcol[2])
+ glColor3ub(lcol[2]->b, lcol[2]->g, lcol[2]->r);
+ else glColor3ub(0, 0, 0);
+ glNormal3fv(ls[2]->v->no);
+ glVertex3fv(ls[2]->v->co);
+ }
+ glEnd();
+ }
+ }
+ }
+}
+
+static void bmDM_drawFacesTex(DerivedMesh *dm,
+ int (*setDrawOptions)(MTFace *tface, int has_vcol, int matnr),
+ int (*compareDrawOptions)(void *userData, int cur_index, int next_index),
+ void *userData)
+{
+ bmDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData);
+}
+
+static void bmDM_drawMappedFacesTex(DerivedMesh *dm,
+ int (*setDrawOptions)(void *userData, int index),
+ int (*compareDrawOptions)(void *userData, int cur_index, int next_index),
+ void *userData)
+{
+ bmDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData);
+}
+
+static void bmDM_drawMappedFacesGLSL(DerivedMesh *dm,
+ int (*setMaterial)(int, void *attribs),
+ int (*setDrawOptions)(void *userData, int index),
+ void *userData)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMesh *bm= bmdm->tc->bm;
+ BMEditMesh *em = bmdm->tc;
+ float (*vertexCos)[3]= bmdm->vertexCos;
+ float (*vertexNos)[3]= bmdm->vertexNos;
+ BMFace *efa;
+ BMLoop **ltri;
+ DMVertexAttribs attribs;
+ GPUVertexAttribs gattribs;
+
+ int i, b, matnr, new_matnr, dodraw;
+
+ dodraw = 0;
+ matnr = -1;
+
+ memset(&attribs, 0, sizeof(attribs));
+
+ /* always use smooth shading even for flat faces, else vertex colors wont interpolate */
+ glShadeModel(GL_SMOOTH);
+ BM_ElemIndex_Ensure(bm, BM_VERT | BM_FACE);
+
+#define PASSATTRIB(loop, eve, vert) { \
+ if(attribs.totorco) { \
+ float *orco = attribs.orco.array[BM_GetIndex(eve)]; \
+ glVertexAttrib3fvARB(attribs.orco.glIndex, orco); \
+ } \
+ for(b = 0; b < attribs.tottface; b++) { \
+ MLoopUV *_luv = CustomData_bmesh_get_n(&bm->ldata, loop->head.data, CD_MLOOPUV, b);\
+ glVertexAttrib2fvARB(attribs.tface[b].glIndex, _luv->uv); \
+ } \
+ for(b = 0; b < attribs.totmcol; b++) { \
+ MLoopCol *_cp = CustomData_bmesh_get_n(&bm->ldata, loop->head.data, CD_MLOOPCOL, b);\
+ GLubyte _col[4]; \
+ _col[0]= _cp->b; _col[1]= _cp->g; _col[2]= _cp->r; _col[3]= _cp->a; \
+ glVertexAttrib4ubvARB(attribs.mcol[b].glIndex, _col); \
+ } \
+ if(attribs.tottang) { \
+ float *tang = attribs.tang.array[i*4 + vert]; \
+ glVertexAttrib3fvARB(attribs.tang.glIndex, tang); \
+ } \
+ }
+
+
+ for (i=0, ltri=em->looptris[0]; i<em->tottri; i++, ltri += 3) {
+ int drawSmooth;
+
+ efa = ltri[0]->f;
+ drawSmooth= BM_TestHFlag(efa, BM_SMOOTH);
+
+ if(setDrawOptions && !setDrawOptions(userData, BM_GetIndex(efa)))
+ continue;
+
+ new_matnr = efa->mat_nr + 1;
+ if(new_matnr != matnr) {
+ dodraw = setMaterial(matnr = new_matnr, &gattribs);
+ if(dodraw)
+ DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
+ }
+
+ if(dodraw) {
+ glBegin(GL_TRIANGLES);
+ if (!drawSmooth) {
+ if(vertexCos) glNormal3fv(bmdm->faceNos[i]);
+ else glNormal3fv(efa->no);
+
+ PASSATTRIB(ltri[0], ltri[0]->v, 0);
+ if(vertexCos) glVertex3fv(vertexCos[BM_GetIndex(ltri[0]->v)]);
+ else glVertex3fv(ltri[0]->v->co);
+
+ PASSATTRIB(ltri[1], ltri[1]->v, 1);
+ if(vertexCos) glVertex3fv(vertexCos[BM_GetIndex(ltri[1]->v)]);
+ else glVertex3fv(ltri[1]->v->co);
+
+ PASSATTRIB(ltri[2], ltri[2]->v, 2);
+ if(vertexCos) glVertex3fv(vertexCos[BM_GetIndex(ltri[2]->v)]);
+ else glVertex3fv(ltri[2]->v->co);
+ } else {
+ PASSATTRIB(ltri[0], ltri[0]->v, 0);
+ if(vertexCos) {
+ glNormal3fv(vertexNos[BM_GetIndex(ltri[0]->v)]);
+ glVertex3fv(vertexCos[BM_GetIndex(ltri[0]->v)]);
+ }
+ else {
+ glNormal3fv(ltri[0]->v->no);
+ glVertex3fv(ltri[0]->v->co);
+ }
+
+ PASSATTRIB(ltri[1], ltri[1]->v, 1);
+ if(vertexCos) {
+ glNormal3fv(vertexNos[BM_GetIndex(ltri[1]->v)]);
+ glVertex3fv(vertexCos[BM_GetIndex(ltri[1]->v)]);
+ }
+ else {
+ glNormal3fv(ltri[1]->v->no);
+ glVertex3fv(ltri[1]->v->co);
+ }
+
+ PASSATTRIB(ltri[2], ltri[2]->v, 2);
+ if(vertexCos) {
+ glNormal3fv(vertexNos[BM_GetIndex(ltri[2]->v)]);
+ glVertex3fv(vertexCos[BM_GetIndex(ltri[2]->v)]);
+ }
+ else {
+ glNormal3fv(ltri[2]->v->no);
+ glVertex3fv(ltri[2]->v->co);
+ }
+ }
+ glEnd();
+ }
+ }
+#undef PASSATTRIB
+}
+
+static void bmDM_drawFacesGLSL(DerivedMesh *dm,
+ int (*setMaterial)(int, void *attribs))
+{
+ dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL);
+}
+
+
+static void bmDM_drawMappedFacesMat(DerivedMesh *dm,
+ void (*setMaterial)(void *userData, int, void *attribs),
+ int (*setFace)(void *userData, int index), void *userData)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMesh *bm= bmdm->tc->bm;
+ BMEditMesh *em = bmdm->tc;
+ float (*vertexCos)[3]= bmdm->vertexCos;
+ float (*vertexNos)[3]= bmdm->vertexNos;
+ BMFace *efa;
+ BMLoop **ltri;
+ DMVertexAttribs attribs= {{{0}}};
+ GPUVertexAttribs gattribs;
+ int i, b, matnr, new_matnr;
+
+ matnr = -1;
+
+ /* always use smooth shading even for flat faces, else vertex colors wont interpolate */
+ glShadeModel(GL_SMOOTH);
+
+ BM_ElemIndex_Ensure(bm, BM_VERT);
+
+#define PASSATTRIB(loop, eve, vert) { \
+ if(attribs.totorco) { \
+ float *orco = attribs.orco.array[BM_GetIndex(eve)]; \
+ glVertexAttrib3fvARB(attribs.orco.glIndex, orco); \
+ } \
+ for(b = 0; b < attribs.tottface; b++) { \
+ MLoopUV *_luv = CustomData_bmesh_get_n(&bm->ldata, loop->head.data, CD_MLOOPUV, b);\
+ glVertexAttrib2fvARB(attribs.tface[b].glIndex, _luv->uv); \
+ } \
+ for(b = 0; b < attribs.totmcol; b++) { \
+ MLoopCol *_cp = CustomData_bmesh_get_n(&bm->ldata, loop->head.data, CD_MLOOPCOL, b);\
+ GLubyte _col[4]; \
+ _col[0]= _cp->b; _col[1]= _cp->g; _col[2]= _cp->r; _col[3]= _cp->a; \
+ glVertexAttrib4ubvARB(attribs.mcol[b].glIndex, _col); \
+ } \
+ if(attribs.tottang) { \
+ float *tang = attribs.tang.array[i*4 + vert]; \
+ glVertexAttrib4fvARB(attribs.tang.glIndex, tang); \
+ } \
+}
+
+ for (i=0, ltri=em->looptris[0]; i<em->tottri; i++, ltri += 3) {
+ int drawSmooth;
+
+ efa = ltri[0]->f;
+ drawSmooth = BM_TestHFlag(efa, BM_SMOOTH);
+
+ /* face hiding */
+ if(setFace && !setFace(userData, BM_GetIndex(efa)))
+ continue;
+
+ /* material */
+ new_matnr = efa->mat_nr + 1;
+ if(new_matnr != matnr) {
+ setMaterial(userData, matnr = new_matnr, &gattribs);
+ DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
+ }
+
+ /* face */
+ glBegin(GL_TRIANGLES);
+ if (!drawSmooth) {
+ if(vertexCos) glNormal3fv(bmdm->faceNos[i]);
+ else glNormal3fv(efa->no);
+
+ PASSATTRIB(ltri[0], ltri[0]->v, 0);
+ if(vertexCos) glVertex3fv(vertexCos[BM_GetIndex(ltri[0]->v)]);
+ else glVertex3fv(ltri[0]->v->co);
+
+ PASSATTRIB(ltri[1], ltri[1]->v, 1);
+ if(vertexCos) glVertex3fv(vertexCos[BM_GetIndex(ltri[1]->v)]);
+ else glVertex3fv(ltri[1]->v->co);
+
+ PASSATTRIB(ltri[2], ltri[2]->v, 2);
+ if(vertexCos) glVertex3fv(vertexCos[BM_GetIndex(ltri[2]->v)]);
+ else glVertex3fv(ltri[2]->v->co);
+
+ } else {
+ PASSATTRIB(ltri[0], ltri[0]->v, 0);
+ if(vertexCos) {
+ glNormal3fv(vertexNos[BM_GetIndex(ltri[0]->v)]);
+ glVertex3fv(vertexCos[BM_GetIndex(ltri[0]->v)]);
+ }
+ else {
+ glNormal3fv(ltri[0]->v->no);
+ glVertex3fv(ltri[0]->v->co);
+ }
+
+ PASSATTRIB(ltri[1], ltri[1]->v, 1);
+ if(vertexCos) {
+ glNormal3fv(vertexNos[BM_GetIndex(ltri[1]->v)]);
+ glVertex3fv(vertexCos[BM_GetIndex(ltri[1]->v)]);
+ }
+ else {
+ glNormal3fv(ltri[1]->v->no);
+ glVertex3fv(ltri[1]->v->co);
+ }
+
+ PASSATTRIB(ltri[2], ltri[2]->v, 2);
+ if(vertexCos) {
+ glNormal3fv(vertexNos[BM_GetIndex(ltri[2]->v)]);
+ glVertex3fv(vertexCos[BM_GetIndex(ltri[2]->v)]);
+ }
+ else {
+ glNormal3fv(ltri[2]->v->no);
+ glVertex3fv(ltri[2]->v->co);
+ }
+ }
+ glEnd();
+ }
+#undef PASSATTRIB
+}
+
+static void bmDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3])
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMVert *eve;
+ BMIter iter;
+ int i;
+
+ if (bmdm->tc->bm->totvert) {
+ eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&iter), i++) {
+ if (bmdm->vertexCos) {
+ DO_MINMAX(bmdm->vertexCos[i], min_r, max_r);
+ } else {
+ DO_MINMAX(eve->co, min_r, max_r);
+ }
+ }
+ } else {
+ min_r[0] = min_r[1] = min_r[2] = max_r[0] = max_r[1] = max_r[2] = 0.0;
+ }
+}
+static int bmDM_getNumVerts(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+
+ return bmdm->tc->bm->totvert;
+}
+
+static int bmDM_getNumEdges(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+
+ return bmdm->tc->bm->totedge;
+}
+
+static int bmDM_getNumTessFaces(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+
+ return bmdm->tc->tottri;
+}
+
+static int bmDM_getNumLoops(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+
+ return bmdm->tc->bm->totloop;
+}
+
+static int bmDM_getNumPolys(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+
+ return bmdm->tc->bm->totface;
+}
+
+static int bmvert_to_mvert(BMesh *bm, BMVert *ev, MVert *vert_r)
+{
+ copy_v3_v3(vert_r->co, ev->co);
+
+ normal_float_to_short_v3(vert_r->no, ev->no);
+
+ vert_r->flag = BM_Vert_Flag_To_MEFlag(ev);
+
+ if (CustomData_has_layer(&bm->vdata, CD_BWEIGHT)) {
+ vert_r->bweight = (unsigned char) (BM_GetCDf(&bm->vdata, ev, CD_BWEIGHT)*255.0f);
+ }
+
+ return 1;
+}
+
+static void bmDM_getVert(DerivedMesh *dm, int index, MVert *vert_r)
+{
+ BMVert *ev;
+
+ if (index < 0 || index >= ((EditDerivedBMesh *)dm)->tv) {
+ printf("error in bmDM_getVert.\n");
+ return;
+ }
+
+ ev = ((EditDerivedBMesh *)dm)->vtable[index];
+ bmvert_to_mvert(((EditDerivedBMesh *)dm)->tc->bm, ev, vert_r);
+}
+
+static void bmDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r)
+{
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
+ BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
+ BMEdge *e;
+
+ if (index < 0 || index >= ((EditDerivedBMesh *)dm)->te) {
+ printf("error in bmDM_getEdge.\n");
+ return;
+ }
+
+ e = bmdm->etable[index];
+
+ if (CustomData_has_layer(&bm->edata, CD_BWEIGHT)) {
+ edge_r->bweight = (unsigned char) (BM_GetCDf(&bm->edata, e, CD_BWEIGHT)*255.0f);
+ }
+
+ if (CustomData_has_layer(&bm->edata, CD_CREASE)) {
+ edge_r->crease = (unsigned char) (BM_GetCDf(&bm->edata, e, CD_CREASE)*255.0f);
+ }
+
+ edge_r->flag = BM_Edge_Flag_To_MEFlag(e);
+
+ edge_r->v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, e->v1));
+ edge_r->v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, e->v2));
+}
+
+static void bmDM_getTessFace(DerivedMesh *dm, int index, MFace *face_r)
+{
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
+ BMFace *ef;
+ BMLoop **l;
+
+ if (index < 0 || index >= ((EditDerivedBMesh *)dm)->tf) {
+ printf("error in bmDM_getTessFace.\n");
+ return;
+ }
+
+ l = ((EditDerivedBMesh *)dm)->tc->looptris[index];
+
+ ef = l[0]->f;
+
+ face_r->mat_nr = (unsigned char) ef->mat_nr;
+ face_r->flag = BM_Face_Flag_To_MEFlag(ef);
+
+ face_r->v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, l[0]->v));
+ face_r->v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, l[1]->v));
+ face_r->v3 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, l[2]->v));
+ face_r->v4 = 0;
+
+ test_index_face(face_r, NULL, 0, 3);
+}
+
+static void bmDM_copyVertArray(DerivedMesh *dm, MVert *vert_r)
+{
+ BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
+ BMVert *ev;
+ BMIter iter;
+
+ ev = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for( ; ev; ev = BMIter_Step(&iter), ++vert_r) {
+ copy_v3_v3(vert_r->co, ev->co);
+
+ normal_float_to_short_v3(vert_r->no, ev->no);
+
+ vert_r->flag = BM_Vert_Flag_To_MEFlag(ev);
+
+ if (CustomData_has_layer(&bm->vdata, CD_BWEIGHT)) {
+ vert_r->bweight = (unsigned char) (BM_GetCDf(&bm->vdata, ev, CD_BWEIGHT)*255.0f);
+ }
+ }
+}
+
+static void bmDM_copyEdgeArray(DerivedMesh *dm, MEdge *edge_r)
+{
+ BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
+ BMEdge *ee;
+ BMIter iter;
+ int has_bweight = CustomData_has_layer(&bm->edata, CD_BWEIGHT);
+ int has_crease = CustomData_has_layer(&bm->edata, CD_CREASE);
+
+ BM_ElemIndex_Ensure(bm, BM_VERT);
+
+ ee = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL);
+ for( ; ee; ee=BMIter_Step(&iter), edge_r++) {
+ if (has_bweight) {
+ edge_r->bweight = (unsigned char) (BM_GetCDf(&bm->edata, ee, CD_BWEIGHT)*255.0f);
+ }
+
+ if (has_crease) {
+ edge_r->crease = (unsigned char) (BM_GetCDf(&bm->edata, ee, CD_CREASE)*255.0f);
+ }
+
+ edge_r->flag = BM_Edge_Flag_To_MEFlag(ee);
+
+ edge_r->v1 = (int)BM_GetIndex(ee->v1);
+ edge_r->v2 = (int)BM_GetIndex(ee->v2);
+ }
+}
+
+static void bmDM_copyTessFaceArray(DerivedMesh *dm, MFace *face_r)
+{
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
+ BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
+ BMFace *ef;
+ BMLoop **l;
+ int i;
+
+ BM_ElemIndex_Ensure(bm, BM_VERT);
+
+ for (i=0; i<bmdm->tc->tottri; i++, face_r++) {
+ l = bmdm->tc->looptris[i];
+ ef = l[0]->f;
+
+ face_r->mat_nr = (unsigned char) ef->mat_nr;
+
+ face_r->flag = BM_Face_Flag_To_MEFlag(ef);
+
+ face_r->v1 = BM_GetIndex(l[0]->v);
+ face_r->v2 = BM_GetIndex(l[1]->v);
+ face_r->v3 = BM_GetIndex(l[2]->v);
+ face_r->v4 = 0;
+
+ test_index_face(face_r, NULL, 0, 3);
+ }
+}
+
+
+static void bmDM_copyLoopArray(DerivedMesh *dm, MLoop *loop_r)
+{
+ /* EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; */ /* UNUSED */
+ BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
+ BMIter iter, liter;
+ BMFace *f;
+ BMLoop *l;
+
+ BM_ElemIndex_Ensure(bm, BM_VERT | BM_EDGE);
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ loop_r->v = BM_GetIndex(l->v);
+ loop_r->e = BM_GetIndex(l->e);
+ loop_r++;
+ }
+ }
+}
+
+static void bmDM_copyPolyArray(DerivedMesh *dm, MPoly *poly_r)
+{
+ /* EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; */ /* UNUSED */
+ BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
+ BMIter iter;
+ BMFace *f;
+ int i;
+
+ i = 0;
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ poly_r->flag = BM_Face_Flag_To_MEFlag(f);
+ poly_r->loopstart = i;
+ poly_r->totloop = f->len;
+ poly_r->mat_nr = f->mat_nr;
+
+ poly_r++;
+ i += f->len;
+ }
+}
+
+static void *bmDM_getTessFaceDataArray(DerivedMesh *dm, int type)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMesh *bm= bmdm->tc->bm;
+ BMFace *efa;
+ char *data, *bmdata;
+ void *datalayer;
+ int index /*, offset*/ /*UNUSED */, size, i;
+
+ datalayer = DM_get_tessface_data_layer(dm, type);
+ if(datalayer)
+ return datalayer;
+
+ /* layers are store per face for editmesh, we convert to a tbmporary
+ * data layer array in the derivedmesh when these are requested */
+ if(type == CD_MTFACE || type == CD_MCOL) {
+ index = CustomData_get_layer_index(&bm->pdata, type);
+
+ if(index != -1) {
+ /* offset = bm->pdata.layers[index].offset; */ /* UNUSED */
+ size = CustomData_sizeof(type);
+
+ DM_add_tessface_layer(dm, type, CD_CALLOC, NULL);
+ index = CustomData_get_layer_index(&dm->faceData, type);
+ dm->faceData.layers[index].flag |= CD_FLAG_TEMPORARY;
+
+ data = datalayer = DM_get_tessface_data_layer(dm, type);
+ for (i=0; i<bmdm->tc->tottri; i++, data+=size) {
+ efa = bmdm->tc->looptris[i][0]->f;
+ /*BMESH_TODO: need to still add tface data,
+ derived from the loops.*/
+ bmdata = CustomData_bmesh_get(&bm->pdata, efa->head.data, type);
+ memcpy(data, bmdata, size);
+ }
+ }
+ }
+
+ return datalayer;
+}
+
+static void bmDM_getVertCos(DerivedMesh *dm, float (*cos_r)[3])
+{
+ EditDerivedBMesh *emdm= (EditDerivedBMesh*) dm;
+ BMVert *eve;
+ BMIter iter;
+ int i;
+
+ i= 0;
+ BM_ITER(eve, &iter, emdm->tc->bm, BM_VERTS_OF_MESH, NULL) {
+ if (emdm->vertexCos) {
+ copy_v3_v3(cos_r[i], emdm->vertexCos[i]);
+ } else {
+ copy_v3_v3(cos_r[i], eve->co);
+ }
+
+ i++;
+ }
+}
+
+static void bmDM_release(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh *)dm;
+
+ if (DM_release(dm)) {
+ if (bmdm->vertexCos) {
+ MEM_freeN(bmdm->vertexCos);
+ MEM_freeN(bmdm->vertexNos);
+ MEM_freeN(bmdm->faceNos);
+ }
+
+ if (bmdm->fhash) BLI_ghash_free(bmdm->fhash, NULL, NULL);
+ if (bmdm->ehash) BLI_ghash_free(bmdm->ehash, NULL, NULL);
+ if (bmdm->vhash) BLI_ghash_free(bmdm->vhash, NULL, NULL);
+
+ if (bmdm->vtable) MEM_freeN(bmdm->vtable);
+ if (bmdm->etable) MEM_freeN(bmdm->etable);
+ if (bmdm->ftable) MEM_freeN(bmdm->ftable);
+
+ MEM_freeN(bmdm);
+ }
+}
+
+static CustomData *bmDm_getVertDataLayout(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
+
+ return &bmdm->tc->bm->vdata;
+}
+
+static CustomData *bmDm_getEdgeDataLayout(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
+
+ return &bmdm->tc->bm->edata;
+}
+
+static CustomData *bmDm_getTessFaceDataLayout(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
+
+ return &bmdm->dm.faceData;
+}
+
+static CustomData *bmDm_getLoopDataLayout(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
+
+ return &bmdm->tc->bm->ldata;
+}
+
+static CustomData *bmDm_getPolyDataLayout(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
+
+ return &bmdm->tc->bm->pdata;
+}
+
+
+DerivedMesh *getEditDerivedBMesh(BMEditMesh *em, Object *UNUSED(ob),
+ float (*vertexCos)[3])
+{
+ EditDerivedBMesh *bmdm = MEM_callocN(sizeof(*bmdm), __func__);
+ BMesh *bm = em->bm;
+
+ bmdm->tc = em;
+
+ DM_init((DerivedMesh*)bmdm, DM_TYPE_EDITBMESH, em->bm->totvert,
+ em->bm->totedge, em->tottri, em->bm->totloop, em->bm->totface);
+
+ CustomData_from_bmeshpoly(&bmdm->dm.faceData, &em->bm->pdata, &em->bm->ldata, 0);
+
+ bmdm->dm.getVertCos = bmDM_getVertCos;
+ bmdm->dm.getMinMax = bmDM_getMinMax;
+
+ bmdm->dm.getVertDataLayout = bmDm_getVertDataLayout;
+ bmdm->dm.getEdgeDataLayout = bmDm_getEdgeDataLayout;
+ bmdm->dm.getTessFaceDataLayout = bmDm_getTessFaceDataLayout;
+ bmdm->dm.getLoopDataLayout = bmDm_getLoopDataLayout;
+ bmdm->dm.getPolyDataLayout = bmDm_getPolyDataLayout;
+
+ bmdm->dm.getNumVerts = bmDM_getNumVerts;
+ bmdm->dm.getNumEdges = bmDM_getNumEdges;
+ bmdm->dm.getNumTessFaces = bmDM_getNumTessFaces;
+ bmdm->dm.getNumLoops = bmDM_getNumLoops;
+ bmdm->dm.getNumPolys = bmDM_getNumPolys;
+
+ bmdm->dm.getVert = bmDM_getVert;
+ bmdm->dm.getEdge = bmDM_getEdge;
+ bmdm->dm.getTessFace = bmDM_getTessFace;
+ bmdm->dm.copyVertArray = bmDM_copyVertArray;
+ bmdm->dm.copyEdgeArray = bmDM_copyEdgeArray;
+ bmdm->dm.copyTessFaceArray = bmDM_copyTessFaceArray;
+ bmdm->dm.copyLoopArray = bmDM_copyLoopArray;
+ bmdm->dm.copyPolyArray = bmDM_copyPolyArray;
+
+ bmdm->dm.getTessFaceDataArray = bmDM_getTessFaceDataArray;
+
+ bmdm->dm.calcNormals = bmDM_calcNormals;
+ bmdm->dm.recalcTesselation = bmDM_recalcTesselation;
+
+ bmdm->dm.foreachMappedVert = bmDM_foreachMappedVert;
+ bmdm->dm.foreachMappedEdge = bmDM_foreachMappedEdge;
+ bmdm->dm.foreachMappedFaceCenter = bmDM_foreachMappedFaceCenter;
+
+ bmdm->dm.drawEdges = bmDM_drawEdges;
+ bmdm->dm.drawMappedEdges = bmDM_drawMappedEdges;
+ bmdm->dm.drawMappedEdgesInterp = bmDM_drawMappedEdgesInterp;
+ bmdm->dm.drawMappedFaces = bmDM_drawMappedFaces;
+ bmdm->dm.drawMappedFacesTex = bmDM_drawMappedFacesTex;
+ bmdm->dm.drawMappedFacesGLSL = bmDM_drawMappedFacesGLSL;
+ bmdm->dm.drawMappedFacesMat = bmDM_drawMappedFacesMat;
+ bmdm->dm.drawFacesTex = bmDM_drawFacesTex;
+ bmdm->dm.drawFacesGLSL = bmDM_drawFacesGLSL;
+ bmdm->dm.drawUVEdges = bmDM_drawUVEdges;
+
+ bmdm->dm.release = bmDM_release;
+
+ bmdm->vertexCos = vertexCos;
+
+ if(CustomData_has_layer(&bm->vdata, CD_MDEFORMVERT)) {
+ BMIter iter;
+ BMVert *eve;
+ int i;
+
+ DM_add_vert_layer(&bmdm->dm, CD_MDEFORMVERT, CD_CALLOC, NULL);
+
+ eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&iter), i++)
+ DM_set_vert_data(&bmdm->dm, i, CD_MDEFORMVERT,
+ CustomData_bmesh_get(&bm->vdata, eve->head.data, CD_MDEFORMVERT));
+ }
+
+ if(vertexCos) {
+ BMVert *eve;
+ BMIter iter;
+ int totface = bmdm->tc->tottri;
+ int i;
+
+ BM_ElemIndex_Ensure(bm, BM_VERT);
+
+ bmdm->vertexNos = MEM_callocN(sizeof(*bmdm->vertexNos) * bm->totvert, "bmdm_vno");
+ bmdm->faceNos = MEM_mallocN(sizeof(*bmdm->faceNos)*totface, "bmdm_vno");
+
+ for (i=0; i<bmdm->tc->tottri; i++) {
+ BMLoop **l = bmdm->tc->looptris[i];
+ float *v1 = vertexCos[(int) BM_GetIndex(l[0]->v)];
+ float *v2 = vertexCos[(int) BM_GetIndex(l[1]->v)];
+ float *v3 = vertexCos[(int) BM_GetIndex(l[2]->v)];
+ float *no = bmdm->faceNos[i];
+
+ normal_tri_v3( no,v1, v2, v3);
+ add_v3_v3v3(bmdm->vertexNos[BM_GetIndex(l[0]->v)], bmdm->vertexNos[BM_GetIndex(l[0]->v)], no);
+ add_v3_v3v3(bmdm->vertexNos[BM_GetIndex(l[1]->v)], bmdm->vertexNos[BM_GetIndex(l[1]->v)], no);
+ add_v3_v3v3(bmdm->vertexNos[BM_GetIndex(l[2]->v)], bmdm->vertexNos[BM_GetIndex(l[2]->v)], no);
+ }
+
+ eve=BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&iter), i++) {
+ float *no = bmdm->vertexNos[i];
+ /* following Mesh convention; we use vertex coordinate itself
+ * for normal in this case */
+ if (normalize_v3(no)==0.0) {
+ copy_v3_v3(no, vertexCos[i]);
+ normalize_v3(no);
+ }
+ }
+ }
+
+ //bmdm_recalc_lookups(bmdm);
+
+ return (DerivedMesh*) bmdm;
+}