/** * $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 * * * Version: $Id: sector.c,v 1.34 2000/09/25 22:02:54 ton Exp $ */ #include "blender.h" #include "graphics.h" #include "group.h" #include "sector.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) ***************************************************** */ Object *Glifebuf[LF_MAXLIFE]; Object *Gsectorbuf[256], *Gcursector; int Gtotsect, Gtotlife, Gmaxsect; int Gdfra, Gdfras, Gdfrao; /* debug */ int sectcount; int matcount, spherecount, cylcount, facecount; void del_dupli_life(Object *ob); int (*intersect_func)(); Object *main_actor; char *simul_load_str; typedef struct Snijp { float labda, minlabda, inpspeed; float radius, radiusq, slen;/* genormaliseerd, lengte */ float fhdist; /* last used fhdist */ 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); } /* ******************** LBUF ************************** */ #define LBUFSTEP 4 void add_to_lbuf(LBuf *lbuf, Object *ob) { if(lbuf->max==0) { lbuf->ob= callocN(sizeof(void *)*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(sizeof(void *)*lbuf->max, "nlbuf"); memcpy(obar, lbuf->ob, lbuf->max * sizeof(void *)); 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(Object *ob, float *vec) { float centre[3], size[3]; get_local_bounds(ob, centre, size); if(vec[0] < centre[0]-size[0]) return 1; if(vec[1] < centre[1]-size[1]) return 1; if(vec[2] < centre[2]-size[2]) return 1; if(vec[0] > centre[0]+size[0]) return 1; if(vec[1] > centre[1]+size[1]) return 1; if(vec[2] > centre[2]+size[2]) return 1; return 0; } int sector_cliptest_sphere(Object *ob, float *vec, float radius) { float centre[3], size[3]; get_local_bounds(ob, centre, size); if(vec[0] < centre[0]-size[0]-radius) return 1; if(vec[1] < centre[1]-size[1]-radius) return 1; if(vec[2] < centre[2]-size[2]-radius) return 1; if(vec[0] > centre[0]+size[0]-radius) return 1; if(vec[1] > centre[1]+size[1]-radius) return 1; if(vec[2] > centre[2]+size[2]-radius) return 1; return 0; } int sector_inside(Object *ob, float *vec, float *local) /* vec is globaal */ { if(ob==0) return 0; ApplyMatrix(ob->imat, vec, local); if( sector_cliptest(ob, local)==0 ) return 1; return 0; } Object *find_sector(float *vec, float *local) /* algemene find */ { Base *base; base= FIRSTBASE; while(base) { if(base->lay & G.scene->lay) { if(base->object->gameflag & OB_SECTOR) { if(sector_inside(base->object, vec, local)) { return base->object; } } } base= base->next; } return 0; } void life_in_sector_test(Object *ob) { Life *lf; Object *se, *obp; int b, out=0; lf= ob->life; if(lf==NULL || (lf->flag & OB_DYNAMIC)==0) return; /* apart afhandelen voor PROPS? */ /* nog steeds in de huidige sector? */ if(lf->sector) { out= sector_cliptest(lf->sector, lf->loc1); if(out) { del_from_lbuf( &(lf->sector->lbuf), ob); b= lf->sector->port.tot; while(b--) { obp= lf->sector->port.ob[b]; ApplyMatrix(obp->imat, lf->loc, lf->loc1); out= sector_cliptest(obp, lf->loc1); if(out==0) { lf->sector= obp; if((lf->flag & OB_MAINACTOR)==0) { if((lf->dflag & LF_TEMPLIFE)==0) { add_to_lbuf( &(lf->sector->lbuf), ob); } } break; } } } } if(out || lf->sector==NULL) { se= find_sector(lf->loc, lf->loc1); if(se) { lf->sector= se; if((lf->flag & OB_MAINACTOR)==0) { if((lf->dflag & LF_TEMPLIFE)==0) { 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"); */ if(ob==main_actor) { lf->loc1[0]= lf->loc1[1]= 0; lf->loc1[2]= lf->axsize; } lf->speed[0]= lf->speed[1]= lf->speed[2]= 0; /* misschien speed flippen? twijfelachtig */ } } } 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 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= FH_DYNA; return 1; } int vertex_sphere_intersect(float *v1, Snijp *sn, float *oldloc, float *speed) { float labda, labdacor, bsq, u, disc, rc[3]; 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= FH_SECTOR; /* 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(float *base, float *v2, Snijp *sn, float *oldloc, float *speed) { float s, t, u,dist, len, len2, labda, labdacor, axis[3], rc[3], n[3], o[3]; axis[0]= v2[0]-base[0]; axis[1]= v2[1]-base[1]; axis[2]= v2[2]-base[2]; len2= Normalise(axis); if(len2radius); */ 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); u= (o[0]*speed[0] + o[1]*speed[1] + o[2]*speed[2]); if(u<-TOLER || u>TOLER) s= fabs(safsqrt( sn->radiusq - dist*dist) / u); else return 0; /* 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= FH_SECTOR; /* 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 actor_bounds_overlap(Object *ob1, Object *ob2) { float axsize1, axsize2; float centre1[3], size[3]; float centre2[3]; if(ob1->gameflag & OB_DYNAMIC) { axsize1= ob1->life->axsize; VECCOPY(centre1, ob1->life->loc); } else { get_local_bounds(ob1, centre1, size); axsize1= MAX3(size[0]+fabs(centre1[0]), size[1]+fabs(centre1[1]), size[2]+fabs(centre1[2])); axsize1*= 1.41/ob1->sizefac; VECCOPY(centre1, ob1->obmat[3]); } if(ob2->gameflag & OB_DYNAMIC) { axsize2= ob2->life->axsize; VECCOPY(centre2, ob2->life->loc); } else { get_local_bounds(ob2, centre2, size); axsize2= MAX3(size[0]+fabs(centre2[0]), size[1]+fabs(centre2[1]), size[2]+fabs(centre2[2])); axsize2*= 1.41/ob2->sizefac; VECCOPY(centre2, ob2->obmat[3]); } if( centre1[0] + axsize1 < centre2[0] - axsize2) return 0; if( centre1[0] - axsize1 > centre2[0] + axsize2) return 0; if( centre1[1] + axsize1 < centre2[1] - axsize2) return 0; if( centre1[1] - axsize1 > centre2[1] + axsize2) return 0; if( centre1[2] + axsize1 < centre2[2] - axsize2) return 0; if( centre1[2] - axsize1 > centre2[2] + axsize2) return 0; return 1; } int intersect_dynalife(Object *ob, Life *lf, Snijp *sn) { extern Material defmaterial; Object *obs; Life *lfs; float fac, mindist, vec[3], 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= Gtotlife; while(a--) { obs= Glifebuf[a]; if(obs->life && (obs->lay & ob->lay)) { lfs= obs->life; /* not intersect with itself or dupli's with the 'mother' */ if(lf!=lfs && lfs->collision!=ob && lf->from!=obs && lfs->from!=ob && (lfs->flag & OB_DYNAMIC)) { /* manhattan pre-test */ /* 3.0, for speed vector! */ 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->imat, lfs->loc, loc1); loc1[3]= lf->sector->sizefac*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= give_current_material(ob, 1); if(sn->ma==NULL) sn->ma= &defmaterial; sn->obmat= 0; sn->face= 0; lf->collision= obs; lfs->collision= ob; if(sn->ma->reflect!=0.0) { /* each dyna half the speed */ VecMulf(sn->no, 0.5); fac= fsqrt(lf->speed[0]*lf->speed[0] + lf->speed[1]*lf->speed[1] + lf->speed[2]*lf->speed[2] ); fac *= sn->ma->reflect; /* rotate to global coords */ vec[0]= -sn->no[0]*fac; vec[1]= -sn->no[1]*fac; vec[2]= -sn->no[2]*fac; Mat4Mul3Vecfl(lfs->sector->obmat, vec); obs->life->force[0]+= vec[0]; obs->life->force[1]+= vec[1]; obs->life->force[2]+= vec[2]; } } } } } /* hier geen patch: in ruil voor labdacor delen door 2 (sphere_sphere_intersect) */ return found; } int intersect_prop(Object *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->life; if(lfs && lf!=lfs && ob->type==OB_MESH && (lfs->flag & OB_PROP)) { if( actor_bounds_overlap(lf->ob, ob) ) { Mesh *me= ob->data; /* transformeren naar life coordinaten */ ApplyMatrix(ob->imat, lf->loc, loc2); ApplyMatrix(ob->imat, lf->oldloc, oldloc2); sn->radius= ob->sizefac*lf->axsize; sn->radiusq= sn->radius*sn->radius; speed2[0]= loc2[0]-oldloc2[0]; speed2[1]= loc2[1]-oldloc2[1]; speed2[2]= loc2[2]-oldloc2[2]; init_snijp(me, sn, oldloc2, speed2); if(sn->ocx) { dface= me->dface; a= me->totface; while(a--) { if( intersect_func(dface, sn, oldloc2, speed2)) { sn->obmat= ob->obmat[0]; lf->collision= ob; lfs->collision= lf->ob; found= 1; } dface++; } } } } } } return found; } /* return 1: matrices differ */ int matrix_differ(float mat1[][4], float mat2[][4]) { /* pretty stupid, but still effective to avoid the 'gluing' on an edge (should be fixed!) */ int a, b; for(a=0; a<4; a++) { for(b=0; b<4; b++) { if(mat1[a][b] != mat2[a][b]) return 1; } } return 0; } void force_from_prop(Life *lf, Snijp *sn) /* maar 1 tegelijk!!! */ { Object *ob; Life *lfs; Object *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->life; if(lfs && lf!=lfs && (lfs->dflag & LF_DYNACHANGED)) { if( (lfs->flag & OB_PROP) && ob->type==OB_MESH) { if( actor_bounds_overlap(ob, lf->ob) ) { if(matrix_differ(lfs->oldimat, ob->imat)) { Mesh *me= ob->data; 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); sn->radius= ob->sizefac*lf->axsize; sn->radiusq= sn->radius*sn->radius; speed2[0]= loc2[0]-oldloc2[0]; speed2[1]= loc2[1]-oldloc2[1]; speed2[2]= loc2[2]-oldloc2[2]; init_snijp(me, sn, oldloc2, speed2); if(sn->ocx) { dface= me->dface; a= me->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- (sn->face->ma->reflect))*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; } } }} } } } } } void collision_detect(Object *ob, Life *lf) { /* een soort reetrees routine: zoek dichtstbijzijnde snijpunt */ /* werken met de lokale life co's */ Mesh *me; Object *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->data; if(me==0) return; sn.minlabda= 0.0; sn.lay= lf->lay; intersect_func= intersect_dface_cyl; /* beetje speedup */ oldloc1= lf->oldloc1; speed1= lf->speed1; while(found) { sn.labda= 1.0; sn.obmat= 0; sn.radius= lf->localaxsize; sn.radiusq= sn.radius*sn.radius; 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; } /* 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->port.tot; while(b--) { Object *obp= se->port.ob[b]; Mesh *me= obp->data; 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(obp->imat, lf->loc, loc2); ApplyMatrix(obp->imat, lf->oldloc, oldloc2); speed2[0]= loc2[0]-oldloc2[0]; speed2[1]= loc2[1]-oldloc2[1]; speed2[2]= loc2[2]-oldloc2[2]; init_snijp(me, &sn, oldloc2, speed2); if(sn.ocx) { dface= me->dface; a= me->totface; while(a--) { if(dface!=from) { if( intersect_func(dface, &sn, oldloc2, speed2)) { sn.obmat= obp->obmat[0]; lf->collision= obp; found= 1; } } dface++; } if(obp->lbuf.tot) found |= intersect_prop(obp, lf, &sn); } } 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==FH_SECTOR) sn.ma= sn.face->ma; } /* nieuwe speed, hier refl.demping: -1.0: parrallel aan vlak, -2.0: zuivere botsing */ fac= (-1.0- (sn.ma->reflect))*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->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: *********************** */ int intersect_fh(DFace *dface, float *oldloc, Snijp *sn, float *speed, float fhdist) { float s, t, tlab, inploc, inpspeed; short 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; 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]) < -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= tlab; sn->face= dface; if(tlab<= fhdist) { sn->flag= FH_SECTOR; sn->fhdist= fhdist; return 1; } return 0; } return 0; } void euler_rot_euler(float *eul1, float *eul2, int local) { /* convert to matrix, mult, convert back */ float mat[3][3], mat1[3][3], mat2[3][3]; if(eul2[0]!=0.0 || eul2[1]!=0.0 || eul2[2]!=0.0) { EulToMat3(eul1, mat1); EulToMat3(eul2, mat2); if(local) Mat3MulMat3(mat, mat1, mat2); else Mat3MulMat3(mat, mat2, mat1); Mat3ToEul(mat, eul1); } } void update_Fheight(Life *lf) { /* alleen anti-zwaartekracht: pas op met rotaties. Normaal vlak= F_afstoot */ DFace *dface; Material *ma; Mesh *me; Life *lfs; Object *propob, *se, *foundprop=NULL; Snijp sn; float *mat, speed[3], fhdist, alpha, fac, loc2[3], oldloc2[3], loc1[3], no[3]; int a, b; lf->contact= 0; lf->floor= 0; lf->floorloc[0]= lf->floorloc[1]= lf->floorloc[2]= 0.0; sn.labda= 80.0; sn.face= 0; sn.ma= 0; sn.flag= 0; sn.radius= UNSUREF; mat= lf->sector->obmat[0]; /* rotate! intersect is in local coords */ speed[0]= -80.0*mat[8]; speed[1]= -80.0*mat[9]; speed[2]= -80.0*mat[10]; me= lf->sector->data; init_snijp(me, &sn, lf->loc1, speed); VECCOPY(speed, mat+8); Normalise(speed); dface= me->dface; a= me->totface; while(a--) { if((dface->ma->fhdist)!=0.0) { fhdist= lf->localaxsize + dface->ma->fhdist*lf->sector->sizefac; /* alleen loodrechte projektie!!! */ if( intersect_fh(dface, lf->loc1, &sn, speed, fhdist) ) { /* no break: best fh! */ } } dface++; } /* or maybe the props? */ if(lf->sector->lbuf.tot) { se= lf->sector; for(b=0; blbuf.tot; b++) { propob= se->lbuf.ob[b]; lfs= propob->life; if(lfs && (lfs->flag & OB_PROP) && lf!=lfs && propob->type==OB_MESH) { Mesh *me= propob->data; /* is er wel 'n Fh vlak in mesh ? */ /* transformeren naar life coordinaten */ ApplyMatrix(propob->imat, lf->loc, loc1); dface= me->dface; a= me->totface; speed[0]= -80.0*propob->obmat[2][0]; speed[1]= -80.0*propob->obmat[2][1]; speed[2]= -80.0*propob->obmat[2][2]; init_snijp(me, &sn, loc1, speed); speed[0]= propob->obmat[2][0]; speed[1]= propob->obmat[2][1]; speed[2]= propob->obmat[2][2]; Normalise(speed); while(a--) { if((dface->ma->fhdist)!=0.0) { fhdist= (lf->axsize + dface->ma->fhdist)*propob->sizefac; /* loodrechte projektie */ if( intersect_fh(dface, loc1, &sn, speed, fhdist) ) { /* normaal roteren volgens life */ mat= propob->obmat[0]; foundprop= propob; sn.flag = FH_PROP; } } dface++; } if(sn.flag == FH_PROP) break; } } } if(sn.face) { /* floor locatie voor schaduw: altijd relatief en naar beneden! */ fac= -1.0*sn.labda; lf->floorloc[0]= 0.05*lf->localaxsize+fac*mat[8]; lf->floorloc[1]= 0.05*lf->localaxsize+fac*mat[9]; lf->floorloc[2]= 0.05*lf->localaxsize+fac*mat[10]; lf->floor= sn.face; if(sn.flag) { if(sn.face->ma->dynamode & MA_FH_NOR) { /* 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, global */ no[0]= mat[8]; no[1]= mat[9]; no[2]= mat[10]; } Normalise(no); ma= sn.face->ma; lf->contact= ma; /* sn.labda==0.0: exact op afstand dist */ sn.labda= 1.0 - sn.labda/(sn.fhdist); if(foundprop && sn.flag == FH_PROP) sn.labda*= ma->fh*foundprop->sizefac; else sn.labda*= ma->fh; lf->force[0]+= sn.labda*no[0]; lf->force[1]+= sn.labda*no[1]; lf->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*= (ma->xyfrict); /* wrong name */ 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->flag & OB_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= ((ma->friction)); 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*((ma->friction)); /* xy frict */ lf->speed[0] *= alpha; lf->speed[1] *= alpha; } if(lf->flag & OB_ROT_FH) { float *fp, cross[3], quat[4], fno[3]; int axis= 0; int upflag= 2; /* axis */ VECCOPY(no, lf->ob->obmat[2]); /* face normal */ VECCOPY(fno, sn.face->no); Mat4Mul3Vecfl(lf->sector->obmat, fno); fac= no[0]*fno[0]+ no[1]*fno[1]+ no[2]*fno[2]; /* just be sure we can make a cross vector */ if(fac<0.99990) { Crossf(cross, no, fno); Normalise(cross); fac= 0.2*safacos(fac); /* 0.5 is 100%, 0.2 means damping */ quat[0]= fcos(fac); quat[1]= cross[0]*fsin(fac); quat[2]= cross[1]*fsin(fac); quat[3]= cross[2]*fsin(fac); QuatToEul(quat, cross); euler_rot_euler(lf->rot, cross, 0); /* global */ } } } } } void aerodynamics_life(Object *ob, Life *lf) { float *q, speed[3], len, inp; if(lf->aero==0.0) return; /* the direction vector rotates the speed... */ /* only X/Y axis now */ if(lf->flag1 & LF_AERO_AXIS_Y) q= ob->obmat[1]; else q= ob->obmat[0]; VECCOPY(speed, lf->speed); len= Normalise(speed); if(len > TOLER) { inp= q[0]*speed[0] + q[1]*speed[1] + q[2]*speed[2] ; inp*= lf->aero; lf->speed[0]= inp*len*q[0] + (1.0-fabs(inp))*lf->speed[0]; lf->speed[1]= inp*len*q[1] + (1.0-fabs(inp))*lf->speed[1]; /* keep the z component? */ /* lf->speed[2]= inp*len*q[2] + (1.0-fabs(inp))*lf->speed[2]; */ } } void clear_life(Life *lf) { lf->flag1 &= ~(LF_CALC_MATRIX); lf->force[0]=lf->force[1]=lf->force[2]= 0.0; lf->omega[0]=lf->omega[1]=lf->omega[2]= 0.0; lf->dloc[0]=lf->dloc[1]=lf->dloc[2]= 0.0; lf->drot[0]=lf->drot[1]=lf->drot[2]= 0.0; lf->frictfac= 1.0; /* lf->collision= 0; */ } void update_motion(Object *ob) { Life *lf; float frict, grav; short doit; if(ob->life==NULL) { if(ob->type==OB_CAMERA) { where_is_object_simul(ob); return; } } lf= ob->life; /* cameras update also when outside sector */ if(lf->sector==NULL && ob->type!=OB_CAMERA) return; if(lf->flag & OB_DYNAMIC) { /* aerodynamics_life(ob, lf); */ /* zwaartekracht */ if(G.scene->world) grav= -DTIME*0.1*G.scene->world->gravity*ob->mass; else grav= -DTIME*ob->mass; /* Fh: contact/schaduw. VOOR de sensor-input afhandelen: kan je de wrijving overwinnen */ if(lf->sector && lf->flag & OB_DO_FH) update_Fheight(lf); /* toetsen */ sca_handling(ob, lf); lf->speed[0]+= (lf->force[0]/ob->mass); lf->speed[1]+= (lf->force[1]/ob->mass); lf->speed[2]+= grav + (lf->force[2]/ob->mass); lf->rotspeed[0]+= lf->omega[0]; lf->rotspeed[1]+= lf->omega[1]; lf->rotspeed[2]+= lf->omega[2]; /* wrijving */ if(ob->damping!=0.0) { frict= 1.0-ob->damping; /* lf->frictfac */ lf->speed[0]*= frict; lf->speed[1]*= frict; lf->speed[2]*= frict; } if(ob->rdamping!=0.0) { frict= 1.0-ob->rdamping; lf->rotspeed[0]*= frict; lf->rotspeed[1]*= frict; lf->rotspeed[2]*= frict; } VECCOPY(lf->oldloc, lf->loc); lf->loc[0]+= lf->speed[0]+lf->dloc[0]; lf->loc[1]+= lf->speed[1]+lf->dloc[1]; lf->loc[2]+= lf->speed[2]+lf->dloc[2]; /* lf->drot is set to zero for each time step */ VecAddf(lf->drot, lf->drot, lf->rotspeed); euler_rot_euler(lf->rot, lf->drot, lf->dflag & LF_ROT_LOCAL); 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 { sca_handling(ob, lf); /* this here, not for dyna's! */ /* the old engine had a special collision sensor input */ lf->collision= NULL; if(lf->flag & OB_CHILD) { /* omega stuff */ lf->rotspeed[0]+= lf->omega[0]; lf->rotspeed[1]+= lf->omega[1]; lf->rotspeed[2]+= lf->omega[2]; if(ob->rdamping!=0.0) { frict= 1.0-ob->rdamping; lf->rotspeed[0]*= frict; lf->rotspeed[1]*= frict; lf->rotspeed[2]*= frict; } } lf->rot[0]+= lf->rotspeed[0]+lf->drot[0]; lf->rot[1]+= lf->rotspeed[1]+lf->drot[1]; lf->rot[2]+= lf->rotspeed[2]+lf->drot[2]; VECCOPY(ob->rot, lf->rot); ob->loc[0]+= lf->dloc[0]; ob->loc[1]+= lf->dloc[1]; ob->loc[2]+= lf->dloc[2]; } /* check for dyna changed and parent transformation */ if(lf->flag & OB_CHILD) lf->flag1 |= LF_CALC_MATRIX; else if(ob->parent) lf->flag1 |= LF_CALC_MATRIX; if(lf->flag & OB_PROP) if(lf->flag1 & LF_CALC_MATRIX) lf->dflag |= LF_DYNACHANGED; if(ob->flag & OB_FROMGROUP) { /* the where_is_object_time was called already */ Mat4CpyMat4(lf->oldimat, ob->imat); Mat4InvertSimp(ob->imat, ob->obmat); VECCOPY(lf->loc, ob->obmat[3]); } else if(lf->flag1 & LF_CALC_MATRIX) { where_is_object_simul(ob); Mat4CpyMat4(lf->oldimat, ob->imat); Mat4InvertSimp(ob->imat, ob->obmat); VECCOPY(lf->loc, ob->obmat[3]); } else Mat4CpyMat4(lf->oldimat, ob->imat); /* this cycles, not really nice, but it allows controllers * to write in actuators of other objects. */ clear_life(lf); } /* ************* REALTIME ************** */ 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 */ } /* **************** INIT ***************************** */ /* 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; TFace *tface; 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; tface= me->tface; a= me->totface; while(a--) { if(tface && (tface->mode & TF_DYNAMIC)==0) { dface->ocx= 0; } else 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++; if(tface) tface++; } } 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_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) { if(dface->v4) CalcNormFloat4(dface->v1, dface->v2, dface->v3, dface->v4, dface->no); else 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; } /* **************** INIT ***************************** */ /* objects with overlapping boundboxes, add to portal array */ void add_object_portals(Object *ob) { Object *port; Base *base; float dist, bb1[3], bb2[3], cent1[3], cent2[3]; int test; /* rotate bbsize to global coords */ get_local_bounds(ob, cent1, bb1); Mat4Mul3Vecfl(ob->obmat, bb1); bb1[0]= fabs(bb1[0]); bb1[1]= fabs(bb1[1]); bb1[2]= fabs(bb1[2]); Mat4MulVecfl(ob->obmat, cent1); base= FIRSTBASE; while(base) { if(base->lay & G.scene->lay) { port= base->object; if(port!=ob && ( port->gameflag & OB_SECTOR )) { /* rotate bbsize to global coords */ get_local_bounds(port, cent2, bb2); Mat4Mul3Vecfl(port->obmat, bb2); bb2[0]= fabs(bb2[0]); bb2[1]= fabs(bb2[1]); bb2[2]= fabs(bb2[2]); Mat4MulVecfl(port->obmat, cent2); /* is it close? */ test= 0; dist= fabs(cent1[0] - cent2[0]) ; if( dist < 1.05*(bb1[0]+bb2[0]) ) test++; dist= fabs(cent1[1] - cent2[1]) ; if( dist < 1.05*(bb1[1]+bb2[1]) ) test++; dist= fabs(cent1[2] - cent2[2]) ; if( dist < 1.05*(bb1[2]+bb2[2]) ) test++; if(test==3) { add_to_lbuf(&ob->port, port); } } } base= base->next; } } void init_sectors() { extern Material defmaterial; Base *base; Mesh *me; Life *lf; float centre[3], *fp; int a; Gcursector= 0; Gtotsect= 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) */ Gdfra= Gdfrao= 1; base= FIRSTBASE; while(base) { base->object->dfras= 0; where_is_object_simul(base->object); Mat4Invert(base->object->imat, base->object->obmat); fp= base->object->imat[0]; base->object->sizefac= fsqrt(fp[0]*fp[0] + fp[1]*fp[1] + fp[2]*fp[2]); if(base->object->type==OB_MESH) { BoundBox *bb= ( (Mesh *)base->object->data )->bb; if(bb==0) { tex_space_mesh(base->object->data); } /* geen layertest meer */ if(base->object->gameflag & OB_SECTOR) { Object *ob= base->object; ob->lbuf.tot= ob->lbuf.max= 0; ob->lbuf.ob= 0; ob->port.tot= ob->port.max= 0; ob->port.ob= 0; get_local_bounds(ob, centre, ob->bbsize); me= ob->data; if(me->flag & ME_ISDONE); else { init_dynamesh(ob, me); me->flag |= ME_ISDONE; } } } base= base->next; } base= FIRSTBASE; while(base) { if(base->lay & G.scene->lay) { if(base->object->gameflag & OB_SECTOR) { add_object_portals(base->object); } } base= base->next; } } int test_visibility(float *lookat, float *from, Life *lf, Object *se) { Snijp sn; Mesh *me; DFace *dface; float fac, loc1[3], oldloc1[3], speed1[3]; short a, found; if(se==0) return 0; /* transformeren naar lokale sector coords en intersecten */ ApplyMatrix(se->imat, from, loc1); ApplyMatrix(se->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->data; 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]= (20*loc1[0] + oldloc1[0])/21.0; loc1[1]= (20*loc1[1] + oldloc1[1])/21.0; loc1[2]= (20*loc1[2] + oldloc1[2])/21.0; ApplyMatrix(se->obmat, loc1, from); return 1; } } return 0; } void end_sectors() { Base *base; base= FIRSTBASE; while(base) { if(base->object->type==OB_MESH) { end_dynamesh(base->object->data); } free_lbuf(&(base->object->lbuf)); free_lbuf(&(base->object->port)); base= base->next; } Gcursector= 0; } void add_dyna_life(Object *ob) { int a, *ip=0; if(Gtotlifelife==NULL || ob->life==NULL) return; if(Gtotlifelay= from->lay; lf= from->life; 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; */ /* } */ Mat3CpyMat4(mat, from->obmat); Mat3ToEul(mat, newob->rot); VECCOPY(newob->loc, from->obmat[3]); } else if((lf->flag & OB_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->life=lfn= dupallocN(ob->life); newob->life->ob= newob; VECCOPY(lfn->loc, newob->loc); VECCOPY(lfn->rot, newob->rot); VECCOPY(lfn->speed, lf->speed); VECCOPY(lfn->oldloc, lf->oldloc); /* copy SCA */ clear_sca_new_poins_ob(newob); copy_sensors(&newob->sensors, &ob->sensors); copy_controllers(&newob->controllers, &ob->controllers); copy_actuators(&newob->actuators, &ob->actuators); set_sca_new_poins_ob(newob); /* link controllers to sensors */ sens= newob->sensors.first; while(sens) { sens->ob= newob; for(a=0; atotlinks; a++) { add_sens_to_cont(sens, sens->links[a]); } sens= sens->next; } /* controller reset */ cont= newob->controllers.first; while(cont) { cont->val= 0; cont->valo= 0; cont= cont->next; } /* actuator reset, init */ act= newob->actuators.first; while(act) { act->ob= newob; act->go= 0; if(act->type==ACT_IPO) { bIpoActuator *ia; ia= act->data; ia->sta= 2*ia->sta; ia->end= 2*ia->end; ia->cur= ia->sta; } act= act->next; } /* property copy */ copy_properties(&newob->prop, &ob->prop); prop= newob->prop.first; while(prop) { if(prop->type==PROP_TIME) prop->data= Gdfra - 2*prop->old; prop= prop->next; } do_obipo(newob, 2*lf->sfra, 0, 0); lfn->dflag |= LF_TEMPLIFE; lfn->timer= time; lfn->collision= 0; while(from->parent) from= from->parent; lfn->from= from; if(from->gameflag & OB_LIFE) lfn->sector= ((Life *)from->life)->sector; } } void del_dupli_life(Object *ob) { bSensor *sens; Life *lf; int a, b; /* opzoeken in array */ a= Gtotlife; while(a--) { if(Glifebuf[a]==ob) { if(ob->gameflag & OB_LIFE) { lf= ob->life; if(lf->dflag & LF_TEMPLIFE) { /* remove sensors, they can be linked to not-duplicated stuff */ sens= ob->sensors.first; while(sens) { for(b=0; btotlinks; b++) { rem_sens_from_cont(sens, sens->links[b]); } sens= sens->next; } free_sensors(&ob->sensors); free_controllers(&ob->controllers); free_actuators(&ob->actuators); free_properties(&ob->prop); freeN(lf); freeN(ob); Gtotlife--; Glifebuf[a]= Glifebuf[Gtotlife]; } } return; } } } void del_dupli_lifes() { int a; a= Gtotlife; while(a--) { del_dupli_life(Glifebuf[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) { /* 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; tot= 5; ctab= clipcube; fand= 63; while(tot--) { if(tot==5) { hoco[0]= vec[0]; hoco[1]= vec[1]; hoco[2]= vec[2]; } else { 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) { Object *ob, *obp; Camera *ca; Base *base; float far, lens, piramat[4][4], dist, bbs; short a, b, 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; Gtotsect= 0; /* Gmaxsect= G.scene->maxdrawsector; */ Gmaxsect= 32; /* uitzondering afhandelen */ if(Gcursector==0 || cam==0) { base= FIRSTBASE; while(base) { if(base->lay & G.scene->lay) { if(base->object->gameflag & OB_SECTOR) { Gsectorbuf[Gtotsect]= base->object; Gtotsect++; if(Gtotsect>=Gmaxsect) break; } } base= base->next; } return; } Gsectorbuf[0]= Gcursector; Gcursector->dfras= Gdfras; Gtotsect= 1; Mat4Ortho(cam->obmat); Mat4Invert(cam->imat, cam->obmat); /* viewmat */ Mat4CpyMat4(piramat, cam->imat); view_to_piramat(piramat, lens, far); /* add the adjoining sectors */ a= Gcursector->port.tot; while(a--) { ob= Gcursector->port.ob[a]; Gsectorbuf[Gtotsect]= ob; ob->dfras= Gdfras; Gtotsect++; } while(Gtotsect=startsect; b--) { ob= Gsectorbuf[b]; a= ob->port.tot; while(a--) { obp= ob->port.ob[a]; if(obp->dfras!=Gdfras) { obp->dfras= Gdfras; if(ob->lay & G.scene->lay) { /* in beeld */ if(cliptest_sector(obp->obmat[3], obp->bbsize, piramat[0])) { Gsectorbuf[Gtotsect]= obp; Gtotsect++; if(Gtotsect>=Gmaxsect) break; } } } } if(Gtotsect>=Gmaxsect) break; } /* geen meer bijgekomen */ if(Gtotsect==beforesect) return; startsect= beforesect; } } /* ************* MAIN ************** */ void update_sector_lifes(Object *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!=Gdfras) { ob->dfras= Gdfras; lf= ob->life; if(lf->flag & (OB_DYNAMIC|OB_ACTOR)); else { update_motion(ob); } } } } } void lifebuf_sector_lifes(Object *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) { lf= ob->life; if(lf->flag & (OB_DYNAMIC|OB_ACTOR)) { if(lf->flag & OB_CHILD); else add_dyna_life(ob); } } } } void update_lifes() { Object *ob; Life *lf; int a, b; /* cleanup lifebuf */ for(a=0; agameflag & OB_LIFE) { /* if(ob->type!=OB_CAMERA) { */ lf= ob->life; if( (lf->flag & OB_MAINACTOR)==0) { if( (lf->dflag & LF_TEMPLIFE)==0 ) { Gtotlife--; Glifebuf[a]= Glifebuf[Gtotlife]; a--; } } /* } */ } } /* build lifebuf */ a= Gtotsect; while(a-- > 0) { lifebuf_sector_lifes(Gsectorbuf[a]); } G.scene->camera->dfras= Gdfras; /* events and motion */ a= Gtotsect; while(a-- > 0) { update_sector_lifes(Gsectorbuf[a]); } /* alle main+link en temp lifes: in volgorde ivm parents! */ for(a=0; alay & G.scene->lay) { if(ob->life) { life_in_sector_test(ob); update_motion(ob); lf= ob->life; for(b=0; blinks.tot; b++) update_motion(lf->links.ob[b]); } } } if(main_actor) Gcursector= ((Life *)main_actor->life)->sector; /* apart doen ivm delete */ a= Gtotlife; while(a--) { ob= Glifebuf[a]; if(ob->life) { lf= ob->life; if(lf->dflag & LF_TEMPLIFE) { if(lf->timer<=0 || lf->sector==0) { /* we let them exist for one gamecycle, for sensors */ if(ob->lay == (1<<21)) del_dupli_life(ob); else ob->lay= (1<<21); } } } } } void update_realtime_textures() { /* wordt aangeroepen met constante */ Image *ima; int a; ima= G.main->image.first; while(ima) { if(ima->tpageflag & IMA_TWINANIM) { if(ima->twend >= ima->xrep*ima->yrep) ima->twend= ima->xrep*ima->yrep-1; /* check: zit de bindcode niet het array? Vrijgeven. (nog doen) */ ima->lastframe++; if(ima->lastframe > ima->twend) ima->lastframe= ima->twsta; } ima= ima->id.next; } } void drawlife(Object *ob, int dt, uint col) { Life *lf; Object *obedit; float vec[3]; int flag; lf= ob->life; if(lf->sector==NULL) return; if(dtflag & OB_DYNAMIC) { if(lf->floor) { float tmat[4][4]; getmatrix(tmat); cpack(0); glEnable(GL_POLYGON_STIPPLE); loadmatrix(G.vd->viewmat); glTranslatef(ob->obmat[3][0], ob->obmat[3][1], ob->obmat[3][2]); /* floorloc is t.o.v. oldloc!!! */ vec[0]= lf->floorloc[0]; vec[1]= lf->floorloc[1]; vec[2]= lf->floorloc[2]; vec[2]+= 0.2*lf->axsize; glBegin(GL_POLYGON); vec[0]-= 0.4*lf->axsize; vec[1]-= 0.4*lf->axsize; glVertex3fv(vec); vec[0]+= 0.8*lf->axsize; glVertex3fv(vec); vec[1]+= 0.8*lf->axsize; glVertex3fv(vec); vec[0]-= 0.8*lf->axsize; glVertex3fv(vec); glEnd(); glDisable(GL_POLYGON_STIPPLE); cpack(col); loadmatrix(tmat); } } } if(lf->collision) { cpack(0xFFFFFF); } if(lf->dflag & LF_NO_DAMAGE) cpack(0x00FF00); if(ob->type==OB_MESH) { if(ob==G.obedit) drawmeshwire(ob); else if(dt==OB_BOUNDBOX) draw_bounding_volume(ob); else if(dt==OB_WIRE) drawmeshwire(ob); else if(dt==OB_SOLID) drawDispList(ob, dt); else { draw_tface_mesh(ob, ob->data, dt); } } else if(G.vd->drawtype<=OB_SHADED) drawaxes( lf->axsize); if(dtflag & OB_DYNAMIC) { float tmat[4][4], imat[4][4]; vec[0]= vec[1]= vec[2]= 0.0; getmatrix(tmat); Mat4Invert(imat, tmat); setlinestyle(2); drawcircball(vec, lf->axsize, imat); setlinestyle(0); } } } void drawsector(Object *ob, int dt, uint col) /* col: restore van ghost */ { Mesh *me; me= ob->data; if(ob==G.obedit) drawmeshwire(ob); else if(dt==OB_BOUNDBOX) draw_bounding_volume(ob); else if(dt==OB_WIRE) drawmeshwire(ob); else if(dt==OB_SOLID) drawDispList(ob, dt); else { draw_tface_mesh(ob, me, dt); } } void drawview3d_simul(int make_disp) { Object *ob, *obs; Life *lf, *lfl; Material *ma; uint col; int b, a, flag; /* hier doen: anders wordt in header getekend */ areawinset(curarea->win); setwinmatrixview3d(0); /* 0= geen pick rect */ /* don't call setviewmatrix3d() because of where_is_object (slow cam goes wrong) */ if(G.vd->persp>=2 && G.vd->camera) { obmat_to_viewmat(G.vd->camera); } else { QuatToMat4(G.vd->viewquat, G.vd->viewmat); if(G.vd->persp==1) G.vd->viewmat[3][2]-= G.vd->dist; i_translate(G.vd->ofs[0], G.vd->ofs[1], G.vd->ofs[2], G.vd->viewmat); } Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat); Mat4Invert(G.vd->persinv, G.vd->persmat); Mat4Invert(G.vd->viewinv, G.vd->viewmat); if(G.vd->drawtype >= OB_SOLID) { G.zbuf= TRUE; glEnable(GL_DEPTH_TEST); if(G.scene->world) glClearColor(G.scene->world->horr, G.scene->world->horg, G.scene->world->horb, 0.0); else glClearColor(0.4375, 0.4375, 0.4375, 0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } else { glClearColor(0.4375, 0.4375, 0.4375, 0.0); glClear(GL_COLOR_BUFFER_BIT); } /* do this within the drawloop, fog ON doesnt work fine with drawing the interface (linux) */ if(G.vd->drawtype > OB_WIRE) { if(G.scene->world && (G.scene->world->mode & WO_MIST)) { float params[5]; glFogi(GL_FOG_MODE, GL_LINEAR); glFogf(GL_FOG_DENSITY, 0.1); glFogf(GL_FOG_START, G.scene->world->miststa); glFogf(GL_FOG_END, G.scene->world->miststa+G.scene->world->mistdist); params[0]= G.scene->world->horr; params[1]= G.scene->world->horg; params[2]= G.scene->world->horb; params[3]= 0.0; glFogfv(GL_FOG_COLOR, params); glEnable(GL_FOG); } } loadmatrix(G.vd->viewmat); /* extern: camera tekenen */ if(G.vd->persp!=2) { ob= G.scene->camera; if(ob && (ob->lay & G.vd->lay)) { cpack(0x0); multmatrix(ob->obmat); drawcamera(ob); loadmatrix(G.vd->viewmat); } } a= Gtotsect; while(a-- > 0) { ob= Gsectorbuf[a]; multmatrix(ob->obmat); cpack(0x0); drawsector(ob, MIN2(ob->dt, G.vd->drawtype), 0); loadmatrix(G.vd->viewmat); if(ob->lbuf.tot) { for(b=0; blbuf.tot; b++) { obs= ob->lbuf.ob[b]; if(obs->lay & G.vd->lay) { lf= obs->life; if(lf==NULL || (lf->flag & OB_DYNAMIC) || (lf->dflag & LF_DONTDRAW)); else { multmatrix(obs->obmat); col= 0; if( ma=lf->contact) col= rgb_to_cpack(ma->r, ma->g, ma->b); if( lf->flag1 & LF_DRAWNEAR) col= (0xF0A020); drawlife(obs, MIN2(obs->dt, G.vd->drawtype), col); if(G.vd->drawtype!=OB_TEXTURE) { if(obs->dtx & OB_DRAWNAME) drawname(obs); if(obs->dtx & OB_AXIS) drawaxes( lf->axsize); } loadmatrix(G.vd->viewmat); } } } } } a= Gtotlife; while(a--) { ob= Glifebuf[a]; if( (ob->gameflag & OB_LIFE) && (ob->lay & G.vd->lay)) { lf= ob->life; if(lf->dflag & LF_DONTDRAW); else { multmatrix(ob->obmat); if(G.vd->drawtype!=OB_TEXTURE) { col= 0; if( ma=lf->contact) col= rgb_to_cpack(ma->r, ma->g, ma->b); if( lf->flag1 & LF_DRAWNEAR) col= (0xF0A020); drawlife(ob, MIN2(ob->dt, G.vd->drawtype), col); if(ob->dtx & OB_DRAWNAME) drawname(ob); if(ob->dtx & OB_AXIS) drawaxes( lf->axsize); } else drawlife(ob, MIN2(ob->dt, G.vd->drawtype), 0); loadmatrix(G.vd->viewmat); } for(b=0; blinks.tot; b++) { ob= lf->links.ob[b]; if(ob->gameflag & OB_LIFE) { if(ob->lay & G.vd->lay) { lfl= ob->life; if(lfl->dflag & LF_DONTDRAW); else { multmatrix(ob->obmat); if(G.vd->drawtype!=OB_TEXTURE) { col= 0; if( ma=lfl->contact) col= rgb_to_cpack(ma->r, ma->g, ma->b); if( lfl->flag & LF_DRAWNEAR) col= (0xF0A020); drawlife(ob, MIN2(ob->dt, G.vd->drawtype), col); if(ob->dtx & OB_DRAWNAME) drawname(ob); if(ob->dtx & OB_AXIS) drawaxes( lfl->axsize); } else drawlife(ob, MIN2(ob->dt, G.vd->drawtype), 0); loadmatrix(G.vd->viewmat); } } } } } } draw_tface_meshes_tra(); if(G.zbuf) { G.zbuf= FALSE; glDisable(GL_DEPTH_TEST); } glDisable(GL_FOG); /* life.c */ draw_gamedebug_info(); curarea->win_swap= WIN_BACK_OK; } 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; int time, ltime, dtime; int a, b; ushort event=0; short val; /* per life: sector test * sensors * damage * update dynamics <- -> collision detectie * */ if(G.scene->camera==0) { error("no camera"); G.simulf= G_QUIT; return; } if(G.scene->camera->type!=OB_CAMERA) { error("no correct camera"); G.simulf= G_QUIT; return; } /* doet ook mesh_isdone flag */ init_sectors(); init_lifes(); init_devs(); update_time(); tottime= 0.0; swaptime= speed_to_swaptime(G.animspeed); #ifdef __WIN32 ltime = times(&voidbuf)/10; #else #ifdef __BeOS ltime= (glut_system_time())/10000; #else ltime = times(&voidbuf); #endif #endif dtime= 4; /* vantevoren invullen (1/25 sec) */ sectcount=spherecount=cylcount=facecount=matcount= 0; while(TRUE) { /* dynamics lus: stapjes van 0.02 seconden */ Gdfrao= Gdfra; G.fields=0; set_dtime(dtime); /* global in object.c, ook voor cameranet */ dbswaptime= dtime; if(dtime>25) dtime= 25; while(dtime>0) { Gdfra++; Gdfras= Gdfra; event= pad_read(); if(event==SPACEKEY || event==ESCKEY) { G.simulf |= G_QUIT; break; } update_lifes(); if(Gdfra & 1) update_realtime_textures(); dtime -= 2; G.fields++; sectcount++; } build_sectorlist(G.scene->camera); drawview3d_simul(0); screen_swapbuffers(); /* tijdberekening: in hondersten van seconde */ while(dtime<2) { #ifdef __WIN32 time = times(&voidbuf)/10; #else #ifdef __BeOS time= (glut_system_time())/10000; #else time = times(&voidbuf); #endif #endif dtime+= (time - ltime); ltime= time; if(dtime<2) usleep(1); } /* viewrotate */ if(get_mbut() & M_MOUSE) { if(U.flag & VIEWMOVE) { if(G.qual & LR_SHIFTKEY) viewmove(0); else if(G.qual & LR_CTRLKEY) viewmove(2); else viewmove(1); } else { if(G.qual & LR_SHIFTKEY) viewmove(1); else if(G.qual & LR_CTRLKEY) viewmove(2); else viewmove(0); } } if(G.simulf & (G_RESTART|G_QUIT|G_SETSCENE|G_LOADFILE)) break; } end_sectors(); end_lifes(event!=SPACEKEY); set_dtime(2); /* restore */ G.qual= 0; if(G.simulf & G_LOADFILE) { char str[64]; /* two levels of load events. first we must make sure we leave the simul, then we can add to the queue */ sprintf(str, "%s.blend", simul_load_str); add_readfile_event(str); } /* PRINT4(d, d, d, d, sectcount, facecount, cylcount, spherecount); */ /* PRINT(d, matcount); */ } void sector_simulate() { Scene *lastscene; Object *lastcamera; if(G.vd==0) return; lastscene= G.scene; lastcamera= G.vd->camera; G.f |= G_SIMULATION; G.simulf= 0; waitcursor(1); while(TRUE) { sector_go(); if(G.simulf & G_LOADFILE) break; if(G.simulf & G_SETSCENE) { extern Scene *actuator_scene; /* life.c */ if(actuator_scene) set_scene(actuator_scene); } if(G.simulf & G_RESTART); if(G.simulf & G_QUIT) { reset_slowparents(); /* editobject.c */ break; } G.simulf= 0; } /* this in fact should be solved for SPACE... */ if(G.scene!=lastscene) set_scene(lastscene); G.vd->camera= lastcamera; G.f &= ~G_SIMULATION; allqueue(REDRAWVIEW3D, 0); allqueue(REDRAWBUTSALL, 0); waitcursor(0); }