Undo revision 23130 which was a merge with 2.5, a messy one because I did something...
[blender.git] / source / blender / blenkernel / intern / cdderivedmesh.c
index ebfb96f..706eece 100644 (file)
@@ -42,6 +42,7 @@
 #include "BKE_displist.h"
 #include "BKE_global.h"
 #include "BKE_mesh.h"
+#include "BKE_multires.h"
 #include "BKE_utildefines.h"
 
 #include "BLI_arithb.h"
 
 #include "DNA_mesh_types.h"
 #include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
 #include "DNA_object_fluidsim.h"
 #include "DNA_object_types.h"
 #include "DNA_scene_types.h"
 
 #include "MEM_guardedalloc.h"
 
+#include "GPU_draw.h"
+#include "GPU_extensions.h"
+#include "GPU_material.h"
+
 #include <string.h>
 #include <limits.h>
+#include <math.h>
 
 typedef struct {
        DerivedMesh dm;
@@ -117,7 +124,7 @@ static void cdDM_copyEdgeArray(DerivedMesh *dm, MEdge *edge_r)
        memcpy(edge_r, cddm->medge, sizeof(*edge_r) * dm->numEdgeData);
 }
 
-void cdDM_copyFaceArray(DerivedMesh *dm, MFace *face_r)
+static void cdDM_copyFaceArray(DerivedMesh *dm, MFace *face_r)
 {
        CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
        memcpy(face_r, cddm->mface, sizeof(*face_r) * dm->numFaceData);
@@ -243,7 +250,7 @@ static void cdDM_drawLooseEdges(DerivedMesh *dm)
        glEnd();
 }
 
