1 #define DB_LEVEL 1
2 #include "3dc.h"
3 #include "inline.h"
4 #include "module.h"
5 #include "dynblock.h"
6 #include "stratdef.h"
7 #include "gamedef.h"
8 #include "track.h"
9 #include "jsndsup.h"
10 #include "psndplat.h"
11 #include "ourasert.h"
12 #include "mempool.h"
13
14 #include "db.h"
15
16 static void Preprocess_Smooth_Track_Controller(TRACK_CONTROLLER* tc);
17 static void SmoothTrackPosition(TRACK_SECTION_DATA* trackPtr, int u, VECTORCH *outputPositionPtr);
18 static void SmoothTrackOrientation(TRACK_SECTION_DATA* trackPtr, int lerp, MATRIXCH* outputMatrixPtr);
19 static void BasicSlerp(QUAT *input1,QUAT *input2,QUAT *output,int lerp);
20 static void MakeControlQuat(QUAT *control, QUAT *q0, QUAT *q1, QUAT *q2);
21 static void LnQuat(QUAT *q);
22 static void ExpPurelyImaginaryQuat(QUAT *q);
23 extern void MulQuat(QUAT *q1, QUAT *q2, QUAT *output);
24
25 extern int NormalFrameTime;
26 extern void QNormalise(QUAT*);
27 extern int QDot(QUAT *, QUAT *);
28
TrackSlerp(TRACK_SECTION_DATA * tsd,int lerp,MATRIXCH * output_mat)29 static void TrackSlerp(TRACK_SECTION_DATA* tsd,int lerp,MATRIXCH* output_mat)
30 {
31 int sclp,sclq;
32
33 QUAT* input1=&tsd->quat_start;
34 QUAT* input2=&tsd->quat_end;
35 QUAT output;
36
37 if(lerp<0) lerp=0;
38 if(lerp>65536)lerp=65536;
39
40 /* First check for special case. */
41
42 if (tsd->omega==2048) {
43 int t1,t2;
44
45 output.quatx=-input1->quaty;
46 output.quaty=input1->quatx;
47 output.quatz=-input1->quatw;
48 output.quatw=input1->quatz;
49
50 t1=MUL_FIXED((ONE_FIXED-lerp),1024);
51 sclp=GetSin(t1);
52
53 t2=MUL_FIXED(lerp,1024);
54 sclq=GetSin(t2);
55
56 output.quatx=(MUL_FIXED(input1->quatx,sclp))+(MUL_FIXED(output.quatx,sclq));
57 output.quaty=(MUL_FIXED(input1->quaty,sclp))+(MUL_FIXED(output.quaty,sclq));
58 output.quatz=(MUL_FIXED(input1->quatz,sclp))+(MUL_FIXED(output.quatz,sclq));
59 output.quatw=(MUL_FIXED(input1->quatw,sclp))+(MUL_FIXED(output.quatw,sclq));
60
61 } else {
62 if ( (tsd->omega==0) && (tsd->oneoversinomega==0) ) {
63 sclp=ONE_FIXED-lerp;
64 sclq=lerp;
65 } else {
66 int t1,t2;
67
68 t1=MUL_FIXED((ONE_FIXED-lerp),tsd->omega);
69 t2=GetSin(t1);
70 sclp=MUL_FIXED(t2,tsd->oneoversinomega);
71
72 t1=MUL_FIXED(lerp,tsd->omega);
73 t2=GetSin(t1);
74 sclq=MUL_FIXED(t2,tsd->oneoversinomega);
75
76 }
77
78 output.quatx=(MUL_FIXED(input1->quatx,sclp))+(MUL_FIXED(input2->quatx,sclq));
79 output.quaty=(MUL_FIXED(input1->quaty,sclp))+(MUL_FIXED(input2->quaty,sclq));
80 output.quatz=(MUL_FIXED(input1->quatz,sclp))+(MUL_FIXED(input2->quatz,sclq));
81 output.quatw=(MUL_FIXED(input1->quatw,sclp))+(MUL_FIXED(input2->quatw,sclq));
82 }
83
84 QNormalise(&output);
85 QuatToMat(&output,output_mat);
86 }
87
88
Start_Track_Sound(TRACK_SOUND * ts,VECTORCH * location)89 void Start_Track_Sound(TRACK_SOUND* ts,VECTORCH * location)
90 {
91 SOUND3DDATA s3d;
92
93 GLOBALASSERT(ts);
94
95 ts->playing=1;
96 if(ts->activ_no!=SOUND_NOACTIVEINDEX) return;
97 if(!ts->sound_loaded) return;
98
99 if(ts->loop)
100 {
101 //make sure track is close enough to be heard
102 int dist=VectorDistance(&Player->ObWorld,location);
103 if(dist>ts->outer_range)
104 {
105 return;
106 }
107 }
108
109 s3d.position = *location;
110 s3d.inner_range = ts->inner_range;
111 s3d.outer_range = ts->outer_range;
112 s3d.velocity.vx = 0;
113 s3d.velocity.vy = 0;
114 s3d.velocity.vz = 0;
115
116 if(ts->loop)
117 {
118 Sound_Play ((SOUNDINDEX)ts->sound_loaded->sound_num, "nvpel", &s3d,ts->max_volume,ts->pitch,&ts->activ_no);
119 }
120 else
121 {
122 Sound_Play ((SOUNDINDEX)ts->sound_loaded->sound_num, "nvpe", &s3d,ts->max_volume,ts->pitch,&ts->activ_no);
123 }
124 ts->time_left=GameSounds[ts->sound_loaded->sound_num].length;
125
126 db_logf3(("Playing sound %d\t%s",ts->sound_loaded->sound_num,GameSounds[ts->sound_loaded->sound_num].wavName));
127
128 }
Stop_Track_Sound(TRACK_SOUND * ts)129 void Stop_Track_Sound(TRACK_SOUND* ts)
130 {
131 GLOBALASSERT(ts);
132
133 ts->playing=0;
134 if(ts->activ_no!=SOUND_NOACTIVEINDEX)
135 {
136 Sound_Stop(ts->activ_no);
137 ts->time_left=0;
138 }
139 }
Update_Track_Sound(TRACK_SOUND * ts,VECTORCH * location)140 void Update_Track_Sound(TRACK_SOUND* ts,VECTORCH * location)
141 {
142 GLOBALASSERT(ts);
143
144 if(ts->playing)
145 {
146 ts->time_left-=NormalFrameTime;
147 if(ts->loop)
148 {
149 //check to see if sound is close enough to player
150 int dist=VectorDistance(&Player->ObWorld,location);
151 if(dist>ts->outer_range)
152 {
153 //stop playing the sound for the moment
154 if(ts->activ_no != SOUND_NOACTIVEINDEX)
155 {
156 Sound_Stop(ts->activ_no);
157 }
158 }
159 else
160 {
161 if(ts->activ_no == SOUND_NOACTIVEINDEX)
162 {
163 //restart the sound
164 Start_Track_Sound(ts,location);
165 return;
166 }
167
168 if (ts->activ_no != SOUND_NOACTIVEINDEX)
169 {
170 //update the sound's location
171 SOUND3DDATA s3d;
172 s3d.position = *location;
173 s3d.inner_range = ts->inner_range;
174 s3d.outer_range = ts->outer_range;
175 s3d.velocity.vx = 0;
176 s3d.velocity.vy = 0;
177 s3d.velocity.vz = 0;
178
179 Sound_UpdateNew3d (ts->activ_no, &s3d);
180 }
181 }
182 }
183 else
184 {
185 if(ts->activ_no == SOUND_NOACTIVEINDEX)
186 {
187 //sound has stopped playing.
188 ts->playing=0;
189 }
190 }
191 }
192 }
193
Deallocate_Track_Sound(TRACK_SOUND * ts)194 void Deallocate_Track_Sound(TRACK_SOUND* ts)
195 {
196 GLOBALASSERT(ts);
197
198 Stop_Track_Sound(ts);
199
200 if(ts->sound_loaded)
201 {
202 LoseSound(ts->sound_loaded);
203 }
204
205 #if !USE_LEVEL_MEMORY_POOL
206 DeallocateMem (ts);
207 #endif
208 }
209
Update_Track_Position_Only(TRACK_CONTROLLER * tc)210 void Update_Track_Position_Only(TRACK_CONTROLLER* tc)
211 {
212 TRACK_SECTION_DATA* cur_tsd;
213 DYNAMICSBLOCK* dynptr;
214
215 GLOBALASSERT(tc);
216
217 GLOBALASSERT(tc->sbptr);
218 GLOBALASSERT(tc->sections);
219
220 dynptr=tc->sbptr->DynPtr;
221 GLOBALASSERT(dynptr);
222
223 cur_tsd=&tc->sections[tc->current_section];
224
225
226 //adjust timer until time lies within a section
227 while(tc->timer>cur_tsd->time_for_section || tc->timer<0)
228 {
229 if(tc->timer>cur_tsd->time_for_section)
230 {
231 tc->timer-=cur_tsd->time_for_section;
232
233 if(tc->current_section==(tc->num_sections-1) && !tc->loop)
234 {
235 if(tc->loop_backandforth)
236 {
237 //turn around
238 tc->reverse=1;
239 tc->timer=cur_tsd->time_for_section-tc->timer;
240 }
241 else
242 {
243 //reached end of track
244 tc->timer=cur_tsd->time_for_section;
245 tc->playing=0;
246 tc->reverse=1;
247 }
248 }
249 else
250 {
251 tc->current_section++;
252
253 if(tc->current_section==tc->num_sections) tc->current_section=0;
254
255 cur_tsd=&tc->sections[tc->current_section];
256 }
257
258 }
259 else
260 {
261 if(tc->current_section==0 && !tc->loop)
262 {
263 if(tc->loop_backandforth)
264 {
265 //turn around
266 tc->reverse=0;
267 tc->timer=-tc->timer;
268 }
269 else
270 {
271 //reached end of track
272 tc->timer=0;
273 tc->playing=0;
274 tc->reverse=0;
275 }
276
277 }
278 else
279 {
280 tc->current_section--;
281
282 if(tc->current_section<0) tc->current_section=tc->num_sections-1;
283
284 cur_tsd=&tc->sections[tc->current_section];
285 tc->timer+=cur_tsd->time_for_section;
286 }
287
288 }
289
290 }
291
292 // now work out the object position at this time
293
294 /* KJL 14:47:44 24/03/98 - check for smoothing; if you've
295 less than 3 points then smoothing is a bit pointless */
296 if (tc->use_smoothing && tc->num_sections>=3)
297 {
298 int lerp=MUL_FIXED(tc->timer,cur_tsd->oneovertime);
299 SmoothTrackOrientation(cur_tsd,lerp,&(dynptr->OrientMat));
300 SmoothTrackPosition(cur_tsd,lerp,&(dynptr->Position));
301
302 }
303 else
304 {
305 if(tc->no_rotation)
306 {
307 int lerp=MUL_FIXED(tc->timer,cur_tsd->oneovertime);
308 VECTORCH pivot_pos=cur_tsd->pivot_start;
309
310 pivot_pos.vx+=MUL_FIXED(cur_tsd->pivot_travel.vx,lerp);
311 pivot_pos.vy+=MUL_FIXED(cur_tsd->pivot_travel.vy,lerp);
312 pivot_pos.vz+=MUL_FIXED(cur_tsd->pivot_travel.vz,lerp);
313
314
315
316 dynptr->Position=pivot_pos;
317 }
318 else
319 {
320 int lerp=MUL_FIXED(tc->timer,cur_tsd->oneovertime);
321 MATRIXCH orient;
322 VECTORCH pivot_pos=cur_tsd->pivot_start;
323 VECTORCH object_pos=cur_tsd->object_offset;
324
325 TrackSlerp(cur_tsd,lerp,&orient);
326
327 pivot_pos.vx+=MUL_FIXED(cur_tsd->pivot_travel.vx,lerp);
328 pivot_pos.vy+=MUL_FIXED(cur_tsd->pivot_travel.vy,lerp);
329 pivot_pos.vz+=MUL_FIXED(cur_tsd->pivot_travel.vz,lerp);
330
331 RotateVector(&object_pos,&orient);
332
333 AddVector(&pivot_pos,&object_pos);
334
335
336 dynptr->OrientMat=orient;
337 dynptr->Position=object_pos;
338 }
339 }
340 }
341
Update_Track_Position(TRACK_CONTROLLER * tc)342 void Update_Track_Position(TRACK_CONTROLLER* tc)
343 {
344 DYNAMICSBLOCK* dynptr;
345
346 GLOBALASSERT(tc);
347
348 if(!tc->playing) return;
349
350 GLOBALASSERT(tc->sbptr);
351 GLOBALASSERT(tc->sections);
352
353 dynptr=tc->sbptr->DynPtr;
354 GLOBALASSERT(dynptr);
355
356 if(tc->playing_start_sound)
357 {
358 Update_Track_Sound(tc->start_sound,&dynptr->Position);
359 if(tc->start_sound->playing)
360 {
361 return;
362 }
363 tc->playing_start_sound=FALSE;
364 if(tc->sound)
365 {
366 Start_Track_Sound(tc->sound,&tc->sbptr->DynPtr->Position);
367 }
368 }
369
370 //update timer and current section number
371 if(tc->reverse)
372 {
373 if(tc->use_speed_mult)
374 tc->timer-=MUL_FIXED(NormalFrameTime,tc->speed_mult);
375 else
376 tc->timer-=NormalFrameTime;
377 }
378 else
379 {
380 if(tc->use_speed_mult)
381 tc->timer+=MUL_FIXED(NormalFrameTime,tc->speed_mult);
382 else
383 tc->timer+=NormalFrameTime;
384 }
385
386 Update_Track_Position_Only(tc);
387
388 if(tc->sound)
389 {
390 if(tc->playing)
391 {
392 Update_Track_Sound(tc->sound,&dynptr->Position);
393 }
394 else
395 {
396 Stop_Track_Sound(tc->sound);
397 if(tc->end_sound)
398 {
399 Start_Track_Sound(tc->end_sound,&tc->sbptr->DynPtr->Position);
400 }
401 }
402 }
403 }
404
Preprocess_Track_Controller(TRACK_CONTROLLER * tc)405 void Preprocess_Track_Controller(TRACK_CONTROLLER* tc)
406 {
407 int i;
408 GLOBALASSERT(tc->sections);
409
410 /* KJL 14:47:44 24/03/98 - check for smoothing; if you've
411 less than 3 points then smoothing is a bit pointless */
412 if (tc->use_smoothing && tc->num_sections>=3)
413 {
414 Preprocess_Smooth_Track_Controller(tc);
415 return;
416 }
417
418 for(i=0;i<tc->num_sections;i++)
419 {
420
421 TRACK_SECTION_DATA* tsd=&tc->sections[i];
422
423 tsd->oneovertime=DIV_FIXED(ONE_FIXED,tsd->time_for_section);
424
425 if(!tc->no_rotation)
426 {
427 int cosom,sinom;
428 cosom=QDot(&tsd->quat_start,&tsd->quat_end);
429
430 if (cosom<0) {
431 tsd->quat_end.quatx=-tsd->quat_end.quatx;
432 tsd->quat_end.quaty=-tsd->quat_end.quaty;
433 tsd->quat_end.quatz=-tsd->quat_end.quatz;
434 tsd->quat_end.quatw=-tsd->quat_end.quatw;
435 cosom=-cosom;
436 }
437
438
439 tsd->omega=ArcCos(cosom);
440 sinom=GetSin(tsd->omega);
441 if (sinom) {
442 tsd->oneoversinomega=DIV_FIXED(ONE_FIXED,sinom);
443 } else {
444 tsd->omega=0;
445 tsd->oneoversinomega=0;
446 }
447 }
448 }
449
450 }
451
452
453
Start_Track_Playing(TRACK_CONTROLLER * tc)454 void Start_Track_Playing(TRACK_CONTROLLER* tc)
455 {
456 GLOBALASSERT(tc);
457 GLOBALASSERT(tc->sbptr);
458 GLOBALASSERT(tc->sbptr->DynPtr);
459
460 if(tc->playing) return;
461
462 tc->playing=1;
463 if(tc->start_sound)
464 {
465 tc->playing_start_sound=1;
466 Start_Track_Sound(tc->start_sound,&tc->sbptr->DynPtr->Position);
467 }
468 else if(tc->sound)
469 {
470 Start_Track_Sound(tc->sound,&tc->sbptr->DynPtr->Position);
471 }
472
473 }
474
Stop_Track_Playing(TRACK_CONTROLLER * tc)475 void Stop_Track_Playing(TRACK_CONTROLLER* tc)
476 {
477 GLOBALASSERT(tc);
478 GLOBALASSERT(tc->sbptr);
479 GLOBALASSERT(tc->sbptr->DynPtr);
480
481 if(!tc->playing) return;
482
483 tc->playing=0;
484 tc->playing_start_sound=0;
485
486 if(tc->sound)
487 {
488 Stop_Track_Sound(tc->sound);
489 }
490 if(tc->start_sound)
491 {
492 Stop_Track_Sound(tc->sound);
493 }
494 if(tc->end_sound)
495 {
496 Start_Track_Sound(tc->end_sound,&tc->sbptr->DynPtr->Position);
497 }
498 }
499
500
Reset_Track(TRACK_CONTROLLER * tc)501 void Reset_Track(TRACK_CONTROLLER* tc)
502 {
503 GLOBALASSERT(tc);
504
505 if(tc->sound)
506 {
507 Stop_Track_Sound(tc->sound);
508 }
509 if(tc->start_sound)
510 {
511 Stop_Track_Sound(tc->start_sound);
512 }
513 if(tc->end_sound)
514 {
515 Stop_Track_Sound(tc->end_sound);
516 }
517 tc->timer=tc->initial_state_timer;
518 tc->playing=tc->initial_state_playing;
519 tc->reverse=tc->initial_state_reverse;
520 tc->current_section=0;
521
522 if(tc->playing && tc->sound)
523 {
524 tc->sound->playing=1;
525 }
526
527 }
528
Deallocate_Track(TRACK_CONTROLLER * tc)529 void Deallocate_Track(TRACK_CONTROLLER* tc)
530 {
531 GLOBALASSERT(tc);
532
533
534 if(tc->sound)
535 {
536 Deallocate_Track_Sound(tc->sound);
537 }
538 if(tc->start_sound)
539 {
540 Deallocate_Track_Sound(tc->start_sound);
541 }
542 if(tc->end_sound)
543 {
544 Deallocate_Track_Sound(tc->end_sound);
545 }
546
547 #if !USE_LEVEL_MEMORY_POOL
548 if(tc->sections) DeallocateMem(tc->sections);
549 DeallocateMem(tc);
550 #endif
551
552 }
553
554
555 /*KJL*******************************************************************
556 * *
557 * Smooth track system - this code overlays cubic splines over the lerp *
558 * and slerp code used by the original track system *
559 * *
560 *******************************************************************KJL*/
Preprocess_Smooth_Track_Controller(TRACK_CONTROLLER * tc)561 static void Preprocess_Smooth_Track_Controller(TRACK_CONTROLLER* tc)
562 {
563 int i;
564 GLOBALASSERT(tc->sections);
565
566 for(i=0;i<tc->num_sections;i++)
567 {
568 TRACK_SECTION_DATA* tsd=&tc->sections[i];
569 tsd->oneovertime=DIV_FIXED(ONE_FIXED,tsd->time_for_section);
570
571 if (i==0)
572 {
573 tsd->quat_prev = tsd->quat_start;
574 tsd->pivot_0 = tsd->pivot_start;
575 tsd->pivot_1 = tsd->pivot_start;
576 tsd->pivot_2 = tc->sections[1].pivot_start;
577 tsd->pivot_3 = tc->sections[2].pivot_start;
578 }
579 else if (i==tc->num_sections-1)
580 {
581 tsd->quat_prev = tc->sections[i-1].quat_start;
582 tsd->pivot_0 = tc->sections[i-1].pivot_1;
583 tsd->pivot_1 = tsd->pivot_start;
584
585 tsd->pivot_2 = tsd->pivot_1;
586 tsd->pivot_2.vx += tsd->pivot_travel.vx;
587 tsd->pivot_2.vy += tsd->pivot_travel.vy;
588 tsd->pivot_2.vz += tsd->pivot_travel.vz;
589
590 tsd->pivot_3 = tsd->pivot_2;
591 }
592 else if (i==tc->num_sections-2)
593 {
594 tsd->quat_prev = tc->sections[i-1].quat_start;
595 tsd->pivot_0 = tc->sections[i-1].pivot_1;
596 tsd->pivot_1 = tsd->pivot_start;
597 tsd->pivot_2 = tc->sections[i+1].pivot_start;
598
599 tsd->pivot_3 = tsd->pivot_2;
600 tsd->pivot_3.vx += tc->sections[i+1].pivot_travel.vx;
601 tsd->pivot_3.vy += tc->sections[i+1].pivot_travel.vy;
602 tsd->pivot_3.vz += tc->sections[i+1].pivot_travel.vz;
603 }
604 else
605 {
606 tsd->quat_prev = tc->sections[i-1].quat_start;
607 tsd->pivot_0 = tc->sections[i-1].pivot_start;
608 tsd->pivot_1 = tsd->pivot_start;
609 tsd->pivot_2 = tc->sections[i+1].pivot_start;
610 tsd->pivot_3 = tc->sections[i+2].pivot_start;
611 }
612 }
613
614 for(i=0;i<tc->num_sections;i++)
615 {
616 TRACK_SECTION_DATA* tsd=&tc->sections[i];
617 if (QDot(&tsd->quat_prev,&tsd->quat_start)<0)
618 {
619 tsd->quat_start.quatx=-tsd->quat_start.quatx;
620 tsd->quat_start.quaty=-tsd->quat_start.quaty;
621 tsd->quat_start.quatz=-tsd->quat_start.quatz;
622 tsd->quat_start.quatw=-tsd->quat_start.quatw;
623 }
624 if (QDot(&tsd->quat_start,&tsd->quat_end)<0)
625 {
626 tsd->quat_end.quatx=-tsd->quat_end.quatx;
627 tsd->quat_end.quaty=-tsd->quat_end.quaty;
628 tsd->quat_end.quatz=-tsd->quat_end.quatz;
629 tsd->quat_end.quatw=-tsd->quat_end.quatw;
630 }
631 MakeControlQuat
632 (
633 &(tsd->quat_start_control),
634 &(tsd->quat_prev),
635 &(tsd->quat_start),
636 &(tsd->quat_end)
637 );
638 }
639 for(i=0;i<tc->num_sections-1;i++)
640 {
641 tc->sections[i].quat_end_control = tc->sections[i+1].quat_start_control;
642 }
643 tc->sections[tc->num_sections-1].quat_end_control = tc->sections[tc->num_sections-1].quat_end;
644 }
645
SmoothTrackPosition(TRACK_SECTION_DATA * trackPtr,int u,VECTORCH * outputPositionPtr)646 static void SmoothTrackPosition(TRACK_SECTION_DATA* trackPtr, int u, VECTORCH *outputPositionPtr)
647 {
648 int u2 = MUL_FIXED(u,u);
649 int u3 = MUL_FIXED(u2,u);
650
651 {
652 int a = (-trackPtr->pivot_0.vx+3*trackPtr->pivot_1.vx-3*trackPtr->pivot_2.vx+trackPtr->pivot_3.vx);
653 int b = (2*trackPtr->pivot_0.vx-5*trackPtr->pivot_1.vx+4*trackPtr->pivot_2.vx-trackPtr->pivot_3.vx);
654 int c = (-1*trackPtr->pivot_0.vx+trackPtr->pivot_2.vx);
655 outputPositionPtr->vx = (MUL_FIXED(a,u3)+MUL_FIXED(b,u2)+MUL_FIXED(c,u))/2+trackPtr->pivot_1.vx;
656 }
657 {
658 int a = (-trackPtr->pivot_0.vy+3*trackPtr->pivot_1.vy-3*trackPtr->pivot_2.vy+trackPtr->pivot_3.vy);
659 int b = (2*trackPtr->pivot_0.vy-5*trackPtr->pivot_1.vy+4*trackPtr->pivot_2.vy-trackPtr->pivot_3.vy);
660 int c = (-1*trackPtr->pivot_0.vy+trackPtr->pivot_2.vy);
661 outputPositionPtr->vy = (MUL_FIXED(a,u3)+MUL_FIXED(b,u2)+MUL_FIXED(c,u))/2+trackPtr->pivot_1.vy;
662 }
663 {
664 int a = (-trackPtr->pivot_0.vz+3*trackPtr->pivot_1.vz-3*trackPtr->pivot_2.vz+trackPtr->pivot_3.vz);
665 int b = (2*trackPtr->pivot_0.vz-5*trackPtr->pivot_1.vz+4*trackPtr->pivot_2.vz-trackPtr->pivot_3.vz);
666 int c = (-1*trackPtr->pivot_0.vz+trackPtr->pivot_2.vz);
667 outputPositionPtr->vz = (MUL_FIXED(a,u3)+MUL_FIXED(b,u2)+MUL_FIXED(c,u))/2+trackPtr->pivot_1.vz;
668 }
669 }
670 #if 0
671
672 static void SmoothTrackPositionBSpline(TRACK_SECTION_DATA* trackPtr, int u, VECTORCH *outputPositionPtr)
673 {
674 int u2 = MUL_FIXED(u,u);
675 int u3 = MUL_FIXED(u2,u);
676
677 {
678 int a = (-trackPtr->pivot_0.vx +3*trackPtr->pivot_1.vx -3*trackPtr->pivot_2.vx +1*trackPtr->pivot_3.vx);
679 int b = (3*trackPtr->pivot_0.vx -6*trackPtr->pivot_1.vx +3*trackPtr->pivot_2.vx +0*trackPtr->pivot_3.vx);
680 int c = (-3*trackPtr->pivot_0.vx +0*trackPtr->pivot_1.vx +3*trackPtr->pivot_2.vx +0*trackPtr->pivot_3.vx);
681 int d = (trackPtr->pivot_0.vx +4*trackPtr->pivot_1.vx +1*trackPtr->pivot_2.vx +0*trackPtr->pivot_3.vx);
682
683 outputPositionPtr->vx = (MUL_FIXED(a,u3)+MUL_FIXED(b,u2)+MUL_FIXED(c,u)+d)/6;
684 }
685 {
686 int a = (-trackPtr->pivot_0.vy +3*trackPtr->pivot_1.vy -3*trackPtr->pivot_2.vy +1*trackPtr->pivot_3.vy);
687 int b = (3*trackPtr->pivot_0.vy -6*trackPtr->pivot_1.vy +3*trackPtr->pivot_2.vy +0*trackPtr->pivot_3.vy);
688 int c = (-3*trackPtr->pivot_0.vy +0*trackPtr->pivot_1.vy +3*trackPtr->pivot_2.vy +0*trackPtr->pivot_3.vy);
689 int d = (trackPtr->pivot_0.vy +4*trackPtr->pivot_1.vy +1*trackPtr->pivot_2.vy +0*trackPtr->pivot_3.vy);
690
691 outputPositionPtr->vy = (MUL_FIXED(a,u3)+MUL_FIXED(b,u2)+MUL_FIXED(c,u)+d)/6;
692 }
693 {
694 int a = (-trackPtr->pivot_0.vz +3*trackPtr->pivot_1.vz -3*trackPtr->pivot_2.vz +1*trackPtr->pivot_3.vz);
695 int b = (3*trackPtr->pivot_0.vz -6*trackPtr->pivot_1.vz +3*trackPtr->pivot_2.vz +0*trackPtr->pivot_3.vz);
696 int c = (-3*trackPtr->pivot_0.vz +0*trackPtr->pivot_1.vz +3*trackPtr->pivot_2.vz +0*trackPtr->pivot_3.vz);
697 int d = (trackPtr->pivot_0.vz +4*trackPtr->pivot_1.vz +1*trackPtr->pivot_2.vz +0*trackPtr->pivot_3.vz);
698
699 outputPositionPtr->vz = (MUL_FIXED(a,u3)+MUL_FIXED(b,u2)+MUL_FIXED(c,u)+d)/6;
700 }
701 }
702
703 #endif
704
SmoothTrackOrientation(TRACK_SECTION_DATA * trackPtr,int lerp,MATRIXCH * outputMatrixPtr)705 static void SmoothTrackOrientation(TRACK_SECTION_DATA* trackPtr, int lerp, MATRIXCH* outputMatrixPtr)
706 {
707 QUAT q1,q2,q3;
708
709 if(lerp<0) lerp=0;
710 if(lerp>65536)lerp=65536;
711
712 BasicSlerp(&trackPtr->quat_start,&trackPtr->quat_end, &q1, lerp);
713 BasicSlerp(&trackPtr->quat_start_control,&trackPtr->quat_end_control, &q2, lerp);
714
715 lerp = MUL_FIXED(ONE_FIXED-lerp,2*lerp);
716 if(lerp<0) lerp=0;
717 if(lerp>65536)lerp=65536;
718
719 BasicSlerp(&q1, &q2, &q3, lerp);
720
721 QuatToMat(&q3,outputMatrixPtr);
722 }
723
BasicSlerp(QUAT * input1,QUAT * input2,QUAT * output,int lerp)724 static void BasicSlerp(QUAT *input1,QUAT *input2,QUAT *output,int lerp)
725 {
726 int sclp,sclq;
727
728 int cosom;
729 int omega, sinom;
730
731 cosom=QDot(input1,input2);
732 if (cosom>0)
733 {
734 *output=*input2;
735 }
736 else
737 {
738 output->quatx=-input2->quatx;
739 output->quaty=-input2->quaty;
740 output->quatz=-input2->quatz;
741 output->quatw=-input2->quatw;
742 cosom =-cosom;
743 }
744
745 if(cosom<65500)
746 {
747 omega=ArcCos(cosom);
748 sinom=GetSin(omega);
749
750 /* healthy paranoia */
751 LOCALASSERT(sinom!=0);
752
753 sclp=DIV_FIXED
754 (
755 GetSin
756 (
757 MUL_FIXED((ONE_FIXED-lerp),omega)
758 ),
759 sinom
760 );
761 sclq=DIV_FIXED
762 (
763 GetSin
764 (
765 MUL_FIXED(lerp,omega)
766 ),
767 sinom
768 );
769 }
770 else
771 {
772 sclp=ONE_FIXED-lerp;
773 sclq=lerp;
774 }
775
776
777 output->quatx=(MUL_FIXED(input1->quatx,sclp))+(MUL_FIXED(output->quatx,sclq));
778 output->quaty=(MUL_FIXED(input1->quaty,sclp))+(MUL_FIXED(output->quaty,sclq));
779 output->quatz=(MUL_FIXED(input1->quatz,sclp))+(MUL_FIXED(output->quatz,sclq));
780 output->quatw=(MUL_FIXED(input1->quatw,sclp))+(MUL_FIXED(output->quatw,sclq));
781 QNormalise(output);
782 }
783
MakeControlQuat(QUAT * control,QUAT * q0,QUAT * q1,QUAT * q2)784 static void MakeControlQuat(QUAT *control, QUAT *q0, QUAT *q1, QUAT *q2)
785 {
786 QUAT a;
787 QUAT b,c;
788
789 a.quatx=-q1->quatx;
790 a.quaty=-q1->quaty;
791 a.quatz=-q1->quatz;
792 a.quatw=q1->quatw;
793
794 MulQuat(&a,q2, &b);
795 MulQuat(&a,q0, &c);
796
797 LnQuat(&b);
798 LnQuat(&c);
799
800 a.quatx = -(b.quatx+c.quatx)/4;
801 a.quaty = -(b.quaty+c.quaty)/4;
802 a.quatz = -(b.quatz+c.quatz)/4;
803
804 ExpPurelyImaginaryQuat(&a);
805 MulQuat(q1,&a, control);
806 }
807
808
809 #include <math.h>
LnQuat(QUAT * q)810 static void LnQuat(QUAT *q)
811 {
812 float theta;
813 float m,x,y,z;
814
815 x = q->quatx;
816 y = q->quaty;
817 z = q->quatz;
818
819 if (x==0 && y==0 && z==0)
820 {
821 q->quatw = 0;
822 q->quatx = 0;
823 q->quaty = 0;
824 q->quatz = 0;
825 return;
826
827 }
828 {
829 double cosine = (q->quatw/65536.0);
830
831 if (cosine > 1.0) cosine = 1.0;
832 else if (cosine < -1.0) cosine = -1.0;
833
834
835 theta = (float)acos(cosine);
836 }
837
838 m = (65536.0/sqrt((x*x) + (y*y) + (z*z)) );
839
840 x *= m;
841 y *= m;
842 z *= m;
843
844 q->quatw = 0;
845 q->quatx = (int)(x*theta);
846 q->quaty = (int)(y*theta);
847 q->quatz = (int)(z*theta);
848 }
ExpPurelyImaginaryQuat(QUAT * q)849 static void ExpPurelyImaginaryQuat(QUAT *q)
850 {
851 float x,y,z;
852 int theta;
853
854 x = q->quatx;
855 y = q->quaty;
856 z = q->quatz;
857
858 if (x!=0||y!=0||z!=0)
859 {
860 float m = sqrt((x*x) + (y*y) + (z*z));
861 x /= m;
862 y /= m;
863 z /= m;
864
865 theta = (int)((m / 16.0) / 6.28318530718);
866
867 q->quatx = (int)(x*(float)GetSin(theta));
868 q->quaty = (int)(y*(float)GetSin(theta));
869 q->quatz = (int)(z*(float)GetSin(theta));
870 q->quatw = GetCos(theta);
871 }
872 else
873 {
874 q->quatx = 0;
875 q->quaty = 0;
876 q->quatz = 0;
877 q->quatw = ONE_FIXED;
878 }
879 QNormalise(q);
880 }
881
882
883 /*--------------------**
884 ** Loading and Saving **
885 **--------------------*/
886 #include "savegame.h"
887 typedef struct track_save_block
888 {
889 SAVE_BLOCK_HEADER header;
890
891 int timer;
892 int speed_mult;
893 int current_section;
894
895 unsigned int playing:1;
896 unsigned int reverse:1;
897 unsigned int no_rotation:1;
898 unsigned int use_speed_mult:1;
899
900 unsigned int start_sound_playing:1;
901 unsigned int mid_sound_playing:1;
902 unsigned int end_sound_playing:1;
903
904 int start_sound_time_left;
905 int mid_sound_time_left;
906 int end_sound_time_left;
907
908 }TRACK_SAVE_BLOCK;
909
910 //defines for load/save macros
911 #define SAVELOAD_BLOCK block
912 #define SAVELOAD_BEHAV tc
913
LoadTrackPosition(SAVE_BLOCK_HEADER * header,TRACK_CONTROLLER * tc)914 void LoadTrackPosition(SAVE_BLOCK_HEADER* header,TRACK_CONTROLLER* tc)
915 {
916 TRACK_SAVE_BLOCK* block = (TRACK_SAVE_BLOCK*)header;
917 if(!header || !tc) return;
918
919 //check the size of the save block
920 if(header->size!=sizeof(*block)) return;
921
922 //start copying stuff
923
924 COPYELEMENT_LOAD(timer)
925 COPYELEMENT_LOAD(speed_mult)
926 COPYELEMENT_LOAD(current_section)
927
928 COPYELEMENT_LOAD(playing)
929 COPYELEMENT_LOAD(reverse)
930 COPYELEMENT_LOAD(no_rotation)
931 COPYELEMENT_LOAD(use_speed_mult)
932
933 Update_Track_Position_Only(tc);
934
935 if(tc->start_sound)
936 {
937 tc->start_sound->playing = block->start_sound_playing;
938 tc->start_sound->time_left = block->start_sound_time_left;
939 }
940 if(tc->sound)
941 {
942 tc->sound->playing = block->mid_sound_playing;
943 tc->sound->time_left = block->mid_sound_time_left;
944 }
945 if(tc->end_sound)
946 {
947 tc->end_sound->playing = block->end_sound_playing;
948 tc->end_sound->time_left = block->end_sound_time_left;
949 }
950
951 if(tc->start_sound) Load_SoundState(&tc->start_sound->activ_no);
952 if(tc->sound) Load_SoundState(&tc->sound->activ_no);
953 if(tc->end_sound) Load_SoundState(&tc->end_sound->activ_no);
954
955
956 }
SaveTrackPosition(TRACK_CONTROLLER * tc)957 void SaveTrackPosition(TRACK_CONTROLLER* tc)
958 {
959 TRACK_SAVE_BLOCK* block;
960 if(!tc) return;
961
962 GET_SAVE_BLOCK_POINTER(block);
963
964 //fill in header
965 block->header.type = SaveBlock_Track;
966 block->header.size = sizeof(*block);
967
968 //start copying stuff
969
970 COPYELEMENT_SAVE(timer)
971 COPYELEMENT_SAVE(speed_mult)
972 COPYELEMENT_SAVE(current_section)
973
974 COPYELEMENT_SAVE(playing)
975 COPYELEMENT_SAVE(reverse)
976 COPYELEMENT_SAVE(no_rotation)
977 COPYELEMENT_SAVE(use_speed_mult)
978
979 if(tc->start_sound)
980 {
981 block->start_sound_playing = tc->start_sound->playing;
982 block->start_sound_time_left = tc->start_sound->time_left;
983 }
984 else
985 {
986 block->start_sound_playing = 0;
987 block->start_sound_time_left = 0;
988 }
989
990 if(tc->sound)
991 {
992 block->mid_sound_playing = tc->sound->playing;
993 block->mid_sound_time_left = tc->sound->time_left;
994 }
995 else
996 {
997 block->mid_sound_playing = 0;
998 block->mid_sound_time_left = 0;
999 }
1000
1001 if(tc->end_sound)
1002 {
1003 block->end_sound_playing = tc->end_sound->playing;
1004 block->end_sound_time_left = tc->end_sound->time_left;
1005 }
1006 else
1007 {
1008 block->end_sound_playing = 0;
1009 block->end_sound_time_left = 0;
1010 }
1011
1012 if(tc->start_sound) Save_SoundState(&tc->start_sound->activ_no);
1013 if(tc->sound) Save_SoundState(&tc->sound->activ_no);
1014 if(tc->end_sound) Save_SoundState(&tc->end_sound->activ_no);
1015
1016 }
1017