/** * $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 ***** */ /* * sectormv.c * */ #include "psxblend.h" #include "psxgraph.h" #include "..\frank\movie.h" #include void sector_back(short doflush); void evaluate_camera_network(pObject *set, short mode); // globals short visifac[2]= {2800, 1200}; short distfac[2]= {5000, 2000}; extern pObject *main_actor; pAction *playmovie= 0; BMovie *mainmovie= 0; Stream *only_one= 0; volatile char moviedone=2; typedef struct pCamInfo { int loc[3]; short rot[3], lens; } pCamInfo; #define CAMI MAKE_ID('C', 'A', 'M', 'I') /* 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 /********************************* * * * AUDIO STREAMING * */ #define MAX_VOICE 2 #define ALL_VOICES ((1 << MAX_VOICE) - 1) /* 44100 samples / seconde * = 1764 samples / frame * = 63 blokjes van 28 samples / frame * = 63 blokjes van 16 bytes / frame * = 1008 bytes / frame */ #define SPU_BUFSIZE 2016 #define SPU_BUFSIZEHALF (SPU_BUFSIZE >> 1) SpuStEnv *st; unsigned long st_stop; #define ST_STOP_INIT_VAL 0 unsigned long st_stat = 0; long st_load_ave = 0; char spu_malloc_rec [SPU_MALLOC_RECSIZ * (MAX_VOICE + 1)]; char silence[SPU_BUFSIZEHALF]; char voicebuf[MAX_VOICE][SPU_BUFSIZEHALF]; int spu_started = FALSE; void spust_prepare (void) { register long i; for (i = 0; i < MAX_VOICE; i ++) { st->voice [i].data_addr = (ulong) silence; st->voice [i].status = SPU_ST_PLAY; } st_stop = ST_STOP_INIT_VAL; st_stat = 0; st_load_ave = 0; } long spust_start (unsigned long voice_bit) { if (st_stat == 0L) { spust_prepare (); } st_stat |= voice_bit; return SpuStTransfer (SPU_ST_PREPARE, voice_bit); } void spustCB_next (unsigned long voice_bit) { static int count = 0; static int first = 0; register long i; MFrame * mframe; mframe = mdec_list->first; while(mframe) { if (mframe->audio_finished == FALSE) break; mframe = mframe->next; } if (mframe) { if (mframe->out_started == 0) mframe = 0; } // mframe = 0; if (mframe) { for (i = 0; i < MAX_VOICE; i ++) { if (mframe->voice[i]) { memcpy(voicebuf[i], (void *) mframe->voice[0], SPU_BUFSIZEHALF); st->voice[i].data_addr = (ulong) voicebuf[i]; } else st->voice[i].data_addr = (ulong) silence; } mframe->audio_finished = TRUE; if (mframe->video_finished) { if (mframe->done) *mframe->done = TRUE; mframe->done = 0; } } else { for (i = 0; i < MAX_VOICE; i ++) { st->voice[i].data_addr = (ulong) voicebuf[i]; } } if (st_stop != ST_STOP_INIT_VAL) { for (i = 0; i < MAX_VOICE; i += 2) { if (st_stop & SPU_VOICECH (i)) { /* L-ch */ st->voice[i].status = SPU_ST_STOP; st->voice[i].last_size = SPU_BUFSIZEHALF; /* R-ch */ st->voice[i + 1].status = SPU_ST_STOP; st->voice[i + 1].last_size = SPU_BUFSIZEHALF; } } st_stat &= ~st_stop; st_stop = ST_STOP_INIT_VAL; } } SpuStCallbackProc spustCB_preparation_finished (unsigned long voice_bit, long p_status) { if (p_status == SPU_ST_PREPARE) { spustCB_next (voice_bit); } if (st_stat != 0L) { SpuStTransfer (SPU_ST_START, voice_bit); } } SpuStCallbackProc spustCB_transfer_finished (unsigned long voice_bit, long t_status) { spustCB_next (voice_bit); } SpuStCallbackProc spustCB_stream_finished (unsigned long voice_bit, long s_status) { SpuSetKey (SPU_OFF, voice_bit); } int init_audio_stream() { int i; SpuVoiceAttr s_attr; SpuCommonAttr c_attr; unsigned long buffer_addr [MAX_VOICE]; if (spu_started == TRUE) return; /* ---------------------------------------------------------------- * SPU Initialize * ---------------------------------------------------------------- */ SpuInit (); SpuInitMalloc (MAX_VOICE, spu_malloc_rec); /* ---------------------------------------------------------------- * SPU Common attributes * ---------------------------------------------------------------- */ c_attr.mask = (SPU_COMMON_MVOLL | SPU_COMMON_MVOLR); c_attr.mvol.left = 0x3fff; /* Master volume (left) */ c_attr.mvol.right = 0x3fff; /* Master volume (right) */ SpuSetCommonAttr (&c_attr); /* ---------------------------------------------------------------- * SPU Transfer Mode * ---------------------------------------------------------------- */ SpuSetTransferMode (SPU_TRANSFER_BY_DMA); /* transfer by DMA */ /* */ /* ---------------------------------------------------------------- * SPU streaming setting * ---------------------------------------------------------------- */ /* :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * Initialize SPU streaming * :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: */ st = SpuStInit (0); /* :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * Set some callback functions * :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: */ /* For finishing SPU streaming preparation */ (void) SpuStSetPreparationFinishedCallback ((SpuStCallbackProc) spustCB_preparation_finished); /* For next transferring */ (void) SpuStSetTransferFinishedCallback ((SpuStCallbackProc) spustCB_transfer_finished); /* For finising SPU streaming with some voices */ (void) SpuStSetStreamFinishedCallback ((SpuStCallbackProc) spustCB_stream_finished); /* :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * Allocate buffers in sound buffer * :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: */ for (i = 0; i < MAX_VOICE; i ++) { if ((buffer_addr [i] = SpuMalloc (SPU_BUFSIZE)) == -1) { printf ("SpuMalloc : %d\n", i); return 0; /* ERROR */ } } /* :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: * Set SPU streaming environment * :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: */ /* Size of each buffer in sound buffer */ st->size = SPU_BUFSIZE; st->low_priority = SPU_ON; /* Top address of each buffer in sound buffer */ for (i = 0; i < MAX_VOICE + 1; i ++) { st->voice[i].buf_addr = buffer_addr [i]; } /* ---------------------------------------------------------------- * Voice attributes * ---------------------------------------------------------------- */ /* attribute masks */ s_attr.mask = (SPU_VOICE_VOLL | SPU_VOICE_VOLR | SPU_VOICE_PITCH | SPU_VOICE_WDSA | SPU_VOICE_ADSR_AMODE | SPU_VOICE_ADSR_SMODE | SPU_VOICE_ADSR_RMODE | SPU_VOICE_ADSR_AR | SPU_VOICE_ADSR_DR | SPU_VOICE_ADSR_SR | SPU_VOICE_ADSR_RR | SPU_VOICE_ADSR_SL ); /* attribute values: L-ch */ s_attr.volume.left = 0x3fff; s_attr.volume.right = 0x0; s_attr.pitch = 0x1000; s_attr.a_mode = SPU_VOICE_LINEARIncN; s_attr.s_mode = SPU_VOICE_LINEARIncN; s_attr.r_mode = SPU_VOICE_LINEARDecN; s_attr.ar = 0x0; s_attr.dr = 0x0; s_attr.sr = 0x0; s_attr.rr = 0x3; s_attr.sl = 0xf; for (i = 0; i < MAX_VOICE; i++) { if (i & 1) { /* right channel */ s_attr.volume.left = 0x0; s_attr.volume.right = 0x3fff; } else { /* left channel */ s_attr.volume.left = 0x3fff; s_attr.volume.right = 0x0; } s_attr.voice = SPU_VOICECH (i); s_attr.addr = buffer_addr [i]; SpuSetVoiceAttr (&s_attr); } /* fill silence buffer */ bzero(silence, sizeof(silence)); for (i = 0; i < MAX_VOICE; i++) memcpy(voicebuf[i], silence, SPU_BUFSIZEHALF); spust_start(ALL_VOICES); spu_started = TRUE; } exit_audio_stream() { int i; if (spu_started == FALSE) return; for (i = 0; i < MAX_VOICE; i++) memcpy(voicebuf[i], silence, SPU_BUFSIZEHALF); VSync(0); VSync(0); VSync(0); if (0) { spu_started = FALSE; SpuSetKey (SPU_OFF, SPU_ALLCH); SpuStQuit (); /* SPU streaming */ SpuQuit (); SpuStSetPreparationFinishedCallback ((SpuStCallbackProc) 0); SpuStSetTransferFinishedCallback ((SpuStCallbackProc) 0); SpuStSetStreamFinishedCallback ((SpuStCallbackProc) 0); } } /********************************** */ void start_mainmovie(char *name) { if(name==0) return; if((G.f & G_NETWORK)==0) return; if(only_one) stream_close(only_one); if(mainmovie) movie_close(mainmovie->mv); else mainmovie= mallocN(sizeof(BMovie), "bmovie"); bzero((char *)mainmovie, sizeof(BMovie)); strcpy(mainmovie->file, name); strcat(mainmovie->file, ".mdc"); PRINT(s, mainmovie->file); only_one = stream_open(mainmovie->file); stream_add(only_one); mainmovie->mv= movie_open(only_one, 's'); mainmovie->lastfra = -1; if(mainmovie->mv == 0) printf("can't find %s\n", mainmovie->file); else if (mainmovie->mv->audio_size) { mainmovie->mv->flags |= MV_play_audio; mainmovie->mv->frames--; /* patch */ init_audio_stream(); } } void end_mainmovie() { if(only_one) stream_close(only_one); only_one= 0; if(mainmovie) { movie_close(mainmovie->mv); freeN(mainmovie); mainmovie= 0; } exit_audio_stream(); printf("exit movie\n"); } /* ************ NETWORK ************************* */ void sector_back(short doflush) { static MFrame *mframe= 0; Chunk *chunk; pCamInfo *ci=0; Movie *mv; pObject *ob; short sx, sy, ret; if((G.f & G_NETWORK)==0) return; if(mframe) { moviedone= 0; movie_drawframe(mframe, cdb->draw.clip.x, cdb->draw.clip.y, &moviedone); mframe= 0; } if(doflush) { VSync(0); // loadimage afmaken VSync(0); VSync(0); playmovie= 0; // mogelijk end_mainmovie(); moviedone= 2; // signaal voor 'al gedaan?' streaming_exit(); return; } if(mainmovie==0 || mainmovie->mv==0) { moviedone= 1; return; } // frame nr? mv= mainmovie->mv; CLAMP(mainmovie->cfra, 0, mv->frames-1); // al gedaan? if(mainmovie->lastfra==mainmovie->cfra || moviedone==1) { if((G.f & G_PLAYMOVIE)==0) { RECT rt; if(moviedone==0) return; // is bezig rt.x= 640; rt.y= 0; rt.w= 320; rt.h= 256; MoveImage(&rt, cdb->draw.clip.x, cdb->draw.clip.y); DrawSync(0); if(mainmovie->lastfra==mainmovie->cfra) return; } } // load next mframe = movie_readframe(mv, mainmovie->cfra+1); if(mframe==0) { printf("movie_readframe returned 0 fra:%d\n", mainmovie->cfra); } else if (movie_calcframe(mframe)) { printf("movie_calcframe error fra:%d\n", mainmovie->cfra); mframe= 0; } if(mframe==0) moviedone= 1; else { mainmovie->lastfra= mainmovie->cfra; // info struct lezen chunk = mframe->chunks.first; while(chunk) { if(chunk->id==CAMI) { ci= chunk->data; ob= G.scene->camera; VECCOPY(ob->loc, ci->loc); VECCOPY(ob->rot, ci->rot); object_to_viewmat(ob, &G.viewmat); G.scene->lens= ci->lens; SetGeomScreen(G.scene->lens); break; } chunk= chunk->next; } if(chunk==0) G.f |= G_PLAYMOVIE; } } void evaluate_camera(pCamPos *capo) { VECTOR hoco, new; int sx, sy, inp; int min, max; short fl; ApplyMatrixLV(&capo->piramat, (VECTOR *)main_actor->obmat.t, &hoco); hoco.vx+= capo->piramat.t[0]; hoco.vy+= capo->piramat.t[1]; hoco.vz+= capo->piramat.t[2]; capo->rt=max= hoco.vz; min= -max; fl= 0; if(hoco.vx < min) fl+= 1; else if(hoco.vx > max) fl+= 2; if(hoco.vy < min) fl+= 4; else if(hoco.vy > max) fl+= 8; if(hoco.vz < capo->sta) fl+= 16; else if(hoco.vz >capo->end) fl+= 32; if(fl) { capo->visi= CA_INVALID; return; } /* visibility */ hoco.vx= ((hoco.vx<<12)/min); hoco.vy= ((hoco.vy<<12)/min); max= MAX2( abs(hoco.vx), abs(hoco.vy)); 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 + SMUL(800, capo->end - capo->sta); max= capo->sta + SMUL(3200, capo->end - capo->sta); if(hoco.vz > max) capo->dist= CA_TOTAL; else if(hoco.vz > min) capo->dist= CA_MEDIUM; else capo->dist= CA_CLOSE; /* internal direction (Y-as) */ sx= hoco.vx; sy= hoco.vy; new.vx= main_actor->obmat.m[0][1]; new.vy= main_actor->obmat.m[1][1]; new.vz= main_actor->obmat.m[2][1]; ApplyMatrixLV(&capo->piramat, &new, &hoco); /* eenheden van 256: ivm inprodukt test */ capo->axis[0]= (hoco.vx>>4); capo->axis[1]= (hoco.vy>>4); if(capo->visi==CA_OK) capo->direction= CA_MIDDLE; else { inp= sx*hoco.vx + sy*hoco.vy; if(inp<-200) capo->direction= CA_OUTWARD; else if(inp>200) capo->direction= CA_INWARD; else capo->direction= CA_MIDDLE; } if(hoco.vz < -800) capo->view= CA_FRONT; else if(hoco.vz > 800) capo->view= CA_BACK; else capo->view= CA_SIDE; } pCamPos *find_best_campos2(pCamPos *curcapo) /* aktie */ { pCamPos *capo, *bestcapo= 0; int a, round= 0; while(bestcapo==0) { if(curcapo->visi==CA_OK) bestcapo= curcapo; /* stabiliseert */ if(round==1 && curcapo->visi) bestcapo= curcapo; 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; /* kleinste dist */ if(bestcapo==0 || bestcapo->dist>capo->dist) 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++; } if(bestcapo==0) bestcapo= curcapo; return bestcapo; } pCamPos *find_best_campos3(pCamPos *curcapo) /* aktie + back */ { pCamPos *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; } void evaluate_camera_network(pObject *set, short mode) { static pCamPos *curcapo, *bestcapo; pCamPos *capo; pLife *lf; int inp; short a, newsec=0; if((G.f & G_NETWORK)==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(playmovie==0 && G.cursector) start_mainmovie(G.cursector->name); } 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(mainmovie==0) return; if(playmovie) { // event if(playmovie->cur>= playmovie->end) { playmovie= 0; if(G.cursector) start_mainmovie(G.cursector->name); G.f &= ~G_PLAYMOVIE; } else { // was: playmovie->cur+= G.fields; playmovie->cur+= 2; mainmovie->cfra= playmovie->cur/2; 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; mainmovie->cfra= curcapo->sfra; } else { if(curcapo->nl->flag & NL_BACKWARD) mainmovie->cfra= curcapo->nl->sfra - (curcapo->cfie/2); else mainmovie->cfra= curcapo->nl->sfra + (curcapo->cfie/2); 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(G.qual & 1) PRINT4(x, d, d, d, capo, capo->visi, capo->dist, capo->view); } /* 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) { pNetLink *nl= curcapo->ob->network.first; if(newsec) nl= 0; /* is er een netlink? */ while(nl) { if(nl->ob==bestcapo->ob) { // tijdelijk (?) geen achterwaartse if(nl->flag & NL_BACKWARD); else break; } nl= nl->next; } if(nl) { curcapo->nl= nl; curcapo->cfie= 0; // fields mainmovie->cfra= nl->sfra; // frames } else { mainmovie->cfra= bestcapo->sfra; // frames curcapo= bestcapo; } bestcapo->dura= bestcapo->hold; } else mainmovie->cfra= bestcapo->sfra; // frames } } else mainmovie->cfra= curcapo->sfra; }