-static void cdDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int))
+static void cdDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int, void *attribs))
 {
        CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
        MVert *mvert = cddm->mvert;
@@ -271,7 +278,7 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int))
                   || new_shademodel != shademodel) {
                        glEnd();
 
-                       drawCurrentMat = setMaterial(matnr = new_matnr);
+                       drawCurrentMat = setMaterial(matnr = new_matnr, NULL);
 
                        glShadeModel(shademodel = new_shademodel);
                        glBegin(glmode = new_glmode);
@@ -475,10 +482,14 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us
        CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
        MVert *mv = cddm->mvert;
        MFace *mf = cddm->mface;
-       MCol *mc = DM_get_face_data_layer(dm, CD_MCOL);
+       MCol *mc;
        float *nors= dm->getFaceDataArray(dm, CD_NORMAL);
        int i, orig, *index = DM_get_face_data_layer(dm, CD_ORIGINDEX);
 
+       mc = DM_get_face_data_layer(dm, CD_WEIGHT_MCOL);
+       if(!mc)
+               mc = DM_get_face_data_layer(dm, CD_MCOL);
+
        for(i = 0; i < dm->numFaceData; i++, mf++) {
                int drawSmooth = (mf->flag & ME_SMOOTH);
 
@@ -556,6 +567,134 @@ static void cdDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void
        cdDM_drawFacesTex_common(dm, NULL, setDrawOptions, userData);
 }
 
+static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, void *attribs), int (*setDrawOptions)(void *userData, int index), void *userData)
+{
+       CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
+       GPUVertexAttribs gattribs;
+       DMVertexAttribs attribs;
+       MVert *mvert = cddm->mvert;
+       MFace *mface = cddm->mface;
+       MTFace *tf = dm->getFaceDataArray(dm, CD_MTFACE);
+       float (*nors)[3] = dm->getFaceDataArray(dm, CD_NORMAL);
+       int a, b, dodraw, smoothnormal, matnr, new_matnr;
+       int transp, new_transp, orig_transp;
+       int orig, *index = dm->getFaceDataArray(dm, CD_ORIGINDEX);
+
+       matnr = -1;
+       smoothnormal = 0;
+       dodraw = 0;
+       transp = GPU_get_material_blend_mode();
+       orig_transp = transp;
+
+       memset(&attribs, 0, sizeof(attribs));
+
+       glShadeModel(GL_SMOOTH);
+       glBegin(GL_QUADS);
+
+       for(a = 0; a < dm->numFaceData; a++, mface++) {
+               new_matnr = mface->mat_nr + 1;
+
+               if(new_matnr != matnr) {
+                       glEnd();
+
+                       dodraw = setMaterial(matnr = new_matnr, &gattribs);
+                       if(dodraw)
+                               DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
+
+                       glBegin(GL_QUADS);
+               }
+
+               if(!dodraw) {
+                       continue;
+               }
+               else if(setDrawOptions) {
+                       orig = index[a];
+
+                       if(orig == ORIGINDEX_NONE)
+                               continue;
+                       else if(!setDrawOptions(userData, orig))
+                               continue;
+               }
+
+               if(tf) {
+                       new_transp = tf[a].transp;
+
+                       if(new_transp != transp) {
+                               glEnd();
+
+                               if(new_transp == GPU_BLEND_SOLID && orig_transp != GPU_BLEND_SOLID)
+                                       GPU_set_material_blend_mode(orig_transp);
+                               else
+                                       GPU_set_material_blend_mode(new_transp);
+                               transp = new_transp;
+
+                               glBegin(GL_QUADS);
+                       }
+               }
+
+               smoothnormal = (mface->flag & ME_SMOOTH);
+
+               if(!smoothnormal) {
+                       if(nors) {
+                               glNormal3fv(nors[a]);
+                       }
+                       else {
+                               /* TODO ideally a normal layer should always be available */
+                               float nor[3];
+                               if(mface->v4) {
+                                       CalcNormFloat4(mvert[mface->v1].co, mvert[mface->v2].co,
+                                                                  mvert[mface->v3].co, mvert[mface->v4].co,
+                                                                  nor);
+                               } else {
+                                       CalcNormFloat(mvert[mface->v1].co, mvert[mface->v2].co,
+                                                                 mvert[mface->v3].co, nor);
+                               }
+                               glNormal3fv(nor);
+                       }
+               }
+
+#define PASSVERT(index, vert) {                                                                                                        \
+       if(attribs.totorco)                                                                                                                     \
+               glVertexAttrib3fvARB(attribs.orco.glIndex, attribs.orco.array[index]);  \
+       for(b = 0; b < attribs.tottface; b++) {                                                                         \
+               MTFace *tf = &attribs.tface[b].array[a];                                                                \
+               glVertexAttrib2fvARB(attribs.tface[b].glIndex, tf->uv[vert]);                   \
+       }                                                                                                                                                       \
+       for(b = 0; b < attribs.totmcol; b++) {                                                                          \
+               MCol *cp = &attribs.mcol[b].array[a*4 + vert];                                                  \
+               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[a*4 + vert];                                                   \
+               glVertexAttrib3fvARB(attribs.tang.glIndex, tang);                                               \
+       }                                                                                                                                                       \
+       if(smoothnormal)                                                                                                                        \
+               glNormal3sv(mvert[index].no);                                                                                   \
+       glVertex3fv(mvert[index].co);                                                                                           \
+}
+
+               PASSVERT(mface->v1, 0);
+               PASSVERT(mface->v2, 1);
+               PASSVERT(mface->v3, 2);
+               if(mface->v4)
+                       PASSVERT(mface->v4, 3)
+               else
+                       PASSVERT(mface->v3, 2)
+
+#undef PASSVERT
+       }
+       glEnd();
+
+       glShadeModel(GL_FLAT);
+}
+
+static void cdDM_drawFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, void *attribs))
+{
+       dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL);
+}
+
 static void cdDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
 {
        CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
@@ -713,8 +852,10 @@ static CDDerivedMesh *cdDM_create(const char *desc)
        dm->drawFacesSolid = cdDM_drawFacesSolid;
        dm->drawFacesColored = cdDM_drawFacesColored;
        dm->drawFacesTex = cdDM_drawFacesTex;
+       dm->drawFacesGLSL = cdDM_drawFacesGLSL;
        dm->drawMappedFaces = cdDM_drawMappedFaces;
        dm->drawMappedFacesTex = cdDM_drawMappedFacesTex;
+       dm->drawMappedFacesGLSL = cdDM_drawMappedFacesGLSL;
 
        dm->foreachMappedVert = cdDM_foreachMappedVert;
        dm->foreachMappedEdge = cdDM_foreachMappedEdge;
@@ -732,6 +873,10 @@ DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces)
 
        DM_init(dm, numVerts, numEdges, numFaces);
 
