1 /***** HModel.c *****/
2 /***** CDF 21/10/97 *****/
3
4 #include "3dc.h"
5
6 #include "inline.h"
7 #include "module.h"
8 #include "stratdef.h"
9 #include "gamedef.h"
10 #include "comp_shp.h"
11 #include "dynblock.h"
12 #include "dynamics.h"
13 #include "pfarlocs.h"
14 #include "pheromon.h"
15 #include "bh_types.h"
16 #include "pvisible.h"
17 #include "bh_far.h"
18 #include "bh_debri.h"
19 #include "bh_pred.h"
20 #include "bh_paq.h"
21 #include "bh_queen.h"
22 #include "bh_marin.h"
23 #include "lighting.h"
24 #include "bh_weap.h"
25 #include "weapons.h"
26 #include "psnd.h"
27 #include "load_shp.h"
28 #include "plat_shp.h"
29 #include "avp_userprofile.h"
30 #include "maths.h"
31 #include "opengl.h"
32
33 #define UseLocalAssert Yes
34 #include "ourasert.h"
35 #include "particle.h"
36 #include "kshape.h"
37 #include "sfx.h"
38 #include "dxlog.h"
39 #include <math.h>
40
41 #define AUTODETECT 1
42 #define ADD_ELEVATION_OFFSETS 1
43 #define SPARKS_FOR_A_SPRAY 15
44
45 int Simplify_HModel_Rendering=0;
46
47 extern enum PARTICLE_ID GetBloodType(STRATEGYBLOCK *sbPtr);
48 extern void DoShapeAnimation (DISPLAYBLOCK * dptr);
49 extern void RenderThisHierarchicalDisplayblock(DISPLAYBLOCK *dbPtr);
50 void MatToQuat (MATRIXCH *m, QUAT *quat);
51
52 /* protos for this file */
53 void New_Preprocess_Keyframe(KEYFRAME_DATA *this_keyframe, KEYFRAME_DATA *next_keyframe,int one);
54 void MulQuat(QUAT *q1,QUAT *q2,QUAT *output);
55 void Slerp(KEYFRAME_DATA *input,int lerp,QUAT *output);
56 void Analyse_Tweening_Data(HMODELCONTROLLER *controller,SECTION_DATA *this_section_data,int base_timer,VECTORCH *output_offset,MATRIXCH *output_matrix);
57 static void FindHeatSource_Recursion(HMODELCONTROLLER *controllerPtr, SECTION_DATA *sectionDataPtr);
58 void Budge_HModel(HMODELCONTROLLER *controller,VECTORCH *offset);
59
60 /* external globals */
61 extern int NormalFrameTime;
62 extern int GlobalFrameCounter;
63 extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr;
64
65 int GlobalGoreRate=NORMAL_GORE_RATE;
66 int incIDnum; /* Has to be global. */
67 int GlobalLevelOfDetail_Hierarchical;
68
69 STRATEGYBLOCK *Global_HModel_Sptr;
70 HMODELCONTROLLER *Global_Controller_Ptr;
71 static DISPLAYBLOCK *Global_HModel_DispPtr;
72
73 DAMAGEBLOCK Default_Damageblock = {
74 5, /* Health */
75 0, /* Armour */
76 0, /* IsOnFire */
77 {
78 0, /* Acid Resistant */
79 0, /* Fire Resistant */
80 0, /* Electric Resistant */
81 0, /* Perfect Armour */
82 0, /* Electric Sensitive */
83 0, /* Combustability */
84 0, /* Indestructable */
85 },
86 };
87
88 MATRIXCH Identity_RotMat = {
89 ONE_FIXED,0,0,
90 0,ONE_FIXED,0,
91 0,0,ONE_FIXED,
92 };
93
QNormalise(QUAT * q)94 void QNormalise(QUAT *q)
95 {
96 float nw = q->quatw;
97 float nx = q->quatx;
98 float ny = q->quaty;
99 float nz = q->quatz;
100
101 float m = sqrt(nw*nw+nx*nx+ny*ny+nz*nz);
102
103 if (!m) return;
104
105 m = 65536.0/m;
106
107 f2i(q->quatw,nw * m);
108 f2i(q->quatx,nx * m);
109 f2i(q->quaty,ny * m);
110 f2i(q->quatz,nz * m);
111 }
112
113
GetSequenceID(int sequence_type,int sub_sequence)114 int GetSequenceID(int sequence_type,int sub_sequence) {
115 return( (sub_sequence<<16)+sequence_type);
116 }
117
GetSequencePointer(int sequence_type,int sub_sequence,SECTION * this_section)118 SEQUENCE *GetSequencePointer(int sequence_type,int sub_sequence,SECTION *this_section) {
119
120 int sequence_id,a;
121 SEQUENCE *sequence_pointer;
122
123 sequence_id=GetSequenceID(sequence_type,sub_sequence);
124
125 for (a=0; a<this_section->num_sequences; a++) {
126 if (this_section->sequence_array[a].sequence_id==sequence_id) {
127 sequence_pointer=&(this_section->sequence_array[a]);
128 break;
129 }
130 }
131
132 if (a==this_section->num_sequences) {
133 //textprint("Unknown HModel sequence! %d,%d\n",sequence_type,sub_sequence);
134 return(&(this_section->sequence_array[0]));
135 //GLOBALASSERT(0);
136 //return(NULL);
137 }
138
139 return(sequence_pointer);
140
141 }
142 #if 0
143 void Preprocess_Keyframe(KEYFRAME_DATA *this_keyframe, KEYFRAME_DATA *next_keyframe,int one) {
144 {
145
146 New_Preprocess_Keyframe(this_keyframe,next_keyframe,one);
147 }
148 #endif
QDot(QUAT * this_quat,QUAT * next_quat)149 int QDot(QUAT *this_quat, QUAT *next_quat) {
150
151 int qdot;
152
153 qdot=( (MUL_FIXED(this_quat->quatx,next_quat->quatx)) +
154 (MUL_FIXED(this_quat->quaty,next_quat->quaty)) +
155 (MUL_FIXED(this_quat->quatz,next_quat->quatz)) +
156 (MUL_FIXED(this_quat->quatw,next_quat->quatw)) );
157
158 return(qdot);
159 }
160
New_Preprocess_Keyframe(KEYFRAME_DATA * this_keyframe,KEYFRAME_DATA * next_keyframe,int one)161 void New_Preprocess_Keyframe(KEYFRAME_DATA *this_keyframe, KEYFRAME_DATA *next_keyframe,int one) {
162
163 int cosom;
164 QUAT_SHORT *this_quat, *next_quat;
165
166 LOCALASSERT(this_keyframe);
167 LOCALASSERT(next_keyframe);
168
169 this_quat=&this_keyframe->QOrient;
170 next_quat=&next_keyframe->QOrient;
171
172 //QNormalise(this_quat);
173 //QNormalise(next_quat);
174
175
176 //cosom=QDot(this_quat,next_quat);
177 cosom=( (MUL_FIXED((int)this_quat->quatx,(int)next_quat->quatx)) +
178 (MUL_FIXED((int)this_quat->quaty,(int)next_quat->quaty)) +
179 (MUL_FIXED((int)this_quat->quatz,(int)next_quat->quatz)) +
180 (MUL_FIXED((int)this_quat->quatw,(int)next_quat->quatw)))<<1;
181
182 if (cosom<0) {
183 this_keyframe->slerp_to_negative_quat=1;
184 cosom=-cosom;
185 }
186 else{
187 this_keyframe->slerp_to_negative_quat=0;
188 }
189
190
191 this_keyframe->omega=(unsigned short)ArcCos(cosom);
192
193 GLOBALASSERT(this_keyframe->Sequence_Length>0);
194 this_keyframe->oneoversequencelength=DIV_FIXED(one,(int)this_keyframe->Sequence_Length);
195
196 }
197
Preprocess_Section(SECTION * this_section,char * riffname,VECTORCH * offset_to_return)198 void Preprocess_Section(SECTION *this_section, char *riffname ,VECTORCH* offset_to_return) {
199
200 KEYFRAME_DATA *this_keyframe;
201 VECTORCH cumulative_gore_direction;
202 VECTORCH next_one_down;
203 SECTION_ATTACHMENT *sec_att;
204 int a;
205
206 if (this_section->ShapeName!=NULL) {
207 this_section->ShapeNum=GetLoadedShapeMSL(this_section->ShapeName);
208 if (this_section->ShapeNum==-1) {
209 textprint("\n\n\n\nShape has a name! %s\n",this_section->ShapeName);
210 GLOBALASSERT(0);
211 }
212 this_section->Shape=GetShapeData(this_section->ShapeNum);
213 } else {
214 /* Do nothing, as requested by John. */
215 }
216
217 /* Get section attachment... */
218
219 sec_att=GetThisSectionAttachment(riffname,this_section->Section_Name,this_section->Hierarchy_Name);
220 if (sec_att==NULL) {
221 /* Try for the general one. */
222 sec_att=GetThisSectionAttachment(riffname,this_section->Section_Name,NULL);
223 }
224
225 if (sec_att) {
226 this_section->StartingStats=sec_att->StartingStats;
227 this_section->flags&=~section_is_master_root;
228 this_section->flags|=sec_att->flags;
229 } else {
230 /* Default! */
231 this_section->StartingStats=Default_Stats.StartingStats;
232 this_section->flags|=Default_Stats.flags;
233 }
234
235 /* Now ID number. */
236
237 this_section->IDnumber=incIDnum;
238 incIDnum++;
239
240 /* Okay. */
241
242 for (a=0; a<this_section->num_sequences; a++) {
243
244 int one=0;
245
246 /* Pass through to find sequence length. */
247
248 this_keyframe=this_section->sequence_array[a].first_frame;
249
250 while(1){
251
252 one+=this_keyframe->Sequence_Length;
253
254 /*See if we have got to the end*/
255 if(this_keyframe->last_frame) break;
256 /* Next frame */
257 this_keyframe=this_keyframe->Next_Frame;
258
259 }
260
261 /* Second pass. */
262
263 this_keyframe=this_section->sequence_array[a].first_frame;
264
265 while(1) {
266
267 New_Preprocess_Keyframe(this_keyframe, this_keyframe->Next_Frame,one);
268
269
270 /*See if we have got to the end*/
271 if(this_keyframe->last_frame) break;
272 /* Next frame */
273 this_keyframe=this_keyframe->Next_Frame;
274
275 }
276
277 }
278
279 cumulative_gore_direction.vx=0;
280 cumulative_gore_direction.vy=0;
281 cumulative_gore_direction.vz=0;
282
283 /* Now call recursion... */
284
285 if (this_section->Children!=NULL) {
286 SECTION **child_list_ptr;
287
288 child_list_ptr=this_section->Children;
289
290 while (*child_list_ptr!=NULL) {
291 Preprocess_Section(*child_list_ptr,riffname,&next_one_down);
292 child_list_ptr++;
293
294 cumulative_gore_direction.vx+=next_one_down.vx;
295 cumulative_gore_direction.vy+=next_one_down.vy;
296 cumulative_gore_direction.vz+=next_one_down.vz;
297 }
298 }
299
300 if ( (cumulative_gore_direction.vx==0)
301 && (cumulative_gore_direction.vy==0)
302 && (cumulative_gore_direction.vz==0) ) {
303 /* Darn. Have a default. */
304 cumulative_gore_direction.vx=4096;
305 }
306
307 cumulative_gore_direction.vx=-cumulative_gore_direction.vx;
308 cumulative_gore_direction.vy=-cumulative_gore_direction.vy;
309 cumulative_gore_direction.vz=-cumulative_gore_direction.vz;
310
311 Normalise(&cumulative_gore_direction);
312
313 this_section->gore_spray_direction=cumulative_gore_direction;
314
315 if(offset_to_return)
316 {
317 GetKeyFrameOffset(this_section->sequence_array[0].first_frame,offset_to_return);
318 }
319
320 }
321
Preprocess_HModel(SECTION * root,char * riffname)322 void Preprocess_HModel(SECTION *root, char *riffname) {
323 /* One-time preprocessor, prerocesses the 'deltas' for all sequences. */
324
325 GLOBALASSERT(root); /* Stop messin' about... */
326
327 incIDnum=0;
328 /* Root can't spray gore... */
329 Preprocess_Section(root,riffname,0);
330 root->gore_spray_direction.vx=0;
331 root->gore_spray_direction.vy=0;
332 root->gore_spray_direction.vz=0;
333
334 /* Shouldn't this be set anyway? */
335 root->flags|=section_is_master_root;
336
337 }
338
Setup_Texture_Animation_For_Section(SECTION_DATA * this_section_data)339 void Setup_Texture_Animation_For_Section(SECTION_DATA *this_section_data)
340 {
341 GLOBALASSERT(this_section_data);
342
343 if(this_section_data->tac_ptr)
344 {
345 //get rid of old animation control blocks
346 TXACTRLBLK *tac_next;
347 tac_next=this_section_data->tac_ptr;
348 while (tac_next) {
349 TXACTRLBLK *tac_temp;
350
351 tac_temp=tac_next->tac_next;
352 DeallocateMem(tac_next);
353 tac_next=tac_temp;
354
355 }
356 this_section_data->tac_ptr=0;
357 }
358
359 if (this_section_data->Shape) {
360 if (this_section_data->Shape->shapeflags & ShapeFlag_HasTextureAnimation) {
361
362 TXACTRLBLK **pptxactrlblk;
363 int item_num;
364 int shape_num = this_section_data->ShapeNum;
365 SHAPEHEADER *shptr = GetShapeData(shape_num);
366 pptxactrlblk = &this_section_data->tac_ptr;
367 for(item_num = 0; item_num < shptr->numitems; item_num ++)
368 {
369 POLYHEADER *poly = (POLYHEADER*)(shptr->items[item_num]);
370 LOCALASSERT(poly);
371
372 SetupPolygonFlagAccessForShape(shptr);
373
374 if((Request_PolyFlags((void *)poly)) & iflag_txanim)
375 {
376 TXACTRLBLK *pnew_txactrlblk;
377
378 pnew_txactrlblk = AllocateMem(sizeof(TXACTRLBLK));
379 if(pnew_txactrlblk)
380 {
381 pnew_txactrlblk->tac_flags = 0;
382 pnew_txactrlblk->tac_item = item_num;
383 pnew_txactrlblk->tac_sequence = 0;
384 pnew_txactrlblk->tac_node = 0;
385 pnew_txactrlblk->tac_txarray = GetTxAnimArrayZ(shape_num, item_num);
386 pnew_txactrlblk->tac_txah_s = GetTxAnimHeaderFromShape(pnew_txactrlblk, shape_num);
387
388 *pptxactrlblk = pnew_txactrlblk;
389 pptxactrlblk = &pnew_txactrlblk->tac_next;
390 }
391 else *pptxactrlblk = NULL;
392 }
393 }
394 *pptxactrlblk=0;
395 }
396 }
397 }
398
Create_New_Section(SECTION * this_section)399 SECTION_DATA *Create_New_Section(SECTION *this_section) {
400
401 SECTION_DATA *this_section_data;
402 int num_children;
403
404 if (this_section->ShapeName!=NULL) {
405 this_section->ShapeNum=GetLoadedShapeMSL(this_section->ShapeName);
406 if (this_section->ShapeNum==-1) {
407 GLOBALASSERT(0);
408 }
409 this_section->Shape=GetShapeData(this_section->ShapeNum);
410 } else {
411 /* Do nothing, as requested by John. */
412 }
413
414 /* Create SECTION_DATA. */
415
416 this_section_data=(SECTION_DATA *)AllocateMem(sizeof(SECTION_DATA));
417 GLOBALASSERT(this_section_data);
418
419 this_section_data->sac_ptr=NULL;
420 this_section_data->tac_ptr=NULL;
421 this_section_data->sempai=this_section;
422
423 this_section_data->current_damage.Health=this_section_data->sempai->StartingStats.Health<<16;
424 this_section_data->current_damage.Armour=this_section_data->sempai->StartingStats.Armour<<16;
425 this_section_data->current_damage.SB_H_flags=this_section_data->sempai->StartingStats.SB_H_flags;
426
427 if (this_section_data->current_damage.Health<=0) {
428 /* Wrong! */
429
430 this_section_data->current_damage=Default_Damageblock;
431 }
432
433 this_section_data->my_controller=Global_Controller_Ptr;
434 /* Note not initialised! */
435 this_section_data->flags=0;
436
437 /* KJL 17:04:41 31/07/98 - Decal support */
438 this_section_data->NumberOfDecals = 0;
439 this_section_data->NextDecalToUse = 0;
440
441
442 this_section_data->ShapeNum=this_section->ShapeNum;
443 this_section_data->Shape=this_section->Shape;
444
445 /* This just so it's not uninitialised. */
446 this_section_data->Prev_Sibling=NULL;
447 this_section_data->My_Parent=NULL;
448 this_section_data->Next_Sibling=NULL;
449
450 this_section_data->replacement_id=0;
451
452 /* Init shape animations... */
453
454 #if AUTODETECT
455 if (this_section->Shape) {
456 if (this_section->Shape->animation_header) {
457 #else
458 if (this_section->flags§ion_has_shape_animation) {
459 #endif
460
461 GLOBALASSERT(this_section->Shape->animation_header);
462
463 this_section_data->sac_ptr=AllocateMem(sizeof(SHAPEANIMATIONCONTROLLER));
464
465 InitShapeAnimationController (this_section_data->sac_ptr, this_section->Shape);
466
467 }
468 #if AUTODETECT
469 }
470 #endif
471
472 /* Init texture animations. */
473 this_section_data->tac_ptr=0;
474 Setup_Texture_Animation_For_Section(this_section_data);
475
476 /* Now call recursion... */
477
478 num_children=0;
479
480 if (this_section->Children!=NULL) {
481 SECTION **child_list_ptr;
482 SECTION_DATA *new_child_list_ptr;
483
484 SECTION_DATA *last_child,*first_child;
485
486 last_child=NULL;
487 first_child=NULL;
488
489 /* Create subsections. */
490
491 child_list_ptr=this_section->Children;
492
493 while (*child_list_ptr!=NULL) {
494
495 (new_child_list_ptr)=Create_New_Section(*child_list_ptr);
496
497 (new_child_list_ptr)->Prev_Sibling=last_child;
498 (new_child_list_ptr)->My_Parent=this_section_data;
499 (new_child_list_ptr)->Next_Sibling=NULL; /* For now... */
500
501 if (first_child==NULL) {
502 first_child=new_child_list_ptr;
503 }
504
505 if (last_child) {
506 last_child->Next_Sibling=(new_child_list_ptr);
507 }
508 last_child=(new_child_list_ptr);
509
510 child_list_ptr++;
511 }
512 (new_child_list_ptr)=NULL;
513
514 this_section_data->First_Child=first_child;
515 } else {
516 this_section_data->First_Child=NULL;
517 }
518
519 return(this_section_data);
520
521 }
522
523 void Create_HModel(HMODELCONTROLLER *controller,SECTION *root) {
524
525 /* Connects sequence to controller and must generate
526 the list of section_data structures. */
527
528 GLOBALASSERT(root); /* Stop messin' about... */
529
530 Global_Controller_Ptr=controller;
531
532 controller->Root_Section=root; /* That's a given. */
533 controller->Seconds_For_Sequence=ONE_FIXED;
534 controller->timer_increment=ONE_FIXED;
535 /* Seconds_For_Sequence and timer_increment are dealt with elsewhere. */
536 controller->sequence_timer=0;
537
538 controller->FrameStamp=-1;
539 controller->View_FrameStamp=-1;
540 controller->Computed_Position.vx=0;
541 controller->Computed_Position.vy=0;
542 controller->Computed_Position.vz=0;
543
544 controller->Playing=0;
545 controller->Reversed=0;
546 controller->Looped=0;
547
548 controller->After_Tweening_Sequence_Type=-1;
549 controller->After_Tweening_Sub_Sequence=-1;
550 controller->AT_seconds_for_sequence=ONE_FIXED;
551 controller->AT_sequence_timer=0;
552 controller->Tweening=Controller_NoTweening;
553 controller->LoopAfterTweening=0;
554 controller->StopAfterTweening=0;
555
556 controller->DisableBleeding=0;
557 controller->LockTopSection=0;
558 controller->ZeroRootDisplacement=0;
559 controller->ZeroRootRotation=0;
560 controller->DisableSounds=0;
561
562 /* Controller elevation now removed. All done through delta sequences, 8/4/98. */
563 controller->ElevationTweening=0;
564
565 controller->Deltas=NULL;
566
567 /* Every time a section is preprocessed, it must generate a section_data for
568 itself, and clip it to the last section_data that was generated. */
569
570 controller->section_data=Create_New_Section(controller->Root_Section);
571
572 controller->section_data->Prev_Sibling=NULL;
573 controller->section_data->My_Parent=NULL;
574 controller->section_data->Next_Sibling=NULL;
575
576 if (root->flags§ion_is_master_root) {
577 controller->section_data->flags|=section_data_master_root;
578 }
579
580 }
581
582 void Destructor_Recursion(SECTION_DATA *doomed_section_data) {
583
584 /* Remove other bits. */
585
586 if (doomed_section_data->sac_ptr) {
587 DeallocateMem(doomed_section_data->sac_ptr);
588 }
589
590 if (doomed_section_data->tac_ptr) {
591 TXACTRLBLK *tac_next;
592 tac_next=doomed_section_data->tac_ptr;
593 while (tac_next) {
594 TXACTRLBLK *tac_temp;
595
596 tac_temp=tac_next->tac_next;
597 DeallocateMem(tac_next);
598 tac_next=tac_temp;
599
600 }
601 }
602
603 /* Recurse. */
604
605 if (doomed_section_data->First_Child!=NULL) {
606
607 SECTION_DATA *child_list_ptr;
608
609 child_list_ptr=doomed_section_data->First_Child;
610
611 while (child_list_ptr!=NULL) {
612 /* Remove each child... */
613 /* JH - 19/2/98 store the next sibling so that we don't access dealloced memory */
614 SECTION_DATA * next_sibling_ptr = child_list_ptr->Next_Sibling;
615 Destructor_Recursion(child_list_ptr);
616 child_list_ptr=next_sibling_ptr;
617 }
618
619 }
620
621 /* Now remove the section... */
622
623 DeallocateMem(doomed_section_data);
624
625 }
626
627 void Prune_Section(SECTION_DATA *doomed_section_data) {
628
629 GLOBALASSERT(doomed_section_data);
630 /* Destroys section, and all children. */
631
632 if (doomed_section_data->Prev_Sibling) {
633 GLOBALASSERT(doomed_section_data->Prev_Sibling->Next_Sibling==doomed_section_data);
634 doomed_section_data->Prev_Sibling->Next_Sibling=doomed_section_data->Next_Sibling;
635 }
636
637 if (doomed_section_data->Next_Sibling) {
638 GLOBALASSERT(doomed_section_data->Next_Sibling->Prev_Sibling==doomed_section_data);
639 doomed_section_data->Next_Sibling->Prev_Sibling=doomed_section_data->Prev_Sibling;
640 }
641
642 if (doomed_section_data->My_Parent) {
643 if (doomed_section_data->My_Parent->First_Child==doomed_section_data) {
644 doomed_section_data->My_Parent->First_Child=doomed_section_data->Next_Sibling;
645 }
646 }
647
648 /* Now destroy. */
649 Destructor_Recursion(doomed_section_data);
650
651 }
652
653 void Delete_Deltas_Recursion(DELTA_CONTROLLER *delta_controller) {
654
655 if (delta_controller==NULL) {
656 return;
657 }
658
659 if (delta_controller->next_controller) {
660 Delete_Deltas_Recursion(delta_controller->next_controller);
661 }
662
663 DeallocateMem(delta_controller->id);
664 DeallocateMem(delta_controller);
665
666 }
667
668 void Dispel_HModel(HMODELCONTROLLER *controller) {
669
670 /* For getting rid of the section_data. */
671
672 if (controller->section_data!=NULL) {
673
674 Destructor_Recursion(controller->section_data);
675
676 controller->section_data=NULL;
677
678 }
679
680 Delete_Deltas_Recursion(controller->Deltas);
681
682 }
683
684 void RemoveAllDeltas(HMODELCONTROLLER *controller) {
685
686 /* Pretty self explainatory. */
687 GLOBALASSERT(controller);
688
689 Delete_Deltas_Recursion(controller->Deltas);
690 controller->Deltas=NULL;
691
692 }
693
694 /* SetElevationDeltas removed, 8.4.98. CDF. */
695
696 void Process_Delta_Controller(SECTION_DATA *this_section_data,DELTA_CONTROLLER *delta_controller,VECTORCH *output_offset,QUAT *output_quat) {
697
698 SEQUENCE *delta_sequence;
699 int a;
700 int working_timer,lerp,lastframe_working_timer;
701 KEYFRAME_DATA *this_frame,*next_frame;
702 int sequence_type,sub_sequence,timer;
703
704 if (delta_controller==NULL) {
705 return;
706 }
707
708 sequence_type=delta_controller->sequence_type;
709 sub_sequence=delta_controller->sub_sequence;
710 timer=delta_controller->timer;
711
712 GLOBALASSERT(sequence_type>-1);
713 GLOBALASSERT(sub_sequence>-1);
714
715 delta_sequence=GetSequencePointer(sequence_type,sub_sequence,this_section_data->sempai);
716
717 GLOBALASSERT(delta_sequence);
718
719 /* Final Frame Correction. */
720
721 this_frame=delta_sequence->first_frame;
722
723 a=0;
724
725 while (!this_frame->last_frame) {
726 a+=this_frame->Sequence_Length;
727 this_frame=this_frame->Next_Frame;
728 }
729
730 /* Now a is the 'real' sequence length. */
731
732 working_timer=MUL_FIXED(timer,a);
733
734 lastframe_working_timer=delta_controller->lastframe_timer;
735 lastframe_working_timer=MUL_FIXED(lastframe_working_timer,a);
736
737 /* Now do that thing. */
738
739 this_frame=delta_sequence->first_frame;
740
741 a=0; /* Status flag... */
742
743 while (a==0) {
744 next_frame=this_frame->Next_Frame;
745 if (working_timer>=this_frame->Sequence_Length) {
746 /* We've gone beyond this frame: get next keyframe. */
747 working_timer-=this_frame->Sequence_Length;
748 lastframe_working_timer-=this_frame->Sequence_Length;
749
750 /* Have we looped? */
751 if (this_frame->last_frame) {
752 /* Some deltas are really fast. */
753 this_frame=delta_sequence->first_frame;
754 }
755 else{
756 /* Advance frame... */
757 this_frame=next_frame;
758 }
759
760 if (lastframe_working_timer<=0) {
761 if(this_frame->frame_has_extended_data)
762 {
763 KEYFRAME_DATA_EXTENDED* this_frame_extended=(KEYFRAME_DATA_EXTENDED*) this_frame;
764 /* Check flags... */
765 this_section_data->my_controller->keyframe_flags|=this_frame_extended->flags;
766 /* ...And keyframe sounds... */
767 if (this_frame_extended->sound) {
768 if (this_section_data->my_controller->DisableSounds==0) {
769 PlayHierarchySound(this_frame_extended->sound,&this_section_data->Last_World_Offset);
770 }
771 }
772 }
773 }
774
775 } else {
776 a=1; /* Exit loop with success. */
777 }
778 /* Better make sure the last 'frame' has 65536 length... */
779 }
780
781 /* Now, this_frame and next_frame are set, and working_timer<this_frame->Sequence_Length. */
782 lerp=MUL_FIXED(working_timer,this_frame->oneoversequencelength);
783
784 GetKeyFrameOffset(this_frame,output_offset);
785 if(next_frame->shift_offset)
786 {
787 VECTORCH next_offset;
788 GetKeyFrameOffset(next_frame,&next_offset);
789 output_offset->vx+=MUL_FIXED(next_offset.vx - output_offset->vx,lerp);
790 output_offset->vy+=MUL_FIXED(next_offset.vy - output_offset->vy,lerp);
791 output_offset->vz+=MUL_FIXED(next_offset.vz - output_offset->vz,lerp);
792 }
793 else
794 {
795 output_offset->vx+=MUL_FIXED((int)next_frame->Offset_x - output_offset->vx,lerp);
796 output_offset->vy+=MUL_FIXED((int)next_frame->Offset_y - output_offset->vy,lerp);
797 output_offset->vz+=MUL_FIXED((int)next_frame->Offset_z - output_offset->vz,lerp);
798 }
799
800
801 /* Now deal with orientation. */
802
803
804 Slerp(this_frame,lerp,output_quat);
805
806 delta_controller->lastframe_timer=delta_controller->timer;
807
808 }
809
810 void Handle_Section_Timer(HMODELCONTROLLER *controller,SECTION_DATA *this_section_data,KEYFRAME_DATA *input_frame,int base_timer, int *working_timer) {
811
812 KEYFRAME_DATA *this_frame,*next_frame;
813 int a;
814
815 if (this_section_data->freezeframe_timer!=-1) {
816 (*working_timer)=this_section_data->freezeframe_timer;
817 } else {
818 (*working_timer)=base_timer;
819 }
820
821 if (this_section_data->accumulated_timer>(*working_timer)) {
822 /* We must have looped. Or be reversed.... ! */
823 this_section_data->accumulated_timer=0;
824 this_section_data->current_keyframe=input_frame;
825 if(input_frame->frame_has_extended_data)
826 {
827 /* Check start flags... */
828 KEYFRAME_DATA_EXTENDED* input_frame_extended=(KEYFRAME_DATA_EXTENDED*) input_frame;
829 controller->keyframe_flags|=input_frame_extended->flags;
830 /* And Keyframe Sounds. */
831 if (input_frame_extended->sound) {
832 if (controller->DisableSounds==0) {
833 PlayHierarchySound(input_frame_extended->sound,&this_section_data->World_Offset);
834 }
835 }
836 }
837 }
838
839 this_frame=this_section_data->current_keyframe;
840 (*working_timer)-=this_section_data->accumulated_timer;
841
842 /* Now, a lot like the old way, but we shouldn't need to loop more than once. */
843 /* If we do, we have a game framerate slower than the anim framerate. */
844
845 a=0; /* Status flag... */
846
847 while (a==0) {
848 if (this_frame==NULL) {
849 this_frame=input_frame; // Heaven help us.
850 }
851 if (this_frame->last_frame) {
852 /* Low framerate loop? */
853 next_frame=input_frame;
854 }
855 else{
856 next_frame=this_frame->Next_Frame;
857 }
858
859 if ((*working_timer)>=this_frame->Sequence_Length) {
860 /* We've gone beyond this frame: get next keyframe. */
861 (*working_timer)-=this_frame->Sequence_Length;
862 /* Add sequence length to accumulated_timer. */
863 this_section_data->accumulated_timer+=this_frame->Sequence_Length;
864 /* Advance frame... */
865 this_frame=next_frame;
866 if (controller->Reversed==0) {
867 if(this_frame->frame_has_extended_data)
868 {
869 KEYFRAME_DATA_EXTENDED* this_frame_extended=(KEYFRAME_DATA_EXTENDED*) this_frame;
870 /* Check flags... */
871 controller->keyframe_flags|=this_frame_extended->flags;
872 /* ...And keyframe sounds... */
873 if (this_frame_extended->sound) {
874 if (controller->DisableSounds==0) {
875 PlayHierarchySound(this_frame_extended->sound,&this_section_data->World_Offset);
876 }
877 }
878 }
879 }
880 /* Update current keyframe. */
881 this_section_data->current_keyframe=this_frame;
882 } else {
883 a=1; /* Exit loop with success. */
884 }
885 /* Better make sure the last 'frame' has 65536 length... */
886 }
887
888 if (controller->Reversed) {
889 /* Okay, maybe a bit cheesy. Trigger flags and sounds... */
890 KEYFRAME_DATA *cthis_frame,*cnext_frame;
891 int b,rev_working_timer;
892
893 rev_working_timer=this_section_data->lastframe_timer-this_section_data->accumulated_timer;
894 cthis_frame=this_frame;
895 b=0;
896
897 while (b==0) {
898 if (cthis_frame==NULL) {
899 cthis_frame=input_frame; // Heaven help us.
900 }
901 if (cthis_frame->last_frame) {
902 /* Low framerate loop? */
903 cnext_frame=input_frame;
904 }
905 else{
906 cnext_frame=cthis_frame->Next_Frame;
907 }
908 if (rev_working_timer>=cthis_frame->Sequence_Length) {
909 /* We've gone beyond this frame: get next keyframe. */
910 rev_working_timer-=cthis_frame->Sequence_Length;
911 /* Advance frame... */
912 cthis_frame=cnext_frame;
913 /* Check flags... */
914 if(this_frame->frame_has_extended_data)
915 {
916 KEYFRAME_DATA_EXTENDED* this_frame_extended=(KEYFRAME_DATA_EXTENDED*) this_frame;
917 controller->keyframe_flags|=this_frame_extended->flags;
918 /* ...And keyframe sounds... */
919 if (this_frame_extended->sound) {
920 if (controller->DisableSounds==0) {
921 PlayHierarchySound(this_frame_extended->sound,&this_section_data->World_Offset);
922 }
923 }
924 }
925 } else {
926 b=1; /* Exit loop with success. */
927 }
928 /* Better make sure the last 'frame' has 65536 length... */
929 }
930
931 }
932
933 /* Check for looping? */
934 if (this_frame->last_frame) {
935 if (controller->Looped==0) {
936 /* Stop at last frame. */
937 (*working_timer)=0;
938 }
939 }
940
941 this_section_data->lastframe_timer=base_timer;
942 }
943
944 void New_Analyse_Keyframe_Data(HMODELCONTROLLER *controller,SECTION_DATA *this_section_data,KEYFRAME_DATA *input_frame,int base_timer,VECTORCH *output_offset,MATRIXCH *output_matrix) {
945
946 KEYFRAME_DATA *this_frame;
947 QUAT output_quat;
948 int working_timer,lerp;
949
950 /* This *should* never fire, should it? */
951
952 GLOBALASSERT(input_frame);
953
954 /* Check the input is in a sensible place. */
955 #if 0 //this can't occur anymore with the new way of storing offsets
956 if ( !( (input_frame->Offset.vx<1000000 && input_frame->Offset.vx>-1000000)
957 && (input_frame->Offset.vy<1000000 && input_frame->Offset.vy>-1000000)
958 && (input_frame->Offset.vz<1000000 && input_frame->Offset.vz>-1000000)
959 ) ) {
960
961 LOGDXFMT(("First Tests in NEW_ANALYSE_KEYFRAME_DATA.\n"));
962 if (Global_HModel_Sptr) {
963 LOGDXFMT(("Misplaced object is of type %d\n",Global_HModel_Sptr->I_SBtype));
964 if (Global_HModel_Sptr->SBdptr) {
965 LOGDXFMT(("Object is Near.\n"));
966 } else {
967 LOGDXFMT(("Object is Far.\n"));
968 }
969 } else {
970 LOGDXFMT(("Misplaced object has no SBptr.\n"));
971 }
972 LOGDXFMT(("Name of section: %s\n",this_section_data->sempai->Section_Name));
973 LOGDXFMT(("It was playing sequence: %d,%d\n",controller->Sequence_Type,controller->Sub_Sequence));
974 LOGDXFMT(("Sequence Timer = %d\n",controller->sequence_timer));
975 LOGDXFMT(("Tweening flags %d\n",controller->Tweening));
976
977 if (this_section_data->My_Parent) {
978 LOGDXFMT(("Parent Position %d,%d,%d\n",this_section_data->My_Parent->World_Offset.vx,this_section_data->My_Parent->World_Offset.vy,this_section_data->My_Parent->World_Offset.vz));
979 } else {
980 LOGDXFMT(("No parent.\n"));
981 }
982 LOGDXFMT(("This Position %d,%d,%d\n",this_section_data->World_Offset.vx,this_section_data->World_Offset.vy,this_section_data->World_Offset.vz));
983 LOGDXFMT(("This Keyframe Position %d,%d,%d\n",input_frame->Offset.vx,input_frame->Offset.vy,input_frame->Offset.vz));
984
985 LOCALASSERT(input_frame->Offset.vx<1000000 && input_frame->Offset.vx>-1000000);
986 LOCALASSERT(input_frame->Offset.vy<1000000 && input_frame->Offset.vy>-1000000);
987 LOCALASSERT(input_frame->Offset.vz<1000000 && input_frame->Offset.vz>-1000000);
988
989 }
990 #endif
991
992 /* First find the current frame. */
993
994 if (input_frame->last_frame) {
995 /* This is rigid. */
996 GetKeyFrameOffset(input_frame,output_offset);
997
998 CopyShortQuatToInt(&input_frame->QOrient,&output_quat);
999
1000 /* Elevation gone! Now deltas? */
1001
1002 {
1003 DELTA_CONTROLLER *dcon;
1004 QUAT elevation_quat,temp_quat;
1005 VECTORCH elevation_offset;
1006
1007 dcon=controller->Deltas;
1008
1009 while (dcon) {
1010 if (dcon->Active) {
1011 Process_Delta_Controller(this_section_data,dcon,&elevation_offset,&elevation_quat);
1012 output_offset->vx+=elevation_offset.vx;
1013 output_offset->vy+=elevation_offset.vy;
1014 output_offset->vz+=elevation_offset.vz;
1015
1016 temp_quat.quatw=output_quat.quatw;
1017 temp_quat.quatx=output_quat.quatx;
1018 temp_quat.quaty=output_quat.quaty;
1019 temp_quat.quatz=output_quat.quatz;
1020
1021 MulQuat(&elevation_quat,&temp_quat,&output_quat);
1022 }
1023 dcon=dcon->next_controller;
1024 }
1025 }
1026
1027 QuatToMat(&output_quat,output_matrix);
1028
1029 /* Check the output is in a sensible place. */
1030 if ( !( (output_offset->vx<1000000 && output_offset->vx>-1000000)
1031 && (output_offset->vy<1000000 && output_offset->vy>-1000000)
1032 && (output_offset->vz<1000000 && output_offset->vz>-1000000)
1033 ) ) {
1034 VECTORCH frame_offset;
1035 GetKeyFrameOffset(input_frame,&frame_offset);
1036
1037 LOGDXFMT(("Second Tests in NEW_ANALYSE_KEYFRAME_DATA.\n"));
1038 if (Global_HModel_Sptr) {
1039 LOGDXFMT(("Misplaced object is of type %d\n",Global_HModel_Sptr->I_SBtype));
1040 if (Global_HModel_Sptr->SBdptr) {
1041 LOGDXFMT(("Object is Near.\n"));
1042 } else {
1043 LOGDXFMT(("Object is Far.\n"));
1044 }
1045 } else {
1046 LOGDXFMT(("Misplaced object has no SBptr.\n"));
1047 }
1048 LOGDXFMT(("Name of section: %s\n",this_section_data->sempai->Section_Name));
1049 LOGDXFMT(("It was playing sequence: %d,%d\n",controller->Sequence_Type,controller->Sub_Sequence));
1050 LOGDXFMT(("Sequence Timer = %d\n",controller->sequence_timer));
1051 LOGDXFMT(("Tweening flags %d\n",controller->Tweening));
1052
1053 if (this_section_data->My_Parent) {
1054 LOGDXFMT(("Parent Position %d,%d,%d\n",this_section_data->My_Parent->World_Offset.vx,this_section_data->My_Parent->World_Offset.vy,this_section_data->My_Parent->World_Offset.vz));
1055 } else {
1056 LOGDXFMT(("No parent.\n"));
1057 }
1058 LOGDXFMT(("This Position %d,%d,%d\n",this_section_data->World_Offset.vx,this_section_data->World_Offset.vy,this_section_data->World_Offset.vz));
1059 LOGDXFMT(("This Keyframe Position %d,%d,%d\n",frame_offset.vx,frame_offset.vy,frame_offset.vz));
1060 LOGDXFMT(("Output Offset %d,%d,%d\n",output_offset->vx,output_offset->vy,output_offset->vz));
1061
1062 LOCALASSERT(output_offset->vx<1000000 && output_offset->vx>-1000000);
1063 LOCALASSERT(output_offset->vy<1000000 && output_offset->vy>-1000000);
1064 LOCALASSERT(output_offset->vz<1000000 && output_offset->vz>-1000000);
1065
1066 }
1067
1068 return;
1069 }
1070
1071 /* New way. */
1072
1073 Handle_Section_Timer(controller,this_section_data,input_frame,base_timer,&working_timer);
1074 this_frame=this_section_data->current_keyframe;
1075
1076 /* Now, this_frame and next_frame are set, and working_timer<this_frame->Sequence_Length. */
1077
1078
1079 lerp=MUL_FIXED(working_timer,this_frame->oneoversequencelength);
1080
1081 {
1082 KEYFRAME_DATA* next_frame=this_frame->Next_Frame;
1083
1084 GetKeyFrameOffset(this_frame,output_offset);
1085 if(next_frame->shift_offset)
1086 {
1087 VECTORCH next_offset;
1088 GetKeyFrameOffset(next_frame,&next_offset);
1089 output_offset->vx+=MUL_FIXED(next_offset.vx - output_offset->vx,lerp);
1090 output_offset->vy+=MUL_FIXED(next_offset.vy - output_offset->vy,lerp);
1091 output_offset->vz+=MUL_FIXED(next_offset.vz - output_offset->vz,lerp);
1092 }
1093 else
1094 {
1095 output_offset->vx+=MUL_FIXED((int)next_frame->Offset_x - output_offset->vx,lerp);
1096 output_offset->vy+=MUL_FIXED((int)next_frame->Offset_y - output_offset->vy,lerp);
1097 output_offset->vz+=MUL_FIXED((int)next_frame->Offset_z - output_offset->vz,lerp);
1098 }
1099 }
1100 /* Now deal with orientation. */
1101
1102
1103 Slerp(this_frame,lerp,&output_quat);
1104
1105 /* Elevation gone! Now deltas? */
1106 {
1107 DELTA_CONTROLLER *dcon;
1108 QUAT elevation_quat,temp_quat;
1109 VECTORCH elevation_offset;
1110
1111 dcon=controller->Deltas;
1112
1113 while (dcon) {
1114 if (dcon->Active) {
1115 Process_Delta_Controller(this_section_data,dcon,&elevation_offset,&elevation_quat);
1116 output_offset->vx+=elevation_offset.vx;
1117 output_offset->vy+=elevation_offset.vy;
1118 output_offset->vz+=elevation_offset.vz;
1119
1120 temp_quat.quatw=output_quat.quatw;
1121 temp_quat.quatx=output_quat.quatx;
1122 temp_quat.quaty=output_quat.quaty;
1123 temp_quat.quatz=output_quat.quatz;
1124
1125 MulQuat(&elevation_quat,&temp_quat,&output_quat);
1126 }
1127 dcon=dcon->next_controller;
1128 }
1129 }
1130
1131 QuatToMat(&output_quat,output_matrix);
1132
1133 /* Check the output is in a sensible place. */
1134 if ( !( (output_offset->vx<1000000 && output_offset->vx>-1000000)
1135 && (output_offset->vy<1000000 && output_offset->vy>-1000000)
1136 && (output_offset->vz<1000000 && output_offset->vz>-1000000)
1137 ) ) {
1138
1139 VECTORCH frame_offset;
1140 GetKeyFrameOffset(input_frame,&frame_offset);
1141
1142 LOGDXFMT(("Third Tests in NEW_ANALYSE_KEYFRAME_DATA.\n"));
1143 if (Global_HModel_Sptr) {
1144 LOGDXFMT(("Misplaced object is of type %d\n",Global_HModel_Sptr->I_SBtype));
1145 if (Global_HModel_Sptr->SBdptr) {
1146 LOGDXFMT(("Object is Near.\n"));
1147 } else {
1148 LOGDXFMT(("Object is Far.\n"));
1149 }
1150 } else {
1151 LOGDXFMT(("Misplaced object has no SBptr.\n"));
1152 }
1153 LOGDXFMT(("Name of section: %s\n",this_section_data->sempai->Section_Name));
1154 LOGDXFMT(("It was playing sequence: %d,%d\n",controller->Sequence_Type,controller->Sub_Sequence));
1155 LOGDXFMT(("Sequence Timer = %d\n",controller->sequence_timer));
1156 LOGDXFMT(("Tweening flags %d\n",controller->Tweening));
1157
1158 if (this_section_data->My_Parent) {
1159 LOGDXFMT(("Parent Position %d,%d,%d\n",this_section_data->My_Parent->World_Offset.vx,this_section_data->My_Parent->World_Offset.vy,this_section_data->My_Parent->World_Offset.vz));
1160 } else {
1161 LOGDXFMT(("No parent.\n"));
1162 }
1163 LOGDXFMT(("This Position %d,%d,%d\n",this_section_data->World_Offset.vx,this_section_data->World_Offset.vy,this_section_data->World_Offset.vz));
1164 LOGDXFMT(("This Keyframe Position %d,%d,%d\n",frame_offset.vx,frame_offset.vy,frame_offset.vz));
1165 LOGDXFMT(("Output Offset %d,%d,%d\n",output_offset->vx,output_offset->vy,output_offset->vz));
1166
1167 LOCALASSERT(output_offset->vx<1000000 && output_offset->vx>-1000000);
1168 LOCALASSERT(output_offset->vy<1000000 && output_offset->vy>-1000000);
1169 LOCALASSERT(output_offset->vz<1000000 && output_offset->vz>-1000000);
1170
1171 }
1172
1173 }
1174
1175 SHAPEHEADER *Get_Degraded_Shape(SHAPEHEADER *base_shape)
1176 {
1177 VECTORCH *worldposition,viewposition;
1178 ADAPTIVE_DEGRADATION_DESC *array_ptr;
1179 int lodScale;
1180 extern float CameraZoomScale;
1181
1182 if ((base_shape->shape_degradation_array==NULL)||(Global_HModel_Sptr==NULL)) {
1183 return(base_shape);
1184 }
1185
1186 worldposition=&Global_HModel_Sptr->DynPtr->Position;
1187
1188 MakeVector(worldposition, &Global_VDB_Ptr->VDB_World, &viewposition);
1189 RotateVector(&viewposition, &Global_VDB_Ptr->VDB_Mat);
1190
1191
1192 array_ptr=base_shape->shape_degradation_array;
1193
1194 {
1195 lodScale = (float)GlobalLevelOfDetail_Hierarchical*CameraZoomScale;
1196
1197 }
1198 /* Now walk array. */
1199 {
1200
1201 int objectDistance = viewposition.vz;
1202
1203 if (lodScale!=ONE_FIXED)
1204 {
1205 objectDistance = MUL_FIXED(objectDistance,lodScale);
1206 }
1207 if (objectDistance<=0) objectDistance=1;
1208 f2i(viewposition.vz, viewposition.vz*CameraZoomScale);
1209
1210 /* KJL 12:30:37 09/06/98 - the object distance is scaled by a global variable
1211 so that the level of detail can be changed on the fly.
1212
1213 N.B. The last distance stored in the shape_degradation_array is always zero, so that
1214 the while loop below will always terminate. */
1215 if (!array_ptr->shapeCanBeUsedCloseUp)
1216 {
1217 if(array_ptr->distance<viewposition.vz)
1218 {
1219 return (array_ptr->shape);
1220 }
1221 else
1222 {
1223 array_ptr++;
1224 }
1225
1226 }
1227 while (array_ptr->distance>objectDistance) array_ptr++;
1228 }
1229 /* Should have a valid entry now. */
1230 return(array_ptr->shape);
1231 }
1232
1233 void Process_Section(HMODELCONTROLLER *controller,SECTION_DATA *this_section_data,VECTORCH *parent_position,MATRIXCH *parent_orientation,int frame_timer, int sequence_type, int subsequence, int render) {
1234
1235 KEYFRAME_DATA *sequence_start;
1236 SECTION *this_section;
1237 SEQUENCE *this_sequence;
1238
1239 VECTORCH diagnostic_vector;
1240 int Use_GoreRate;
1241
1242 /* Work out which SECTION to use. */
1243
1244 this_section=this_section_data->sempai;
1245
1246 if (controller!=this_section_data->my_controller) {
1247 LOGDXFMT(("Wrong Controller assert in PROCESS_SECTION.w\n"));
1248 LOGDXFMT(("Name of section: %s\n",this_section_data->sempai->Section_Name));
1249 LOGDXFMT(("It was playing sequence: %d,%d\n",controller->Sequence_Type,controller->Sub_Sequence));
1250 LOGDXFMT(("Sequence Timer = %d\n",controller->sequence_timer));
1251 LOGDXFMT(("Tweening flags %d\n",controller->Tweening));
1252 GLOBALASSERT(controller==this_section_data->my_controller);
1253 }
1254
1255 /* We can't just stop at a terminate_here, because that will
1256 do over the section_data list. */
1257
1258 /* Well, actually, now we can. */
1259
1260 /* Put in a sequence switcher!!! */
1261
1262 /* There now is one. */
1263
1264 /* Quick auto-correction... */
1265 if (frame_timer<0) {
1266 frame_timer=0;
1267 }
1268
1269 if (frame_timer>=65536) {
1270 frame_timer=65535;
1271 }
1272
1273 diagnostic_vector.vx=0;
1274 diagnostic_vector.vy=0;
1275 diagnostic_vector.vz=0;
1276
1277 if ((controller->FrameStamp!=GlobalFrameCounter)
1278 ||((this_section_data->flags§ion_data_initialised)==0)) {
1279
1280 int fake_frame_timer;
1281
1282 /* Positions not computed yet this frame. */
1283
1284 this_sequence=GetSequencePointer(sequence_type,subsequence,this_section);
1285 sequence_start=this_sequence->first_frame;
1286
1287 if ((controller->LockTopSection)&&(this_section_data==controller->section_data)) {
1288 fake_frame_timer=0;
1289 } else {
1290 fake_frame_timer=frame_timer;
1291 }
1292
1293 /* For this section, find the interpolated offset and eulers. */
1294 this_section_data->Last_World_Offset=this_section_data->World_Offset;
1295
1296 if (this_section_data->Tweening) {
1297 Analyse_Tweening_Data(controller,this_section_data,frame_timer,&(this_section_data->World_Offset),&(this_section_data->RelSecMat));
1298 } else {
1299 New_Analyse_Keyframe_Data(controller,this_section_data,sequence_start,fake_frame_timer,&(this_section_data->World_Offset),&(this_section_data->RelSecMat));
1300 }
1301
1302 if ((controller->ZeroRootDisplacement)&&(this_section_data==controller->section_data)) {
1303 this_section_data->World_Offset.vx=0;
1304 this_section_data->World_Offset.vy=0;
1305 this_section_data->World_Offset.vz=0;
1306 }
1307
1308 if ((controller->ZeroRootRotation)&&(this_section_data==controller->section_data)) {
1309 this_section_data->RelSecMat=Identity_RotMat;
1310 }
1311
1312 this_section_data->Offset=this_section_data->World_Offset;
1313
1314 diagnostic_vector=this_section_data->World_Offset;
1315
1316 /* The parent's position will be used with the offset value and rotation
1317 matrix to determine the position of the new section. */
1318
1319 RotateVector(&this_section_data->World_Offset,parent_orientation);
1320 AddVector(parent_position,&(this_section_data->World_Offset));
1321
1322 /* Create the absolute rotation matrix for this section. */
1323 MatrixMultiply(parent_orientation,&(this_section_data->RelSecMat),&(this_section_data->SecMat));
1324
1325 /* Set the initialised flag... */
1326 this_section_data->flags|=section_data_initialised;
1327 }
1328
1329 /* Check the object is in a sensible place. */
1330 if ( !( (this_section_data->World_Offset.vx<1000000 && this_section_data->World_Offset.vx>-1000000)
1331 && (this_section_data->World_Offset.vy<1000000 && this_section_data->World_Offset.vy>-1000000)
1332 && (this_section_data->World_Offset.vz<1000000 && this_section_data->World_Offset.vz>-1000000)
1333 ) ) {
1334
1335 LOGDXFMT(("Tests in PROCESS_SECTION.\n"));
1336 if (Global_HModel_Sptr) {
1337 LOGDXFMT(("Misplaced object is of type %d\n",Global_HModel_Sptr->I_SBtype));
1338 if (Global_HModel_Sptr->SBdptr) {
1339 LOGDXFMT(("Object is Near.\n"));
1340 } else {
1341 LOGDXFMT(("Object is Far.\n"));
1342 }
1343 } else {
1344 LOGDXFMT(("Misplaced object has no SBptr.\n"));
1345 }
1346 LOGDXFMT(("Name of section: %s\n",this_section_data->sempai->Section_Name));
1347 LOGDXFMT(("It was playing sequence: %d,%d\n",controller->Sequence_Type,controller->Sub_Sequence));
1348 LOGDXFMT(("Sequence Timer = %d\n",controller->sequence_timer));
1349 LOGDXFMT(("Tweening flags %d\n",controller->Tweening));
1350
1351 LOGDXFMT(("Diagnostic Vector %d,%d,%d\n",diagnostic_vector.vx,diagnostic_vector.vy,diagnostic_vector.vz));
1352 LOGDXFMT(("Parent Orientation Matrix: %d,%d,%d\n",parent_orientation->mat11,parent_orientation->mat12,parent_orientation->mat13));
1353 LOGDXFMT(("Parent Orientation Matrix: %d,%d,%d\n",parent_orientation->mat21,parent_orientation->mat22,parent_orientation->mat23));
1354 LOGDXFMT(("Parent Orientation Matrix: %d,%d,%d\n",parent_orientation->mat31,parent_orientation->mat32,parent_orientation->mat33));
1355
1356 LOGDXFMT(("Parent Position %d,%d,%d\n",parent_position->vx,parent_position->vy,parent_position->vz));
1357 LOGDXFMT(("This Position %d,%d,%d\n",this_section_data->World_Offset.vx,this_section_data->World_Offset.vy,this_section_data->World_Offset.vz));
1358
1359 LOCALASSERT(this_section_data->World_Offset.vx<1000000 && this_section_data->World_Offset.vx>-1000000);
1360 LOCALASSERT(this_section_data->World_Offset.vy<1000000 && this_section_data->World_Offset.vy>-1000000);
1361 LOCALASSERT(this_section_data->World_Offset.vz<1000000 && this_section_data->World_Offset.vz>-1000000);
1362
1363 }
1364
1365 /* Now call recursion... */
1366
1367 if ((this_section_data->First_Child!=NULL)
1368 &&( (this_section_data->flags§ion_data_terminate_here)==0)) {
1369
1370 SECTION_DATA *child_ptr;
1371
1372 child_ptr=this_section_data->First_Child;
1373
1374 while (child_ptr!=NULL) {
1375
1376 LOCALASSERT(child_ptr->My_Parent==this_section_data);
1377
1378 Process_Section(controller,child_ptr,&(this_section_data->World_Offset),&(this_section_data->SecMat),frame_timer,sequence_type,subsequence,render);
1379 child_ptr=child_ptr->Next_Sibling;
1380 }
1381
1382 }
1383
1384 /* Finally, if this section has a shape, and we are rendering, render it. */
1385
1386 if ((this_section_data->Shape!=NULL)&&((this_section_data->flags§ion_data_notreal)==0)
1387 &&(render)) {
1388 /* Unreal things don't get plotted, either. */
1389
1390 DISPLAYBLOCK dummy_displayblock;
1391 SHAPEHEADER *shape_to_use;
1392
1393 GLOBALASSERT(this_section_data->ShapeNum);
1394
1395 /* Decide what shape to use. */
1396
1397 if (this_section_data->Shape) {
1398 if (this_section_data->Shape->shape_degradation_array==NULL) {
1399 shape_to_use=this_section_data->Shape;
1400 } else {
1401 shape_to_use=Get_Degraded_Shape(this_section_data->Shape);
1402 }
1403 } else {
1404 shape_to_use=NULL;
1405 }
1406
1407 /* This really needs to be pre-zeroed, a static
1408 in this file... but not yet. */
1409
1410 if (Simplify_HModel_Rendering) {
1411 dummy_displayblock.ObShape=GetLoadedShapeMSL("Shell");
1412 dummy_displayblock.ObShapeData=GetShapeData(dummy_displayblock.ObShape);
1413 } else {
1414 dummy_displayblock.ObShape=this_section_data->ShapeNum;
1415 dummy_displayblock.ObShapeData=shape_to_use;
1416 }
1417 dummy_displayblock.name=NULL;
1418 dummy_displayblock.ObWorld=this_section_data->World_Offset;
1419 dummy_displayblock.ObEuler.EulerX=0;
1420 dummy_displayblock.ObEuler.EulerY=0;
1421 dummy_displayblock.ObEuler.EulerZ=0;
1422 dummy_displayblock.ObMat=this_section_data->SecMat;
1423 dummy_displayblock.ObFlags=ObFlag_VertexHazing|ObFlag_MultLSrc;
1424 dummy_displayblock.ObFlags2=Global_HModel_DispPtr->ObFlags2;
1425 dummy_displayblock.ObFlags3=0;
1426 dummy_displayblock.ObNumLights=0;
1427 dummy_displayblock.ObVDBPtr=NULL;
1428 if(shape_to_use)
1429 dummy_displayblock.ObRadius=shape_to_use->shaperadius;
1430 else
1431 dummy_displayblock.ObRadius=0;
1432 dummy_displayblock.ObMaxX=0;
1433 dummy_displayblock.ObMinX=0;
1434 dummy_displayblock.ObMaxY=0;
1435 dummy_displayblock.ObMinY=0;
1436 dummy_displayblock.ObMaxZ=0;
1437 dummy_displayblock.ObMinZ=0;
1438 dummy_displayblock.ObTxAnimCtrlBlks=this_section_data->tac_ptr;
1439 dummy_displayblock.ObEIDPtr=NULL;
1440 dummy_displayblock.ObMorphCtrl=NULL;
1441 dummy_displayblock.ObStrategyBlock=Global_HModel_Sptr;
1442 dummy_displayblock.ShapeAnimControlBlock=this_section_data->sac_ptr;
1443 dummy_displayblock.HModelControlBlock=NULL; /* Don't even want to think about that. */
1444 dummy_displayblock.ObMyModule=NULL;
1445 dummy_displayblock.SpecialFXFlags = Global_HModel_DispPtr->SpecialFXFlags;
1446
1447 MakeVector(&dummy_displayblock.ObWorld, &Global_VDB_Ptr->VDB_World, &dummy_displayblock.ObView);
1448 RotateVector(&dummy_displayblock.ObView, &Global_VDB_Ptr->VDB_Mat);
1449
1450 /* Whilst we're here... */
1451
1452 this_section_data->View_Offset=dummy_displayblock.ObView;
1453 this_section_data->flags|=section_data_view_init;
1454 controller->View_FrameStamp=GlobalFrameCounter;
1455
1456 /* Ho hum. */
1457
1458 if (dummy_displayblock.ShapeAnimControlBlock) {
1459 DoShapeAnimation(&dummy_displayblock);
1460 }
1461
1462 if(this_section->flags&(section_flag_heatsource|section_flag_affectedbyheat))
1463 {
1464 dummy_displayblock.SpecialFXFlags|=SFXFLAG_ISAFFECTEDBYHEAT;
1465 }
1466
1467 #if 1
1468 if (PIPECLEANER_CHEATMODE)
1469 if (Global_HModel_Sptr)
1470 if (Global_HModel_Sptr->SBdptr)
1471 if (! ((Global_HModel_Sptr->SBdptr->ObWorld.vx == parent_position->vx)
1472 &&(Global_HModel_Sptr->SBdptr->ObWorld.vy == parent_position->vy)
1473 &&(Global_HModel_Sptr->SBdptr->ObWorld.vz == parent_position->vz)) )
1474 {
1475 PARTICLE particle;
1476
1477 particle.Colour = 0xffffffff;
1478 particle.Size = 30;
1479
1480 particle.ParticleID = PARTICLE_LASERBEAM;
1481 particle.Position = this_section_data->World_Offset;
1482 particle.Offset = *parent_position;;
1483
1484 D3D_DecalSystem_Setup();
1485 RenderParticle(&particle);
1486
1487 particle.ParticleID=PARTICLE_ANDROID_BLOOD;
1488
1489 particle.Size = shape_to_use->shaperadius/8;
1490 RenderParticle(&particle);
1491 D3D_DecalSystem_End();
1492
1493 }
1494 #endif
1495
1496 RenderThisHierarchicalDisplayblock(&dummy_displayblock);
1497
1498 } else if (controller->View_FrameStamp!=GlobalFrameCounter) {
1499 this_section_data->flags&=(~section_data_view_init);
1500 }
1501
1502 /* Gore spray... */
1503
1504 if (GlobalGoreRate==0) return;
1505 if (NumberOfBloodParticles>=MAX_NO_OF_BLOOD_PARTICLES) return;
1506 if (controller->DisableBleeding) return;
1507
1508 Use_GoreRate=GlobalGoreRate;
1509 if (SUPERGORE_MODE) {
1510 Use_GoreRate/=5;
1511 }
1512
1513 /* A terminator must spray (backwards) from the origin, to be the stump. */
1514
1515 if (this_section_data->flags§ion_data_terminate_here) {
1516 if (this_section->flags§ion_sprays_anything) {
1517 /* Check for non-zero spray direction... */
1518 if ( (this_section->gore_spray_direction.vx!=0)
1519 || (this_section->gore_spray_direction.vy!=0)
1520 || (this_section->gore_spray_direction.vz!=0) ) {
1521
1522 this_section_data->gore_timer+=NormalFrameTime;
1523
1524 /* New and Special Sparks Code! 16/7/98 */
1525 if (this_section->flags§ion_sprays_sparks) {
1526 while (this_section_data->gore_timer>(GlobalGoreRate*SPARKS_FOR_A_SPRAY)) {
1527
1528 VECTORCH final_spray_direction;
1529 MATRIXCH spray_orient;
1530 /* Spray is go! */
1531
1532 RotateAndCopyVector(&this_section->gore_spray_direction,&final_spray_direction,&this_section_data->SecMat);
1533
1534 /* Reverse direction for stumps. */
1535
1536 final_spray_direction.vx=-final_spray_direction.vx;
1537 final_spray_direction.vy=-final_spray_direction.vy;
1538 final_spray_direction.vz=-final_spray_direction.vz;
1539
1540 /* Scale down. */
1541
1542 final_spray_direction.vx>>=5;
1543 final_spray_direction.vy>>=5;
1544 final_spray_direction.vz>>=5;
1545
1546 /* Add random element. */
1547
1548 final_spray_direction.vx+=( (FastRandom()&1023)-512);
1549 final_spray_direction.vy+=( (FastRandom()&1023)-512);
1550 final_spray_direction.vz+=( (FastRandom()&1023)-512);
1551
1552 Normalise(&final_spray_direction);
1553 /* Now convert back to a matrix. */
1554 MakeMatrixFromDirection(&final_spray_direction,&spray_orient);
1555
1556 /* Call spray function. */
1557
1558 MakeSprayOfSparks(&spray_orient,&this_section_data->World_Offset);
1559
1560 Sound_Play(SID_SPARKS,"d",&this_section_data->World_Offset);
1561
1562 this_section_data->gore_timer-=(GlobalGoreRate*SPARKS_FOR_A_SPRAY);
1563 }
1564 GLOBALASSERT(this_section_data->gore_timer<=(GlobalGoreRate*SPARKS_FOR_A_SPRAY));
1565 } else {
1566 while (this_section_data->gore_timer>Use_GoreRate) {
1567
1568 VECTORCH final_spray_direction;
1569 enum PARTICLE_ID blood_type;
1570 /* Spray is go! */
1571
1572 RotateAndCopyVector(&this_section->gore_spray_direction,&final_spray_direction,&this_section_data->SecMat);
1573
1574 /* Reverse direction for stumps. */
1575
1576 final_spray_direction.vx=-final_spray_direction.vx;
1577 final_spray_direction.vy=-final_spray_direction.vy;
1578 final_spray_direction.vz=-final_spray_direction.vz;
1579
1580 /* Scale down. */
1581
1582 final_spray_direction.vx>>=5;
1583 final_spray_direction.vy>>=5;
1584 final_spray_direction.vz>>=5;
1585
1586 /* Add random element. */
1587
1588 final_spray_direction.vx+=( (FastRandom()&1023)-512);
1589 final_spray_direction.vy+=( (FastRandom()&1023)-512);
1590 final_spray_direction.vz+=( (FastRandom()&1023)-512);
1591
1592 if (SUPERGORE_MODE) {
1593 final_spray_direction.vx<<=1;
1594 final_spray_direction.vy<<=1;
1595 final_spray_direction.vz<<=1;
1596 }
1597
1598 /* Identify spray type. */
1599
1600 if (this_section->flags§ion_sprays_blood) {
1601 blood_type=GetBloodType(Global_HModel_Sptr);
1602 /* Er... default? */
1603 } else if (this_section->flags§ion_sprays_acid) {
1604 blood_type=PARTICLE_ALIEN_BLOOD;
1605 } else if (this_section->flags§ion_sprays_predoblood) {
1606 blood_type=PARTICLE_PREDATOR_BLOOD;
1607 } else if (this_section->flags§ion_sprays_sparks) {
1608 blood_type=PARTICLE_SPARK;
1609 } else {
1610 blood_type=PARTICLE_FLAME;
1611 /* Distinctive. */
1612 }
1613
1614 /* Call spray function. */
1615
1616 MakeParticle(&this_section_data->World_Offset, &final_spray_direction, blood_type);
1617
1618 this_section_data->gore_timer-=Use_GoreRate;
1619 }
1620 }
1621 }
1622 }
1623 }
1624
1625 /* A false root must also spray from the origin... to be the missing part. */
1626
1627 if (this_section_data->flags§ion_data_false_root) {
1628 if (this_section->flags§ion_sprays_anything) {
1629 /* Check for non-zero spray direction... */
1630 if ( (this_section->gore_spray_direction.vx!=0)
1631 || (this_section->gore_spray_direction.vy!=0)
1632 || (this_section->gore_spray_direction.vz!=0) ) {
1633
1634 this_section_data->gore_timer+=NormalFrameTime;
1635
1636 /* I don't *think* a section can be both... */
1637 /* But if it is, we'll just have to live with it. */
1638
1639 /* New and Special Sparks Code! 16/7/98 */
1640 if (this_section->flags§ion_sprays_sparks) {
1641 while (this_section_data->gore_timer>(GlobalGoreRate*SPARKS_FOR_A_SPRAY)) {
1642
1643 VECTORCH final_spray_direction;
1644 MATRIXCH spray_orient;
1645
1646 /* Spray is go! */
1647
1648 RotateAndCopyVector(&this_section->gore_spray_direction,&final_spray_direction,&this_section_data->SecMat);
1649
1650 /* Scale down. */
1651
1652 final_spray_direction.vx>>=5;
1653 final_spray_direction.vy>>=5;
1654 final_spray_direction.vz>>=5;
1655
1656 /* Add random element. */
1657
1658 final_spray_direction.vx+=( (FastRandom()&1023)-512);
1659 final_spray_direction.vy+=( (FastRandom()&1023)-512);
1660 final_spray_direction.vz+=( (FastRandom()&1023)-512);
1661 Normalise(&final_spray_direction);
1662
1663 /* Now convert back to a matrix. */
1664 MakeMatrixFromDirection(&final_spray_direction,&spray_orient);
1665
1666 /* Call spray function. */
1667
1668 MakeSprayOfSparks(&spray_orient,&this_section_data->World_Offset);
1669
1670 Sound_Play(SID_SPARKS,"d",&this_section_data->World_Offset);
1671
1672 this_section_data->gore_timer-=(GlobalGoreRate*SPARKS_FOR_A_SPRAY);
1673 }
1674 GLOBALASSERT(this_section_data->gore_timer<=(GlobalGoreRate*SPARKS_FOR_A_SPRAY));
1675 } else {
1676
1677 while (this_section_data->gore_timer>Use_GoreRate) {
1678
1679 enum PARTICLE_ID blood_type;
1680 VECTORCH final_spray_direction;
1681 /* Spray is go! */
1682
1683 RotateAndCopyVector(&this_section->gore_spray_direction,&final_spray_direction,&this_section_data->SecMat);
1684
1685 /* Scale down. */
1686
1687 final_spray_direction.vx>>=5;
1688 final_spray_direction.vy>>=5;
1689 final_spray_direction.vz>>=5;
1690
1691 /* Add random element. */
1692
1693 final_spray_direction.vx+=( (FastRandom()&1023)-512);
1694 final_spray_direction.vy+=( (FastRandom()&1023)-512);
1695 final_spray_direction.vz+=( (FastRandom()&1023)-512);
1696
1697 if (SUPERGORE_MODE) {
1698 final_spray_direction.vx<<=1;
1699 final_spray_direction.vy<<=1;
1700 final_spray_direction.vz<<=1;
1701 }
1702
1703 /* Identify spray type. */
1704
1705 if (this_section->flags§ion_sprays_blood) {
1706 blood_type=GetBloodType(Global_HModel_Sptr);
1707 /* Er... default? */
1708 } else if (this_section->flags§ion_sprays_acid) {
1709 blood_type=PARTICLE_ALIEN_BLOOD;
1710 } else if (this_section->flags§ion_sprays_predoblood) {
1711 blood_type=PARTICLE_PREDATOR_BLOOD;
1712 } else if (this_section->flags§ion_sprays_sparks) {
1713 blood_type=PARTICLE_SPARK;
1714 } else {
1715 blood_type=PARTICLE_FLAME;
1716 /* Distinctive. */
1717 }
1718
1719 /* Call spray function. */
1720
1721 MakeParticle(&this_section_data->World_Offset, &final_spray_direction, blood_type);
1722
1723 this_section_data->gore_timer-=Use_GoreRate;
1724 }
1725 }
1726 }
1727 }
1728 }
1729
1730 /* Part three... wounded section. */
1731
1732 if (this_section_data->current_damage.Health<(this_section->StartingStats.Health<<ONE_FIXED_SHIFT)) {
1733 if (this_section->flags§ion_sprays_anything) {
1734 int bleeding_rate;
1735
1736 if (this_section_data->current_damage.Health==0) {
1737 /* Bleed a lot. */
1738 bleeding_rate=Use_GoreRate;
1739 } else {
1740 /* Just bleed a bit. */
1741 bleeding_rate=(Use_GoreRate<<1);
1742 }
1743
1744 /* Don't care about non-zero spray direction here. */
1745
1746 this_section_data->gore_timer+=NormalFrameTime;
1747
1748 /* I don't *think* a section can be both... */
1749 /* But if it is, we'll just have to live with it. */
1750
1751 /* New and Special Sparks Code! 16/7/98 */
1752 if (this_section->flags§ion_sprays_sparks) {
1753 while (this_section_data->gore_timer>(bleeding_rate*SPARKS_FOR_A_SPRAY)) {
1754
1755 VECTORCH final_spray_direction;
1756 MATRIXCH spray_orient;
1757
1758 /* Spray is go! */
1759
1760 /* Zero base direction. */
1761
1762 final_spray_direction.vx=0;
1763 final_spray_direction.vy=0;
1764 final_spray_direction.vz=0;
1765
1766 /* Add random element. */
1767
1768 while ( (final_spray_direction.vx==0)
1769 &&(final_spray_direction.vy==0)
1770 &&(final_spray_direction.vz==0)) {
1771 final_spray_direction.vx+=( (FastRandom()&1023)-512);
1772 final_spray_direction.vy+=( (FastRandom()&1023)-512);
1773 final_spray_direction.vz+=( (FastRandom()&1023)-512);
1774 }
1775 Normalise(&final_spray_direction);
1776
1777 /* Now convert back to a matrix. */
1778 MakeMatrixFromDirection(&final_spray_direction,&spray_orient);
1779
1780 /* Call spray function. */
1781
1782 MakeSprayOfSparks(&spray_orient,&this_section_data->World_Offset);
1783
1784 Sound_Play(SID_SPARKS,"d",&this_section_data->World_Offset);
1785
1786 this_section_data->gore_timer-=(bleeding_rate*SPARKS_FOR_A_SPRAY);
1787 }
1788 GLOBALASSERT(this_section_data->gore_timer<=(bleeding_rate*SPARKS_FOR_A_SPRAY));
1789 } else {
1790
1791 while (this_section_data->gore_timer>bleeding_rate) {
1792
1793 enum PARTICLE_ID blood_type;
1794 VECTORCH final_spray_direction;
1795 /* Spray is go! */
1796
1797 /* Zero base direction. */
1798
1799 final_spray_direction.vx=0;
1800 final_spray_direction.vy=0;
1801 final_spray_direction.vz=0;
1802
1803 /* Add random element. */
1804
1805 final_spray_direction.vx+=( (FastRandom()&1023)-512);
1806 final_spray_direction.vy+=( (FastRandom()&1023)-512);
1807 final_spray_direction.vz+=( (FastRandom()&1023)-512);
1808
1809 /* Identify spray type. */
1810
1811 if (this_section->flags§ion_sprays_blood) {
1812 blood_type=GetBloodType(Global_HModel_Sptr);
1813 /* Er... default? */
1814 } else if (this_section->flags§ion_sprays_acid) {
1815 blood_type=PARTICLE_ALIEN_BLOOD;
1816 } else if (this_section->flags§ion_sprays_predoblood) {
1817 blood_type=PARTICLE_PREDATOR_BLOOD;
1818 } else if (this_section->flags§ion_sprays_sparks) {
1819 blood_type=PARTICLE_SPARK;
1820 } else {
1821 blood_type=PARTICLE_FLAME;
1822 /* Distinctive. */
1823 }
1824
1825 /* Call spray function. */
1826
1827 MakeParticle(&this_section_data->World_Offset, &final_spray_direction, blood_type);
1828
1829 this_section_data->gore_timer-=bleeding_rate;
1830 }
1831 GLOBALASSERT(this_section_data->gore_timer<=bleeding_rate);
1832 }
1833 }
1834 }
1835
1836 }
1837
1838 void Init_Sequence_Recursion(SECTION_DATA *this_section_data, int sequence_type,int subsequence, int seconds_for_sequence) {
1839
1840 SEQUENCE *sequence_ptr;
1841
1842 sequence_ptr=GetSequencePointer(sequence_type,subsequence,this_section_data->sempai);
1843
1844 /* Init fields. */
1845
1846 this_section_data->current_sequence=sequence_ptr;
1847 this_section_data->current_keyframe=sequence_ptr->first_frame;
1848 this_section_data->accumulated_timer=0;
1849 this_section_data->freezeframe_timer=-1;
1850 this_section_data->lastframe_timer=0;
1851 this_section_data->gore_timer=0; /* As good a time as any. */
1852
1853 /* Zero last world offset, just for the record. */
1854 this_section_data->Last_World_Offset.vx=0;
1855 this_section_data->Last_World_Offset.vy=0;
1856 this_section_data->Last_World_Offset.vz=0;
1857
1858 /* Deinit tweening. */
1859
1860 this_section_data->Tweening=0;
1861
1862 /* Keyframe and Sound Flags. */
1863 if(sequence_ptr->first_frame->frame_has_extended_data)
1864 {
1865 KEYFRAME_DATA_EXTENDED* first_frame_extended=(KEYFRAME_DATA_EXTENDED*) sequence_ptr->first_frame;
1866 this_section_data->my_controller->keyframe_flags|=first_frame_extended->flags;
1867 if (first_frame_extended->sound) {
1868 if (this_section_data->flags§ion_data_initialised) {
1869 if (this_section_data->my_controller->DisableSounds==0) {
1870 PlayHierarchySound(first_frame_extended->sound,&this_section_data->World_Offset);
1871 }
1872 }
1873 }
1874 }
1875 /* Animation. */
1876
1877 if (this_section_data->sac_ptr) {
1878
1879 SHAPEANIMATIONCONTROLDATA sacd ;
1880 SHAPEANIMATIONSEQUENCE *sequence_pointer;
1881 int num_frames,sequence;
1882
1883 sequence=(sequence_type<<16)+subsequence;
1884
1885 InitShapeAnimationControlData(&sacd);
1886 /* Compute rate. */
1887
1888 sequence_pointer=this_section_data->sac_ptr->anim_header->anim_sequences;
1889 GLOBALASSERT(sequence<this_section_data->sac_ptr->anim_header->num_sequences);
1890 num_frames=sequence_pointer[sequence].num_frames;
1891
1892 sacd.seconds_per_frame = seconds_for_sequence/num_frames;
1893 /* Okay. */
1894 sacd.sequence_no = sequence;
1895 sacd.default_start_and_end_frames = 1;
1896 sacd.reversed = 0;
1897 sacd.stop_at_end = 0;
1898 SetOrphanedShapeAnimationSequence (this_section_data->sac_ptr, &sacd);
1899
1900 }
1901
1902 /* Recurse. */
1903
1904 if ( (this_section_data->First_Child!=NULL)
1905 &&( (this_section_data->flags§ion_data_terminate_here)==0)) {
1906 /* Respect the terminator! */
1907
1908 SECTION_DATA *child_list_ptr;
1909
1910 child_list_ptr=this_section_data->First_Child;
1911
1912 while (child_list_ptr!=NULL) {
1913 Init_Sequence_Recursion(child_list_ptr,sequence_type,subsequence,seconds_for_sequence);
1914 child_list_ptr=child_list_ptr->Next_Sibling;
1915 }
1916
1917 }
1918
1919 }
1920
1921 void HModel_ChangeSpeed(HMODELCONTROLLER *controller, int seconds_for_sequence) {
1922
1923 /* Simple enough... */
1924
1925 controller->Seconds_For_Sequence=seconds_for_sequence;
1926 controller->timer_increment=DIV_FIXED(ONE_FIXED,controller->Seconds_For_Sequence);
1927
1928 }
1929
1930 void HModel_SetToolsRelativeSpeed(HMODELCONTROLLER *controller, int factor) {
1931
1932 KEYFRAME_DATA *sequence_start;
1933 SEQUENCE *this_sequence;
1934 int real_time;
1935
1936 GLOBALASSERT(controller);
1937 GLOBALASSERT(factor>0);
1938 /* Find the tools speed for this sequence... */
1939
1940 this_sequence=GetSequencePointer(controller->Sequence_Type,controller->Sub_Sequence,controller->Root_Section);
1941 sequence_start=this_sequence->first_frame;
1942 GLOBALASSERT(sequence_start);
1943
1944 real_time=this_sequence->Time;
1945 if (real_time<=0) {
1946 real_time=ONE_FIXED;
1947 /* Might want to assert here? */
1948 }
1949
1950 real_time=MUL_FIXED(real_time,factor);
1951 HModel_ChangeSpeed(controller,real_time);
1952
1953 }
1954
1955 void InitHModelSequence(HMODELCONTROLLER *controller, int sequence_type,int subsequence, int seconds_for_sequence) {
1956
1957 KEYFRAME_DATA *sequence_start;
1958 SEQUENCE *this_sequence;
1959 int real_time;
1960
1961 GLOBALASSERT(controller);
1962 GLOBALASSERT(seconds_for_sequence);
1963
1964 /* Check this sequence exists... */
1965
1966 this_sequence=GetSequencePointer(sequence_type,subsequence,controller->Root_Section);
1967 sequence_start=this_sequence->first_frame;
1968 GLOBALASSERT(sequence_start);
1969
1970 if (seconds_for_sequence>0) {
1971 real_time=seconds_for_sequence;
1972 } else {
1973 real_time=this_sequence->Time;
1974 if (real_time<=0) {
1975 real_time=ONE_FIXED;
1976 /* Might want to assert here. */
1977 }
1978 }
1979
1980 /* Now set it up. */
1981
1982 controller->Sequence_Type=sequence_type;
1983 controller->Sub_Sequence=subsequence;
1984 controller->Seconds_For_Sequence=real_time;
1985 controller->timer_increment=DIV_FIXED(ONE_FIXED,controller->Seconds_For_Sequence);
1986 controller->sequence_timer=0;
1987 controller->Playing=1;
1988 controller->Reversed=0;
1989 controller->Looped=1;
1990
1991 controller->keyframe_flags=0;
1992
1993 controller->After_Tweening_Sequence_Type=-1;
1994 controller->After_Tweening_Sub_Sequence=-1;
1995 controller->AT_seconds_for_sequence=ONE_FIXED;
1996 controller->AT_sequence_timer=0;
1997 controller->Tweening=Controller_NoTweening;
1998
1999 /* Recurse though hierarchy, setting up all the section_data sequence stores? */
2000
2001 Init_Sequence_Recursion(controller->section_data, sequence_type, subsequence,seconds_for_sequence);
2002
2003 }
2004
2005 static void HMTimer_Kernel(HMODELCONTROLLER *controller) {
2006
2007 /* Core of the timer code. */
2008
2009 if (controller->Tweening==Controller_EndTweening) {
2010 int reversed, AT_sequence_timer;
2011
2012 reversed=controller->Reversed; /* Remember this! */
2013 AT_sequence_timer=controller->AT_sequence_timer; /* Remember this, too! */
2014
2015 if (controller->AT_seconds_for_sequence==0) {
2016 GLOBALASSERT(controller->AT_seconds_for_sequence);
2017 }
2018
2019 InitHModelSequence(controller,controller->After_Tweening_Sequence_Type,
2020 controller->After_Tweening_Sub_Sequence,controller->AT_seconds_for_sequence);
2021
2022 if (reversed) {
2023 controller->Reversed=1;
2024 #if 0
2025 controller->sequence_timer=(ONE_FIXED-1);
2026 #endif
2027 }
2028
2029 /* This should now always be set, though InitHModelSequence zeros it (D'oh!). */
2030 controller->sequence_timer=AT_sequence_timer;
2031
2032 if (controller->LoopAfterTweening) {
2033 controller->Looped=1;
2034 } else {
2035 controller->Looped=0;
2036 }
2037 if (controller->StopAfterTweening) {
2038 /* Hey ho. */
2039 controller->Playing=0;
2040 }
2041 controller->Tweening=Controller_NoTweening;
2042 controller->ElevationTweening=0;
2043 }
2044
2045 if (controller->Playing) {
2046 if (controller->Reversed) {
2047 if (controller->Tweening!=Controller_NoTweening) {
2048 GLOBALASSERT(controller->Tweening==Controller_Tweening);
2049 /* Still tween forwards. */
2050 controller->sequence_timer+=MUL_FIXED(controller->timer_increment,NormalFrameTime);
2051 if (controller->sequence_timer>=ONE_FIXED) {
2052 controller->sequence_timer=ONE_FIXED;
2053 controller->Tweening=Controller_EndTweening;
2054 }
2055 } else {
2056 GLOBALASSERT(controller->Tweening==Controller_NoTweening);
2057 controller->sequence_timer-=MUL_FIXED(controller->timer_increment,NormalFrameTime);
2058 if (controller->Looped) {
2059 while (controller->sequence_timer<0) {
2060 /* Might lose count of how many times we've looped, but who's counting? */
2061 controller->sequence_timer+=ONE_FIXED;
2062 }
2063 } else {
2064 if (controller->sequence_timer<0) {
2065 controller->sequence_timer=0;
2066 }
2067 }
2068 }
2069 } else {
2070 controller->sequence_timer+=MUL_FIXED(controller->timer_increment,NormalFrameTime);
2071
2072 if (controller->Tweening!=Controller_NoTweening) {
2073 GLOBALASSERT(controller->Tweening==Controller_Tweening);
2074 if (controller->sequence_timer>=ONE_FIXED) {
2075 controller->sequence_timer=ONE_FIXED;
2076 controller->Tweening=Controller_EndTweening;
2077 }
2078
2079 } else if (controller->Looped) {
2080 while (controller->sequence_timer>=ONE_FIXED) {
2081 /* Might lose count of how many times we've looped, but who's counting? */
2082 controller->sequence_timer-=ONE_FIXED;
2083 }
2084 } else {
2085 if (controller->sequence_timer>=ONE_FIXED) {
2086 controller->sequence_timer=ONE_FIXED-1;
2087 }
2088 }
2089 }
2090 }
2091
2092 /* Do delta timers, too. */
2093
2094 {
2095 DELTA_CONTROLLER *dcon;
2096
2097 dcon=controller->Deltas;
2098
2099 while (dcon) {
2100
2101 if ((dcon->seconds_for_sequence)&&(dcon->Playing)&&(dcon->Active)) {
2102 dcon->timer+=MUL_FIXED(dcon->timer_increment,NormalFrameTime);
2103 if (dcon->Looped) {
2104 if (dcon->timer>=ONE_FIXED) dcon->timer-=ONE_FIXED;
2105 } else {
2106 if (dcon->timer>=ONE_FIXED) dcon->timer=ONE_FIXED-1;
2107 }
2108 }
2109
2110 dcon=dcon->next_controller;
2111 }
2112 }
2113
2114 }
2115
2116 void DoHModel(HMODELCONTROLLER *controller, DISPLAYBLOCK *dptr) {
2117
2118 GLOBALASSERT(controller);
2119 GLOBALASSERT(dptr);
2120
2121 Global_HModel_Sptr=dptr->ObStrategyBlock;
2122 Global_HModel_DispPtr=dptr;
2123
2124 /* Check the object is in a sensible place. */
2125 if ( !( (dptr->ObWorld.vx<1000000 && dptr->ObWorld.vx>-1000000)
2126 && (dptr->ObWorld.vy<1000000 && dptr->ObWorld.vy>-1000000)
2127 && (dptr->ObWorld.vz<1000000 && dptr->ObWorld.vz>-1000000)
2128 ) ) {
2129
2130 LOGDXFMT(("Tests in DOHMODEL.\n"));
2131 if (Global_HModel_Sptr) {
2132 LOGDXFMT(("Misplaced object is of type %d\n",Global_HModel_Sptr->I_SBtype));
2133 } else {
2134 LOGDXFMT(("Misplaced object has no SBptr.\n"));
2135 }
2136 LOGDXFMT(("It was playing sequence: %d,%d\n",controller->Sequence_Type,controller->Sub_Sequence));
2137
2138 LOCALASSERT(dptr->ObWorld.vx<1000000 && dptr->ObWorld.vx>-1000000);
2139 LOCALASSERT(dptr->ObWorld.vy<1000000 && dptr->ObWorld.vy>-1000000);
2140 LOCALASSERT(dptr->ObWorld.vz<1000000 && dptr->ObWorld.vz>-1000000);
2141
2142 }
2143
2144 GLOBALASSERT(controller->section_data->my_controller==controller);
2145
2146 /* Only do timer if you're out of date. */
2147
2148 if (controller->FrameStamp!=GlobalFrameCounter) {
2149
2150 HMTimer_Kernel(controller);
2151
2152 controller->keyframe_flags=0;
2153
2154 } else {
2155 VECTORCH offset;
2156 /* Want to budge? */
2157
2158 offset.vx=dptr->ObWorld.vx-controller->Computed_Position.vx;
2159 offset.vy=dptr->ObWorld.vy-controller->Computed_Position.vy;
2160 offset.vz=dptr->ObWorld.vz-controller->Computed_Position.vz;
2161
2162 if ((offset.vx!=0)||(offset.vy!=0)||(offset.vz!=0)) {
2163 /* I reckon you'd be better off taking the budge. */
2164 Budge_HModel(controller,&offset);
2165 }
2166
2167 }
2168
2169 /* That handled the timer. Now render it. */
2170 {
2171 int render;
2172
2173 if (dptr->ObFlags&ObFlag_NotVis) {
2174 textprint("HModel NotVis!\n");
2175 render=0;
2176 } else {
2177 render=1;
2178 }
2179 Process_Section(controller,controller->section_data,&dptr->ObWorld,&dptr->ObMat,controller->sequence_timer,controller->Sequence_Type,controller->Sub_Sequence,render);
2180
2181 }
2182 /* Note braces! Process_Section is OUTSIDE, 'cos you might still want to render! */
2183
2184 /* Update frame stamp. */
2185
2186 controller->FrameStamp=GlobalFrameCounter;
2187 controller->Computed_Position=dptr->ObWorld;
2188
2189 }
2190
2191 void DoHModelTimer_Recursion(HMODELCONTROLLER *controller,SECTION_DATA *this_section_data,int frame_timer, int sequence_type, int subsequence) {
2192
2193 KEYFRAME_DATA *sequence_start;
2194 SECTION *this_section;
2195 SEQUENCE *this_sequence;
2196
2197 /* Cut down Process_Section. */
2198
2199 this_section=this_section_data->sempai;
2200
2201 if (controller->FrameStamp!=GlobalFrameCounter) {
2202
2203 /* Positions not computed yet this frame. */
2204
2205 this_sequence=GetSequencePointer(sequence_type,subsequence,this_section);
2206 sequence_start=this_sequence->first_frame;
2207
2208 /* For this section, find the interpolated offset and eulers. */
2209
2210 if (this_section_data->Tweening) {
2211 /* Err... do nothing. */
2212 } else {
2213 int working_timer;
2214
2215 Handle_Section_Timer(controller,this_section_data,sequence_start,frame_timer, &working_timer);
2216 }
2217
2218 }
2219
2220 /* Now call recursion... */
2221
2222 if ((this_section_data->First_Child!=NULL)
2223 &&( (this_section_data->flags§ion_data_terminate_here)==0)) {
2224
2225 SECTION_DATA *child_ptr;
2226
2227 child_ptr=this_section_data->First_Child;
2228
2229 while (child_ptr!=NULL) {
2230
2231 LOCALASSERT(child_ptr->My_Parent==this_section_data);
2232
2233 DoHModelTimer_Recursion(controller,child_ptr,frame_timer,sequence_type,subsequence);
2234 child_ptr=child_ptr->Next_Sibling;
2235 }
2236
2237 }
2238
2239 }
2240
2241 void DoHModelTimer(HMODELCONTROLLER *controller) {
2242
2243 /* Be VERY careful with this function - it can put the timer and the
2244 position computations out of step. Once you've called this, call NO
2245 OTHER HMODEL FUNCTIONS on this model until the next frame! */
2246
2247 GLOBALASSERT(controller);
2248
2249 if (controller->FrameStamp==GlobalFrameCounter) {
2250 /* Done a timer this frame already! */
2251 return;
2252 }
2253
2254 controller->keyframe_flags=0;
2255
2256 HMTimer_Kernel(controller);
2257
2258 /* That handled the timer. No rendering this time. */
2259
2260 DoHModelTimer_Recursion(controller,controller->section_data,controller->sequence_timer,controller->Sequence_Type,controller->Sub_Sequence);
2261
2262 }
2263
2264 void ProveHModel(HMODELCONTROLLER *controller, DISPLAYBLOCK *dptr) {
2265
2266 /* Simply to verify a new hmodel, and remove junk. */
2267
2268 GLOBALASSERT(controller);
2269 GLOBALASSERT(dptr);
2270
2271 Global_HModel_Sptr=dptr->ObStrategyBlock;
2272
2273 /* Check the object is in a sensible place. */
2274 if ( !( (dptr->ObWorld.vx<1000000 && dptr->ObWorld.vx>-1000000)
2275 && (dptr->ObWorld.vy<1000000 && dptr->ObWorld.vy>-1000000)
2276 && (dptr->ObWorld.vz<1000000 && dptr->ObWorld.vz>-1000000)
2277 ) ) {
2278
2279 LOGDXFMT(("Tests in PROVEHMODEL.\n"));
2280 if (Global_HModel_Sptr) {
2281 LOGDXFMT(("Misplaced object is of type %d\n",Global_HModel_Sptr->I_SBtype));
2282 } else {
2283 LOGDXFMT(("Misplaced object has no SBptr.\n"));
2284 }
2285 LOGDXFMT(("It was playing sequence: %d,%d\n",controller->Sequence_Type,controller->Sub_Sequence));
2286
2287 LOCALASSERT(dptr->ObWorld.vx<1000000 && dptr->ObWorld.vx>-1000000);
2288 LOCALASSERT(dptr->ObWorld.vy<1000000 && dptr->ObWorld.vy>-1000000);
2289 LOCALASSERT(dptr->ObWorld.vz<1000000 && dptr->ObWorld.vz>-1000000);
2290
2291 }
2292
2293 GLOBALASSERT(controller->section_data->my_controller==controller);
2294
2295 if (controller->FrameStamp==GlobalFrameCounter) {
2296 VECTORCH offset;
2297 /* Want to budge? */
2298
2299 offset.vx=dptr->ObWorld.vx-controller->Computed_Position.vx;
2300 offset.vy=dptr->ObWorld.vy-controller->Computed_Position.vy;
2301 offset.vz=dptr->ObWorld.vz-controller->Computed_Position.vz;
2302
2303 if ((offset.vx!=0)||(offset.vy!=0)||(offset.vz!=0)) {
2304 /* I reckon you'd be better off taking the budge. */
2305 Budge_HModel(controller,&offset);
2306 }
2307 }
2308
2309 if (controller->FrameStamp!=GlobalFrameCounter) {
2310 controller->keyframe_flags=0;
2311 HMTimer_Kernel(controller);
2312 }
2313 /* That handled the timer. Now update positions. */
2314
2315 Process_Section(controller,controller->section_data,&dptr->ObWorld,&dptr->ObMat,controller->sequence_timer,controller->Sequence_Type,controller->Sub_Sequence,0);
2316
2317 controller->FrameStamp=GlobalFrameCounter;
2318 controller->Computed_Position=dptr->ObWorld;
2319
2320 GLOBALASSERT(controller->section_data->flags§ion_data_initialised);
2321
2322 }
2323
2324 void ProveHModel_Far(HMODELCONTROLLER *controller, STRATEGYBLOCK *sbPtr) {
2325
2326 /* Simply to verify a new hmodel, and remove junk. */
2327
2328 GLOBALASSERT(controller);
2329 GLOBALASSERT(sbPtr);
2330
2331 Global_HModel_Sptr=sbPtr;
2332
2333 GLOBALASSERT(sbPtr->DynPtr);
2334
2335 /* Check the object is in a sensible place. */
2336 if ( !( (sbPtr->DynPtr->Position.vx<1000000 && sbPtr->DynPtr->Position.vx>-1000000)
2337 && (sbPtr->DynPtr->Position.vy<1000000 && sbPtr->DynPtr->Position.vy>-1000000)
2338 && (sbPtr->DynPtr->Position.vz<1000000 && sbPtr->DynPtr->Position.vz>-1000000)
2339 ) ) {
2340
2341 LOGDXFMT(("Tests in PROVEHMODEL_FAR.\n"));
2342 if (Global_HModel_Sptr) {
2343 LOGDXFMT(("Misplaced object is of type %d\n",Global_HModel_Sptr->I_SBtype));
2344 } else {
2345 LOGDXFMT(("Misplaced object has no SBptr.\n"));
2346 }
2347 LOGDXFMT(("It was playing sequence: %d,%d\n",controller->Sequence_Type,controller->Sub_Sequence));
2348
2349 LOCALASSERT(sbPtr->DynPtr->Position.vx<1000000 && sbPtr->DynPtr->Position.vx>-1000000);
2350 LOCALASSERT(sbPtr->DynPtr->Position.vy<1000000 && sbPtr->DynPtr->Position.vy>-1000000);
2351 LOCALASSERT(sbPtr->DynPtr->Position.vz<1000000 && sbPtr->DynPtr->Position.vz>-1000000);
2352
2353 }
2354
2355 GLOBALASSERT(controller->section_data->my_controller==controller);
2356
2357 if (controller->FrameStamp==GlobalFrameCounter) {
2358 VECTORCH offset;
2359 /* Want to budge? */
2360
2361 offset.vx=controller->Computed_Position.vx-sbPtr->DynPtr->Position.vx;
2362 offset.vy=controller->Computed_Position.vy-sbPtr->DynPtr->Position.vy;
2363 offset.vz=controller->Computed_Position.vz-sbPtr->DynPtr->Position.vz;
2364
2365 if ((offset.vx!=0)||(offset.vy!=0)||(offset.vz!=0)) {
2366 /* I reckon you'd be better off taking the budge. */
2367 Budge_HModel(controller,&offset);
2368 }
2369 }
2370
2371 if (controller->FrameStamp!=GlobalFrameCounter) {
2372 controller->keyframe_flags=0;
2373 HMTimer_Kernel(controller);
2374 }
2375 /* That handled the timer. Now update positions. */
2376
2377 Process_Section(controller,controller->section_data,&sbPtr->DynPtr->Position,&sbPtr->DynPtr->OrientMat,controller->sequence_timer,controller->Sequence_Type,controller->Sub_Sequence,0);
2378
2379 controller->FrameStamp=GlobalFrameCounter;
2380 controller->Computed_Position=sbPtr->DynPtr->Position;
2381
2382 GLOBALASSERT(controller->section_data->flags§ion_data_initialised);
2383
2384 }
2385
2386
2387 int Prune_Recursion_Virtual(SECTION_DATA *this_section_data) {
2388
2389 int sol;
2390 SECTION *this_section;
2391
2392 /* Work out which SECTION_DATA to use. */
2393
2394 this_section=this_section_data->sempai;
2395
2396 sol=0;
2397
2398 if (this_section->flags§ion_has_sparkoflife) sol=1;
2399
2400 this_section_data->flags|=section_data_notreal;
2401
2402
2403 if ( (this_section_data->First_Child!=NULL)
2404 &&( (this_section_data->flags§ion_data_terminate_here)==0)) {
2405
2406 SECTION_DATA *child_list_ptr;
2407
2408 child_list_ptr=this_section_data->First_Child;
2409
2410 while (child_list_ptr!=NULL) {
2411 if (Prune_Recursion_Virtual(child_list_ptr)) sol=1;
2412 child_list_ptr=child_list_ptr->Next_Sibling;
2413 }
2414
2415 }
2416
2417 return(sol);
2418
2419 }
2420
2421 int Prune_HModel_Virtual(SECTION_DATA *top_section) {
2422
2423 SECTION *this_section;
2424 int sol;
2425
2426 /* To make top_section, and everything below it, unreal. */
2427 /* Must pass back up the recursion if any section pruned */
2428 /* has the spark of life. */
2429
2430 this_section=top_section->sempai;
2431 sol=0;
2432
2433 if (Prune_Recursion_Virtual(top_section)) sol=1;
2434 top_section->flags|=section_data_terminate_here;
2435 top_section->gore_timer=0;
2436
2437 return(sol);
2438
2439 }
2440
2441 void Correlation_Recursion(SECTION_DATA *this_section_data, SECTION_DATA *alt_section_data) {
2442
2443 /* Correlate existance. */
2444
2445 if (alt_section_data->flags§ion_data_notreal) {
2446 this_section_data->flags|=section_data_notreal;
2447 }
2448
2449 if (alt_section_data->flags§ion_data_terminate_here) {
2450 this_section_data->flags|=section_data_terminate_here;
2451 this_section_data->gore_timer=0; /* As good a time as any. */
2452 }
2453
2454 /* Now call recursion... */
2455
2456 if ((this_section_data->First_Child!=NULL)
2457 &&( (this_section_data->flags§ion_data_terminate_here)==0)) {
2458
2459 SECTION_DATA *child_list_ptr,*alt_child_list_ptr;
2460
2461 child_list_ptr=this_section_data->First_Child;
2462 alt_child_list_ptr=alt_section_data->First_Child;
2463
2464 while (child_list_ptr!=NULL) {
2465 Correlation_Recursion(child_list_ptr,alt_child_list_ptr);
2466 child_list_ptr=child_list_ptr->Next_Sibling;
2467 alt_child_list_ptr=alt_child_list_ptr->Next_Sibling;
2468 }
2469 }
2470 }
2471
2472 void Correlate_HModel_Instances(SECTION_DATA *victim,SECTION_DATA *templat) {
2473
2474 GLOBALASSERT(victim->sempai==templat->sempai);
2475
2476 /* You'd better not be being silly. */
2477
2478 /* The top section must be a false root. */
2479
2480 victim->flags|=section_data_false_root;
2481
2482 /* Start recursion. */
2483
2484 Correlation_Recursion(victim,templat);
2485 }
2486
2487 void MulQuat(QUAT *q1,QUAT *q2,QUAT *output) {
2488
2489 VECTORCH v1,v2,v3;
2490 int tw;
2491
2492 /* Multiply quats... */
2493
2494 v1.vx=q1->quatx;
2495 v1.vy=q1->quaty;
2496 v1.vz=q1->quatz;
2497
2498 v2.vx=q2->quatx;
2499 v2.vy=q2->quaty;
2500 v2.vz=q2->quatz;
2501
2502 CrossProduct(&v1,&v2,&v3);
2503
2504 tw=MUL_FIXED(q1->quatw,q2->quatw);
2505 tw-=DotProduct(&v1,&v2);
2506
2507 v3.vx+=MUL_FIXED(q1->quatw,v2.vx);
2508 v3.vx+=MUL_FIXED(q2->quatw,v1.vx);
2509
2510 v3.vy+=MUL_FIXED(q1->quatw,v2.vy);
2511 v3.vy+=MUL_FIXED(q2->quatw,v1.vy);
2512
2513 v3.vz+=MUL_FIXED(q1->quatw,v2.vz);
2514 v3.vz+=MUL_FIXED(q2->quatw,v1.vz);
2515
2516 output->quatw=tw;
2517 output->quatx=v3.vx;
2518 output->quaty=v3.vy;
2519 output->quatz=v3.vz;
2520
2521 QNormalise(output);
2522
2523 }
2524
2525 void Slerp(KEYFRAME_DATA *input,int lerp,QUAT *output) {
2526
2527 int sclp,sclq;
2528 int omega=input->omega; //probably faster copying to an int , rather than using the bitfield
2529 KEYFRAME_DATA* next_frame=input->Next_Frame;
2530
2531 /* First check for special case. */
2532
2533 if ((lerp<0)||(lerp>=65536)) {
2534 GLOBALASSERT(lerp>=0);
2535 GLOBALASSERT(lerp<65536);
2536 }
2537
2538 if (omega==2048) {
2539 int t1,t2;
2540
2541 output->quatx=((int)-input->QOrient.quaty)<<1;
2542 output->quaty=((int)input->QOrient.quatx)<<1;
2543 output->quatz=((int)-input->QOrient.quatw)<<1;
2544 output->quatw=((int)input->QOrient.quatz)<<1;
2545
2546 t1=MUL_FIXED((ONE_FIXED-lerp),1024);
2547 sclp=GetSin(t1);
2548
2549 t2=MUL_FIXED(lerp,1024);
2550 sclq=GetSin(t2);
2551
2552 //multiply sclp and sclq by 2 to make up for short quats
2553 sclp<<=1;
2554 sclq<<=1;
2555
2556 output->quatx=(MUL_FIXED((int)input->QOrient.quatx,sclp))+(MUL_FIXED(output->quatx,sclq));
2557 output->quaty=(MUL_FIXED((int)input->QOrient.quaty,sclp))+(MUL_FIXED(output->quaty,sclq));
2558 output->quatz=(MUL_FIXED((int)input->QOrient.quatz,sclp))+(MUL_FIXED(output->quatz,sclq));
2559 output->quatw=(MUL_FIXED((int)input->QOrient.quatw,sclp))+(MUL_FIXED(output->quatw,sclq));
2560
2561 } else {
2562 if (omega==0) {
2563 sclp=ONE_FIXED-lerp;
2564 sclq=lerp;
2565 } else {
2566 int t1,t2;
2567 int oneoversinomega=GetOneOverSin(omega);
2568
2569 t1=MUL_FIXED((ONE_FIXED-lerp),omega);
2570 t2=GetSin(t1);
2571 sclp=MUL_FIXED(t2,oneoversinomega);
2572
2573 t1=MUL_FIXED(lerp,omega);
2574 t2=GetSin(t1);
2575 sclq=MUL_FIXED(t2,oneoversinomega);
2576
2577 }
2578 //multiply sclp and sclq by 2 to make up for short quats
2579 sclp<<=1;
2580 sclq<<=1;
2581
2582 if(input->slerp_to_negative_quat)
2583 {
2584 //instead of actually negating the quaternion , negate sclq
2585 sclq=-sclq;
2586 }
2587
2588 output->quatx=(MUL_FIXED((int)input->QOrient.quatx,sclp))+(MUL_FIXED((int)next_frame->QOrient.quatx,sclq));
2589 output->quaty=(MUL_FIXED((int)input->QOrient.quaty,sclp))+(MUL_FIXED((int)next_frame->QOrient.quaty,sclq));
2590 output->quatz=(MUL_FIXED((int)input->QOrient.quatz,sclp))+(MUL_FIXED((int)next_frame->QOrient.quatz,sclq));
2591 output->quatw=(MUL_FIXED((int)input->QOrient.quatw,sclp))+(MUL_FIXED((int)next_frame->QOrient.quatw,sclq));
2592 }
2593
2594 QNormalise(output);
2595
2596 }
2597
2598 void Slerp2(SECTION_DATA *input,int lerp,QUAT *output) {
2599
2600 /* Just a different input structure. */
2601
2602 int sclp,sclq;
2603
2604 /* First check for special case. */
2605
2606 GLOBALASSERT(lerp>=0);
2607 GLOBALASSERT(lerp<65536);
2608
2609 if (input->omega==2048) {
2610 int t1,t2;
2611
2612 output->quatx=-input->stored_quat.quaty;
2613 output->quaty=input->stored_quat.quatx;
2614 output->quatz=-input->stored_quat.quatw;
2615 output->quatw=input->stored_quat.quatz;
2616
2617 t1=MUL_FIXED((ONE_FIXED-lerp),1024);
2618 sclp=GetSin(t1);
2619
2620 t2=MUL_FIXED(lerp,1024);
2621 sclq=GetSin(t2);
2622
2623 output->quatx=(MUL_FIXED(input->stored_quat.quatx,sclp))+(MUL_FIXED(output->quatx,sclq));
2624 output->quaty=(MUL_FIXED(input->stored_quat.quaty,sclp))+(MUL_FIXED(output->quaty,sclq));
2625 output->quatz=(MUL_FIXED(input->stored_quat.quatz,sclp))+(MUL_FIXED(output->quatz,sclq));
2626 output->quatw=(MUL_FIXED(input->stored_quat.quatw,sclp))+(MUL_FIXED(output->quatw,sclq));
2627
2628 } else {
2629 if ( (input->omega==0) && (input->oneoversinomega==0) ) {
2630 sclp=ONE_FIXED-lerp;
2631 sclq=lerp;
2632 } else {
2633 int t1,t2;
2634
2635 t1=MUL_FIXED((ONE_FIXED-lerp),input->omega);
2636 t2=GetSin(t1);
2637 sclp=MUL_FIXED(t2,input->oneoversinomega);
2638
2639 t1=MUL_FIXED(lerp,input->omega);
2640 t2=GetSin(t1);
2641 sclq=MUL_FIXED(t2,input->oneoversinomega);
2642
2643 }
2644
2645 output->quatx=(MUL_FIXED(input->stored_quat.quatx,sclp))+(MUL_FIXED(input->target_quat.quatx,sclq));
2646 output->quaty=(MUL_FIXED(input->stored_quat.quaty,sclp))+(MUL_FIXED(input->target_quat.quaty,sclq));
2647 output->quatz=(MUL_FIXED(input->stored_quat.quatz,sclp))+(MUL_FIXED(input->target_quat.quatz,sclq));
2648 output->quatw=(MUL_FIXED(input->stored_quat.quatw,sclp))+(MUL_FIXED(input->target_quat.quatw,sclq));
2649 }
2650
2651 QNormalise(output);
2652
2653 }
2654
2655 void Gibbing_Recursion(STRATEGYBLOCK *sbPtr,SECTION_DATA *this_section_data, int probability) {
2656
2657 /* General gibbing function. */
2658
2659
2660 /* Recurse. */
2661
2662 if ( (this_section_data->First_Child!=NULL)
2663 &&( (this_section_data->flags§ion_data_terminate_here)==0)) {
2664
2665
2666 SECTION_DATA *child_list_ptr;
2667
2668 child_list_ptr=this_section_data->First_Child;
2669
2670 while (child_list_ptr!=NULL) {
2671
2672 if ( (child_list_ptr->flags§ion_data_terminate_here)==0) {
2673
2674 /* Right. Roll some dice... */
2675 if (((child_list_ptr->sempai->flags§ion_flag_never_frag)==0)
2676 &&((SeededFastRandom()&65535)<probability)) {
2677 /* Frag this bit... */
2678 DISPLAYBLOCK *this_debris;
2679
2680 this_debris=MakeHierarchicalDebris(sbPtr,child_list_ptr, &child_list_ptr->World_Offset, &child_list_ptr->SecMat,NULL,4);
2681 /* Oh Dear! Every section below and including this one becomes... unreal.
2682 And if any of them contain the spark of life, we need to know. */
2683
2684 /* Now, gibb the debris ;-) */
2685
2686 if ( (this_debris) &&
2687 ((this_debris->HModelControlBlock->section_data->sempai->flags§ion_flag_nofurthergibbing)==0) ) {
2688 GLOBALASSERT(this_debris->HModelControlBlock);
2689 GLOBALASSERT(this_debris->HModelControlBlock->section_data);
2690 Gibbing_Recursion(sbPtr,this_debris->HModelControlBlock->section_data,probability);
2691 }
2692
2693 } else {
2694
2695 Gibbing_Recursion(sbPtr,child_list_ptr,probability);
2696
2697 }
2698 }
2699 child_list_ptr=child_list_ptr->Next_Sibling;
2700 }
2701
2702 }
2703
2704 }
2705
2706 void Extreme_Gibbing(STRATEGYBLOCK *sbPtr,SECTION_DATA *this_section_data, int probability) {
2707
2708 /* Shell for gibbing. Do gibbing... */
2709
2710 Gibbing_Recursion(sbPtr,this_section_data,probability);
2711
2712 /* Now frag the body off. */
2713
2714 if ( (SeededFastRandom()&65535)<probability) {
2715 MakeHierarchicalDebris(sbPtr,this_section_data, &this_section_data->World_Offset, &this_section_data->SecMat,NULL,4);
2716 }
2717 }
2718
2719 int Change_Controller_Recursion(HMODELCONTROLLER *new_controller,SECTION_DATA *this_section_data) {
2720
2721 int wounds;
2722
2723 this_section_data->my_controller=new_controller;
2724 wounds=this_section_data->sempai->flags§ion_flags_wounding;
2725
2726 /* Now call recursion... */
2727
2728 if (this_section_data->First_Child!=NULL) {
2729
2730 SECTION_DATA *child_list_ptr;
2731
2732 child_list_ptr=this_section_data->First_Child;
2733
2734 while (child_list_ptr!=NULL) {
2735 wounds|=Change_Controller_Recursion(new_controller,child_list_ptr);
2736 child_list_ptr=child_list_ptr->Next_Sibling;
2737 }
2738 }
2739
2740 return(wounds);
2741
2742 }
2743
2744 int Splice_HModels(HMODELCONTROLLER *new_controller,SECTION_DATA *top_section_data) {
2745
2746 /* Real fragging. */
2747 int wounds;
2748 SECTION_DATA *new_top_section;
2749
2750 /* Init new controller. */
2751
2752 wounds=0;
2753 Global_Controller_Ptr=new_controller;
2754
2755 new_controller->Seconds_For_Sequence=ONE_FIXED;
2756 new_controller->timer_increment=ONE_FIXED;
2757 /* Seconds_For_Sequence and timer_increment are dealt with elsewhere. */
2758 new_controller->sequence_timer=0;
2759 new_controller->Playing=0;
2760 new_controller->Reversed=0;
2761 new_controller->Looped=0;
2762
2763 new_controller->FrameStamp=-1;
2764 new_controller->View_FrameStamp=-1;
2765
2766 if (top_section_data->my_controller) {
2767 new_controller->DisableBleeding=top_section_data->my_controller->DisableBleeding;
2768 new_controller->DisableSounds=top_section_data->my_controller->DisableSounds;
2769 } else {
2770 new_controller->DisableBleeding=0;
2771 new_controller->DisableSounds=0;
2772 }
2773 /* Probably set on return, but never mind. */
2774 new_controller->LockTopSection=0;
2775 new_controller->ZeroRootDisplacement=0;
2776 new_controller->ZeroRootRotation=0;
2777 new_controller->AT_sequence_timer=0;
2778
2779 /* Copy them over, splice them over, or ignore BY HAND. */
2780 new_controller->Deltas=NULL;
2781
2782 new_controller->keyframe_flags=0;
2783
2784 /* Every time a section is preprocessed, it must generate a section_data for
2785 itself, and clip it to the last section_data that was generated. */
2786
2787 /* Create a new top section... */
2788
2789 new_top_section=(SECTION_DATA *)AllocateMem(sizeof(SECTION_DATA));
2790 GLOBALASSERT(new_top_section);
2791
2792 /* Now. Copy the old top_section_data into the new top section. */
2793
2794 *new_top_section=*top_section_data;
2795
2796 top_section_data->tac_ptr=NULL;
2797
2798 /* Correct for new parentage. */
2799 new_top_section->My_Parent=NULL;
2800
2801 if (new_top_section->First_Child!=NULL) {
2802
2803 SECTION_DATA *child_ptr;
2804
2805 child_ptr=new_top_section->First_Child;
2806
2807 while (child_ptr!=NULL) {
2808
2809 child_ptr->My_Parent=new_top_section;
2810
2811 child_ptr=child_ptr->Next_Sibling;
2812 }
2813
2814 }
2815
2816
2817 /* ...and top_section_data gets no children. */
2818
2819 top_section_data->First_Child=NULL;
2820
2821 /* Set flags. */
2822
2823 new_top_section->flags=top_section_data->flags&(~section_data_initialised);
2824 top_section_data->flags|=section_data_terminate_here;
2825 top_section_data->gore_timer=0;
2826 top_section_data->flags|=section_data_notreal;
2827 new_top_section->flags|=section_data_false_root;
2828 new_top_section->gore_timer=0;
2829
2830 /* Connect to controller. */
2831
2832 new_controller->section_data=new_top_section;
2833 new_controller->Root_Section=new_top_section->sempai;
2834
2835 wounds=Change_Controller_Recursion(new_controller,new_top_section);
2836
2837 return(wounds);
2838
2839 }
2840
2841 SECTION_DATA *GetSectionData_Recursion(SECTION_DATA *this_section_data,char *name) {
2842
2843 SECTION_DATA *sdptr;
2844
2845 sdptr=NULL;
2846
2847 if (strcmp(name,this_section_data->sempai->Section_Name)==0) {
2848 /* We are that section! */
2849 return(this_section_data);
2850 }
2851
2852 /* Now call recursion... */
2853
2854 if (this_section_data->First_Child!=NULL) {
2855
2856 SECTION_DATA *child_list_ptr;
2857
2858 child_list_ptr=this_section_data->First_Child;
2859
2860 while (child_list_ptr!=NULL) {
2861 sdptr=GetSectionData_Recursion(child_list_ptr,name);
2862 child_list_ptr=child_list_ptr->Next_Sibling;
2863
2864 if (sdptr) {
2865 return(sdptr); /* We got one! */
2866 }
2867 }
2868 }
2869
2870 return(sdptr);
2871
2872 }
2873
2874 SECTION_DATA *GetThisSectionData(SECTION_DATA *root,char *name) {
2875
2876 if ((root==NULL)||(name==NULL)) {
2877 return(NULL);
2878 }
2879
2880 return(GetSectionData_Recursion(root,name));
2881
2882 }
2883
2884 SECTION *GetSection_Recursion(SECTION *this_section,char *name) {
2885
2886 SECTION *sptr;
2887
2888 sptr=NULL;
2889
2890 if (strcmp(name,this_section->Section_Name)==0) {
2891 /* We are that section! */
2892 return(this_section);
2893 }
2894
2895 /* Now call recursion... */
2896
2897 if (this_section->Children!=NULL) {
2898
2899 SECTION **child_list_ptr;
2900
2901 child_list_ptr=this_section->Children;
2902
2903 while (*child_list_ptr!=NULL) {
2904
2905 sptr=GetSection_Recursion(*child_list_ptr,name);
2906 child_list_ptr++;
2907
2908 if (sptr) {
2909 return(sptr); /* We got one! */
2910 }
2911 }
2912 }
2913
2914 return(sptr);
2915
2916 }
2917
2918 SECTION *GetThisSection(SECTION *root,char *name) {
2919
2920 if ((root==NULL)||(name==NULL)) {
2921 return(NULL);
2922 }
2923
2924 return(GetSection_Recursion(root,name));
2925
2926 }
2927
2928 void MatToQuat (MATRIXCH *m, QUAT *quat)
2929 {
2930 const int X=0;
2931 const int Y=1;
2932 const int Z=2;
2933 const int W=3;
2934
2935 double mat[4][4];
2936 double q[4];
2937
2938 int i,j,k;
2939 double tr,s;
2940
2941 int const nxt[3] =
2942 {
2943 //Y,Z,X
2944 1,2,0
2945 };
2946
2947 // we could try transposing the matrix here
2948
2949 // TransposeMatrixCH(m);
2950
2951 mat[0][0] = (double) m->mat11 / ONE_FIXED;
2952 mat[1][0] = (double) m->mat21 / ONE_FIXED;
2953 mat[2][0] = (double) m->mat31 / ONE_FIXED;
2954 mat[0][1] = (double) m->mat12 / ONE_FIXED;
2955 mat[1][1] = (double) m->mat22 / ONE_FIXED;
2956 mat[2][1] = (double) m->mat32 / ONE_FIXED;
2957 mat[0][2] = (double) m->mat13 / ONE_FIXED;
2958 mat[1][2] = (double) m->mat23 / ONE_FIXED;
2959 mat[2][2] = (double) m->mat33 / ONE_FIXED;
2960
2961
2962
2963 tr= mat[0][0]+mat[1][1]+mat[2][2];
2964
2965 if (tr>0.0)
2966 {
2967 s=sqrt(tr+1.0);
2968 q[W] = s*0.5;
2969 s = 0.5/s;
2970
2971 q[X] = (mat[1][2] - mat[2][1])*s;
2972 q[Y] = (mat[2][0] - mat[0][2])*s;
2973 q[Z] = (mat[0][1] - mat[1][0])*s;
2974 }
2975 else
2976 {
2977 i = X;
2978 if (mat[Y][Y] > mat[X][X]) i = Y;
2979 if (mat[Z][Z] > mat[i][i]) i = Z;
2980 j = nxt[i]; k = nxt[j];
2981
2982 s = sqrt((mat[i][i] - (mat[j][j]+mat[k][k])) + 1.0);
2983
2984 q[i] = s*0.5;
2985 s = 0.5/s;
2986 q[W] = (mat[j][k] - mat[k][j])*s;
2987 q[j] = (mat[i][j] + mat[j][i])*s;
2988 q[k] = (mat[i][k] + mat[k][i])*s;
2989 }
2990
2991 quat->quatx = (int) ((double) q[X]*65536.0);
2992 quat->quaty = (int) ((double) q[Y]*65536.0);
2993 quat->quatz = (int) ((double) q[Z]*65536.0);
2994 quat->quatw = (int) ((double) q[W]*65536.0);
2995
2996 quat->quatw = -quat->quatw;
2997
2998 QNormalise(quat);
2999
3000 }
3001
3002 void Init_Tweening_Recursion(SECTION_DATA *this_section_data, int target_sequence_type,int target_subsequence, int seconds_for_tweening, int backwards) {
3003
3004 SEQUENCE *sequence_ptr;
3005
3006 /* Firstly, store current state. */
3007
3008 this_section_data->stored_offset=this_section_data->Offset;
3009 MatToQuat(&this_section_data->RelSecMat,&this_section_data->stored_quat);
3010
3011 /* Now, get target state. */
3012
3013 sequence_ptr=GetSequencePointer(target_sequence_type,target_subsequence,this_section_data->sempai);
3014
3015 if (backwards) {
3016 KEYFRAME_DATA *current_frame;
3017 /* Deduce last frame. */
3018 current_frame=sequence_ptr->last_frame;
3019
3020 /* Must now have the last frame. */
3021 GetKeyFrameOffset(current_frame,&this_section_data->target_offset);
3022
3023 CopyShortQuatToInt(¤t_frame->QOrient,&this_section_data->target_quat);
3024 } else {
3025 GetKeyFrameOffset(sequence_ptr->first_frame,&this_section_data->target_offset);
3026 CopyShortQuatToInt(&sequence_ptr->first_frame->QOrient,&this_section_data->target_quat);
3027 }
3028
3029 /* Preprocess slerp values. */
3030
3031 {
3032
3033 this_section_data->delta_offset.vx=this_section_data->target_offset.vx-this_section_data->stored_offset.vx;
3034 this_section_data->delta_offset.vy=this_section_data->target_offset.vy-this_section_data->stored_offset.vy;
3035 this_section_data->delta_offset.vz=this_section_data->target_offset.vz-this_section_data->stored_offset.vz;
3036
3037 }
3038
3039 {
3040 int cosom,sinom;
3041 QUAT *this_quat, *next_quat;
3042
3043 this_quat=&this_section_data->stored_quat;
3044 next_quat=&this_section_data->target_quat;
3045
3046
3047 cosom=QDot(this_quat,next_quat);
3048
3049 if (cosom<0) {
3050 next_quat->quatx=-next_quat->quatx;
3051 next_quat->quaty=-next_quat->quaty;
3052 next_quat->quatz=-next_quat->quatz;
3053 next_quat->quatw=-next_quat->quatw;
3054
3055 cosom=-cosom;
3056 }
3057
3058
3059 this_section_data->omega=ArcCos(cosom);
3060 sinom=GetSin(this_section_data->omega);
3061 if (sinom) {
3062 this_section_data->oneoversinomega=GetOneOverSin(this_section_data->omega);
3063 } else {
3064 /* Yuk. */
3065 this_section_data->omega=0;
3066 this_section_data->oneoversinomega=0;
3067 }
3068
3069 GLOBALASSERT(seconds_for_tweening>0);
3070 this_section_data->oneovertweeninglength=DIV_FIXED(ONE_FIXED,seconds_for_tweening);
3071
3072 }
3073
3074 /* Init fields... I guess. */
3075
3076 this_section_data->current_sequence=sequence_ptr;
3077 this_section_data->current_keyframe=sequence_ptr->first_frame;
3078 this_section_data->accumulated_timer=0;
3079 this_section_data->freezeframe_timer=-1;
3080 this_section_data->lastframe_timer=0;
3081 this_section_data->gore_timer=0; /* As good a time as any. */
3082
3083 this_section_data->Tweening=1;
3084
3085 /* Animation? */
3086
3087 /* Nah. */
3088
3089 /* Recurse. */
3090
3091 if ( (this_section_data->First_Child!=NULL)
3092 &&( (this_section_data->flags§ion_data_terminate_here)==0)) {
3093 /* Respect the terminator! */
3094
3095 SECTION_DATA *child_list_ptr;
3096
3097 child_list_ptr=this_section_data->First_Child;
3098
3099 while (child_list_ptr!=NULL) {
3100 Init_Tweening_Recursion(child_list_ptr,target_sequence_type,target_subsequence,seconds_for_tweening,backwards);
3101 child_list_ptr=child_list_ptr->Next_Sibling;
3102 }
3103
3104 }
3105
3106 }
3107
3108
3109 void InitHModelTweening(HMODELCONTROLLER *controller, int seconds_for_tweening,
3110 int target_sequence_type, int target_subsequence, int target_seconds_for_sequence, int loop) {
3111
3112 /* Just set it up... */
3113 GLOBALASSERT(target_seconds_for_sequence);
3114
3115 controller->Sequence_Type=target_sequence_type;
3116 controller->Sub_Sequence=target_subsequence;
3117 controller->Seconds_For_Sequence=seconds_for_tweening;
3118 controller->timer_increment=DIV_FIXED(ONE_FIXED,controller->Seconds_For_Sequence);
3119 controller->sequence_timer=0;
3120 controller->Playing=1;
3121 controller->Reversed=0;
3122 controller->Looped=1;
3123
3124 controller->After_Tweening_Sequence_Type=target_sequence_type;
3125 controller->After_Tweening_Sub_Sequence=target_subsequence;
3126 controller->AT_seconds_for_sequence=target_seconds_for_sequence;
3127 controller->AT_sequence_timer=0;
3128 controller->Tweening=Controller_Tweening;
3129 if (loop) {
3130 controller->LoopAfterTweening=1;
3131 } else {
3132 controller->LoopAfterTweening=0;
3133 }
3134 controller->StopAfterTweening=0;
3135 controller->ElevationTweening=0;
3136
3137 /* Recurse though hierarchy, setting up all the section_data sequence stores? */
3138
3139 Init_Tweening_Recursion(controller->section_data, target_sequence_type, target_subsequence,seconds_for_tweening,0);
3140
3141 }
3142
3143 void InitHModelTweening_Backwards(HMODELCONTROLLER *controller, int seconds_for_tweening,
3144 int target_sequence_type, int target_subsequence, int target_seconds_for_sequence, int loop) {
3145
3146 /* Ooh, yuck. */
3147 GLOBALASSERT(target_seconds_for_sequence);
3148
3149 controller->Sequence_Type=target_sequence_type;
3150 controller->Sub_Sequence=target_subsequence;
3151 controller->Seconds_For_Sequence=seconds_for_tweening;
3152 controller->timer_increment=DIV_FIXED(ONE_FIXED,controller->Seconds_For_Sequence);
3153 controller->sequence_timer=0;
3154 controller->Playing=1;
3155 controller->Reversed=1;
3156 controller->Looped=1;
3157
3158 controller->After_Tweening_Sequence_Type=target_sequence_type;
3159 controller->After_Tweening_Sub_Sequence=target_subsequence;
3160 controller->AT_seconds_for_sequence=target_seconds_for_sequence;
3161 controller->AT_sequence_timer=(ONE_FIXED-1);
3162 controller->Tweening=Controller_Tweening;
3163 if (loop) {
3164 controller->LoopAfterTweening=1;
3165 } else {
3166 controller->LoopAfterTweening=0;
3167 }
3168 controller->StopAfterTweening=0;
3169 controller->ElevationTweening=0;
3170
3171 /* Recurse though hierarchy, setting up all the section_data sequence stores? */
3172
3173 Init_Tweening_Recursion(controller->section_data, target_sequence_type, target_subsequence,seconds_for_tweening,1);
3174
3175 }
3176
3177 void ReSnap(HMODELCONTROLLER *controller,SECTION_DATA *this_section_data, int elevation) {
3178
3179 SEQUENCE *sequence_ptr;
3180 /* In this procedure, we have to get the new target quat and offset. */
3181
3182 sequence_ptr=GetSequencePointer(controller->After_Tweening_Sequence_Type,controller->After_Tweening_Sub_Sequence,this_section_data->sempai);
3183
3184 #if 0
3185 if (controller->Reversed) {
3186 /* We're in a backwards tween. */
3187 KEYFRAME_DATA *current_frame;
3188 /* Deduce last frame. */
3189 current_frame=sequence_ptr->last_frame;
3190
3191 /* Must now have the last frame. */
3192 this_section_data->target_offset=current_frame->Offset;
3193 CopyShortQuatToInt(¤t_frame->QOrient,&this_section_data->target_quat);
3194 } else {
3195 this_section_data->target_offset=sequence_ptr->first_frame->Offset;
3196 CopyShortQuatToInt(&sequence_ptr->first_frame->QOrient,&this_section_data->target_quat);
3197 }
3198 #else
3199 /* Now, irritatingly, we have to put our faith in AT_sequence_timer. */
3200 if (controller->AT_sequence_timer==(ONE_FIXED-1)) {
3201 /* We're in a backwards tween. */
3202 KEYFRAME_DATA *current_frame;
3203 /* Deduce last frame. */
3204 current_frame=sequence_ptr->last_frame;
3205
3206 /* Must now have the last frame. */
3207 GetKeyFrameOffset(current_frame,&this_section_data->target_offset);
3208 CopyShortQuatToInt(¤t_frame->QOrient,&this_section_data->target_quat);
3209 } else if (controller->AT_sequence_timer==0) {
3210 GetKeyFrameOffset(sequence_ptr->first_frame,&this_section_data->target_offset);
3211 CopyShortQuatToInt(&sequence_ptr->first_frame->QOrient,&this_section_data->target_quat);
3212 } else {
3213 int a,working_timer,lerp;
3214 KEYFRAME_DATA *this_frame,*next_frame;
3215
3216 this_frame=sequence_ptr->first_frame;
3217 GLOBALASSERT(this_frame);
3218 working_timer=controller->AT_sequence_timer;
3219
3220 a=0; /* Status flag... */
3221
3222 while (a==0) {
3223 if (this_frame->last_frame) {
3224 /* Low framerate loop? */
3225 next_frame=sequence_ptr->first_frame;
3226 }
3227 else{
3228 next_frame=this_frame->Next_Frame;
3229 }
3230
3231 if (working_timer>=this_frame->Sequence_Length) {
3232 /* We've gone beyond this frame: get next keyframe. */
3233 working_timer-=this_frame->Sequence_Length;
3234 /* Advance frame... */
3235 this_frame=next_frame;
3236 } else {
3237 a=1; /* Exit loop with success. */
3238 }
3239 /* Better make sure the last 'frame' has 65536 length... */
3240 }
3241 GLOBALASSERT(working_timer>=0);
3242 /* Now we should have a frame and a timer. */
3243
3244 lerp=MUL_FIXED(working_timer,this_frame->oneoversequencelength);
3245
3246 GetKeyFrameOffset(this_frame,&this_section_data->target_offset);
3247
3248 if(next_frame->shift_offset)
3249 {
3250 VECTORCH next_offset;
3251 GetKeyFrameOffset(next_frame,&next_offset);
3252 this_section_data->target_offset.vx+=MUL_FIXED(next_offset.vx - this_section_data->target_offset.vx,lerp);
3253 this_section_data->target_offset.vy+=MUL_FIXED(next_offset.vy - this_section_data->target_offset.vy,lerp);
3254 this_section_data->target_offset.vz+=MUL_FIXED(next_offset.vz - this_section_data->target_offset.vz,lerp);
3255 }
3256 else
3257 {
3258 this_section_data->target_offset.vx+=MUL_FIXED((int)next_frame->Offset_x - this_section_data->target_offset.vx,lerp);
3259 this_section_data->target_offset.vy+=MUL_FIXED((int)next_frame->Offset_y - this_section_data->target_offset.vy,lerp);
3260 this_section_data->target_offset.vz+=MUL_FIXED((int)next_frame->Offset_z - this_section_data->target_offset.vz,lerp);
3261 }
3262
3263 /* Now deal with orientation. */
3264
3265 Slerp(this_frame,lerp,&this_section_data->target_quat);
3266
3267 }
3268 #endif
3269
3270 if (elevation) {
3271
3272 /* Elevation gone! Now deltas? */
3273 {
3274 DELTA_CONTROLLER *dcon;
3275 QUAT elevation_quat,temp_quat;
3276 VECTORCH elevation_offset;
3277
3278 dcon=controller->Deltas;
3279
3280 while (dcon) {
3281 if (dcon->Active) {
3282 Process_Delta_Controller(this_section_data,dcon,&elevation_offset,&elevation_quat);
3283 this_section_data->target_offset.vx+=elevation_offset.vx;
3284 this_section_data->target_offset.vy+=elevation_offset.vy;
3285 this_section_data->target_offset.vz+=elevation_offset.vz;
3286
3287 temp_quat.quatw=this_section_data->target_quat.quatw;
3288 temp_quat.quatx=this_section_data->target_quat.quatx;
3289 temp_quat.quaty=this_section_data->target_quat.quaty;
3290 temp_quat.quatz=this_section_data->target_quat.quatz;
3291
3292 MulQuat(&elevation_quat,&temp_quat,&this_section_data->target_quat);
3293 }
3294 dcon=dcon->next_controller;
3295 }
3296 }
3297
3298 }
3299
3300 /* Now recompute values. */
3301
3302 {
3303
3304 this_section_data->delta_offset.vx=this_section_data->target_offset.vx-this_section_data->stored_offset.vx;
3305 this_section_data->delta_offset.vy=this_section_data->target_offset.vy-this_section_data->stored_offset.vy;
3306 this_section_data->delta_offset.vz=this_section_data->target_offset.vz-this_section_data->stored_offset.vz;
3307
3308 }
3309
3310 {
3311 int cosom,sinom;
3312 QUAT *this_quat, *next_quat;
3313
3314 this_quat=&this_section_data->stored_quat;
3315 next_quat=&this_section_data->target_quat;
3316
3317
3318 cosom=QDot(this_quat,next_quat);
3319
3320 if (cosom<0) {
3321 next_quat->quatx=-next_quat->quatx;
3322 next_quat->quaty=-next_quat->quaty;
3323 next_quat->quatz=-next_quat->quatz;
3324 next_quat->quatw=-next_quat->quatw;
3325 cosom=-cosom;
3326 }
3327
3328
3329 this_section_data->omega=ArcCos(cosom);
3330 sinom=GetSin(this_section_data->omega);
3331 if (sinom) {
3332 this_section_data->oneoversinomega=GetOneOverSin(this_section_data->omega);
3333 } else {
3334 /* Yuk. */
3335 this_section_data->omega=0;
3336 this_section_data->oneoversinomega=0;
3337 }
3338
3339 }
3340
3341 }
3342
3343 void Analyse_Tweening_Data(HMODELCONTROLLER *controller,SECTION_DATA *this_section_data,int base_timer,VECTORCH *output_offset,MATRIXCH *output_matrix) {
3344
3345 QUAT output_quat;
3346 int working_timer,lerp;
3347
3348 /* Go go gadget tweening. */
3349
3350 /* There is only one frame. */
3351
3352 working_timer=base_timer;
3353 /* Tests: can't be too careful. */
3354 if (working_timer>=65536) working_timer=65535;
3355 if (working_timer<0) working_timer=0;
3356
3357 /* Now, a lot like the old way, but we shouldn't need to loop more than once. */
3358 /* If we do, we have a game framerate slower than the anim framerate. */
3359
3360 if (controller->Deltas) {
3361 /* Resnap with elevation. */
3362 ReSnap(controller,this_section_data,1);
3363
3364 controller->ElevationTweening=1;
3365
3366 } else if (controller->ElevationTweening) {
3367 /* It's all messed up now. 'Resnap' WITHOUT elevation. */
3368
3369 ReSnap(controller,this_section_data,0);
3370
3371 controller->ElevationTweening=0;
3372
3373 }
3374
3375 /* Now, this_frame and next_frame are set, and working_timer<this_frame->Sequence_Length. */
3376
3377 output_offset->vx=(MUL_FIXED(this_section_data->delta_offset.vx,working_timer))+this_section_data->stored_offset.vx;
3378 output_offset->vy=(MUL_FIXED(this_section_data->delta_offset.vy,working_timer))+this_section_data->stored_offset.vy;
3379 output_offset->vz=(MUL_FIXED(this_section_data->delta_offset.vz,working_timer))+this_section_data->stored_offset.vz;
3380
3381 /* Now deal with orientation. */
3382
3383 lerp=working_timer;
3384
3385 Slerp2(this_section_data,lerp,&output_quat);
3386
3387 /* NO elevation! */
3388
3389 QuatToMat(&output_quat,output_matrix);
3390
3391 /* Just to make sure. */
3392 MNormalise(output_matrix);
3393 }
3394
3395
3396 /* KJL 16:51:20 10/02/98 - Heat source stuff */
3397
3398 int FindHeatSourcesInHModel(DISPLAYBLOCK *dispPtr)
3399 {
3400 HMODELCONTROLLER *controllerPtr = dispPtr->HModelControlBlock;
3401
3402 LOCALASSERT(controllerPtr);
3403
3404 /* KJL 16:36:12 10/02/98 - check positions are up to date */
3405 ProveHModel(controllerPtr,dispPtr);
3406
3407 NumberOfHeatSources=0;
3408
3409 /* KJL 16:36:25 10/02/98 - process model */
3410 FindHeatSource_Recursion(controllerPtr,controllerPtr->section_data);
3411
3412 return 0;
3413 }
3414
3415 static void FindHeatSource_Recursion(HMODELCONTROLLER *controllerPtr, SECTION_DATA *sectionDataPtr)
3416 {
3417 /* KJL 16:29:40 10/02/98 - Recurse through hmodel */
3418 if ((sectionDataPtr->First_Child!=NULL)&&(!(sectionDataPtr->flags§ion_data_terminate_here)))
3419 {
3420 SECTION_DATA *childSectionPtr = sectionDataPtr->First_Child;
3421
3422 while (childSectionPtr!=NULL)
3423 {
3424 LOCALASSERT(childSectionPtr->My_Parent==sectionDataPtr);
3425
3426 FindHeatSource_Recursion(controllerPtr,childSectionPtr);
3427 childSectionPtr=childSectionPtr->Next_Sibling;
3428 }
3429 }
3430
3431 /* KJL 16:30:03 10/02/98 - record heat source */
3432 if (sectionDataPtr->sempai->flags§ion_flag_heatsource)
3433 {
3434 /* KJL 16:36:58 10/02/98 - currently just position; could have size, orientation, etc. */
3435 HeatSourceList[NumberOfHeatSources].Position.vx = sectionDataPtr->World_Offset.vx;
3436 HeatSourceList[NumberOfHeatSources].Position.vy = sectionDataPtr->World_Offset.vy;
3437 HeatSourceList[NumberOfHeatSources].Position.vz = sectionDataPtr->World_Offset.vz;
3438 TranslatePointIntoViewspace(&(HeatSourceList[NumberOfHeatSources].Position));
3439 NumberOfHeatSources++;
3440 }
3441 }
3442
3443 DELTA_CONTROLLER *Get_Delta_Sequence(HMODELCONTROLLER *controller,char *id) {
3444
3445 DELTA_CONTROLLER *delta_controller;
3446
3447 /* Get the controller that matches id. */
3448
3449 delta_controller=controller->Deltas;
3450
3451 while (delta_controller) {
3452
3453 if (strcmp(id,delta_controller->id)==0) {
3454 break;
3455 }
3456 delta_controller=delta_controller->next_controller;
3457
3458 }
3459 return(delta_controller);
3460 }
3461
3462 void Remove_Delta_Sequence(HMODELCONTROLLER *controller,char *id) {
3463
3464 DELTA_CONTROLLER *delta_controller;
3465 DELTA_CONTROLLER **source;
3466
3467 delta_controller=controller->Deltas;
3468 source=&controller->Deltas;
3469
3470 while (delta_controller) {
3471
3472 if (strcmp(id,delta_controller->id)==0) {
3473 break;
3474 }
3475 source=&delta_controller->next_controller;
3476 delta_controller=delta_controller->next_controller;
3477
3478 }
3479
3480 if (delta_controller) {
3481 /* Remove it. */
3482 *source=delta_controller->next_controller;
3483
3484 DeallocateMem(delta_controller->id);
3485 DeallocateMem(delta_controller);
3486 }
3487 }
3488
3489 DELTA_CONTROLLER *Add_Delta_Sequence(HMODELCONTROLLER *controller,char *id,int sequence_type,int sub_sequence, int seconds_for_sequence) {
3490
3491 KEYFRAME_DATA *sequence_start;
3492 SEQUENCE *this_sequence;
3493 DELTA_CONTROLLER *delta_controller;
3494
3495 /* Create a new delta sequence. */
3496
3497 delta_controller=(DELTA_CONTROLLER *)AllocateMem(sizeof(DELTA_CONTROLLER));
3498
3499 GLOBALASSERT(delta_controller);
3500
3501 delta_controller->next_controller=controller->Deltas;
3502 controller->Deltas=delta_controller;
3503
3504 delta_controller->id = AllocateMem(strlen(id)+1);
3505 strcpy(delta_controller->id,id);
3506
3507 delta_controller->sequence_type=sequence_type;
3508 delta_controller->sub_sequence=sub_sequence;
3509 delta_controller->timer=0;
3510 delta_controller->lastframe_timer=-1;
3511 delta_controller->Looped=0;
3512 delta_controller->Playing=0;
3513 delta_controller->Active=1; /* By default. */
3514 delta_controller->my_hmodel_controller=controller;
3515
3516 this_sequence=GetSequencePointer(sequence_type,sub_sequence,delta_controller->my_hmodel_controller->Root_Section);
3517 sequence_start=this_sequence->first_frame;
3518 GLOBALASSERT(sequence_start);
3519
3520 if (seconds_for_sequence>=0) {
3521 delta_controller->seconds_for_sequence=seconds_for_sequence; // Special case, 0 is legal.
3522 } else {
3523 delta_controller->seconds_for_sequence=this_sequence->Time;
3524 if (delta_controller->seconds_for_sequence<=0) {
3525 delta_controller->seconds_for_sequence=ONE_FIXED;
3526 /* Might want to assert here? */
3527 }
3528 }
3529
3530 if (delta_controller->seconds_for_sequence) {
3531 delta_controller->timer_increment=DIV_FIXED(ONE_FIXED,delta_controller->seconds_for_sequence);
3532 } else {
3533 delta_controller->timer_increment=0;
3534 }
3535
3536 return(delta_controller);
3537
3538 }
3539
3540 void Start_Delta_Sequence(DELTA_CONTROLLER *delta_controller,int sequence_type,int sub_sequence,int seconds_for_sequence) {
3541
3542 KEYFRAME_DATA *sequence_start;
3543 SEQUENCE *this_sequence;
3544 GLOBALASSERT(delta_controller);
3545
3546 /* Again, you must start it and loop it by hand. */
3547
3548 delta_controller->sequence_type=sequence_type;
3549 delta_controller->sub_sequence=sub_sequence;
3550 delta_controller->timer=0;
3551 delta_controller->Looped=0;
3552 delta_controller->Playing=0;
3553
3554 this_sequence=GetSequencePointer(sequence_type,sub_sequence,delta_controller->my_hmodel_controller->Root_Section);
3555 sequence_start=this_sequence->first_frame;
3556 GLOBALASSERT(sequence_start);
3557
3558 if (seconds_for_sequence>=0) {
3559 delta_controller->seconds_for_sequence=seconds_for_sequence; // Special case, 0 is legal.
3560 } else {
3561 delta_controller->seconds_for_sequence=this_sequence->Time;
3562 if (delta_controller->seconds_for_sequence<=0) {
3563 delta_controller->seconds_for_sequence=ONE_FIXED;
3564 /* Might want to assert here? */
3565 }
3566 }
3567
3568 if (delta_controller->seconds_for_sequence) {
3569 delta_controller->timer_increment=DIV_FIXED(ONE_FIXED,delta_controller->seconds_for_sequence);
3570 } else {
3571 delta_controller->timer_increment=0;
3572 }
3573
3574 }
3575
3576 void Delta_Sequence_ChangeSpeed(DELTA_CONTROLLER *delta_controller,int seconds_for_sequence) {
3577
3578 GLOBALASSERT(delta_controller);
3579
3580 delta_controller->seconds_for_sequence=seconds_for_sequence; // Special case.
3581
3582 if (delta_controller->seconds_for_sequence) {
3583 delta_controller->timer_increment=DIV_FIXED(ONE_FIXED,delta_controller->seconds_for_sequence);
3584 } else {
3585 delta_controller->timer_increment=0;
3586 }
3587
3588 }
3589
3590 SECTION *Get_Corresponding_Section(SECTION **List_Ptr,char *Name) {
3591
3592 SECTION **child_list_ptr=List_Ptr;
3593
3594 while (*child_list_ptr!=NULL) {
3595 if (strcmp((*child_list_ptr)->Section_Name,Name)==0) {
3596 break;
3597 }
3598 child_list_ptr++;
3599 }
3600
3601 return(*child_list_ptr);
3602 }
3603
3604 SECTION_DATA *GetThisSectionData_FromChildrenOnly(SECTION_DATA *parent,char *name) {
3605
3606 SECTION_DATA *sdptr;
3607
3608 if ((parent==NULL)||(name==NULL)) {
3609 return(NULL);
3610 }
3611
3612 sdptr=NULL;
3613
3614 if (parent->First_Child!=NULL) {
3615
3616 SECTION_DATA *child_list_ptr;
3617
3618 child_list_ptr=parent->First_Child;
3619
3620 while (child_list_ptr!=NULL) {
3621
3622 if (strcmp(name,child_list_ptr->sempai->Section_Name)==0) {
3623 /* Got it. */
3624 return(child_list_ptr);
3625 }
3626
3627 child_list_ptr=child_list_ptr->Next_Sibling;
3628 }
3629 }
3630
3631 return(sdptr);
3632
3633 }
3634
3635 void Transmogrification_Recursion(STRATEGYBLOCK *sbPtr,HMODELCONTROLLER *controller,SECTION_DATA *this_section_data,SECTION *new_template, SECTION *old_template, int frag, int newsections, int regrowsections) {
3636
3637 /* Doesn't really matter which tree we're walking... does it? */
3638
3639 GLOBALASSERT(new_template);
3640 GLOBALASSERT(old_template);
3641 GLOBALASSERT(strcmp(new_template->Section_Name,old_template->Section_Name)==0);
3642
3643 GLOBALASSERT(this_section_data);
3644
3645 if ( (new_template->Children!=NULL) && (old_template->Children!=NULL) ) {
3646 /* Complex. I'd really like to walk both at the same time. */
3647 SECTION **new_child_list_ptr,**old_child_list_ptr;
3648
3649 new_child_list_ptr=new_template->Children;
3650 old_child_list_ptr=old_template->Children;
3651
3652 /* First, let's walk the new template. */
3653 while (*new_child_list_ptr!=NULL) {
3654
3655 SECTION *corresponding_section;
3656
3657 corresponding_section=Get_Corresponding_Section(old_child_list_ptr,(*new_child_list_ptr)->Section_Name);
3658
3659 if (corresponding_section!=NULL) {
3660 /* Section also exists in old template. Deal with it and recurse. */
3661 SECTION_DATA *child_section_data;
3662
3663 child_section_data=GetThisSectionData_FromChildrenOnly(this_section_data,(*new_child_list_ptr)->Section_Name);
3664
3665 if (child_section_data) {
3666 /* Hey, it might be fragged off. Now deal with it. */
3667
3668 child_section_data->sempai=*new_child_list_ptr;
3669
3670 Transmogrification_Recursion(sbPtr,controller,child_section_data,*new_child_list_ptr, corresponding_section, frag, newsections, regrowsections);
3671 } else if (regrowsections) {
3672 /* If it is fragged off, put it back. */
3673 SECTION_DATA *new_child;
3674
3675 new_child=Create_New_Section(*new_child_list_ptr);
3676
3677 new_child->My_Parent=this_section_data;
3678 new_child->Prev_Sibling=NULL;
3679 new_child->Next_Sibling=this_section_data->First_Child;
3680 if (this_section_data->First_Child) {
3681 this_section_data->First_Child->Prev_Sibling=new_child;
3682 }
3683 this_section_data->First_Child=new_child;
3684 Init_Sequence_Recursion(new_child, controller->Sequence_Type, controller->Sub_Sequence,controller->Seconds_For_Sequence);
3685 /* Prove new positions. */
3686 Process_Section(controller,new_child,&(this_section_data->World_Offset),&(this_section_data->SecMat),0,controller->Sequence_Type,controller->Sub_Sequence,0);
3687 }
3688
3689 } else if (newsections) {
3690 /* No corresponding old section: create a new bit. */
3691 SECTION_DATA *new_child;
3692
3693 new_child=Create_New_Section(*new_child_list_ptr);
3694
3695 new_child->My_Parent=this_section_data;
3696 new_child->Prev_Sibling=NULL;
3697 new_child->Next_Sibling=this_section_data->First_Child;
3698 if (this_section_data->First_Child) {
3699 this_section_data->First_Child->Prev_Sibling=new_child;
3700 }
3701 this_section_data->First_Child=new_child;
3702 Init_Sequence_Recursion(new_child, controller->Sequence_Type, controller->Sub_Sequence,controller->Seconds_For_Sequence);
3703 /* Prove new positions. */
3704 Process_Section(controller,new_child,&(this_section_data->World_Offset),&(this_section_data->SecMat),0,controller->Sequence_Type,controller->Sub_Sequence,0);
3705 }
3706
3707 new_child_list_ptr++;
3708 }
3709 /* Now, let's walk the old template. */
3710 new_child_list_ptr=new_template->Children;
3711 while (*old_child_list_ptr!=NULL) {
3712
3713 SECTION *corresponding_section;
3714
3715 corresponding_section=Get_Corresponding_Section(new_child_list_ptr,(*old_child_list_ptr)->Section_Name);
3716
3717 if (corresponding_section!=NULL) {
3718 /* Section also exists in new template. Do nothing, it should already have been dealt with. */
3719 } else {
3720 /* No corresponding new section: delete this branch. */
3721 SECTION_DATA *superfluous_section;
3722
3723 superfluous_section=GetThisSectionData_FromChildrenOnly(this_section_data,(*old_child_list_ptr)->Section_Name);
3724 if (superfluous_section) {
3725 if (frag) {
3726 MakeHierarchicalDebris(sbPtr,superfluous_section, &superfluous_section->World_Offset, &superfluous_section->SecMat,NULL,2);
3727 Prune_Section(superfluous_section);
3728 } else {
3729 Prune_Section(superfluous_section);
3730 }
3731
3732 }
3733 }
3734
3735 old_child_list_ptr++;
3736 }
3737
3738
3739 } else if (new_template->Children!=NULL) {
3740
3741 if (newsections) {
3742 /* A whole lotta new branches. */
3743 SECTION_DATA *new_child;
3744 SECTION **new_child_list_ptr;
3745
3746 new_child_list_ptr=new_template->Children;
3747
3748 while (*new_child_list_ptr!=NULL) {
3749
3750 new_child=Create_New_Section(*new_child_list_ptr);
3751
3752 new_child->My_Parent=this_section_data;
3753 new_child->Prev_Sibling=NULL;
3754 new_child->Next_Sibling=this_section_data->First_Child;
3755 if (this_section_data->First_Child) {
3756 this_section_data->First_Child->Prev_Sibling=new_child;
3757 }
3758 this_section_data->First_Child=new_child;
3759
3760 Init_Sequence_Recursion(new_child, controller->Sequence_Type, controller->Sub_Sequence,controller->Seconds_For_Sequence);
3761
3762 new_child_list_ptr++;
3763 }
3764 }
3765 } else if (old_template->Children!=NULL) {
3766 /* Remove all branches. */
3767 SECTION_DATA *data_child_ptr;
3768
3769 data_child_ptr=this_section_data->First_Child;
3770
3771 while (data_child_ptr!=NULL) {
3772
3773 SECTION_DATA *next_one;
3774
3775 LOCALASSERT(data_child_ptr->My_Parent==this_section_data);
3776 next_one=data_child_ptr->Next_Sibling;
3777 if (frag) {
3778 MakeHierarchicalDebris(sbPtr,data_child_ptr, &data_child_ptr->World_Offset, &data_child_ptr->SecMat,NULL,2);
3779 Prune_Section(data_child_ptr);
3780 } else {
3781 Prune_Section(data_child_ptr);
3782 }
3783 data_child_ptr=next_one;
3784 }
3785
3786 } else {
3787 /* Null case. */
3788 }
3789
3790 }
3791
3792 void Transmogrify_HModels(STRATEGYBLOCK *sbPtr,HMODELCONTROLLER *controller,SECTION *new_template, int frag, int newsections, int regrowsections) {
3793
3794 SECTION *old_template;
3795
3796 /* Convert one HModel to another template... */
3797 Global_Controller_Ptr=controller;
3798
3799 old_template=controller->Root_Section;
3800
3801 /* Compare the two templates to each other. */
3802
3803 GLOBALASSERT(controller->section_data->sempai==old_template);
3804
3805 controller->section_data->sempai=new_template;
3806
3807 Transmogrification_Recursion(sbPtr,controller,controller->section_data,new_template,old_template,frag,newsections,regrowsections);
3808
3809 controller->Root_Section=new_template;
3810 }
3811
3812 void TrimToTemplate_Recursion(STRATEGYBLOCK *sbPtr,HMODELCONTROLLER *controller,SECTION_DATA *this_section_data,SECTION *new_template, SECTION *old_template, int frag) {
3813
3814 /* Doesn't really matter which tree we're walking... does it? */
3815
3816 GLOBALASSERT(new_template);
3817 GLOBALASSERT(old_template);
3818 GLOBALASSERT(strcmp(new_template->Section_Name,old_template->Section_Name)==0);
3819
3820 GLOBALASSERT(this_section_data);
3821
3822 if ( (new_template->Children!=NULL) && (old_template->Children!=NULL) ) {
3823 /* Complex. I'd really like to walk both at the same time. */
3824 SECTION **new_child_list_ptr,**old_child_list_ptr;
3825
3826 new_child_list_ptr=new_template->Children;
3827 old_child_list_ptr=old_template->Children;
3828
3829 /* Let's walk the old template. */
3830 while (*old_child_list_ptr!=NULL) {
3831
3832 SECTION *corresponding_section;
3833
3834 corresponding_section=Get_Corresponding_Section(new_child_list_ptr,(*old_child_list_ptr)->Section_Name);
3835
3836 if (corresponding_section!=NULL) {
3837 /* Section also exists in new template. Recurse. */
3838 SECTION_DATA *child_section_data;
3839
3840 child_section_data=GetThisSectionData_FromChildrenOnly(this_section_data,(*old_child_list_ptr)->Section_Name);
3841
3842 if (child_section_data) {
3843 /* Hey, it might be fragged off. Now deal with it. */
3844
3845 TrimToTemplate_Recursion(sbPtr,controller,child_section_data,corresponding_section,*old_child_list_ptr, frag);
3846 }
3847 } else {
3848 /* No corresponding new section: delete this branch. */
3849 SECTION_DATA *superfluous_section;
3850
3851 superfluous_section=GetThisSectionData_FromChildrenOnly(this_section_data,(*old_child_list_ptr)->Section_Name);
3852 if (superfluous_section) {
3853 if (frag) {
3854 MakeHierarchicalDebris(sbPtr,superfluous_section, &superfluous_section->World_Offset, &superfluous_section->SecMat,NULL,2);
3855 Prune_Section(superfluous_section);
3856 } else {
3857 Prune_Section(superfluous_section);
3858 }
3859
3860 }
3861 }
3862
3863 old_child_list_ptr++;
3864 }
3865
3866 } else if (old_template->Children!=NULL) {
3867 /* Remove all branches. */
3868 SECTION_DATA *data_child_ptr;
3869
3870 data_child_ptr=this_section_data->First_Child;
3871
3872 while (data_child_ptr!=NULL) {
3873
3874 SECTION_DATA *next_one;
3875
3876 LOCALASSERT(data_child_ptr->My_Parent==this_section_data);
3877 next_one=data_child_ptr->Next_Sibling;
3878 if (frag) {
3879 MakeHierarchicalDebris(sbPtr,data_child_ptr, &data_child_ptr->World_Offset, &data_child_ptr->SecMat,NULL,2);
3880 Prune_Section(data_child_ptr);
3881 } else {
3882 Prune_Section(data_child_ptr);
3883 }
3884 data_child_ptr=next_one;
3885 }
3886
3887 } else {
3888 /* Null case. */
3889 }
3890
3891 }
3892
3893 void TrimToTemplate(STRATEGYBLOCK *sbPtr,HMODELCONTROLLER *controller,SECTION *new_template, int frag) {
3894
3895 SECTION *old_template;
3896
3897 /* Convert one HModel to another template... */
3898
3899 old_template=controller->Root_Section;
3900
3901 /* Compare the two templates to each other. */
3902
3903 GLOBALASSERT(controller->section_data->sempai==old_template);
3904 if (strcmp(new_template->Section_Name,old_template->Section_Name)) {
3905 GLOBALASSERT(strcmp(new_template->Section_Name,old_template->Section_Name)==0);
3906 }
3907 TrimToTemplate_Recursion(sbPtr,controller,controller->section_data,new_template,old_template,frag);
3908
3909 }
3910
3911 int HModelSequence_Exists(HMODELCONTROLLER *controller,int sequence_type,int sub_sequence) {
3912
3913 int sequence_id,a;
3914 SEQUENCE *sequence_pointer;
3915
3916 sequence_id=GetSequenceID(sequence_type,sub_sequence);
3917
3918 for (a=0; a<controller->Root_Section->num_sequences; a++) {
3919 if (controller->Root_Section->sequence_array[a].sequence_id==sequence_id) {
3920 sequence_pointer=&(controller->Root_Section->sequence_array[a]);
3921 break;
3922 }
3923 }
3924
3925 if (a==controller->Root_Section->num_sequences) {
3926 /* No such animal. */
3927 return(0);
3928 } else {
3929 return(1);
3930 }
3931
3932 }
3933
3934 int HModelSequence_Exists_FromRoot(SECTION *root,int sequence_type,int sub_sequence) {
3935
3936 int sequence_id,a;
3937 SEQUENCE *sequence_pointer;
3938
3939 if (!root) {
3940 return(0);
3941 }
3942
3943 sequence_id=GetSequenceID(sequence_type,sub_sequence);
3944
3945 for (a=0; a<root->num_sequences; a++) {
3946 if (root->sequence_array[a].sequence_id==sequence_id) {
3947 sequence_pointer=&(root->sequence_array[a]);
3948 break;
3949 }
3950 }
3951
3952 if (a==root->num_sequences) {
3953 /* No such animal. */
3954 return(0);
3955 } else {
3956 return(1);
3957 }
3958
3959 }
3960
3961 void KRS_Recursion(SECTION_DATA *this_section_data, int probability) {
3962
3963 /* General gibbing function. */
3964
3965
3966 /* Recurse. */
3967
3968 if ( (this_section_data->First_Child!=NULL)
3969 &&( (this_section_data->flags§ion_data_terminate_here)==0)) {
3970
3971
3972 SECTION_DATA *child_list_ptr;
3973
3974 child_list_ptr=this_section_data->First_Child;
3975
3976 while (child_list_ptr!=NULL) {
3977
3978 if ( (child_list_ptr->flags§ion_data_terminate_here)==0) {
3979
3980 /* Right. Roll some dice... */
3981 if ( (SeededFastRandom()&65535)<probability) {
3982 /* Kill this bit... */
3983
3984 child_list_ptr->current_damage.Health=0;
3985
3986 KRS_Recursion(child_list_ptr,probability);
3987
3988 } else {
3989
3990 KRS_Recursion(child_list_ptr,probability);
3991
3992 }
3993 }
3994 child_list_ptr=child_list_ptr->Next_Sibling;
3995 }
3996
3997 }
3998
3999 }
4000
4001 void KillRandomSections(SECTION_DATA *this_section_data, int probability) {
4002
4003 /* A bit like gibbing, but less extreme. */
4004
4005 KRS_Recursion(this_section_data,probability);
4006
4007 }
4008
4009 void Budge_Recursion(SECTION_DATA *this_section_data,VECTORCH *offset) {
4010
4011 SECTION_DATA *sdptr;
4012
4013 sdptr=NULL;
4014
4015 /* Budge! */
4016 this_section_data->World_Offset.vx+=offset->vx;
4017 this_section_data->World_Offset.vy+=offset->vy;
4018 this_section_data->World_Offset.vz+=offset->vz;
4019
4020 /* Now call recursion... */
4021
4022 if (this_section_data->First_Child!=NULL) {
4023
4024 SECTION_DATA *child_list_ptr;
4025
4026 child_list_ptr=this_section_data->First_Child;
4027
4028 while (child_list_ptr!=NULL) {
4029 Budge_Recursion(child_list_ptr,offset);
4030 child_list_ptr=child_list_ptr->Next_Sibling;
4031 }
4032 }
4033
4034 return;
4035
4036 }
4037
4038 void Budge_HModel(HMODELCONTROLLER *controller,VECTORCH *offset) {
4039
4040 /* Shift a model. */
4041
4042 if ((offset==NULL)||(controller==NULL)) {
4043 return;
4044 }
4045
4046 /* */
4047
4048 Budge_Recursion(controller->section_data,offset);
4049
4050 }
4051
4052 void HModelRegen_Recursion(SECTION_DATA *this_section_data, int time) {
4053
4054 SECTION_DATA *sdptr;
4055 int health_increment;
4056
4057 sdptr=NULL;
4058
4059 /* Regenerate this section. */
4060 if (this_section_data->current_damage.Health>0) {
4061
4062 health_increment=DIV_FIXED((this_section_data->sempai->StartingStats.Health*NormalFrameTime),time);
4063 this_section_data->current_damage.Health+=health_increment;
4064
4065 if (this_section_data->current_damage.Health>(this_section_data->sempai->StartingStats.Health<<ONE_FIXED_SHIFT)) {
4066 this_section_data->current_damage.Health=(this_section_data->sempai->StartingStats.Health<<ONE_FIXED_SHIFT);
4067 }
4068 }
4069
4070 /* Now call recursion... */
4071
4072 if (this_section_data->First_Child!=NULL) {
4073
4074 SECTION_DATA *child_list_ptr;
4075
4076 child_list_ptr=this_section_data->First_Child;
4077
4078 while (child_list_ptr!=NULL) {
4079 HModelRegen_Recursion(child_list_ptr,time);
4080 child_list_ptr=child_list_ptr->Next_Sibling;
4081 }
4082 }
4083
4084 return;
4085
4086 }
4087
4088 void HModel_Regen(HMODELCONTROLLER *controller,int time) {
4089
4090 /* Regenerate sections. */
4091
4092 HModelRegen_Recursion(controller->section_data,time);
4093
4094 }
4095
4096 int HModelAnimation_IsFinished(HMODELCONTROLLER *controller) {
4097
4098 /* This now gets used all over the place... */
4099
4100 if (controller->Tweening!=Controller_NoTweening) {
4101 return(0);
4102 }
4103 if (controller->Looped) {
4104 return(0);
4105 }
4106 if (controller->Reversed) {
4107 if (controller->sequence_timer!=0) {
4108 return(0);
4109 }
4110 } else {
4111 if (controller->sequence_timer!=(ONE_FIXED-1)) {
4112 return(0);
4113 }
4114 }
4115 return(1);
4116 }
4117
4118 int DeltaAnimation_IsFinished(DELTA_CONTROLLER *controller) {
4119
4120 if (controller->Looped) {
4121 return(0);
4122 }
4123 if (controller->Playing==0) {
4124 return(1);
4125 }
4126 if (controller->Active==0) {
4127 return(1);
4128 }
4129 if (controller->timer!=(ONE_FIXED-1)) {
4130 return(0);
4131 }
4132 return(1);
4133 }
4134
4135 SECTION_DATA *PointInHModel_Recursion(SECTION_DATA *this_section_data, VECTORCH *point) {
4136
4137 SECTION_DATA *hit;
4138
4139 hit=NULL;
4140
4141 /* Test this section. */
4142
4143 /* Use shape data. */
4144 if (this_section_data->Shape!=NULL) {
4145 VECTORCH offset;
4146 int dist;
4147
4148 offset.vx=this_section_data->World_Offset.vx-point->vx;
4149 offset.vy=this_section_data->World_Offset.vy-point->vy;
4150 offset.vz=this_section_data->World_Offset.vz-point->vz;
4151 dist=Approximate3dMagnitude(&offset);
4152 if (dist<this_section_data->Shape->shaperadius) {
4153 /* Hit! */
4154 hit=this_section_data;
4155 }
4156 }
4157
4158 if (hit) {
4159 return(hit);
4160 }
4161
4162 /* Now call recursion... */
4163
4164 if (this_section_data->First_Child!=NULL) {
4165
4166 SECTION_DATA *child_list_ptr;
4167
4168 child_list_ptr=this_section_data->First_Child;
4169
4170 while (child_list_ptr!=NULL) {
4171 hit=PointInHModel_Recursion(child_list_ptr,point);
4172 child_list_ptr=child_list_ptr->Next_Sibling;
4173 }
4174 }
4175
4176 return(hit);
4177
4178 }
4179
4180 SECTION_DATA *PointInHModel(HMODELCONTROLLER *controller,VECTORCH *point) {
4181
4182 /* Test for point in model. */
4183
4184 return(PointInHModel_Recursion(controller->section_data,point));
4185
4186 }
4187
4188 SECTION *Get_Corresponding_Section_Recursive(SECTION *this_section,char *Name) {
4189
4190 SECTION **child_list_ptr;
4191
4192 if (strcmp(this_section->Section_Name,Name)==0) {
4193 return(this_section);
4194 }
4195
4196 /* Recurse. */
4197 child_list_ptr=this_section->Children;
4198
4199 if (child_list_ptr) {
4200 while (*child_list_ptr!=NULL) {
4201 SECTION *cosec;
4202
4203 cosec=Get_Corresponding_Section_Recursive(*child_list_ptr,Name);
4204 if (cosec) {
4205 /* Back out! */
4206 return(cosec);
4207 }
4208 child_list_ptr++;
4209 }
4210 }
4211
4212 /* No luck. */
4213 return(NULL);
4214 }
4215
4216 SECTION_DATA *GetSectionFromID_Recursion(SECTION_DATA *this_section_data,int IDnumber) {
4217
4218 SECTION_DATA *sdptr;
4219
4220 sdptr=NULL;
4221
4222 if (this_section_data->sempai->IDnumber==IDnumber) {
4223 /* We are that section! */
4224 return(this_section_data);
4225 }
4226
4227 /* Now call recursion... */
4228
4229 if (this_section_data->First_Child!=NULL) {
4230
4231 SECTION_DATA *child_list_ptr;
4232
4233 child_list_ptr=this_section_data->First_Child;
4234
4235 while (child_list_ptr!=NULL) {
4236 sdptr=GetSectionFromID_Recursion(child_list_ptr,IDnumber);
4237 child_list_ptr=child_list_ptr->Next_Sibling;
4238
4239 if (sdptr) {
4240 return(sdptr); /* We got one! */
4241 }
4242 }
4243 }
4244
4245 return(sdptr);
4246
4247 }
4248
4249 SECTION_DATA *GetThisSectionData_FromID(SECTION_DATA *root,int IDnumber) {
4250
4251 if (root==NULL) {
4252 return(NULL);
4253 }
4254
4255 return(GetSectionFromID_Recursion(root,IDnumber));
4256
4257 }
4258
4259 SECTION *GetThisSection_FromID(SECTION *this_section,int IDnumber)
4260 {
4261 if (this_section==NULL) {
4262 return(NULL);
4263 }
4264
4265 //is this the section that we're looking for
4266 if(this_section->IDnumber == IDnumber) return this_section;
4267
4268 //try this section's children then
4269 if(this_section->Children)
4270 {
4271 SECTION **child_list_ptr = this_section->Children;
4272
4273 while(*child_list_ptr)
4274 {
4275 SECTION* return_section = GetThisSection_FromID(*child_list_ptr,IDnumber);
4276 if(return_section) return return_section;
4277 child_list_ptr++;
4278 }
4279 }
4280
4281 //out of luck
4282 return NULL;
4283 }
4284
4285
4286 void PlayHierarchySound(HIERARCHY_SOUND* sound,VECTORCH* location)
4287 {
4288 GLOBALASSERT(sound);
4289 GLOBALASSERT(location);
4290
4291 sound->s3d.position=*location;
4292
4293 if (!Global_VDB_Ptr) {
4294 return;
4295 }
4296
4297 /* Marine_ignore, to stop them getting alarmed by their own footsteps! */
4298 Sound_Play (sound->sound_index, "nvpm", &sound->s3d,sound->volume,sound->pitch);
4299 }
4300
4301 void Init_Tweening_ToTheMiddle_Recursion(SECTION_DATA *this_section_data, int target_sequence_type,int target_subsequence, int seconds_for_tweening, int target_sequence_timer, int backwards) {
4302
4303 SEQUENCE *sequence_ptr;
4304
4305 /* Firstly, store current state. */
4306
4307 this_section_data->stored_offset=this_section_data->Offset;
4308 MatToQuat(&this_section_data->RelSecMat,&this_section_data->stored_quat);
4309
4310 /* Now, get target state. */
4311
4312 sequence_ptr=GetSequencePointer(target_sequence_type,target_subsequence,this_section_data->sempai);
4313
4314 /* Deduce target positions. Backwards flag is irrelevant... */
4315
4316 {
4317 int a,working_timer,lerp;
4318 KEYFRAME_DATA *this_frame,*next_frame;
4319
4320 this_frame=sequence_ptr->first_frame;
4321 GLOBALASSERT(this_frame);
4322 working_timer=target_sequence_timer;
4323
4324 a=0; /* Status flag... */
4325
4326 while (a==0) {
4327 if (this_frame->last_frame) {
4328 /* Low framerate loop? */
4329 next_frame=sequence_ptr->first_frame;
4330 }
4331 else{
4332 next_frame=this_frame->Next_Frame;
4333 }
4334 if (working_timer>=this_frame->Sequence_Length) {
4335 /* We've gone beyond this frame: get next keyframe. */
4336 working_timer-=this_frame->Sequence_Length;
4337 /* Advance frame... */
4338 this_frame=next_frame;
4339 } else {
4340 a=1; /* Exit loop with success. */
4341 }
4342 /* Better make sure the last 'frame' has 65536 length... */
4343 }
4344 GLOBALASSERT(working_timer>=0);
4345 /* Now we should have a frame and a timer. */
4346 lerp=MUL_FIXED(working_timer,this_frame->oneoversequencelength);
4347
4348 GetKeyFrameOffset(this_frame,&this_section_data->target_offset);
4349
4350 if(next_frame->shift_offset)
4351 {
4352 VECTORCH next_offset;
4353 GetKeyFrameOffset(next_frame,&next_offset);
4354 this_section_data->target_offset.vx+=MUL_FIXED(next_offset.vx - this_section_data->target_offset.vx,lerp);
4355 this_section_data->target_offset.vy+=MUL_FIXED(next_offset.vy - this_section_data->target_offset.vy,lerp);
4356 this_section_data->target_offset.vz+=MUL_FIXED(next_offset.vz - this_section_data->target_offset.vz,lerp);
4357 }
4358 else
4359 {
4360 this_section_data->target_offset.vx+=MUL_FIXED((int)next_frame->Offset_x - this_section_data->target_offset.vx,lerp);
4361 this_section_data->target_offset.vy+=MUL_FIXED((int)next_frame->Offset_y - this_section_data->target_offset.vy,lerp);
4362 this_section_data->target_offset.vz+=MUL_FIXED((int)next_frame->Offset_z - this_section_data->target_offset.vz,lerp);
4363 }
4364
4365 /* Now deal with orientation. */
4366
4367 Slerp(this_frame,lerp,&this_section_data->target_quat);
4368
4369 }
4370
4371 /* Preprocess slerp values. */
4372
4373 {
4374
4375 this_section_data->delta_offset.vx=this_section_data->target_offset.vx-this_section_data->stored_offset.vx;
4376 this_section_data->delta_offset.vy=this_section_data->target_offset.vy-this_section_data->stored_offset.vy;
4377 this_section_data->delta_offset.vz=this_section_data->target_offset.vz-this_section_data->stored_offset.vz;
4378
4379 }
4380
4381 {
4382 int cosom,sinom;
4383 QUAT *this_quat, *next_quat;
4384
4385 this_quat=&this_section_data->stored_quat;
4386 next_quat=&this_section_data->target_quat;
4387
4388
4389 cosom=QDot(this_quat,next_quat);
4390
4391 if (cosom<0) {
4392 next_quat->quatx=-next_quat->quatx;
4393 next_quat->quaty=-next_quat->quaty;
4394 next_quat->quatz=-next_quat->quatz;
4395 next_quat->quatw=-next_quat->quatw;
4396 cosom=-cosom;
4397 }
4398
4399
4400 this_section_data->omega=ArcCos(cosom);
4401 sinom=GetSin(this_section_data->omega);
4402 if (sinom) {
4403 this_section_data->oneoversinomega=GetOneOverSin(this_section_data->omega);
4404 } else {
4405 /* Yuk. */
4406 this_section_data->omega=0;
4407 this_section_data->oneoversinomega=0;
4408 }
4409
4410 GLOBALASSERT(seconds_for_tweening>0);
4411 this_section_data->oneovertweeninglength=DIV_FIXED(ONE_FIXED,seconds_for_tweening);
4412
4413 }
4414
4415 /* Init fields... I guess. */
4416
4417 this_section_data->current_sequence=sequence_ptr;
4418 this_section_data->current_keyframe=sequence_ptr->first_frame;
4419 this_section_data->accumulated_timer=0;
4420 this_section_data->freezeframe_timer=-1;
4421 this_section_data->lastframe_timer=0;
4422 this_section_data->gore_timer=0; /* As good a time as any. */
4423
4424 this_section_data->Tweening=1;
4425
4426 /* Animation? */
4427
4428 /* Nah. */
4429
4430 /* Recurse. */
4431
4432 if ( (this_section_data->First_Child!=NULL)
4433 &&( (this_section_data->flags§ion_data_terminate_here)==0)) {
4434 /* Respect the terminator! */
4435
4436 SECTION_DATA *child_list_ptr;
4437
4438 child_list_ptr=this_section_data->First_Child;
4439
4440 while (child_list_ptr!=NULL) {
4441 Init_Tweening_ToTheMiddle_Recursion(child_list_ptr,target_sequence_type,target_subsequence,seconds_for_tweening,target_sequence_timer,backwards);
4442 child_list_ptr=child_list_ptr->Next_Sibling;
4443 }
4444
4445 }
4446
4447 }
4448
4449
4450 void InitHModelTweening_ToTheMiddle(HMODELCONTROLLER *controller, int seconds_for_tweening,
4451 int target_sequence_type, int target_subsequence, int target_seconds_for_sequence, int target_sequence_timer, int loop) {
4452
4453 /* Just set it up... */
4454 GLOBALASSERT(target_seconds_for_sequence);
4455
4456 controller->Sequence_Type=target_sequence_type;
4457 controller->Sub_Sequence=target_subsequence;
4458 controller->Seconds_For_Sequence=seconds_for_tweening;
4459 controller->timer_increment=DIV_FIXED(ONE_FIXED,controller->Seconds_For_Sequence);
4460 controller->sequence_timer=0;
4461 controller->Playing=1;
4462 controller->Reversed=0;
4463 controller->Looped=1;
4464
4465 controller->After_Tweening_Sequence_Type=target_sequence_type;
4466 controller->After_Tweening_Sub_Sequence=target_subsequence;
4467 controller->AT_seconds_for_sequence=target_seconds_for_sequence;
4468
4469 controller->AT_sequence_timer=target_sequence_timer;
4470 while (controller->AT_sequence_timer>=ONE_FIXED) {
4471 controller->AT_sequence_timer-=ONE_FIXED;
4472 }
4473
4474 controller->Tweening=Controller_Tweening;
4475 if (loop) {
4476 controller->LoopAfterTweening=1;
4477 } else {
4478 controller->LoopAfterTweening=0;
4479 }
4480 controller->StopAfterTweening=0;
4481 controller->ElevationTweening=0;
4482
4483 /* Recurse though hierarchy, setting up all the section_data sequence stores? */
4484
4485 Init_Tweening_ToTheMiddle_Recursion(controller->section_data, target_sequence_type, target_subsequence,seconds_for_tweening,target_sequence_timer,0);
4486
4487 }
4488
4489 void Verify_Positions_Recursion(HMODELCONTROLLER *controller,SECTION_DATA *this_section_data,VECTORCH *parent_position,char *callCode) {
4490
4491 /* Verify positions... */
4492
4493 if ( !( (this_section_data->World_Offset.vx<1000000 && this_section_data->World_Offset.vx>-1000000)
4494 && (this_section_data->World_Offset.vy<1000000 && this_section_data->World_Offset.vy>-1000000)
4495 && (this_section_data->World_Offset.vz<1000000 && this_section_data->World_Offset.vz>-1000000)
4496 ) ) {
4497
4498 LOGDXFMT(("Tests in VERIFY_POSITIONS_RECURSION.\n"));
4499 if (callCode) {
4500 LOGDXFMT(("Call code %s\n",callCode));
4501 } else {
4502 LOGDXFMT(("No call code!\n"));
4503 }
4504 if (Global_HModel_Sptr) {
4505 LOGDXFMT(("Misplaced object is of type %d\n",Global_HModel_Sptr->I_SBtype));
4506 if (Global_HModel_Sptr->SBdptr) {
4507 LOGDXFMT(("Object is Near.\n"));
4508 } else {
4509 LOGDXFMT(("Object is Far.\n"));
4510 }
4511 } else {
4512 LOGDXFMT(("Misplaced object has no SBptr.\n"));
4513 }
4514 LOGDXFMT(("Name of section: %s\n",this_section_data->sempai->Section_Name));
4515 LOGDXFMT(("It was playing sequence: %d,%d\n",controller->Sequence_Type,controller->Sub_Sequence));
4516 LOGDXFMT(("Sequence Timer = %d\n",controller->sequence_timer));
4517 LOGDXFMT(("Tweening flags %d\n",controller->Tweening));
4518
4519 LOGDXFMT(("Parent Position %d,%d,%d\n",parent_position->vx,parent_position->vy,parent_position->vz));
4520 LOGDXFMT(("This Position %d,%d,%d\n",this_section_data->World_Offset.vx,this_section_data->World_Offset.vy,this_section_data->World_Offset.vz));
4521
4522 LOCALASSERT(this_section_data->World_Offset.vx<1000000 && this_section_data->World_Offset.vx>-1000000);
4523 LOCALASSERT(this_section_data->World_Offset.vy<1000000 && this_section_data->World_Offset.vy>-1000000);
4524 LOCALASSERT(this_section_data->World_Offset.vz<1000000 && this_section_data->World_Offset.vz>-1000000);
4525
4526 }
4527
4528 /* Now call recursion... */
4529
4530 if (this_section_data->First_Child!=NULL) {
4531
4532 SECTION_DATA *child_list_ptr;
4533
4534 child_list_ptr=this_section_data->First_Child;
4535
4536 while (child_list_ptr!=NULL) {
4537 Verify_Positions_Recursion(controller,child_list_ptr,&this_section_data->World_Offset,callCode);
4538 child_list_ptr=child_list_ptr->Next_Sibling;
4539 }
4540 }
4541
4542 return;
4543
4544 }
4545
4546 void Verify_Positions_In_HModel(STRATEGYBLOCK *sbPtr,HMODELCONTROLLER *controller,char *callCode) {
4547
4548 /* Verify position integrity. */
4549
4550 if ((controller==NULL)||(sbPtr==NULL)) {
4551 return;
4552 }
4553
4554 /* */
4555
4556 Global_HModel_Sptr=sbPtr;
4557 Global_Controller_Ptr=controller;
4558 Global_HModel_DispPtr=sbPtr->SBdptr;
4559
4560 Verify_Positions_Recursion(controller,controller->section_data,&sbPtr->DynPtr->Position,callCode);
4561
4562 }
4563
4564
4565
4566
4567 void CopyShortQuatToInt(QUAT_SHORT* qs,QUAT* q)
4568 {
4569 q->quatx=((int)qs->quatx)<<1;
4570 q->quaty=((int)qs->quaty)<<1;
4571 q->quatz=((int)qs->quatz)<<1;
4572 q->quatw=((int)qs->quatw)<<1;
4573 }
4574
4575
4576 void CopyIntQuatToShort(QUAT* q,QUAT_SHORT* qs)
4577 {
4578 if(q->quatx>65535) qs->quatx=32767;
4579 else if(q->quatx<-65536) qs->quatx=-32768;
4580 else qs->quatx=q->quatx>>1;
4581
4582 if(q->quaty>65535) qs->quaty=32767;
4583 else if(q->quaty<-65536) qs->quaty=-32768;
4584 else qs->quaty=q->quaty>>1;
4585
4586 if(q->quatz>65535) qs->quatz=32767;
4587 else if(q->quatz<-65536) qs->quatz=-32768;
4588 else qs->quatz=q->quatz>>1;
4589
4590 if(q->quatw>65535) qs->quatw=32767;
4591 else if(q->quatw<-65536) qs->quatw=-32768;
4592 else qs->quatw=q->quatw>>1;
4593
4594 }
4595
4596 void GetKeyFrameOffset(KEYFRAME_DATA* frame,VECTORCH* output_vector)
4597 {
4598 if(frame->shift_offset)
4599 {
4600 output_vector->vx=((int)frame->Offset_x)<<KEYFRAME_VECTOR_SHIFT;
4601 output_vector->vy=((int)frame->Offset_y)<<KEYFRAME_VECTOR_SHIFT;
4602 output_vector->vz=((int)frame->Offset_z)<<KEYFRAME_VECTOR_SHIFT;
4603 }
4604 else
4605 {
4606 output_vector->vx=(int)frame->Offset_x;
4607 output_vector->vy=(int)frame->Offset_y;
4608 output_vector->vz=(int)frame->Offset_z;
4609 }
4610 }
4611
4612
4613 void SetKeyFrameOffset(KEYFRAME_DATA* frame,VECTORCH* input_vector)
4614 {
4615 if(input_vector->vx>=-32768 && input_vector->vx<=32767 &&
4616 input_vector->vy>=-32768 && input_vector->vy<=32767 &&
4617 input_vector->vz>=-32768 && input_vector->vz<=32767)
4618 {
4619 frame->Offset_x=(short)input_vector->vx;
4620 frame->Offset_y=(short)input_vector->vy;
4621 frame->Offset_z=(short)input_vector->vz;
4622
4623 frame->shift_offset=0;
4624 }
4625 else
4626 {
4627 frame->Offset_x=(short)(input_vector->vx >> KEYFRAME_VECTOR_SHIFT);
4628 frame->Offset_y=(short)(input_vector->vy >> KEYFRAME_VECTOR_SHIFT);
4629 frame->Offset_z=(short)(input_vector->vz >> KEYFRAME_VECTOR_SHIFT);
4630
4631 frame->shift_offset=1;
4632
4633 }
4634 }
4635
4636 int HModelDepthTest_Recursion(SECTION_DATA *this_section_data, SECTION_DATA *test_section_data,int depth) {
4637
4638 SECTION_DATA *sdptr;
4639 int totals;
4640
4641 sdptr=NULL;
4642 totals=0;
4643
4644 /* Return if too deep. */
4645 if (depth<0) {
4646 return(0);
4647 }
4648
4649 /* Test this section? */
4650 if (this_section_data==test_section_data) {
4651 /* Success. */
4652 return(1);
4653 }
4654
4655 /* Now call recursion... */
4656
4657 if (this_section_data->First_Child!=NULL) {
4658
4659 SECTION_DATA *child_list_ptr;
4660
4661 child_list_ptr=this_section_data->First_Child;
4662
4663 while (child_list_ptr!=NULL) {
4664 totals+=HModelDepthTest_Recursion(child_list_ptr,test_section_data,depth-1);
4665 child_list_ptr=child_list_ptr->Next_Sibling;
4666 }
4667 }
4668
4669 return(totals);
4670
4671 }
4672
4673 int HModel_DepthTest(HMODELCONTROLLER *controller,SECTION_DATA *test_section_data,int depth) {
4674
4675 /* Regenerate sections. */
4676
4677 return(HModelDepthTest_Recursion(controller->section_data,test_section_data,depth));
4678
4679 }
4680
4681 void DeInitialise_Recursion(SECTION_DATA *this_section_data) {
4682
4683 SECTION_DATA *sdptr;
4684
4685 sdptr=NULL;
4686
4687 this_section_data->flags=this_section_data->flags&(~section_data_initialised);
4688
4689 /* Now call recursion... */
4690
4691 if (this_section_data->First_Child!=NULL) {
4692
4693 SECTION_DATA *child_list_ptr;
4694
4695 child_list_ptr=this_section_data->First_Child;
4696
4697 while (child_list_ptr!=NULL) {
4698 DeInitialise_Recursion(child_list_ptr);
4699 child_list_ptr=child_list_ptr->Next_Sibling;
4700 }
4701 }
4702
4703 return;
4704
4705 }
4706
4707 void DeInitialise_HModel(HMODELCONTROLLER *controller) {
4708
4709 /* Recursively set all 'initialised' flags to zero. */
4710
4711 if (controller==NULL) {
4712 return;
4713 }
4714
4715 DeInitialise_Recursion(controller->section_data);
4716
4717 }
4718
4719
4720 static void EnsureChildrenAreInAscendingIDOrder(SECTION_DATA* section)
4721 {
4722 /*
4723 This checks all the children of a section to make sure that they are placed in ascending Id order.
4724 This is needed for the saving and loading process to work properly.
4725 (In the majority of cases, sections will be in the right order , so this should be fairly quick)
4726 */
4727
4728 SECTION_DATA* child_section = section->First_Child;
4729
4730 if(!child_section) return;
4731
4732 while(child_section->Next_Sibling)
4733 {
4734 SECTION_DATA* next_section = child_section->Next_Sibling;
4735 if(next_section->sempai->IDnumber<child_section->sempai->IDnumber)
4736 {
4737 /*
4738 These two sections are out of order , so we need to swap them
4739 */
4740
4741
4742 /*First correct the children before and adter the ones being swapped*/
4743
4744 if(child_section->Prev_Sibling)
4745 {
4746 child_section->Prev_Sibling->Next_Sibling = next_section;
4747 }
4748 if(next_section->Next_Sibling)
4749 {
4750 next_section->Next_Sibling->Prev_Sibling = child_section;
4751 }
4752
4753 /*
4754 If we are swapping the first child , then we need to alter the parent's pointer
4755 */
4756 if(section->First_Child == child_section)
4757 {
4758 section->First_Child = next_section;
4759 }
4760
4761
4762 /*
4763 Give the sections being swapped the pointers to the sections before and after them
4764 */
4765 child_section->Next_Sibling = next_section->Next_Sibling;
4766 next_section->Prev_Sibling = child_section->Prev_Sibling;
4767
4768
4769 child_section->Prev_Sibling = next_section;
4770 next_section->Next_Sibling = child_section;
4771
4772
4773 /*The next section we will have to consider is the one we have just swapped ealier in the list*/
4774 child_section = next_section;
4775
4776 /*
4777 If the section has a previous sibling then we need to look back at that one , since the previous sibling's
4778 if could be higher than that of the section we have just swapped
4779 */
4780
4781 if(child_section->Prev_Sibling) child_section = child_section->Prev_Sibling;
4782
4783 }
4784 else
4785 {
4786 //No problem with this section , go on to the next
4787 child_section = child_section->Next_Sibling;
4788 }
4789 }
4790 }
4791
4792 /*--------------------**
4793 ** Loading and Saving **
4794 **--------------------*/
4795 #include "savegame.h"
4796
4797 static void LoadHierarchySection(SECTION_DATA* section);
4798 static void SaveHierarchySectionRecursion(SECTION_DATA* section);
4799
4800 static void LoadHierarchySectionDecals(SAVE_BLOCK_HEADER* header,SECTION_DATA* section);
4801 static void SaveHierarchySectionDecals(SECTION_DATA* section);
4802
4803 static void LoadHierarchySectionTween(SAVE_BLOCK_HEADER* header,SECTION_DATA* section);
4804 static void SaveHierarchySectionTween(SECTION_DATA* section);
4805
4806 static void LoadHierarchyDelta(SAVE_BLOCK_HEADER* header,HMODELCONTROLLER* controller);
4807 static void SaveHierarchyDelta(DELTA_CONTROLLER* delta);
4808
4809 typedef struct hierarchy_save_block
4810 {
4811 SAVE_BLOCK_HEADER header;
4812
4813 int structure_size;
4814
4815 int Seconds_For_Sequence;
4816 int timer_increment;
4817 int Sequence_Type;
4818 int Sub_Sequence;
4819 int sequence_timer;
4820 int FrameStamp;
4821 VECTORCH Computed_Position;
4822
4823 int keyframe_flags;
4824
4825 int After_Tweening_Sequence_Type;
4826 int After_Tweening_Sub_Sequence;
4827 int AT_seconds_for_sequence;
4828 int AT_sequence_timer;
4829
4830 unsigned int Playing:1;
4831 unsigned int Reversed:1;
4832 unsigned int Looped:1;
4833 unsigned int Tweening:2;
4834 unsigned int LoopAfterTweening:1;
4835 unsigned int StopAfterTweening:1;
4836 unsigned int ElevationTweening:1;
4837 unsigned int DisableBleeding:1;
4838 unsigned int LockTopSection:1;
4839 unsigned int ZeroRootDisplacement:1;
4840 unsigned int ZeroRootRotation:1;
4841 unsigned int DisableSounds:1;
4842
4843 int root_section_id;
4844
4845 }HIERARCHY_SAVE_BLOCK;
4846
4847
4848 //defines for load/save macros
4849 #define SAVELOAD_BLOCK block
4850 #define SAVELOAD_BEHAV controller
4851
4852
4853 void LoadHierarchy(SAVE_BLOCK_HEADER* header,HMODELCONTROLLER* controller)
4854 {
4855 SECTION *root_section;
4856 const char *Rif_Name;
4857 const char *Hierarchy_Name;
4858 HIERARCHY_SAVE_BLOCK* block = (HIERARCHY_SAVE_BLOCK*) header;
4859
4860 //make sure the block is the correct size
4861 if(block->structure_size != sizeof(*block)) return;
4862
4863 //get the names from just after the block
4864 {
4865 char* buffer=(char*) header;
4866 buffer+=sizeof(*block);
4867
4868 Hierarchy_Name = buffer;
4869 buffer+= strlen(Hierarchy_Name)+1;
4870 Rif_Name = buffer;
4871 }
4872
4873 {
4874 BOOL needToCreateHModel = FALSE;
4875
4876 //make sure that the initial model has been set up , and is using the correct hierarchy
4877 if(controller->Root_Section)
4878 {
4879 if(strcmp(Rif_Name,controller->Root_Section->Rif_Name) || strcmp(Hierarchy_Name,controller->Root_Section->Hierarchy_Name))
4880 {
4881 needToCreateHModel = TRUE;
4882 }
4883 else if(controller->Root_Section->IDnumber != block->root_section_id)
4884 {
4885 needToCreateHModel = TRUE;
4886 }
4887 }
4888 else
4889 {
4890 needToCreateHModel = TRUE;
4891 }
4892
4893 //check to see if we need to change hierarchy
4894 if(needToCreateHModel)
4895 {
4896 extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name);
4897
4898 root_section = GetNamedHierarchyFromLibrary(Rif_Name,Hierarchy_Name);
4899 if(!root_section) return;
4900
4901 //may not want the 'real' root (hierarchical debris)
4902 root_section = GetThisSection_FromID(root_section,block->root_section_id);
4903 if(!root_section) return;
4904
4905
4906 //reinitialise the hierarchy
4907 Dispel_HModel(controller);
4908 Create_HModel(controller,root_section);
4909 }
4910 }
4911
4912 //copy the stuff for the controller
4913 COPYELEMENT_LOAD(Seconds_For_Sequence)
4914 COPYELEMENT_LOAD(timer_increment)
4915 COPYELEMENT_LOAD(Sequence_Type)
4916 COPYELEMENT_LOAD(Sub_Sequence)
4917 COPYELEMENT_LOAD(sequence_timer)
4918 COPYELEMENT_LOAD(FrameStamp)
4919 COPYELEMENT_LOAD(Computed_Position)
4920 COPYELEMENT_LOAD(keyframe_flags)
4921 COPYELEMENT_LOAD(After_Tweening_Sequence_Type)
4922 COPYELEMENT_LOAD(After_Tweening_Sub_Sequence)
4923 COPYELEMENT_LOAD(AT_seconds_for_sequence)
4924 COPYELEMENT_LOAD(AT_sequence_timer)
4925 COPYELEMENT_LOAD(Playing)
4926 COPYELEMENT_LOAD(Reversed)
4927 COPYELEMENT_LOAD(Looped)
4928 COPYELEMENT_LOAD(Tweening)
4929 COPYELEMENT_LOAD(LoopAfterTweening)
4930 COPYELEMENT_LOAD(StopAfterTweening)
4931 COPYELEMENT_LOAD(ElevationTweening)
4932 COPYELEMENT_LOAD(DisableBleeding)
4933 COPYELEMENT_LOAD(LockTopSection)
4934 COPYELEMENT_LOAD(ZeroRootDisplacement)
4935 COPYELEMENT_LOAD(ZeroRootRotation)
4936 COPYELEMENT_LOAD(DisableSounds);
4937
4938
4939 //load the delta sequences
4940 {
4941 SAVE_BLOCK_HEADER* delta_header;
4942
4943 while((delta_header = GetNextBlockIfOfType(SaveBlock_HierarchyDelta)))
4944 {
4945 LoadHierarchyDelta(delta_header,controller);
4946 }
4947
4948 }
4949
4950 ///load the section data
4951 LoadHierarchySection(controller->section_data);
4952
4953 }
4954
4955
4956 void SaveHierarchy(HMODELCONTROLLER* controller)
4957 {
4958 HIERARCHY_SAVE_BLOCK* block;
4959 if(!controller) return;
4960 if(!controller->Root_Section) return;
4961
4962 GET_SAVE_BLOCK_POINTER(block);
4963
4964 //fill in header
4965 block->header.type = SaveBlock_Hierarchy;
4966 block->header.size = sizeof(*block);
4967 block->structure_size =block->header.size;
4968
4969 COPYELEMENT_SAVE(Seconds_For_Sequence)
4970 COPYELEMENT_SAVE(timer_increment)
4971 COPYELEMENT_SAVE(Sequence_Type)
4972 COPYELEMENT_SAVE(Sub_Sequence)
4973 COPYELEMENT_SAVE(sequence_timer)
4974 COPYELEMENT_SAVE(FrameStamp)
4975 COPYELEMENT_SAVE(Computed_Position)
4976 COPYELEMENT_SAVE(keyframe_flags)
4977 COPYELEMENT_SAVE(After_Tweening_Sequence_Type)
4978 COPYELEMENT_SAVE(After_Tweening_Sub_Sequence)
4979 COPYELEMENT_SAVE(AT_seconds_for_sequence)
4980 COPYELEMENT_SAVE(AT_sequence_timer)
4981 COPYELEMENT_SAVE(Playing)
4982 COPYELEMENT_SAVE(Reversed)
4983 COPYELEMENT_SAVE(Looped)
4984 COPYELEMENT_SAVE(Tweening)
4985 COPYELEMENT_SAVE(LoopAfterTweening)
4986 COPYELEMENT_SAVE(StopAfterTweening)
4987 COPYELEMENT_SAVE(ElevationTweening)
4988 COPYELEMENT_SAVE(DisableBleeding)
4989 COPYELEMENT_SAVE(LockTopSection)
4990 COPYELEMENT_SAVE(ZeroRootDisplacement)
4991 COPYELEMENT_SAVE(ZeroRootRotation)
4992 COPYELEMENT_SAVE(DisableSounds);
4993
4994 block->root_section_id = controller->Root_Section->IDnumber;
4995
4996 {
4997 char* buffer;
4998 char* Hierarchy_Name = controller->Root_Section->Hierarchy_Name;
4999 char* Rif_Name = controller->Root_Section->Rif_Name;
5000
5001 //increase the block size by enough to hold these names
5002 block->header.size+= strlen(Hierarchy_Name)+strlen(Rif_Name)+2;
5003
5004 //alllocate memoey , and copy names;
5005 buffer = GetPointerForSaveBlock(strlen(Hierarchy_Name)+1);
5006 strcpy(buffer,Hierarchy_Name);
5007
5008 buffer = GetPointerForSaveBlock(strlen(Rif_Name)+1);
5009 strcpy(buffer,Rif_Name);
5010
5011 }
5012
5013 //save the delta sequences
5014 {
5015 DELTA_CONTROLLER* delta = controller->Deltas;
5016
5017 while(delta)
5018 {
5019 SaveHierarchyDelta(delta);
5020 delta=delta->next_controller;
5021 }
5022 }
5023
5024 //now save the section data
5025 SaveHierarchySectionRecursion(controller->section_data);
5026 }
5027
5028 typedef struct hierarchy_delta_save_block
5029 {
5030 SAVE_BLOCK_HEADER header;
5031
5032 int timer;
5033 int lastframe_timer;
5034 int sequence_type;
5035 int sub_sequence;
5036 int seconds_for_sequence;
5037 int timer_increment;
5038 int Looped:1;
5039 int Playing:1;
5040 int Active:1;
5041
5042 }HIERARCHY_DELTA_SAVE_BLOCK;
5043
5044 #undef SAVELOAD_BEHAV
5045 //defines for load/save macros
5046 #define SAVELOAD_BEHAV delta
5047
5048 static void LoadHierarchyDelta(SAVE_BLOCK_HEADER* header,HMODELCONTROLLER* controller)
5049 {
5050 DELTA_CONTROLLER* delta;
5051 HIERARCHY_DELTA_SAVE_BLOCK* block = (HIERARCHY_DELTA_SAVE_BLOCK*) header;
5052 char* name = (char*) (block+1);
5053
5054 delta = Get_Delta_Sequence(controller,name);
5055 if(!delta)
5056 {
5057 delta = Add_Delta_Sequence(controller,name,block->sequence_type,block->sub_sequence,block->seconds_for_sequence);
5058 }
5059
5060
5061 COPYELEMENT_LOAD(timer)
5062 COPYELEMENT_LOAD(lastframe_timer)
5063 COPYELEMENT_LOAD(timer_increment)
5064 COPYELEMENT_LOAD(Looped)
5065 COPYELEMENT_LOAD(Playing)
5066 COPYELEMENT_LOAD(Active)
5067 COPYELEMENT_LOAD(sequence_type)
5068 COPYELEMENT_LOAD(sub_sequence)
5069 COPYELEMENT_LOAD(seconds_for_sequence)
5070
5071
5072
5073
5074 }
5075
5076 static void SaveHierarchyDelta(DELTA_CONTROLLER* delta)
5077 {
5078 HIERARCHY_DELTA_SAVE_BLOCK* block;
5079 int size;
5080
5081 //work out memory needed
5082 size=sizeof(*block) + strlen(delta->id) +1;
5083 block = (HIERARCHY_DELTA_SAVE_BLOCK*) GetPointerForSaveBlock(size);
5084
5085 //fill in the header
5086 block->header.size = size;
5087 block->header.type = SaveBlock_HierarchyDelta;
5088
5089 COPYELEMENT_SAVE(timer)
5090 COPYELEMENT_SAVE(lastframe_timer)
5091 COPYELEMENT_SAVE(timer_increment)
5092 COPYELEMENT_SAVE(Looped)
5093 COPYELEMENT_SAVE(Playing)
5094 COPYELEMENT_SAVE(Active)
5095 COPYELEMENT_SAVE(sequence_type)
5096 COPYELEMENT_SAVE(sub_sequence)
5097 COPYELEMENT_SAVE(seconds_for_sequence)
5098
5099 //tack the name on the end
5100 {
5101 char* name = (char*)(block+1);
5102 strcpy(name,delta->id);
5103 }
5104
5105
5106 }
5107
5108
5109 typedef struct hierarchy_section_save_block
5110 {
5111 SAVE_BLOCK_HEADER header;
5112
5113 //from section
5114 int IDnumber;
5115
5116 //from section_data
5117 VECTORCH Offset;
5118 VECTORCH World_Offset;
5119 VECTORCH Last_World_Offset;
5120 MATRIXCH RelSecMat;
5121 MATRIXCH SecMat;
5122
5123 struct damageblock current_damage;
5124
5125 int accumulated_timer;
5126 int freezeframe_timer;
5127 int lastframe_timer;
5128 int gore_timer;
5129
5130 int flags;
5131
5132 int sequence_id;
5133 int keyframe_time;
5134
5135
5136 int replacement_id;
5137
5138 }HIERARCHY_SECTION_SAVE_BLOCK;
5139
5140
5141 #undef SAVELOAD_BEHAV
5142 //defines for load/save macros
5143 #define SAVELOAD_BEHAV section
5144
5145 extern HIERARCHY_SHAPE_REPLACEMENT* GetHierarchyAlternateShapeFromId(const char* rif_name,int replacement_id,char* section_name);
5146
5147
5148 static void LoadHierarchySection(SECTION_DATA* section)
5149 {
5150 SAVE_BLOCK_HEADER* header;
5151 SAVE_BLOCK_HEADER* decal_header;
5152 SAVE_BLOCK_HEADER* tween_header;
5153
5154 HIERARCHY_SECTION_SAVE_BLOCK* block;
5155
5156 header=GetNextBlockIfOfType(SaveBlock_HierarchySection);
5157 decal_header=GetNextBlockIfOfType(SaveBlock_HierarchyDecals);
5158 tween_header=GetNextBlockIfOfType(SaveBlock_HierarchyTween);
5159
5160 /*
5161 In this bit we go through the hierechy section data , and saved section data in increasing
5162 ID number order. Whenever we find any sections without saved data , we need to prunce them
5163 (since they will have been blown off the original hierarchy)
5164 */
5165
5166 while(header && section)
5167 {
5168 block = (HIERARCHY_SECTION_SAVE_BLOCK*) header;
5169
5170 if(block->header.size!=sizeof(*block)) return;
5171
5172 //compare section id numbers
5173 if(block->IDnumber == section->sempai->IDnumber)
5174 {
5175 //copy stuff for this section then
5176 COPYELEMENT_LOAD(Offset);
5177 COPYELEMENT_LOAD(World_Offset);
5178 COPYELEMENT_LOAD(Last_World_Offset);
5179 COPYELEMENT_LOAD(RelSecMat);
5180 COPYELEMENT_LOAD(SecMat);
5181
5182 COPYELEMENT_LOAD(current_damage);
5183
5184 COPYELEMENT_LOAD(accumulated_timer);
5185 COPYELEMENT_LOAD(freezeframe_timer);
5186 COPYELEMENT_LOAD(lastframe_timer);
5187 COPYELEMENT_LOAD(gore_timer);
5188
5189 COPYELEMENT_LOAD(flags);
5190 COPYELEMENT_LOAD(replacement_id);
5191
5192
5193 //see if this section is using an alternate shape set
5194 {
5195 int desiredShapeIndex = section->sempai->ShapeNum;
5196 HIERARCHY_SHAPE_REPLACEMENT* replacement = GetHierarchyAlternateShapeFromId(section->sempai->Rif_Name,block->replacement_id,section->sempai->Section_Name);
5197
5198 if(replacement)
5199 {
5200 desiredShapeIndex = replacement->replacement_shape_index;
5201 }
5202
5203 if(section->ShapeNum != desiredShapeIndex)
5204 {
5205 section->ShapeNum = desiredShapeIndex;
5206
5207 if(desiredShapeIndex>=0)
5208 {
5209 section->Shape = mainshapelist[desiredShapeIndex];
5210 }
5211 else
5212 {
5213 section->Shape = 0;
5214 }
5215 Setup_Texture_Animation_For_Section(section);
5216
5217 }
5218 }
5219
5220
5221 //load decals
5222 if(decal_header)
5223 {
5224 LoadHierarchySectionDecals(decal_header,section);
5225 }
5226 else
5227 {
5228 section->NumberOfDecals = 0;
5229 section->NextDecalToUse = 0;
5230
5231 }
5232
5233 //load tweening data
5234 if(tween_header)
5235 {
5236 LoadHierarchySectionTween(tween_header,section);
5237 }
5238 else
5239 {
5240 section->Tweening = 0;
5241 }
5242
5243
5244 //get the current sequence and frame
5245
5246 {
5247 int a;
5248 int time;
5249 SECTION* this_section = section->sempai;
5250 section->current_sequence=&(this_section->sequence_array[0]);
5251
5252 for (a=0; a<this_section->num_sequences; a++) {
5253 if (this_section->sequence_array[a].sequence_id==block->sequence_id) {
5254 section->current_sequence=&(this_section->sequence_array[a]);
5255 break;
5256 }
5257 }
5258
5259 time = block->keyframe_time;
5260 section->current_keyframe = section->current_sequence->first_frame;
5261
5262 while(time>=section->current_keyframe->Sequence_Length)
5263 {
5264 time-= section->current_keyframe->Sequence_Length;
5265
5266 if(section->current_keyframe->last_frame)
5267 {
5268 break;
5269 }
5270 else
5271 {
5272 section->current_keyframe = section->current_keyframe->Next_Frame;
5273 }
5274 }
5275
5276
5277
5278
5279
5280 }
5281
5282 //move to the next section data
5283 if(section->First_Child)
5284 {
5285 section = section->First_Child;
5286 }
5287 else if (section->Next_Sibling)
5288 {
5289 section = section->Next_Sibling;
5290 }
5291 else
5292 {
5293 BOOL section_found=FALSE;
5294 while(section && !section_found)
5295 {
5296 section = section->My_Parent;
5297 if(section)
5298 {
5299 if(section->Next_Sibling)
5300 {
5301 section=section->Next_Sibling;
5302 section_found = TRUE;
5303 }
5304 }
5305 }
5306 }
5307
5308 //move to next saved section
5309 header=GetNextBlockIfOfType(SaveBlock_HierarchySection);
5310 decal_header=GetNextBlockIfOfType(SaveBlock_HierarchyDecals);
5311 tween_header=GetNextBlockIfOfType(SaveBlock_HierarchyTween);
5312 }
5313 else if(block->IDnumber > section->sempai->IDnumber)
5314 {
5315 /*
5316 There was no saved data for this section , so we will need to prune it
5317 */
5318
5319 SECTION_DATA* pruned_section = section;
5320
5321 if (section->Next_Sibling)
5322 {
5323 section = section->Next_Sibling;
5324 }
5325 else
5326 {
5327 BOOL section_found=FALSE;
5328 while(section && !section_found)
5329 {
5330 section = section->My_Parent;
5331 if(section)
5332 {
5333 if(section->Next_Sibling)
5334 {
5335 section=section->Next_Sibling;
5336 section_found = TRUE;
5337 }
5338 }
5339 }
5340 }
5341 Prune_Section(pruned_section);
5342
5343 }
5344 else
5345 {
5346 //move to next saved section (we will need to advance until the saved id number matches
5347 //the section id number)
5348 //Nb. This probably never happens anyway
5349 header=GetNextBlockIfOfType(SaveBlock_HierarchySection);
5350 decal_header=GetNextBlockIfOfType(SaveBlock_HierarchyDecals);
5351 tween_header=GetNextBlockIfOfType(SaveBlock_HierarchyTween);
5352 }
5353 }
5354
5355 //prune the remaining sections
5356 while(section)
5357 {
5358 SECTION_DATA* pruned_section = section;
5359
5360 if (section->Next_Sibling)
5361 {
5362 section = section->Next_Sibling;
5363 }
5364 else
5365 {
5366 BOOL section_found=FALSE;
5367 while(section && !section_found)
5368 {
5369 section = section->My_Parent;
5370 if(section)
5371 {
5372 if(section->Next_Sibling)
5373 {
5374 section=section->Next_Sibling;
5375 section_found = TRUE;
5376 }
5377 }
5378 }
5379 }
5380 Prune_Section(pruned_section);
5381 }
5382
5383 }
5384
5385
5386 static void SaveHierarchySectionRecursion(SECTION_DATA* section)
5387 {
5388 HIERARCHY_SECTION_SAVE_BLOCK* block;
5389
5390 GET_SAVE_BLOCK_POINTER(block);
5391
5392 //fill in header
5393 block->header.type = SaveBlock_HierarchySection;
5394 block->header.size = sizeof(*block);
5395
5396
5397 block->IDnumber = section->sempai->IDnumber;
5398
5399 //copy stuff
5400 COPYELEMENT_SAVE(Offset);
5401 COPYELEMENT_SAVE(World_Offset);
5402 COPYELEMENT_SAVE(Last_World_Offset);
5403 COPYELEMENT_SAVE(RelSecMat);
5404 COPYELEMENT_SAVE(SecMat);
5405
5406 COPYELEMENT_SAVE(current_damage);
5407
5408 COPYELEMENT_SAVE(accumulated_timer);
5409 COPYELEMENT_SAVE(freezeframe_timer);
5410 COPYELEMENT_SAVE(lastframe_timer);
5411 COPYELEMENT_SAVE(gore_timer);
5412
5413 COPYELEMENT_SAVE(flags);
5414 COPYELEMENT_SAVE(replacement_id);
5415
5416 //get current sequence id
5417 block->sequence_id = section->current_sequence->sequence_id;
5418
5419 {
5420 KEYFRAME_DATA* frame = section->current_sequence->first_frame;
5421 int time=0;
5422
5423 while(frame != section->current_keyframe)
5424 {
5425 time += frame->Sequence_Length;
5426
5427 if(frame->last_frame) break;
5428
5429 frame = frame->Next_Frame;
5430 }
5431
5432 block->keyframe_time = time;
5433
5434 }
5435
5436
5437 //save decals (if needed)
5438 if(section->NumberOfDecals)
5439 {
5440 SaveHierarchySectionDecals(section);
5441 }
5442
5443 //save tweening (if needed)
5444 if(section->Tweening)
5445 {
5446 SaveHierarchySectionTween(section);
5447 }
5448
5449 //recurse down hierarchy
5450 if (section->First_Child!=NULL) {
5451
5452 SECTION_DATA * child_section;
5453 /*
5454 Must make sure the children are in the right order before saving.
5455 */
5456 EnsureChildrenAreInAscendingIDOrder(section);
5457
5458 child_section = section->First_Child;
5459
5460 while (child_section)
5461 {
5462 SaveHierarchySectionRecursion(child_section);
5463 child_section = child_section->Next_Sibling;
5464 }
5465 }
5466
5467
5468 }
5469
5470
5471
5472 //section decal data
5473 typedef struct hierarchy_decal_save_block
5474 {
5475 SAVE_BLOCK_HEADER header;
5476
5477 int NumberOfDecals;
5478 int NextDecalToUse;
5479 OBJECT_DECAL Decals[MAX_NO_OF_DECALS_PER_HIERARCHICAL_SECTION];
5480 }HIERARCHY_DECAL_SAVE_BLOCK;
5481
5482
5483
5484
5485
5486 static void LoadHierarchySectionDecals(SAVE_BLOCK_HEADER* header,SECTION_DATA* section)
5487 {
5488 int i;
5489
5490 HIERARCHY_DECAL_SAVE_BLOCK* block = (HIERARCHY_DECAL_SAVE_BLOCK*) header;
5491
5492 COPYELEMENT_LOAD(NumberOfDecals);
5493 COPYELEMENT_LOAD(NextDecalToUse);
5494
5495 for(i=0;i<block->NumberOfDecals;i++)
5496 {
5497 COPYELEMENT_LOAD(Decals[i]);
5498 }
5499
5500 }
5501
5502
5503 static void SaveHierarchySectionDecals(SECTION_DATA* section)
5504 {
5505 HIERARCHY_DECAL_SAVE_BLOCK* block;
5506 int i;
5507
5508 //determine how much space is required for the decals present
5509 int size = sizeof(HIERARCHY_DECAL_SAVE_BLOCK);
5510 size -= (MAX_NO_OF_DECALS_PER_HIERARCHICAL_SECTION - section->NumberOfDecals) * sizeof(OBJECT_DECAL);
5511
5512 block = (HIERARCHY_DECAL_SAVE_BLOCK*) GetPointerForSaveBlock(size);
5513
5514 //fill in the header
5515 block->header.type = SaveBlock_HierarchyDecals;
5516 block->header.size = size;
5517
5518 //copy the decals
5519
5520 COPYELEMENT_SAVE(NumberOfDecals);
5521 COPYELEMENT_SAVE(NextDecalToUse);
5522
5523 for(i=0;i<block->NumberOfDecals;i++)
5524 {
5525 COPYELEMENT_SAVE(Decals[i]);
5526 }
5527
5528
5529 }
5530
5531
5532 //section tweening data
5533 typedef struct hierarchy_tween_save_block
5534 {
5535 SAVE_BLOCK_HEADER header;
5536
5537 /* Tweening */
5538 VECTORCH stored_offset;
5539 VECTORCH target_offset;
5540 VECTORCH delta_offset;
5541 QUAT stored_quat;
5542 QUAT target_quat;
5543 int omega;
5544 int oneoversinomega;
5545 int oneovertweeninglength;
5546 unsigned int Tweening:1;
5547
5548
5549 }HIERARCHY_TWEEN_SAVE_BLOCK;
5550
5551 static void LoadHierarchySectionTween(SAVE_BLOCK_HEADER* header,SECTION_DATA* section)
5552 {
5553 //see if this section has tweening data saved
5554 HIERARCHY_TWEEN_SAVE_BLOCK* block = (HIERARCHY_TWEEN_SAVE_BLOCK*) header;
5555 if(!block) return;
5556
5557 COPYELEMENT_LOAD(stored_offset);
5558 COPYELEMENT_LOAD(target_offset);
5559 COPYELEMENT_LOAD(delta_offset);
5560 COPYELEMENT_LOAD(stored_quat);
5561 COPYELEMENT_LOAD(target_quat);
5562 COPYELEMENT_LOAD(omega);
5563 COPYELEMENT_LOAD(oneoversinomega);
5564 COPYELEMENT_LOAD(oneovertweeninglength);
5565 COPYELEMENT_LOAD(Tweening);
5566 }
5567
5568 static void SaveHierarchySectionTween(SECTION_DATA* section)
5569 {
5570 HIERARCHY_TWEEN_SAVE_BLOCK* block;
5571
5572 GET_SAVE_BLOCK_POINTER(block);
5573
5574 //fill in the header
5575 block->header.type = SaveBlock_HierarchyTween;
5576 block->header.size = sizeof(*block);
5577
5578 //copy stuff
5579
5580 COPYELEMENT_SAVE(stored_offset);
5581 COPYELEMENT_SAVE(target_offset);
5582 COPYELEMENT_SAVE(delta_offset);
5583 COPYELEMENT_SAVE(stored_quat);
5584 COPYELEMENT_SAVE(target_quat);
5585 COPYELEMENT_SAVE(omega);
5586 COPYELEMENT_SAVE(oneoversinomega);
5587 COPYELEMENT_SAVE(oneovertweeninglength);
5588 COPYELEMENT_SAVE(Tweening);
5589
5590 }
5591