Wow! A new feature!
[blender.git] / source / blender / blenkernel / intern / DerivedMesh.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2005 Blender Foundation.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif
36
37 #include "MEM_guardedalloc.h"
38
39 #include "DNA_effect_types.h"
40 #include "DNA_mesh_types.h"
41 #include "DNA_meshdata_types.h"
42 #include "DNA_modifier_types.h"
43 #include "DNA_object_types.h"
44 #include "DNA_object_force.h"
45
46 #include "BLI_arithb.h"
47 #include "BLI_blenlib.h"
48 #include "BLI_editVert.h"
49
50 #include "BKE_utildefines.h"
51 #include "BKE_DerivedMesh.h"
52 #include "BKE_displist.h"
53 #include "BKE_effect.h"
54 #include "BKE_global.h"
55 #include "BKE_material.h"
56 #include "BKE_mesh.h"
57 #include "BKE_object.h"
58 #include "BKE_subsurf.h"
59 #include "BKE_deform.h"
60 #include "BKE_modifier.h"
61
62 #include "BIF_gl.h"
63 #include "BIF_glutil.h"
64
65 ///////////////////////////////////
66 ///////////////////////////////////
67
68 typedef struct {
69         DerivedMesh dm;
70
71         Object *ob;
72         Mesh *me;
73         MVert *verts;
74         float *nors;
75
76         int freeNors, freeVerts;
77 } MeshDerivedMesh;
78
79 static DispListMesh *meshDM_convertToDispListMesh(DerivedMesh *dm)
80 {
81         MeshDerivedMesh *mdm = (MeshDerivedMesh*) dm;
82         Mesh *me = mdm->me;
83         DispListMesh *dlm = MEM_callocN(sizeof(*dlm), "dlm");
84
85         dlm->totvert = me->totvert;
86         dlm->totedge = me->totedge;
87         dlm->totface = me->totface;
88         dlm->mvert = mdm->verts;
89         dlm->medge = me->medge;
90         dlm->mface = me->mface;
91         dlm->tface = me->tface;
92         dlm->mcol = me->mcol;
93         dlm->nors = mdm->nors;
94         dlm->dontFreeVerts = dlm->dontFreeOther = dlm->dontFreeNors = 1;
95
96         return dlm;
97 }
98
99 static void meshDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3])
100 {
101         MeshDerivedMesh *mdm = (MeshDerivedMesh*) dm;
102         Mesh *me = mdm->me;
103         int i;
104
105         if (me->totvert) {
106                 for (i=0; i<me->totvert; i++) {
107                         DO_MINMAX(mdm->verts[i].co, min_r, max_r);
108                 }
109         } else {
110                 min_r[0] = min_r[1] = min_r[2] = max_r[0] = max_r[1] = max_r[2] = 0.0;
111         }
112 }
113
114 static void meshDM_getVertCos(DerivedMesh *dm, float (*cos_r)[3])
115 {
116         MeshDerivedMesh *mdm = (MeshDerivedMesh*) dm;
117         Mesh *me = mdm->me;
118         int i;
119
120         for (i=0; i<me->totvert; i++) {
121                 cos_r[i][0] = mdm->verts[i].co[0];
122                 cos_r[i][1] = mdm->verts[i].co[1];
123                 cos_r[i][2] = mdm->verts[i].co[2];
124         }
125 }
126
127 static void meshDM_getVertCo(DerivedMesh *dm, int index, float co_r[3])
128 {
129         MeshDerivedMesh *mdm = (MeshDerivedMesh*) dm;
130         float *co = mdm->verts[index].co;
131
132         co_r[0] = co[0];
133         co_r[1] = co[1];
134         co_r[2] = co[2];
135 }
136
137 static void meshDM_getVertNo(DerivedMesh *dm, int index, float no_r[3])
138 {
139         MeshDerivedMesh *mdm = (MeshDerivedMesh*) dm;
140         short *no = mdm->verts[index].no;
141
142         no_r[0] = no[0]/32767.f;
143         no_r[1] = no[1]/32767.f;
144         no_r[2] = no[2]/32767.f;
145 }
146
147 static void meshDM_drawVerts(DerivedMesh *dm)
148 {
149         MeshDerivedMesh *mdm = (MeshDerivedMesh*) dm;
150         Mesh *me = mdm->me;
151         int a;
152
153         glBegin(GL_POINTS);
154         for(a=0; a<me->totvert; a++) {
155                 glVertex3fv(mdm->verts[ a].co);
156         }
157         glEnd();
158 }
159 static void meshDM_drawEdges(DerivedMesh *dm)
160 {
161         MeshDerivedMesh *mdm = (MeshDerivedMesh*) dm;
162         Mesh *me= mdm->me;
163         int a;
164         MFace *mface = me->mface;
165
166         if(me->medge) {
167                 MEdge *medge= me->medge;
168                 
169                 glBegin(GL_LINES);
170                 for(a=me->totedge; a>0; a--, medge++) {
171                         if(medge->flag & ME_EDGEDRAW) {
172                                 glVertex3fv(mdm->verts[ medge->v1].co);
173                                 glVertex3fv(mdm->verts[ medge->v2].co);
174                         }
175                 }
176                 glEnd();
177         }
178         else {
179                 glBegin(GL_LINES);
180                 for(a=0; a<me->totface; a++, mface++) {
181                         int test= mface->edcode;
182                         
183                         if(test) {
184                                 if(test&ME_V1V2){
185                                         glVertex3fv(mdm->verts[mface->v1].co);
186                                         glVertex3fv(mdm->verts[mface->v2].co);
187                                 }
188
189                                 if(mface->v3) {
190                                         if(test&ME_V2V3){
191                                                 glVertex3fv(mdm->verts[mface->v2].co);
192                                                 glVertex3fv(mdm->verts[mface->v3].co);
193                                         }
194
195                                         if (mface->v4) {
196                                                 if(test&ME_V3V4){
197                                                         glVertex3fv(mdm->verts[mface->v3].co);
198                                                         glVertex3fv(mdm->verts[mface->v4].co);
199                                                 }
200                                                 if(test&ME_V4V1){
201                                                         glVertex3fv(mdm->verts[mface->v4].co);
202                                                         glVertex3fv(mdm->verts[mface->v1].co);
203                                                 }
204                                         } else {
205                                                 if(test&ME_V3V1){
206                                                         glVertex3fv(mdm->verts[mface->v3].co);
207                                                         glVertex3fv(mdm->verts[mface->v1].co);
208                                                 }
209                                         }
210                                 }
211                         }
212                 }
213                 glEnd();
214         }
215 }
216 static void meshDM_drawLooseEdges(DerivedMesh *dm)
217 {
218         MeshDerivedMesh *mdm = (MeshDerivedMesh*) dm;
219         Mesh *me = mdm->me;
220         MFace *mface= me->mface;
221         int a;
222
223         glBegin(GL_LINES);
224         for(a=0; a<me->totface; a++, mface++) {
225                 if(!mface->v3) {
226                         glVertex3fv(mdm->verts[mface->v3].co);
227                         glVertex3fv(mdm->verts[mface->v4].co);
228                 } 
229         }
230         glEnd();
231 }
232 static void meshDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int))
233 {
234         MeshDerivedMesh *mdm = (MeshDerivedMesh*) dm;
235         Mesh *me = mdm->me;
236         MVert *mvert= mdm->verts;
237         MFace *mface= me->mface;
238         float *nors = mdm->nors;
239         int a;
240         int glmode=-1, shademodel=-1, matnr=-1, drawCurrentMat=1;
241
242 #define PASSVERT(index, punoBit) {                              \
243         if (shademodel==GL_SMOOTH) {                            \
244                 short *no = mvert[index].no;                    \
245                 if (mface->puno&punoBit) {                              \
246                         glNormal3s(-no[0], -no[1], -no[2]); \
247                 } else {                                                                \
248                         glNormal3sv(no);                                        \
249                 }                                                                               \
250         }                                                                                       \
251         glVertex3fv(mvert[index].co);   \
252 }
253
254         glBegin(glmode=GL_QUADS);
255         for(a=0; a<me->totface; a++, mface++, nors+=3) {
256                 if(mface->v3) {
257                         int new_glmode, new_matnr, new_shademodel;
258                                 
259                         new_glmode = mface->v4?GL_QUADS:GL_TRIANGLES;
260                         new_matnr = mface->mat_nr+1;
261                         new_shademodel = (!(me->flag&ME_AUTOSMOOTH) && (mface->flag & ME_SMOOTH))?GL_SMOOTH:GL_FLAT;
262                         
263                         if (new_glmode!=glmode || new_matnr!=matnr || new_shademodel!=shademodel) {
264                                 glEnd();
265
266                                 drawCurrentMat = setMaterial(matnr=new_matnr);
267
268                                 glShadeModel(shademodel=new_shademodel);
269                                 glBegin(glmode=new_glmode);
270                         } 
271                         
272                         if (drawCurrentMat) {
273                                 if(shademodel==GL_FLAT) 
274                                         glNormal3fv(nors);
275
276                                 PASSVERT(mface->v1, ME_FLIPV1);
277                                 PASSVERT(mface->v2, ME_FLIPV2);
278                                 PASSVERT(mface->v3, ME_FLIPV3);
279                                 if (mface->v4) {
280                                         PASSVERT(mface->v4, ME_FLIPV4);
281                                 }
282                         }
283                 }
284         }
285         glEnd();
286
287         glShadeModel(GL_FLAT);
288 #undef PASSVERT
289 }
290
291 static void meshDM_drawFacesColored(DerivedMesh *dm, int useTwoSide, unsigned char *col1, unsigned char *col2)
292 {
293         MeshDerivedMesh *mdm = (MeshDerivedMesh*) dm;
294         Mesh *me= mdm->me;
295         MFace *mface= me->mface;
296         int a, glmode;
297         unsigned char *cp1, *cp2;
298
299         cp1= col1;
300         if(col2) {
301                 cp2= col2;
302         } else {
303                 cp2= NULL;
304                 useTwoSide= 0;
305         }
306
307         /* there's a conflict here... twosided colors versus culling...? */
308         /* defined by history, only texture faces have culling option */
309         /* we need that as mesh option builtin, next to double sided lighting */
310         if(col1 && col2)
311                 glEnable(GL_CULL_FACE);
312         
313         glShadeModel(GL_SMOOTH);
314         glBegin(glmode=GL_QUADS);
315         for(a=0; a<me->totface; a++, mface++, cp1+= 16) {
316                 if(mface->v3) {
317                         int new_glmode= mface->v4?GL_QUADS:GL_TRIANGLES;
318
319                         if (new_glmode!=glmode) {
320                                 glEnd();
321                                 glBegin(glmode= new_glmode);
322                         }
323                                 
324                         glColor3ub(cp1[3], cp1[2], cp1[1]);
325                         glVertex3fv( mdm->verts[mface->v1].co );
326                         glColor3ub(cp1[7], cp1[6], cp1[5]);
327                         glVertex3fv( mdm->verts[mface->v2].co );
328                         glColor3ub(cp1[11], cp1[10], cp1[9]);
329                         glVertex3fv( mdm->verts[mface->v3].co );
330                         if(mface->v4) {
331                                 glColor3ub(cp1[15], cp1[14], cp1[13]);
332                                 glVertex3fv( mdm->verts[mface->v4].co );
333                         }
334                                 
335                         if(useTwoSide) {
336                                 glColor3ub(cp2[11], cp2[10], cp2[9]);
337                                 glVertex3fv( mdm->verts[mface->v3].co );
338                                 glColor3ub(cp2[7], cp2[6], cp2[5]);
339                                 glVertex3fv( mdm->verts[mface->v2].co );
340                                 glColor3ub(cp2[3], cp2[2], cp2[1]);
341                                 glVertex3fv( mdm->verts[mface->v1].co );
342                                 if(mface->v4) {
343                                         glColor3ub(cp2[15], cp2[14], cp2[13]);
344                                         glVertex3fv( mdm->verts[mface->v4].co );
345                                 }
346                         }
347                 }
348                 if(col2) cp2+= 16;
349         }
350         glEnd();
351
352         glShadeModel(GL_FLAT);
353         glDisable(GL_CULL_FACE);
354 }
355
356 static void meshDM_drawFacesTex(DerivedMesh *dm, int (*setDrawParams)(TFace *tf, int matnr)) 
357 {
358         MeshDerivedMesh *mdm = (MeshDerivedMesh*) dm;
359         Mesh *me = mdm->me;
360         MVert *mvert= mdm->verts;
361         MFace *mface= me->mface;
362         TFace *tface = me->tface;
363         float *nors = mdm->nors;
364         int a;
365
366         for (a=0; a<me->totface; a++) {
367                 MFace *mf= &mface[a];
368                 TFace *tf = tface?&tface[a]:NULL;
369                 unsigned char *cp= NULL;
370                 
371                 if(mf->v3==0) continue;
372                 if(tf && ((tf->flag&TF_HIDE) || (tf->mode&TF_INVISIBLE))) continue;
373
374                 if (setDrawParams(tf, mf->mat_nr)) {
375                         if (tf) {
376                                 cp= (unsigned char *) tf->col;
377                         } else if (me->mcol) {
378                                 cp= (unsigned char *) &me->mcol[a*4];
379                         }
380                 }
381
382                 if (!(mf->flag&ME_SMOOTH)) {
383                         glNormal3fv(&nors[a*3]);
384                 }
385
386                 glBegin(mf->v4?GL_QUADS:GL_TRIANGLES);
387                 if (tf) glTexCoord2fv(tf->uv[0]);
388                 if (cp) glColor3ub(cp[3], cp[2], cp[1]);
389                 if (mf->flag&ME_SMOOTH) glNormal3sv(mvert[mf->v1].no);
390                 glVertex3fv(mvert[mf->v1].co);
391                         
392                 if (tf) glTexCoord2fv(tf->uv[1]);
393                 if (cp) glColor3ub(cp[7], cp[6], cp[5]);
394                 if (mf->flag&ME_SMOOTH) glNormal3sv(mvert[mf->v2].no);
395                 glVertex3fv(mvert[mf->v2].co);
396
397                 if (tf) glTexCoord2fv(tf->uv[2]);
398                 if (cp) glColor3ub(cp[11], cp[10], cp[9]);
399                 if (mf->flag&ME_SMOOTH) glNormal3sv(mvert[mf->v3].no);
400                 glVertex3fv(mvert[mf->v3].co);
401
402                 if(mf->v4) {
403                         if (tf) glTexCoord2fv(tf->uv[3]);
404                         if (cp) glColor3ub(cp[15], cp[14], cp[13]);
405                         if (mf->flag&ME_SMOOTH) glNormal3sv(mvert[mf->v4].no);
406                         glVertex3fv(mvert[mf->v4].co);
407                 }
408                 glEnd();
409         }
410 }
411 static int meshDM_getNumVerts(DerivedMesh *dm)
412 {
413         MeshDerivedMesh *mdm = (MeshDerivedMesh*) dm;
414         Mesh *me = mdm->me;
415
416         return me->totvert;
417 }
418 static int meshDM_getNumFaces(DerivedMesh *dm)
419 {
420         MeshDerivedMesh *mdm = (MeshDerivedMesh*) dm;
421         Mesh *me = mdm->me;
422
423         return me->totface;
424 }
425
426 static void meshDM_release(DerivedMesh *dm)
427 {
428         MeshDerivedMesh *mdm = (MeshDerivedMesh*) dm;
429
430         if (mdm->freeNors) MEM_freeN(mdm->nors);
431         if (mdm->freeVerts) MEM_freeN(mdm->verts);
432         MEM_freeN(mdm);
433 }
434
435 static float *mesh_build_faceNormals(Object *meshOb) 
436 {
437         Mesh *me = meshOb->data;
438         float *nors = MEM_mallocN(sizeof(float)*3*me->totface, "meshnormals");
439         float *n1 = nors;
440         int i;
441
442         for (i=0; i<me->totface; i++,n1+=3) {
443                 MFace *mf = &me->mface[i];
444                 
445                 if (mf->v3) {
446                         MVert *ve1= &me->mvert[mf->v1];
447                         MVert *ve2= &me->mvert[mf->v2];
448                         MVert *ve3= &me->mvert[mf->v3];
449                         MVert *ve4= &me->mvert[mf->v4];
450                                         
451                         if(mf->v4) CalcNormFloat4(ve1->co, ve2->co, ve3->co, ve4->co, n1);
452                         else CalcNormFloat(ve1->co, ve2->co, ve3->co, n1);
453                 }
454         }
455
456         return nors;
457 }
458
459 static DerivedMesh *getMeshDerivedMesh(Mesh *me, Object *ob, float (*vertCos)[3])
460 {
461         MeshDerivedMesh *mdm = MEM_callocN(sizeof(*mdm), "mdm");
462
463         mdm->dm.getMinMax = meshDM_getMinMax;
464
465         mdm->dm.convertToDispListMesh = meshDM_convertToDispListMesh;
466         mdm->dm.getNumVerts = meshDM_getNumVerts;
467         mdm->dm.getNumFaces = meshDM_getNumFaces;
468
469         mdm->dm.getVertCos = meshDM_getVertCos;
470         mdm->dm.getVertCo = meshDM_getVertCo;
471         mdm->dm.getVertNo = meshDM_getVertNo;
472
473         mdm->dm.drawVerts = meshDM_drawVerts;
474
475         mdm->dm.drawEdges = meshDM_drawEdges;
476         mdm->dm.drawMappedEdges = meshDM_drawEdges;
477         mdm->dm.drawLooseEdges = meshDM_drawLooseEdges;
478
479         mdm->dm.drawFacesSolid = meshDM_drawFacesSolid;
480         mdm->dm.drawFacesColored = meshDM_drawFacesColored;
481         mdm->dm.drawFacesTex = meshDM_drawFacesTex;
482
483         mdm->dm.release = meshDM_release;
484         
485         mdm->ob = ob;
486         mdm->me = me;
487         mdm->verts = me->mvert;
488         mdm->nors = NULL;
489         mdm->freeNors = 0;
490         mdm->freeVerts = 0;
491
492         if (vertCos) {
493                 int i;
494
495                 mdm->verts = MEM_mallocN(sizeof(*mdm->verts)*me->totvert, "deformedVerts");
496                 for (i=0; i<me->totvert; i++) {
497                         mdm->verts[i].co[0] = vertCos[i][0];
498                         mdm->verts[i].co[1] = vertCos[i][1];
499                         mdm->verts[i].co[2] = vertCos[i][2];
500                 }
501                 mesh_calc_normals(mdm->verts, me->totvert, me->mface, me->totface, &mdm->nors);
502                 mdm->freeNors = 1;
503                 mdm->freeVerts = 1;
504         } else {
505                 mdm->nors = mesh_build_faceNormals(ob);
506                 mdm->freeNors = 1;
507         }
508
509         return (DerivedMesh*) mdm;
510 }
511
512 ///
513
514 typedef struct {
515         DerivedMesh dm;
516
517         EditMesh *em;
518 } EditMeshDerivedMesh;
519
520 static void emDM_getMappedVertCoEM(DerivedMesh *dm, void *vert, float co_r[3])
521 {
522         EditVert *eve = vert;
523
524         co_r[0] = eve->co[0];
525         co_r[1] = eve->co[1];
526         co_r[2] = eve->co[2];
527 }
528 static void emDM_drawMappedVertsEM(DerivedMesh *dm, int (*setDrawOptions)(void *userData, EditVert *vert), void *userData)
529 {
530         EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
531         EditVert *eve;
532
533         bglBegin(GL_POINTS);
534         for(eve= emdm->em->verts.first; eve; eve= eve->next) {
535                 if(!setDrawOptions || setDrawOptions(userData, eve))
536                         bglVertex3fv(eve->co);
537         }
538         bglEnd();               
539 }
540 static void emDM_drawMappedEdgeEM(DerivedMesh *dm, void *edge)
541 {
542         EditEdge *eed = edge;
543
544         glBegin(GL_LINES);
545         glVertex3fv(eed->v1->co);
546         glVertex3fv(eed->v2->co);
547         glEnd();
548 }
549 static void emDM_drawMappedEdgesEM(DerivedMesh *dm, int (*setDrawOptions)(void *userData, EditEdge *edge), void *userData) 
550 {
551         EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
552         EditEdge *eed;
553
554         glBegin(GL_LINES);
555         for(eed= emdm->em->edges.first; eed; eed= eed->next) {
556                 if(!setDrawOptions || setDrawOptions(userData, eed)) {
557                         glVertex3fv(eed->v1->co);
558                         glVertex3fv(eed->v2->co);
559                 }
560         }
561         glEnd();
562 }
563 static void emDM_drawMappedEdgesInterpEM(DerivedMesh *dm, int (*setDrawOptions)(void *userData, EditEdge *edge), void (*setDrawInterpOptions)(void *userData, EditEdge *edge, float t), void *userData) 
564 {
565         EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
566         EditEdge *eed;
567
568         glBegin(GL_LINES);
569         for(eed= emdm->em->edges.first; eed; eed= eed->next) {
570                 if(!setDrawOptions || setDrawOptions(userData, eed)) {
571                         setDrawInterpOptions(userData, eed, 0.0);
572                         glVertex3fv(eed->v1->co);
573                         setDrawInterpOptions(userData, eed, 1.0);
574                         glVertex3fv(eed->v2->co);
575                 }
576         }
577         glEnd();
578 }
579 static void emDM_drawMappedFacesEM(DerivedMesh *dm, int (*setDrawOptions)(void *userData, EditFace *face), void *userData)
580 {
581         EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
582         EditFace *efa;
583
584         for (efa= emdm->em->faces.first; efa; efa= efa->next) {
585                 if(!setDrawOptions || setDrawOptions(userData, efa)) {
586                         glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
587                         glVertex3fv(efa->v1->co);
588                         glVertex3fv(efa->v2->co);
589                         glVertex3fv(efa->v3->co);
590                         if(efa->v4) glVertex3fv(efa->v4->co);
591                         glEnd();
592                 }
593         }
594 }
595 static void emDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int))
596 {
597         EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
598         EditFace *efa;
599
600         for (efa= emdm->em->faces.first; efa; efa= efa->next) {
601                 if(efa->h==0) {
602                         if (setMaterial(efa->mat_nr+1)) {
603                                 glNormal3fv(efa->n);
604                                 glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
605                                 glVertex3fv(efa->v1->co);
606                                 glVertex3fv(efa->v2->co);
607                                 glVertex3fv(efa->v3->co);
608                                 if(efa->v4) glVertex3fv(efa->v4->co);
609                                 glEnd();
610                         }
611                 }
612         }
613 }
614
615 static void emDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3])
616 {
617         EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
618         EditVert *eve;
619
620         if (emdm->em->verts.first) {
621                 for (eve= emdm->em->verts.first; eve; eve= eve->next) {
622                         DO_MINMAX(eve->co, min_r, max_r);
623                 }
624         } else {
625                 min_r[0] = min_r[1] = min_r[2] = max_r[0] = max_r[1] = max_r[2] = 0.0;
626         }
627 }
628 static int emDM_getNumVerts(DerivedMesh *dm)
629 {
630         EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
631
632         return BLI_countlist(&emdm->em->verts);
633 }
634 static int emDM_getNumFaces(DerivedMesh *dm)
635 {
636         EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
637
638         return BLI_countlist(&emdm->em->faces);
639 }
640
641 static DerivedMesh *getEditMeshDerivedMesh(EditMesh *em)
642 {
643         EditMeshDerivedMesh *emdm = MEM_callocN(sizeof(*emdm), "emdm");
644
645         emdm->dm.getMinMax = emDM_getMinMax;
646
647         emdm->dm.getNumVerts = emDM_getNumVerts;
648         emdm->dm.getNumFaces = emDM_getNumFaces;
649         emdm->dm.getMappedVertCoEM = emDM_getMappedVertCoEM;
650
651         emdm->dm.drawMappedVertsEM = emDM_drawMappedVertsEM;
652
653         emdm->dm.drawMappedEdgeEM = emDM_drawMappedEdgeEM;
654         emdm->dm.drawMappedEdgesEM = emDM_drawMappedEdgesEM;
655         emdm->dm.drawMappedEdgesInterpEM = emDM_drawMappedEdgesInterpEM;
656         
657         emdm->dm.drawFacesSolid = emDM_drawFacesSolid;
658         emdm->dm.drawMappedFacesEM = emDM_drawMappedFacesEM;
659
660         emdm->dm.release = (void(*)(DerivedMesh*)) MEM_freeN;
661         
662         emdm->em = em;
663
664         return (DerivedMesh*) emdm;
665 }
666
667 ///
668
669 typedef struct {
670         DerivedMesh dm;
671
672         DispListMesh *dlm;
673 } SSDerivedMesh;
674
675 static void ssDM_drawMappedEdges(DerivedMesh *dm)
676 {
677         SSDerivedMesh *ssdm = (SSDerivedMesh*) dm;
678         DispListMesh *dlm = ssdm->dlm;
679         MEdge *medge= dlm->medge;
680         MVert *mvert= dlm->mvert;
681         int a;
682         
683         glBegin(GL_LINES);
684         for (a=0; a<dlm->totedge; a++, medge++) {
685                 if (medge->flag&ME_EDGEDRAW) {
686                         glVertex3fv(mvert[medge->v1].co); 
687                         glVertex3fv(mvert[medge->v2].co);
688                 }
689         }
690         glEnd();
691 }
692
693 static void ssDM_drawLooseEdges(DerivedMesh *dm)
694 {
695         /* Can't implement currently */ 
696 }
697
698 static void ssDM_drawVerts(DerivedMesh *dm)
699 {
700         SSDerivedMesh *ssdm = (SSDerivedMesh*) dm;
701         DispListMesh *dlm = ssdm->dlm;
702         MVert *mvert= dlm->mvert;
703         int i;
704
705         bglBegin(GL_POINTS);
706         for (i=0; i<dlm->totvert; i++) {
707                 bglVertex3fv(mvert[i].co);
708         }
709         bglEnd();
710 }
711 static void ssDM_drawEdges(DerivedMesh *dm) 
712 {
713         SSDerivedMesh *ssdm = (SSDerivedMesh*) dm;
714         DispListMesh *dlm = ssdm->dlm;
715         MVert *mvert= dlm->mvert;
716         int i;
717
718         if (dlm->medge) {
719                 MEdge *medge= dlm->medge;
720         
721                 glBegin(GL_LINES);
722                 for (i=0; i<dlm->totedge; i++, medge++) {
723                         glVertex3fv(mvert[medge->v1].co); 
724                         glVertex3fv(mvert[medge->v2].co);
725                 }
726                 glEnd();
727         } else {
728                 MFace *mface= dlm->mface;
729
730                 glBegin(GL_LINES);
731                 for (i=0; i<dlm->totface; i++, mface++) {
732                         glVertex3fv(mvert[mface->v1].co);
733                         glVertex3fv(mvert[mface->v2].co);
734
735                         if (mface->v3) {
736                                 glVertex3fv(mvert[mface->v2].co);
737                                 glVertex3fv(mvert[mface->v3].co);
738
739                                 glVertex3fv(mvert[mface->v3].co);
740                                 if (mface->v4) {
741                                         glVertex3fv(mvert[mface->v4].co);
742
743                                         glVertex3fv(mvert[mface->v4].co);
744                                 }
745                                 glVertex3fv(mvert[mface->v1].co);
746                         }
747                 }
748                 glEnd();
749         }
750 }
751 static void ssDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int))
752 {
753         SSDerivedMesh *ssdm = (SSDerivedMesh*) dm;
754         DispListMesh *dlm = ssdm->dlm;
755         float *nors = dlm->nors;
756         int glmode=-1, shademodel=-1, matnr=-1, drawCurrentMat=1;
757         int i;
758
759 #define PASSVERT(ind) {                                         \
760         if (shademodel==GL_SMOOTH)                              \
761                 glNormal3sv(dlm->mvert[(ind)].no);      \
762         glVertex3fv(dlm->mvert[(ind)].co);              \
763 }
764
765         glBegin(glmode=GL_QUADS);
766         for (i=0; i<dlm->totface; i++) {
767                 MFace *mf= &dlm->mface[i];
768                 
769                 if (mf->v3) {
770                         int new_glmode = mf->v4?GL_QUADS:GL_TRIANGLES;
771                         int new_shademodel = (mf->flag&ME_SMOOTH)?GL_SMOOTH:GL_FLAT;
772                         int new_matnr = mf->mat_nr+1;
773                         
774                         if(new_glmode!=glmode || new_shademodel!=shademodel || new_matnr!=matnr) {
775                                 glEnd();
776
777                                 drawCurrentMat = setMaterial(matnr=new_matnr);
778
779                                 glShadeModel(shademodel=new_shademodel);
780                                 glBegin(glmode=new_glmode);
781                         }
782                         
783                         if (drawCurrentMat) {
784                                 if (shademodel==GL_FLAT)
785                                         glNormal3fv(&nors[i*3]);
786                                         
787                                 PASSVERT(mf->v1);
788                                 PASSVERT(mf->v2);
789                                 PASSVERT(mf->v3);
790                                 if (mf->v4)
791                                         PASSVERT(mf->v4);
792                         }
793                 }
794         }
795         glEnd();
796         
797 #undef PASSVERT
798 }
799 static void ssDM_drawFacesColored(DerivedMesh *dm, int useTwoSided, unsigned char *vcols1, unsigned char *vcols2)
800 {
801         SSDerivedMesh *ssdm = (SSDerivedMesh*) dm;
802         DispListMesh *dlm = ssdm->dlm;
803         int i, lmode;
804         
805         glShadeModel(GL_SMOOTH);
806         if (vcols2) {
807                 glEnable(GL_CULL_FACE);
808         } else {
809                 useTwoSided = 0;
810         }
811                 
812 #define PASSVERT(vidx, fidx) {                                  \
813         unsigned char *col= &colbase[fidx*4];           \
814         glColor3ub(col[3], col[2], col[1]);                     \
815         glVertex3fv(dlm->mvert[(vidx)].co);                     \
816 }
817
818         glBegin(lmode= GL_QUADS);
819         for (i=0; i<dlm->totface; i++) {
820                 MFace *mf= &dlm->mface[i];
821                 
822                 if (mf->v3) {
823                         int nmode= mf->v4?GL_QUADS:GL_TRIANGLES;
824                         unsigned char *colbase= &vcols1[i*16];
825                         
826                         if (nmode!=lmode) {
827                                 glEnd();
828                                 glBegin(lmode= nmode);
829                         }
830                         
831                         PASSVERT(mf->v1, 0);
832                         PASSVERT(mf->v2, 1);
833                         PASSVERT(mf->v3, 2);
834                         if (mf->v4)
835                                 PASSVERT(mf->v4, 3);
836                         
837                         if (useTwoSided) {
838                                 unsigned char *colbase= &vcols2[i*16];
839
840                                 if (mf->v4)
841                                         PASSVERT(mf->v4, 3);
842                                 PASSVERT(mf->v3, 2);
843                                 PASSVERT(mf->v2, 1);
844                                 PASSVERT(mf->v1, 0);
845                         }
846                 }
847         }
848         glEnd();
849
850         if (vcols2)
851                 glDisable(GL_CULL_FACE);
852         
853 #undef PASSVERT
854 }
855 static void ssDM_drawFacesTex(DerivedMesh *dm, int (*setDrawParams)(TFace *tf, int matnr)) 
856 {
857         SSDerivedMesh *ssdm = (SSDerivedMesh*) dm;
858         DispListMesh *dlm = ssdm->dlm;
859         MVert *mvert= dlm->mvert;
860         MFace *mface= dlm->mface;
861         TFace *tface = dlm->tface;
862         float *nors = dlm->nors;
863         int a;
864         
865         for (a=0; a<dlm->totface; a++) {
866                 MFace *mf= &mface[a];
867                 TFace *tf = tface?&tface[a]:NULL;
868                 unsigned char *cp= NULL;
869                 
870                 if(mf->v3==0) continue;
871                 if(tf && ((tf->flag&TF_HIDE) || (tf->mode&TF_INVISIBLE))) continue;
872
873                 if (setDrawParams(tf, mf->mat_nr)) {
874                         if (tf) {
875                                 cp= (unsigned char*) tf->col;
876                         } else if (dlm->mcol) {
877                                 cp= (unsigned char*) &dlm->mcol[a*4];
878                         }
879                 }
880
881                 if (!(mf->flag&ME_SMOOTH)) {
882                         glNormal3fv(&nors[a*3]);
883                 }
884
885                 glBegin(mf->v4?GL_QUADS:GL_TRIANGLES);
886                 if (tf) glTexCoord2fv(tf->uv[0]);
887                 if (cp) glColor3ub(cp[3], cp[2], cp[1]);
888                 if (mf->flag&ME_SMOOTH) glNormal3sv(mvert[mf->v1].no);
889                 glVertex3fv((mvert+mf->v1)->co);
890                         
891                 if (tf) glTexCoord2fv(tf->uv[1]);
892                 if (cp) glColor3ub(cp[7], cp[6], cp[5]);
893                 if (mf->flag&ME_SMOOTH) glNormal3sv(mvert[mf->v2].no);
894                 glVertex3fv((mvert+mf->v2)->co);
895
896                 if (tf) glTexCoord2fv(tf->uv[2]);
897                 if (cp) glColor3ub(cp[11], cp[10], cp[9]);
898                 if (mf->flag&ME_SMOOTH) glNormal3sv(mvert[mf->v3].no);
899                 glVertex3fv((mvert+mf->v3)->co);
900
901                 if(mf->v4) {
902                         if (tf) glTexCoord2fv(tf->uv[3]);
903                         if (cp) glColor3ub(cp[15], cp[14], cp[13]);
904                         if (mf->flag&ME_SMOOTH) glNormal3sv(mvert[mf->v4].no);
905                         glVertex3fv((mvert+mf->v4)->co);
906                 }
907                 glEnd();
908         }
909 }
910
911 static void ssDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3])
912 {
913         SSDerivedMesh *ssdm = (SSDerivedMesh*) dm;
914         int i;
915
916         if (ssdm->dlm->totvert) {
917                 for (i=0; i<ssdm->dlm->totvert; i++) {
918                         DO_MINMAX(ssdm->dlm->mvert[i].co, min_r, max_r);
919                 }
920         } else {
921                 min_r[0] = min_r[1] = min_r[2] = max_r[0] = max_r[1] = max_r[2] = 0.0;
922         }
923 }
924
925 static void ssDM_getVertCos(DerivedMesh *dm, float (*cos_r)[3])
926 {
927         SSDerivedMesh *ssdm = (SSDerivedMesh*) dm;
928         int i;
929
930         for (i=0; i<ssdm->dlm->totvert; i++) {
931                 cos_r[i][0] = ssdm->dlm->mvert[i].co[0];
932                 cos_r[i][1] = ssdm->dlm->mvert[i].co[1];
933                 cos_r[i][2] = ssdm->dlm->mvert[i].co[2];
934         }
935 }
936
937 static int ssDM_getNumVerts(DerivedMesh *dm)
938 {
939         SSDerivedMesh *ssdm = (SSDerivedMesh*) dm;
940
941         return ssdm->dlm->totvert;
942 }
943 static int ssDM_getNumFaces(DerivedMesh *dm)
944 {
945         SSDerivedMesh *ssdm = (SSDerivedMesh*) dm;
946
947         return ssdm->dlm->totface;
948 }
949
950 static DispListMesh *ssDM_convertToDispListMesh(DerivedMesh *dm)
951 {
952         SSDerivedMesh *ssdm = (SSDerivedMesh*) dm;
953
954         return displistmesh_copy(ssdm->dlm);
955 }
956
957 static void ssDM_release(DerivedMesh *dm)
958 {
959         SSDerivedMesh *ssdm = (SSDerivedMesh*) dm;
960
961         displistmesh_free(ssdm->dlm);
962
963         MEM_freeN(dm);
964 }
965
966 DerivedMesh *derivedmesh_from_displistmesh(DispListMesh *dlm)
967 {
968         SSDerivedMesh *ssdm = MEM_callocN(sizeof(*ssdm), "ssdm");
969
970         ssdm->dm.getMinMax = ssDM_getMinMax;
971
972         ssdm->dm.getNumVerts = ssDM_getNumVerts;
973         ssdm->dm.getNumFaces = ssDM_getNumFaces;
974         ssdm->dm.convertToDispListMesh = ssDM_convertToDispListMesh;
975
976         ssdm->dm.getVertCos = ssDM_getVertCos;
977
978         ssdm->dm.drawVerts = ssDM_drawVerts;
979
980         ssdm->dm.drawEdges = ssDM_drawEdges;
981         ssdm->dm.drawMappedEdges = ssDM_drawMappedEdges;
982         ssdm->dm.drawLooseEdges = ssDM_drawLooseEdges;
983
984         ssdm->dm.drawFacesSolid = ssDM_drawFacesSolid;
985         ssdm->dm.drawFacesColored = ssDM_drawFacesColored;
986         ssdm->dm.drawFacesTex = ssDM_drawFacesTex;
987
988         ssdm->dm.release = ssDM_release;
989         
990         ssdm->dlm = dlm;
991
992         return (DerivedMesh*) ssdm;
993 }
994
995 /***/
996
997 static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], DerivedMesh **deform_r, DerivedMesh **final_r, int useRenderParams, int useDeform)
998 {
999         Mesh *me = ob->data;
1000         ModifierData *md= ob->modifiers.first;
1001         float (*deformedVerts)[3];
1002         DerivedMesh *dm;
1003         int a, numVerts = me->totvert;
1004
1005         if (deform_r) *deform_r = NULL;
1006         *final_r = NULL;
1007
1008                 /* Note: useDeform==1 implies ob must be non-NULL */
1009
1010         if (useDeform && ob) {
1011                 mesh_modifier(ob, &deformedVerts);
1012
1013                 if (!deformedVerts) {
1014                         deformedVerts = MEM_mallocN(sizeof(*deformedVerts)*numVerts, "vertexcos1");
1015                         for (a=0; a<numVerts; a++) {
1016                                 VECCOPY(deformedVerts[a], me->mvert[a].co);
1017                         }
1018                 }
1019
1020                         /* Apply all leading deforming modifiers */
1021                 for (; md; md=md->next) {
1022                         ModifierTypeInfo *mti = modifierType_get_info(md->type);
1023
1024                         if (!(md->mode&(1<<useRenderParams))) continue;
1025                         if (mti->isDisabled && mti->isDisabled(md)) continue;
1026
1027                         if (mti->type==eModifierTypeType_OnlyDeform) {
1028                                 mti->deformVerts(md, ob, deformedVerts, numVerts);
1029                         } else {
1030                                 break;
1031                         }
1032                 }
1033
1034                         /* Result of all leading deforming modifiers is cached for
1035                          * places that wish to use the original mesh but with deformed
1036                          * coordinates (vpaint, etc.)
1037                          */
1038                 if (deform_r) *deform_r = getMeshDerivedMesh(me, ob, deformedVerts);
1039         } else {
1040                 deformedVerts = inputVertexCos;
1041         }
1042
1043                 /* Now apply all remaining modifiers. If useDeform is off then skip
1044                  * OnlyDeform ones. 
1045                  */
1046         dm = NULL;
1047         for (; md; md=md->next) {
1048                 ModifierTypeInfo *mti = modifierType_get_info(md->type);
1049
1050                 if (!(md->mode&(1<<useRenderParams))) continue;
1051                 if (mti->type==eModifierTypeType_OnlyDeform && !useDeform) continue;
1052                 if (mti->isDisabled && mti->isDisabled(md)) continue;
1053
1054                         /* How to apply modifier depends on (a) what we already have as
1055                          * a result of previous modifiers (could be a DerivedMesh or just
1056                          * deformed vertices) and (b) what type the modifier is.
1057                          */
1058
1059                 if (mti->type==eModifierTypeType_OnlyDeform) {
1060                                 /* No existing verts to deform, need to build them. */
1061                         if (!deformedVerts) {
1062                                 if (dm) {
1063                                                 /* Deforming a derived mesh, read the vertex locations out of the mesh and
1064                                                  * deform them. Once done with this run of deformers will be written back.
1065                                                  */
1066                                         numVerts = dm->getNumVerts(dm);
1067                                         deformedVerts = MEM_mallocN(sizeof(*deformedVerts)*numVerts, "dfmv");
1068                                         dm->getVertCos(dm, deformedVerts);
1069                                 } else {
1070                                         numVerts = me->totvert;
1071                                         deformedVerts = MEM_mallocN(sizeof(*deformedVerts)*numVerts, "vertexcos2");
1072                                         for (a=0; a<numVerts; a++) {
1073                                                 VECCOPY(deformedVerts[a], me->mvert[a].co);
1074                                         }
1075                                 }
1076                         }
1077
1078                         mti->deformVerts(md, ob, deformedVerts, numVerts);
1079                 } else {
1080                                 /* There are 4 cases here (have deform? have dm?) but they all are handled
1081                                  * by the modifier apply function, which will also free the DerivedMesh if
1082                                  * it exists.
1083                                  */
1084                         dm = mti->applyModifier(md, ob, dm, deformedVerts, useRenderParams);
1085
1086                         if (deformedVerts) {
1087                                 if (deformedVerts!=inputVertexCos) {
1088                                         MEM_freeN(deformedVerts);
1089                                 }
1090                                 deformedVerts = 0;
1091                         }
1092                 }
1093         }
1094
1095                 /* Fake the subsurf modifier */
1096         {
1097                 int level = useRenderParams?me->subdivr:me->subdiv;
1098
1099                 if ((me->flag&ME_SUBSURF) && level) {
1100                         ModifierTypeInfo *mti = modifierType_get_info(eModifierType_Subsurf);
1101                         SubsurfModifierData smd;
1102
1103                         smd.levels = me->subdiv;
1104                         smd.renderLevels = me->subdivr;
1105                         smd.subdivType = me->subsurftype;
1106
1107                         dm = mti->applyModifier(&smd.modifier, ob, dm, deformedVerts, useRenderParams);
1108
1109                         if (deformedVerts) {
1110                                 if (deformedVerts!=inputVertexCos) {
1111                                         MEM_freeN(deformedVerts);
1112                                 }
1113                                 deformedVerts = 0;
1114                         }
1115                 }
1116         }
1117
1118                 /* Yay, we are done. If we have a DerivedMesh and deformed vertices need to apply
1119                  * these back onto the DerivedMesh. If we have no DerivedMesh then we need to build
1120                  * one.
1121                  */
1122         if (dm && deformedVerts) {
1123                 DispListMesh *dlm = dm->convertToDispListMesh(dm); // XXX what if verts or nors were shared
1124                 int i;
1125
1126                         /* XXX, would like to avoid the conversion to a DLM here if possible.
1127                          * Requires adding a DerivedMesh.updateVertCos method.
1128                          */
1129                 for (i=0; i<numVerts; i++) {
1130                         VECCOPY(dlm->mvert[i].co, deformedVerts[i]);
1131                 }
1132
1133                 dm->release(dm);
1134
1135                 if (dlm->nors && !dlm->dontFreeNors) {
1136                         MEM_freeN(dlm->nors);
1137                         dlm->nors = 0;
1138                 }
1139
1140                 mesh_calc_normals(dlm->mvert, dlm->totvert, dlm->mface, dlm->totface, &dlm->nors);
1141                 *final_r = derivedmesh_from_displistmesh(dlm);
1142         } else if (dm) {
1143                 *final_r = dm;
1144         } else {
1145                 *final_r = getMeshDerivedMesh(me, ob, deformedVerts);
1146         }
1147
1148         if (deformedVerts && deformedVerts!=inputVertexCos) {
1149                 MEM_freeN(deformedVerts);
1150         }
1151 }
1152
1153 /***/
1154
1155 static void clear_and_build_mesh_data(Object *ob, int mustBuildForMesh)
1156 {
1157         float min[3], max[3];
1158         Mesh *me= ob->data;
1159
1160         if(ob->flag&OB_FROMDUPLI) return;
1161
1162                 /* also serves as signal to remake texspace */
1163         if (me->bb) {
1164                 MEM_freeN(me->bb);
1165                 me->bb = NULL;
1166         }
1167
1168         freedisplist(&ob->disp);
1169
1170         if (ob->derivedFinal) {
1171                 ob->derivedFinal->release(ob->derivedFinal);
1172                 ob->derivedFinal= NULL;
1173         }
1174         if (ob->derivedDeform) {
1175                 ob->derivedDeform->release(ob->derivedDeform);
1176                 ob->derivedDeform= NULL;
1177         }
1178
1179         if (ob==G.obedit) {
1180                 G.editMesh->derived= subsurf_make_derived_from_editmesh(G.editMesh, me->subdiv, me->subsurftype, G.editMesh->derived);
1181         } 
1182         
1183         if (ob!=G.obedit || mustBuildForMesh) {
1184                 mesh_calc_modifiers(ob, NULL, &ob->derivedDeform, &ob->derivedFinal, 0, 1);
1185         
1186                 INIT_MINMAX(min, max);
1187
1188                 ob->derivedFinal->getMinMax(ob->derivedFinal, min, max);
1189
1190                 boundbox_set_from_min_max(mesh_get_bb(ob->data), min, max);
1191
1192                 build_particle_system(ob);
1193         }
1194 }
1195
1196 void makeDispListMesh(Object *ob)
1197 {
1198         clear_and_build_mesh_data(ob, 0);
1199 }
1200
1201 /***/
1202
1203 DerivedMesh *mesh_get_derived_final(Object *ob, int *needsFree_r)
1204 {
1205         Mesh *me = ob->data;
1206
1207         if (!ob->derivedFinal) {
1208                 clear_and_build_mesh_data(ob, 1);
1209         }
1210
1211         *needsFree_r = 0;
1212         return ob->derivedFinal;
1213 }
1214
1215 DerivedMesh *mesh_get_derived_deform(Object *ob, int *needsFree_r)
1216 {
1217         if (!ob->derivedDeform) {
1218                 clear_and_build_mesh_data(ob, 1);
1219         } 
1220
1221         *needsFree_r = 0;
1222         return ob->derivedDeform;
1223 }
1224
1225 DerivedMesh *mesh_create_derived_render(Object *ob)
1226 {
1227         DerivedMesh *final;
1228
1229         mesh_calc_modifiers(ob, NULL, NULL, &final, 1, 1);
1230
1231         return final;
1232 }
1233
1234 DerivedMesh *mesh_create_derived_no_deform(Object *ob, float (*vertCos)[3])
1235 {
1236         DerivedMesh *final;
1237
1238         mesh_calc_modifiers(ob, vertCos, NULL, &final, 0, 0);
1239
1240         return final;
1241 }
1242
1243 DerivedMesh *mesh_create_derived_no_deform_render(Object *ob, float (*vertCos)[3])
1244 {
1245         DerivedMesh *final;
1246
1247         mesh_calc_modifiers(ob, vertCos, NULL, &final, 1, 0);
1248
1249         return final;
1250 }
1251
1252 /***/
1253
1254 DerivedMesh *editmesh_get_derived_proxy(void)
1255 {
1256         return getEditMeshDerivedMesh(G.editMesh);
1257 }
1258
1259 DerivedMesh *editmesh_get_derived(void)
1260 {
1261         Mesh *me= G.obedit->data;
1262
1263         if ((me->flag&ME_SUBSURF) && me->subdiv) {
1264                 if (!G.editMesh->derived) {
1265                         makeDispListMesh(G.obedit);
1266                 }
1267
1268                 return G.editMesh->derived;
1269         } 
1270
1271         return NULL;
1272 }
1273
1274 DerivedMesh *editmesh_get_derived_cage(int *needsFree_r)
1275 {
1276         Mesh *me= G.obedit->data;
1277         DerivedMesh *dm = NULL;
1278
1279         *needsFree_r = 0;
1280
1281         if (me->flag&ME_OPT_EDGES) {
1282                 dm = editmesh_get_derived();
1283         }
1284         if (!dm) {
1285                 *needsFree_r = 1;
1286                 dm = editmesh_get_derived_proxy();
1287         }
1288
1289         return dm;
1290 }