+       CustomData_add_layer(&dm->vertData, CD_ORIGINDEX, CD_CALLOC, NULL, numVerts);
+       CustomData_add_layer(&dm->edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges);
+       CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_CALLOC, NULL, numFaces);
+
        CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts);
        CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
        CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numFaces);
@@ -747,24 +892,27 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *ob)
 {
        CDDerivedMesh *cddm = cdDM_create("CDDM_from_mesh dm");
        DerivedMesh *dm = &cddm->dm;
+       CustomDataMask mask = CD_MASK_MESH & (~CD_MASK_MDISPS);
        int i, *index, alloctype;
 
        /* this does a referenced copy, the only new layers being ORIGINDEX,
         * with an exception for fluidsim */
 
        DM_init(dm, mesh->totvert, mesh->totedge, mesh->totface);
+
+       CustomData_add_layer(&dm->vertData, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totvert);
+       CustomData_add_layer(&dm->edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totedge);
+       CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totface);
+
        dm->deformedOnly = 1;
 
-       if(ob->fluidsimSettings && ob->fluidsimSettings->meshSurface)
-               alloctype= CD_DUPLICATE;
-       else
-               alloctype= CD_REFERENCE;
+       alloctype= CD_REFERENCE;
 
-       CustomData_merge(&mesh->vdata, &dm->vertData, CD_MASK_MESH, alloctype,
+       CustomData_merge(&mesh->vdata, &dm->vertData, mask, alloctype,
                         mesh->totvert);
-       CustomData_merge(&mesh->edata, &dm->edgeData, CD_MASK_MESH, alloctype,
+       CustomData_merge(&mesh->edata, &dm->edgeData, mask, alloctype,
                         mesh->totedge);
-       CustomData_merge(&mesh->fdata, &dm->faceData, CD_MASK_MESH, alloctype,
+       CustomData_merge(&mesh->fdata, &dm->faceData, mask, alloctype,
                         mesh->totface);
 
        cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
@@ -782,12 +930,6 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *ob)
        index = CustomData_get_layer(&dm->faceData, CD_ORIGINDEX);
        for(i = 0; i < mesh->totface; ++i, ++index)
                *index = i;
-       
-       /* works in conjunction with hack during modifier calc, where active mcol
-          layer with weight paint colors is temporarily added */
-       if ((G.f & G_WEIGHTPAINT) &&
-               (ob && ob==(G.scene->basact?G.scene->basact->object:NULL)))
-               CustomData_duplicate_referenced_layer(&dm->faceData, CD_MCOL);
 
        return dm;
 }
@@ -840,6 +982,7 @@ DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *me)
                mv->no[0] = eve->no[0] * 32767.0;
                mv->no[1] = eve->no[1] * 32767.0;
                mv->no[2] = eve->no[2] * 32767.0;
+               mv->bweight = (unsigned char) (eve->bweight * 255.0f);
 
                mv->mat_nr = 0;
                mv->flag = 0;
@@ -857,6 +1000,7 @@ DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *me)
                med->v1 = eed->v1->tmp.l;
                med->v2 = eed->v2->tmp.l;
                med->crease = (unsigned char) (eed->crease * 255.0f);
