/** * $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) 1997 by Ton Roosendaal, Frank van Beek and Joeri Kassenaar. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ /** * $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) 1997 by Ton Roosendaal, Frank van Beek and Joeri Kassenaar. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ /* * psector.c * */ #include "psxblend.h" #include "psxgraph.h" // 81= 4096/50 #define DTIME 81 // als boven: met correctie voor graden en 14 bits #define RDTIME (110) #define DYNAFIX 16384 #define SECTORFIX 4096 #define GLOBALFIX 1024 #define GLOBALSHIFT 2 extern short debuginfo; // main01.c extern int old_sp; // main01.c // exports void del_dupli_life(pObject *ob); int (*intersect_func)(); pObject *main_actor; typedef struct Snijp { int labda, minlabda, inpspeed; int radius, radiusq, slen; /* slen: lengte speed */ pDFace *face; pMaterial *ma; MATRIX *obmat; /* als hier iets staat: ook doen! */ short no[3]; /* als flag==1, staat hier normaal */ short speedn[3]; /* genormaliseerd */ ushort ocx, ocy, ocz; /* van de 'ray' of de life */ char flag; /* 0: vlak gesneden, 1: cylinder/sphere */ char lay; } Snijp; void *dupallocN(void *poin) { BHead *bhead; void *new=0; bhead= poin; bhead--; if(bhead->code==DATA || bhead->code==ID_OB || bhead->code==ID_LF) { new= mallocN(bhead->len, "dupallocN"); memcpy(new, poin, bhead->len); } else printf("illegal dupalloc\n"); return new; } void ApplyMatrix12(MATRIX *mat, int *old, int *new) { /* in 12 bits, uit 12 bits */ // dit is sneller: zie main01.c if((mat->flag & MAT_FAST)) { if(mat->flag==MAT_ONE) { new[0]= old[0] + (mat->t[0]<t[1]<flag==MAT_270) { new[0]= -old[1] + (mat->t[0]<t[1]<flag==MAT_180) { new[0]= -old[0] + (mat->t[0]<t[1]<flag==MAT_90) { new[0]= old[1] + (mat->t[0]<t[1]<flag); new[2]= old[2] + (mat->t[2]<t[0]<t[1]<t[2]<t[0])<t[1])<t[2])<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, short *size, int *vec, short 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(pLBuf *lbuf, pObject *ob) { if(lbuf->max==0) { lbuf->ob= callocN(4*LBUFSTEP, "firstlbuf"); lbuf->max= LBUFSTEP; lbuf->tot= 1; lbuf->ob[0]= ob; } else { pObject **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(pLBuf *lbuf) { if(lbuf->ob) freeN(lbuf->ob); lbuf->ob= 0; lbuf->max= lbuf->tot= 0; } void del_from_lbuf(pLBuf *lbuf, pObject *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(pMesh *me, Snijp *sn, int *oldloc, short *speed) { int vec[3]; short *dvec; ushort *size; short a, b, min[3], max[3]; /* optimalisering sphere en cyl */ VECCOPY(sn->speedn, speed); sn->slen= Normalises(sn->speedn); sn->ocx= 0; /* voldoende om hierop te testen */ /* ivm. returns wel pas op 't eind berekenen */ //sn->ocx= 0xFFFF; //sn->ocy= 0xFFFF; //sn->ocz= 0xFFFF; //return; if(me==0 || me->oc==0 || sn->slen==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) { a= ((vec[0]-sn->radius)<<4)/size[0]; b= ((vec[0]-sn->radius+speed[0])<<4)/size[0]; min[0]= MIN2(a, b); a= ((vec[0]+sn->radius)<<4)/size[0]; b= ((vec[0]+sn->radius+speed[0])<<4)/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) { a= ((vec[1]-sn->radius)<<4)/size[1]; b= ((vec[1]-sn->radius+speed[1])<<4)/size[1]; min[1]= MIN2(a, b); a= ((vec[1]+sn->radius)<<4)/size[1]; b= ((vec[1]+sn->radius+speed[1])<<4)/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) { a= ((vec[2]-sn->radius)<<4)/size[2]; b= ((vec[2]-sn->radius+speed[2])<<4)/size[2]; min[2]= MIN2(a, b); a= ((vec[2]+sn->radius)<<4)/size[2]; b= ((vec[2]+sn->radius+speed[2])<<4)/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(pSector *se, int *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(pSector *se, int *vec, int *local) /* vec is globale co */ { if(se->ob==0) return 0; ApplyMatrix12(&se->ob->imat, vec, local); if( sector_cliptest(se, local)==0 ) return 1; return 0; } pSector *find_sector(int *vec, int *local) /* algemene find: slow */ { pBase *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(pObject *ob) { static int outcount= 0; pLife *lf; pLBuf *lb; pSector *se; pPortal *po; short 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); if(debuginfo) printf("out, but found one\n"); outcount= 0; return; } /* helaas: */ if(lf->dflag & LF_TEMPLIFE) { lf->timer= 0; } else { if(outcount==0) printf("out\n"); outcount++; if(outcount>100) { G.f |= G_RESTART; printf("out: restart\n"); outcount= 0; } } } } if(lf->sector==0) { lf->sector= find_sector(lf->loc, lf->loc1); if( (lf->dflag & LF_TEMPLIFE)==0) { ; /* zie sector.c */ } } } void mainactor_in_sector_test() /* zet G.cursector */ { pPortal *po; int vec[3], local[3]; int b, out; if(main_actor==0) return; /* van 10 naar 12 bits */ vec[0]= main_actor->obmat.t[0]<obmat.t[1]<obmat.t[2]<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 */ start_mainmovie(G.cursector->name); return; } } po++; } /* helaas */ G.cursector= 0; } } if(G.cursector==0) { G.cursector= find_sector(vec, local); if(G.cursector) { evaluate_camera_network(0, -1); /* init */ start_mainmovie(G.cursector->name); } } } void normal_rot_inv(MATRIX *mat, MATRIX *inv, SVECTOR *no) { VECTOR vec; int x, y, z; // KOLOMMEN ANDERS DAN ANDERS!!! x= (no->vx*mat->m[0][0] + no->vy*mat->m[0][1] + no->vz*mat->m[0][2])>>12; y= (no->vx*mat->m[1][0] + no->vy*mat->m[1][1] + no->vz*mat->m[1][2])>>12; z= (no->vx*mat->m[2][0] + no->vy*mat->m[2][1] + no->vz*mat->m[2][2])>>12; no->vx= (x*inv->m[0][0] + y*inv->m[0][1] + z*inv->m[0][2])>>12; no->vy= (x*inv->m[1][0] + y*inv->m[1][1] + z*inv->m[1][2])>>12; no->vz= (x*inv->m[2][0] + y*inv->m[2][1] + z*inv->m[2][2])>>12; // geen normalise: inpspeed bevat scale-informatie // VectorNormalS(&vec, no); } /* ********************** DYNA ************************* */ #define TOLER 80 #define UNSURE (320<<10) #define UNSURE1 (128<<8) /* labdacor labda */ /* -----x---------x------- */ /* . . */ /* geval 1 -----.----> . */ /* geval 2 --.---------.--> */ /* geval 3 . ----.------> */ /* geval 4 . -----> . */ int intersect_dface(pDFace *dface, Snijp *sn, int *oldloc, short *speed) { int labda, labdacor, ndist, s, t, inploc, inpspeed; int cox=0, coy=1; int a, b; /* 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); // test 1: mag je delen? if(ndist>=0 || (ndist+UNSURE)<=inpspeed) return 0; labdacor= ( (ndist+UNSURE)<<4 )/(inpspeed>>10); labda= (ndist<<4)/(inpspeed>>10); // debug test oftie nog leeft // if(G.qual & 1) printf("fa %x lab %d min %d\n", dface, labdacor, sn->minlabda); /* dit is een soort interval-wiskunde */ // deze twee regels zijn samen nodig: geval 1 afvangen if(labdacor<=sn->minlabda) { if(labda<=sn->minlabda) return 0; } if(labdacor>=sn->labda) { if(labda>=sn->labda) return 0; // voorkomt hobbelen } if(dface->proj==1) coy= 2; else if(dface->proj==2) { cox= 1; coy= 2; } s= oldloc[cox] + S14MUL(labda, speed[cox]); t= oldloc[coy] + S14MUL(labda, speed[coy]); if( (dface->v2[cox] - s)*(dface->v2[coy] - dface->v1[coy]) < (dface->v2[coy] - t)*(dface->v2[cox] - dface->v1[cox]) -UNSURE1) return 0; if( (dface->v3[cox] - s)*(dface->v3[coy] - dface->v2[coy]) < (dface->v3[coy] - t)*(dface->v3[cox] - dface->v2[cox]) -UNSURE1) 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]) -UNSURE1) return 0; } else { if( (dface->v4[cox] - s)*(dface->v4[coy] - dface->v3[coy]) < (dface->v4[coy] - t)*(dface->v4[cox] - dface->v3[cox]) -UNSURE1) return 0; if( (dface->v1[cox] - s)*(dface->v1[coy] - dface->v4[coy]) < (dface->v1[coy] - t)*(dface->v1[cox] - dface->v4[cox]) -UNSURE1) return 0; } sn->labda= labdacor; sn->inpspeed= (inpspeed)>>12; sn->face= dface; sn->flag= 0; return 1; } return 0; } int sphere_sphere_intersect(int *v1, Snijp *sn, int *oldloc, short *speed) { int labda, labdacor, len, bsq, u, disc, rc[3]; int 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])>>12; u= rc[0]*rc[0] + rc[1]*rc[1] + rc[2]*rc[2] - 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; /* PATCH!!! */ if(labdacor<0) labdacor/= 2; /* 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) ; /* corrigeren: v1[3]= axsize */ disc= (v1[3]<<12)/radius; sn->no[0]= SMUL(sn->no[0], disc); sn->no[1]= SMUL(sn->no[1], disc); sn->no[2]= SMUL(sn->no[2], disc); sn->labda= labdacor; /* inpspeed op lengte brengen: twee keer radius!!! (inpspeed wordt weer met normaal vermenigvuldigd)*/ /* inspeed: 16 bits */ radiusq= v1[3]*v1[3]; sn->inpspeed= ( (sn->no[0]*speed[0] + sn->no[1]*speed[1] + sn->no[2]*speed[2])<<4 )/(radiusq>>12); sn->flag= 2; return 1; } int vertex_sphere_intersect(short *v1, Snijp *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; /* 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) ; 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); sn->flag= 1; return 1; } int cylinder_edge_intersect(short *base, short *v2, Snijp *sn, int *oldloc, short *speed) { int osp, rdd, s, t, dist, len, len2, labda, labdacor, rc[3]; short axis[3], n[3], o[3]; 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 ); if( dist>=sn->radius ) return 0; 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); labdacor= (t-s); labda= (t+s); /* 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; return 1; } int intersect_dface_cyl(pDFace *dface, Snijp *sn, int *oldloc, short *speed) { short *v1, *v2, *v3, *v4; int labda, labdacor, ndist, ndistr, s, t, inploc, inpspeed; int out; short cox=0, coy=1, ok, ed, cytest; int a, b; /* 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); ndistr= ndist+(sn->radius<<14); // test 1: mag je delen? if(ndist>=0 || (ndistr)<=inpspeed) return 0; labda= (ndist<<4)/(inpspeed>>10); /* voor s-t */ labdacor= (ndistr<<4 )/(inpspeed>>10); // debug test oftie nog leeft // if(G.qual & 1) printf("fa %x lab %d min %d\n", dface, labdacor, sn->minlabda); /* 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) { /* geen labda, wel met correctie zodat snijp binnen vlak valt */ /* dit is in feite de loodrechte projektie */ s= oldloc[cox] - S14MUL(sn->radius, dface->no[cox]); t= oldloc[coy] - S14MUL(sn->radius, dface->no[coy]); labdacor= 0; } else { /* met correctie zodat snijp binnen vlak valt */ s= oldloc[cox] + ((labdacor*speed[cox] - sn->radius*dface->no[cox])>>14); t= oldloc[coy] + ((labdacor*speed[coy] - sn->radius*dface->no[coy])>>14); } 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>>12; 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; } short intersect_dynalife(pObject *ob, pLife *lf, Snijp *sn) { pObject *obs; pLife *lfs; int mindist, loc1[4]; /* loc1 is incl axsize */ short a, b, found= 0; /* nodig voor genormaliseerde speed */ init_snijp(0, sn, lf->oldloc1, lf->speed1); if(sn->slen < 10) 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*(sn->radius+lfs->axsize); if( abs(lf->loc[0]-lf->loc[0]) > mindist ) continue; if( abs(lf->loc[1]-lf->loc[1]) > mindist ) continue; if( abs(lf->loc[2]-lf->loc[2]) > mindist ) continue; /* gebruik lokale sector coords */ ApplyMatrix12(&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= &G.defaultmaterial; 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(pSector *se, pLife *lf, Snijp *sn) { /* botst Life *lf tegen een van de props uit *se ? */ /* ook se doorgeven: portals */ pObject *ob; pLife *lfs; pDFace *dface; int oldloc2[3], loc2[3]; int a, b, found= 0; short speed2[3]; 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 */ ApplyMatrix12(&ob->imat, lf->loc, loc2); ApplyMatrix12(&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); lf->collision= ob; lfs->collision= ob; /* alleen waar/nietwaar */ found= 1; } dface++; } } } } } return found; } void force_from_prop(pLife *lf, Snijp *sn) /* maar 1 tegelijk!!! */ { pObject *ob; pLife *lfs; pSector *se; pDFace *dface; int fac, oldloc2[3], loc2[3]; short speed2[3]; short a, b, found, *no; 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; sn->labda= DYNAFIX; found= 0; /* werken aan de hand van de 'virtuele' vorige positie van life */ ApplyMatrix12(&ob->imat, lf->loc, loc2); ApplyMatrix12(&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]+= S14MUL(sn->labda, speed2[0]); oldloc2[1]+= S14MUL(sn->labda, speed2[1]); oldloc2[2]+= S14MUL(sn->labda, speed2[2]); // nieuwe speed, hier refl.demping: -1.0: parrallel aan vlak, -2.0: zuivere botsing // fac wordt zo 12 bits fac= S14MUL( -4096-sn->face->ma->ref, 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]= S14MUL(fac, no[0]); speed2[1]= S14MUL(fac, no[1]); speed2[2]= S14MUL(fac, no[2]); /* de virtuele oldloc */ oldloc2[0]-= S14MUL(sn->labda, speed2[0]); oldloc2[1]-= S14MUL(sn->labda, speed2[1]); oldloc2[2]-= S14MUL(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]; ApplyMatrix12(&ob->obmat, loc2, lf->loc); ApplyMatrixSV(&ob->obmat, (SVECTOR *)speed2, (SVECTOR *)lf->speed); /* oldloc niet meer nodig */ return; } } } } } } } int test_visibility(int *lookat, int *from, pLife *lf, pSector *se) { Snijp sn; pMesh *me; pDFace *dface; int fac, loc1[3], oldloc1[3]; short speed1[3]; short a, found; // lookat en from zijn 12 bits int if(se==0 || se->dynamesh==0) return 0; /* transformeren naar lokale sector coords en intersecten */ ApplyMatrix12(&se->ob->imat, from, loc1); ApplyMatrix12(&se->ob->imat, lookat, oldloc1); /* hier oppassen met shorts! */ fac= loc1[0]-oldloc1[0]; speed1[0]= CLAMPIS(fac, -32767, 32767); fac= loc1[1]-oldloc1[1]; speed1[1]= CLAMPIS(fac, -32767, 32767); fac= loc1[2]-oldloc1[2]; speed1[2]= CLAMPIS(fac, -32767, 32767); me= se->dynamesh; sn.minlabda= sn.radius= 0; /* radius op nul voor init_snijp */ sn.labda= DYNAFIX; 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])>>14; oldloc1[1]+= (sn.labda*speed1[1])>>14; oldloc1[2]+= (sn.labda*speed1[2])>>14; /* reflectie berekenen: fac en no zijn 14 bits, speed 12 bits */ fac= -sn.inpspeed; // 2* is hieronder gecompenseerd speed1[0]+= (fac*sn.face->no[0])>>15; speed1[1]+= (fac*sn.face->no[1])>>15; speed1[2]+= (fac*sn.face->no[2])>>15; fac= (DYNAFIX - sn.labda); /* endloc */ oldloc1[0]+= (fac*speed1[0])>>14; oldloc1[1]+= (fac*speed1[1])>>14; oldloc1[2]+= (fac*speed1[2])>>14; /* blenden */ loc1[0]= (15*loc1[0] + oldloc1[0])>>4; loc1[1]= (15*loc1[1] + oldloc1[1])>>4; loc1[2]= (15*loc1[2] + oldloc1[2])>>4; ApplyMatrix12(&se->ob->obmat, loc1, from); return 1; } } return 0; } void collision_detect(pObject *ob, pLife *lf) { /* een soort reetrees routine: zoek dichtstbijzijnde snijpunt */ /* werken met de lokale life co's */ Snijp sn; pMesh *me; pPortal *po; pSector *se; pDFace *dface, *from=0; int *oldloc1, fac, len; short a, b, found=1, transback=0, colcount=0; short *speed1, *no; lf->collision= 0; se= lf->sector; me= se->dynamesh; if(me==0) return; sn.minlabda= 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= TOLER; /* voor octree */ intersect_func= intersect_dface; } /* beetje speedup */ oldloc1= lf->oldloc1; speed1= lf->speed1; while(found) { sn.labda= DYNAFIX; 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(lf->sector, 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)) { int oldloc2[3], loc2[3]; short 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 */ ApplyMatrix12(&po->ob->imat, lf->loc, loc2); ApplyMatrix12(&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); lf->collision= po->ob; found= 1; } } dface++; } } } po++; } if(found) { colcount++; transback= 1; from= sn.face; /* de bots loc */ lf->colloc[0]= oldloc1[0]+ S14MUL(sn.labda, speed1[0]); lf->colloc[1]= oldloc1[1]+ S14MUL(sn.labda, speed1[1]); lf->colloc[2]= oldloc1[2]+ S14MUL(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 wordt 12 bits fac= S14MUL( -4096-sn.ma->ref, sn.inpspeed); /* pas op: als sn.obmat (in andere object) de sn.face->no[] roteren */ if(sn.obmat) { SVECTOR nor; nor.vx= no[0]; nor.vy= no[1]; nor.vz= no[2]; normal_rot_inv(sn.obmat, &lf->sector->ob->imat, &nor); speed1[0]+= S14MUL(fac, nor.vx); speed1[1]+= S14MUL(fac, nor.vy); speed1[2]+= S14MUL(fac, nor.vz); } else { speed1[0]+= S14MUL(fac, no[0]); speed1[1]+= S14MUL(fac, no[1]); speed1[2]+= S14MUL(fac, no[2]); } /* de virtuele oldloc */ oldloc1[0]= lf->colloc[0] - S14MUL(sn.labda, speed1[0]); oldloc1[1]= lf->colloc[1] - S14MUL(sn.labda, speed1[1]); oldloc1[2]= lf->colloc[2] - S14MUL(sn.labda, speed1[2]); if(colcount>3) if( sn.labda <= sn.minlabda) found= 0; if(sn.minlabda>=DYNAFIX) 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); // if(colcount) { // a= abs(sn.inpspeed>>5); // if(a>5) play_sample(METALBUMP, 16, 0, a,a); // } } /* ******************* hele fh spul: *********************** */ #define FH_SECTOR 1 #define FH_PROP 2 int intersect_fh(pDFace *dface, int *oldloc, Snijp *sn) { int s, t, tlab, inploc, inpspeed, ndist; /* 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; inpspeed= -(dface->no[2]<<12); /* 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); // test 1: mag je delen? if(ndist>=0 || (ndist)< (inpspeed<<5) ) return 0; // labda is hier 12 bits!!! tlab= (ndist<<2)/(inpspeed>>10); if(tlab<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]) -UNSURE1) return 0; if( (dface->v3[0] - s)*(dface->v3[1] - dface->v2[1]) < (dface->v3[1] - t)*(dface->v3[0] - dface->v2[0]) -UNSURE1) 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]) -UNSURE1) return 0; } else { if( (dface->v4[0] - s)*(dface->v4[1] - dface->v3[1]) < (dface->v4[1] - t)*(dface->v4[0] - dface->v3[0]) -UNSURE1) return 0; if( (dface->v1[0] - s)*(dface->v1[1] - dface->v4[1]) < (dface->v1[1] - t)*(dface->v1[0] - dface->v4[0]) -UNSURE1) return 0; } sn->labda= tlab; sn->face= dface; if(tlab<= dface->ma->fh_dist) { sn->flag= FH_SECTOR; return 1; } return 0; } return 0; } int intersect_fh_rot(pDFace *dface, int *oldloc, Snijp *sn, short *speed) { int s, t, inploc, inpspeed, ndist, tlab; short cox=0, coy=1; /* speed: 0, 0, -1 (maar dan geroteerd) */ /* 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]; ndist= (dface->dist - inploc); // test 1: mag je delen? if(ndist>=0 || (ndist)<(inpspeed<<5)) return 0; // labda is hier 12 bits!!! tlab= (ndist<<2)/(inpspeed>>10); if(tlab<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])>>12); t= oldloc[coy] + ((tlab*speed[coy])>>12); if( (dface->v2[cox] - s)*(dface->v2[coy] - dface->v1[coy]) < (dface->v2[coy] - t)*(dface->v2[cox] - dface->v1[cox]) -UNSURE1) return 0; if( (dface->v3[cox] - s)*(dface->v3[coy] - dface->v2[coy]) < (dface->v3[coy] - t)*(dface->v3[cox] - dface->v2[cox]) -UNSURE1) 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]) -UNSURE1) return 0; } else { if( (dface->v4[cox] - s)*(dface->v4[coy] - dface->v3[coy]) < (dface->v4[coy] - t)*(dface->v4[cox] - dface->v3[cox]) -UNSURE1) return 0; if( (dface->v1[cox] - s)*(dface->v1[coy] - dface->v4[coy]) < (dface->v1[coy] - t)*(dface->v1[cox] - dface->v4[cox]) -UNSURE1) return 0; } sn->labda= tlab; sn->face= dface; if(tlab<= dface->ma->fh_dist) { sn->flag= FH_PROP; } return 1; } return 0; } void update_Fheight(pLife *lf, short *force) { /* alleen anti-zwaartekracht: pas op met rotaties. Normaal vlak= F_afstoot */ pLife *lfs; pDFace *dface; pMaterial *ma; pSector *se; pObject *propob; Snijp sn; int alpha, fac, loc2[3], oldloc2[3], loc1[3]; short a, b, speed[3], no[3], *mat; // force is 14 bits lf->contact= 0; lf->floor= 0; /* is er wel 'n Fh vlak in mesh ? */ if(lf->sector->dynamesh==0) return; sn.labda= 32*4096; sn.face= 0; sn.flag= 0; sn.radius= TOLER; mat= lf->sector->ob->obmat.m[0]; speed[0]=speed[1]= 0; speed[2]= -7*4096; init_snijp(lf->sector->dynamesh, &sn, lf->loc1, speed); dface= lf->sector->dynamesh->dface; a= lf->sector->dynamesh->totface; while(a--) { if(dface->ma->fh_dist) { /* 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 */ ApplyMatrix12(&propob->imat, lf->loc, loc1); dface= lfs->dynamesh->dface; a= lfs->dynamesh->totface; /* psx matrix ANDERSOM!!! */ speed[0]= -propob->obmat.m[0][2]<<3; speed[1]= -propob->obmat.m[1][2]<<3; speed[2]= -propob->obmat.m[2][2]<<3; init_snijp(lfs->dynamesh, &sn, loc1, speed); speed[0]= propob->obmat.m[0][2]; speed[1]= propob->obmat.m[1][2]; speed[2]= propob->obmat.m[2][2]; while(a--) { if(dface->ma->fh_dist) { /* loodrechte projektie */ if( intersect_fh_rot(dface, loc1, &sn, speed) ) { /* normaal roteren volgens life */ mat= propob->obmat.m[0]; if(sn.flag == FH_PROP) break; } } dface++; } if(sn.flag == FH_PROP) break; } } } if(sn.face) { /* psx matrix ANDERSOM!!! */ 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[1] + sn.face->no[2]*mat[2])>>14; no[1]= (sn.face->no[0]*mat[3] + sn.face->no[1]*mat[4] + sn.face->no[2]*mat[5])>>14; no[2]= (sn.face->no[0]*mat[6] + sn.face->no[1]*mat[7] + sn.face->no[2]*mat[8])>>14; } else { /* alleen loodrecht */ no[0]= mat[2]; no[1]= mat[5]; no[2]= mat[8]; } /* floor locatie voor schaduw: altijd relatief! */ lf->floorloc[0]= - (sn.labda*no[0])>>14; /* naar 10 bits shiften */ lf->floorloc[1]= - (sn.labda*no[1])>>14; lf->floorloc[2]= - (sn.labda*no[2])>>14; lf->floor= sn.face; if(sn.flag) { ma= sn.face->ma; lf->contact= ma; /* labda==0.0: exact op afstand dist */ sn.labda= 4096 - (sn.labda<<12)/ma->fh_dist; sn.labda= SMUL(sn.labda, sn.face->ma->fh_int); /* force 14 bits */ force[0]+= S10MUL(sn.labda, no[0]); force[1]+= S10MUL(sn.labda, no[1]); force[2]+= S10MUL(sn.labda, no[2]); /* extra fh friction, alleen in richting normaal */ // no is hier 12 bits! alpha= (lf->speed[0]*no[0] + lf->speed[1]*no[1] + lf->speed[2]*no[2])>>12; alpha= SMUL(alpha, ma->fh_frict); lf->speed[0] -= S12MUL(alpha, no[0]); lf->speed[1] -= S12MUL(alpha, no[1]); lf->speed[2] -= S12MUL(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 */ ApplyMatrix12(&propob->imat, lf->loc, loc2); ApplyMatrix12(&lfs->oldimat, lf->loc, oldloc2); speed[0]= oldloc2[0]-loc2[0]; speed[1]= oldloc2[1]-loc2[1]; speed[2]= oldloc2[2]-loc2[2]; /* terug transformeren: mat3! */ ApplyMatrixSV(&propob->obmat, (SVECTOR *)speed, (SVECTOR *)no); /* dit is de 'stilstaande' speed */ fac= SMUL(ma->fh_xyfrict, lf->frictfac); alpha= 4096 - fac; lf->speed[0]= (alpha*lf->speed[0] + fac*no[0])>>12; lf->speed[1]= (alpha*lf->speed[1] + fac*no[1])>>12; lf->speed[2]= (alpha*lf->speed[2] + fac*no[2])>>12; } else { alpha= 4096 - SMUL(lf->frictfac, ma->fh_xyfrict); // niet shiften, voorkom driften! lf->speed[0]= (alpha*lf->speed[0])/4096; lf->speed[1]= (alpha*lf->speed[1])/4096; } } } } // ALLE globale coords 10 BITS // alle texmesh coords 10 bits // FIXPOINT VARS en GTE 12 bits, // SNELHEID 12 bits, lf->loc, dynamesh coords 12 bits // labda en inpr en dyna->no 14 bits void update_dynamics(pObject *ob) { pLife *lf; short event, frict, speed[3], force[3], omega[3]; if(ob->type==OB_CAMERA) { where_is_object(ob); return; } lf= ob->data; if(lf->type==LF_DYNAMIC) { // contact: ook botsingscontact zetten: voor sensors // zwaartekracht // force is 14 bits force[0]= force[1]= omega[0]=omega[1]=omega[2]= 0; force[2]= - SMUL(G.scene->grav, lf->mass); /* Fh: contact */ if(lf->sector && (lf->flag & LF_DO_FH)) update_Fheight(lf, force); /* Al 2 keer een vervelnde (flipperkast) bug gehad: beide keren omdat de 'bal' geen sensors heeft, en in sensor_input iets ge-initialiseerd wordt. Zoals frictfac! */ /* toetsen */ if(lf->flag & LF_SENSORS) sensor_input(ob, lf, force, omega); // speed even 14 bits speed[0]= 4*lf->speed[0]+ force[0] ; speed[1]= 4*lf->speed[1]+ force[1] ; speed[2]= 4*lf->speed[2]+ force[2] ; lf->rotspeed[0]+= omega[0]; lf->rotspeed[1]+= omega[1]; lf->rotspeed[2]+= omega[2]; /* wrijving */ if(lf->frict) { frict= 4096 - SMUL(lf->frict, lf->frictfac); // negatieve getallen shiften niet zo goed, dus delen: (zie timer.blend) lf->speed[0]= (speed[0]*frict)/16384; lf->speed[1]= (speed[1]*frict)/16384; lf->speed[2]= (speed[2]*frict)/16384; } else { lf->speed[0]= speed[0]/4; lf->speed[1]= speed[1]/4; lf->speed[2]= speed[2]/4; // voorkom driften if(lf->speed[0]<0) lf->speed[0]+=1; if(speed[1]<0) lf->speed[1]+=1; if(speed[2]<0) lf->speed[2]+=1; } if( lf->rotfrict ) { frict= 4096 - lf->rotfrict; lf->rotspeed[0]= (lf->rotspeed[0]*frict)/4096; lf->rotspeed[1]= (lf->rotspeed[1]*frict)/4096; lf->rotspeed[2]= (lf->rotspeed[2]*frict)/4096; } 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]>>6; lf->rot[1]+= lf->rotspeed[1]>>6; lf->rot[2]+= lf->rotspeed[2]>>6; 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]>>2); ob->loc[0]= lf->loc[0]>>GLOBALSHIFT; ob->loc[1]= lf->loc[1]>>GLOBALSHIFT; ob->loc[2]= lf->loc[2]>>GLOBALSHIFT; VECCOPY(ob->rot, lf->rot); where_is_object(ob); mat_invert(&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; sensor_input(ob, lf, force, omega); lf->rotspeed[0]+= omega[0]; lf->rotspeed[1]+= omega[1]; lf->rotspeed[2]+= omega[2]; if( lf->rotfrict ) { frict= 4096 - lf->rotfrict; lf->rotspeed[0]= (lf->rotspeed[0]*frict)/4096; lf->rotspeed[1]= (lf->rotspeed[1]*frict)/4096; lf->rotspeed[2]= (lf->rotspeed[2]*frict)/4096; } lf->rot[0]+= lf->rotspeed[0]>>6; lf->rot[1]+= lf->rotspeed[1]>>6; lf->rot[2]+= lf->rotspeed[2]>>6; VECCOPY(ob->rot, lf->rot); } else { sensor_input(ob, lf, force, omega); } } /* link: altijd where_is doen */ where_is_object(ob); mat_invert(&ob->imat, &ob->obmat); } else { /* toetsen */ if(lf->flag & LF_SENSORS) { /* force en omega worden hier niet gebruikt */ if(event= sensor_input(ob, lf, force, omega)) { if(event & SN_ROTCHANGED) { VECCOPY(ob->rot, lf->rot); } lf->oldimat= ob->imat; where_is_object(ob); mat_invert(&ob->imat, &ob->obmat); } else { lf->dflag &= ~LF_DYNACHANGED; if(ob->parent) where_is_object(ob); } } lf->collision= 0; /* is mogelijk door dynalife gezet */ } } } /* ************* REALTIME ************** */ void view_to_piramat(MATRIX *piramat, int lens) { int xfac; /* far: altijd 16384 (OTSIZE) */ /* maakt viewmat piramidevormig voor eenvoudige clip */ lens= (lens<<12)/160; xfac= (lens*256)/320; piramat->m[0][0]= SMUL(xfac, piramat->m[0][0]); piramat->m[0][1]= SMUL(xfac, piramat->m[0][1]); piramat->m[0][2]= SMUL(xfac, piramat->m[0][2]); // piramat->t[0]= SMUL(xfac, piramat->t[0]); xfac>>= 2; piramat->t[0]>>= 2; piramat->t[0]= (xfac*piramat->t[0])>>8; piramat->m[1][0]= SMUL(lens, piramat->m[1][0]); piramat->m[1][1]= SMUL(lens, piramat->m[1][1]); piramat->m[1][2]= SMUL(lens, piramat->m[1][2]); // piramat->t[1]= SMUL(lens, piramat->t[1]); lens>>= 2; piramat->t[1]>>= 2; piramat->t[1]= (lens*piramat->t[1])>>8; //piramat->m[2][0]= piramat->m[2][0]; //piramat->m[2][1]= piramat->m[2][1]; //piramat->m[2][2]= piramat->m[2][2]; //piramat->t[2]= piramat->t[2]; } void init_sectors() { extern int subdiv4; pBase *base; pMesh *me; pPortal *po; pSector *se; pCamPos *capo; pLife *lf; int a; short lens; 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_def_dyna_material(); base= FIRSTBASE; while(base) { base->object->dfras= 0; if(base->object->type==OB_SECTOR) { se= base->object->data; se->ob= base->object; if(se->texmesh) se->texmesh->lastfra= 0; // is verplaatst naat readfile, ivm framebuffer_alloc /* if(se->campos) G.f |= G_NETWORK; */ // moet eigenlijk op SGI capo= se->campos; for(a=0; atotcam; a++, capo++) { where_is_object(capo->ob); object_to_viewmat(capo->ob, &capo->piramat); view_to_piramat(&capo->piramat, capo->lens); } // sectoren zijn statisch: op SGI berekend // where_is_object(base->object); // mat_invert(&base->object->imat, &base->object->obmat); } base= base->next; } // de portal->ob pointers (optim?) base= FIRSTBASE; while(base) { /* geen layertest: pointers! */ if(base->object->type==OB_SECTOR) { se= base->object->data; po= se->portals; a= se->totport; while(a--) { po->ob= po->sector->ob; po++; } } base= base->next; } if(G.f & G_NETWORK) { printf("Camera NetWork\n"); evaluate_camera_network(0, -1); /*init */ subdiv4= 0; } //else subdiv4= 1000; else subdiv4= 0; } void end_sectors() { pBase *base; pSector *se; sector_back(1); // flush en vrijgeven if(G.f & G_RESTART) return; base= FIRSTBASE; while(base) { if(base->object->type==OB_SECTOR) { se= base->object->data; if(se->lbuf.ob) { freeN(se->lbuf.ob); se->lbuf.ob= 0; se->lbuf.tot= 0; } } base= base->next; } } void add_dyna_life(pObject *ob) { 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.t); } else if(lf->type==LF_DYNAMIC && lf->collision) { VECCOPY(newob->loc, lf->colloc); newob->loc[0]= lf->colloc[0]>>GLOBALSHIFT; newob->loc[1]= lf->colloc[1]>>GLOBALSHIFT; newob->loc[2]= lf->colloc[2]>>GLOBALSHIFT; VECCOPY(newob->rot, from->rot); } else { VECCOPY(newob->loc, from->loc); VECCOPY(newob->rot, from->rot); } where_is_object(newob); add_dyna_life(newob); newob->data=lfn= dupallocN(ob->data); if(lfn->type==LF_DYNAMIC) { lfn->loc[0]= newob->loc[0]<loc[1]= newob->loc[1]<loc[2]= newob->loc[2]<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(pObject *ob) { pLife *lf; pSensor *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); 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(int *vec, short *size, MATRIX *mat, short round) { /* deze pakt de vier tetraederpunten */ /* geen abs(new.vz). zie ook SGI code */ VECTOR hoco, new; int min, max; 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.vx= vec[0] - size[0]; else hoco.vx= vec[0] + size[0]; if(ctab[1]) hoco.vy= vec[1] - size[1]; else hoco.vy= vec[1] + size[1]; if(ctab[2]) hoco.vz= vec[2] - size[2]; else hoco.vz= vec[2] + size[2]; ApplyMatrixLV(mat, &hoco, &new); new.vx+= mat->t[0]; new.vy+= mat->t[1]; new.vz+= mat->t[2]; max= new.vz; min= -max; fl= 0; if(new.vx < min) fl+= 1; else if(new.vx > max) fl+= 2; if(new.vy < min) fl+= 4; else if(new.vy > max) fl+= 8; if(new.vz < 0) fl+= 16; else if(new.vz >16384) fl+= 32; fand &= fl; if(fand==0) return 1; ctab+= 3; } return 0; } void build_sectorlist() { pSector *se; pBase *base; pPortal *po; pObject *ob; MATRIX piramat; short a, b, round, beforesect, startsect; startsect= 0; G.totsect= 0; G.maxsect= G.scene->maxdrawsector; /* uitzondering afhandelen */ if(G.cursector==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; piramat= G.viewmat; // copy view_to_piramat(&piramat, G.scene->lens); SetRotMatrix(&piramat); SetTransMatrix(&piramat); 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((int *)ob->obmat.t, po->sector->bbsize, &piramat, 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 ************** */ int swapbuffers_OT() { extern int sw_time; extern volatile char moviedone; // sectormovie.c DB *dbold; int time=0; draw_text_info(); dbold= cdb; cdb = (cdb==db)? db+1: db; /* swap double buffer ID */ DrawSync(0); /* wait for end of drawing */ dbold->dr_time= GetRCnt(RCntCNT1); VSync(0); /* wait for the next V-BLNK */ sw_time= GetRCnt(RCntCNT1); ResetRCnt(RCntCNT1); if(sw_time<=315) { VSync(0); sw_time= 628; ResetRCnt(RCntCNT1); } else if(sw_time>10000) sw_time= 10000; // na pause of menu PutDispEnv(&cdb->disp); /* update display environment */ PutDrawEnv(&cdb->draw); /* update drawing environment */ if(G.f & G_NETWORK) { sector_back(0); // movie? while( moviedone==0 ) { time= GetRCnt(RCntCNT1); if (time > 1000) break; } // voor masks if((G.f & G_PLAYMOVIE)==0) { MoveImage(&cdb->draw.clip, 640, 0); DrawSync(0); } } // oude OT DrawOTag(dbold->ot+OTSIZE-1); // int cdb->ot wordt vanaf nu gewerkt: ClearOTagR(cdb->ot, OTSIZE); // clear ordering table cdb->curpbuf= cdb->pbuf; cdb->curdbuf= cdb->dbuf; } /* ************* MAIN ************** */ void update_sector_lifes(pSector *se) { pObject *ob; pLife *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() { pObject *ob; pLife *lf; pPortal *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(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 int sw_time; // screen.c short a, b, dtime, padd; /* per life: sector test * sensors * damage * update dynamics <- -> collision detectie * */ /* hier iets doen met tijd init */ sw_time= 628; // 25 Hz init_sectors(); /* doet ook mesh_isdone flag */ init_lifes(); init_devs(); while(TRUE) { /* dynamics lus: stapjes van 0.02 seconden */ G.dfrao= G.dfra; G.fields= 0; cdb->ca_time=cdb->ga_time= GetRCnt(RCntCNT1); dtime= MIN2(sw_time, 1000); while(dtime > 0) { G.dfra++; G.dfras= G.dfra; pad_read(); if(G.qual & PADh) { if(G.qual & PADk) make_menu(); //if(G.qual== PADk+1+8 ) make_menu(); //if(G.qual & PADh) exit_func(); pad_read(); } update_lifes(); dtime-= 314; G.fields++; } if(G.fields) cdb->ga_time= (GetRCnt(RCntCNT1) - cdb->ga_time)/G.fields; if(G.f & G_NETWORK) { evaluate_camera_network(0, 0); } else { mainactor_in_sector_test(); object_to_viewmat(G.scene->camera, &G.viewmat); } build_sectorlist(); if( (G.f & G_PLAYMOVIE)==0) { //old_sp= SetSp(DCACHE_TOP-12); draw_all(); //SetSp(old_sp); } cdb->ca_time= GetRCnt(RCntCNT1) - cdb->ca_time; swapbuffers_OT(); if(G.f & (G_LOADFILE+G_RESTART+G_QUIT)) break; } end_sectors(); end_lifes(1); /* restore */ movie_exit(); }