/** * $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 * * maart 96 * * */ #include "blender.h" #include "screen.h" #include #include #include "sector.h" #include "psx.h" #include "blendpsx.h" /* ******************** NOTES ************************** - de interne klok loopt op 50 Hz. - variable klok: erg lelijk en instabiel: botsingen/krachten/ipoos hangen nauw samen (ook met events) - klok op 25 Hz: zou kunnen. Is dan lastig naar 17 Hz terug te brengen (alsie framerate niet haalt) ***************************************************** */ /* debug */ int sectcount; int matcount, spherecount, cylcount, facecount; short simuldevs[32], simulvals[32]; void del_dupli_life(Object *ob); int (*intersect_func)(); Object *main_actor; typedef struct Snijp { float labda, minlabda, inpspeed; float radius, radiusq, slen;/* genormaliseerd, lengte */ DFace *face; /* alleen fh */ Material *ma; float *obmat; /* als hier iets staat: ook doen! */ float no[3]; /* als flag==1, staat hier normaal */ float speedn[3]; ushort ocx, ocy, ocz; /* van de 'ray' of de life */ char flag; /* 0: vlak gesneden, 1: cylinder/sphere, 2:life */ char lay; } Snijp; void ApplyMatrix(void *mat, float *old, float *new) { /* if(sectcount<100) matcount++; */ VecMat4MulVecfl(new, mat, old); } /* ************** PORTALS ************** */ int passed_portal(int type, float *size, float *vec) { switch(type) { case PO_XPOS: if(vec[0]>size[0]) return 1; break; case PO_XNEG: if(vec[0]<-size[0]) return 1; break; case PO_YPOS: if(vec[1]>size[1]) return 1; break; case PO_YNEG: if(vec[1]<-size[1]) return 1; break; case PO_ZPOS: if(vec[2]>size[2]) return 1; break; case PO_ZNEG: if(vec[2]<-size[2]) return 1; break; } return 0; } int passed_portal_safe(int type, float *size, float *vec, float safe) { switch(type) { case PO_XPOS: if(vec[0]+safe>size[0]) return 1; break; case PO_XNEG: if(vec[0]-safe<-size[0]) return 1; break; case PO_YPOS: if(vec[1]+safe>size[1]) return 1; break; case PO_YNEG: if(vec[1]-safe<-size[1]) return 1; break; case PO_ZPOS: if(vec[2]+safe>size[2]) return 1; break; case PO_ZNEG: if(vec[2]-safe<-size[2]) return 1; break; } return 0; } /* ******************** LBUF ************************** */ #define LBUFSTEP 4 void add_to_lbuf(LBuf *lbuf, Object *ob) { if(lbuf->max==0) { lbuf->ob= callocN(4*LBUFSTEP, "firstlbuf"); lbuf->max= LBUFSTEP; lbuf->tot= 1; lbuf->ob[0]= ob; } else { Object **obar; /* dubbels: gewoon toestaan */ if(lbuf->tot==lbuf->max) { lbuf->max+= LBUFSTEP; obar= callocN(4*lbuf->max, "nlbuf"); LONGCOPY(obar, lbuf->ob, lbuf->max); freeN(lbuf->ob); lbuf->ob= obar; } lbuf->ob[ lbuf->tot ]= ob; lbuf->tot++; } } void free_lbuf(LBuf *lbuf) { if(lbuf->ob) freeN(lbuf->ob); lbuf->ob= 0; lbuf->max= lbuf->tot= 0; } void del_from_lbuf(LBuf *lbuf, Object *ob) { int a; if(lbuf->tot==0 || lbuf->max==0) return; for(a=0; atot; a++) { /* dubbels: wel afvangen */ if(lbuf->ob[a] == ob) { lbuf->tot--; if(lbuf->tot>a) { lbuf->ob[a] = lbuf->ob[ lbuf->tot ]; lbuf->ob[ lbuf->tot ]= 0; /* hoeft niet? */ } else lbuf->ob[a]= 0; } } } /* ****************** OCTREE x:16 y:16 z:16 *************************** */ void init_snijp(Mesh *me, Snijp *sn, float *oldloc, float *speed) { float vec[3], *dvec, *size; short a, b, min[3], max[3]; /* optimalisering sphere en cyl */ VECCOPY(sn->speedn, speed); sn->slen= Normalise(sn->speedn); sn->ocx= 0; /* voldoende om hierop te testen */ /* ivm. returns wel pas op 't eind berekenen */ if(me==0 || me->oc==0 || sn->slen==0.0) return; dvec= me->oc->dvec; size= me->oc->size; vec[0]= oldloc[0]-dvec[0]; vec[1]= oldloc[1]-dvec[1]; vec[2]= oldloc[2]-dvec[2]; if(size[0]!=0.0) { a= ffloor(16.0*(vec[0]-sn->radius)/size[0]); b= ffloor(16.0*(vec[0]-sn->radius+speed[0])/size[0]); min[0]= MIN2(a, b); a= ffloor(16.0*(vec[0]+sn->radius)/size[0]); b= ffloor(16.0*(vec[0]+sn->radius+speed[0])/size[0]); max[0]= MAX2(a, b); if(max[0]<0 || min[0]>15) return; if(max[0]>15) max[0]= 15; if(min[0]< 0) min[0]= 0; } else {min[0]=0; max[0]= 15;} if(size[1]!=0.0) { a= ffloor(16.0*(vec[1]-sn->radius)/size[1]); b= ffloor(16.0*(vec[1]-sn->radius+speed[1])/size[1]); min[1]= MIN2(a, b); a= ffloor(16.0*(vec[1]+sn->radius)/size[1]); b= ffloor(16.0*(vec[1]+sn->radius+speed[1])/size[1]); max[1]= MAX2(a, b); if(max[1]<0 || min[1]>15) return; if(max[1]>15) max[1]= 15; if(min[1]< 0) min[1]= 0; } else {min[1]=0; max[1]= 15;} if(size[2]!=0.0) { a= ffloor(16.0*(vec[2]-sn->radius)/size[2]); b= ffloor(16.0*(vec[2]-sn->radius+speed[2])/size[2]); min[2]= MIN2(a, b); a= ffloor(16.0*(vec[2]+sn->radius)/size[2]); b= ffloor(16.0*(vec[2]+sn->radius+speed[2])/size[2]); max[2]= MAX2(a, b); if(max[2]<0 || min[2]>15) return; if(max[2]>15) max[2]= 15; if(min[2]<0) min[2]= 0; } else {min[2]=0; max[2]= 15;} sn->ocx= BROW(min[0], max[0]); sn->ocy= BROW(min[1], max[1]); sn->ocz= BROW(min[2], max[2]); } /* ****************** INSIDE **************************** */ int sector_cliptest(Sector *se, float *vec) { if(se->type==SE_CUBE) { if(vec[0]<-se->size[0]) return PO_XNEG; if(vec[1]<-se->size[1]) return PO_YNEG; if(vec[2]<-se->size[2]) return PO_ZNEG; if(vec[0]>se->size[0]) return PO_XPOS; if(vec[1]>se->size[1]) return PO_YPOS; if(vec[2]>se->size[2]) return PO_ZPOS; } return 0; } int sector_inside(Sector *se, float *vec, float *local) /* vec is globaal */ { if(se->ob==0) return 0; ApplyMatrix(se->ob->imat, vec, local); if( sector_cliptest(se, local)==0 ) return 1; return 0; } int sector_cliptest_sure(Sector *se, float *vec, float sure) { if(se->type==SE_CUBE) { if(vec[0]<-se->size[0]+sure) return PO_XNEG; if(vec[1]<-se->size[1]+sure) return PO_YNEG; if(vec[2]<-se->size[2]+sure) return PO_ZNEG; if(vec[0]>se->size[0]-sure) return PO_XPOS; if(vec[1]>se->size[1]-sure) return PO_YPOS; if(vec[2]>se->size[2]-sure) return PO_ZPOS; } return 0; } /* ook op PSX? */ int sector_intersect(Sector *se, Object *ob) { Life *lf; Mesh *me; float vec[3], local[3]; int a; if(ob->type!=OB_LIFE) return 0; lf= ob->data; me= lf->dynamesh; if(me==0) me= lf->texmesh; if(me==0 || me->bb==0 || me->totface==0) return 0; for(a=0; a<8; a++) { VECCOPY(vec, me->bb->vec[a]); Mat4MulVecfl(ob->obmat, vec); ApplyMatrix(se->ob->imat, vec, local); if( sector_cliptest_sure(se, local, 0.05)==0 ) return 1; } return 0; } Sector *find_sector(float *vec, float *local) /* algemene find */ { Base *base; base= FIRSTBASE; while(base) { if(base->lay & G.scene->lay) { if(base->object->type==OB_SECTOR) { if(sector_inside(base->object->data, vec, local)) { return base->object->data; } } } base= base->next; } return 0; } void life_in_sector_test(Object *ob) { Life *lf; LBuf *lb; Portal *po; Sector *se; int b, out; lf= ob->data; if(lf->type != LF_DYNAMIC) return; /* apart afhandelen voor PROPS! */ /* nog steeds in de huidige sector? */ if(lf->sector) { out= sector_cliptest(lf->sector, lf->loc1); if(out) { /* welke portalen */ if(lf->dflag & LF_TEMPLIFE) lb= 0; else if((lf->flag & LF_MAINACTOR)==0) { lb= &(lf->sector->lbuf); del_from_lbuf( lb, ob); } else lb= 0; se= lf->sector; b= se->totport; po= se->portals; while(b--) { if(po->sector && passed_portal(po->type, se->size, lf->loc1)) { if(sector_inside(po->sector, lf->loc, lf->loc1)) { lf->sector= po->sector; if(lb) add_to_lbuf( &(lf->sector->lbuf), ob); return; } } po++; } /* diagonaal ofzo? */ se= find_sector(lf->loc, lf->loc1); if(se) { lf->sector= se; if(lb) add_to_lbuf( &(lf->sector->lbuf), ob); printf("out, but found one\n"); return; } /* helaas: */ if(lf->dflag & LF_TEMPLIFE) { lf->timer= 0; } else { /* printf("out\n"); */ lf->loc1[0]= lf->loc1[1]= 0; lf->loc1[2]= 0.5*lf->sector->size[2]; lf->speed[0]= lf->speed[1]= lf->speed[2]= 0; ApplyMatrix(lf->sector->ob->obmat, lf->loc1, lf->loc); /* misschien speed flippen? twijfelachtig */ } } } if(lf->sector==0 ) { lf->sector= find_sector(lf->loc, lf->loc1); if( (lf->dflag & LF_TEMPLIFE)==0) { /**/ /* dit zit niet in de engine, waarom? */ if(lf->sector && (lf->flag & LF_MAINACTOR)==0) add_to_lbuf( &(lf->sector->lbuf), ob); } } } void mainactor_in_sector_test() /* zet G.cursector */ { Portal *po; float vec[3], local[3]; int b, out; if(main_actor==0) return; /* vanwege psx */ vec[0]= main_actor->obmat[3][0]; vec[1]= main_actor->obmat[3][1]; vec[2]= main_actor->obmat[3][2]; /* nog steeds in de huidige sector? */ if(G.cursector) { /* lokale coord: */ ApplyMatrix(G.cursector->ob->imat, vec, local); out= sector_cliptest(G.cursector, local); if(out) { /* welke portalen */ b= G.cursector->totport; po= G.cursector->portals; while(b--) { if(po->sector && passed_portal(po->type, G.cursector->size, local)) { if(sector_inside(po->sector, vec, local)) { G.cursector= po->sector; evaluate_camera_network(0, -1); /* init */ ; return; } } po++; } /* helaas: */ G.cursector= 0; } } if(G.cursector==0) { G.cursector= find_sector(main_actor->obmat[3], local); if(G.cursector) { evaluate_camera_network(0, -1); /* init */ ; } } } void normal_rot_inv(mat, inv, no) float mat[][4], inv[][4], *no; { float x, y, z; x= no[0]*mat[0][0] + no[1]*mat[1][0] + no[2]*mat[2][0]; y= no[0]*mat[0][1] + no[1]*mat[1][1] + no[2]*mat[2][1]; z= no[0]*mat[0][2] + no[1]*mat[1][2] + no[2]*mat[2][2]; no[0]= x*inv[0][0] + y*inv[1][0] + z*inv[2][0]; no[1]= x*inv[0][1] + y*inv[1][1] + z*inv[2][1]; no[2]= x*inv[0][2] + y*inv[1][2] + z*inv[2][2]; /* geen normalise: inpspeed bevat scale-informatie */ /* Normalise(no); */ } /* ********************** DYNA ************************* */ #define UNSUREF 0.02 /* labdacor labda */ /* -----x---------x------- */ /* . . */ /* geval 1 -----.----> . */ /* geval 2 --.---------.--> */ /* geval 3 . ----.------> */ /* geval 4 . -----> . */ int intersect_dface(DFace *dface, Snijp *sn, float *oldloc, float *speed) { float ndist, labda, labdacor, s, t, inploc, inpspeed; int cox=0, coy=1; /* als dface->v3==0 : dface->ocx==0 */ if( (dface->ocx & sn->ocx)==0 ) return 0; if( (dface->ocy & sn->ocy)==0 ) return 0; if( (dface->ocz & sn->ocz)==0 ) return 0; if((sn->lay & dface->ma->lay)==0) return 0; inpspeed= dface->no[0]*speed[0] + dface->no[1]*speed[1] + dface->no[2]*speed[2]; /* single sided! */ if(inpspeed < -TOLER) { inploc= dface->no[0]*oldloc[0] + dface->no[1]*oldloc[1] + dface->no[2]*oldloc[2]; ndist= dface->dist - inploc; /* negatief! */ if(ndist>0.0) return 0; labda= (ndist)/inpspeed; /* voor s-t */ labdacor= (ndist+UNSUREF)/inpspeed; /* labda is gegarandeerd > 0! (ndist<0.0) */ /* dit is een soort interval-wiskunde */ if(labdacor<=sn->minlabda) { if(labda<=sn->minlabda) return 0; } if(labdacor>=sn->labda) { if(labda>= sn->labda) return 0; } if(dface->proj==1) coy= 2; else if(dface->proj==2) { cox= 1; coy= 2; } s= oldloc[cox] + labda*speed[cox]; t= oldloc[coy] + labda*speed[coy]; if( (dface->v2[cox] - s)*(dface->v2[coy] - dface->v1[coy]) - (dface->v2[coy] - t)*(dface->v2[cox] - dface->v1[cox]) < -TOLER ) return 0; if( (dface->v3[cox] - s)*(dface->v3[coy] - dface->v2[coy]) - (dface->v3[coy] - t)*(dface->v3[cox] - dface->v2[cox])< -TOLER ) return 0; if(dface->v4==0) { if( (dface->v1[cox] - s)*(dface->v1[coy] - dface->v3[coy]) - (dface->v1[coy] - t)*(dface->v1[cox] - dface->v3[cox])< -TOLER ) return 0; } else { if( (dface->v4[cox] - s)*(dface->v4[coy] - dface->v3[coy]) - (dface->v4[coy] - t)*(dface->v4[cox] - dface->v3[cox])< -TOLER ) return 0; if( (dface->v1[cox] - s)*(dface->v1[coy] - dface->v4[coy]) - (dface->v1[coy] - t)*(dface->v1[cox] - dface->v4[cox])< -TOLER ) return 0; } sn->labda= labdacor; sn->inpspeed= inpspeed; sn->face= dface; sn->flag= 0; return 1; } return 0; } /* genormaliseerde speed en kwadratische straal in sn-struct? inclusief lengte speed */ typedef struct pSnijp { int labda, minlabda, inpspeed; int radius, radiusq, slen; /* slen: lengte speed */ short no[3]; /* als flag==1, staat hier normaal */ short speedn[3]; /* genormaliseerd */ ushort ocx, ocy, ocz; /* van de 'ray' of de life */ short flag; /* 0: vlak gesneden, 1: cylinder/sphere */ } pSnijp; #define FIX(fac) ((int)(4096.0*fac)) #define FIX14(fac) ((int)(16384.0*fac)) #define S14MUL(a, b) ( ((a)*(b))>>14 ) void fix_coordvec(int *ip, float *fp) { ip[0]= FIX(fp[0]); ip[1]= FIX(fp[1]); ip[2]= FIX(fp[2]); } void fix_coordvecs(short *ip, float *fp) { ip[0]= FIX(fp[0]); ip[1]= FIX(fp[1]); ip[2]= FIX(fp[2]); } int SquareRoot0(int num) { return (int)fsqrt( (float)num); } int Normalises(short *vec) /* 12 bits */ { float fp[3], len; VECCOPY(fp, vec); len= Normalise(fp); vec[0]= FIX(fp[0]); vec[1]= FIX(fp[1]); vec[2]= FIX(fp[2]); return (int)(len); } void CrossS(c, a, b) short *c, *a, *b; { c[0] = (a[1] * b[2] - a[2] * b[1])>>12; c[1] = (a[2] * b[0] - a[0] * b[2])>>12; c[2] = (a[0] * b[1] - a[1] * b[0])>>12; } int vertex_sphere_intersect_i(int *v1, pSnijp *sn, int *oldloc, short *speed) { int labda, labdacor, len, bsq, u, disc, rc[3]; if(sn->slen < 10) return 0; /* superslow */ rc[0]= oldloc[0]-v1[0]; rc[1]= oldloc[1]-v1[1]; rc[2]= oldloc[2]-v1[2]; bsq= (rc[0]*sn->speedn[0] + rc[1]*sn->speedn[1] + rc[2]*sn->speedn[2])>>12; u= rc[0]*rc[0] + rc[1]*rc[1] + rc[2]*rc[2] - sn->radiusq; disc= bsq*bsq - u; if(disc>=0) { disc= SquareRoot0(disc); u= -bsq - disc; /* mag je delen? */ if( u < -sn->slen || u> sn->slen) return 0; labdacor= (u<<14)/(sn->slen); /* 14 bits */ u= -bsq + disc; labda= (u<<12)/(sn->slen>>2); } else return 0; /* twee gevallen waarbij geen snijpunt is */ if(labdacor>=sn->labda && labda>=sn->labda) return 0; if(labdacor<=sn->minlabda && labda<=sn->minlabda) return 0; PRINT2(f, f, labdacor/16384.0, labda/16384.0); /* snijpunt en normaal */ /* hier 12 bits */ sn->no[0]= rc[0] + ((labdacor*speed[0])>>14) ; sn->no[1]= rc[1] + ((labdacor*speed[1])>>14) ; sn->no[2]= rc[2] + ((labdacor*speed[2])>>14) ; PRINT3(f, f, f, sn->no[0]/4096.0, sn->no[1]/4096.0, sn->no[2]/4096.0); sn->labda= labdacor; /* inpspeed op lengte brengen: twee keer radius!!! (inpspeed wordt weer met normaal vermenigvuldigd)*/ /* inspeed: 16 bits */ sn->inpspeed= ( (sn->no[0]*speed[0] + sn->no[1]*speed[1] + sn->no[2]*speed[2])<<4 )/(sn->radiusq>>12); PRINT(f, sn->inpspeed/65536.0); sn->flag= 1; if(FALSE) { /* namaak refl */ int fac; short speed1[3]; VECCOPY(speed1, speed); fac= S14MUL( -4096-4096, sn->inpspeed); speed1[0]+= S14MUL(fac, sn->no[0]); speed1[1]+= S14MUL(fac, sn->no[1]); speed1[2]+= S14MUL(fac, sn->no[2]); PRINT3(f, f, f, speed1[0]/4096.0, speed1[1]/4096.0, speed1[2]/4096.0); } return 1; } int sphere_sphere_intersect(float *v1, Snijp *sn, float *oldloc, float *speed) { float labda, labdacor, bsq, u, disc, rc[3]; float radius, radiusq; radius= v1[3]+sn->radius; radiusq= radius*radius; rc[0]= oldloc[0]-v1[0]; rc[1]= oldloc[1]-v1[1]; rc[2]= oldloc[2]-v1[2]; bsq= rc[0]*sn->speedn[0] + rc[1]*sn->speedn[1] + rc[2]*sn->speedn[2]; u= rc[0]*rc[0] + rc[1]*rc[1] + rc[2]*rc[2] - radiusq; disc= bsq*bsq - u; if(disc>=0.0) { disc= fsqrt(disc); labdacor= (-bsq - disc)/sn->slen; /* intrede */ labda= (-bsq + disc)/sn->slen; } else return 0; /* twee gevallen waarbij geen snijpunt is */ if(labdacor>=sn->labda && labda>=sn->labda) return 0; if(labdacor<=sn->minlabda && labda<=sn->minlabda) return 0; /* PATCH!!! */ if(labdacor<0.0) labdacor/= 2.0; /* snijpunt en normaal */ sn->no[0]= rc[0] + labdacor*speed[0] ; sn->no[1]= rc[1] + labdacor*speed[1] ; sn->no[2]= rc[2] + labdacor*speed[2] ; /* corrigeren: v1[3]= axsize */ disc= v1[3]/radius; sn->no[0]*= disc; sn->no[1]*= disc; sn->no[2]*= disc; sn->labda= labdacor; /* inpspeed op lengte brengen: twee keer radius!!! (inpspeed wordt weer met normaal vermenigvuldigd)*/ radiusq= v1[3]*v1[3]; sn->inpspeed= (sn->no[0]*speed[0] + sn->no[1]*speed[1] + sn->no[2]*speed[2])/(radiusq); sn->flag= 2; return 1; } int vertex_sphere_intersect(float *v1, Snijp *sn, float *oldloc, float *speed) { float labda, labdacor, bsq, u, disc, rc[3]; if(FALSE){ pSnijp psn; int iv1[3], ioldloc[3]; short ispeed[3]; fix_coordvec(iv1, v1); fix_coordvec(ioldloc, oldloc); fix_coordvecs(ispeed, speed); psn.radius= FIX(sn->radius); psn.radiusq= psn.radius*psn.radius; psn.labda= FIX14(sn->labda); psn.minlabda= FIX14(sn->minlabda); fix_coordvecs(psn.speedn, sn->speedn); psn.slen= FIX(sn->slen); vertex_sphere_intersect_i(iv1, &psn, ioldloc, ispeed); } /* if(sectcount<100) spherecount++; */ rc[0]= oldloc[0]-v1[0]; rc[1]= oldloc[1]-v1[1]; rc[2]= oldloc[2]-v1[2]; bsq= rc[0]*sn->speedn[0] + rc[1]*sn->speedn[1] + rc[2]*sn->speedn[2]; u= rc[0]*rc[0] + rc[1]*rc[1] + rc[2]*rc[2] - sn->radiusq; disc= bsq*bsq - u; if(disc>=0.0) { disc= fsqrt(disc); labdacor= (-bsq - disc)/sn->slen; /* intrede */ labda= (-bsq + disc)/sn->slen; } else return 0; /* twee gevallen waarbij geen snijpunt is */ if(labdacor>=sn->labda && labda>=sn->labda) return 0; if(labdacor<=sn->minlabda && labda<=sn->minlabda) return 0; /* PRINT2(f, f, labdacor, labda); */ /* snijpunt en normaal */ sn->no[0]= rc[0] + labdacor*speed[0] ; sn->no[1]= rc[1] + labdacor*speed[1] ; sn->no[2]= rc[2] + labdacor*speed[2] ; /* PRINT3(f, f, f, sn->no[0], sn->no[1], sn->no[2]); */ sn->labda= labdacor; /* inpspeed op lengte brengen: twee keer radius!!! (inpspeed wordt weer met normaal vermenigvuldigd)*/ sn->inpspeed= (sn->no[0]*speed[0] + sn->no[1]*speed[1] + sn->no[2]*speed[2])/(sn->radiusq); sn->flag= 1; /* PRINT(f, sn->inpspeed); */ if(FALSE) { /* namaak refl */ float fac, speed1[3]; VECCOPY(speed1, speed); fac= (-2.0)*sn->inpspeed; speed1[0]+= fac*sn->no[0]; speed1[1]+= fac*sn->no[1]; speed1[2]+= fac*sn->no[2]; PRINT3(f, f, f, speed1[0], speed1[1], speed1[2]); } return 1; } int cylinder_edge_intersect_i(int *base, int *v2, pSnijp *sn, int *oldloc, short *speed) { int osp, rdd, s, t, dist, len, len2, labda, labdacor, rc[3]; short axis[3], n[3], o[3]; PRINT(d, sn->slen); if(sn->slen < 10) return 0; /* superslow */ axis[0]= v2[0]-base[0]; axis[1]= v2[1]-base[1]; axis[2]= v2[2]-base[2]; len2= Normalises(axis); /* op PSX:test eerst! */ rc[0]= oldloc[0]-base[0]; rc[1]= oldloc[1]-base[1]; rc[2]= oldloc[2]-base[2]; CrossS(n, speed, axis); len= Normalises(n); if(len==0) return 0; dist= abs( (rc[0]*n[0] + rc[1]*n[1] + rc[2]*n[2])>>12 ); PRINT2(d, d, dist, sn->radius); if( dist>=sn->radius ) return 0; /* CrossS(o, rc, axis); */ o[0] = (rc[1] * axis[2] - rc[2] * axis[1])>>12; o[1] = (rc[2] * axis[0] - rc[0] * axis[2])>>12; o[2] = (rc[0] * axis[1] - rc[1] * axis[0])>>12; t= -((o[0]*n[0] + o[1]*n[1] + o[2]*n[2])<<2)/(len); /* 14 bits */ CrossS(o, n, axis); osp= (o[0]*speed[0] + o[1]*speed[1] + o[2]*speed[2])>>12; rdd= SquareRoot0(sn->radiusq-dist*dist); s= abs( (rdd<<14) / osp); PRINT2(f, f, s/16384.0, t/16384.0); labdacor= (t-s); labda= (t+s); PRINT2(f, f, labdacor/16384.0, labda/16384.0); /* twee gevallen waarbij geen snijpunt is */ if(labdacor>=sn->labda && labda>=sn->labda) return 0; if(labdacor<=sn->minlabda && labda<=sn->minlabda) return 0; /* normaalvector berekenen */ /* snijpunt: */ rc[0]= rc[0] + ((labdacor*speed[0])>>14); rc[1]= rc[1] + ((labdacor*speed[1])>>14); rc[2]= rc[2] + ((labdacor*speed[2])>>14); s= (rc[0]*axis[0] + rc[1]*axis[1] + rc[2]*axis[2])>>12 ; if(s<0 || s>len2) return 0; /* tot aan de laatste return niets in de sn struct invullen! */ /* 12 bits */ sn->no[0]= rc[0] - ((s*axis[0])>>12); sn->no[1]= rc[1] - ((s*axis[1])>>12); sn->no[2]= rc[2] - ((s*axis[2])>>12); sn->labda= labdacor; /* 16 bits */ sn->inpspeed= ( (sn->no[0]*speed[0] + sn->no[1]*speed[1] + sn->no[2]*speed[2])<<4 )/(sn->radiusq>>12); sn->flag= 1; PRINT(f, sn->inpspeed/65536.0); if(TRUE) { /* namaak refl */ int fac; short speed1[3]; VECCOPY(speed1, speed); fac= S14MUL( -4096-4096, sn->inpspeed); speed1[0]+= S14MUL(fac, sn->no[0]); speed1[1]+= S14MUL(fac, sn->no[1]); speed1[2]+= S14MUL(fac, sn->no[2]); PRINT3(f, f, f, speed1[0]/4096.0, speed1[1]/4096.0, speed1[2]/4096.0); } return 1; } int cylinder_edge_intersect(float *base, float *v2, Snijp *sn, float *oldloc, float *speed) { float s, t, dist, len, len2, labda, labdacor, axis[3], rc[3], n[3], o[3]; if(FALSE){ pSnijp psn; int ibase[3], iv2[3], ioldloc[3]; short ispeed[3]; fix_coordvec(iv2, v2); fix_coordvec(ibase, base); fix_coordvec(ioldloc, oldloc); fix_coordvecs(ispeed, speed); psn.radius= FIX(sn->radius); psn.radiusq= psn.radius*psn.radius; psn.labda= FIX14(sn->labda); psn.minlabda= FIX14(sn->minlabda); fix_coordvecs(psn.speedn, sn->speedn); psn.slen= FIX(sn->slen); cylinder_edge_intersect_i(ibase, iv2, &psn, ioldloc, ispeed); } axis[0]= v2[0]-base[0]; axis[1]= v2[1]-base[1]; axis[2]= v2[2]-base[2]; len2= Normalise(axis); rc[0]= oldloc[0]-base[0]; rc[1]= oldloc[1]-base[1]; rc[2]= oldloc[2]-base[2]; /* if(sectcount<100) cylcount++; */ Crossf(n, speed, axis); len= Normalise(n); if(len==0.0) return 0; dist= fabs( rc[0]*n[0] + rc[1]*n[1] + rc[2]*n[2] ); /* PRINT2(f, f, dist, sn->radius); */ if( dist>=sn->radius ) return 0; Crossf(o, rc, axis); t= -(o[0]*n[0] + o[1]*n[1] + o[2]*n[2])/len; Crossf(o, n, axis); s= fabs(fsqrt(sn->radiusq-dist*dist) / (o[0]*speed[0] + o[1]*speed[1] + o[2]*speed[2])); /* PRINT2(f, f, s, t ); */ labdacor= (t-s); labda= (t+s); /* PRINT2(f, f, labdacor, labda); */ /* twee gevallen waarbij geen snijpunt is */ if(labdacor>=sn->labda && labda>=sn->labda) return 0; if(labdacor<=sn->minlabda && labda<=sn->minlabda) return 0; /* normaalvector berekenen */ /* snijpunt: */ rc[0]= rc[0] + labdacor*speed[0] ; rc[1]= rc[1] + labdacor*speed[1] ; rc[2]= rc[2] + labdacor*speed[2] ; s= (rc[0]*axis[0] + rc[1]*axis[1] + rc[2]*axis[2]) ; if(s<0.0 || s>len2) return 0; /* tot aan de laatste return niets in de sn struct invullen! */ sn->no[0]= (rc[0] - s*axis[0]); sn->no[1]= (rc[1] - s*axis[1]); sn->no[2]= (rc[2] - s*axis[2]); sn->labda= labdacor; sn->inpspeed= (sn->no[0]*speed[0] + sn->no[1]*speed[1] + sn->no[2]*speed[2])/sn->radiusq; sn->flag= 1; /* PRINT(f, sn->inpspeed); */ if(FALSE) { /* namaak refl */ float fac, speed1[3]; VECCOPY(speed1, speed); fac= (-2.0)*sn->inpspeed; speed1[0]+= fac*sn->no[0]; speed1[1]+= fac*sn->no[1]; speed1[2]+= fac*sn->no[2]; PRINT3(f, f, f, speed1[0], speed1[1], speed1[2]); } return 1; } int intersect_dface_cyl(DFace *dface, Snijp *sn, float *oldloc, float *speed) { float *v1, *v2, *v3, *v4; float ndist, labda, labdacor, s, t, inploc, inpspeed; float out; short cox=0, coy=1, ok, ed, cytest; /* als dface->v3==0 : dface->ocx==0 */ if( (dface->ocx & sn->ocx)==0 ) return 0; if( (dface->ocy & sn->ocy)==0 ) return 0; if( (dface->ocz & sn->ocz)==0 ) return 0; if((sn->lay & dface->ma->lay)==0) return 0; dface->flag |= DF_HILITE; inpspeed= dface->no[0]*speed[0] + dface->no[1]*speed[1] + dface->no[2]*speed[2]; /* single sided! */ if(inpspeed < -TOLER) { inploc= dface->no[0]*oldloc[0] + dface->no[1]*oldloc[1] + dface->no[2]*oldloc[2]; ndist= dface->dist - inploc; /* negatief! */ if(ndist>0.0) return 0; labda= (ndist)/inpspeed; /* voor s-t */ labdacor= (ndist+sn->radius)/inpspeed; /* labda is gegarandeerd > 0! (ndist<0.0) */ /* twee gevallen waarbij geen snijpunt is */ if(labdacor>=sn->labda && labda>=sn->labda) return 0; if(labdacor<=sn->minlabda && labda<=sn->minlabda) return 0; if(dface->proj==1) coy= 2; else if(dface->proj==2) { cox= 1; coy= 2; } /* testen oftie exact het vlak snijdt */ if(labdacor<=0.0) { /* geen labda, wel met correctie zodat snijp binnen vlak valt */ /* dit is in feite de loodrechte projektie */ s= oldloc[cox] - sn->radius*dface->no[cox]; t= oldloc[coy] - sn->radius*dface->no[coy]; labdacor= 0.0; } else { /* met correctie zodat snijp binnen vlak valt */ s= oldloc[cox] + labdacor*speed[cox] - sn->radius*dface->no[cox]; t= oldloc[coy] + labdacor*speed[coy] - sn->radius*dface->no[coy]; } /* if(sectcount<100) facecount++; */ v1= dface->v1; v2= dface->v2; v3= dface->v3; v4= dface->v4; cytest= 0; out= (v2[cox] - s)*(v2[coy] - v1[coy]) - (v2[coy] - t)*(v2[cox] - v1[cox]); if(out > -TOLER) { out= (v3[cox] - s)*(v3[coy] - v2[coy]) - (v3[coy] - t)*(v3[cox] - v2[cox]); if(out > -TOLER) { ok= 0; if(v4==0) { out= (v1[cox] - s)*(v1[coy] - v3[coy]) - (v1[coy] - t)*(v1[cox] - v3[cox]); if(out > -TOLER) ok= 1; else cytest= 3; } else { out= (v4[cox] - s)*(v4[coy] - v3[coy]) - (v4[coy] - t)*(v4[cox] - v3[cox]); if(out > -TOLER) { out= (v1[cox] - s)*(v1[coy] - v4[coy]) - (v1[coy] - t)*(v1[cox] - v4[cox]); if(out > -TOLER) ok= 1; else cytest= 5; } else cytest= 4; } if(ok) { sn->labda= labdacor; sn->inpspeed= inpspeed; sn->face= dface; sn->flag= 0; return 1; } } else cytest= 2; } else cytest= 1; /* edges (= cylinders) testen */ ok= 0; ed= dface->edcode; switch(cytest) { case 1: if( (ed & DF_V1V2) && cylinder_edge_intersect(v1, v2, sn, oldloc, speed) ) ok= 1; break; case 2: if( (ed & DF_V2V3) && cylinder_edge_intersect(v2, v3, sn, oldloc, speed) ) ok= 1; break; case 3: if( (ed & DF_V3V1) && cylinder_edge_intersect(v3, v1, sn, oldloc, speed) ) ok= 1; break; case 4: if( (ed & DF_V3V4) && cylinder_edge_intersect(v3, v4, sn, oldloc, speed) ) ok= 1; break; case 5: if( (ed & DF_V4V1) && cylinder_edge_intersect(v4, v1, sn, oldloc, speed) ) ok= 1; break; } if(ok) sn->face= dface; if(ok==0) { if( (ed & DF_V1) && vertex_sphere_intersect(v1, sn, oldloc, speed)) { sn->face= dface; return 1; } if( (ed & DF_V2) && vertex_sphere_intersect(v2, sn, oldloc, speed)) { sn->face= dface; return 1; } if( (ed & DF_V3) && vertex_sphere_intersect(v3, sn, oldloc, speed)) { sn->face= dface; return 1; } if(v4) if( (ed & DF_V4) && vertex_sphere_intersect(v4, sn, oldloc, speed)) { sn->face= dface; return 1; } } /* PATCH: onderzoeken hoe en wat en waarom: extreem negatieve labda's */ /* waarschijnlijk iets van doen met meerdere snijps? */ if(sn->labdaminlabda) sn->labda= sn->minlabda; return ok; } return 0; } int intersect_dynalife(Object *ob, Life *lf, Snijp *sn) { extern Material defmaterial; Object *obs; Life *lfs; float mindist, loc1[4]; /* loc1 is incl axsize */ int a, b, found= 0; /* nodig voor genormaliseerde speed */ init_snijp(0, sn, lf->oldloc1, lf->speed1); if(sn->slen < 0.0001) return 0; a= G.totlife; while(a--) { obs= G.lifebuf[a]; if(obs->type!=OB_CAMERA) { lfs= obs->data; if(lf!=lfs && lfs->collision!=ob && lf->from!=obs && lfs->type==LF_DYNAMIC && (lfs->dflag & LF_TEMPLIFE)==0) { /* manhattan pre-test */ mindist= 3.0*(sn->radius+lfs->axsize); if( fabs(lf->loc[0]-lf->loc[0]) > mindist ) continue; if( fabs(lf->loc[1]-lf->loc[1]) > mindist ) continue; if( fabs(lf->loc[2]-lf->loc[2]) > mindist ) continue; /* gebruik lokale sector coords */ ApplyMatrix(lf->sector->ob->imat, lfs->loc, loc1); loc1[3]= lfs->axsize; /* truuk: bollen met stralen r1 en r2 snijden is equiv. met lijn snijden met bol van straal r1+r2 ! */ if(sphere_sphere_intersect(loc1, sn, lf->oldloc1, lf->speed1)) { found= 1; sn->ma= &defmaterial; sn->obmat= 0; sn->face= 0; lf->collision= obs; lfs->collision= ob; } } } } /* hier geen patch: in ruil voor labdacor delen door 2 (sphere_sphere_intersect) */ return found; } int intersect_prop(Sector *se, Life *lf, Snijp *sn) { /* botst Life *lf tegen een van de props uit *se ? */ Object *ob; Life *lfs; DFace *dface; float oldloc2[3], loc2[3], speed2[3]; int a, b, found= 0; for(b=0; blbuf.tot; b++) { ob= se->lbuf.ob[b]; if(ob->lay & G.scene->lay) { /* ivm layer event */ lfs= ob->data; if(lf!=lfs && lfs->dynamesh && lfs->type==LF_PROP) { /* transformeren naar life coordinaten */ ApplyMatrix(ob->imat, lf->loc, loc2); ApplyMatrix(ob->imat, lf->oldloc, oldloc2); speed2[0]= loc2[0]-oldloc2[0]; speed2[1]= loc2[1]-oldloc2[1]; speed2[2]= loc2[2]-oldloc2[2]; init_snijp(lfs->dynamesh, sn, oldloc2, speed2); if(sn->ocx) { dface= lfs->dynamesh->dface; a= lfs->dynamesh->totface; while(a--) { if( intersect_func(dface, sn, oldloc2, speed2)) { sn->obmat= ob->obmat[0]; lf->collision= ob; lfs->collision= ob; /* alleen waar/nietwaar */ found= 1; } dface++; } } } } } return found; } void force_from_prop(Life *lf, Snijp *sn) /* maar 1 tegelijk!!! */ { Object *ob; Life *lfs; Sector *se; DFace *dface; float fac, oldloc2[3], loc2[3], speed2[3], *no; int a, b, found; /* struct sn wordt doorgegeven vanwege de reeds ingevulde radius */ /* mogelijke denkfout: het eerste de beste vlak wordt gepakt! is soms * niet het vlak met de meeste/juiste force... * Voorlopig afhandelen door Fh ook bij props te doen? */ se= lf->sector; for(b=0; blbuf.tot; b++) { ob= se->lbuf.ob[b]; if(G.scene->lay & ob->lay) { lfs= ob->data; if(lf!=lfs && (lfs->dflag & LF_DYNACHANGED)) { if(lfs->type==LF_PROP && lfs->dynamesh) { sn->minlabda= 0.0; sn->labda= 1.0; found= 0; /* werken aan de hand van de 'virtuele' vorige positie van life */ ApplyMatrix(ob->imat, lf->loc, loc2); ApplyMatrix(lfs->oldimat, lf->oldloc, oldloc2); speed2[0]= loc2[0]-oldloc2[0]; speed2[1]= loc2[1]-oldloc2[1]; speed2[2]= loc2[2]-oldloc2[2]; init_snijp(lfs->dynamesh, sn, oldloc2, speed2); if(sn->ocx) { dface= lfs->dynamesh->dface; a= lfs->dynamesh->totface; while(a--) { if( intersect_func(dface, sn, oldloc2, speed2)) { found= 1; } dface++; } if(found) { /* de bots loc */ oldloc2[0]+= sn->labda*speed2[0]; oldloc2[1]+= sn->labda*speed2[1]; oldloc2[2]+= sn->labda*speed2[2]; /* nieuwe speed, hier refl.demping: -1.0: parrallel aan vlak, -2.0: zuivere botsing */ fac= (-1.0- DYNA_REF(sn->face->ma))*sn->inpspeed; /* oplossing: hier stond +=, komt neer op min speed2 !!! */ /* min speed2= exact de speed van het botsvlak!!! */ if(sn->flag==0) no= sn->face->no; else no= sn->no; speed2[0]= fac*no[0]; speed2[1]= fac*no[1]; speed2[2]= fac*no[2]; /* de virtuele oldloc */ oldloc2[0]-= sn->labda*speed2[0]; oldloc2[1]-= sn->labda*speed2[1]; oldloc2[2]-= sn->labda*speed2[2]; /* de (nieuwe) eindlocatie */ loc2[0]= oldloc2[0]+speed2[0]; loc2[1]= oldloc2[1]+speed2[1]; loc2[2]= oldloc2[2]+speed2[2]; ApplyMatrix(ob->obmat, loc2, lf->loc); Mat4Mul3Vecfl(ob->obmat, speed2); VECCOPY(lf->speed, speed2); /* oldloc niet meer nodig */ return; } } } } } } } int test_visibility(float *lookat, float *from, Life *lf, Sector *se) { Snijp sn; Mesh *me; DFace *dface; float fac, loc1[3], oldloc1[3], speed1[3]; short a, found; if(se==0 || se->dynamesh==0) return 0; /* transformeren naar lokale sector coords en intersecten */ ApplyMatrix(se->ob->imat, from, loc1); ApplyMatrix(se->ob->imat, lookat, oldloc1); /* hier oppassen met shorts! */ speed1[0]= loc1[0]-oldloc1[0]; speed1[1]= loc1[1]-oldloc1[1]; speed1[2]= loc1[2]-oldloc1[2]; me= se->dynamesh; sn.minlabda= sn.radius= 0.0; /* radius op nul voor init_snijp */ sn.labda= 1.0; sn.obmat= 0; sn.lay= lf->lay; found= 0; init_snijp(me, &sn, oldloc1, speed1); if(sn.ocx) { dface= me->dface; a= me->totface; while(a--) { if( intersect_dface(dface, &sn, oldloc1, speed1)) found= 1; dface++; } if(found) { /* de bots loc */ oldloc1[0]+= sn.labda*speed1[0]; oldloc1[1]+= sn.labda*speed1[1]; oldloc1[2]+= sn.labda*speed1[2]; /* reflectie berekenen */ fac= (-2.0)*sn.inpspeed; speed1[0]+= fac*sn.face->no[0]; speed1[1]+= fac*sn.face->no[1]; speed1[2]+= fac*sn.face->no[2]; fac= (1.0 - sn.labda); /* endloc */ oldloc1[0]+= fac*speed1[0]; oldloc1[1]+= fac*speed1[1]; oldloc1[2]+= fac*speed1[2]; /* blenden */ loc1[0]= (15*loc1[0] + oldloc1[0])/16.0; loc1[1]= (15*loc1[1] + oldloc1[1])/16.0; loc1[2]= (15*loc1[2] + oldloc1[2])/16.0; ApplyMatrix(se->ob->obmat, loc1, from); return 1; } } return 0; } void collision_detect(Object *ob, Life *lf) { /* een soort reetrees routine: zoek dichtstbijzijnde snijpunt */ /* werken met de lokale life co's */ Mesh *me; Portal *po; Sector *se; DFace *dface, *from=0; float *oldloc1, *speed1, *no, fac, len; Snijp sn; int a, b, found=1, transback=0, colcount=0; lf->collision= 0; se= lf->sector; me= se->dynamesh; if(me==0) return; sn.minlabda= 0.0; sn.lay= lf->lay; if(lf->flag & LF_SPHERE) { sn.radius= lf->axsize; sn.radiusq= sn.radius*sn.radius; intersect_func= intersect_dface_cyl; } else { sn.radius= UNSUREF; /* voor octree */ intersect_func= intersect_dface; } /* beetje speedup */ oldloc1= lf->oldloc1; speed1= lf->speed1; while(found) { sn.labda= 1.0; sn.obmat= 0; found= 0; init_snijp(me, &sn, oldloc1, speed1); if(sn.ocx) { dface= me->dface; a= me->totface; while(a--) { if(dface!=from) { if( intersect_func(dface, &sn, oldloc1, speed1)) found= 1; } dface++; } if(found) lf->collision= se->ob; } /* de prop lifes */ /* tijdelijk lopen we ze allemaal af */ /* toch maar vast de globale opnieuw berekenen... */ if(transback) { life_from_inv_sector_co(lf); transback= 0; } if(se->lbuf.tot) found |= intersect_prop(se, lf, &sn); found |= intersect_dynalife(ob, lf, &sn); /* als loc buiten sector ligt, doen ook vlakken van portals mee */ b= se->totport; po= se->portals; while(b--) { /* safe: voor krappe sectoren waar andere in steken! */ if(po->sector && po->sector->dynamesh && passed_portal_safe(po->type, se->size, lf->loc1, lf->axsize)) { float oldloc2[3], loc2[3], speed2[3]; /* toch maar vast de globale opnieuw berekenen want... */ if(transback) { life_from_inv_sector_co(lf); transback= 0; } /* ... we moeten transformeren naar nieuwe locale coordinaten */ ApplyMatrix(po->ob->imat, lf->loc, loc2); ApplyMatrix(po->ob->imat, lf->oldloc, oldloc2); speed2[0]= loc2[0]-oldloc2[0]; speed2[1]= loc2[1]-oldloc2[1]; speed2[2]= loc2[2]-oldloc2[2]; init_snijp(po->sector->dynamesh, &sn, oldloc2, speed2); if(sn.ocx) { dface= po->sector->dynamesh->dface; a= po->sector->dynamesh->totface; while(a--) { if(dface!=from) { if( intersect_func(dface, &sn, oldloc2, speed2)) { sn.obmat= po->ob->obmat[0]; lf->collision= po->ob; found= 1; } } dface++; } } } po++; } if(found) { colcount++; transback= 1; from= sn.face; /* de bots loc */ lf->colloc[0]= oldloc1[0]+ sn.labda*speed1[0]; lf->colloc[1]= oldloc1[1]+ sn.labda*speed1[1]; lf->colloc[2]= oldloc1[2]+ sn.labda*speed1[2]; if(sn.flag==0) { no= sn.face->no; sn.ma= sn.face->ma; } else { no= sn.no; if(sn.flag==1) sn.ma= sn.face->ma; } /* nieuwe speed, hier refl.demping: -1.0: parrallel aan vlak, -2.0: zuivere botsing */ fac= (-1.0- DYNA_REF(sn.ma))*sn.inpspeed; /* pas op: als sn.obmat (in andere object) de no[] roteren */ if(sn.obmat) { float nor[3]; VECCOPY(nor, no); normal_rot_inv(sn.obmat, se->ob->imat, nor); speed1[0]+= fac*nor[0]; speed1[1]+= fac*nor[1]; speed1[2]+= fac*nor[2]; } else { speed1[0]+= fac*no[0]; speed1[1]+= fac*no[1]; speed1[2]+= fac*no[2]; } /* de virtuele oldloc */ oldloc1[0]= lf->colloc[0] - sn.labda*speed1[0]; oldloc1[1]= lf->colloc[1] - sn.labda*speed1[1]; oldloc1[2]= lf->colloc[2] - sn.labda*speed1[2]; if(colcount>3) if( sn.labda <= sn.minlabda) found= 0; if(sn.minlabda>=1.0) found= 0; else sn.minlabda= sn.labda; } } /* als er gebotst is: terug transformeren naar globale coordinaten */ if(transback) life_from_inv_sector_co(lf); /* als laatste: de kracht die static life uitoefenen kan */ force_from_prop(lf, &sn); } /* ******************* hele fh spul: *********************** */ #define FH_SECTOR 1 #define FH_PROP 2 int intersect_fh(DFace *dface, float *oldloc, Snijp *sn) { float s, t, tlab, inploc, inpspeed; /* speed: 0, 0, -1 */ /* als dface->v3==0 : dface->ocx==0 */ if( (dface->ocx & sn->ocx)==0 ) return 0; if( (dface->ocy & sn->ocy)==0 ) return 0; if( (dface->ocz & sn->ocz)==0 ) return 0; dface->flag |= DF_HILITE; inpspeed= (-1.0)*dface->no[2]; /* single sided! */ if(inpspeed < -TOLER) { inploc= dface->no[0]*oldloc[0] + dface->no[1]*oldloc[1] + dface->no[2]*oldloc[2]; tlab= (dface->dist - inploc)/inpspeed; if(tlab < 0.0 || tlab >= sn->labda) return 0; s= oldloc[0]; t= oldloc[1]; if( (dface->v2[0] - s)*(dface->v2[1] - dface->v1[1]) < (dface->v2[1] - t)*(dface->v2[0] - dface->v1[0])) return 0; if( (dface->v3[0] - s)*(dface->v3[1] - dface->v2[1]) < (dface->v3[1] - t)*(dface->v3[0] - dface->v2[0])) return 0; if(dface->v4==0) { if( (dface->v1[0] - s)*(dface->v1[1] - dface->v3[1]) < (dface->v1[1] - t)*(dface->v1[0] - dface->v3[0])) return 0; } else { if( (dface->v4[0] - s)*(dface->v4[1] - dface->v3[1]) < (dface->v4[1] - t)*(dface->v4[0] - dface->v3[0])) return 0; if( (dface->v1[0] - s)*(dface->v1[1] - dface->v4[1]) < (dface->v1[1] - t)*(dface->v1[0] - dface->v4[0])) return 0; } sn->labda= tlab; sn->face= dface; if(tlab<= DYNA_FH_DIST(dface->ma)) { sn->flag= FH_SECTOR; return 1; } return 0; } return 0; } /* alleen vor props, iets andere return opzet */ int intersect_fh_rot(DFace *dface, float *oldloc, Snijp *sn, float *speed) { float s, t, inploc, inpspeed, tlab; short cox=0, coy=1; /* speed: 0, 0, -1 (maar dan geroteerd) (lengte 1) */ /* als dface->v3==0 : dface->ocx==0 */ if( (dface->ocx & sn->ocx)==0 ) return 0; if( (dface->ocy & sn->ocy)==0 ) return 0; if( (dface->ocz & sn->ocz)==0 ) return 0; dface->flag |= DF_HILITE; inpspeed= -dface->no[0]*speed[0] - dface->no[1]*speed[1] - dface->no[2]*speed[2]; /* single sided! */ if(inpspeed < -TOLER) { inploc= dface->no[0]*oldloc[0] + dface->no[1]*oldloc[1] + dface->no[2]*oldloc[2]; tlab= (dface->dist - inploc)/inpspeed; if(tlab < 0.0 || tlab >= sn->labda) return 0; if(dface->proj==1) coy= 2; else if(dface->proj==2) { cox= 1; coy= 2; } s= oldloc[cox] + tlab*speed[cox]; t= oldloc[coy] + tlab*speed[coy]; if( (dface->v2[cox] - s)*(dface->v2[coy] - dface->v1[coy]) - (dface->v2[coy] - t)*(dface->v2[cox] - dface->v1[cox]) < 0.0 ) return 0; if( (dface->v3[cox] - s)*(dface->v3[coy] - dface->v2[coy]) - (dface->v3[coy] - t)*(dface->v3[cox] - dface->v2[cox])< 0.0 ) return 0; if(dface->v4==0) { if( (dface->v1[cox] - s)*(dface->v1[coy] - dface->v3[coy]) - (dface->v1[coy] - t)*(dface->v1[cox] - dface->v3[cox])< 0.0 ) return 0; } else { if( (dface->v4[cox] - s)*(dface->v4[coy] - dface->v3[coy]) - (dface->v4[coy] - t)*(dface->v4[cox] - dface->v3[cox])< 0.0 ) return 0; if( (dface->v1[cox] - s)*(dface->v1[coy] - dface->v4[coy]) - (dface->v1[coy] - t)*(dface->v1[cox] - dface->v4[cox])< 0.0 ) return 0; } sn->labda= tlab; sn->face= dface; if(tlab<= DYNA_FH_DIST(dface->ma)) { sn->flag= FH_PROP; } return 1; } return 0; } void update_Fheight(Life *lf, float *force) { /* alleen anti-zwaartekracht: pas op met rotaties. Normaal vlak= F_afstoot */ DFace *dface; Material *ma; Life *lfs; Sector *se; Object *propob; Snijp sn; float *mat, speed[3], alpha, fac, loc2[3], oldloc2[3], loc1[3], no[3]; int a, b; lf->contact= 0; lf->floor= 0; /* is er wel 'n Fh vlak in mesh ? */ if(lf->sector->dynamesh==0) return; sn.labda= 32.0; sn.face= 0; sn.ma= 0; sn.flag= 0; sn.radius= UNSUREF; mat= lf->sector->ob->obmat[0]; speed[0]=speed[1]= 0.0; speed[2]= -8.0; init_snijp(lf->sector->dynamesh, &sn, lf->loc1, speed); dface= lf->sector->dynamesh->dface; a= lf->sector->dynamesh->totface; while(a--) { if(DYNA_FH_DIST(dface->ma)!=0.0) { /* alleen loodrechte projektie!!! */ if( intersect_fh(dface, lf->loc1, &sn) ) { /* geen break: beste fh! */ } } dface++; } /* of mogelijk de props? */ if(sn.flag==0 && lf->sector->lbuf.tot) { se= lf->sector; for(b=0; blbuf.tot; b++) { propob= se->lbuf.ob[b]; lfs= propob->data; if(lf!=lfs && lfs->dynamesh) { /* is er wel 'n Fh vlak in mesh ? */ /* transformeren naar life coordinaten */ ApplyMatrix(propob->imat, lf->loc, loc1); dface= lfs->dynamesh->dface; a= lfs->dynamesh->totface; speed[0]= -8.0*propob->obmat[2][0]; speed[1]= -8.0*propob->obmat[2][1]; speed[2]= -8.0*propob->obmat[2][2]; init_snijp(lfs->dynamesh, &sn, loc1, speed); speed[0]= propob->obmat[2][0]; speed[1]= propob->obmat[2][1]; speed[2]= propob->obmat[2][2]; while(a--) { if(DYNA_FH_DIST(dface->ma)!=0.0) { /* loodrechte projektie */ if( intersect_fh_rot(dface, loc1, &sn, speed) ) { /* normaal roteren volgens life */ mat= propob->obmat[0]; if(sn.flag == FH_PROP) break; } } dface++; } if(sn.flag == FH_PROP) break; } } } if(sn.face) { if(FALSE) { /* normaal roteren naar world coords: 'wipeout' wandjes, duwen in richting normaal vlak */ no[0]= sn.face->no[0]*mat[0] + sn.face->no[1]*mat[4] + sn.face->no[2]*mat[8]; no[1]= sn.face->no[0]*mat[1] + sn.face->no[1]*mat[5] + sn.face->no[2]*mat[9]; no[2]= sn.face->no[0]*mat[2] + sn.face->no[1]*mat[6] + sn.face->no[2]*mat[10]; } else { /* alleen loodrecht */ no[0]= mat[8]; no[1]= mat[9]; no[2]= mat[10]; } /* floor locatie voor schaduw: altijd relatief! */ lf->floorloc[0]= - sn.labda*no[0]; lf->floorloc[1]= - sn.labda*no[1]; lf->floorloc[2]= - sn.labda*no[2]; lf->floor= sn.face; if(sn.flag) { ma= sn.face->ma; lf->contact= ma; /* sn.labda==0.0: exact op afstand dist */ sn.labda= 1.0 - sn.labda/DYNA_FH_DIST(ma); /* let op: 0.1 is ook verwerkt in de writepsx */ sn.labda*= 0.1*DYNA_FH_INT(ma); force[0]+= sn.labda*no[0]; force[1]+= sn.labda*no[1]; force[2]+= sn.labda*no[2]; /* extra fh friction, alleen in richting normaal */ alpha= lf->speed[0]*no[0] + lf->speed[1]*no[1] + lf->speed[2]*no[2] ; alpha*= DYNA_FH_FRICT(ma); lf->speed[0] -= alpha*no[0]; lf->speed[1] -= alpha*no[1]; lf->speed[2] -= alpha*no[2]; if( (sn.flag==FH_PROP) && (lfs->dflag & LF_DYNACHANGED) && lfs->type==LF_PROP) { /* werken aan de hand van de 'virtuele' vorige positie van life */ ApplyMatrix(propob->imat, lf->loc, loc2); ApplyMatrix(lfs->oldimat, lf->loc, oldloc2); no[0]= oldloc2[0]-loc2[0]; no[1]= oldloc2[1]-loc2[1]; no[2]= oldloc2[2]-loc2[2]; /* terug transformeren */ Mat4Mul3Vecfl(propob->obmat, no); /* dit is de 'stilstaande' speed */ fac= (DYNA_FH_XYFRICT(ma)); fac*= lf->frictfac; alpha= 1.0-fac; lf->speed[0]= alpha*lf->speed[0] + fac*no[0]; lf->speed[1]= alpha*lf->speed[1] + fac*no[1]; lf->speed[2]= alpha*lf->speed[2] + fac*no[2]; } else { alpha= 1.0 - lf->frictfac*(DYNA_FH_XYFRICT(ma)); lf->speed[0] *= alpha; lf->speed[1] *= alpha; } } } } void update_dynamics(Object *ob) { Life *lf; float frict, force[3], omega[3]; short event; if(ob->type==OB_CAMERA) { where_is_object_simul(ob); return; } lf= ob->data; if(lf->type==LF_DYNAMIC) { /* zwaartekracht */ force[0]= force[1]= 0.0; force[2]= -DTIME*G.scene->grav*lf->mass; omega[0]=omega[1]=omega[2]= 0.0; /* Fh: contact/schaduw. VOOR de sensor-input afhandelen: kan je de wrijving overwinnen */ if(lf->sector && (lf->flag & LF_DO_FH)) update_Fheight(lf, force); /* toetsen */ if(lf->flag & LF_SENSORS) sensor_input(ob, lf, force, omega); lf->speed[0]+= force[0]; lf->speed[1]+= force[1]; lf->speed[2]+= force[2]; lf->rotspeed[0]+= omega[0]; lf->rotspeed[1]+= omega[1]; lf->rotspeed[2]+= omega[2]; /* wrijving */ if(lf->frict!=0.0) { frict= 1.0-lf->frict*lf->frictfac; lf->speed[0]*= frict; lf->speed[1]*= frict; lf->speed[2]*= frict; } if(lf->rotfrict!=0.0) { frict= 1.0-lf->rotfrict; lf->rotspeed[0]*= frict; lf->rotspeed[1]*= frict; lf->rotspeed[2]*= frict; } VECCOPY(lf->oldloc, lf->loc); lf->loc[0]+= lf->speed[0]; lf->loc[1]+= lf->speed[1]; lf->loc[2]+= lf->speed[2]; lf->rot[0]+= lf->rotspeed[0]; lf->rot[1]+= lf->rotspeed[1]; lf->rot[2]+= lf->rotspeed[2]; life_to_local_sector_co(lf); if(lf->sector) collision_detect(ob, lf); if(lf->collision) collision_sensor_input(ob, lf); /* floorloc is berekend t.o.v. oldloc */ lf->floorloc[2]-= lf->speed[2]; VECCOPY(ob->loc, lf->loc); VECCOPY(ob->rot, lf->rot); where_is_object_simul(ob); Mat4InvertSimp(ob->imat, ob->obmat); } else { if(lf->type==LF_LINK) { /* toetsen */ if(lf->flag & LF_SENSORS) { if(lf->dflag & LF_OMEGA) { omega[0]=omega[1]=omega[2]= 0.0; sensor_input(ob, lf, force, omega); lf->rotspeed[0]+= omega[0]; lf->rotspeed[1]+= omega[1]; lf->rotspeed[2]+= omega[2]; if(lf->rotfrict!=0.0) { frict= 1.0-lf->rotfrict; lf->rotspeed[0]*= frict; lf->rotspeed[1]*= frict; lf->rotspeed[2]*= frict; } lf->rot[0]+= lf->rotspeed[0]; lf->rot[1]+= lf->rotspeed[1]; lf->rot[2]+= lf->rotspeed[2]; VECCOPY(ob->rot, lf->rot); } else { sensor_input(ob, lf, force, omega); } } /* link: altijd where_is doen */ where_is_object_simul(ob); Mat4InvertSimp(ob->imat, ob->obmat); } else { /* toetsen */ if(lf->flag & LF_SENSORS) { /* force en omega worden niet gebruikt */ if(event= sensor_input(ob, lf, force, omega) ) { if(event & SN_ROTCHANGED) { VECCOPY(ob->rot, lf->rot); } Mat4CpyMat4(lf->oldimat, ob->imat); where_is_object_simul(ob); Mat4InvertSimp(ob->imat, ob->obmat); } else { lf->dflag &= ~LF_DYNACHANGED; if(ob->parent) where_is_object_simul(ob); } } lf->collision= 0; /* is mogelijk door dynalife gezet */ } } } /* ************* REALTIME ************** */ #define SE_MAXBUF 32 #define LF_MAXBUF 32 void view_to_piramat(float mat[][4], float lens, float far) { /* maakt viewmat piramidevormig voor eenvoudige clip */ lens/= 12.0; /* hier stond 16.0 */ mat[0][0]*= (256.0/320.0)*lens; mat[1][0]*= (256.0/320.0)*lens; mat[2][0]*= (256.0/320.0)*lens; mat[3][0]*= (256.0/320.0)*lens; mat[0][1]*= lens; mat[1][1]*= lens; mat[2][1]*= lens; mat[3][1]*= lens; mat[0][2]*= -1; mat[1][2]*= -1; mat[2][2]*= -1; mat[3][2]*= -1; mat[3][3]= far; /* cliptest_sector leest dit uit */ } void init_sectors() { extern Material defmaterial; Base *base; Mesh *me; Portal *po; Sector *se; Life *lf; int a, printerr=0; G.cursector= 0; G.totsect= 0; /* vlaggen resetten */ me= G.main->mesh.first; while(me) { me->flag &= ~ME_ISDONE; me= me->id.next; } /* dit zijn globale INT tellers (gaat 10000 uren mee) */ G.dfra= G.dfrao= 1; init_dyna_material(&defmaterial); base= FIRSTBASE; while(base) { base->object->dfras= 0; /* geen layertest meer */ if(base->object->type==OB_SECTOR) { se= base->object->data; se->ob= base->object; se->lbuf.tot= se->lbuf.max= 0; se->lbuf.ob= 0; /* if(se->texmesh) se->texmesh->lastfra= 0; */ where_is_object_simul(base->object); Mat4Invert(base->object->imat, base->object->obmat); VECCOPY(se->bbsize, se->size); Mat4Mul3Vecfl(base->object->obmat, se->bbsize); portal_detect(base->object); if(se->dynamesh) { /* tijdelijke patch */ if(se->dynamesh->tface) { freeN(se->dynamesh->tface); se->dynamesh->tface= 0; PRINT(s, se->dynamesh->id.name+2); printerr= 1; } if(se->dynamesh->flag & ME_ISDONE); else { init_dynamesh(base->object, se->dynamesh); se->dynamesh->flag |= ME_ISDONE; } } } base= base->next; } if(printerr) error("dynamesh had tfaces"); /* portals testen: sectors die niet zijn gedaan wissen */ /* en de portal->ob pointers (optim?) */ base= FIRSTBASE; while(base) { if(base->object->type==OB_SECTOR) { se= base->object->data; po= se->portals; a= se->totport; while(a--) { if(po->sector) { if(po->sector->dynamesh->flag & ME_ISDONE) { po->ob= po->sector->ob; } else po->sector= 0; } po++; } } base= base->next; } } void end_sectors() { Base *base; Sector *se; base= FIRSTBASE; while(base) { if(base->object->type==OB_SECTOR) { se= base->object->data; se->ob= base->object; end_dynamesh(se->dynamesh); free_lbuf(&se->lbuf); } base= base->next; } G.cursector= 0; } void add_dyna_life(Object *ob) /* uitzondering: camera zit er ook in */ { int a, *ip=0; if(G.totlifelay= from->lay; lf= from->data; if(from->parent) { /* zeer primitieve rotatie ! */ VECCOPY(newob->rot, from->rot); par= from->parent; while(par) { newob->rot[0]+= par->rot[0]; newob->rot[1]+= par->rot[1]; newob->rot[2]+= par->rot[2]; par= par->parent; } VECCOPY(newob->loc, from->obmat[3]); } else if(lf->type==LF_DYNAMIC && lf->collision) { VECCOPY(newob->loc, lf->colloc); VECCOPY(newob->rot, from->rot); } else { VECCOPY(newob->loc, from->loc); VECCOPY(newob->rot, from->rot); } where_is_object_simul(newob); add_dyna_life(newob); newob->data=lfn= dupallocN(ob->data); VECCOPY(lfn->loc, newob->loc); VECCOPY(lfn->rot, newob->rot); lfn->sensors= dupallocN(lfn->sensors); for(a=lfn->totsens, sn=lfn->sensors; a>0; a--, sn++) { sn->events= dupallocN(sn->events); sn->actions= dupallocN(sn->actions); } lfn->dflag |= LF_TEMPLIFE; lfn->timer= time; lfn->sector= lf->sector; lfn->collision= 0; while(from->parent) from= from->parent; lfn->from= from; } } void del_dupli_life(Object *ob) { Life *lf; Sensor *sn; int a, b; /* opzoeken in array */ a= G.totlife; while(a--) { if(G.lifebuf[a]==ob) { if(ob->type==OB_LIFE) { lf= ob->data; if(lf->dflag & LF_TEMPLIFE) { for(b=lf->totsens, sn=lf->sensors; b>0; b--, sn++) { freeN(sn->events); freeN(sn->actions); } freeN(lf->sensors); freeN(lf); ob->data= 0; freeN(ob); G.totlife--; G.lifebuf[a]= G.lifebuf[G.totlife]; } } return; } } } void del_dupli_lifes() { int a; a= G.totlife; while(a--) { del_dupli_life(G.lifebuf[a]); } } char clipcube[24]= {0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0}; int cliptest_sector(float *vec, float *size, float *mat, short round) { /* deze pakt de vier tetraederpunten */ /* interessante notitie: max= fabs(hoco[2]) zou je denken, * fabs is echter veel te weinig kritisch. Op deze wijze (met sign) * meer uitval achter de camera, maar wel OK! */ float hoco[3], min, max, far=mat[15]; short fl, fand, a, tot; char *ctab; /* nu de vraag hoeveel zin dit nog heeft? */ if(round<=3) tot= 8; else tot= 4; ctab= clipcube; fand= 63; while(tot--) { if(ctab[0]) hoco[0]= vec[0] - size[0]; else hoco[0]= vec[0] + size[0]; if(ctab[1]) hoco[1]= vec[1] - size[1]; else hoco[1]= vec[1] + size[1]; if(ctab[2]) hoco[2]= vec[2] - size[2]; else hoco[2]= vec[2] + size[2]; Mat4MulVecfl(mat, hoco); max= (hoco[2]); min= -max; fl= 0; if(hoco[0] < min) fl+= 1; else if(hoco[0] > max) fl+= 2; if(hoco[1] < min) fl+= 4; else if(hoco[1] > max) fl+= 8; if(hoco[2] < 0.0) fl+= 16; else if(hoco[2] > far) fl+= 32; fand &= fl; if(fand==0) return 1; ctab+= 3; } return 0; } void build_sectorlist(Object *cam) { Portal *po; Object *ob; Camera *ca; Base *base; Sector *se; float far, lens, piramat[4][4], seview[3], secentre[3]; short a, b, round, beforesect, startsect; float viewfac; if(G.scene->camera==0) { lens= 35.0; far= 16.0; } else { ca= G.scene->camera->data; lens= ca->lens; far= ca->clipend; } startsect= 0; G.totsect= 0; G.maxsect= G.scene->maxdrawsector; /* uitzondering afhandelen */ if(G.cursector==0 || cam==0) { base= FIRSTBASE; while(base) { if(base->lay & G.scene->lay) { if(base->object->type==OB_SECTOR) { G.sectorbuf[G.totsect]= base->object->data; G.totsect++; if(G.totsect>=G.maxsect) break; } } base= base->next; } return; } G.sectorbuf[0]= G.cursector; G.cursector->ob->dfras= G.dfras; G.cursector->depth= 0; G.totsect= 1; Mat4Ortho(cam->obmat); Mat4Invert(cam->imat, cam->obmat); /* viewmat */ Mat4CpyMat4(piramat, cam->imat); view_to_piramat(piramat, lens, far); round= 1; while(G.totsect=startsect; b--) { se= G.sectorbuf[b]; a= se->totport; po= se->portals; while(a--) { if(po->sector && po->ob->dfras!=G.dfras) { po->ob->dfras= G.dfras; ob= po->ob; if(ob->lay & G.scene->lay) { /* in beeld */ if(cliptest_sector(ob->obmat[3], po->sector->bbsize, piramat[0], round)) { G.sectorbuf[G.totsect]= po->sector; po->sector->depth= round; G.totsect++; if(G.totsect>=G.maxsect) break; } } } po++; } if(G.totsect>=G.maxsect) break; } round++; /* geen meer bijgekomen */ if(G.totsect==beforesect) return; startsect= beforesect; } } /* ************* REALTIME mainlus ************** */ /* swapbuffers_OT() */ /* ************* MAIN ************** */ void update_sector_lifes(Sector *se) { Object *ob; Life *lf; short a, b; if(se==0) return; for(b=0; blbuf.tot; b++) { ob= se->lbuf.ob[b]; if(ob->lay & G.scene->lay) { /* lifes zitten in meerdere sectoren of sector 2x afgehandeld */ if(ob->dfras!=G.dfras) { ob->dfras= G.dfras; lf= ob->data; /* beweegbare props: ook in lifebuf ivm sector wissel */ if(lf->type==LF_DYNAMIC) { add_dyna_life(ob); } else { update_dynamics(ob); } } } } } void update_lifes() { Object *ob; Life *lf; Portal *po; int a, b; /* cleanup lifebuf */ for(a=0; atype==OB_LIFE) { lf= ob->data; if( (lf->flag & LF_MAINACTOR)==0) { if( (lf->dflag & LF_TEMPLIFE)==0 ) { G.totlife--; G.lifebuf[a]= G.lifebuf[G.totlife]; a--; } } } } a= G.totsect; while(a-- > 0) { update_sector_lifes(G.sectorbuf[a]); } if(G.cursector) { a= G.cursector->totport; po= G.cursector->portals; while(a--) { update_sector_lifes(po->sector); po++; } } /* alle main+link en temp lifes: in volgorde ivm parents! */ for(a=0; atype==OB_LIFE) { life_in_sector_test(ob); update_dynamics(ob); lf= ob->data; for(b=0; blinks.tot; b++) update_dynamics(lf->links.ob[b]); } else where_is_object_simul(ob); /* camera */ } /* apart doen ivm delete */ a= G.totlife; while(a--) { ob= G.lifebuf[a]; if(ob->type==OB_LIFE) { lf= ob->data; if(lf->dflag & LF_TEMPLIFE) { if(lf->timer<=0 || lf->sector==0) { del_dupli_life(ob); } } } } } void sector_go() { extern double tottime; /* drawview.c */ extern int dbswaptime; /* global in life.c, voor print */ extern double speed_to_swaptime(int); /* drawview.c */ extern int update_time(); struct tms voidbuf; double swaptime; long time, ltime, dtime; int a, b; short event=0, val; /* per life: sector test * sensors * damage * update dynamics <- -> collision detectie * */ init_sectors(); /* doet ook mesh_isdone flag */ init_lifes(); init_camera_network(); init_devs(); update_time(); tottime= 0.0; swaptime= speed_to_swaptime(G.animspeed); ltime = times(&voidbuf); dtime= 4; /* vantevoren invullen (1/25 sec) */ sectcount=spherecount=cylcount=facecount=matcount= 0; while(TRUE) { /* dynamics lus: stapjes van 0.02 seconden */ G.dfrao= G.dfra; G.fields=0; set_dtime(dtime); /* global in object.c, ook voor cameranet */ dbswaptime= dtime; if(dtime>25) dtime= 25; while(dtime>0) { G.dfra++; G.dfras= G.dfra; event= pad_read(); if(event==SPACEKEY || event==ESCKEY) { G.simulf |= G_QUIT; break; } update_lifes(); dtime -= 2; G.fields++; sectcount++; } if(G.simulf & G_NETWORK) { evaluate_camera_network(0, 0); } else { mainactor_in_sector_test(); } build_sectorlist(G.scene->camera); drawview3d_simul(0); screen_swapbuffers(); /* tijdberekening: in hondersten van seconde */ while(dtime<2) { time = times(&voidbuf); dtime+= (time - ltime); if(dtime<2) sginap(1); } ltime= time; if(G.simulf & (G_RESTART+G_QUIT)) break; } end_camera_network(); end_sectors(); end_lifes(event!=SPACEKEY); set_dtime(2); /* restore */ G.qual= 0; /* PRINT4(d, d, d, d, sectcount, facecount, cylcount, spherecount); */ /* PRINT(d, matcount); */ }