/** * $Id:$ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** * * The contents of this file may be used under the terms of either the GNU * General Public License Version 2 or later (the "GPL", see * http://www.gnu.org/licenses/gpl.html ), or the Blender License 1.0 or * later (the "BL", see http://www.blender.org/BL/ ) which has to be * bought from the Blender Foundation to become active, in which case the * above mentioned GPL option does not apply. * * The Original Code is Copyright (C) 2002 by NaN Holding BV. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ /* sector.c MIXED MODEL * * aug 97 SILICON VERSIE * * */ #include "blender.h" #include "screen.h" #include #include #include "sector.h" #include "psx.h" #include "blendpsx.h" extern Object *main_actor; float visifac[2]= {0.7, 0.3}; float distfac[2]= {10.0, 5.0}; void evaluate_camera_network(Object *set, short mode); /* regel voor FUZZY getallen: hoe hoger hoe beter */ /* capo->visi */ #define CA_INVALID 0 #define CA_ALWAYS_TEST 1 #define CA_TEST_OUTWARD 2 #define CA_OK 3 /* capo->direction */ #define CA_OUTWARD 0 #define CA_MIDDLE 1 #define CA_INWARD 2 /* capo->dist */ #define CA_TOTAL 0 #define CA_MEDIUM 1 #define CA_CLOSE 2 /* capo->d_axis */ /* #define CA_INVALID 0 */ #define CA_SMALL 1 /* #define CA_OK 3 */ /* capo->view */ #define CA_SIDE 0 #define CA_FRONT 1 #define CA_BACK 2 /* capo->flag */ #define CA_SETPOS 1 /* ********************************** */ Sector *find_sector_lay(float *vec, float *local, ulong lay) /* algemene find */ { Base *base; base= FIRSTBASE; while(base) { if(base->lay & lay) { if(base->object->type==OB_SECTOR) { if(sector_inside(base->object->data, vec, local)) { return base->object->data; } } } base= base->next; } return 0; } /* ************* CAMERA NETWORK ************** */ void add_camera_to_sector(Sector *se, Object *ob) { /* in stappen van 8 malloccen */ CamPos *capo; Camera *cam; if(se==0) return; if((se->totcam & 7)==0) { capo= callocN( (se->totcam+8)*sizeof(CamPos), "campos"); if(se->totcam) { memcpy(capo, se->campos, sizeof(CamPos)*se->totcam); freeN(se->campos); } se->campos= capo; } else capo= se->campos; capo+= se->totcam; se->totcam++; capo->ob= ob; cam= ob->data; Mat4Ortho(ob->obmat); Mat4Invert(ob->imat, ob->obmat); /* viewmat */ Mat4CpyMat4(capo->piramat, ob->imat); view_to_piramat(capo->piramat, cam->lens, cam->clipend); VECCOPY(capo->loc, ob->loc); VECCOPY(capo->rot, ob->rot); capo->sta= cam->netsta; capo->end= cam->netend; capo->clipsta= cam->clipsta; capo->clipend= cam->clipend; capo->lens= cam->lens; capo->hold= cam->hold; } short netlink_flag(Object *to, Object *from, Sector *se) { CamPos *capo; short a, fl=0; /* zit object to ook in deze sector? */ capo= se->campos; for(a=0; atotcam; a++, capo++) { if(capo->ob==to) fl |= NL_BOTH; } if(fl & NL_BOTH) { if( strcmp(to->id.name, from->id.name) < 0 ) fl |= NL_BACKWARD; } return fl; } short netlink_sfra(Object *to, Object *from, Sector *se) { CamPos *capo; NetLink *nl; short a; /* van to naar from is backwards: vind de sfra */ capo= se->campos; for(a=0; atotcam; a++, capo++) { if(capo->ob == to) { nl= capo->ob->network.first; while(nl) { if((nl->flag & NL_BACKWARD)==0) { if(nl->ob == from) return nl->sfra - 1 + nl->len/2; } nl= nl->next; } } } return 0; } void next_camera(int prev) { Base *base; Sector *se, *cursec; Camera *cam; CamPos *capo; float tempf[3]; int a; if(G.scene->camera==0) return; if(G.vd->persp!=2) return; sector_calc_imat(); /* anders na het renderen: cursec niet vinden */ /* in de sector van de huidige camera: andere vinden */ cursec= find_sector_lay(G.scene->camera->obmat[3], tempf, G.scene->camera->lay); if(cursec==0) { error("Camera not in a sector (layer?)"); return; } base= FIRSTBASE; while(base) { if(base->lay & G.scene->lay) { if(base->object->type==OB_SECTOR) { Mat4Invert(base->object->imat, base->object->obmat); } } base= base->next; } /* alle camera's aflopen, sectortest, aan sector-array toevoegen */ base= FIRSTBASE; while(base) { if(base->lay & G.scene->lay) { if(base->object->type == OB_CAMERA) { cam= base->object->data; if(cam->flag & CAM_NETWORK) { se= find_sector_lay(base->object->obmat[3], tempf, base->lay); if(se && se==cursec) add_camera_to_sector(se, base->object); } } } base= base->next; } /* gaat ie */ if(cursec->totcam) { capo= cursec->campos; for(a=0; atotcam; a++, capo++) { capo->ob->flag &= ~SELECT; if(capo->ob==G.scene->camera) break; } if(a==cursec->totcam) a= 0; if(prev==0) { /* next camera */ if(a==cursec->totcam-1) a= 0; else a++; } else { /* prev camera */ if(a==0) a= cursec->totcam-1; else a--; } capo= cursec->campos+a; G.scene->camera= G.vd->camera= capo->ob; capo->ob->flag |= SELECT; copy_objectflags(); if((G.f & (G_FACESELECT|G_VERTEXPAINT))==0) { set_active_object(capo->ob); handle_view3d_lock(); } freeN(cursec->campos); cursec->campos= 0; cursec->totcam= 0; allqueue(REDRAWVIEW3D, 0); } } void init_camera_network() { Life *lf; Base *base; Sector *se; CamPos *capo; CamFrame *cf; NetLink *nl; Camera *cam, *camnl; float t, fac, mfac, tempf[3]; int a, cfie; /* alle camera's aflopen, sectortest, aan sector-array toevoegen */ base= FIRSTBASE; while(base) { if(base->lay & G.scene->lay) { if(base->object->type == OB_CAMERA) { cam= base->object->data; if(cam->flag & CAM_NETWORK) { G.simulf |= G_NETWORK; se= find_sector_lay(base->object->obmat[3], tempf, base->lay); add_camera_to_sector(se, base->object); } } } base= base->next; } /* sectors aflopen en camera's tellen */ if(G.simulf & G_NETWORK) { printf("Camera network on\n"); base= FIRSTBASE; while(base) { if(base->lay & G.scene->lay) { if(base->object->type == OB_SECTOR) { se= base->object->data; se->totfra= 0; capo= se->campos; for(a=0; atotcam; a++, capo++) { capo->sfra= se->totfra; /* frame in 'movie' */ se->totfra++; nl= capo->ob->network.first; while(nl) { nl->flag = netlink_flag(nl->ob, capo->ob, se); if((nl->flag & NL_BACKWARD)==0) { nl->sfra= se->totfra; se->totfra+= nl->len/2; } nl= nl->next; } } /* backwardse startframes vinden */ capo= se->campos; for(a=0; atotcam; a++, capo++) { nl= capo->ob->network.first; while(nl) { if(nl->flag & NL_BACKWARD) { nl->sfra= netlink_sfra(nl->ob, capo->ob, se); } nl= nl->next; } } /* CamFrame array aanleggen */ if(se->totfra) { cf=se->camframe= callocN( se->totfra*sizeof(CamFrame), "camframe"); } capo= se->campos; for(a=0; atotcam; a++, capo++) { VECCOPY(cf->loc, capo->ob->loc); VECCOPY(cf->rot, capo->ob->rot); cam= capo->ob->data; cf->lens= cam->lens; cf->clipsta= cam->clipsta; cf->clipend= cam->clipend; cf++; nl= capo->ob->network.first; while(nl) { if((nl->flag & NL_BACKWARD)==0) { for(cfie=0; cfielen; cfie+=2, cf++) { t= cfie+2; t/= (float)(nl->len+2); fac= t*t; fac= 3.0*fac - 2.0*t*fac; mfac= 1.0-fac; cf->loc[0]= mfac*capo->loc[0] + fac*nl->ob->loc[0]; cf->loc[1]= mfac*capo->loc[1] + fac*nl->ob->loc[1]; cf->loc[2]= mfac*capo->loc[2] + fac*nl->ob->loc[2]; cf->rot[0]= mfac*capo->rot[0] + fac*nl->ob->rot[0]; cf->rot[1]= mfac*capo->rot[1] + fac*nl->ob->rot[1]; cf->rot[2]= mfac*capo->rot[2] + fac*nl->ob->rot[2]; camnl= nl->ob->data; cf->lens= mfac*capo->lens+ fac*camnl->lens; cf->clipsta= mfac*cam->clipsta+ fac*camnl->clipsta; cf->clipend= mfac*cam->clipend+ fac*camnl->clipend; } } nl= nl->next; } } } } base= base->next; } evaluate_camera_network(0, -1); /*init */ } } void end_camera_network() { CamPos *capo; Sector *se; Base *base; Camera *cam; int a; base= FIRSTBASE; while(base) { if(base->lay & G.scene->lay) { if(base->object->type == OB_SECTOR) { se= base->object->data; capo= se->campos; for(a=0; atotcam; a++, capo++) { /* restore */ VECCOPY(capo->ob->loc, capo->loc); VECCOPY(capo->ob->rot, capo->rot); if(capo->ob->type==OB_CAMERA) { cam= capo->ob->data; cam->lens= capo->lens; cam->netsta= capo->sta; cam->netend= capo->end; cam->clipsta= capo->clipsta; cam->clipend= capo->clipend; } } if(se->campos) freeN(se->campos); if(se->camframe) freeN(se->camframe); se->campos= 0; se->camframe= 0; se->totcam= 0; } } base= base->next; } G.simulf &= ~G_NETWORK; } void set_netclipsta(CamPos *capo) { Camera *cam= G.scene->camera->data; if(capo==0 || capo->ob==0) return; cam->netsta= capo->sta; cam->netend= capo->end; } void sector_frame_to_camera(Sector *se) { CamFrame *cf; Camera *cam; Object *ob= G.scene->camera; if(ob==0 || se==0 || se->camframe==0) return; cf= se->camframe + se->cfra; VECCOPY(ob->loc, cf->loc); VECCOPY(ob->rot, cf->rot); cam= ob->data; cam->lens= cf->lens; cam->clipsta= cf->clipsta; cam->clipend= cf->clipend; } void init_render_camera_network() { static int isdone= 0; Base *base; Sector *se; short sfra, efra; /* backgroundrender afhandelen */ if(G.background) { if(isdone) return; isdone= 1; } sfra= 1; efra= 0; G.simulf= 0; init_sectors(); /* doet ook mesh_isdone flag */ init_camera_network(); /* EFRA berekenen */ G.cursector= 0; base= FIRSTBASE; while(base) { if(base->lay & G.scene->lay) { if(base->object->type == OB_SECTOR) { se= base->object->data; if(se->flag & SE_RENDER_NETWORK) { if(se->campos) { se->sfra= efra + 1; efra+= se->totfra; } } } } base= base->next; } if(efra == 0) efra= 1; if(G.background==0) { EFRA= efra; SFRA= sfra; } } void end_render_camera_network() { if(G.background) return; end_camera_network(); /* staat ook in exit_blender */ end_sectors(); G.cursector= 0; } void render_frame_to_camera() { Base *base; Sector *se= 0; int sfra=1; /* is init_camera_net gedaan? */ if((G.simulf & G_NETWORK)==0) return; /* welke sector */ G.cursector= 0; base= FIRSTBASE; while(base) { if(base->lay & G.scene->lay) { if(base->object->type == OB_SECTOR) { se= base->object->data; if(se->flag & SE_RENDER_NETWORK) { if(se->totfra) { if(CFRA < se->sfra+se->totfra) break; sfra += se->totfra; } } se= 0; } } base= base->next; } if(se) { G.cursector= se; G.cursector->cfra= CFRA-sfra; sector_frame_to_camera(G.cursector); } } void render_frame_to_info(float *loc, float *rot, float *lens) { CamFrame *cf; render_frame_to_camera(); if(G.cursector) { cf= G.cursector->camframe + G.cursector->cfra; *lens= cf->lens; VECCOPY(loc, cf->loc); VECCOPY(rot, cf->rot); } } void evaluate_camera(CamPos *capo) { float hoco[3], sx, sy, inp; float min, max; short fl; VECCOPY(hoco, main_actor->obmat[3]); Mat4MulVecfl(capo->piramat, 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] < capo->sta) fl+= 16; else if(hoco[2] > capo->end) fl+= 32; if(fl) { capo->visi= CA_INVALID; capo->dura= 0; return; } /* visibility */ hoco[0]= (hoco[0]/min); hoco[1]= (hoco[1]/min); max= MAX2( fabs(hoco[0]), fabs(hoco[1])); if(max < visifac[1]) capo->visi= CA_OK; else if(max < visifac[0]) capo->visi= CA_TEST_OUTWARD; else capo->visi= CA_ALWAYS_TEST; /* dist: 'echte' coords */ min= capo->sta + 0.2*(capo->end - capo->sta); max= capo->sta + 0.8*(capo->end - capo->sta); if(hoco[2] > max) capo->dist= CA_TOTAL; else if(hoco[2] > min) capo->dist= CA_MEDIUM; else capo->dist= CA_CLOSE; /* internal direction (Y-as) */ sx= hoco[0]; sy= hoco[1]; VECCOPY(hoco, main_actor->obmat[1]); Mat4Mul3Vecfl(capo->piramat, hoco); /* eenheden van 256: ivm inprodukt test */ capo->axis[0]= (256.0*hoco[0]); capo->axis[1]= (256.0*hoco[1]); if(capo->visi==CA_OK) capo->direction= CA_MIDDLE; else { inp= sx*hoco[0]+sy*hoco[1]; if(inp<0.1) capo->direction= CA_OUTWARD; else if(inp>0.1) capo->direction= CA_INWARD; else capo->direction= CA_MIDDLE; } if(hoco[2] < -0.1) capo->view= CA_FRONT; else if(hoco[2] > 0.1) capo->view= CA_BACK; else capo->view= CA_SIDE; } CamPos *find_best_campos1(CamPos *curcapo) /* leuk voor stills */ { CamPos *capo, *bestcapo= 0; int a, round= 0; while(bestcapo==0) { capo= G.cursector->campos; for(a=0; atotcam; a++, capo++) { if(capo->visi==CA_INVALID) continue; if(capo->d_axis==CA_INVALID) continue; /* alleen 1e ronde */ if(curcapo->visi==CA_OK) { /* alleen closere met juiste as */ if(bestcapo==0) bestcapo= curcapo; if(capo->visi==CA_OK) { if(capo->dist>curcapo->dist) { if(bestcapo==0 || bestcapo->distdist) bestcapo= capo; } } } else if(curcapo->visi==CA_TEST_OUTWARD) { /* alleen inward accepteren */ if(bestcapo==0) bestcapo= curcapo; if(capo->visi==CA_OK) { if(capo->dist>curcapo->dist) { if(bestcapo==0 || bestcapo->distdist) bestcapo= capo; } } else if(curcapo->direction==CA_OUTWARD) { if(capo->visi>=CA_TEST_OUTWARD) { if(capo->direction==CA_INWARD) { /* beste dist */ if(bestcapo==0 || bestcapo->distdist) bestcapo= capo; } } } } else if(curcapo->visi==CA_ALWAYS_TEST) { /* betere visi accepteren */ if(capo->visi>CA_ALWAYS_TEST) { /* dist vergelijken met bestcapo */ if(bestcapo==0 || bestcapo->distdist) bestcapo= capo; } } else { /* cur visi==0: alles accepteren */ if(bestcapo==0 || capo->visi>bestcapo->visi) bestcapo= capo; } if(capo->visi && (capo->ob->flag & 1)) { if(getbutton(LEFTSHIFTKEY)) PRINT4(d, d, d, d, round, capo->visi, capo->dist, capo->d_axis); } } if(bestcapo==0) { if(round==0) { capo= G.cursector->campos; for(a=0; atotcam; a++, capo++) capo->d_axis= CA_SMALL; } else break; } round++; } } CamPos *find_best_campos2(CamPos *curcapo) /* aktie */ { CamPos *capo, *bestcapo= 0; int a, round= 0; /* 1e ronde: alleen VISI / D_AXIS camera's * 2e ronde: alle VISI */ while(bestcapo==0) { if(curcapo->visi==CA_OK) bestcapo= curcapo; /* stabiliseert */ if(round==1 && curcapo->visi) bestcapo= curcapo; /* wanhopig */ capo= G.cursector->campos; for(a=0; atotcam; a++, capo++) { if(capo->visi==CA_INVALID) continue; if(capo->d_axis==CA_INVALID) continue; /* alleen 1e ronde */ if(curcapo->visi==0 || curcapo->direction==CA_OUTWARD) { /* altijd betere vinden */ if(capo->direction!=CA_OUTWARD) { /* beste visi */ if(bestcapo==0 || bestcapo->visivisi) bestcapo= capo; /* beste dist */ if(bestcapo==0 || bestcapo->distdist) bestcapo= capo; } } } if(bestcapo==0) { if(round==0) { capo= G.cursector->campos; for(a=0; atotcam; a++, capo++) capo->d_axis= CA_SMALL; } else if(round==1) { /* noodgreep! */ capo= G.cursector->campos; for(a=0; atotcam; a++, capo++) if(capo->visi) return capo; } else break; } round++; } return bestcapo; } CamPos *find_best_campos3(CamPos *curcapo) /* aktie + back */ { CamPos *capo, *bestcapo= 0; short a, round= 0; if(curcapo->visi && curcapo->view==CA_BACK) bestcapo= curcapo; capo= G.cursector->campos; for(a=0; atotcam; a++, capo++) { if(capo->visi==CA_INVALID) continue; if(capo->view!=CA_BACK) continue; /* als we hier zijn: capo is back+visi */ if(bestcapo==0) bestcapo= capo; /* beste axis */ if(bestcapo->direction==0 && bestcapo->direction < capo->direction) bestcapo= capo; /* beste dist */ if(capo->direction==CA_INWARD) { if(bestcapo->dist < capo->dist) bestcapo= capo; /* beste visi */ if(capo->dist==CA_CLOSE) { if(bestcapo->visi < capo->visi) bestcapo= capo; } } } return bestcapo; } Action *playmovie= 0; void evaluate_camera_network(Object *set, short mode) { static CamPos *curcapo, *bestcapo; CamPos *capo; Life *lf; int inp; short a, newsec=0; if(main_actor==0) return; if(mode== -1) { /* init */ curcapo= bestcapo= 0; playmovie= 0; return; } lf= main_actor->data; if(lf->sector != G.cursector) { curcapo= bestcapo= 0; G.cursector= lf->sector; } if(G.cursector==0 || G.cursector->totcam==0) return; if(set) { capo= G.cursector->campos; for(a=0; atotcam; a++, capo++) { if(capo->ob==set) { bestcapo= capo; bestcapo->flag |= CA_SETPOS; if(curcapo) curcapo->dura= 0; bestcapo->dura= bestcapo->hold; break; } } } if(G.fields==0) return; if(playmovie) { Object *ob; float ctime; if(playmovie->poin==0 || playmovie->cur>= playmovie->end) { playmovie= 0; } else { ob= playmovie->poin; playmovie->cur+= G.fields; ctime= (float)(0.5*playmovie->cur); where_is_object_time(ob, ctime); VECCOPY(G.scene->camera->loc, ob->loc); VECCOPY(G.scene->camera->rot, ob->rot); return; } } if(curcapo && curcapo->nl) { /* link aan't afspelen */ curcapo->cfie+= G.fields; /* rekenen in fields */ if( curcapo->cfie >= curcapo->nl->len) { curcapo->nl= 0; curcapo= bestcapo; G.cursector->cfra= curcapo->sfra; } else { if(curcapo->nl->flag & NL_BACKWARD) G.cursector->cfra= curcapo->nl->sfra - (curcapo->cfie/2); else G.cursector->cfra= curcapo->nl->sfra + (curcapo->cfie/2); sector_frame_to_camera(G.cursector); return; } } if(curcapo==0) { /* Of de eerste Of de huidige camera, NIET bestcapo */ capo=curcapo= G.cursector->campos; if(curcapo==0) return; for(a=0; atotcam; a++, capo++) { if(bestcapo==capo); else if(capo->ob==G.scene->camera) curcapo= capo; } curcapo->dura= 0; newsec= 1; } /* alle camera's in huidige sector aflopen PLUS huidige camera */ capo= G.cursector->campos; for(a=0; atotcam; a++, capo++) { if(capo!=curcapo) evaluate_camera(capo); } evaluate_camera(curcapo); /* de as regel */ capo= G.cursector->campos; for(a=0; atotcam; a++, capo++) { inp= curcapo->axis[0]*capo->axis[0] + curcapo->axis[1]*capo->axis[1]; if(inp<-100) capo->d_axis= CA_INVALID; else if(inp<10000) capo->d_axis= CA_SMALL; else capo->d_axis= CA_OK; if(capo->ob->flag & 1) { if(getbutton(LEFTSHIFTKEY)) { PRINT4(d, d, d, d, capo->visi, capo->dist, capo->view, capo->direction); } } } /* de conservatieve regel */ if(curcapo->dura>0) curcapo->dura-= G.fields; if(curcapo->dura<=0) { /* de beste */ if(bestcapo && (bestcapo->flag & CA_SETPOS)) bestcapo->flag &= ~CA_SETPOS; else { bestcapo= find_best_campos3(curcapo); if(bestcapo==0) bestcapo= find_best_campos2(curcapo); /* tzt vervangen */ } if(bestcapo) { if(bestcapo!=curcapo) { NetLink *nl= curcapo->ob->network.first; if(newsec) nl= 0; /* is er een netlink? */ while(nl) { if(nl->ob==bestcapo->ob) break; nl= nl->next; } if(nl) { curcapo->nl= nl; curcapo->cfie= 0; G.cursector->cfra= nl->sfra; /* frames */ } else { G.cursector->cfra= bestcapo->sfra; /* frames */ curcapo= bestcapo; } bestcapo->dura= bestcapo->hold; } else G.cursector->cfra= bestcapo->sfra; /* frames */ } } /* if(getbutton(LEFTSHIFTKEY)) PRINT2(x, d, G.cursector, G.cursector->cfra); */ sector_frame_to_camera(G.cursector); set_netclipsta(curcapo); } void add_networklink() { Object *obact; Base *base; static short len= 25; short mode; NetLink *nl; obact= OBACT; if(obact==0) return; mode= pupmenu("NetWork %t|add link %x1| remove link %x2"); if(mode<1) return; if(mode==1) button(&len, 2, 250, "Frames"); /* leg links van de ACTIEVE naar de GESELECTEERDE en terug */ base= FIRSTBASE; while(base) { if TESTBASE(base) { if(base->object!=obact) { /* 1: van obact naar ob */ nl= obact->network.first; while(nl) { if(nl->ob==base->object) break; nl= nl->next; } if(mode==1) { /* add */ if(nl==0) { nl= callocN(sizeof(NetLink), "Netlink"); addtail(&obact->network, nl); } nl->ob= base->object; nl->len= 2*len; /* fields */ } else if(mode==2 && nl) { /* del */ remlink(&obact->network, nl); freeN(nl); } /* 2: van ob naar obact */ nl= base->object->network.first; while(nl) { if(nl->ob==obact) break; nl= nl->next; } if(mode==1) { /* add */ if(nl==0) { nl= callocN(sizeof(NetLink), "Netlink"); addtail(&base->object->network, nl); } nl->ob= obact; nl->len= 2*len; /* fields */ } else if(mode==2 && nl) { /* del */ remlink(&base->object->network, nl); freeN(nl); } } } base= base->next; } allqueue(REDRAWVIEW3D, 0); }