This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/blenkernel/intern/displist.c

2148 lines
47 KiB
C

/* displist.c
*
*
* $Id$
*
* ***** BEGIN GPL/BL DUAL 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. The Blender
* Foundation also sells licenses for use in proprietary software under
* the Blender License. See http://www.blender.org/BL/ for information
* about this.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL/BL DUAL LICENSE BLOCK *****
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <math.h>
#include <stdio.h>
#include <string.h>
#include "MEM_guardedalloc.h"
#include "IMB_imbuf_types.h"
#include "DNA_texture_types.h"
#include "DNA_meta_types.h"
#include "DNA_curve_types.h"
#include "DNA_effect_types.h"
#include "DNA_listBase.h"
#include "DNA_lamp_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_scene_types.h"
#include "DNA_image_types.h"
#include "DNA_material_types.h"
#include "DNA_view3d_types.h"
#include "DNA_lattice_types.h"
#include "BLI_blenlib.h"
#include "BLI_arithb.h"
#include "BLI_editVert.h"
#include "BKE_bad_level_calls.h"
#include "BKE_utildefines.h"
#include "BKE_global.h"
#include "BKE_displist.h"
#include "BKE_deform.h"
#include "BKE_DerivedMesh.h"
#include "BKE_object.h"
#include "BKE_world.h"
#include "BKE_mesh.h"
#include "BKE_effect.h"
#include "BKE_mball.h"
#include "BKE_material.h"
#include "BKE_curve.h"
#include "BKE_anim.h"
#include "BKE_screen.h"
#include "BKE_texture.h"
#include "BKE_library.h"
#include "BKE_font.h"
#include "BKE_lattice.h"
#include "BKE_scene.h"
#include "BKE_subsurf.h"
#include "nla.h" /* For __NLA: Please do not remove yet */
#include "render.h"
/***/
typedef struct _FastLamp FastLamp;
struct _FastLamp {
FastLamp *next;
short type, mode, lay, rt;
float co[3];
float vec[3];
float dist, distkw, att1, att2, spotsi, spotbl, r, g, b;
};
/***/
static void boundbox_displist(Object *ob);
static FastLamp *fastlamplist= NULL;
static float fviewmat[4][4];
void displistmesh_free(DispListMesh *dlm)
{
// also check on mvert and mface, can be NULL after decimator (ton)
if (!dlm->dontFreeVerts && dlm->mvert) MEM_freeN(dlm->mvert);
if (!dlm->dontFreeNors && dlm->nors) MEM_freeN(dlm->nors);
if (!dlm->dontFreeOther) {
if (dlm->medge) MEM_freeN(dlm->medge);
if (dlm->mface) MEM_freeN(dlm->mface);
if (dlm->mcol) MEM_freeN(dlm->mcol);
if (dlm->tface) MEM_freeN(dlm->tface);
}
MEM_freeN(dlm);
}
DispListMesh *displistmesh_copy(DispListMesh *odlm)
{
DispListMesh *ndlm= MEM_dupallocN(odlm);
ndlm->mvert= MEM_dupallocN(odlm->mvert);
ndlm->medge= MEM_dupallocN(odlm->medge);
ndlm->mface= MEM_dupallocN(odlm->mface);
if (odlm->nors) ndlm->nors = MEM_dupallocN(odlm->nors);
if (odlm->mcol) ndlm->mcol= MEM_dupallocN(odlm->mcol);
if (odlm->tface) ndlm->tface= MEM_dupallocN(odlm->tface);
return ndlm;
}
void displistmesh_calc_normals(DispListMesh *dlm)
{
MVert *mverts= dlm->mvert;
MFace *mfaces= dlm->mface;
float (*tnorms)[3]= MEM_callocN(dlm->totvert*sizeof(*tnorms), "tnorms");
int i;
if (!dlm->dontFreeNors && dlm->nors) {
MEM_freeN(dlm->nors);
}
dlm->nors= MEM_mallocN(sizeof(*dlm->nors)*3*dlm->totface, "meshnormals");
dlm->dontFreeNors= 0;
for (i=0; i<dlm->totface; i++) {
MFace *mf= &mfaces[i];
float *f_no= &dlm->nors[i*3];
if (!mf->v3)
continue;
if (mf->v4)
CalcNormFloat4(mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co, mverts[mf->v4].co, f_no);
else
CalcNormFloat(mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co, f_no);
VecAddf(tnorms[mf->v1], tnorms[mf->v1], f_no);
VecAddf(tnorms[mf->v2], tnorms[mf->v2], f_no);
VecAddf(tnorms[mf->v3], tnorms[mf->v3], f_no);
if (mf->v4)
VecAddf(tnorms[mf->v4], tnorms[mf->v4], f_no);
}
for (i=0; i<dlm->totvert; i++) {
MVert *mv= &mverts[i];
float *no= tnorms[i];
Normalise(no);
mv->no[0]= (short)(no[0]*32767.0);
mv->no[1]= (short)(no[1]*32767.0);
mv->no[2]= (short)(no[2]*32767.0);
}
MEM_freeN(tnorms);
}
void displistmesh_to_mesh(DispListMesh *dlm, Mesh *me)
{
MFace *mfaces;
int i;
if (dlm->totvert>MESH_MAX_VERTS) {
error("Too many vertices");
} else {
me->totface= dlm->totface;
me->totvert= dlm->totvert;
me->mvert= MEM_dupallocN(dlm->mvert);
me->mface= mfaces= MEM_mallocN(sizeof(*mfaces)*me->totface, "me->mface");
me->tface= MEM_dupallocN(dlm->tface);
me->mcol= MEM_dupallocN(dlm->mcol);
if(dlm->medge) {
me->totedge= dlm->totedge;
me->medge= MEM_dupallocN(dlm->medge);
}
for (i=0; i<me->totface; i++) {
MFace *mf= &mfaces[i];
MFace *oldmf= &dlm->mface[i];
mf->v1= oldmf->v1;
mf->v2= oldmf->v2;
mf->v3= oldmf->v3;
mf->v4= oldmf->v4;
mf->flag= oldmf->flag;
mf->mat_nr= oldmf->mat_nr;
mf->puno= 0;
mf->edcode= ME_V1V2|ME_V2V3|ME_V3V4|ME_V4V1;
}
}
}
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);
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 0;
}
int displist_has_faces(ListBase *lb)
{
DispList *dl;
dl= lb->first;
while(dl) {
if ELEM4(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF, DL_POLY)
return 1;
dl= dl->next;
}
return 0;
}
void copy_displist(ListBase *lbn, ListBase *lb)
{
DispList *dln, *dl;
lbn->first= lbn->last= 0;
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);
dl= dl->next;
}
}
static void initfastshade(void)
{
Base *base;
Object *ob;
Lamp *la;
FastLamp *fl;
float mat[4][4];
init_render_world();
if(fastlamplist) return;
if(G.scene->camera==0) G.scene->camera= scene_find_camera(G.scene);
if(G.scene->camera==0) return;
/* copied from 'roteerscene' (does that function still exist? (ton) */
where_is_object(G.scene->camera);
Mat4CpyMat4(R.viewinv, G.scene->camera->obmat);
Mat4Ortho(R.viewinv);
Mat4Invert(fviewmat, R.viewinv);
/* initrendertexture(); */
base= G.scene->base.first;
while(base) {
ob= base->object;
if( ob->type==OB_LAMP && (base->lay & G.scene->lay)) {
Mat4MulMat4(mat, ob->obmat, fviewmat);
la= ob->data;
fl= MEM_mallocN(sizeof(FastLamp), "initfastshade2");
fl->next= fastlamplist;
fastlamplist= fl;
fl->type= la->type;
fl->mode= la->mode;
fl->lay= base->lay;
fl->vec[0]= mat[2][0];
fl->vec[1]= mat[2][1];
fl->vec[2]= mat[2][2];
Normalise(fl->vec);
fl->co[0]= mat[3][0];
fl->co[1]= mat[3][1];
fl->co[2]= mat[3][2];
fl->dist= la->dist;
fl->distkw= fl->dist*fl->dist;
fl->att1= la->att1;
fl->att2= la->att2;
fl->spotsi= (float)cos( M_PI*la->spotsize/360.0 );
fl->spotbl= (1.0f-fl->spotsi)*la->spotblend;
fl->r= la->energy*la->r;
fl->g= la->energy*la->g;
fl->b= la->energy*la->b;
}
if(base->next==0 && G.scene->set && base==G.scene->base.last) base= G.scene->set->base.first;
else base= base->next;
}
}
void freefastshade()
{
while (fastlamplist) {
FastLamp *fl= fastlamplist;
fastlamplist= fl->next;
MEM_freeN(fl);
}
}
static void fastshade(float *co, float *nor, float *orco, Material *ma, char *col1, char *col2, char *vertcol)
{
ShadeInput shi;
FastLamp *fl;
float i, t, inp, is, soft, lv[3], lampdist, ld;
float diff1[3], diff2[3];
float isr1=0, isg1=0, isb1=0, isr=0, isg=0, isb=0;
int a, back;
if(ma==0) return;
shi.mat= ma;
shi.vlr= NULL; // have to do this!
// copy all relevant material vars, note, keep this synced with render_types.h
memcpy(&shi.r, &shi.mat->r, 23*sizeof(float));
// set special cases:
shi.har= shi.mat->har;
shi.osatex= 0; // also prevents reading vlr
VECCOPY(shi.vn, nor);
if(ma->mode & MA_VERTEXCOLP) {
if(vertcol) {
shi.r= vertcol[3]/255.0;
shi.g= vertcol[2]/255.0;
shi.b= vertcol[1]/255.0;
}
}
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_UV) {
VECCOPY(shi.uv, 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) {
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]);
}
do_material_tex(&shi);
}
if(ma->mode & MA_SHLESS) {
if(vertcol && (ma->mode & (MA_VERTEXCOL+MA_VERTEXCOLP))== MA_VERTEXCOL ) {
float fac;
fac= vertcol[3]*shi.r;
col1[3]= fac>=1.0?255:(char)fac;
fac= vertcol[2]*shi.g;
col1[2]= fac>=1.0?255:(char)fac;
fac= vertcol[1]*shi.b;
col1[1]= fac>=1.0?255:(char)fac;
}
else {
int fac;
fac= (int) (255.0*shi.r);
col1[3]= fac>255?255:(char)fac;
fac= (int) (255.0*shi.g);
col1[2]= fac>255?255:(char)fac;
fac= (int) (255.0*shi.b);
col1[1]= fac>255?255:(char)fac;
}
if(col2) {
col2[3]= col1[3];
col2[2]= col1[2];
col2[1]= col1[1];
}
return;
}
if( vertcol && (ma->mode & (MA_VERTEXCOL+MA_VERTEXCOLP))== MA_VERTEXCOL ) {
diff1[0]= diff2[0]= shi.r*(shi.emit+vertcol[3]/255.0);
diff1[1]= diff2[1]= shi.g*(shi.emit+vertcol[2]/255.0);
diff1[2]= diff2[2]= shi.b*(shi.emit+vertcol[1]/255.0);
}
else {
diff1[0]= diff2[0]= shi.r*shi.emit;
diff1[1]= diff2[1]= shi.g*shi.emit;
diff1[2]= diff2[2]= shi.b*shi.emit;
}
shi.view[0]= 0.0;
shi.view[1]= 0.0;
shi.view[2]= 1.0;
Normalise(shi.view);
for (fl= fastlamplist; fl; fl= fl->next) {
/* if(fl->mode & LA_LAYER) if((fl->lay & ma->lay)==0) continue; */
if(fl->type==LA_SUN || fl->type==LA_HEMI) {
VECCOPY(lv, fl->vec);
lampdist= 1.0;
}
else {
lv[0]= fl->co[0] - co[0];
lv[1]= fl->co[1] - co[1];
lv[2]= fl->co[2] - co[2];
ld= sqrt(lv[0]*lv[0]+lv[1]*lv[1]+lv[2]*lv[2]);
lv[0]/=ld;
lv[1]/=ld;
lv[2]/=ld;
if(fl->mode & LA_QUAD) {
t= 1.0;
if(fl->att1>0.0)
t= fl->dist/(fl->dist+fl->att1*ld);
if(fl->att2>0.0)
t*= fl->distkw/(fl->distkw+fl->att2*ld*ld);
lampdist= t;
}
else {
lampdist= (fl->dist/(fl->dist+ld));
}
if(fl->mode & LA_SPHERE) {
t= fl->dist - ld;
if(t<0.0) continue;
t/= fl->dist;
lampdist*= (t);
}
}
if(fl->type==LA_SPOT) {
inp= lv[0]*fl->vec[0]+lv[1]*fl->vec[1]+lv[2]*fl->vec[2];
if(inp<fl->spotsi) continue;
else {
t= inp-fl->spotsi;
i= 1.0;
soft= 1.0;
if(t<fl->spotbl && fl->spotbl!=0.0) {
/* soft area */
i= t/fl->spotbl;
t= i*i;
soft= (3.0*t-2.0*t*i);
inp*= soft;
}
lampdist*=inp;
}
}
if(fl->mode & LA_NO_DIFF) is= 0.0;
else {
is= nor[0]*lv[0]+ nor[1]*lv[1]+ nor[2]*lv[2];
if(ma->diff_shader==MA_DIFF_ORENNAYAR) is= OrenNayar_Diff(nor, lv, shi.view, ma->roughness);
else if(ma->diff_shader==MA_DIFF_TOON) is= Toon_Diff(nor, lv, shi.view, ma->param[0], ma->param[1]);
else if(ma->diff_shader==MA_DIFF_MINNAERT) is= Minnaert_Diff(is, nor, shi.view, ma->darkness);
}
back= 0;
if(is<0.0) {
back= 1;
is= -is;
}
inp= is*lampdist*shi.refl;
if(back==0) {
add_to_diffuse(diff1, &shi, is, inp*fl->r, inp*fl->g, inp*fl->b);
//diff1[0]+= inp*fl->r;
//diff1[1]+= inp*fl->g;
//diff1[2]+= inp*fl->b;
} else if(col2) {
add_to_diffuse(diff2, &shi, is, inp*fl->r, inp*fl->g, inp*fl->b);
//diff2[0]+= inp*fl->r;
//diff2[1]+= inp*fl->g;
//diff2[2]+= inp*fl->b;
}
if(shi.spec!=0.0 && (fl->mode & LA_NO_SPEC)==0) {
float specfac;
if(ma->spec_shader==MA_SPEC_PHONG)
specfac= Phong_Spec(nor, lv, shi.view, shi.har);
else if(ma->spec_shader==MA_SPEC_COOKTORR)
specfac= CookTorr_Spec(nor, lv, shi.view, shi.har);
else if(ma->spec_shader==MA_SPEC_BLINN)
specfac= Blinn_Spec(nor, lv, shi.view, ma->refrac, (float)shi.har);
else if(ma->spec_shader==MA_SPEC_WARDISO)
specfac= WardIso_Spec(nor, lv, shi.view, ma->rms);
else
specfac= Toon_Spec(nor, lv, shi.view, ma->param[2], ma->param[3]);
if(specfac>0) {
t= specfac*shi.spec*lampdist;
if(back==0) {
if(ma->mode & MA_RAMP_SPEC) {
float spec[3];
do_specular_ramp(&shi, specfac, t, spec);
isr+= t*(fl->r * spec[0]);
isg+= t*(fl->g * spec[1]);
isb+= t*(fl->b * spec[2]);
}
else {
isr+= t*(fl->r * shi.specr);
isg+= t*(fl->g * shi.specg);
isb+= t*(fl->b * shi.specb);
}
}
else if(col2) {
if(ma->mode & MA_RAMP_SPEC) {
float spec[3];
do_specular_ramp(&shi, specfac, t, spec);
isr1+= t*(fl->r * spec[0]);
isg1+= t*(fl->g * spec[1]);
isb1+= t*(fl->b * spec[2]);
}
else {
isr1+= t*(fl->r * shi.specr);
isg1+= t*(fl->g * shi.specg);
isb1+= t*(fl->b * shi.specb);
}
}
}
}
}
if(ma->mode & MA_RAMP_COL) ramp_diffuse_result(diff1, &shi);
if(ma->mode & MA_RAMP_SPEC) ramp_spec_result(&isr, &isg, &isb, &shi);
a= 256*(diff1[0] + shi.ambr +isr);
if(a>255) col1[3]= 255;
else col1[3]= a;
a= 256*(diff1[1] + shi.ambg +isg);
if(a>255) col1[2]= 255;
else col1[2]= a;
a= 256*(diff1[2] + shi.ambb +isb);
if(a>255) col1[1]= 255;
else col1[1]= a;
if(col2) {
if(ma->mode & MA_RAMP_COL) ramp_diffuse_result(diff2, &shi);
if(ma->mode & MA_RAMP_SPEC) ramp_spec_result(&isr1, &isg1, &isb1, &shi);
a= 256*(diff2[0] + shi.ambr +isr1);
if(a>255) col2[3]= 255;
else col2[3]= a;
a= 256*(diff2[1] + shi.ambg +isg1);
if(a>255) col2[2]= 255;
else col2[2]= a;
a= 256*(diff2[2] + shi.ambb +isb1);
if(a>255) col2[1]= 255;
else col2[1]= a;
}
}
static float *mesh_build_faceNormals(Object *meshOb)
{
Mesh *me = meshOb->data;
float *nors = MEM_mallocN(sizeof(float)*3*me->totface, "meshnormals");
float *n1 = nors;
int i;
for (i=0; i<me->totface; i++,n1+=3) {
MFace *mf = &me->mface[i];
if (mf->v3) {
MVert *ve1= &me->mvert[mf->v1];
MVert *ve2= &me->mvert[mf->v2];
MVert *ve3= &me->mvert[mf->v3];
MVert *ve4= &me->mvert[mf->v4];
if(mf->v4) CalcNormFloat4(ve1->co, ve2->co, ve3->co, ve4->co, n1);
else CalcNormFloat(ve1->co, ve2->co, ve3->co, n1);
}
}
return nors;
}
void addnormalsDispList(Object *ob, ListBase *lb)
{
DispList *dl = NULL;
Mesh *me;
float *vdata, *ndata, nor[3];
float *v1, *v2, *v3, *v4;
float *n1, *n2, *n3, *n4;
int a, b, p1, p2, p3, p4;
if(ob->type==OB_MESH) {
me= get_mesh(ob);
if(me->totface==0) return;
if(me->disp.first==0) {
dl= MEM_callocN(sizeof(DispList), "meshdisp");
dl->type= DL_NORS;
dl->parts= 1;
dl->nr= me->totface;
BLI_addtail(&me->disp, dl);
}
else return;
if(dl->nors==0) {
dl->nors= mesh_build_faceNormals(ob);
}
return;
}
dl= lb->first;
while(dl) {
if(dl->type==DL_INDEX3) {
if(dl->nors==0) {
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==0) {
dl->nors= MEM_callocN(sizeof(float)*3*dl->nr*dl->parts, "dlnors");
vdata= dl->verts;
ndata= dl->nors;
for(a=0; a<dl->parts; a++) {
DL_SURFINDEX(dl->flag & DL_CYCL_U, dl->flag & DL_CYCL_V, dl->nr, dl->parts);
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(; b<dl->nr; b++) {
CalcNormFloat4(v1, v3, v4, v2, nor);
VecAddf(n1, n1, nor);
VecAddf(n2, n2, nor);
VecAddf(n3, n3, nor);
VecAddf(n4, 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--) {
Normalise(v1);
v1+= 3;
}
}
}
dl= dl->next;
}
}
void shadeDispList(Object *ob)
{
DispList *dl, *dlob;
Material *ma = NULL;
Curve *cu;
float *orco=NULL, imat[3][3], tmat[4][4], mat[4][4], vec[3], xn, yn, zn;
float *fp, *nor, n1[3];
unsigned int *col1;
int a, lastmat= -1, need_orco = 0;
if(ob->flag & OB_FROMDUPLI) return;
initfastshade();
Mat4MulMat4(mat, ob->obmat, fviewmat);
Mat4Invert(tmat, mat);
Mat3CpyMat4(imat, tmat);
if(ob->transflag & OB_NEG_SCALE) Mat3MulFloat((float *)imat, -1.0);
dl = find_displist(&ob->disp, DL_VERTCOL);
if (dl) {
BLI_remlink(&ob->disp, dl);
free_disp_elem(dl);
}
need_orco= 0;
for(a=0; a<ob->totcol; a++) {
ma= give_current_material(ob, a+1);
if(ma) {
init_render_material(ma);
if(ma->texco & TEXCO_ORCO) need_orco= 1;
}
}
if(ob->type==OB_MESH) {
Mesh *me= ob->data;
int dmNeedsFree;
DerivedMesh *dm= mesh_get_derived_final(ob, &dmNeedsFree);
DispListMesh *dlm;
MVert *mvert;
if (need_orco) {
make_orco_displist_mesh(ob, me->subdiv);
orco= me->orco;
} else {
orco= NULL;
}
dlm= dm->convertToDispListMesh(dm);
if (dlm && dlm->totvert) {
float *vnors, *vn;
int i;
dlob= MEM_callocN(sizeof(DispList), "displistshade");
BLI_addtail(&ob->disp, dlob);
dlob->type= DL_VERTCOL;
dlob->col1= MEM_mallocN(sizeof(*dlob->col1)*dlm->totface*4, "col1");
if (me->flag & ME_TWOSIDED)
dlob->col2= MEM_mallocN(sizeof(*dlob->col2)*dlm->totface*4, "col1");
/* vertexnormals */
vn=vnors= MEM_mallocN(dlm->totvert*3*sizeof(float), "vnors disp");
mvert= dlm->mvert;
a= dlm->totvert;
while(a--) {
xn= mvert->no[0];
yn= mvert->no[1];
zn= mvert->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;
Normalise(vn);
mvert++; vn+=3;
}
for (i=0; i<dlm->totface; i++) {
MFace *mf= &dlm->mface[i];
if (mf->v3) {
int j, vidx[4], nverts= mf->v4?4:3;
unsigned char *col1base= (unsigned char*) &dlob->col1[i*4];
unsigned char *col2base= (unsigned char*) (dlob->col2?&dlob->col2[i*4]:NULL);
unsigned char *mcolbase;
float nor[3];
if (dlm->tface) {
mcolbase = (unsigned char*) dlm->tface[i].col;
} else if (dlm->mcol) {
mcolbase = (unsigned char*) &dlm->mcol[i*4];
} else {
mcolbase = NULL;
}
ma= give_current_material(ob, mf->mat_nr+1);
if(ma==0) ma= &defmaterial;
vidx[0]= mf->v1;
vidx[1]= mf->v2;
vidx[2]= mf->v3;
vidx[3]= mf->v4;
// XXX, should all DLM's have normals?
if (dlm->nors) {
VECCOPY(nor, &dlm->nors[i*3]);
} else {
if (mf->v4)
CalcNormFloat4(dlm->mvert[mf->v1].co, dlm->mvert[mf->v2].co, dlm->mvert[mf->v3].co, dlm->mvert[mf->v4].co, nor);
else
CalcNormFloat(dlm->mvert[mf->v1].co, dlm->mvert[mf->v2].co, dlm->mvert[mf->v3].co, nor);
}
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];
Normalise(n1);
vn = n1;
for (j=0; j<nverts; j++) {
MVert *mv= &dlm->mvert[vidx[j]];
unsigned char *col1= &col1base[j*4];
unsigned char *col2= col2base?&col2base[j*4]:NULL;
unsigned char *mcol= mcolbase?&mcolbase[j*4]:NULL;
VECCOPY(vec, mv->co);
Mat4MulVecfl(mat, vec);
if(mf->flag & ME_SMOOTH) vn= vnors+3*vidx[j];
fastshade(vec, vn, orco?&orco[vidx[j]*3]:mv->co, ma, col1, col2, mcol);
}
}
}
MEM_freeN(vnors);
}
displistmesh_free(dlm);
if (need_orco && orco) {
MEM_freeN(me->orco);
me->orco= NULL;
}
if (dmNeedsFree) dm->release(dm);
}
else if ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT) {
/* now we need the normals */
cu= ob->data;
dl= cu->disp.first;
while(dl) {
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==0) 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];
Normalise(n1);
fp= dl->verts;
a= dl->nr;
while(a--) {
VECCOPY(vec, fp);
Mat4MulVecfl(mat, vec);
fastshade(vec, n1, fp, ma, (char *)col1, 0, 0);
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--) {
VECCOPY(vec, fp);
Mat4MulVecfl(mat, vec);
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];
Normalise(n1);
fastshade(vec, n1, fp, ma, (char *)col1, 0, 0);
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) {
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==0) ma= &defmaterial;
fp= dl->verts;
nor= dl->nors;
a= dl->nr;
while(a--) {
VECCOPY(vec, fp);
Mat4MulVecfl(mat, vec);
/* 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];
Normalise(n1);
fastshade(vec, n1, fp, ma, (char *)col1, 0, 0);
fp+= 3; col1++; nor+= 3;
}
}
}
dl= dl->next;
}
}
for(a=0; a<ob->totcol; a++) {
ma= give_current_material(ob, a+1);
if(ma) end_render_material(ma);
}
}
void reshadeall_displist(void)
{
Base *base;
Object *ob;
freefastshade();
base= G.scene->base.first;
while(base) {
if(base->lay & G.scene->lay) {
ob= base->object;
/* Metaballs have standard displist at the Object */
if(ob->type==OB_MBALL) shadeDispList(ob);
else freedisplist(&ob->disp);
}
base= base->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;
}
}
static void curve_to_displist(ListBase *nubase, ListBase *dispbase)
{
Nurb *nu;
DispList *dl;
BezTriple *bezt, *prevbezt;
BPoint *bp;
float *data, *v1, *v2;
int a, len;
nu= nubase->first;
while(nu) {
if(nu->hide==0) {
if((nu->type & 7)==CU_BEZIER) {
/* count */
len= 0;
a= nu->pntsu-1;
if(nu->flagu & 1) a++;
prevbezt= nu->bezt;
bezt= prevbezt+1;
while(a--) {
if(a==0 && (nu->flagu & 1)) bezt= nu->bezt;
if(prevbezt->h2==HD_VECT && bezt->h1==HD_VECT) len++;
else len+= nu->resolu;
if(a==0 && (nu->flagu & 1)==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 & 1) {
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 {
v1= prevbezt->vec[1];
v2= bezt->vec[0];
forward_diff_bezier(v1[0], v1[3], v2[0], v2[3], data, nu->resolu, 3);
forward_diff_bezier(v1[1], v1[4], v2[1], v2[4], data+1, nu->resolu, 3);
if((nu->type & 8)==0)
forward_diff_bezier(v1[2], v1[5], v2[2], v2[5], data+2, nu->resolu, 3);
data+= 3*nu->resolu;
}
if(a==0 && dl->type==DL_SEGM) {
VECCOPY(data, bezt->vec[1]);
}
prevbezt= bezt;
bezt++;
}
}
else if((nu->type & 7)==CU_NURBS) {
len= nu->pntsu*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;
data= dl->verts;
if(nu->flagu & 1) dl->type= DL_POLY;
else dl->type= DL_SEGM;
makeNurbcurve(nu, data, 3);
}
else if((nu->type & 7)==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;
data= dl->verts;
if(nu->flagu & 1) 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)
{
EditVert *eve, *v1, *vlast;
EditFace *efa;
DispList *dlnew=0, *dl;
float *f1;
int colnr=0, charidx=0, cont=1, tot, a, *index;
long totvert;
if(dispbase==0) return;
if(dispbase->first==0) return;
while(cont) {
cont= 0;
totvert=0;
dl= dispbase->first;
while(dl) {
if(dl->type==DL_POLY) {
if(charidx<dl->charidx) cont= 1;
else if(charidx==dl->charidx) {
colnr= dl->col;
charidx= dl->charidx;
/* make editverts and edges */
f1= dl->verts;
a= dl->nr;
eve= v1= 0;
while(a--) {
vlast= eve;
eve= BLI_addfillvert(f1);
totvert++;
if(vlast==0) v1= eve;
else {
BLI_addfilledge(vlast, eve);
}
f1+=3;
}
if(eve!=0 && v1!=0) {
BLI_addfilledge(eve, v1);
}
}
}
dl= dl->next;
}
/* to make edgefill work
G.obedit can be 0 on file load */
if (G.obedit) {
BLI_setScanFillObjectRef(G.obedit);
BLI_setScanFillColourRef(&G.obedit->actcol);
}
if(totvert && BLI_edgefill(0)!=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->vn= (EditVert *)totvert;
totvert++;
eve= eve->next;
}
/* index data */
efa= fillfacebase.first;
index= dlnew->index;
while(efa) {
index[0]= (long)efa->v1->vn;
index[1]= (long)efa->v2->vn;
index[2]= (long)efa->v3->vn;
index+= 3;
efa= efa->next;
}
}
BLI_addhead(to, dlnew);
}
BLI_end_edgefill();
charidx++;
}
/* 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= 0;
if(cu->flag & CU_3D) return;
if( (cu->flag & (CU_FRONT+CU_BACK))==0 ) return;
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;
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;
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);
filldisplist(&back, dispbase);
freedisplist(&front);
freedisplist(&back);
filldisplist(dispbase, dispbase);
}
void curve_to_filledpoly(Curve *cu, ListBase *nurb, ListBase *dispbase)
{
DispList *dl;
Nurb *nu;
dl= dispbase->first;
if(cu->flag & CU_3D) return;
nu= nurb->first;
while(nu) {
if(nu->flagu & CU_CYCLIC) break;
nu= nu->next;
}
if(nu==0) return;
if(dl->type==DL_SURF) bevels_to_filledpoly(cu, dispbase);
else {
if(cu->flag & CU_FRONT) filldisplist(dispbase, dispbase);
}
}
/* 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(Object *taperobj, int cur, int tot)
{
Curve *cu;
DispList *dl;
if(taperobj==NULL) return 1.0;
cu= taperobj->data;
dl= cu->disp.first;
if(dl==NULL) {
makeDispListCurveTypes(taperobj);
dl= cu->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; a<dl->nr; 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 makeDispListMesh(Object *ob)
{
MVert *deformedMVerts = NULL;
Mesh *me;
if(!ob || (ob->flag&OB_FROMDUPLI) || ob->type!=OB_MESH) return;
me= ob->data;
/* also serves as signal to remake texspace */
if (me->bb) {
MEM_freeN(me->bb);
me->bb = NULL;
}
freedisplist(&(ob->disp));
freedisplist(&me->disp);
if (me->derived) {
me->derived->release(me->derived);
me->derived= NULL;
}
if (ob->derivedDeform) {
ob->derivedDeform->release(ob->derivedDeform);
ob->derivedDeform= NULL;
}
if (ob!=G.obedit) {
mesh_modifier(ob, &deformedMVerts);
if (deformedMVerts) {
ob->derivedDeform = derivedmesh_from_mesh(ob, deformedMVerts);
}
}
if (mesh_uses_displist(me)) { /* subsurf */
if (ob==G.obedit) {
G.editMesh->derived= subsurf_make_derived_from_editmesh(G.editMesh, me->subdiv, me->subsurftype, G.editMesh->derived);
} else {
me->derived= subsurf_make_derived_from_mesh(ob, me->subdiv, 1);
}
}
{
BoundBox *bb=0;
float min[3], max[3];
INIT_MINMAX(min, max);
bb= mesh_get_bb(ob->data);
if (me->derived) {
me->derived->getMinMax(me->derived, min, max);
} else if (ob->derivedDeform) {
ob->derivedDeform->getMinMax(ob->derivedDeform, min, max);
}
if(bb) {
bb->vec[0][0]=bb->vec[1][0]=bb->vec[2][0]=bb->vec[3][0]= min[0];
bb->vec[4][0]=bb->vec[5][0]=bb->vec[6][0]=bb->vec[7][0]= max[0];
bb->vec[0][1]=bb->vec[1][1]=bb->vec[4][1]=bb->vec[5][1]= min[1];
bb->vec[2][1]=bb->vec[3][1]=bb->vec[6][1]=bb->vec[7][1]= max[1];
bb->vec[0][2]=bb->vec[3][2]=bb->vec[4][2]=bb->vec[7][2]= min[2];
bb->vec[1][2]=bb->vec[2][2]=bb->vec[5][2]=bb->vec[6][2]= max[2];
}
}
build_particle_system(ob);
}
void makeDispListMBall(Object *ob)
{
if(!ob || (ob->flag&OB_FROMDUPLI) || ob->type!=OB_MBALL) return;
freedisplist(&(ob->disp));
if(ob->type==OB_MBALL) {
if(ob==find_basis_mball(ob)) {
metaball_polygonize(ob);
tex_space_mball(ob);
object_deform(ob);
}
}
boundbox_displist(ob);
}
void makeDispListCurveTypes(Object *ob)
{
Nurb *nu;
Curve *cu;
BPoint *bp;
ListBase dlbev, *dispbase;
DispList *dl, *dlb;
BevList *bl;
BevPoint *bevp;
float *data, *fp1, widfac, vec[3];
int len, a, b, draw=0;
if(!ob || (ob->flag&OB_FROMDUPLI) || !ELEM3(ob->type, OB_SURF, OB_CURVE, OB_FONT)) return;
if(ob==NULL) return;
if(ob->flag & OB_FROMDUPLI) return;
freedisplist(&(ob->disp));
if(ob->type==OB_SURF) {
draw= ob->dt;
cu= ob->data;
dispbase= &(cu->disp);
freedisplist(dispbase);
if(ob==G.obedit) nu= editNurb.first;
else {
curve_modifier(ob, 's');
nu= cu->nurb.first;
}
while(nu) {
if(nu->hide==0) {
if(nu->pntsv==1) {
if(draw==0) len= nu->pntsu;
else len= nu->pntsu*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->rt= nu->flag;
data= dl->verts;
if(nu->flagu & 1) dl->type= DL_POLY;
else dl->type= DL_SEGM;
if(draw==0) {
bp= nu->bp;
while(len--) {
VECCOPY(data, bp->vec);
bp++;
data+= 3;
}
}
else makeNurbcurve(nu, data, 3);
}
else {
if(draw==0 && ob==G.obedit) ;
else {
if(draw==0) len= nu->pntsu*nu->pntsv;
else len= nu->resolu*nu->resolv;
dl= MEM_callocN(sizeof(DispList), "makeDispListsurf");
dl->verts= MEM_callocN(len*3*sizeof(float), "dlverts");
BLI_addtail(dispbase, dl);
if(draw==0) {
dl->parts= nu->pntsv;
dl->nr= nu->pntsu;
if(nu->flagu & 1) dl->flag|= DL_CYCL_U;
if(nu->flagv & 1) dl->flag|= DL_CYCL_V;
}
else {
dl->parts= nu->resolu; /* in reverse, because makeNurbfaces works that way */
dl->nr= nu->resolv;
if(nu->flagv & 1) dl->flag|= DL_CYCL_U; /* reverse too! */
if(nu->flagu & 1) dl->flag|= DL_CYCL_V;
}
dl->col= nu->mat_nr;
dl->rt= nu->flag;
data= dl->verts;
dl->type= DL_SURF;
if(draw==0) {
bp= nu->bp;
while(len--) {
VECCOPY(data, bp->vec);
bp++;
data+= 3;
}
}
else makeNurbfaces(nu, data);
}
}
}
nu= nu->next;
}
tex_space_curve(cu);
if(ob!=G.obedit) curve_modifier(ob, 'e');
if(ob!=G.obedit) object_deform(ob);
}
else if ELEM(ob->type, OB_CURVE, OB_FONT) {
int obedit= (G.obedit && G.obedit->data==ob->data);
draw= ob->dt;
cu= ob->data;
dispbase= &(cu->disp);
freedisplist(dispbase);
BLI_freelistN(&(cu->bev));
if(cu->path) free_path(cu->path);
cu->path= NULL;
if(ob->type==OB_FONT) text_to_curve(ob, 0);
if(!obedit) curve_modifier(ob, 's');
if(obedit) {
if(ob->type==OB_CURVE) curve_to_displist(&editNurb, dispbase);
else curve_to_displist(&cu->nurb, dispbase);
makeBevelList(ob); // always needed, so calc_curvepath() can work
}
else if(cu->ext1==0.0 && cu->ext2==0.0 && cu->bevobj==NULL && cu->width==1.0) {
curve_to_displist(&cu->nurb, dispbase);
makeBevelList(ob); // always needed, so calc_curvepath() can work
}
else {
makeBevelList(ob);
dlbev.first= dlbev.last= NULL;
if(cu->ext1!=0.0 || cu->ext2!=0.0 || cu->bevobj) {
if(ob->dt!=0) makebevelcurve(ob, &dlbev);
}
/* work with bevellist */
widfac= cu->width-1.0;
bl= cu->bev.first;
nu= cu->nurb.first;
while(bl) {
if(dlbev.first==0) {
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;
a= dl->nr;
bevp= (BevPoint *)(bl+1);
data= dl->verts;
while(a--) {
data[0]= bevp->x+widfac*bevp->sina;
data[1]= bevp->y+widfac*bevp->cosa;
data[2]= bevp->z;
bevp++;
data+=3;
}
}
else {
/* for each part of the bevel use a separate displblock */
dlb= dlbev.first;
while(dlb) {
dl= MEM_callocN(sizeof(DispList), "makeDispListbev1");
dl->verts= MEM_callocN(3*sizeof(float)*dlb->nr*bl->nr, "dlverts");
BLI_addtail(dispbase, dl);
/* dl->type= dlb->type; */
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->rt= nu->flag;
data= dl->verts;
bevp= (BevPoint *)(bl+1);
for(a=0; a<bl->nr; a++) { /* for each point of poly make a bevel piece */
float fac;
/* returns 1.0 if no taper, of course */
fac= calc_taper(cu->taperobj, a, bl->nr);
/* rotate bevel piece and write in data */
fp1= dlb->verts;
b= dlb->nr;
while(b--) {
if(cu->flag & CU_3D) {
vec[0]= fp1[1]+widfac;
vec[1]= fp1[2];
vec[2]= 0.0;
Mat3MulVecfl(bevp->mat, vec);
data[0]= bevp->x+ fac*vec[0];
data[1]= bevp->y+ fac*vec[1];
data[2]= bevp->z+ fac*vec[2];
}
else {
data[0]= bevp->x+ fac*(fp1[1]+widfac)*bevp->sina;
data[1]= bevp->y+ fac*(fp1[1]+widfac)*bevp->cosa;
data[2]= bevp->z+ fac*fp1[2];
}
data+=3;
fp1+=3;
}
bevp++;
}
dlb= dlb->next;
}
}
bl= bl->next;
nu= nu->next;
}
if(cu->ext1!=0.0 || cu->ext2!=0.0 || cu->bevobj) {
freedisplist(&dlbev);
}
}
if(cu->flag & CU_PATH) calc_curvepath(ob);
if(!obedit) {
curve_modifier(ob, 'e');
object_deform(ob);
}
tex_space_curve(cu);
}
boundbox_displist(ob);
}
/*******************************/
/***** OUTLINE *****/
/*******************************/
typedef struct Sample{
short x, y;
} Sample;
typedef struct Segment{
/* coordinates */
struct Segment * next, * prev;
float co[2];
} Segment;
static int dflt_in_out(struct ImBuf * ibuf, int x, int y)
{
unsigned char * rect;
if (ibuf == 0) return (0);
if (x < 0 || y < 0 || x >= ibuf->x || y >= ibuf->y || ibuf->rect == 0) return (-1);
rect = (unsigned char *) (ibuf->rect + (y * ibuf->x) + x);
if (rect[0] > 0x81) return (1);
return(0);
}
static Sample * outline(struct ImBuf * ibuf,
int (*in_or_out)(struct ImBuf *, int, int))
{
static int dirs[8][2] = {
{-1, 0}, {-1, 1}, {0, 1}, {1, 1},
{1, 0}, {1, -1}, {0, -1}, {-1, -1}
};
int dir, x, y, in, i;
int count, sampcount;
int startx = 0, starty = 0;
Sample * samp, * oldsamp;
/* input:
* 1 - image
* 2 - pointer to function that defines which pixel 'in' or 'out' is
*/
if (ibuf == 0) return (0);
if (ibuf->rect == 0) return (0);
if (in_or_out == 0) in_or_out = dflt_in_out;
in = in_or_out(ibuf, 0, 0);
/* search for first transition, and continue from there */
for (y = 0; y < ibuf->y; y++) {
for (x = 0; x < ibuf->x; x++) {
if (in_or_out(ibuf, x, y) != in) {
/* found first 'other' point !! */
if (x != startx) dir = 0;
else dir = 6;
startx = x; starty = y;
count = 1;
sampcount = 2000;
samp = MEM_mallocN(sampcount * sizeof(Sample), "wire_samples");
do{
samp[count].x = x; samp[count].y = y;
count++;
if (count >= sampcount) {
oldsamp = samp;
samp = MEM_mallocN(2 * sampcount * sizeof(Sample), "wire_samples");
memcpy(samp, oldsamp, sampcount * sizeof(Sample));
sampcount *= 2;
MEM_freeN(oldsamp);
}
i = 0;
while(in_or_out(ibuf, x + dirs[dir][0], y + dirs[dir][1]) == in) {
dir = (dir + 1) & 0x7;
if (i++ == 9) break;
}
if (i >= 8) {
/* this has to be a loose point */
break;
}
x += dirs[dir][0];
y += dirs[dir][1];
dir = (dir - 3) & 0x7;
} while(x != startx || y != starty);
if (i >= 8) {
/* patch for loose points */
MEM_freeN(samp);
} else {
count = count - 1;
samp[0].x = count >> 16;
samp[0].y = count;
return(samp);
}
}
}
}
/* printf("no transition \n"); */
return(0);
}
/*******************************/
/***** WIREFRAME *****/
/*******************************/
static float DistToLine2D(short *v1, short *v2, short *v3) /* using Hesse formula :NO LINE PIECE! */
{
float a[2],deler;
a[0] = v2[1]-v3[1];
a[1] = v3[0]-v2[0];
deler = sqrt(a[0]*a[0]+a[1]*a[1]);
if(deler == 0.0) return 0;
return fabs((v1[0]-v2[0])*a[0]+(v1[1]-v2[1])*a[1])/deler;
}
static float ComputeMaxShpError(Sample *samp, int first, int last, int *splitPoint)
/* samp: Array of digitized points */
/* first, last: Indices defining region */
/* splitpoint: Point of maximum error */
{
int i;
float maxDist; /* Maximum error */
float dist; /* Current error */
*splitPoint = (last - first + 1) / 2;
maxDist = 0.0;
for (i = first + 1; i < last; i++) {
dist = DistToLine2D((short *)(samp+i), (short *)(samp+first), (short *)(samp+last));
if (dist >= maxDist) {
maxDist = dist;
*splitPoint = i;
}
}
return (maxDist);
}
static void FitPoly(Sample *samp, int first, int last, float shperr, ListBase *seglist)
/* Samp: Array of digitized points */
/* first,last: Indices of first and last pts in region */
/* spherr: User-defined error squared */
{
Segment * seg; /* Control points segment*/
float maxError; /* Maximum fitting error */
int splitPoint; /* Point to split point set at */
int nPts; /* Number of points in subset */
nPts = last - first + 1;
/* Use heuristic if region only has two points in it */
seg = MEM_mallocN(sizeof(Segment), "wure_segment");
seg->co[0] = samp[first].x;
seg->co[1] = samp[first].y;
if (nPts == 2) {
BLI_addtail(seglist, seg);
return;
}
maxError = ComputeMaxShpError(samp, first, last, &splitPoint);
if (maxError < shperr) {
BLI_addtail(seglist, seg);
return;
}
/* Fitting failed -- split at max error point and fit recursively */
FitPoly(samp, first, splitPoint, shperr, seglist);
FitPoly(samp, splitPoint, last, shperr, seglist);
MEM_freeN(seg);
}
static void ibuf2wire(ListBase * wireframe, struct ImBuf * ibuf)
{
int count;
Sample * samp;
/* first make a list of samples */
samp = outline(ibuf, 0);
if (samp == 0) return;
count = (samp[0].x << 16) + samp[0].y;
if (count) FitPoly(samp, 1, count, 1.0, wireframe); /* was 3.0. Frank */
MEM_freeN(samp);
}
void imagestodisplist(void)
{
Base *base;
Object *ob;
Material *ma;
Tex *tex;
Mesh *me;
ListBase _wireframe, *wireframe;
DispList *dl;
Segment *seg;
float *data, xfac, yfac, xsi, ysi, vec[3], dum;
int tot;
_wireframe.first= 0;
_wireframe.last= 0;
wireframe = &_wireframe;
init_render_textures();
base= G.scene->base.first;
while(base) {
if(( (base->flag & SELECT) && (base->lay & G.scene->lay) ) ) {
if( base->object->type==OB_MESH) {
ob= base->object;
me= ob->data;
ma= give_current_material(ob, 1);
if(ma && ma->mtex[0] && ma->mtex[0]->tex) {
tex= ma->mtex[0]->tex;
/* this takes care of correct loading of new imbufs */
externtex(ma->mtex[0], vec, &dum, &dum, &dum, &dum, &dum);
if(tex->type==TEX_IMAGE && tex->ima && tex->ima->ibuf) {
ob->dtx |= OB_DRAWIMAGE;
ibuf2wire(wireframe, tex->ima->ibuf);
tot= 0;
seg = wireframe->first;
while (seg) {
tot++;
seg = seg->next;
}
if(tot) {
float size[3];
freedisplist(&(ob->disp));
dl= MEM_callocN(sizeof(DispList), "makeDispListimage");
dl->verts= MEM_callocN(3*sizeof(float)*tot, "dlverts");
BLI_addtail(&(ob->disp), dl);
dl->type= DL_POLY;
dl->parts= 1;
dl->nr= tot;
xsi= 0.5*(tex->ima->ibuf->x);
ysi= 0.5*(tex->ima->ibuf->y);
mesh_get_texspace(me, NULL, NULL, size);
xfac= size[0]/xsi;
yfac= size[1]/ysi;
data= dl->verts;
seg = wireframe->first;
while (seg) {
data[0]= xfac*(seg->co[0]-xsi);
data[1]= yfac*(seg->co[1]-ysi);
data+= 3;
seg = seg->next;
}
BLI_freelistN(wireframe);
}
}
}
}
}
base= base->next;
}
end_render_textures();
allqueue(REDRAWVIEW3D, 0);
}
static void boundbox_displist(Object *ob)
{
BoundBox *bb=0;
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;
if(cu->bb==0) cu->bb= MEM_callocN(sizeof(BoundBox), "boundbox");
bb= cu->bb;
dl= cu->disp.first;
while (dl) {
if(dl->type==DL_INDEX3 || dl->type==DL_INDEX3) tot= dl->nr;
else tot= dl->nr*dl->parts;
vert= dl->verts;
for(a=0; a<tot; a++, vert+=3) {
DO_MINMAX(vert, min, max);
}
dl= dl->next;
}
}
if(bb) {
bb->vec[0][0]=bb->vec[1][0]=bb->vec[2][0]=bb->vec[3][0]= min[0];
bb->vec[4][0]=bb->vec[5][0]=bb->vec[6][0]=bb->vec[7][0]= max[0];
bb->vec[0][1]=bb->vec[1][1]=bb->vec[4][1]=bb->vec[5][1]= min[1];
bb->vec[2][1]=bb->vec[3][1]=bb->vec[6][1]=bb->vec[7][1]= max[1];
bb->vec[0][2]=bb->vec[3][2]=bb->vec[4][2]=bb->vec[7][2]= min[2];
bb->vec[1][2]=bb->vec[2][2]=bb->vec[5][2]=bb->vec[6][2]= max[2];
}
}