2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
/* displist.c GRAPHICS
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* maart 95
|
|
|
|
*
|
|
|
|
* $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 *****
|
|
|
|
*/
|
2002-11-25 10:13:52 +00:00
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
#include <math.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
#include "BLI_winstuff.h"
|
|
|
|
#endif
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
#include "nla.h" /* For __NLA: Please do not remove yet */
|
|
|
|
|
|
|
|
#include "IMB_imbuf_types.h"
|
|
|
|
|
|
|
|
#include "DNA_texture_types.h"
|
|
|
|
#include "DNA_meta_types.h"
|
|
|
|
#include "DNA_curve_types.h"
|
|
|
|
#include "DNA_listBase.h"
|
|
|
|
#include "DNA_lamp_types.h"
|
|
|
|
#include "DNA_object_types.h"
|
|
|
|
#include "DNA_mesh_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_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"
|
|
|
|
|
|
|
|
/***/
|
|
|
|
|
|
|
|
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 FastLamp *fastlamplist= NULL;
|
|
|
|
static float fviewmat[4][4];
|
|
|
|
|
|
|
|
static void displistmesh_free(DispListMesh *dlm) {
|
|
|
|
// also check on mvert and mface, can be NULL after decimator (ton)
|
|
|
|
if( dlm->mvert) MEM_freeN(dlm->mvert);
|
|
|
|
if (dlm->mface) MEM_freeN(dlm->mface);
|
|
|
|
if (dlm->mcol) MEM_freeN(dlm->mcol);
|
|
|
|
if (dlm->tface) MEM_freeN(dlm->tface);
|
|
|
|
MEM_freeN(dlm);
|
|
|
|
}
|
|
|
|
|
|
|
|
static DispListMesh *displistmesh_copy(DispListMesh *odlm) {
|
|
|
|
DispListMesh *ndlm= MEM_dupallocN(odlm);
|
|
|
|
ndlm->mvert= MEM_dupallocN(odlm->mvert);
|
|
|
|
ndlm->mface= MEM_dupallocN(odlm->mface);
|
|
|
|
if (odlm->mcol) ndlm->mcol= MEM_dupallocN(odlm->mcol);
|
|
|
|
if (odlm->tface) ndlm->tface= MEM_dupallocN(odlm->tface);
|
|
|
|
|
|
|
|
return ndlm;
|
|
|
|
}
|
|
|
|
|
|
|
|
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->mesh) displistmesh_free(dl->mesh);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void free_displist_by_type(ListBase *lb, int type)
|
|
|
|
{
|
|
|
|
DispList *dl;
|
|
|
|
|
|
|
|
for (dl= lb->first; dl; ) {
|
|
|
|
DispList *next= dl->next;
|
|
|
|
|
|
|
|
if (dl->type==type) {
|
|
|
|
BLI_remlink(lb, dl);
|
|
|
|
free_disp_elem(dl);
|
|
|
|
}
|
|
|
|
|
|
|
|
dl= next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
if (dl->mesh)
|
|
|
|
dln->mesh= displistmesh_copy(dl->mesh);
|
|
|
|
|
|
|
|
dl= dl->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void initfastshade(void)
|
|
|
|
{
|
|
|
|
Base *base;
|
|
|
|
Object *ob;
|
|
|
|
Lamp *la;
|
|
|
|
FastLamp *fl;
|
|
|
|
float mat[4][4];
|
|
|
|
|
|
|
|
R.vlr= 0;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
/* uit roteerscene gejat */
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
FastLamp *fl;
|
|
|
|
float i, t, inp, soft, inpr, inpg, inpb, isr=0, isg=0, isb=0, lv[3], lampdist, ld;
|
|
|
|
float inpr1, inpg1, inpb1, isr1=0, isg1=0, isb1=0;
|
|
|
|
int a, back;
|
|
|
|
|
|
|
|
if(ma==0) return;
|
|
|
|
R.mat= ma;
|
|
|
|
R.matren= ma->ren;
|
|
|
|
ma= R.matren;
|
|
|
|
|
|
|
|
if(ma->mode & MA_VERTEXCOLP) {
|
|
|
|
if(vertcol) {
|
|
|
|
ma->r= vertcol[3]/255.0;
|
|
|
|
ma->g= vertcol[2]/255.0;
|
|
|
|
ma->b= vertcol[1]/255.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(ma->texco) {
|
|
|
|
VECCOPY(R.lo, orco);
|
|
|
|
VECCOPY(R.vn, nor);
|
|
|
|
|
|
|
|
if(ma->texco & TEXCO_GLOB) {
|
|
|
|
VECCOPY(R.gl, R.lo);
|
|
|
|
}
|
|
|
|
if(ma->texco & TEXCO_WINDOW) {
|
|
|
|
VECCOPY(R.winco, R.lo);
|
|
|
|
}
|
|
|
|
if(ma->texco & TEXCO_STICKY) {
|
|
|
|
VECCOPY(R.sticky, R.lo);
|
|
|
|
}
|
|
|
|
if(ma->texco & TEXCO_UV) {
|
|
|
|
VECCOPY(R.uv, R.lo);
|
|
|
|
}
|
|
|
|
if(ma->texco & TEXCO_OBJECT) {
|
|
|
|
VECCOPY(R.co, R.lo);
|
|
|
|
}
|
|
|
|
if(ma->texco & TEXCO_NORM) {
|
|
|
|
VECCOPY(R.orn, R.vn);
|
|
|
|
}
|
|
|
|
if(ma->texco & TEXCO_REFL) {
|
|
|
|
|
|
|
|
inp= 2.0*(R.vn[2]);
|
|
|
|
R.ref[0]= (inp*R.vn[0]);
|
|
|
|
R.ref[1]= (inp*R.vn[1]);
|
|
|
|
R.ref[2]= (-1.0+inp*R.vn[2]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(ma->mode & MA_VERTEXCOLP) {
|
|
|
|
R.mat->r= ma->r;
|
|
|
|
R.mat->g= ma->g;
|
|
|
|
R.mat->b= ma->b;
|
|
|
|
}
|
|
|
|
do_material_tex();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(ma->mode & MA_SHLESS) {
|
|
|
|
if(vertcol && (ma->mode & (MA_VERTEXCOL+MA_VERTEXCOLP))== MA_VERTEXCOL ) {
|
|
|
|
col1[3]= vertcol[3]*ma->r;
|
|
|
|
col1[2]= vertcol[2]*ma->g;
|
|
|
|
col1[1]= vertcol[1]*ma->b;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
col1[3]= (255.0*ma->r);
|
|
|
|
col1[2]= (255.0*ma->g);
|
|
|
|
col1[1]= (255.0*ma->b);
|
|
|
|
}
|
|
|
|
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 ) {
|
|
|
|
inpr= inpr1= ma->emit+vertcol[3]/255.0;
|
|
|
|
inpg= inpg1= ma->emit+vertcol[2]/255.0;
|
|
|
|
inpb= inpb1= ma->emit+vertcol[1]/255.0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
inpr= inpg= inpb= inpr1= inpg1= inpb1= ma->emit;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* col[0]= (255.0*ma->r); */
|
|
|
|
/* col[1]= (255.0*ma->g); */
|
|
|
|
/* col[2]= (255.0*ma->b); */
|
|
|
|
|
|
|
|
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) {
|
|
|
|
/* zachte gebied */
|
|
|
|
i= t/fl->spotbl;
|
|
|
|
t= i*i;
|
|
|
|
soft= (3.0*t-2.0*t*i);
|
|
|
|
inp*= soft;
|
|
|
|
}
|
|
|
|
|
|
|
|
lampdist*=inp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inp= nor[0]*lv[0]+ nor[1]*lv[1]+ nor[2]*lv[2];
|
|
|
|
|
|
|
|
back= 0;
|
|
|
|
if(inp<0.0) {
|
|
|
|
back= 1;
|
|
|
|
inp= -inp;
|
|
|
|
}
|
|
|
|
inp*= lampdist*ma->ref;
|
|
|
|
|
|
|
|
if(back==0) {
|
|
|
|
inpr+= inp*fl->r;
|
|
|
|
inpg+= inp*fl->g;
|
|
|
|
inpb+= inp*fl->b;
|
|
|
|
} else if(col2) {
|
|
|
|
inpr1+= inp*fl->r;
|
|
|
|
inpg1+= inp*fl->g;
|
|
|
|
inpb1+= inp*fl->b;
|
|
|
|
}
|
|
|
|
if(ma->spec) {
|
|
|
|
|
|
|
|
lv[2]+= 1.0;
|
|
|
|
Normalise(lv);
|
|
|
|
t= nor[0]*lv[0]+nor[1]*lv[1]+nor[2]*lv[2];
|
|
|
|
if(t>0) {
|
|
|
|
t= ma->spec*lampdist*RE_Spec(t, ma->har);
|
|
|
|
if(back==0) {
|
|
|
|
isr+= t*(fl->r * ma->specr);
|
|
|
|
isg+= t*(fl->g * ma->specg);
|
|
|
|
isb+= t*(fl->b * ma->specb);
|
|
|
|
}
|
|
|
|
else if(col2) {
|
|
|
|
isr1+= t*(fl->r * ma->specr);
|
|
|
|
isg1+= t*(fl->g * ma->specg);
|
|
|
|
isb1+= t*(fl->b * ma->specb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
a= 256*(inpr*ma->r + ma->ambr +isr);
|
|
|
|
if(a>255) col1[3]= 255;
|
|
|
|
else col1[3]= a;
|
|
|
|
a= 256*(inpg*ma->g + ma->ambg +isg);
|
|
|
|
if(a>255) col1[2]= 255;
|
|
|
|
else col1[2]= a;
|
|
|
|
a= 256*(inpb*ma->b + ma->ambb +isb);
|
|
|
|
if(a>255) col1[1]= 255;
|
|
|
|
else col1[1]= a;
|
|
|
|
|
|
|
|
if(col2) {
|
|
|
|
a= 256*(inpr1*ma->r + ma->ambr +isr1);
|
|
|
|
if(a>255) col2[3]= 255;
|
|
|
|
else col2[3]= a;
|
|
|
|
a= 256*(inpr1*ma->g + ma->ambg +isg1);
|
|
|
|
if(a>255) col2[2]= 255;
|
|
|
|
else col2[2]= a;
|
|
|
|
a= 256*(inpr1*ma->b + ma->ambb +isb1);
|
|
|
|
if(a>255) col2[1]= 255;
|
|
|
|
else col2[1]= a;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void addnormalsDispList(Object *ob, ListBase *lb)
|
|
|
|
{
|
|
|
|
DispList *dl = NULL;
|
|
|
|
Mesh *me;
|
|
|
|
MVert *ve1, *ve2, *ve3, *ve4;
|
|
|
|
MFace *mface;
|
|
|
|
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 (mesh_uses_displist(me)) {
|
|
|
|
DispList *dl= find_displist(&me->disp, DL_MESH);
|
|
|
|
|
|
|
|
if (dl && !dl->nors) {
|
|
|
|
DispListMesh *dlm= dl->mesh;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
dl->nors= MEM_mallocN(sizeof(*dl->nors)*3*dlm->totface, "meshnormals");
|
|
|
|
|
|
|
|
for (i=0; i<dlm->totface; i++) {
|
|
|
|
MFaceInt *mf= &dlm->mface[i];
|
|
|
|
float *no= &dl->nors[i*3];
|
|
|
|
|
|
|
|
if (mf->v3) {
|
|
|
|
if (mf->v4)
|
|
|
|
CalcNormFloat4(dlm->mvert[mf->v1].co, dlm->mvert[mf->v2].co, dlm->mvert[mf->v3].co, dlm->mvert[mf->v4].co, no);
|
|
|
|
else
|
|
|
|
CalcNormFloat(dlm->mvert[mf->v1].co, dlm->mvert[mf->v2].co, dlm->mvert[mf->v3].co, no);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(dl->nors==0) {
|
|
|
|
dl->nors= MEM_mallocN(sizeof(float)*3*me->totface, "meshnormals");
|
|
|
|
n1= dl->nors;
|
|
|
|
mface= me->mface;
|
|
|
|
a= me->totface;
|
|
|
|
while(a--) {
|
|
|
|
if(mface->v3) {
|
|
|
|
ve1= me->mvert+mface->v1;
|
|
|
|
ve2= me->mvert+mface->v2;
|
|
|
|
ve3= me->mvert+mface->v3;
|
|
|
|
ve4= me->mvert+mface->v4;
|
|
|
|
|
|
|
|
if(mface->v4) CalcNormFloat4(ve1->co, ve2->co, ve3->co, ve4->co, n1);
|
|
|
|
else CalcNormFloat(ve1->co, ve2->co, ve3->co, n1);
|
|
|
|
}
|
|
|
|
n1+= 3;
|
|
|
|
mface++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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 & 1, dl->flag & 2, 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)
|
|
|
|
{
|
|
|
|
MFace *mface;
|
|
|
|
MVert *mvert;
|
|
|
|
DispList *dl, *dlob, *dldeform;
|
|
|
|
Material *ma = NULL;
|
|
|
|
Mesh *me;
|
|
|
|
Curve *cu;
|
|
|
|
/* extern Material defmaterial; *//* initrender.c, already in bad lev calls*/
|
|
|
|
float *orco, imat[3][3], tmat[4][4], mat[4][4], vec[3], xn, yn, zn;
|
|
|
|
float *fp, *nor, n1[3];
|
|
|
|
unsigned int *col1, *col2, *vertcol;
|
|
|
|
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);
|
|
|
|
|
|
|
|
/* we halen de dl_verts eruit, deform info */
|
|
|
|
dldeform= find_displist(&ob->disp, DL_VERTS);
|
|
|
|
if(dldeform) BLI_remlink(&ob->disp, dldeform);
|
|
|
|
|
|
|
|
/* Metaballs hebben de standaard displist aan het Object zitten */
|
|
|
|
if(ob->type!=OB_MBALL) freedisplist(&ob->disp);
|
|
|
|
|
|
|
|
if((R.flag & R_RENDERING)==0) {
|
|
|
|
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->ren->texco & TEXCO_ORCO) need_orco= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(ob->type==OB_MESH) {
|
|
|
|
|
|
|
|
me= ob->data;
|
|
|
|
|
|
|
|
if (mesh_uses_displist(me)) {
|
|
|
|
if (need_orco) {
|
|
|
|
make_orco_displist_mesh(ob, me->subdiv);
|
|
|
|
orco= me->orco;
|
|
|
|
}
|
|
|
|
|
|
|
|
dl= me->disp.first;
|
|
|
|
while(dl) {
|
|
|
|
if(dl->type==DL_MESH) {
|
|
|
|
DispListMesh *dlm= dl->mesh;
|
|
|
|
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");
|
|
|
|
|
|
|
|
for (i=0; i<dlm->totface; i++) {
|
|
|
|
MFaceInt *mf= &dlm->mface[i];
|
|
|
|
|
|
|
|
if (mf->v3) {
|
|
|
|
int j, vidx[4], nverts= mf->v4?4:3;
|
|
|
|
unsigned int *col1base= &dlob->col1[i*4];
|
|
|
|
unsigned int *col2base= dlob->col2?&dlob->col2[i*4]:NULL;
|
|
|
|
MCol *mcolbase= dlm->mcol?&dlm->mcol[i*4]:NULL;
|
|
|
|
float nor[3];
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
for (j=0; j<nverts; j++) {
|
|
|
|
MVert *mv= &dlm->mvert[vidx[j]];
|
|
|
|
unsigned int *col1= &col1base[j];
|
|
|
|
unsigned int *col2= col2base?&col2base[j]:NULL;
|
|
|
|
MCol *mcol= mcolbase?&mcolbase[j]:NULL;
|
|
|
|
|
|
|
|
VECCOPY(vec, mv->co);
|
|
|
|
Mat4MulVecfl(mat, vec);
|
|
|
|
|
|
|
|
if (need_orco && orco)
|
|
|
|
fastshade(vec, n1, &orco[vidx[j]*3], ma, (char *)col1, (char*)col2, (char*) mcol);
|
|
|
|
else
|
|
|
|
fastshade(vec, n1, mv->co, ma, (char *)col1, (char*)col2, (char*) mcol);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dl= dl->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (need_orco && orco) {
|
|
|
|
MEM_freeN(me->orco);
|
|
|
|
me->orco= NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(me->totvert>0) {
|
|
|
|
|
|
|
|
if(me->orco==0 && need_orco) {
|
|
|
|
make_orco_mesh(me);
|
|
|
|
}
|
|
|
|
orco= me->orco;
|
|
|
|
/* ms= me->msticky; */
|
|
|
|
|
|
|
|
dl= me->disp.first;
|
|
|
|
if(dl==0 || dl->nors==0) addnormalsDispList(ob, &me->disp);
|
|
|
|
dl= me->disp.first;
|
|
|
|
if(dl==0 || dl->nors==0) return;
|
|
|
|
nor= dl->nors;
|
|
|
|
|
|
|
|
dl= MEM_callocN(sizeof(DispList), "displistshade");
|
|
|
|
BLI_addtail(&ob->disp, dl);
|
|
|
|
dl->type= DL_VERTCOL;
|
|
|
|
col1= dl->col1= MEM_mallocN(4*sizeof(int)*me->totface, "col1");
|
|
|
|
col2= 0;
|
|
|
|
if(me->tface) tface_to_mcol(me);
|
|
|
|
vertcol= (unsigned int *)me->mcol;
|
|
|
|
|
|
|
|
if( me->flag & ME_TWOSIDED) {
|
|
|
|
col2= dl->col2= MEM_mallocN(4*sizeof(int)*me->totface, "col2");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* even geen puno's */
|
|
|
|
mvert= me->mvert;
|
|
|
|
a= me->totvert;
|
|
|
|
while(FALSE || a--) {
|
|
|
|
|
|
|
|
VECCOPY(vec, mvert->co);
|
|
|
|
Mat4MulVecfl(mat, vec);
|
|
|
|
|
|
|
|
xn= mvert->no[0];
|
|
|
|
yn= mvert->no[1];
|
|
|
|
zn= mvert->no[2];
|
|
|
|
|
|
|
|
/* transpose ! */
|
|
|
|
n1[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn;
|
|
|
|
n1[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn;
|
|
|
|
n1[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn;
|
|
|
|
Normalise(n1);
|
|
|
|
|
|
|
|
mvert++;
|
|
|
|
}
|
|
|
|
|
|
|
|
mface= me->mface;
|
|
|
|
a= me->totface;
|
|
|
|
while(a--) {
|
|
|
|
|
|
|
|
if(mface->v3) {
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
|
|
|
if(lastmat!=mface->mat_nr) {
|
|
|
|
ma= give_current_material(ob, mface->mat_nr+1);
|
|
|
|
if(ma==0) ma= &defmaterial;
|
|
|
|
lastmat= mface->mat_nr;
|
|
|
|
}
|
|
|
|
|
|
|
|
mvert= me->mvert+mface->v1;
|
|
|
|
VECCOPY(vec, mvert->co);
|
|
|
|
Mat4MulVecfl(mat, vec);
|
|
|
|
|
|
|
|
if(orco) fastshade(vec, n1, orco+3*mface->v1, ma, (char *)col1, (char *)col2, (char *)vertcol);
|
|
|
|
else fastshade(vec, n1, mvert->co, ma, (char *)col1, (char *)col2, (char *)vertcol);
|
|
|
|
col1++;
|
|
|
|
if(vertcol) vertcol++;
|
|
|
|
if(col2) col2++;
|
|
|
|
|
|
|
|
mvert= me->mvert+mface->v2;
|
|
|
|
VECCOPY(vec, mvert->co);
|
|
|
|
Mat4MulVecfl(mat, vec);
|
|
|
|
|
|
|
|
if(orco) fastshade(vec, n1, orco+3*mface->v2, ma, (char *)col1, (char *)col2, (char *)vertcol);
|
|
|
|
else fastshade(vec, n1, mvert->co, ma, (char *)col1, (char *)col2, (char *)vertcol);
|
|
|
|
col1++;
|
|
|
|
if(vertcol) vertcol++;
|
|
|
|
if(col2) col2++;
|
|
|
|
|
|
|
|
mvert= me->mvert+mface->v3;
|
|
|
|
VECCOPY(vec, mvert->co);
|
|
|
|
Mat4MulVecfl(mat, vec);
|
|
|
|
|
|
|
|
if(orco) fastshade(vec, n1, orco+3*mface->v3, ma, (char *)col1, (char *)col2, (char *)vertcol);
|
|
|
|
else fastshade(vec, n1, mvert->co, ma, (char *)col1, (char *)col2, (char *)vertcol);
|
|
|
|
col1++;
|
|
|
|
if(vertcol) vertcol++;
|
|
|
|
if(col2) col2++;
|
|
|
|
|
|
|
|
if(mface->v4) {
|
|
|
|
mvert= me->mvert+mface->v4;
|
|
|
|
VECCOPY(vec, mvert->co);
|
|
|
|
Mat4MulVecfl(mat, vec);
|
|
|
|
|
|
|
|
if(orco) fastshade(vec, n1, orco+3*mface->v4, ma, (char *)col1, (char *)col2, (char *)vertcol);
|
|
|
|
else fastshade(vec, n1, mvert->co, ma, (char *)col1, (char *)col2, (char *)vertcol);
|
|
|
|
}
|
|
|
|
col1++;
|
|
|
|
if(vertcol) vertcol++;
|
|
|
|
if(col2) col2++;
|
|
|
|
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
col1+=4;
|
|
|
|
if(vertcol) vertcol+=4;
|
|
|
|
if(col2) col2+=4;
|
|
|
|
}
|
|
|
|
|
|
|
|
nor+= 3;
|
|
|
|
mface++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(me->orco) {
|
|
|
|
MEM_freeN(me->orco);
|
|
|
|
me->orco= 0;
|
|
|
|
}
|
|
|
|
if(me->tface) {
|
|
|
|
MEM_freeN(me->mcol);
|
|
|
|
me->mcol= 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT) {
|
|
|
|
|
|
|
|
/* nu hebben we wel de normalen nodig */
|
|
|
|
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) {
|
|
|
|
/* er is maar 1 normaal */
|
|
|
|
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) {
|
|
|
|
/* normalen zijn er al */
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if((R.flag & R_RENDERING)==0) {
|
|
|
|
for(a=0; a<ob->totcol; a++) {
|
|
|
|
ma= give_current_material(ob, a+1);
|
|
|
|
if(ma) end_render_material(ma);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* deze was er tijdelijk uitgehaald */
|
|
|
|
if(dldeform) BLI_addtail(&ob->disp, dldeform);
|
|
|
|
}
|
|
|
|
|
|
|
|
void reshadeall_displist(void)
|
|
|
|
{
|
|
|
|
DispList *dldeform;
|
|
|
|
Base *base;
|
|
|
|
Object *ob;
|
|
|
|
|
|
|
|
freefastshade();
|
|
|
|
|
|
|
|
base= G.scene->base.first;
|
|
|
|
while(base) {
|
|
|
|
if(base->lay & G.scene->lay) {
|
|
|
|
|
|
|
|
ob= base->object;
|
|
|
|
|
|
|
|
/* we halen de dl_verts eruit, deform info */
|
|
|
|
dldeform= find_displist(&ob->disp, DL_VERTS);
|
|
|
|
if(dldeform) BLI_remlink(&ob->disp, dldeform);
|
|
|
|
|
|
|
|
/* Metaballs hebben de standaard displist aan het Object zitten */
|
|
|
|
if(ob->type==OB_MBALL) shadeDispList(ob);
|
|
|
|
else freedisplist(&ob->disp);
|
|
|
|
|
|
|
|
if(dldeform) BLI_addtail(&ob->disp, dldeform);
|
|
|
|
}
|
|
|
|
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) {
|
|
|
|
|
|
|
|
/* tellen */
|
|
|
|
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 i.v.m. maakbez */
|
|
|
|
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;
|
|
|
|
|
|
|
|
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];
|
|
|
|
maakbez(v1[0], v1[3], v2[0], v2[3], data, nu->resolu);
|
|
|
|
maakbez(v1[1], v1[4], v2[1], v2[4], data+1, nu->resolu);
|
|
|
|
if((nu->type & 8)==0)
|
|
|
|
maakbez(v1[2], v1[5], v2[2], v2[5], data+2, nu->resolu);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void filldisplist(ListBase *dispbase, ListBase *to)
|
|
|
|
{
|
|
|
|
EditVert *eve, *v1, *vlast;
|
|
|
|
EditVlak *evl;
|
|
|
|
DispList *dlnew=0, *dl;
|
|
|
|
float *f1;
|
|
|
|
int colnr=0, cont=1, tot, a, *index;
|
|
|
|
long totvert;
|
|
|
|
|
|
|
|
if(dispbase==0) return;
|
|
|
|
if(dispbase->first==0) return;
|
|
|
|
|
|
|
|
/* tijd= clock(); */
|
|
|
|
/* bit-wise and comes after == .... so this doesn't work... */
|
|
|
|
/* if(G.f & G_PLAYANIM == 0) waitcursor(1); */
|
|
|
|
if( !(G.f & G_PLAYANIM) ) waitcursor(1);
|
|
|
|
|
|
|
|
while(cont) {
|
|
|
|
cont= 0;
|
|
|
|
totvert=0;
|
|
|
|
|
|
|
|
dl= dispbase->first;
|
|
|
|
while(dl) {
|
|
|
|
|
|
|
|
if(dl->type==DL_POLY) {
|
|
|
|
if(colnr<dl->col) cont= 1;
|
|
|
|
else if(colnr==dl->col) {
|
|
|
|
|
|
|
|
colnr= dl->col;
|
|
|
|
|
|
|
|
/* editverts en edges maken */
|
|
|
|
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) {
|
|
|
|
|
|
|
|
/* vlakken tellen */
|
|
|
|
tot= 0;
|
|
|
|
evl= fillvlakbase.first;
|
|
|
|
while(evl) {
|
|
|
|
tot++;
|
|
|
|
evl= evl->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");
|
|
|
|
|
|
|
|
/* vertdata */
|
|
|
|
f1= dlnew->verts;
|
|
|
|
totvert= 0;
|
|
|
|
eve= fillvertbase.first;
|
|
|
|
while(eve) {
|
|
|
|
VECCOPY(f1, eve->co);
|
|
|
|
f1+= 3;
|
|
|
|
|
|
|
|
/* indexnummer */
|
|
|
|
eve->vn= (EditVert *)totvert;
|
|
|
|
totvert++;
|
|
|
|
|
|
|
|
eve= eve->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* indexdata */
|
|
|
|
evl= fillvlakbase.first;
|
|
|
|
index= dlnew->index;
|
|
|
|
while(evl) {
|
|
|
|
index[0]= (long)evl->v1->vn;
|
|
|
|
index[1]= (long)evl->v2->vn;
|
|
|
|
index[2]= (long)evl->v3->vn;
|
|
|
|
|
|
|
|
index+= 3;
|
|
|
|
evl= evl->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_addhead(to, dlnew);
|
|
|
|
|
|
|
|
}
|
|
|
|
BLI_end_edgefill();
|
|
|
|
|
|
|
|
colnr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* poly's niet vrijgeven. nodig voor wireframe display */
|
|
|
|
|
|
|
|
/* same as above ... */
|
|
|
|
/* if(G.f & G_PLAYANIM == 0) waitcursor(0); */
|
|
|
|
if( !(G.f & G_PLAYANIM) ) waitcursor(0);
|
|
|
|
/* printf("time: %d\n",(clock()-tijd)/1000); */
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
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==2) {
|
|
|
|
if(cu->flag & CU_BACK) {
|
|
|
|
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) {
|
|
|
|
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 *dispbase)
|
|
|
|
{
|
|
|
|
DispList *dl;
|
|
|
|
Nurb *nu;
|
|
|
|
|
|
|
|
dl= dispbase->first;
|
|
|
|
|
|
|
|
if(cu->flag & CU_3D) return;
|
|
|
|
|
|
|
|
nu= cu->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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int dl_onlyzero= 0;
|
|
|
|
|
|
|
|
void set_displist_onlyzero(int val)
|
|
|
|
{
|
|
|
|
dl_onlyzero= val;
|
|
|
|
}
|
|
|
|
|
|
|
|
void makeDispList(Object *ob)
|
|
|
|
{
|
|
|
|
Mesh *me;
|
|
|
|
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==0) return;
|
|
|
|
if(ob->flag & OB_FROMDUPLI) return;
|
|
|
|
freedisplist(&(ob->disp));
|
|
|
|
|
|
|
|
if(ob->type==OB_MESH) {
|
|
|
|
me= ob->data;
|
|
|
|
|
|
|
|
freedisplist(&(me->disp));
|
|
|
|
|
|
|
|
tex_space_mesh(ob->data);
|
|
|
|
|
|
|
|
object_deform(ob);
|
|
|
|
|
|
|
|
if(ob->effect.first) object_wave(ob);
|
|
|
|
|
|
|
|
if ((me->flag & ME_SUBSURF) && me->subdiv>0) {
|
|
|
|
if (ob==G.obedit)
|
|
|
|
subsurf_make_editmesh(ob);
|
|
|
|
else
|
|
|
|
subsurf_make_mesh(ob, me->subdiv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(ob->type==OB_MBALL) {
|
|
|
|
ob= find_basis_mball(ob);
|
|
|
|
|
|
|
|
metaball_polygonize(ob);
|
|
|
|
tex_space_mball(ob);
|
|
|
|
}
|
|
|
|
else if(ob->type==OB_SURF) {
|
|
|
|
|
|
|
|
draw= ob->dt;
|
|
|
|
cu= ob->data;
|
|
|
|
dispbase= &(cu->disp);
|
|
|
|
if(dl_onlyzero && dispbase->first) return;
|
|
|
|
freedisplist(dispbase);
|
|
|
|
|
|
|
|
if(ob==G.obedit) nu= editNurb.first;
|
|
|
|
else 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;
|
|
|
|
|
|
|
|
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|= 1;
|
|
|
|
if(nu->flagv & 1) dl->flag|= 2;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
dl->parts= nu->resolu; /* andersom want makeNurbfaces gaat zo */
|
|
|
|
dl->nr= nu->resolv;
|
|
|
|
if(nu->flagv & 1) dl->flag|= 1; /* ook andersom ! */
|
|
|
|
if(nu->flagu & 1) dl->flag|= 2;
|
|
|
|
}
|
|
|
|
dl->col= nu->mat_nr;
|
|
|
|
|
|
|
|
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) object_deform(ob);
|
|
|
|
}
|
|
|
|
else if ELEM(ob->type, OB_CURVE, OB_FONT) {
|
|
|
|
|
|
|
|
draw= ob->dt;
|
|
|
|
cu= ob->data;
|
|
|
|
dispbase= &(cu->disp);
|
|
|
|
if(dl_onlyzero && dispbase->first) return;
|
|
|
|
freedisplist(dispbase);
|
|
|
|
|
|
|
|
if(cu->path) free_path(cu->path);
|
|
|
|
cu->path= 0;
|
|
|
|
|
|
|
|
BLI_freelistN(&(cu->bev));
|
|
|
|
|
|
|
|
if(ob==G.obedit) {
|
|
|
|
if(ob->type==OB_CURVE) curve_to_displist(&editNurb, dispbase);
|
|
|
|
else curve_to_displist(&cu->nurb, dispbase);
|
|
|
|
if(cu->flag & CU_PATH) makeBevelList(ob);
|
|
|
|
}
|
|
|
|
else if(cu->ext1==0.0 && cu->ext2==0.0 && cu->bevobj==0 && cu->width==1.0) {
|
|
|
|
curve_to_displist(&cu->nurb, dispbase);
|
|
|
|
if(cu->flag & CU_PATH) makeBevelList(ob);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
makeBevelList(ob);
|
|
|
|
|
|
|
|
dlbev.first= dlbev.last= 0;
|
|
|
|
if(cu->ext1!=0.0 || cu->ext2!=0.0 || cu->bevobj) {
|
|
|
|
if(ob->dt!=0) makebevelcurve(ob, &dlbev);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* met bevellist werken */
|
|
|
|
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;
|
|
|
|
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 {
|
|
|
|
/* voor iedere stuk van de bevel een aparte dispblok maken */
|
|
|
|
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= 0;
|
|
|
|
if(dlb->type==DL_POLY) dl->flag++;
|
|
|
|
if(bl->poly>=0) dl->flag+=2;
|
|
|
|
|
|
|
|
dl->parts= bl->nr;
|
|
|
|
dl->nr= dlb->nr;
|
|
|
|
dl->col= nu->mat_nr;
|
|
|
|
|
|
|
|
data= dl->verts;
|
|
|
|
bevp= (BevPoint *)(bl+1);
|
|
|
|
a= bl->nr;
|
|
|
|
while(a--) { /* voor ieder punt van poly een bevelstuk maken */
|
|
|
|
|
|
|
|
/* roteer bevelstuk en schrijf 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+ vec[0];
|
|
|
|
data[1]= bevp->y+ vec[1];
|
|
|
|
data[2]= bevp->z+ vec[2];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
data[0]= bevp->x+ (fp1[1]+widfac)*bevp->sina;
|
|
|
|
data[1]= bevp->y+ (fp1[1]+widfac)*bevp->cosa;
|
|
|
|
data[2]= bevp->z+ 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(ob!=G.obedit) object_deform(ob);
|
|
|
|
|
|
|
|
tex_space_curve(cu);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*******************************/
|
|
|
|
/***** OUTLINE *****/
|
|
|
|
/*******************************/
|
|
|
|
|
|
|
|
typedef struct Sample{
|
|
|
|
short x, y;
|
|
|
|
} Sample;
|
|
|
|
|
|
|
|
typedef struct Segment{
|
|
|
|
/* coordinaten */
|
|
|
|
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;
|
|
|
|
|
|
|
|
/* wat erin gaat:
|
|
|
|
* 1 - plaatje waarvan outline berekent moet worden,
|
|
|
|
* 2 - pointer naar functie die bepaalt welke pixel in of uit 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);
|
|
|
|
|
|
|
|
/* zoek naar eerste overgang en ga van daar uit 'zoeken' */
|
|
|
|
for (y = 0; y < ibuf->y; y++) {
|
|
|
|
for (x = 0; x < ibuf->x; x++) {
|
|
|
|
if (in_or_out(ibuf, x, y) != in) {
|
|
|
|
/* eerste 'andere' punt gevonden !! */
|
|
|
|
|
|
|
|
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) {
|
|
|
|
/* dit moet een losse punt geweest zijn */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
x += dirs[dir][0];
|
|
|
|
y += dirs[dir][1];
|
|
|
|
dir = (dir - 3) & 0x7;
|
|
|
|
} while(x != startx || y != starty);
|
|
|
|
|
|
|
|
if (i >= 8) {
|
|
|
|
/* losse punten patch */
|
|
|
|
MEM_freeN(samp);
|
|
|
|
} else {
|
|
|
|
count = count - 1;
|
|
|
|
samp[0].x = count >> 16;
|
|
|
|
samp[0].y = count;
|
|
|
|
return(samp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* printf("geen overgang \n"); */
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*******************************/
|
|
|
|
/***** WIREFRAME *****/
|
|
|
|
/*******************************/
|
|
|
|
|
|
|
|
|
|
|
|
static float DistToLine2D(short *v1, short *v2, short *v3) /* met formule van Hesse :GEEN LIJNSTUK! */
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
|
|
|
/* eerst een lijst met samples maken */
|
|
|
|
|
|
|
|
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];
|
|
|
|
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;
|
|
|
|
|
|
|
|
/* dit zorgt voor correct laden van nieuwe imbufs */
|
|
|
|
externtex(ma->mtex[0], vec);
|
|
|
|
|
|
|
|
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) {
|
|
|
|
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);
|
|
|
|
xfac= me->size[0]/xsi;
|
|
|
|
yfac= me->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);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* on frame change */
|
|
|
|
|
|
|
|
void test_all_displists(void)
|
|
|
|
{
|
|
|
|
Base *base;
|
|
|
|
Object *ob;
|
|
|
|
unsigned int lay;
|
|
|
|
|
|
|
|
/* background */
|
|
|
|
lay= G.scene->lay;
|
|
|
|
|
|
|
|
base= G.scene->base.first;
|
|
|
|
while(base) {
|
|
|
|
if(base->lay & lay) {
|
|
|
|
ob= base->object;
|
|
|
|
|
|
|
|
|
|
|
|
if(ob->type==OB_MBALL && ob->ipo) {
|
|
|
|
// find metaball object holding the displist
|
|
|
|
// WARNING: if more metaballs have IPO's the displist
|
|
|
|
// is recalculated to often...
|
|
|
|
|
|
|
|
if(ob->disp.first == NULL) {
|
|
|
|
ob= find_basis_mball(ob);
|
|
|
|
}
|
|
|
|
|
|
|
|
makeDispList(ob);
|
|
|
|
}
|
|
|
|
else if(ob->parent) {
|
|
|
|
|
|
|
|
if (ob->parent->type == OB_LATTICE)
|
|
|
|
makeDispList(ob);
|
|
|
|
else if ((ob->parent->type == OB_IKA) && (ob->partype == PARSKEL))
|
|
|
|
makeDispList(ob);
|
|
|
|
#ifdef __NLA
|
|
|
|
else if ((ob->parent->type==OB_ARMATURE) && (ob->partype == PARSKEL))
|
|
|
|
makeDispList(ob);
|
|
|
|
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
if ELEM(ob->type, OB_CURVE, OB_SURF) {
|
|
|
|
if(ob!=G.obedit) {
|
|
|
|
if( ((Curve *)(ob->data))->key ) makeDispList(ob);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(ob->type==OB_FONT) {
|
|
|
|
Curve *cu= ob->data;
|
|
|
|
if(cu->textoncurve) {
|
|
|
|
if( ((Curve *)cu->textoncurve->data)->key ) {
|
|
|
|
text_to_curve(ob, 0);
|
|
|
|
makeDispList(ob);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(ob->type==OB_MESH) {
|
|
|
|
if(ob->effect.first) object_wave(ob);
|
|
|
|
if(ob!=G.obedit) {
|
|
|
|
if( ((Mesh *)(ob->data))->key ) makeDispList(ob);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
if(base->next==0 && G.scene->set && base==G.scene->base.last) base= G.scene->set->base.first;
|
|
|
|
else base= base->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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(ob->type==OB_MESH) {
|
|
|
|
Mesh *me= ob->data;
|
|
|
|
|
|
|
|
dl= find_displist(&ob->disp, DL_VERTS);
|
|
|
|
if(!dl) return;
|
|
|
|
|
|
|
|
if(me->bb==0) me->bb= MEM_callocN(sizeof(BoundBox), "boundbox");
|
|
|
|
bb= me->bb;
|
|
|
|
|
|
|
|
vert= dl->verts;
|
|
|
|
for(a=0; a<dl->nr; a++, vert+=3) {
|
|
|
|
DO_MINMAX(vert, min, max);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else 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];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|