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