/** * $Id:$ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** * * The contents of this file may be used under the terms of either the GNU * General Public License Version 2 or later (the "GPL", see * http://www.gnu.org/licenses/gpl.html ), or the Blender License 1.0 or * later (the "BL", see http://www.blender.org/BL/ ) which has to be * bought from the Blender Foundation to become active, in which case the * above mentioned GPL option does not apply. * * The Original Code is Copyright (C) 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 ***** */ /* sector.c MIXED MODEL * * aug 97 * * alle SGI-blender routines * */ #include "blender.h" #include "screen.h" #include #include #include "sector.h" /* ************ SECTORSPUL ******************* */ void unlink_sector(Sector *se) { /* loskoppelen: */ if(se->dynamesh) se->dynamesh->id.us--; if(se->texmesh) se->texmesh->id.us--; } /* niet sector zelf vrijgeven */ void free_sector(Sector *se) { unlink_sector(se); if(se->portals) freeN(se->portals); } Sector *add_sector() { Sector *se; Mesh *me; Portal *po; MVert *mvert; MFace *mface; TFace *tface; int a; se= alloc_libblock(&G.main->sector, ID_SE, "Sector"); se->type= SE_CUBE; se->flag= SE_SHOW_TEXMESH; se->size[0]= se->size[1]= se->size[2]= 1.0; se->r= se->g= se->b= 1.0; /* standaard plane */ se->dynamesh= me= add_mesh(); rename_id(me, "DynaMesh"); me->flag &= ~ME_TWOSIDED; me->mvert= mvert= callocN(4*sizeof(MVert), "mvert"); me->totvert= 4; me->totface= 1; for(a=0; a<4; a++, mvert++) { if(a==1 || a==2) mvert->co[0]= 1.0; else mvert->co[0]= -1.0; if(a==0 || a==1) mvert->co[1]= 1.0; else mvert->co[1]= -1.0; mvert->co[2]= -1.0; } me->mface= mface= callocN(sizeof(MFace), "mface"); mface->v1= 0; mface->v2= 3; mface->v3= 2; mface->v4= 1; mface->edcode= ME_V1V2+ME_V2V3+ME_V3V4+ME_V4V1; se->totport= 4; se->actport= 1; po= se->portals= callocN((se->totport)*sizeof(Portal), "portal"); po->type= PO_XPOS; (po+1)->type= PO_XNEG; (po+2)->type= PO_YPOS; (po+3)->type= PO_YNEG; /* TEXMESH: ook standaard plane */ se->texmesh= me= add_mesh(); rename_id(me, "TexMesh"); me->flag &= ~ME_TWOSIDED; me->totvert= 4; me->totface= 1; me->mface= dupallocN(se->dynamesh->mface); me->mvert= dupallocN(se->dynamesh->mvert); me->tface= tface= callocN(sizeof(TFace), "tface"); default_tface(tface); tface->flag |= SELECT|ACTIVE; return se; } Sector *copy_sector(Sector *se) { Sector *sen; int a; sen= copy_libblock(se); id_us_plus(sen->dynamesh); id_us_plus(sen->texmesh); sen->portals= dupallocN(se->portals); sen->ob= 0; return sen; } void make_local_sector(Sector *se) { Object *ob; Sector *sen; int local=0, lib=0; /* - zijn er alleen lib users: niet doen * - zijn er alleen locale users: flag zetten * - mixed: copy */ if(se->id.lib==0) return; if(se->id.us==1) { se->id.lib= 0; se->id.flag= LIB_LOCAL; new_id(0, se, 0); if(se->texmesh) make_local_mesh(se->texmesh); if(se->dynamesh) make_local_mesh(se->dynamesh); return; } ob= G.main->object.first; while(ob) { if(ob->data==se) { if(ob->id.lib) lib= 1; else local= 1; } ob= ob->id.next; } if(local && lib==0) { se->id.lib= 0; se->id.flag= LIB_LOCAL; new_id(0, se, 0); } else if(local && lib) { sen= copy_sector(se); sen->id.us= 0; ob= G.main->object.first; while(ob) { if(ob->data==se) { if(ob->id.lib==0) { ob->data= sen; sen->id.us++; se->id.us--; } } ob= ob->id.next; } } } /* **************** ARRAY EDIT ******************************** */ void add_array_element(void **base, short *act, short *tot, int size) { void *temp; char *cp; if(*act > *tot) *act = *tot; if(*act==0) *act= 1; temp= callocN( (*tot+1)*size, "add_array"); if(*base) { memcpy(temp, *base, (*tot)*size); cp= temp; memcpy(cp + (*tot)*size, cp + (*act-1)*size, size); freeN(*base); } *base= temp; (*tot)++; *act = *tot; } void delete_array_element(void **base, short *act, short *tot, int size) { Portal *po; int a; char *cp; if(*tot == 0) return; if(*act==0) *act= 1; if(*tot == 1) { *tot= *act= 0; freeN(*base); *base= 0; } else { cp= *base; cp+= (*act-1)*size; for(a= *act-1; a< *tot-1; a++, cp+=size) { memcpy(cp, cp+size, size); } (*tot)--; if( *tot == 0) *act= 0; else if(*act > *tot) *act = *tot; } } /* ***************** PORTALS ****************************** */ void add_portal(Sector *se) { Portal *po; /* aktieve portal: dupli */ add_array_element((void **)&se->portals, &se->actport, &se->totport, sizeof(Portal)); if(se->totport==1) { /* init */ po= se->portals; po->type= PO_XPOS; } } void delete_portal(Sector *se) { Portal *po; int a; /* aktieve portal: del */ delete_array_element((void **)&se->portals, &se->actport, &se->totport, sizeof(Portal)); } void testportals(Sector *se) { Portal *po; float cent[3], dx; int a, cox, coy; a= se->totport; po= se->portals; while(a--) { get_co_portal(se, po->type, po->ofs, cent); if(po->type==PO_XPOS || po->type==PO_XNEG) { cox= 1; coy= 2; } else if(po->type==PO_YPOS || po->type==PO_YNEG) { cox= 0; coy= 2; } else { cox= 0; coy= 1; } if( fabs(cent[cox]) > se->size[cox] ) { if(po->ofs[0]>0.0) po->ofs[0]= se->size[cox]; else po->ofs[0]= -se->size[cox]; } if( fabs(cent[coy]) > se->size[coy] ) { if(po->ofs[1]>0.0) po->ofs[1]= se->size[coy]; else po->ofs[1]= -se->size[coy]; } po++; } } /* ************ OCTREE **************** */ /* deze versie voor vlakken */ void calculate_ocvec(short *ocvec, float *v1, float *dvec, float *size) { int a; if(size[0]!=0.0) ocvec[0]= ffloor(16.0*(v1[0]-dvec[0])/size[0]); else ocvec[0]= 0; CLAMP(ocvec[0], 0, 15); if(size[1]!=0.0) ocvec[1]= ffloor(16.0*(v1[1]-dvec[1])/size[1]); else ocvec[1]= 0; CLAMP(ocvec[1], 0, 15); if(size[2]!=0.0) ocvec[2]= ffloor(16.0*(v1[2]-dvec[2])/size[2]); else ocvec[2]= 0; CLAMP(ocvec[2], 0, 15); } void init_mesh_octree(Mesh *me) { DFace *dface; int a, b; short min[3], max[3], ocvec[3]; /* ocinfo maken */ if(me->dface==0) return; me->oc= mallocN(sizeof(OcInfo), "oc"); if(me->bb==0) boundbox_mesh(me, me->oc->dvec, me->oc->size); VecSubf(me->oc->size, me->bb->vec[6], me->bb->vec[0]); VECCOPY(me->oc->dvec, me->bb->vec[0]); if(me->oc->size[0] < 0.01) me->oc->size[0]= 0.0; if(me->oc->size[1] < 0.01) me->oc->size[1]= 0.0; if(me->oc->size[2] < 0.01) me->oc->size[2]= 0.0; /* dface->ocx/y/z berekenen */ dface= me->dface; a= me->totface; while(a--) { if(dface->v3==0) { dface->ocx= 0; } else { min[0]=min[1]=min[2]= 16; max[0]=max[1]=max[2]= 0; calculate_ocvec(ocvec, dface->v1, me->oc->dvec, me->oc->size); DO_MINMAX(ocvec, min, max); calculate_ocvec(ocvec, dface->v2, me->oc->dvec, me->oc->size); DO_MINMAX(ocvec, min, max); calculate_ocvec(ocvec, dface->v3, me->oc->dvec, me->oc->size); DO_MINMAX(ocvec, min, max); if(dface->v4) { calculate_ocvec(ocvec, dface->v4, me->oc->dvec, me->oc->size); DO_MINMAX(ocvec, min, max); } dface->ocx= BROW(min[0], max[0]); dface->ocy= BROW(min[1], max[1]); dface->ocz= BROW(min[2], max[2]); } dface++; } } void switch_dir_dface(DFace *dface) { short edcode; /* niet de normaal flippen: is alleen optim voor intersect */ /* OP DEZE MANIER GAAT IE OP DE PSX MIS!!!! * if(dface->v4) { * SWAP(float *, dface->v2, dface->v3); * SWAP(float *, dface->v1, dface->v4); * } * else { * SWAP(float *, dface->v1, dface->v3); * } */ /* deze is GOED!! (ook voor vierhoeken ) */ SWAP(float *, dface->v1, dface->v3); edcode= 0; if(dface->edcode & DF_V1) edcode |= DF_V3; if(dface->edcode & DF_V2) edcode |= DF_V2; if(dface->edcode & DF_V3) edcode |= DF_V1; if(dface->edcode & DF_V4) edcode |= DF_V4; if(dface->v4) { if(dface->edcode & DF_V1V2) edcode |= DF_V2V3; if(dface->edcode & DF_V2V3) edcode |= DF_V1V2; if(dface->edcode & DF_V3V4) edcode |= DF_V4V1; if(dface->edcode & DF_V4V1) edcode |= DF_V3V4; } else { if(dface->edcode & DF_V1V2) edcode |= DF_V2V3; if(dface->edcode & DF_V2V3) edcode |= DF_V1V2; } dface->edcode= edcode; } void init_dyna_material(Material *ma) { DYNA_REF(ma)= 0.1; DYNA_FH_DIST(ma)= 0.0; DYNA_FH_INT(ma)= 0.0; DYNA_FH_FRICT(ma)= 0.0; DYNA_FH_XYFRICT(ma)= 0.0; ma->lay= 1; } void init_dynamesh(Object *ob, Mesh *me) { extern Material defmaterial; MFace *mface; MVert *v1, *v2, *v3, *v4; DFace *dface; Material *ma; float xn, yn, zn; int a, act=1; if(me->totface==0) return; /* sphereflags vorbereiden */ v1= me->mvert; for(a=0; atotvert; a++, v1++) { v1->flag &= ~ME_SPHERETEMP; if(v1->flag & ME_SPHERETEST) v1->flag |= ME_SPHERETEMP; } me->dface= callocN( me->totface*sizeof(DFace), "DFace"); mface= me->mface; dface= me->dface; ma= give_current_material(ob, 1); for(a=0; atotface; a++, mface++, dface++) { v1= (me->mvert+mface->v1); v2= (me->mvert+mface->v2); if(mface->v3) v3= (me->mvert+mface->v3); else v3= 0; if(mface->v4) v4= (me->mvert+mface->v4); else v4= 0; dface->v1= v1->co; dface->v2= v2->co; if(v3) dface->v3= v3->co; else dface->v3= 0; if(v4) dface->v4= v4->co; else dface->v4= 0; /* ook dfaces met v3==0. wordt soms uitgelezen */ if(mface->mat_nr != act-1) { act= mface->mat_nr+1; ma= give_current_material(ob, act); } if(ma) dface->ma= ma; else dface->ma= &defmaterial; if(dface->v3) { CalcNormFloat(dface->v1, dface->v2, dface->v3, dface->no); xn= fabs(dface->no[0]); yn= fabs(dface->no[1]); zn= fabs(dface->no[2]); /* edge en vertexcode voor cyl en sphere isect */ dface->edcode= mface->edcode & (~15); if(FALSE) { if(v1->flag & ME_SPHERETEMP) {dface->edcode |= DF_V1; v1->flag -= ME_SPHERETEMP;} if(v2->flag & ME_SPHERETEMP) {dface->edcode |= DF_V2; v2->flag -= ME_SPHERETEMP;} if(v3->flag & ME_SPHERETEMP) {dface->edcode |= DF_V3; v3->flag -= ME_SPHERETEMP;} if(v4) if(v4->flag & ME_SPHERETEMP) {dface->edcode |= DF_V4; v4->flag -= ME_SPHERETEMP;} } else { /* elk vlak moet sphere-code hebben: zie ook editmedh.c commentaar */ if(v1->flag & ME_SPHERETEMP) {dface->edcode |= DF_V1;} if(v2->flag & ME_SPHERETEMP) {dface->edcode |= DF_V2;} if(v3->flag & ME_SPHERETEMP) {dface->edcode |= DF_V3;} if(v4) if(v4->flag & ME_SPHERETEMP) {dface->edcode |= DF_V4;} } /* optimalisering bij intersect_dface() */ if(zn>=xn && zn>=yn) { dface->proj= 0; if( (dface->v2[0] - dface->v3[0])*(dface->v2[1] - dface->v1[1]) < (dface->v2[1] - dface->v3[1])*(dface->v2[0] - dface->v1[0]) ) switch_dir_dface(dface); } else if(yn>=xn && yn>=zn) { dface->proj= 1; if( (dface->v2[0] - dface->v3[0])*(dface->v2[2] - dface->v1[2]) < (dface->v2[2] - dface->v3[2])*(dface->v2[0] - dface->v1[0]) ) switch_dir_dface(dface); } else { dface->proj= 2; if( (dface->v2[1] - dface->v3[1])*(dface->v2[2] - dface->v1[2]) < (dface->v2[2] - dface->v3[2])*(dface->v2[1] - dface->v1[1]) ) switch_dir_dface(dface); } dface->dist= (dface->no[0]*dface->v1[0] + dface->no[1]*dface->v1[1] + dface->no[2]*dface->v1[2] ); } } init_mesh_octree(me); } void end_dynamesh(Mesh *me) { if(me==0) return; if(me->dface) freeN(me->dface); me->dface= 0; if(me->oc) freeN(me->oc); me->oc= 0; } /* *************** */ void sector_simulate() { Camera *cam=0; float params[5]= {8.5, 10.0, 0.0, 0.0, 0.0}; float loc[3], rot[3]; if(G.scene->camera==0 || G.scene->camera->type!=OB_CAMERA) { error("no (correct) camera"); return; } /* soms is de aktieve camera niet in een sector */ VECCOPY(loc, G.scene->camera->loc); VECCOPY(rot, G.scene->camera->rot); unqdevice(MOUSEX); unqdevice(MOUSEY); G.f |= G_SIMULATION; G.simulf= 0; cam= G.scene->camera->data; params[0]= cam->clipend*0.4; params[1]= cam->clipend; fogvertex(FG_VTX_LIN, params); fogvertex(FG_ON, 0); waitcursor(1); while(TRUE) { sector_go(); if(G.simulf & G_LOADFILE); if(G.simulf & G_RESTART); if(G.simulf & G_QUIT) { reset_slowparents(); /* editobject.c */ break; } G.simulf= 0; } waitcursor(0); qdevice(MOUSEX); qdevice(MOUSEY); fogvertex(FG_OFF, 0); G.f &= ~G_SIMULATION; allqueue(REDRAWVIEW3D, 0); allqueue(REDRAWBUTSALL, 0); /* soms is de aktieve camera niet in een sector */ VECCOPY(G.scene->camera->loc, loc); VECCOPY(G.scene->camera->rot, rot); }