/* displist.c * * * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL LICENSE BLOCK ***** */ #include #include #include #include "MEM_guardedalloc.h" #include "DNA_curve_types.h" #include "DNA_meshdata_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" #include "DNA_material_types.h" #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_editVert.h" #include "BLI_scanfill.h" #include "BLI_utildefines.h" #include "BKE_global.h" #include "BKE_displist.h" #include "BKE_cdderivedmesh.h" #include "BKE_object.h" #include "BKE_mball.h" #include "BKE_material.h" #include "BKE_curve.h" #include "BKE_key.h" #include "BKE_anim.h" #include "BKE_font.h" #include "BKE_lattice.h" #include "BKE_modifier.h" #include "RE_pipeline.h" #include "RE_shader_ext.h" #include "BLO_sys_types.h" // for intptr_t support #include "ED_curve.h" /* for BKE_curve_nurbs */ static void boundbox_displist(Object *ob); void free_disp_elem(DispList *dl) { if(dl) { if(dl->verts) MEM_freeN(dl->verts); if(dl->nors) MEM_freeN(dl->nors); if(dl->index) MEM_freeN(dl->index); if(dl->col1) MEM_freeN(dl->col1); if(dl->col2) MEM_freeN(dl->col2); if(dl->bevelSplitFlag) MEM_freeN(dl->bevelSplitFlag); MEM_freeN(dl); } } void freedisplist(ListBase *lb) { DispList *dl; dl= lb->first; while(dl) { BLI_remlink(lb, dl); free_disp_elem(dl); dl= lb->first; } } DispList *find_displist_create(ListBase *lb, int type) { DispList *dl; dl= lb->first; while(dl) { if(dl->type==type) return dl; dl= dl->next; } dl= MEM_callocN(sizeof(DispList), "find_disp"); dl->type= type; BLI_addtail(lb, dl); return dl; } DispList *find_displist(ListBase *lb, int type) { DispList *dl; dl= lb->first; while(dl) { if(dl->type==type) return dl; dl= dl->next; } return NULL; } int displist_has_faces(ListBase *lb) { DispList *dl; for(dl= lb->first; dl; dl= dl->next) { if ELEM3(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF) return 1; } return 0; } void copy_displist(ListBase *lbn, ListBase *lb) { DispList *dln, *dl; freedisplist(lbn); dl= lb->first; while(dl) { dln= MEM_dupallocN(dl); BLI_addtail(lbn, dln); dln->verts= MEM_dupallocN(dl->verts); dln->nors= MEM_dupallocN(dl->nors); dln->index= MEM_dupallocN(dl->index); dln->col1= MEM_dupallocN(dl->col1); dln->col2= MEM_dupallocN(dl->col2); if(dl->bevelSplitFlag) dln->bevelSplitFlag= MEM_dupallocN(dl->bevelSplitFlag); dl= dl->next; } } void addnormalsDispList(ListBase *lb) { DispList *dl = NULL; float *vdata, *ndata, nor[3]; float *v1, *v2, *v3, *v4; float *n1, *n2, *n3, *n4; int a, b, p1, p2, p3, p4; dl= lb->first; while(dl) { if(dl->type==DL_INDEX3) { if(dl->nors==NULL) { dl->nors= MEM_callocN(sizeof(float)*3, "dlnors"); if(dl->verts[2]<0.0) dl->nors[2]= -1.0; else dl->nors[2]= 1.0; } } else if(dl->type==DL_SURF) { if(dl->nors==NULL) { dl->nors= MEM_callocN(sizeof(float)*3*dl->nr*dl->parts, "dlnors"); vdata= dl->verts; ndata= dl->nors; for(a=0; aparts; a++) { if (surfindex_displist(dl, a, &b, &p1, &p2, &p3, &p4)==0) break; v1= vdata+ 3*p1; n1= ndata+ 3*p1; v2= vdata+ 3*p2; n2= ndata+ 3*p2; v3= vdata+ 3*p3; n3= ndata+ 3*p3; v4= vdata+ 3*p4; n4= ndata+ 3*p4; for(; bnr; b++) { normal_quad_v3( nor,v1, v3, v4, v2); add_v3_v3(n1, nor); add_v3_v3(n2, nor); add_v3_v3(n3, nor); add_v3_v3(n4, nor); v2= v1; v1+= 3; v4= v3; v3+= 3; n2= n1; n1+= 3; n4= n3; n3+= 3; } } a= dl->parts*dl->nr; v1= ndata; while(a--) { normalize_v3(v1); v1+= 3; } } } dl= dl->next; } } void count_displist(ListBase *lb, int *totvert, int *totface) { DispList *dl; dl= lb->first; while(dl) { switch(dl->type) { case DL_SURF: *totvert+= dl->nr*dl->parts; *totface+= (dl->nr-1)*(dl->parts-1); break; case DL_INDEX3: case DL_INDEX4: *totvert+= dl->nr; *totface+= dl->parts; break; case DL_POLY: case DL_SEGM: *totvert+= dl->nr*dl->parts; } dl= dl->next; } } int surfindex_displist(DispList *dl, int a, int *b, int *p1, int *p2, int *p3, int *p4) { if((dl->flag & DL_CYCL_V)==0 && a==(dl->parts)-1) { return 0; } if(dl->flag & DL_CYCL_U) { (*p1)= dl->nr*a; (*p2)= (*p1)+ dl->nr-1; (*p3)= (*p1)+ dl->nr; (*p4)= (*p2)+ dl->nr; (*b)= 0; } else { (*p2)= dl->nr*a; (*p1)= (*p2)+1; (*p4)= (*p2)+ dl->nr; (*p3)= (*p1)+ dl->nr; (*b)= 1; } if( (dl->flag & DL_CYCL_V) && a==dl->parts-1) { \ (*p3)-= dl->nr*dl->parts; \ (*p4)-= dl->nr*dl->parts; \ } return 1; } /* ***************************** shade displist. note colors now are in rgb(a) order ******************** */ /* create default shade input... save cpu cycles with ugly global */ /* XXXX bad code warning: local ShadeInput initialize... */ static ShadeInput shi; static void init_fastshade_shadeinput(Render *re) { memset(&shi, 0, sizeof(ShadeInput)); shi.lay= RE_GetScene(re)->lay; shi.view[2]= -1.0f; shi.passflag= SCE_PASS_COMBINED; shi.combinedflag= -1; } static Render *fastshade_get_render(Scene *UNUSED(scene)) { // XXX 2.5: this crashes combined with previewrender // due to global R so disabled for now #if 0 /* XXX ugly global still, but we can't do preview while rendering */ if(G.rendering==0) { Render *re= RE_GetRender("_Shade View_"); if(re==NULL) { re= RE_NewRender("_Shade View_"); RE_Database_Baking(re, scene, 0, 0); /* 0= no faces */ } return re; } #endif return NULL; } /* called on file reading */ void fastshade_free_render(void) { Render *re= RE_GetRender("_Shade View_"); if(re) { RE_Database_Free(re); RE_FreeRender(re); } } static int fastshade_customdata_layer_num(int n, int active) { /* make the active layer the first */ if (n == active) return 0; else if (n < active) return n+1; else return n; } static void fastshade_customdata(CustomData *fdata, int a, int j, Material *ma) { CustomDataLayer *layer; MTFace *mtface; int index, n, needuv= ma->texco & TEXCO_UV; char *vertcol; shi.totuv= 0; shi.totcol= 0; for(index=0; indextotlayer; index++) { layer= &fdata->layers[index]; if(needuv && layer->type == CD_MTFACE && shi.totuv < MAX_MTFACE) { n= fastshade_customdata_layer_num(shi.totuv, layer->active_rnd); mtface= &((MTFace*)layer->data)[a]; shi.uv[shi.totuv].uv[0]= 2.0f*mtface->uv[j][0]-1.0f; shi.uv[shi.totuv].uv[1]= 2.0f*mtface->uv[j][1]-1.0f; shi.uv[shi.totuv].uv[2]= 1.0f; shi.uv[shi.totuv].name= layer->name; shi.totuv++; } else if(layer->type == CD_MCOL && shi.totcol < MAX_MCOL) { n= fastshade_customdata_layer_num(shi.totcol, layer->active_rnd); vertcol= (char*)&((MCol*)layer->data)[a*4 + j]; shi.col[shi.totcol].col[0]= ((float)vertcol[3])/255.0f; shi.col[shi.totcol].col[1]= ((float)vertcol[2])/255.0f; shi.col[shi.totcol].col[2]= ((float)vertcol[1])/255.0f; shi.col[shi.totcol].name= layer->name; shi.totcol++; } } if(needuv && shi.totuv == 0) VECCOPY(shi.uv[0].uv, shi.lo); if(shi.totcol) VECCOPY(shi.vcol, shi.col[0].col); } static void fastshade(float *co, float *nor, float *orco, Material *ma, char *col1, char *col2) { ShadeResult shr; int a; VECCOPY(shi.co, co); shi.vn[0]= -nor[0]; shi.vn[1]= -nor[1]; shi.vn[2]= -nor[2]; VECCOPY(shi.vno, shi.vn); VECCOPY(shi.facenor, shi.vn); if(ma->texco) { VECCOPY(shi.lo, orco); if(ma->texco & TEXCO_GLOB) { VECCOPY(shi.gl, shi.lo); } if(ma->texco & TEXCO_WINDOW) { VECCOPY(shi.winco, shi.lo); } if(ma->texco & TEXCO_STICKY) { VECCOPY(shi.sticky, shi.lo); } if(ma->texco & TEXCO_OBJECT) { VECCOPY(shi.co, shi.lo); } if(ma->texco & TEXCO_NORM) { VECCOPY(shi.orn, shi.vn); } if(ma->texco & TEXCO_REFL) { float inp= 2.0*(shi.vn[2]); shi.ref[0]= (inp*shi.vn[0]); shi.ref[1]= (inp*shi.vn[1]); shi.ref[2]= (-1.0+inp*shi.vn[2]); } } shi.mat= ma; /* set each time... node shaders change it */ RE_shade_external(NULL, &shi, &shr); a= 256.0f*(shr.combined[0]); col1[0]= CLAMPIS(a, 0, 255); a= 256.0f*(shr.combined[1]); col1[1]= CLAMPIS(a, 0, 255); a= 256.0f*(shr.combined[2]); col1[2]= CLAMPIS(a, 0, 255); if(col2) { shi.vn[0]= -shi.vn[0]; shi.vn[1]= -shi.vn[1]; shi.vn[2]= -shi.vn[2]; shi.mat= ma; /* set each time... node shaders change it */ RE_shade_external(NULL, &shi, &shr); a= 256.0f*(shr.combined[0]); col2[0]= CLAMPIS(a, 0, 255); a= 256.0f*(shr.combined[1]); col2[1]= CLAMPIS(a, 0, 255); a= 256.0f*(shr.combined[2]); col2[2]= CLAMPIS(a, 0, 255); } } static void init_fastshade_for_ob(Render *re, Object *ob, int *need_orco_r, float mat[4][4], float imat[3][3]) { float tmat[4][4]; float amb[3]= {0.0f, 0.0f, 0.0f}; int a; /* initialize globals in render */ RE_shade_external(re, NULL, NULL); /* initialize global here */ init_fastshade_shadeinput(re); RE_DataBase_GetView(re, tmat); mul_m4_m4m4(mat, ob->obmat, tmat); invert_m4_m4(tmat, mat); copy_m3_m4(imat, tmat); if(ob->transflag & OB_NEG_SCALE) mul_m3_fl(imat, -1.0); if (need_orco_r) *need_orco_r= 0; for(a=0; atotcol; a++) { Material *ma= give_current_material(ob, a+1); if(ma) { init_render_material(ma, 0, amb); if(ma->texco & TEXCO_ORCO) { if (need_orco_r) *need_orco_r= 1; } } } } static void end_fastshade_for_ob(Object *ob) { int a; for(a=0; atotcol; a++) { Material *ma= give_current_material(ob, a+1); if(ma) end_render_material(ma); } } static void mesh_create_shadedColors(Render *re, Object *ob, int onlyForMesh, unsigned int **col1_r, unsigned int **col2_r) { Mesh *me= ob->data; DerivedMesh *dm; MVert *mvert; MFace *mface; unsigned int *col1, *col2; float *orco, *vnors, *nors, imat[3][3], mat[4][4], vec[3]; int a, i, need_orco, totface, totvert; CustomDataMask dataMask = CD_MASK_BAREMESH | CD_MASK_MCOL | CD_MASK_MTFACE | CD_MASK_NORMAL; init_fastshade_for_ob(re, ob, &need_orco, mat, imat); if(need_orco) dataMask |= CD_MASK_ORCO; if (onlyForMesh) dm = mesh_get_derived_deform(RE_GetScene(re), ob, dataMask); else dm = mesh_get_derived_final(RE_GetScene(re), ob, dataMask); mvert = dm->getVertArray(dm); mface = dm->getFaceArray(dm); nors = dm->getFaceDataArray(dm, CD_NORMAL); totvert = dm->getNumVerts(dm); totface = dm->getNumFaces(dm); orco= dm->getVertDataArray(dm, CD_ORCO); if (onlyForMesh) { col1 = *col1_r; col2 = NULL; } else { *col1_r = col1 = MEM_mallocN(sizeof(*col1)*totface*4, "col1"); if (col2_r && (me->flag & ME_TWOSIDED)) col2 = MEM_mallocN(sizeof(*col2)*totface*4, "col2"); else col2 = NULL; if (col2_r) *col2_r = col2; } /* vertexnormals */ vnors= MEM_mallocN(totvert*3*sizeof(float), "vnors disp"); for (a=0; ano[0]; float yn= mv->no[1]; float zn= mv->no[2]; /* transpose ! */ vn[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn; vn[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn; vn[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn; normalize_v3(vn); } for (i=0; imat_nr+1); int j, vidx[4], nverts= mf->v4?4:3; unsigned char *col1base= (unsigned char*) &col1[i*4]; unsigned char *col2base= (unsigned char*) (col2?&col2[i*4]:NULL); float nor[3], n1[3]; if(ma==NULL) ma= &defmaterial; vidx[0]= mf->v1; vidx[1]= mf->v2; vidx[2]= mf->v3; vidx[3]= mf->v4; if (nors) { VECCOPY(nor, &nors[i*3]); } else { if (mf->v4) normal_quad_v3( nor,mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co, mvert[mf->v4].co); else normal_tri_v3( nor,mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co); } n1[0]= imat[0][0]*nor[0]+imat[0][1]*nor[1]+imat[0][2]*nor[2]; n1[1]= imat[1][0]*nor[0]+imat[1][1]*nor[1]+imat[1][2]*nor[2]; n1[2]= imat[2][0]*nor[0]+imat[2][1]*nor[1]+imat[2][2]*nor[2]; normalize_v3(n1); for (j=0; jflag & ME_SMOOTH)?&vnors[3*vidx[j]]:n1; mul_v3_m4v3(vec, mat, mv->co); vec[0]+= 0.001*vn[0]; vec[1]+= 0.001*vn[1]; vec[2]+= 0.001*vn[2]; fastshade_customdata(&dm->faceData, i, j, ma); fastshade(vec, vn, orco?&orco[vidx[j]*3]:mv->co, ma, col1, col2); } } MEM_freeN(vnors); dm->release(dm); end_fastshade_for_ob(ob); } void shadeMeshMCol(Scene *scene, Object *ob, Mesh *me) { Render *re= fastshade_get_render(scene); int a; char *cp; unsigned int *mcol= (unsigned int*)me->mcol; if(re) { mesh_create_shadedColors(re, ob, 1, &mcol, NULL); me->mcol= (MCol*)mcol; /* swap bytes */ for(cp= (char *)me->mcol, a= 4*me->totface; a>0; a--, cp+=4) { SWAP(char, cp[0], cp[3]); SWAP(char, cp[1], cp[2]); } } } /* has base pointer, to check for layer */ /* called from drawobject.c */ void shadeDispList(Scene *scene, Base *base) { Object *ob= base->object; DispList *dl, *dlob; Material *ma = NULL; Render *re; float imat[3][3], mat[4][4], vec[3]; float *fp, *nor, n1[3]; unsigned int *col1; int a, need_orco; re= fastshade_get_render(scene); if(re==NULL) return; dl = find_displist(&ob->disp, DL_VERTCOL); if (dl) { BLI_remlink(&ob->disp, dl); free_disp_elem(dl); } if(ob->type==OB_MESH) { dl= MEM_callocN(sizeof(DispList), "displistshade"); dl->type= DL_VERTCOL; mesh_create_shadedColors(re, ob, 0, &dl->col1, &dl->col2); /* add dl to ob->disp after mesh_create_shadedColors, because it might indirectly free ob->disp */ BLI_addtail(&ob->disp, dl); } else { init_fastshade_for_ob(re, ob, &need_orco, mat, imat); if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { /* now we need the normals */ dl= ob->disp.first; while(dl) { extern Material defmaterial; /* material.c */ dlob= MEM_callocN(sizeof(DispList), "displistshade"); BLI_addtail(&ob->disp, dlob); dlob->type= DL_VERTCOL; dlob->parts= dl->parts; dlob->nr= dl->nr; if(dl->type==DL_INDEX3) { col1= dlob->col1= MEM_mallocN(sizeof(int)*dl->nr, "col1"); } else { col1= dlob->col1= MEM_mallocN(sizeof(int)*dl->parts*dl->nr, "col1"); } ma= give_current_material(ob, dl->col+1); if(ma==NULL) ma= &defmaterial; if(dl->type==DL_INDEX3) { if(dl->nors) { /* there's just one normal */ n1[0]= imat[0][0]*dl->nors[0]+imat[0][1]*dl->nors[1]+imat[0][2]*dl->nors[2]; n1[1]= imat[1][0]*dl->nors[0]+imat[1][1]*dl->nors[1]+imat[1][2]*dl->nors[2]; n1[2]= imat[2][0]*dl->nors[0]+imat[2][1]*dl->nors[1]+imat[2][2]*dl->nors[2]; normalize_v3(n1); fp= dl->verts; a= dl->nr; while(a--) { mul_v3_m4v3(vec, mat, fp); fastshade(vec, n1, fp, ma, (char *)col1, NULL); fp+= 3; col1++; } } } else if(dl->type==DL_SURF) { if(dl->nors) { a= dl->nr*dl->parts; fp= dl->verts; nor= dl->nors; while(a--) { mul_v3_m4v3(vec, mat, fp); n1[0]= imat[0][0]*nor[0]+imat[0][1]*nor[1]+imat[0][2]*nor[2]; n1[1]= imat[1][0]*nor[0]+imat[1][1]*nor[1]+imat[1][2]*nor[2]; n1[2]= imat[2][0]*nor[0]+imat[2][1]*nor[1]+imat[2][2]*nor[2]; normalize_v3(n1); fastshade(vec, n1, fp, ma, (char *)col1, NULL); fp+= 3; nor+= 3; col1++; } } } dl= dl->next; } } else if(ob->type==OB_MBALL) { /* there are normals already */ dl= ob->disp.first; while(dl) { if(dl->type==DL_INDEX4) { if(dl->nors) { extern Material defmaterial; /* material.c */ if(dl->col1) MEM_freeN(dl->col1); col1= dl->col1= MEM_mallocN(sizeof(int)*dl->nr, "col1"); ma= give_current_material(ob, dl->col+1); if(ma==NULL) ma= &defmaterial; fp= dl->verts; nor= dl->nors; a= dl->nr; while(a--) { mul_v3_m4v3(vec, mat, fp); /* transpose ! */ n1[0]= imat[0][0]*nor[0]+imat[0][1]*nor[1]+imat[0][2]*nor[2]; n1[1]= imat[1][0]*nor[0]+imat[1][1]*nor[1]+imat[1][2]*nor[2]; n1[2]= imat[2][0]*nor[0]+imat[2][1]*nor[1]+imat[2][2]*nor[2]; normalize_v3(n1); fastshade(vec, n1, fp, ma, (char *)col1, NULL); fp+= 3; col1++; nor+= 3; } } } dl= dl->next; } } end_fastshade_for_ob(ob); } } /* frees render and shade part of displists */ /* note: dont do a shade again, until a redraw happens */ void reshadeall_displist(Scene *scene) { Base *base; Object *ob; fastshade_free_render(); for(base= scene->base.first; base; base= base->next) { ob= base->object; if(ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) freedisplist(&ob->disp); if(base->lay & scene->lay) { /* Metaballs have standard displist at the Object */ if(ob->type==OB_MBALL) shadeDispList(scene, base); } } } /* ****************** make displists ********************* */ static void curve_to_displist(Curve *cu, ListBase *nubase, ListBase *dispbase, int forRender) { Nurb *nu; DispList *dl; BezTriple *bezt, *prevbezt; BPoint *bp; float *data; int a, len, resolu; nu= nubase->first; while(nu) { if(nu->hide==0) { if(forRender && cu->resolu_ren!=0) resolu= cu->resolu_ren; else resolu= nu->resolu; if(!check_valid_nurb_u(nu)); else if(nu->type == CU_BEZIER) { /* count */ len= 0; a= nu->pntsu-1; if(nu->flagu & CU_NURB_CYCLIC) a++; prevbezt= nu->bezt; bezt= prevbezt+1; while(a--) { if(a==0 && (nu->flagu & CU_NURB_CYCLIC)) bezt= nu->bezt; if(prevbezt->h2==HD_VECT && bezt->h1==HD_VECT) len++; else len+= resolu; if(a==0 && (nu->flagu & CU_NURB_CYCLIC)==0) len++; prevbezt= bezt; bezt++; } dl= MEM_callocN(sizeof(DispList), "makeDispListbez"); /* len+1 because of 'forward_diff_bezier' function */ dl->verts= MEM_callocN( (len+1)*3*sizeof(float), "dlverts"); BLI_addtail(dispbase, dl); dl->parts= 1; dl->nr= len; dl->col= nu->mat_nr; dl->charidx= nu->charidx; data= dl->verts; if(nu->flagu & CU_NURB_CYCLIC) { dl->type= DL_POLY; a= nu->pntsu; } else { dl->type= DL_SEGM; a= nu->pntsu-1; } prevbezt= nu->bezt; bezt= prevbezt+1; while(a--) { if(a==0 && dl->type== DL_POLY) bezt= nu->bezt; if(prevbezt->h2==HD_VECT && bezt->h1==HD_VECT) { VECCOPY(data, prevbezt->vec[1]); data+= 3; } else { int j; for(j=0; j<3; j++) { forward_diff_bezier( prevbezt->vec[1][j], prevbezt->vec[2][j], bezt->vec[0][j], bezt->vec[1][j], data+j, resolu, 3*sizeof(float)); } data+= 3*resolu; } if(a==0 && dl->type==DL_SEGM) { VECCOPY(data, bezt->vec[1]); } prevbezt= bezt; bezt++; } } else if(nu->type == CU_NURBS) { len= (resolu*SEGMENTSU(nu)); dl= MEM_callocN(sizeof(DispList), "makeDispListsurf"); dl->verts= MEM_callocN(len*3*sizeof(float), "dlverts"); BLI_addtail(dispbase, dl); dl->parts= 1; dl->nr= len; dl->col= nu->mat_nr; dl->charidx = nu->charidx; data= dl->verts; if(nu->flagu & CU_NURB_CYCLIC) dl->type= DL_POLY; else dl->type= DL_SEGM; makeNurbcurve(nu, data, NULL, NULL, NULL, resolu, 3*sizeof(float)); } else if(nu->type == CU_POLY) { len= nu->pntsu; dl= MEM_callocN(sizeof(DispList), "makeDispListpoly"); dl->verts= MEM_callocN(len*3*sizeof(float), "dlverts"); BLI_addtail(dispbase, dl); dl->parts= 1; dl->nr= len; dl->col= nu->mat_nr; dl->charidx = nu->charidx; data= dl->verts; if(nu->flagu & CU_NURB_CYCLIC) dl->type= DL_POLY; else dl->type= DL_SEGM; a= len; bp= nu->bp; while(a--) { VECCOPY(data, bp->vec); bp++; data+= 3; } } } nu= nu->next; } } void filldisplist(ListBase *dispbase, ListBase *to, int flipnormal) { EditVert *eve, *v1, *vlast; EditFace *efa; DispList *dlnew=NULL, *dl; float *f1; int colnr=0, charidx=0, cont=1, tot, a, *index, nextcol= 0; intptr_t totvert; if(dispbase==NULL) return; if(dispbase->first==NULL) return; while(cont) { cont= 0; totvert= 0; nextcol= 0; dl= dispbase->first; while(dl) { if(dl->type==DL_POLY) { if(charidxcharidx) cont= 1; else if(charidx==dl->charidx) { /* character with needed index */ if(colnr==dl->col) { /* make editverts and edges */ f1= dl->verts; a= dl->nr; eve= v1= NULL; while(a--) { vlast= eve; eve= BLI_addfillvert(f1); totvert++; if(vlast==NULL) v1= eve; else { BLI_addfilledge(vlast, eve); } f1+=3; } if(eve!=NULL && v1!=NULL) { BLI_addfilledge(eve, v1); } } else if (colnrcol) { /* got poly with next material at current char */ cont= 1; nextcol= 1; } } } dl= dl->next; } if(totvert && BLI_edgefill(0)) { // XXX (obedit && obedit->actcol)?(obedit->actcol-1):0)) { /* count faces */ tot= 0; efa= fillfacebase.first; while(efa) { tot++; efa= efa->next; } if(tot) { dlnew= MEM_callocN(sizeof(DispList), "filldisplist"); dlnew->type= DL_INDEX3; dlnew->col= colnr; dlnew->nr= totvert; dlnew->parts= tot; dlnew->index= MEM_mallocN(tot*3*sizeof(int), "dlindex"); dlnew->verts= MEM_mallocN(totvert*3*sizeof(float), "dlverts"); /* vert data */ f1= dlnew->verts; totvert= 0; eve= fillvertbase.first; while(eve) { VECCOPY(f1, eve->co); f1+= 3; /* index number */ eve->tmp.l = totvert; totvert++; eve= eve->next; } /* index data */ efa= fillfacebase.first; index= dlnew->index; while(efa) { index[0]= (intptr_t)efa->v1->tmp.l; index[1]= (intptr_t)efa->v2->tmp.l; index[2]= (intptr_t)efa->v3->tmp.l; if(flipnormal) SWAP(int, index[0], index[2]); index+= 3; efa= efa->next; } } BLI_addhead(to, dlnew); } BLI_end_edgefill(); if(nextcol) { /* stay at current char but fill polys with next material */ colnr++; } else { /* switch to next char and start filling from first material */ charidx++; colnr= 0; } } /* do not free polys, needed for wireframe display */ } static void bevels_to_filledpoly(Curve *cu, ListBase *dispbase) { ListBase front, back; DispList *dl, *dlnew; float *fp, *fp1; int a, dpoly; front.first= front.last= back.first= back.last= NULL; dl= dispbase->first; while(dl) { if(dl->type==DL_SURF) { if( (dl->flag & DL_CYCL_V) && (dl->flag & DL_CYCL_U)==0 ) { if( (cu->flag & CU_BACK) && (dl->flag & DL_BACK_CURVE) ) { dlnew= MEM_callocN(sizeof(DispList), "filldisp"); BLI_addtail(&front, dlnew); dlnew->verts= fp1= MEM_mallocN(sizeof(float)*3*dl->parts, "filldisp1"); dlnew->nr= dl->parts; dlnew->parts= 1; dlnew->type= DL_POLY; dlnew->col= dl->col; dlnew->charidx = dl->charidx; fp= dl->verts; dpoly= 3*dl->nr; a= dl->parts; while(a--) { VECCOPY(fp1, fp); fp1+= 3; fp+= dpoly; } } if( (cu->flag & CU_FRONT) && (dl->flag & DL_FRONT_CURVE) ) { dlnew= MEM_callocN(sizeof(DispList), "filldisp"); BLI_addtail(&back, dlnew); dlnew->verts= fp1= MEM_mallocN(sizeof(float)*3*dl->parts, "filldisp1"); dlnew->nr= dl->parts; dlnew->parts= 1; dlnew->type= DL_POLY; dlnew->col= dl->col; dlnew->charidx= dl->charidx; fp= dl->verts+3*(dl->nr-1); dpoly= 3*dl->nr; a= dl->parts; while(a--) { VECCOPY(fp1, fp); fp1+= 3; fp+= dpoly; } } } } dl= dl->next; } filldisplist(&front, dispbase, 1); filldisplist(&back, dispbase, 0); freedisplist(&front); freedisplist(&back); filldisplist(dispbase, dispbase, 0); } static void curve_to_filledpoly(Curve *cu, ListBase *UNUSED(nurb), ListBase *dispbase) { if(cu->flag & CU_3D) return; if(dispbase->first && ((DispList*) dispbase->first)->type==DL_SURF) { bevels_to_filledpoly(cu, dispbase); } else { filldisplist(dispbase, dispbase, 0); } } /* taper rules: - only 1 curve - first point left, last point right - based on subdivided points in original curve, not on points in taper curve (still) */ float calc_taper(Scene *scene, Object *taperobj, int cur, int tot) { DispList *dl; if(taperobj==NULL || taperobj->type!=OB_CURVE) return 1.0; dl= taperobj->disp.first; if(dl==NULL) { makeDispListCurveTypes(scene, taperobj, 0); dl= taperobj->disp.first; } if(dl) { float fac= ((float)cur)/(float)(tot-1); float minx, dx, *fp; int a; /* horizontal size */ minx= dl->verts[0]; dx= dl->verts[3*(dl->nr-1)] - minx; if(dx>0.0) { fp= dl->verts; for(a=0; anr; a++, fp+=3) { if( (fp[0]-minx)/dx >= fac) { /* interpolate with prev */ if(a>0) { float fac1= (fp[-3]-minx)/dx; float fac2= (fp[0]-minx)/dx; if(fac1!=fac2) return fp[1]*(fac1-fac)/(fac1-fac2) + fp[-2]*(fac-fac2)/(fac1-fac2); } return fp[1]; } } return fp[-2]; // last y coord } } return 1.0; } void makeDispListMBall(Scene *scene, Object *ob) { if(!ob || ob->type!=OB_MBALL) return; // XXX: mball stuff uses plenty of global variables // while this is unchanged updating during render is unsafe if(G.rendering) return; freedisplist(&(ob->disp)); if(ob->type==OB_MBALL) { if(ob==find_basis_mball(scene, ob)) { metaball_polygonize(scene, ob, &ob->disp); tex_space_mball(ob); object_deform_mball(ob, &ob->disp); } } boundbox_displist(ob); } void makeDispListMBall_forRender(Scene *scene, Object *ob, ListBase *dispbase) { metaball_polygonize(scene, ob, dispbase); tex_space_mball(ob); object_deform_mball(ob, dispbase); } static ModifierData *curve_get_tesselate_point(Scene *scene, Object *ob, int forRender, int editmode) { ModifierData *md = modifiers_getVirtualModifierList(ob); ModifierData *preTesselatePoint; int required_mode; if(forRender) required_mode = eModifierMode_Render; else required_mode = eModifierMode_Realtime; if(editmode) required_mode |= eModifierMode_Editmode; preTesselatePoint = NULL; for (; md; md=md->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); if (!modifier_isEnabled(scene, md, required_mode)) continue; if (mti->type == eModifierTypeType_Constructive) return preTesselatePoint; if (ELEM3(md->type, eModifierType_Hook, eModifierType_Softbody, eModifierType_MeshDeform)) { preTesselatePoint = md; /* this modifiers are moving point of tesselation automatically (some of them even can't be applied on tesselated curve), set flag for incformation button in modifier's header */ md->mode |= eModifierMode_ApplyOnSpline; } else if(md->mode&eModifierMode_ApplyOnSpline) { preTesselatePoint = md; } } return preTesselatePoint; } static void curve_calc_modifiers_pre(Scene *scene, Object *ob, int forRender, float (**originalVerts_r)[3], float (**deformedVerts_r)[3], int *numVerts_r) { ModifierData *md = modifiers_getVirtualModifierList(ob); ModifierData *preTesselatePoint; Curve *cu= ob->data; ListBase *nurb= BKE_curve_nurbs(cu); int numVerts = 0; int editmode = (!forRender && cu->editnurb); float (*originalVerts)[3] = NULL; float (*deformedVerts)[3] = NULL; float *keyVerts= NULL; int required_mode; if(forRender) required_mode = eModifierMode_Render; else required_mode = eModifierMode_Realtime; preTesselatePoint = curve_get_tesselate_point(scene, ob, forRender, editmode); if(editmode) required_mode |= eModifierMode_Editmode; if(cu->editnurb==NULL) { keyVerts= do_ob_key(scene, ob); if(keyVerts) { /* split coords from key data, the latter also includes tilts, which is passed through in the modifier stack. this is also the reason curves do not use a virtual shape key modifier yet. */ deformedVerts= curve_getKeyVertexCos(cu, nurb, keyVerts); originalVerts= MEM_dupallocN(deformedVerts); } } if (preTesselatePoint) { for (; md; md=md->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); md->scene= scene; if ((md->mode & required_mode) != required_mode) continue; if (mti->isDisabled && mti->isDisabled(md, forRender)) continue; if (mti->type!=eModifierTypeType_OnlyDeform) continue; if (!deformedVerts) { deformedVerts = curve_getVertexCos(cu, nurb, &numVerts); originalVerts = MEM_dupallocN(deformedVerts); } mti->deformVerts(md, ob, NULL, deformedVerts, numVerts, forRender, editmode); if (md==preTesselatePoint) break; } } if (deformedVerts) curve_applyVertexCos(cu, nurb, deformedVerts); if (keyVerts) /* these are not passed through modifier stack */ curve_applyKeyVertexTilts(cu, nurb, keyVerts); if(keyVerts) MEM_freeN(keyVerts); *originalVerts_r = originalVerts; *deformedVerts_r = deformedVerts; *numVerts_r = numVerts; } static float (*displist_get_allverts (ListBase *dispbase, int *totvert))[3] { DispList *dl; float (*allverts)[3], *fp; *totvert= 0; for (dl=dispbase->first; dl; dl=dl->next) *totvert+= (dl->type==DL_INDEX3)?dl->nr:dl->parts*dl->nr; allverts= MEM_mallocN((*totvert)*sizeof(float)*3, "displist_get_allverts allverts"); fp= (float*)allverts; for (dl=dispbase->first; dl; dl=dl->next) { int offs= 3 * ((dl->type==DL_INDEX3)?dl->nr:dl->parts*dl->nr); memcpy(fp, dl->verts, sizeof(float) * offs); fp+= offs; } return allverts; } static void displist_apply_allverts(ListBase *dispbase, float (*allverts)[3]) { DispList *dl; float *fp; fp= (float*)allverts; for (dl=dispbase->first; dl; dl=dl->next) { int offs= 3 * ((dl->type==DL_INDEX3)?dl->nr:dl->parts*dl->nr); memcpy(dl->verts, fp, sizeof(float) * offs); fp+= offs; } } static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *dispbase, DerivedMesh **derivedFinal, int forRender, float (*originalVerts)[3], float (*deformedVerts)[3]) { ModifierData *md = modifiers_getVirtualModifierList(ob); ModifierData *preTesselatePoint; Curve *cu= ob->data; ListBase *nurb= BKE_curve_nurbs(cu); int required_mode = 0, totvert = 0; int editmode = (!forRender && cu->editnurb); DerivedMesh *dm= NULL, *ndm; float (*vertCos)[3] = NULL; if(forRender) required_mode = eModifierMode_Render; else required_mode = eModifierMode_Realtime; preTesselatePoint = curve_get_tesselate_point(scene, ob, forRender, editmode); if(editmode) required_mode |= eModifierMode_Editmode; if (preTesselatePoint) { md = preTesselatePoint->next; } if (derivedFinal && *derivedFinal) { (*derivedFinal)->release (*derivedFinal); } for (; md; md=md->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); md->scene= scene; if ((md->mode & required_mode) != required_mode) continue; if (mti->isDisabled && mti->isDisabled(md, forRender)) continue; if (mti->type == eModifierTypeType_OnlyDeform || (mti->type == eModifierTypeType_DeformOrConstruct && !dm)) { if (dm) { if (!vertCos) { totvert = dm->getNumVerts(dm); vertCos = MEM_mallocN(sizeof(*vertCos) * totvert, "dfmv"); dm->getVertCos(dm, vertCos); } mti->deformVerts(md, ob, dm, vertCos, totvert, forRender, editmode); } else { if (!vertCos) { vertCos= displist_get_allverts(dispbase, &totvert); } mti->deformVerts(md, ob, NULL, vertCos, totvert, forRender, editmode); } } else { if (!derivedFinal) { /* makeDisplistCurveTypes could be used for beveling, where derived mesh */ /* is totally unnecessary, so we could stop modifiers applying */ /* when we found constructive modifier but derived mesh is unwanted result */ break; } if (dm) { if (vertCos) { DerivedMesh *tdm = CDDM_copy(dm); dm->release(dm); dm = tdm; CDDM_apply_vert_coords(dm, vertCos); CDDM_calc_normals(dm); } } else { if (vertCos) { displist_apply_allverts(dispbase, vertCos); } if (ELEM(ob->type, OB_CURVE, OB_FONT) && (cu->flag & CU_DEFORM_FILL)) { curve_to_filledpoly(cu, nurb, dispbase); } dm= CDDM_from_curve_customDB(ob, dispbase); CDDM_calc_normals(dm); } if (vertCos) { /* Vertex coordinates were applied to necessary data, could free it */ MEM_freeN(vertCos); vertCos= NULL; } ndm = mti->applyModifier(md, ob, dm, forRender, editmode); if (ndm) { /* Modifier returned a new derived mesh */ if (dm && dm != ndm) /* Modifier */ dm->release (dm); dm = ndm; } } } if (vertCos) { if (dm) { DerivedMesh *tdm = CDDM_copy(dm); dm->release(dm); dm = tdm; CDDM_apply_vert_coords(dm, vertCos); CDDM_calc_normals(dm); MEM_freeN(vertCos); } else { displist_apply_allverts(dispbase, vertCos); MEM_freeN(vertCos); vertCos= NULL; } } if (derivedFinal) { (*derivedFinal) = dm; } if (deformedVerts) { curve_applyVertexCos(ob->data, nurb, originalVerts); MEM_freeN(originalVerts); MEM_freeN(deformedVerts); } } static void displist_surf_indices(DispList *dl) { int a, b, p1, p2, p3, p4; int *index; dl->totindex= 0; index=dl->index= MEM_mallocN( 4*sizeof(int)*(dl->parts+1)*(dl->nr+1), "index array nurbs"); for(a=0; aparts; a++) { if (surfindex_displist(dl, a, &b, &p1, &p2, &p3, &p4)==0) break; for(; bnr; b++, index+=4) { index[0]= p1; index[1]= p2; index[2]= p4; index[3]= p3; dl->totindex++; p2= p1; p1++; p4= p3; p3++; } } } static DerivedMesh *create_orco_dm(Scene *scene, Object *ob) { DerivedMesh *dm; ListBase disp= {NULL, NULL}; /* OrcoDM should be created from underformed disp lists */ makeDispListCurveTypes_forOrco(scene, ob, &disp); dm= CDDM_from_curve_customDB(ob, &disp); freedisplist(&disp); return dm; } static void add_orco_dm(Scene *scene, Object *ob, DerivedMesh *dm, DerivedMesh *orcodm) { float (*orco)[3], (*layerorco)[3]; int totvert, a; Curve *cu= ob->data; totvert= dm->getNumVerts(dm); if(orcodm) { orco= MEM_callocN(sizeof(float)*3*totvert, "dm orco"); if(orcodm->getNumVerts(orcodm) == totvert) orcodm->getVertCos(orcodm, orco); else dm->getVertCos(dm, orco); } else { orco= (float(*)[3])make_orco_curve(scene, ob); } for(a=0; aloc[0])/cu->size[0]; co[1] = (co[1]-cu->loc[1])/cu->size[1]; co[2] = (co[2]-cu->loc[2])/cu->size[2]; } if((layerorco = DM_get_vert_data_layer(dm, CD_ORCO))) { memcpy(layerorco, orco, sizeof(float)*totvert); MEM_freeN(orco); } else DM_add_vert_layer(dm, CD_ORCO, CD_ASSIGN, orco); } static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *derivedFinal, int forRender) { /* this function represents logic of mesh's orcodm calculation */ /* for displist-based objects */ ModifierData *md = modifiers_getVirtualModifierList(ob); ModifierData *preTesselatePoint; Curve *cu= ob->data; int required_mode; int editmode = (!forRender && cu->editnurb); DerivedMesh *ndm, *orcodm= NULL; if(forRender) required_mode = eModifierMode_Render; else required_mode = eModifierMode_Realtime; preTesselatePoint = curve_get_tesselate_point(scene, ob, forRender, editmode); if(editmode) required_mode |= eModifierMode_Editmode; if (preTesselatePoint) { md = preTesselatePoint->next; } for (; md; md=md->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); md->scene= scene; if ((md->mode & required_mode) != required_mode) continue; if (mti->isDisabled && mti->isDisabled(md, forRender)) continue; if (mti->type!=eModifierTypeType_Constructive) continue; if(!orcodm) orcodm= create_orco_dm(scene, ob); ndm = mti->applyModifier(md, ob, orcodm, forRender, 0); if(ndm) { /* if the modifier returned a new dm, release the old one */ if(orcodm && orcodm != ndm) { orcodm->release(orcodm); } orcodm = ndm; } } /* add an orco layer if needed */ add_orco_dm(scene, ob, derivedFinal, orcodm); if(orcodm) orcodm->release(orcodm); } void makeDispListSurf(Scene *scene, Object *ob, ListBase *dispbase, DerivedMesh **derivedFinal, int forRender, int forOrco) { ListBase *nubase; Nurb *nu; Curve *cu = ob->data; DispList *dl; float *data; int len; int numVerts; float (*originalVerts)[3]; float (*deformedVerts)[3]; if(!forRender && cu->editnurb) nubase= ED_curve_editnurbs(cu); else nubase= &cu->nurb; if(!forOrco) curve_calc_modifiers_pre(scene, ob, forRender, &originalVerts, &deformedVerts, &numVerts); for (nu=nubase->first; nu; nu=nu->next) { if(forRender || nu->hide==0) { int resolu= nu->resolu, resolv= nu->resolv; if(forRender){ if(cu->resolu_ren) resolu= cu->resolu_ren; if(cu->resolv_ren) resolv= cu->resolv_ren; } if(nu->pntsv==1) { len= SEGMENTSU(nu)*resolu; dl= MEM_callocN(sizeof(DispList), "makeDispListsurf"); dl->verts= MEM_callocN(len*3*sizeof(float), "dlverts"); BLI_addtail(dispbase, dl); dl->parts= 1; dl->nr= len; dl->col= nu->mat_nr; dl->charidx= nu->charidx; /* dl->rt will be used as flag for render face and */ /* CU_2D conflicts with R_NOPUNOFLIP */ dl->rt= nu->flag & ~CU_2D; data= dl->verts; if(nu->flagu & CU_NURB_CYCLIC) dl->type= DL_POLY; else dl->type= DL_SEGM; makeNurbcurve(nu, data, NULL, NULL, NULL, resolu, 3*sizeof(float)); } else { len= (nu->pntsu*resolu) * (nu->pntsv*resolv); dl= MEM_callocN(sizeof(DispList), "makeDispListsurf"); dl->verts= MEM_callocN(len*3*sizeof(float), "dlverts"); BLI_addtail(dispbase, dl); dl->col= nu->mat_nr; dl->charidx= nu->charidx; /* dl->rt will be used as flag for render face and */ /* CU_2D conflicts with R_NOPUNOFLIP */ dl->rt= nu->flag & ~CU_2D; data= dl->verts; dl->type= DL_SURF; dl->parts= (nu->pntsu*resolu); /* in reverse, because makeNurbfaces works that way */ dl->nr= (nu->pntsv*resolv); if(nu->flagv & CU_NURB_CYCLIC) dl->flag|= DL_CYCL_U; /* reverse too! */ if(nu->flagu & CU_NURB_CYCLIC) dl->flag|= DL_CYCL_V; makeNurbfaces(nu, data, 0, resolu, resolv); /* gl array drawing: using indices */ displist_surf_indices(dl); } } } /* make copy of 'undeformed" displist for texture space calculation actually, it's not totally undeformed -- pre-tesselation modifiers are already applied, thats how it worked for years, so keep for compatibility (sergey) */ copy_displist(&cu->disp, dispbase); if (!forRender) { tex_space_curve(cu); } if(!forOrco) curve_calc_modifiers_post(scene, ob, dispbase, derivedFinal, forRender, originalVerts, deformedVerts); } static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispbase, DerivedMesh **derivedFinal, int forRender, int forOrco) { Curve *cu = ob->data; /* we do allow duplis... this is only displist on curve level */ if(!ELEM3(ob->type, OB_SURF, OB_CURVE, OB_FONT)) return; if(ob->type==OB_SURF) { makeDispListSurf(scene, ob, dispbase, derivedFinal, forRender, forOrco); } else if (ELEM(ob->type, OB_CURVE, OB_FONT)) { ListBase dlbev; ListBase *nubase; float (*originalVerts)[3]; float (*deformedVerts)[3]; int numVerts; nubase= BKE_curve_nurbs(cu); BLI_freelistN(&(cu->bev)); if(cu->path) free_path(cu->path); cu->path= NULL; if(ob->type==OB_FONT) BKE_text_to_curve(scene, ob, 0); if(!forOrco) curve_calc_modifiers_pre(scene, ob, forRender, &originalVerts, &deformedVerts, &numVerts); makeBevelList(ob); /* If curve has no bevel will return nothing */ makebevelcurve(scene, ob, &dlbev, forRender); /* no bevel or extrude, and no width correction? */ if (!dlbev.first && cu->width==1.0f) { curve_to_displist(cu, nubase, dispbase, forRender); } else { float widfac= cu->width-1.0; BevList *bl= cu->bev.first; Nurb *nu= nubase->first; for (; bl && nu; bl=bl->next,nu=nu->next) { DispList *dl; float *fp1, *data; BevPoint *bevp; int a,b; if (bl->nr) { /* blank bevel lists can happen */ /* exception handling; curve without bevel or extrude, with width correction */ if(dlbev.first==NULL) { dl= MEM_callocN(sizeof(DispList), "makeDispListbev"); dl->verts= MEM_callocN(3*sizeof(float)*bl->nr, "dlverts"); BLI_addtail(dispbase, dl); if(bl->poly!= -1) dl->type= DL_POLY; else dl->type= DL_SEGM; if(dl->type==DL_SEGM) dl->flag = (DL_FRONT_CURVE|DL_BACK_CURVE); dl->parts= 1; dl->nr= bl->nr; dl->col= nu->mat_nr; dl->charidx= nu->charidx; /* dl->rt will be used as flag for render face and */ /* CU_2D conflicts with R_NOPUNOFLIP */ dl->rt= nu->flag & ~CU_2D; a= dl->nr; bevp= (BevPoint *)(bl+1); data= dl->verts; while(a--) { data[0]= bevp->vec[0]+widfac*bevp->sina; data[1]= bevp->vec[1]+widfac*bevp->cosa; data[2]= bevp->vec[2]; bevp++; data+=3; } } else { DispList *dlb; for (dlb=dlbev.first; dlb; dlb=dlb->next) { /* for each part of the bevel use a separate displblock */ dl= MEM_callocN(sizeof(DispList), "makeDispListbev1"); dl->verts= data= MEM_callocN(3*sizeof(float)*dlb->nr*bl->nr, "dlverts"); BLI_addtail(dispbase, dl); dl->type= DL_SURF; dl->flag= dlb->flag & (DL_FRONT_CURVE|DL_BACK_CURVE); if(dlb->type==DL_POLY) dl->flag |= DL_CYCL_U; if(bl->poly>=0) dl->flag |= DL_CYCL_V; dl->parts= bl->nr; dl->nr= dlb->nr; dl->col= nu->mat_nr; dl->charidx= nu->charidx; /* dl->rt will be used as flag for render face and */ /* CU_2D conflicts with R_NOPUNOFLIP */ dl->rt= nu->flag & ~CU_2D; dl->bevelSplitFlag= MEM_callocN(sizeof(*dl->col2)*((bl->nr+0x1F)>>5), "bevelSplitFlag"); /* for each point of poly make a bevel piece */ bevp= (BevPoint *)(bl+1); for(a=0; anr; a++,bevp++) { float fac=1.0; if (cu->taperobj==NULL) { if ( (cu->bevobj!=NULL) || !((cu->flag & CU_FRONT) || (cu->flag & CU_BACK)) ) fac = bevp->radius; } else { fac = calc_taper(scene, cu->taperobj, a, bl->nr); } if (bevp->split_tag) { dl->bevelSplitFlag[a>>5] |= 1<<(a&0x1F); } /* rotate bevel piece and write in data */ fp1= dlb->verts; for (b=0; bnr; b++,fp1+=3,data+=3) { if(cu->flag & CU_3D) { float vec[3]; vec[0]= fp1[1]+widfac; vec[1]= fp1[2]; vec[2]= 0.0; mul_qt_v3(bevp->quat, vec); data[0]= bevp->vec[0] + fac*vec[0]; data[1]= bevp->vec[1] + fac*vec[1]; data[2]= bevp->vec[2] + fac*vec[2]; } else { data[0]= bevp->vec[0] + fac*(widfac+fp1[1])*bevp->sina; data[1]= bevp->vec[1] + fac*(widfac+fp1[1])*bevp->cosa; data[2]= bevp->vec[2] + fac*fp1[2]; } } } /* gl array drawing: using indices */ displist_surf_indices(dl); } } } } freedisplist(&dlbev); } if (!(cu->flag & CU_DEFORM_FILL)) { curve_to_filledpoly(cu, nubase, dispbase); } if(cu->flag & CU_PATH) calc_curvepath(ob); /* make copy of 'undeformed" displist for texture space calculation actually, it's not totally undeformed -- pre-tesselation modifiers are already applied, thats how it worked for years, so keep for compatibility (sergey) */ copy_displist(&cu->disp, dispbase); if (!forRender) { tex_space_curve(cu); } if(!forOrco) curve_calc_modifiers_post(scene, ob, dispbase, derivedFinal, forRender, originalVerts, deformedVerts); if (cu->flag & CU_DEFORM_FILL && !ob->derivedFinal) { curve_to_filledpoly(cu, nubase, dispbase); } } } void makeDispListCurveTypes(Scene *scene, Object *ob, int forOrco) { Curve *cu= ob->data; ListBase *dispbase; freedisplist(&(ob->disp)); dispbase= &(ob->disp); freedisplist(dispbase); /* free displist used for textspace */ freedisplist(&cu->disp); do_makeDispListCurveTypes(scene, ob, dispbase, &ob->derivedFinal, 0, forOrco); if (ob->derivedFinal) { DM_set_object_boundbox (ob, ob->derivedFinal); } else { boundbox_displist (ob); /* if there is no derivedMesh, object's boundbox is unneeded */ if (ob->bb) { MEM_freeN(ob->bb); ob->bb= NULL; } } } void makeDispListCurveTypes_forRender(Scene *scene, Object *ob, ListBase *dispbase, DerivedMesh **derivedFinal, int forOrco) { do_makeDispListCurveTypes(scene, ob, dispbase, derivedFinal, 1, forOrco); } void makeDispListCurveTypes_forOrco(struct Scene *scene, struct Object *ob, struct ListBase *dispbase) { do_makeDispListCurveTypes(scene, ob, dispbase, NULL, 1, 1); } /* add Orco layer to the displist object which has got derived mesh and return orco */ float *makeOrcoDispList(Scene *scene, Object *ob, DerivedMesh *derivedFinal, int forRender) { float *orco; if (derivedFinal == NULL) derivedFinal= ob->derivedFinal; if (!derivedFinal->getVertDataArray(derivedFinal, CD_ORCO)) { curve_calc_orcodm(scene, ob, derivedFinal, forRender); } orco= derivedFinal->getVertDataArray(derivedFinal, CD_ORCO); if(orco) { orco= MEM_dupallocN(orco); } return orco; } void imagestodisplist(void) { /* removed */ } /* this is confusing, there's also min_max_object, appplying the obmat... */ static void boundbox_displist(Object *ob) { BoundBox *bb=NULL; float min[3], max[3]; DispList *dl; float *vert; int a, tot=0; INIT_MINMAX(min, max); if(ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { Curve *cu= ob->data; int doit= 0; if(cu->bb==NULL) cu->bb= MEM_callocN(sizeof(BoundBox), "boundbox"); bb= cu->bb; dl= ob->disp.first; while (dl) { if(dl->type==DL_INDEX3) tot= dl->nr; else tot= dl->nr*dl->parts; vert= dl->verts; for(a=0; anext; } if(!doit) { min[0] = min[1] = min[2] = -1.0f; max[0] = max[1] = max[2] = 1.0f; } } if(bb) { boundbox_set_from_min_max(bb, min, max); } }