+               med->bweight = (unsigned char) (eed->bweight * 255.0f);
                med->flag = ME_EDGEDRAW|ME_EDGERENDER;
                
                if(eed->seam) med->flag |= ME_SEAM;
@@ -1076,7 +1220,7 @@ void CDDM_calc_edges(DerivedMesh *dm)
        BLI_edgehashIterator_free(ehi);
 
        /* free old CustomData and assign new one */
-       CustomData_free(&dm->edgeData, dm->numVertData);
+       CustomData_free(&dm->edgeData, dm->numEdgeData);
        dm->edgeData = edgeData;
        dm->numEdgeData = numEdges;
 
@@ -1139,3 +1283,192 @@ MFace *CDDM_get_faces(DerivedMesh *dm)
        return ((CDDerivedMesh*)dm)->mface;
 }
 
+/* Multires DerivedMesh, extends CDDM */
+typedef struct MultiresDM {
+       CDDerivedMesh cddm;
+
+       MultiresModifierData *mmd;
+
+       int lvl, totlvl;
+       float (*orco)[3];
+       MVert *subco;
+
+       ListBase *vert_face_map, *vert_edge_map;
+       IndexNode *vert_face_map_mem, *vert_edge_map_mem;
+       int *face_offsets;
+
+       Mesh *me;
+       int modified;
+
+       void (*update)(DerivedMesh*);
+} MultiresDM;
+
+static void MultiresDM_release(DerivedMesh *dm)
+{
+       MultiresDM *mrdm = (MultiresDM*)dm;
+       int mvert_layer;
+
+       /* Before freeing, need to update the displacement map */
+       if(dm->needsFree && mrdm->modified)
+               mrdm->update(dm);
+
+       /* If the MVert data is being used as the sculpt undo store, don't free it */
+       mvert_layer = CustomData_get_layer_index(&dm->vertData, CD_MVERT);
+       if(mvert_layer != -1) {
+               CustomDataLayer *cd = &dm->vertData.layers[mvert_layer];
+               if(cd->data == mrdm->mmd->undo_verts)
+                       cd->flag |= CD_FLAG_NOFREE;
+       }
+
+       if(DM_release(dm)) {
+               MEM_freeN(mrdm->subco);
+               MEM_freeN(mrdm->orco);
+               if(mrdm->vert_face_map)
+                       MEM_freeN(mrdm->vert_face_map);
+               if(mrdm->vert_face_map_mem)
+                       MEM_freeN(mrdm->vert_face_map_mem);
+               if(mrdm->vert_edge_map)
+                       MEM_freeN(mrdm->vert_edge_map);
+               if(mrdm->vert_edge_map_mem)
+                       MEM_freeN(mrdm->vert_edge_map_mem);
+               if(mrdm->face_offsets)
+                       MEM_freeN(mrdm->face_offsets);
+               MEM_freeN(mrdm);
+       }
+}
+
+DerivedMesh *MultiresDM_new(MultiresSubsurf *ms, DerivedMesh *orig, int numVerts, int numEdges, int numFaces)
+{
+       MultiresDM *mrdm = MEM_callocN(sizeof(MultiresDM), "MultiresDM");
+       CDDerivedMesh *cddm = cdDM_create("MultiresDM CDDM");
+       DerivedMesh *dm = NULL;
+
+       mrdm->cddm = *cddm;
+       MEM_freeN(cddm);
+       dm = &mrdm->cddm.dm;
+
+       mrdm->mmd = ms->mmd;
+       mrdm->me = ms->me;
+
+       if(dm) {
+               MDisps *disps;
+               MVert *mvert;
+               int i;
+
+               DM_from_template(dm, orig, numVerts, numEdges, numFaces);
+               CustomData_free_layers(&dm->faceData, CD_MDISPS, numFaces);
+
+               disps = CustomData_get_layer(&orig->faceData, CD_MDISPS);
+               if(disps)
+                       CustomData_add_layer(&dm->faceData, CD_MDISPS, CD_REFERENCE, disps, numFaces);
+
+
+               mvert = CustomData_get_layer(&orig->vertData, CD_MVERT);
+               mrdm->orco = MEM_callocN(sizeof(float) * 3 * orig->getNumVerts(orig), "multires orco");
+               for(i = 0; i < orig->getNumVerts(orig); ++i)
+                       VecCopyf(mrdm->orco[i], mvert[i].co);
+       }
+       else
+               DM_init(dm, numVerts, numEdges, numFaces);
+
+       CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts);
+       CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
+       CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numFaces);
+
+       mrdm->cddm.mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
+       mrdm->cddm.medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
+       mrdm->cddm.mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
+
+       mrdm->lvl = ms->mmd->lvl;
+       mrdm->totlvl = ms->mmd->totlvl;
+       mrdm->subco = MEM_callocN(sizeof(MVert)*numVerts, "multires subdivided verts");
+       mrdm->modified = 0;
+
+       dm->release = MultiresDM_release;
+
+       return dm;
+}
+
+Mesh *MultiresDM_get_mesh(DerivedMesh *dm)
+{
+       return ((MultiresDM*)dm)->me;
+}
+
+void *MultiresDM_get_orco(DerivedMesh *dm)
+{
+       return ((MultiresDM*)dm)->orco;
+
+}
+
+MVert *MultiresDM_get_subco(DerivedMesh *dm)
+{
+       return ((MultiresDM*)dm)->subco;
+}
+
+int MultiresDM_get_totlvl(DerivedMesh *dm)
+{
+       return ((MultiresDM*)dm)->totlvl;
+}
+
+int MultiresDM_get_lvl(DerivedMesh *dm)
+{
+       return ((MultiresDM*)dm)->lvl;
+}
+
+void MultiresDM_set_orco(DerivedMesh *dm, float (*orco)[3])
+{
+       ((MultiresDM*)dm)->orco = orco;
+}
+
+void MultiresDM_set_update(DerivedMesh *dm, void (*update)(DerivedMesh*))
+{
+       ((MultiresDM*)dm)->update = update;
+}
+
+ListBase *MultiresDM_get_vert_face_map(DerivedMesh *dm)
+{
+       MultiresDM *mrdm = (MultiresDM*)dm;
+
+       if(!mrdm->vert_face_map)
+               create_vert_face_map(&mrdm->vert_face_map, &mrdm->vert_face_map_mem, mrdm->me->mface,
+                                    mrdm->me->totvert, mrdm->me->totface);
+
+       return mrdm->vert_face_map;
+}
+
+ListBase *MultiresDM_get_vert_edge_map(DerivedMesh *dm)
+{
+       MultiresDM *mrdm = (MultiresDM*)dm;
+
+       if(!mrdm->vert_edge_map)
+               create_vert_edge_map(&mrdm->vert_edge_map, &mrdm->vert_edge_map_mem, mrdm->me->medge,
+                                    mrdm->me->totvert, mrdm->me->totedge);
+
+       return mrdm->vert_edge_map;
+}
+
+int *MultiresDM_get_face_offsets(DerivedMesh *dm)
+{
+       MultiresDM *mrdm = (MultiresDM*)dm;
+       int i, accum = 0;
+
+       if(!mrdm->face_offsets) {
+               int len = (int)pow(2, mrdm->lvl - 2) - 1;
+               int area = len * len;
+               int t = 1 + len * 3 + area * 3, q = t + len + area;
+
+               mrdm->face_offsets = MEM_callocN(sizeof(int) * mrdm->me->totface, "mrdm face offsets");
+               for(i = 0; i < mrdm->me->totface; ++i) {
+                       mrdm->face_offsets[i] = accum;
+
+                       accum += (mrdm->me->mface[i].v4 ? q : t);
+               }
+       }
+
+       return mrdm->face_offsets;
+}
+
+void MultiresDM_mark_as_modified(DerivedMesh *dm)
+{
+       ((MultiresDM*)dm)->modified = 1;
+}