1 /*
2 PLIB - A Suite of Portable Game Libraries
3 Copyright (C) 1998,2002 Steve Baker
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 For further information visit http://plib.sourceforge.net
20
21 $Id: ssgLoadMDL.cxx 2012 2005-01-15 20:36:46Z sjbaker $
22 */
23
24 //===========================================================================
25 //
26 // File: GngMsfsIO.cpp
27 //
28 // Created: Tue Feb 29 22:20:31 2000
29 //
30 // Author: Thomas Engh Sevaldrud <tse@math.sintef.no>
31 //
32 // Revision: $Id: ssgLoadMDL.cxx 2012 2005-01-15 20:36:46Z sjbaker $
33 //
34 // Description:
35 //
36 //===========================================================================
37 // Copyright (c) 2000 Thomas E. Sevaldrud <tse@math.sintef.no>
38 //===========================================================================
39
40 #include "ssgLocal.h"
41
42 // kludge: global
43 int g_noLoDs =1;
44
45 #ifdef SSG_LOAD_MDL_SUPPORTED
46
47 #include "ssgLoadMDL.h"
48
49 #define DEF_SHININESS 50
50
51 //#define DEBUG
52
53 #ifdef DEBUG
54 #include <iostream>
55 #define DEBUGPRINT(x) std::cerr << x
56 #else
57 #define DEBUGPRINT(x)
58 #endif
59
60 static ssgLoaderOptions *current_options;
61
62 // Temporary vertex arrays
63 static ssgVertexArray *curr_vtx_;
64 static ssgNormalArray *curr_norm_;
65 static ssgIndexArray *curr_index_;
66
67 // Vertex arrays
68 static ssgVertexArray *vertex_array_;
69 static ssgNormalArray *normal_array_;
70 static ssgTexCoordArray *tex_coords_;
71
72 // Current part (index array)
73 static ssgLeaf *curr_part_;
74 static ssgBranch *model_;
75
76 // Moving parts
77 static ssgBranch *ailerons_grp_, *elevator_grp_, *rudder_grp_;
78 static ssgBranch *gear_grp_, *spoilers_grp_, *flaps_grp_;
79 static ssgBranch *prop_grp_;
80
81 static sgMat4 curr_matrix_;
82 static sgVec3 curr_rot_pt_;
83 static sgVec4 curr_col_;
84 static char *curr_tex_name_;
85 static ssgAxisTransform *curr_xfm_;
86
87 int noGT=0, noLT=0, no0=0;
88
89 #define EXPERIMENTAL_CULL_FACE_CODE
90 #ifdef EXPERIMENTAL_CULL_FACE_CODE
91 static bool curr_cull_face_;
92 #endif
93
94 // File Address Stack
95 static const int MAX_STACK_DEPTH = 128; // wk: 32 is too small
96 static long stack_ [MAX_STACK_DEPTH]; // adress part
97 static short lod_ [MAX_STACK_DEPTH]; // lod part of the stack
98 static int stack_depth_;
99 static short noLoDs;
100 static short curr_lod;
101
102 // static sgMat4 matrix_stack_ [MAX_STACK_DEPTH];
103 // static char *textures_ [MAX_STACK_DEPTH];
104 // static ssgBranch *groups_ [MAX_STACK_DEPTH];
105
106 static int start_idx_, last_idx_;
107 static int curr_var_;
108
109 static bool has_normals_, vtx_dirty_, tex_vtx_dirty_;
110 //static bool join_children_, override_normals_;
111
112 //static char *tex_fmt_;
113
114 //===========================================================================
115
116 /*static void initLoader()
117 {
118 start_idx_ = 0;
119 join_children_ = true;
120 override_normals_ = true;
121 tex_fmt_ = "tif";
122 stack_depth_ = 0;
123 #ifdef EXPERIMENTAL_CULL_FACE_CODE
124 curr_cull_face_ = false ;
125 #endif
126 }*/
127
128 #ifdef DEBUG
129 FILE *wkfp;
130
131 #define PRINT_STRUCTURE(a, b) fprintf(wkfp, a, b);
132 #define PRINT_STRUCTURE1(a ) fprintf(wkfp, a);
133
134 #else
135
136 #define PRINT_STRUCTURE(a, b)
137 #define PRINT_STRUCTURE1(a )
138
139 #endif
140
141 //===========================================================================
142
newPart()143 static void newPart()
144 {
145 vtx_dirty_ = true;
146 tex_vtx_dirty_ = true;
147 curr_tex_name_ = NULL;
148 sgSetVec4( curr_col_, 1.0f, 1.0f, 1.0f, 1.0f );
149
150 delete curr_vtx_;
151 delete curr_norm_;
152 curr_vtx_ = new ssgVertexArray ;
153 curr_norm_ = new ssgNormalArray ;
154 }
155
156 //===========================================================================
157
push_stack(long entry,short lod)158 static void push_stack( long entry, short lod ) {
159 assert( stack_depth_ < MAX_STACK_DEPTH - 1 );
160
161 lod_ [stack_depth_] = lod;
162 stack_[stack_depth_++] = entry;
163 }
164
pop_stack(short & lod)165 static long pop_stack(short &lod) {
166 assert( stack_depth_ > 0 );
167
168 lod = lod_[--stack_depth_];
169 return stack_[stack_depth_];
170 }
171
172 //===========================================================================
173
recalcNormals()174 static void recalcNormals() {
175 DEBUGPRINT( "Calculating normals." << std::endl);
176 sgVec3 n;
177
178 for (int i = 0; i < curr_index_->getNum() - 2; i++) {
179 unsigned short ix0 = *curr_index_->get(i );
180 unsigned short ix1 = *curr_index_->get(i + 1);
181 unsigned short ix2 = *curr_index_->get(i + 2);
182
183 sgMakeNormal( n,
184 vertex_array_->get(ix0),
185 vertex_array_->get(ix1),
186 vertex_array_->get(ix2) );
187
188 sgCopyVec3( normal_array_->get(ix0), n );
189 sgCopyVec3( normal_array_->get(ix1), n );
190 sgCopyVec3( normal_array_->get(ix2), n );
191 }
192 }
193
194 //===========================================================================
195
readPoint(FILE * fp,sgVec3 p)196 static void readPoint(FILE* fp, sgVec3 p)
197 {
198 short x_int, y_int, z_int;
199 y_int = ulEndianReadLittle16(fp);
200 z_int = ulEndianReadLittle16(fp);
201 x_int = ulEndianReadLittle16(fp);
202
203 // Convert from .MDL units (ca 2mm) to meters
204 p[0] = -x_int/512.0f;
205 p[1] = y_int/512.0f;
206 p[2] = z_int/512.0f;
207 }
208
209 //===========================================================================
210
211 // MtkPoint3D readPoint(FILE* fp)
212 // {
213 // short x_int, y_int, z_int;
214 // fread(&x_int, 2, 1, fp);
215 // fread(&y_int, 2, 1, fp);
216 // fread(&z_int, 2, 1, fp);
217
218 // // Convert from .MDL units (ca 2mm) to meters
219 // MtkPoint3D p;
220 // p.x() = (double)x_int/512.0;
221 // p.y() = (double)y_int/512.0;
222 // p.z() = (double)z_int/512.0;
223
224 // /*
225 // for(list<MtkTransMatrix3D>::iterator i = matrix_stack_.begin();
226 // i != matrix_stack_.end(); i++)
227 // {
228 // p = p*(*i);
229 // p += (*i).getCol(3);
230 // }
231 // */
232
233 // if(matrix_stack_.size() > 0)
234 // {
235 // MtkTransMatrix3D m = matrix_stack_.front();
236 // p -= m.getCol(3);
237 // p = p*m;
238 // }
239
240 // MtkPoint3D r;
241 // r.y() = p.x();
242 // r.z() = -p.y();
243 // r.x() = p.z();
244
245 // return r;
246 // }
247
248 //===========================================================================
249
readVector(FILE * fp,sgVec3 v)250 static void readVector(FILE* fp, sgVec3 v)
251 {
252 short x_int, y_int, z_int;
253 y_int = ulEndianReadLittle16(fp);
254 z_int = ulEndianReadLittle16(fp);
255 x_int = ulEndianReadLittle16(fp);
256
257 v[0] = -(float)x_int;
258 v[1] = (float)y_int;
259 v[2] = (float)z_int;
260
261 sgNormaliseVec3( v );
262 }
263
264 //===========================================================================
265 // for new lists, especially vertex list:
266
267 struct oneVertex {
268 sgVec3 p, n; // point position, normal
269 sgVec2 tc; // texture coords
270 };
271
272 struct oneVertex *TheVertexList; // array. Kludge: only one allowed
273
274 struct oneTexture {
275 char fname[64];
276 };
277
278 struct oneTexture *TheTextureList; // array. Kludge: only one allowed
279 //===========================================================================
280
createTriangIndices(ssgIndexArray * ixarr,int numverts,const sgVec3 s_norm,long dist)281 static void createTriangIndices(ssgIndexArray *ixarr,
282 int numverts, const sgVec3 s_norm, long dist)
283 {
284 sgVec3 v1, v2, cross;
285
286 if ( numverts > ixarr->getNum() ) {
287 ulSetError( UL_WARNING, "ssgLoadMDL: Index array with too few entries." );
288 return;
289 }
290
291 // triangulate polygons
292 if(numverts == 1)
293 {
294 unsigned short ix0 = *ixarr->get(0);
295 if ( ix0 >= vertex_array_->getNum() ) {
296 ulSetError(UL_WARNING, "ssgLoadMDL: Index out of bounds (%d/%d).",
297 ix0, vertex_array_->getNum() );
298 return;
299 }
300
301 curr_index_->add(ix0);
302 curr_index_->add(ix0);
303 curr_index_->add(ix0);
304 }
305
306 else if(numverts == 2)
307 {
308 unsigned short ix0 = *ixarr->get(0);
309 unsigned short ix1 = *ixarr->get(1);
310 if ( ix0 >= vertex_array_->getNum() ||
311 ix1 >= vertex_array_->getNum() ) {
312 ulSetError(UL_WARNING, "ssgLoadMDL: Index out of bounds. (%d,%d / %d",
313 ix0, ix1, vertex_array_->getNum() );
314 return;
315 }
316
317 curr_index_->add(ix0);
318 curr_index_->add(ix1);
319 curr_index_->add(ix0);
320 }
321
322 else if(numverts == 3)
323 {
324 unsigned short ix0 = *ixarr->get(0);
325 unsigned short ix1 = *ixarr->get(1);
326 unsigned short ix2 = *ixarr->get(2);
327 if ( ix0 >= vertex_array_->getNum() ||
328 ix1 >= vertex_array_->getNum() ||
329 ix2 >= vertex_array_->getNum() ) {
330 ulSetError(UL_WARNING, "ssgLoadMDL: Index out of bounds. " \
331 "(%d,%d,%d / %d)", ix0, ix1, ix2, vertex_array_->getNum());
332 return;
333 }
334
335 sgSubVec3(v1,
336 vertex_array_->get(ix1),
337 vertex_array_->get(ix0));
338 sgSubVec3(v2,
339 vertex_array_->get(ix2),
340 vertex_array_->get(ix0));
341
342 sgVectorProductVec3(cross, v1, v2);
343
344 if(sgScalarProductVec3(cross, s_norm) >= 0.0f)
345 {
346 curr_index_->add(ix0);
347 curr_index_->add(ix1);
348 curr_index_->add(ix2);
349 }
350 else
351 {
352 curr_index_->add(ix0);
353 curr_index_->add(ix2);
354 curr_index_->add(ix1);
355 }
356 }
357
358 else
359 {
360 unsigned short ix0 = *ixarr->get(0);
361 unsigned short ix1 = *ixarr->get(1);
362 unsigned short ix2 = *ixarr->get(2);
363 if ( ix0 >= vertex_array_->getNum() ||
364 ix1 >= vertex_array_->getNum() ||
365 ix2 >= vertex_array_->getNum() ) {
366 ulSetError(UL_WARNING, "ssgLoadMDL: Index out of bounds. " \
367 "(%d,%d,%d / %d)", ix0, ix1, ix2, vertex_array_->getNum());
368 return;
369 }
370
371 // Ensure counter-clockwise ordering
372 sgMakeNormal(cross,
373 vertex_array_->get(ix0),
374 vertex_array_->get(ix1),
375 vertex_array_->get(ix2));
376 bool flip = (sgScalarProductVec3(cross, s_norm) < 0.0);
377
378 curr_index_->add(ix0);
379 char tsA[99999];
380 int bWrong=FALSE;
381 // a lot of debug output follows - sorry!
382 sprintf(tsA, "------- %ld %f\n%f, %f, %f\n",
383 dist, ((float)dist)/(512.0f*32767.0f), s_norm[0], s_norm[1], s_norm[2]);
384 for(int i = 1; i < numverts; i++)
385 {
386 ix1 = *ixarr->get( flip ? numverts-i : i);
387 //
388 SGfloat f = sgScalarProductVec3(s_norm, vertex_array_->get(ix1));
389 sprintf(tsA, "%s%f, ", tsA, f);
390 f = f - ((float)dist)/(512.0f*32767.0f);
391 if((f<-0.5f) || (f>0.5f))
392 bWrong = TRUE;
393 //
394 if ( ix1 >= vertex_array_->getNum() ) {
395 ulSetError(UL_WARNING, "ssgLoadMDL: Index out of bounds. (%d/%d)",
396 ix1, vertex_array_->getNum());
397 continue;
398 }
399
400 curr_index_->add(ix1);
401 }
402 if (bWrong)
403 printf("%s\n-------\n", tsA);
404
405 }
406 }
407
408 //===========================================================================
409
readTexIndices(FILE * fp,int numverts,const sgVec3 s_norm,bool flip_y,long dist)410 static bool readTexIndices(FILE *fp, int numverts, const sgVec3 s_norm, bool flip_y, long dist)
411 {
412 ssgIndexArray temp_index_;
413
414 if(numverts <= 0)
415 return false;
416
417 if(tex_coords_->getNum() <
418 vertex_array_->getNum())
419 {
420 sgVec2 dummy_pt;
421 sgSetVec2(dummy_pt, FLT_MAX, FLT_MAX);
422 for(int i = tex_coords_->getNum();
423 i < vertex_array_->getNum(); i++)
424 tex_coords_->add(dummy_pt);
425 }
426
427 // Read index values and texture coordinates
428 for(int v = 0; v < numverts; v++)
429 {
430 unsigned short ix;
431 short tx_int, ty_int;
432
433 ix = ulEndianReadLittle16(fp);
434 tx_int = ulEndianReadLittle16(fp);
435 ty_int = ulEndianReadLittle16(fp);
436
437 if (flip_y) {
438 ty_int = 255 - ty_int;
439 }
440
441 int tex_idx = ix - start_idx_ + last_idx_;
442
443 sgVec2 tc;
444 sgSetVec2(tc, tx_int/255.0f, ty_int/255.0f);
445
446 sgVec2 curr_tc;
447
448 if ( tex_idx >= 0 && tex_idx < tex_coords_->getNum() ) {
449 sgCopyVec2(curr_tc, tex_coords_->get(tex_idx));
450 } else {
451 ulSetError( UL_WARNING, "ssgLoadMDL: Texture coord out of range (%d).",
452 tex_idx );
453 continue;
454 }
455
456 double dist = sgDistanceVec2(curr_tc, tc);
457
458 if((curr_tc[0] >= FLT_MAX - 1 && curr_tc[1] >= FLT_MAX - 1))
459 {
460 //DEBUGPRINT( "." );
461 sgCopyVec2(tex_coords_->get(tex_idx), tc);
462 }
463
464 else if(dist > 0.0001)
465 {
466 // We have a different texture coordinate for an existing vertex,
467 // so we have to copy this vertex and create a new index for it
468 // to get the correct texture mapping.
469
470 //DEBUGPRINT( "duplicating texture coordinate!\n");
471
472 int idx = ix - start_idx_ + last_idx_;
473 tex_idx = vertex_array_->getNum();
474
475 ssgVertexArray* vtx_arr = vertex_array_; //curr_vtx_;
476 ssgNormalArray* norm_arr = normal_array_; //curr_norm_;
477
478 sgVec3 vtx, nrm;
479 sgCopyVec3( vtx, vtx_arr ->get(idx) );
480 sgCopyVec3( nrm, norm_arr->get(idx) );
481 vtx_arr ->add(vtx);
482 norm_arr->add(nrm);
483
484 tex_coords_->add(tc);
485 }
486
487 temp_index_.add(tex_idx);
488
489 #ifdef DEBUG
490 int check_index = *temp_index_.get(v);
491 float *check_tc = tex_coords_->get(check_index);
492 DEBUGPRINT( "ix[" << v << "] = " << check_index <<
493 " (u=" << check_tc[0] << ", v=" <<
494 check_tc[1] << ")" << std::endl);
495 #endif
496
497 }
498
499 createTriangIndices(&temp_index_, numverts, s_norm, dist);
500
501 return true;
502 }
503
504 //===========================================================================
505
readIndices(FILE * fp,int numverts,const sgVec3 s_norm,long dist)506 static bool readIndices(FILE* fp, int numverts, const sgVec3 s_norm, long dist)
507 {
508 ssgIndexArray temp_index_;
509
510 if(numverts <= 0)
511 return false;
512
513 // Read index values
514 for(int v = 0; v < numverts; v++)
515 {
516 unsigned short ix;
517 ix = ulEndianReadLittle16(fp);
518 temp_index_.add(ix - start_idx_ + last_idx_);
519 DEBUGPRINT( "ix[" << v << "] = " << *temp_index_.get(v) << std::endl);
520 }
521
522 createTriangIndices(&temp_index_, numverts, s_norm, dist);
523
524 return true;
525 }
526
527 //===========================================================================
528
setColor(int color,int pal_id)529 static void setColor(int color, int pal_id)
530 {
531 if(pal_id == 0x68)
532 {
533 curr_col_[0] = fsAltPalette[color].r / 255.0f;
534 curr_col_[1] = fsAltPalette[color].g / 255.0f;
535 curr_col_[2] = fsAltPalette[color].b / 255.0f;
536 curr_col_[3] = 0.2f;
537 }
538 else
539 {
540 curr_col_[0] = fsAcPalette[color].r / 255.0f;
541 curr_col_[1] = fsAcPalette[color].g / 255.0f;
542 curr_col_[2] = fsAcPalette[color].b / 255.0f;
543 curr_col_[3] = 1.0f;
544 }
545 }
546
547 //===========================================================================
548
setColor(int r,int g,int b,int attr)549 static void setColor(int r, int g, int b, int attr)
550 {
551 curr_col_[0] = r / 255.0f;
552 curr_col_[1] = g / 255.0f;
553 curr_col_[2] = b / 255.0f;
554 if(attr < 239)
555 curr_col_[3] = 0.2f;
556 }
557
558 //===========================================================================
559
setTexture(char * name)560 static bool setTexture(char* name)
561 {
562 curr_tex_name_ = name;
563
564 return true;
565 }
566
567 //===========================================================================
568
createState(bool use_texture)569 static ssgSimpleState *createState(bool use_texture)
570 {
571 DEBUGPRINT("new State: col = " << curr_col_[0] << ", " << curr_col_[1] <<
572 ", " << curr_col_[2] << ", " << curr_col_[3]);
573 if ( curr_tex_name_ == NULL )
574 DEBUGPRINT(", tex = <NULL> " << std::endl);
575 else
576 DEBUGPRINT(", tex = " << curr_tex_name_ << std::endl);
577
578 ssgSimpleState *state = new ssgSimpleState();
579
580 state->setShininess(DEF_SHININESS);
581 state->setShadeModel(GL_SMOOTH);
582
583 state->enable (GL_LIGHTING);
584 state->enable (GL_CULL_FACE);
585 state->disable (GL_COLOR_MATERIAL);
586
587 if(curr_col_[3] < 0.99f)
588 {
589 state->setTranslucent();
590 state->enable(GL_BLEND);
591 state->enable(GL_ALPHA_TEST);
592 }
593 else
594 {
595 state->setOpaque();
596 state->disable(GL_BLEND);
597 state->disable(GL_ALPHA_TEST);
598 }
599
600 if(curr_tex_name_ != NULL && use_texture)
601 {
602 state->setMaterial( GL_AMBIENT, 1.0f, 1.0f, 1.0f, curr_col_[3]);
603 state->setMaterial( GL_DIFFUSE, 1.0f, 1.0f, 1.0f, curr_col_[3]);
604 state->enable(GL_TEXTURE_2D);
605 state->setTexture( current_options ->
606 createTexture(curr_tex_name_, FALSE, FALSE) ) ;
607 }
608 else
609 {
610 state->setMaterial( GL_AMBIENT, curr_col_);
611 state->setMaterial( GL_DIFFUSE, curr_col_);
612 state->disable(GL_TEXTURE_2D);
613 }
614
615 state->setMaterial( GL_SPECULAR, 1.0f, 1.0f, 1.0f, curr_col_[3] );
616 state->setMaterial( GL_EMISSION, 0.0f, 0.0f, 0.0f, 1.0f );
617
618 return state;
619 }
620
getCurrGroup()621 static ssgBranch *getCurrGroup() {
622 //Find the correct parent for the new group
623 if(curr_xfm_)
624 return curr_xfm_;
625 else
626 {
627 return model_;
628 }
629 }
630
631 //===========================================================================
632
633 // wk : It's not completely clear to me whether the following two functions can not be merged; Oh well.
634 // CreateAndAddLeaf1 is called then faces are created and then CreateAndAddLeaf2 is called
635
636
CreateAndAddLeaf1(GLenum ty,ssgTexCoordArray * tex_coords_P,bool use_texture)637 static void CreateAndAddLeaf1(GLenum ty, ssgTexCoordArray *tex_coords_P, bool use_texture)
638 {
639 curr_index_ = new ssgIndexArray();
640 curr_part_ = new ssgVtxArray( ty, vertex_array_,
641 normal_array_,
642 tex_coords_P,
643 NULL,
644 curr_index_ );
645 curr_part_->setState( createState(true) );
646 char sName[10];
647 sprintf(sName, "lod %d", (int)curr_lod);
648 curr_part_->setName(sName);
649 }
650
CreateAndAddLeaf2()651 static void CreateAndAddLeaf2()
652 {
653 ssgBranch* grp = getCurrGroup();
654 ((ssgVtxArray *)curr_part_)->removeUnusedVertices();
655 grp->addKid( current_options -> createLeaf(curr_part_, NULL) );
656 }
657
658
659
660 //===========================================================================
661
getMPGroup(int var)662 static ssgBranch *getMPGroup(int var)
663 {
664
665 switch(var)
666 {
667 case 0x4c: // Rudder
668 if(!rudder_grp_)
669 {
670 rudder_grp_ = new ssgBranch();
671 rudder_grp_->setName("rudder");
672 model_->addKid(rudder_grp_);
673 }
674 return rudder_grp_;
675 break;
676
677 case 0x4e: // Elevator
678 if(!elevator_grp_)
679 {
680 elevator_grp_ = new ssgBranch();
681 elevator_grp_->setName("elevator");
682 model_->addKid(elevator_grp_);
683 }
684 return elevator_grp_;
685 break;
686
687 case 0x6a: // Ailerons
688 if(!ailerons_grp_)
689 {
690 ailerons_grp_ = new ssgBranch();
691 ailerons_grp_->setName("ailerons");
692 model_->addKid(ailerons_grp_);
693 }
694 return ailerons_grp_;
695 break;
696
697 case 0x6c: // Flaps
698 if(!flaps_grp_)
699 {
700 flaps_grp_ = new ssgBranch();
701 flaps_grp_->setName("flaps");
702 model_->addKid(flaps_grp_);
703 }
704 return flaps_grp_;
705 break;
706
707 case 0x6e: // Gear
708 if(!gear_grp_)
709 {
710 gear_grp_ = new ssgBranch();
711 gear_grp_->setName("gear");
712 model_->addKid(gear_grp_);
713 }
714 return gear_grp_;
715 break;
716
717 case 0x7c: // Spoilers
718 if(!spoilers_grp_)
719 {
720 spoilers_grp_ = new ssgBranch();
721 spoilers_grp_->setName("spoilers");
722 model_->addKid(spoilers_grp_);
723 }
724 return spoilers_grp_;
725 break;
726
727 case 0x58:
728 case 0x7a: // Propeller
729 if(!prop_grp_)
730 {
731 prop_grp_ = new ssgBranch();
732 prop_grp_->setName("propeller");
733 model_->addKid(prop_grp_);
734 }
735 return prop_grp_;
736 break;
737
738 default:
739 return model_;
740 }
741 return NULL;
742 }
743
744 //===========================================================================
745
getMPLimits(int var,float * min,float * max)746 static void getMPLimits(int var, float *min, float *max)
747 {
748 switch(var)
749 {
750 case 0x4c: // Rudder
751 *min = -30.0;
752 *max = 30.0;
753 break;
754
755 case 0x4e: // Elevator
756 *min = -30.0;
757 *max = 30.0;
758 break;
759
760 case 0x6a: // Ailerons
761 *min = -30.0;
762 *max = 30.0;
763 break;
764
765 case 0x6c: // Flaps
766 *min = 0.0;
767 *max = 70.0;
768 break;
769
770 case 0x6e: // Gear
771 *min = 0.0;
772 *max = -90.0;
773 break;
774
775 case 0x7c: // Spoilers
776 *min = 0.0;
777 *max = 90.0;
778 break;
779
780 case 0x58:
781 case 0x7a: // Propeller
782 *min = 0.0;
783 *max = 360.0;
784 break;
785 }
786 }
787
788
789
ParseBGL(FILE * fp)790 void ParseBGL(FILE *fp) // "traversing" through the file
791 {
792 bool done = false;
793 while(!feof(fp) && !done)
794 {
795 unsigned int skip_offset = 0;
796
797 PRINT_STRUCTURE( "offset %lx\n", (long)ftell(fp))
798 unsigned short opcode = ulEndianReadLittle16(fp);
799
800 DEBUGPRINT( "opcode = " << std::hex << opcode << std::dec << " at address" << ftell(fp)-2 // -2 since opcode has already been read
801 << std::endl );
802
803 switch(opcode)
804 {
805 case 0x23: // BGL_CALL
806 {
807 short offset;
808 offset = ulEndianReadLittle16(fp);
809 long addr = ftell(fp);
810 DEBUGPRINT( "BGL_CALL(" << offset << ")\n" );
811 push_stack(addr, curr_lod);
812 long dst = addr + offset - 4;
813 fseek(fp, dst, SEEK_SET);
814
815
816 PRINT_STRUCTURE( "call %lx\n", (long)offset)
817 }
818 break;
819
820 case 0x8a: // BGL_CALL32
821 {
822 int offset;
823 offset = ulEndianReadLittle32(fp);
824 long addr = ftell(fp);
825 DEBUGPRINT( "BGL_CALL32(" << offset << ")\n" );
826 PRINT_STRUCTURE( "call32 %lx\n", (long)offset)
827 push_stack(addr, curr_lod);
828 long dst = addr + offset - 6;
829 fseek(fp, dst, SEEK_SET);
830 }
831 break;
832
833 case 0x0d: // BGL_JUMP
834 {
835 short offset;
836 offset = ulEndianReadLittle16(fp);
837 PRINT_STRUCTURE( "jump %lx\n", (long)offset)
838 long addr = ftell(fp);
839 long dst = addr + offset - 4;
840 fseek(fp, dst, SEEK_SET);
841 DEBUGPRINT( "BGL_JUMP(" << offset << ")\n" );
842 }
843 break;
844
845 case 0x88: // BGL_JUMP32
846 {
847 int offset;
848 offset = ulEndianReadLittle32(fp);
849 long addr = ftell(fp);
850 DEBUGPRINT( "BGL_JUMP32(" << offset << ")\n" );
851 PRINT_STRUCTURE( "jump32 %lx\n", (long)offset)
852 long dst = addr + offset - 6;
853 fseek(fp, dst, SEEK_SET);
854 }
855 break;
856
857 case 0x8e: // BGL_VFILE_MARKER
858 {
859 short offset;
860 offset = ulEndianReadLittle16(fp);
861 DEBUGPRINT( "vars: " << offset << std::endl);
862 break;
863 }
864
865 case 0x39: // BGL_IFMSK
866 {
867 short offset, var, mask;
868 offset = ulEndianReadLittle16(fp);
869 var = ulEndianReadLittle16(fp);
870 mask = ulEndianReadLittle16(fp);
871 long addr = ftell(fp);
872 long dst = addr + offset - 8;
873 DEBUGPRINT( "BGL_IFMSK(" << offset << ", 0x" << std::hex << var <<
874 ", 0x" << mask << std::dec << ")\n" );
875 // if(var & mask == 0)
876 PRINT_STRUCTURE( "if msk %lx\n", (long)offset)
877 switch(var)
878 {
879 case 0x7e:
880 fseek(fp, dst, SEEK_SET);
881 break;
882
883 default:
884 break;
885 }
886 }
887 break;
888
889 case 0x24: // BGL_IFIN1
890 {
891 short offset, lo, hi;
892 unsigned short var;
893 offset = ulEndianReadLittle16(fp);
894 var = ulEndianReadLittle16(fp);
895 lo = ulEndianReadLittle16(fp);
896 hi = ulEndianReadLittle16(fp);
897 DEBUGPRINT( "BGL_IFIN1(" << offset << ", 0x" << std::hex << var <<
898 ", " << std::dec << lo << ", " << hi << ")\n" );
899 PRINT_STRUCTURE( "ifin1 %lx\n", (long)offset)
900 curr_var_ = var;
901 }
902 break;
903
904 case 0x46: // BGL_POINT_VICALL
905 {
906 short offset, var_rot_x, var_rot_y, var_rot_z;
907 unsigned short int_rot_x, int_rot_y, int_rot_z;
908 offset = ulEndianReadLittle16(fp);
909 sgVec3 ctr;
910 readPoint(fp, ctr);
911
912 int_rot_y = ulEndianReadLittle16(fp);
913 var_rot_y = ulEndianReadLittle16(fp);
914
915 int_rot_x = ulEndianReadLittle16(fp);
916 var_rot_x = ulEndianReadLittle16(fp);
917
918 int_rot_z = ulEndianReadLittle16(fp);
919 var_rot_z = ulEndianReadLittle16(fp);
920
921 float rx = 360.0f*(float)int_rot_x/0xffff;
922 float ry = 360.0f*(float)int_rot_y/0xffff;
923 float rz = 360.0f*(float)int_rot_z/0xffff;
924
925 // We build a rotation matrix by adding all constant
926 // rotations (int_rot_*) to current_matrix_. As soon as we reach
927 // the actual variable rotation, we multiply
928 // the axis of the variable rotation with our current matrix.
929 // This will be the axis of rotation in the original coordinate
930 // system. This can now be inserted into a GngLinearControl
931 // transform.
932 if(var_rot_x > 0 || var_rot_y > 0 || var_rot_z > 0)
933 {
934 ssgAxisTransform* tmp = NULL;
935 if(curr_xfm_)
936 tmp = curr_xfm_;
937 curr_xfm_ = new ssgAxisTransform();
938 curr_xfm_->setCenter(curr_rot_pt_);
939
940 int var = 0;
941 if(var_rot_x > 0)
942 var = var_rot_x;
943 else if(var_rot_y > 0)
944 var = var_rot_y;
945 else if(var_rot_z > 0)
946 var = var_rot_z;
947
948 float min_limit, max_limit;
949 getMPLimits(var, & min_limit, & max_limit);
950
951 sgVec3 axis = { (float)var_rot_y, (float)var_rot_z,
952 (float)var_rot_x };
953 sgNormaliseVec3( axis ) ;
954 sgXformVec3( axis, curr_matrix_ ) ;
955 sgNegateVec3(axis);
956 curr_xfm_->setAxis(axis);
957 curr_xfm_->setRotationLimits(min_limit, max_limit);
958
959 char name[256];
960 sprintf(name, "ssgAxisRotation(%x)", var);
961 curr_xfm_->setName(name);
962 if(tmp)
963 tmp->addKid(curr_xfm_);
964 else
965 {
966 ssgBranch* grp = getMPGroup(var);
967 grp->addKid(curr_xfm_);
968 }
969 }
970
971 // Build up the constant rotations
972 sgMat4 rot_mat;
973 sgMakeRotMat4( rot_mat, ry, rz, rx );
974 sgPostMultMat4( curr_matrix_, rot_mat );
975 sgAddVec3( curr_rot_pt_, ctr );
976
977 long addr = ftell(fp);
978 long dst = addr + offset - 22;
979 fseek(fp, dst, SEEK_SET);
980 push_stack(addr, curr_lod);
981
982 break;
983 }
984
985 case 0x5f: // BGL_IFSIZEV
986 {
987 short offset;
988 unsigned short real_size, pixels_ref;
989 offset = ulEndianReadLittle16(fp);
990 real_size = ulEndianReadLittle16(fp);
991 pixels_ref = ulEndianReadLittle16(fp);
992 DEBUGPRINT("BGL_IFSIZEV: jmp = " << offset << ", sz = " <<
993 real_size << ", px = " << pixels_ref << std::endl);
994 PRINT_STRUCTURE( "ifsizev!! %lx\n", (long)offset)
995 long addr = ftell(fp);
996 long dst = addr + offset - 8;
997 fseek(fp, dst, SEEK_SET);
998 push_stack(addr, ++noLoDs);
999 break;
1000 }
1001
1002 case 0x3b: // BGL_VINSTANCE
1003 {
1004 short offset, var;
1005 offset = ulEndianReadLittle16(fp);
1006 var = ulEndianReadLittle16(fp);
1007 long addr = ftell(fp);
1008 long var_abs = addr + var - 6;
1009 fseek(fp, var_abs, SEEK_SET);
1010 float p = 360.0f * (float)ulEndianReadLittle32(fp) / 0xffffffff;
1011 float r = 360.0f * (float)ulEndianReadLittle32(fp) / 0xffffffff;
1012 float h = 360.0f * (float)ulEndianReadLittle32(fp) / 0xffffffff;
1013 sgMat4 rot_mat;
1014 sgMakeRotMat4(rot_mat, h, p, r);
1015 sgPostMultMat4(curr_matrix_, rot_mat);
1016 DEBUGPRINT( "BGL_VINSTANCE(" << offset << ", h=" << h << ", p=" <<
1017 p << ", r=" << r << ")\n");
1018 long dst = addr + offset - 6;
1019 fseek(fp, dst, SEEK_SET);
1020 }
1021 break;
1022
1023 case 0x0: // EOF
1024 case 0x22: // BGL return
1025 {
1026 curr_xfm_ = NULL;
1027 sgMakeIdentMat4( curr_matrix_ );
1028 sgZeroVec3( curr_rot_pt_ );
1029 curr_var_ = 0;
1030 DEBUGPRINT( "BGL return\n\n");
1031 PRINT_STRUCTURE1("return\n");
1032 if(stack_depth_ == 0)
1033 done = true;
1034 else
1035 {
1036 long addr = pop_stack(curr_lod);
1037 fseek(fp, addr, SEEK_SET);
1038 }
1039 }
1040 break;
1041
1042 case 0x1a: // RESLIST (point list with no normals)
1043 {
1044 newPart();
1045 has_normals_ = false;
1046
1047 start_idx_ = ulEndianReadLittle16(fp);
1048 unsigned short numpoints = ulEndianReadLittle16(fp);
1049
1050 DEBUGPRINT( "New group (unlit): start_idx = " << start_idx_
1051 << ", num vertices = " << numpoints << std::endl);
1052
1053 sgVec3 null_normal;
1054 sgZeroVec3( null_normal );
1055
1056 for(int i = 0; i < numpoints; i++)
1057 {
1058 sgVec3 p;
1059 readPoint(fp, p);
1060 curr_vtx_->add(p);
1061 curr_norm_->add(null_normal);
1062 }
1063 }
1064 break;
1065
1066 case 0x29: // GORAUD RESLIST (point list with normals)
1067 {
1068 newPart();
1069 has_normals_ = true;
1070
1071 start_idx_ = ulEndianReadLittle16(fp);
1072 unsigned short numpoints = ulEndianReadLittle16(fp);
1073
1074 DEBUGPRINT( "New group (goraud): start_idx = " << start_idx_
1075 << ", num vertices = " << numpoints << std::endl);
1076
1077 for(int i = 0; i < numpoints; i++)
1078 {
1079 sgVec3 p;
1080 readPoint(fp, p);
1081 sgVec3 v;
1082 readVector(fp, v);
1083 curr_vtx_->add(p);
1084 curr_norm_->add(v);
1085 }
1086 }
1087 break;
1088
1089 case 0x0f: // STRRES: Start line definition
1090 {
1091 unsigned short idx = ulEndianReadLittle16(fp);
1092 DEBUGPRINT( "Start line: idx = " << idx << std::endl);
1093 if(vtx_dirty_)
1094 {
1095 last_idx_ = vertex_array_->getNum();
1096 for(int i = 0; i < curr_vtx_->getNum(); i++)
1097 {
1098 vertex_array_->add(curr_vtx_ ->get(i));
1099 normal_array_->add(curr_norm_->get(i));
1100 }
1101 vtx_dirty_ = false;
1102 }
1103 CreateAndAddLeaf1(GL_LINES, NULL, false);
1104 #ifdef EXPERIMENTAL_CULL_FACE_CODE
1105 curr_part_->setCullFace ( curr_cull_face_ ) ;
1106 #endif
1107
1108 curr_index_->add(idx - start_idx_ + last_idx_);
1109 ssgBranch *grp = getCurrGroup();
1110 grp->addKid(curr_part_);
1111
1112 //assert(curr_part_->getState()->getTexture() == NULL);
1113 }
1114 break;
1115
1116 case 0x10: // CNTRES: Continue line definition
1117 {
1118 unsigned short idx = ulEndianReadLittle16(fp);
1119 DEBUGPRINT( "Cont. line: idx = " << idx << std::endl);
1120 curr_index_->add(idx - start_idx_ + last_idx_);
1121 }
1122 break;
1123
1124 case 0x20:
1125 case 0x7a: // Goraud shaded Texture-mapped ABCD Facet
1126 {
1127 if(tex_vtx_dirty_)
1128 {
1129 last_idx_ = vertex_array_->getNum();
1130 for(int i = 0; i < curr_vtx_->getNum(); i++)
1131 {
1132 vertex_array_->add(curr_vtx_ ->get(i));
1133 normal_array_->add(curr_norm_->get(i));
1134 }
1135 tex_vtx_dirty_ = false;
1136 }
1137 CreateAndAddLeaf1(GL_TRIANGLE_FAN, tex_coords_, true);
1138
1139 //assert(curr_part_->getState()->getTexture() != NULL);
1140
1141 unsigned short numverts = ulEndianReadLittle16(fp);
1142 DEBUGPRINT( "New part: (goraud/texture), num indices = " <<
1143 numverts << std::endl);
1144
1145 // Normal vector
1146 sgVec3 v;
1147 readVector(fp, v);
1148
1149 // Dot product reference
1150 #ifdef EXPERIMENTAL_CULL_FACE_CODE
1151 long l = ulEndianReadLittle32(fp) ;
1152 if(l>0)
1153 noGT++;
1154 else if (l<0)
1155 noLT++;
1156 if((v[0]==0) && (v[1]==0) && (v[2]==0))
1157 no0++;
1158 //rr_part_->setCullFace ( curr_cull_face_ ) ;
1159
1160 #else
1161 ulEndianReadLittle32(fp);
1162 #endif
1163 // Read vertex indices and texture coordinates
1164 bool flip_y = FALSE;
1165 if(curr_tex_name_!=NULL)
1166 { char *texture_extension =
1167 curr_tex_name_ + strlen(curr_tex_name_) - 3;
1168 flip_y = ulStrEqual( texture_extension, "BMP" ) != 0 ;
1169 }
1170 /*old:
1171 char *texture_extension =
1172 curr_tex_name_ + strlen(curr_tex_name_) - 3;
1173 bool flip_y = ulStrEqual( texture_extension, "BMP" );
1174 */
1175 readTexIndices(fp, numverts, v, flip_y, l); // adds stuff to curr_index_
1176
1177 if(!has_normals_)
1178 {
1179 while (normal_array_->getNum() < vertex_array_->getNum())
1180 normal_array_->add(v);
1181 recalcNormals();
1182 }
1183 CreateAndAddLeaf2();
1184 }
1185 break;
1186
1187 case 0x60: // BGL_FACE_TMAP
1188 {
1189 if(tex_vtx_dirty_)
1190 {
1191 last_idx_ = vertex_array_->getNum();
1192 for(int i = 0; i < curr_vtx_->getNum(); i++)
1193 {
1194 vertex_array_->add(curr_vtx_ ->get(i));
1195 normal_array_->add(curr_norm_->get(i));
1196 }
1197 tex_vtx_dirty_ = false;
1198 }
1199
1200 CreateAndAddLeaf1(GL_TRIANGLE_FAN, tex_coords_, true);
1201
1202 #ifdef EXPERIMENTAL_CULL_FACE_CODE
1203 curr_part_->setCullFace ( curr_cull_face_ ) ;
1204 #endif
1205 //assert(curr_part_->getState()->getTexture() != NULL);
1206
1207 unsigned short numverts = ulEndianReadLittle16(fp);
1208 DEBUGPRINT( "New part: (goraud/texture), num indices = " <<
1209 numverts << std::endl);
1210
1211 // Point in polygon
1212 sgVec3 p;
1213 readPoint(fp, p);
1214
1215 // Normal vector
1216 sgVec3 v;
1217 readVector(fp, v);
1218
1219 // Read vertex inidices and texture coordinates
1220 bool flip_y = FALSE;
1221 if(curr_tex_name_!=NULL)
1222 { char *texture_extension =
1223 curr_tex_name_ + strlen(curr_tex_name_) - 3;
1224 flip_y = ulStrEqual( texture_extension, "BMP" ) != 0 ;
1225 }
1226 /*
1227 char *texture_extension =
1228 curr_tex_name_ + strlen(curr_tex_name_) - 3;
1229 bool flip_y = ulStrEqual( texture_extension, "BMP" );
1230 */
1231 readTexIndices(fp, numverts, v, flip_y, -11);
1232
1233 if(!has_normals_)
1234 {
1235 while (normal_array_->getNum() < vertex_array_->getNum())
1236 normal_array_->add(v);
1237 recalcNormals();
1238 }
1239
1240 CreateAndAddLeaf2();
1241 }
1242 break;
1243
1244 case 0x1d: // BGL_FACE
1245 {
1246 if(vtx_dirty_)
1247 {
1248 last_idx_ = vertex_array_->getNum();
1249 for(int i = 0; i < curr_vtx_->getNum(); i++)
1250 {
1251 vertex_array_->add(curr_vtx_->get(i));
1252 normal_array_->add(curr_norm_->get(i));
1253 }
1254 vtx_dirty_ = false;
1255 }
1256
1257 CreateAndAddLeaf1(GL_TRIANGLE_FAN, NULL, false);
1258
1259 #ifdef EXPERIMENTAL_CULL_FACE_CODE
1260 curr_part_->setCullFace ( curr_cull_face_ ) ;
1261 #endif
1262 //assert(curr_part_->getState()->getTexture() == NULL);
1263
1264 unsigned short numverts = ulEndianReadLittle16(fp);
1265 DEBUGPRINT( "BGL_FACE: num indices = " << numverts << std::endl);
1266
1267 sgVec3 p;
1268 readPoint(fp, p);
1269 // Surface normal
1270 sgVec3 v;
1271 readVector(fp, v);
1272
1273 // Read vertex indices
1274 readIndices(fp, numverts, v, -11);
1275
1276 if(!has_normals_)
1277 {
1278 while (normal_array_->getNum() < vertex_array_->getNum())
1279 normal_array_->add(v);
1280 recalcNormals();
1281 }
1282
1283 CreateAndAddLeaf2();
1284 }
1285 break;
1286
1287 case 0x3e: // FACETN (no texture)
1288 case 0x2a: // Goraud shaded ABCD Facet
1289 {
1290 if(vtx_dirty_)
1291 {
1292 last_idx_ = vertex_array_->getNum();
1293 for(int i = 0; i < curr_vtx_->getNum(); i++)
1294 {
1295 vertex_array_->add(curr_vtx_->get(i));
1296 normal_array_->add(curr_norm_->get(i));
1297 }
1298 vtx_dirty_ = false;
1299 }
1300
1301 CreateAndAddLeaf1(GL_TRIANGLE_FAN, NULL, false);
1302
1303 //assert(curr_part_->getState()->getTexture() == NULL);
1304
1305 unsigned short numverts = ulEndianReadLittle16(fp);
1306 DEBUGPRINT( "BGL_FACETN: num indices = " << numverts << std::endl);
1307
1308 // Surface normal
1309 sgVec3 v;
1310 readVector(fp, v);
1311
1312 // dot-ref
1313 #ifdef EXPERIMENTAL_CULL_FACE_CODE
1314 long l = ulEndianReadLittle32(fp) ;
1315 if(l>0)
1316 noGT++;
1317 else if (l<0)
1318 noLT++;
1319 if((v[0]==0) && (v[1]==0) && (v[2]==0))
1320 no0++;
1321 //rr_part_->setCullFace ( curr_cull_face_ ) ;
1322
1323 #else
1324 ulEndianReadLittle32(fp);
1325 #endif
1326 // Read vertex indices
1327 readIndices(fp, numverts, v, l);
1328
1329 if(!has_normals_)
1330 {
1331 while (normal_array_->getNum() < vertex_array_->getNum())
1332 normal_array_->add(v);
1333 recalcNormals();
1334 }
1335
1336 CreateAndAddLeaf2();
1337 }
1338 break;
1339
1340 case 0x18: // Set texture
1341 {
1342 unsigned short id, dx, scale, dy;
1343 id = ulEndianReadLittle16(fp);
1344 dx = ulEndianReadLittle16(fp);
1345 scale = ulEndianReadLittle16(fp);
1346 dy = ulEndianReadLittle16(fp);
1347 char tex_name[14];
1348 fread(tex_name, 1, 14, fp);
1349 static char tex_filename[14];
1350 int j = 0;
1351 for(int i = 0; i < 14; i++)
1352 {
1353 if(!isspace(tex_name[i]))
1354 tex_filename[j++] = tolower(tex_name[i]);
1355 }
1356 tex_filename[j] = '\0';
1357 DEBUGPRINT( "Set texture: name = " << tex_filename << ", id = " << id
1358 << ", dx = " << dx << ", dy = " << dy << ", scale = " <<
1359 scale << std::endl);
1360 setTexture(tex_filename);
1361 }
1362 break;
1363
1364 case 0x43: // TEXTURE2
1365 {
1366 unsigned short length, idx;
1367 unsigned char flags, chksum;
1368 unsigned int color;
1369 static char tex_filename[128];
1370 length = ulEndianReadLittle16(fp);
1371 idx = ulEndianReadLittle16(fp);
1372 fread(&flags, 1, 1, fp);
1373 fread(&chksum, 1, 1, fp);
1374 color = ulEndianReadLittle32(fp);
1375 if(chksum != 0)
1376 {
1377 DEBUGPRINT( "warning: TEXTURE2 Checksum != 0\n");
1378 }
1379
1380 char c;
1381 int i = 0;
1382 while((c = getc(fp)) != 0)
1383 {
1384 if(!isspace(c))
1385 tex_filename[i++] = tolower(c);
1386 }
1387 tex_filename[i] = '\0';
1388
1389 // Padding byte
1390 if((strlen(tex_filename) + 1) % 2)
1391 c = getc(fp);
1392
1393 DEBUGPRINT( "TEXTURE2: Set texture: name = " << tex_filename <<
1394 std::endl);
1395 setTexture(tex_filename);
1396 break;
1397 }
1398
1399 case 0x50: // GCOLOR (Goraud shaded color)
1400 case 0x51: // LCOLOR (Line color)
1401 case 0x52: // SCOLOR (Light source shaded surface color)
1402 {
1403 unsigned char color, param;
1404 fread(&color, 1, 1, fp);
1405 fread(¶m, 1, 1, fp);
1406 DEBUGPRINT( "Set color = " << (int)color << " (" << std::hex <<
1407 (int)param << std::dec << ")\n");
1408 setColor((int)color, (int)param);
1409 }
1410 break;
1411
1412 case 0x2D: // BGL_SCOLOR24
1413 {
1414 unsigned char col[4];
1415 fread(col, 1, 4, fp);
1416 DEBUGPRINT( "color = " << (int)col[0] << ", " << (int)col[2] <<
1417 ", " << (int)col[3] << ", " << (int)col[1] << std::endl);
1418 setColor(col[0], col[2], col[3], col[1]);
1419 break;
1420 }
1421
1422
1423 //-------------------------------------------
1424 // The next code is either ignored
1425 // or for experimental use..
1426 //-------------------------------------------
1427
1428 case 0x03:
1429 {
1430 //DEBUGPRINT( "BGL_CASE\n" );
1431 unsigned short number_cases = ulEndianReadLittle16(fp);
1432 skip_offset = 6 + 2 * number_cases;
1433 PRINT_STRUCTURE1("case :-( !!\n");
1434 }
1435 break;
1436
1437 case 0xB0: //BGLOP_CRASH_OCTTREE
1438 {
1439 /* from scdis code by Takuya Murakami:
1440
1441 2 Jump Offset
1442 2 Crash Type (See CRASH_FLAG_xxx in makemdl.exe)
1443 2 # of nodes
1444 4*3 box x/y/z
1445 4*3 box w/h/d
1446 1*8 ?
1447 1*8*(# of nodes) ?
1448 */
1449
1450 ulEndianReadLittle32(fp); // ignore jump offset / crash type
1451 int count = ulEndianReadLittle16(fp);
1452 //fseek(fp, 4*3+4*3+1*8+1*8*count, SEEK_CUR);
1453 fseek(fp, 5*8+8*count, SEEK_CUR); // completely experimental
1454 }
1455 break;
1456
1457 case 0xB2: //light
1458 {
1459 /*from scdis code by Takuya Murakami:
1460 Format:
1461 2 type
1462 4*3 offset (x,y,z, real4)
1463 4 intensity
1464 4 linear attenuation factor (real4)
1465 4 squared attenuation factor (real4)
1466 4 color (BGRA : strange byte order...)
1467 4*3 direction(x,y,z real4)
1468 */
1469 fseek(fp, 2+4*10, SEEK_CUR);
1470 }
1471 break;
1472
1473 case 0xB3: //ifinf(1)
1474 {
1475 // long offset = ulEndianReadLittle32(fp);
1476 // unsigned short v = ulEndianReadLittle16(fp);
1477 // float low = ulEndianReadLittleFloat(fp);
1478 // float high = ulEndianReadLittleFloat(fp);
1479 ulEndianReadLittle32(fp);
1480 ulEndianReadLittle16(fp);
1481 ulEndianReadLittleFloat(fp);
1482 ulEndianReadLittleFloat(fp);
1483
1484 }
1485 break;
1486 //-------------------------------------------
1487 // The next codes are CFS2 specific
1488 //-------------------------------------------
1489
1490 case 0xB5: //, VertexList, anaVertexList, 0 ) // VERTEX_LIST_BEGIN
1491 {
1492
1493 newPart();
1494 int count = ulEndianReadLittle16(fp);
1495 ulEndianReadLittle32(fp); // dummy
1496 #ifdef UL_WIN32
1497 if(TheVertexList)
1498 ::MessageBox(0, "More than one vertexlist", "Warning:", 0);
1499 #endif
1500 TheVertexList = new oneVertex[count]; // kludge: TheVertexList is unused??
1501 // 4*8 x,y,z,nx,ny,nz,tu,tv (real4)
1502
1503 for (int i = 0; i < count; i++)
1504 {
1505 TheVertexList[i].p[0] = ulEndianReadLittleFloat(fp); // / 1E6;
1506 TheVertexList[i].p[1] = ulEndianReadLittleFloat(fp); // / 1E6;
1507 TheVertexList[i].p[2] = ulEndianReadLittleFloat(fp); // / 1E6;
1508 TheVertexList[i].n[0] = ulEndianReadLittleFloat(fp);
1509 TheVertexList[i].n[1] = ulEndianReadLittleFloat(fp);
1510 TheVertexList[i].n[2] = ulEndianReadLittleFloat(fp);
1511 TheVertexList[i].tc[0]= ulEndianReadLittleFloat(fp);
1512 TheVertexList[i].tc[1]= ulEndianReadLittleFloat(fp);
1513
1514 curr_vtx_->add(TheVertexList[i].p);
1515 curr_norm_->add(TheVertexList[i].n);
1516 tex_coords_->add(TheVertexList[i].tc);
1517
1518 }
1519 }
1520 break;
1521
1522 case 0xB6: //, MaterialList, anaMaterialList, 0 ) // MATERIAL_LIST_BEGIN
1523 {
1524
1525 int count = ulEndianReadLittle16(fp);
1526 ulEndianReadLittle32(fp); // dummy
1527 fseek(fp, count*4*17, SEEK_CUR);
1528 }
1529
1530 break;
1531
1532 case 0xB7: //, TextureList, anaTextureList, 0 ) // TEXTURE_LIST_BEGIN/TEXTURE_DEF/TEXTURE_LIST_END
1533 {
1534
1535 int count = ulEndianReadLittle16(fp);
1536 ulEndianReadLittle32(fp); // dummy
1537 #ifdef UL_WIN32
1538 if(TheTextureList)
1539 ::MessageBox(0, "More than one texturelist", "Warning:", 0);
1540 #endif
1541 TheTextureList = new oneTexture[count]; // kludge: TheVertexList is unused??
1542 for(int i=0;i<count;i++)
1543 {
1544 // u_int32 cls = get4(); u_int8 r = get1(); u_int8 a = get1(); u_int8 g = get1(); u_int8 b = get1(); u_int32 hint = get4(); float size = getreal4();
1545 fseek(fp, 16, SEEK_CUR);
1546 fread(TheTextureList[i].fname, 64, 1, fp);
1547 }
1548 }
1549 break;
1550
1551 case 0xB9: //, DrawTriList, anaDrawTriList, 0 )
1552 {
1553
1554 if(tex_vtx_dirty_)
1555 {
1556 last_idx_ = vertex_array_->getNum();
1557 for(int i = 0; i < curr_vtx_->getNum(); i++)
1558 {
1559 vertex_array_->add(curr_vtx_ ->get(i));
1560 normal_array_->add(curr_norm_->get(i));
1561 }
1562 tex_vtx_dirty_ = false;
1563 }
1564
1565
1566
1567 ssgVertexArray *vertex_array_bu = (ssgVertexArray *)vertex_array_->clone();
1568
1569 for(int i=0;i<vertex_array_->getNum();i++)
1570 sgXformPnt3(vertex_array_->get(i), curr_matrix_);
1571
1572 CreateAndAddLeaf1(GL_TRIANGLES, tex_coords_, true);
1573 //delete vertex_array_; kludge!!
1574 vertex_array_ = vertex_array_bu; // to undo the transformation
1575
1576 //assert(curr_part_->getState()->getTexture() != NULL);
1577
1578 int base = ulEndianReadLittle16(fp);
1579 // int vertexcount = ulEndianReadLittle16(fp);
1580 ulEndianReadLittle16(fp);
1581 int wkcount = ulEndianReadLittle16(fp);
1582 wkcount = wkcount / 3; // tri
1583 assert(wkcount>0);
1584
1585 DEBUGPRINT( "New part: (DrawTriList), num tris = " << wkcount << std::endl);
1586 if(tex_coords_->getNum() != vertex_array_->getNum())
1587 {
1588 printf("tex_coords_->getNum() = %d, vertex_array_->getNum() = %d\n", tex_coords_->getNum(), vertex_array_->getNum());
1589 assert(FALSE);
1590 }
1591 assert(tex_coords_->getNum() == normal_array_->getNum());
1592 for(int j=0;j<wkcount;j++)
1593 {
1594 int i1 = ulEndianReadLittle16(fp);
1595 int i2 = ulEndianReadLittle16(fp);
1596 int i3 = ulEndianReadLittle16(fp);
1597 if(i1+base>=tex_coords_->getNum())
1598 {
1599 printf("i1+base = %d, i1 = %d, base = %d, tex_coords_->getNum() = %d\n", i1+base, i1, base, tex_coords_->getNum());
1600 assert(FALSE);
1601 }
1602 assert(i2+base<tex_coords_->getNum());
1603 assert(i3+base<tex_coords_->getNum());
1604
1605 curr_index_->add(i1+base);
1606 curr_index_->add(i2+base);
1607 curr_index_->add(i3+base);
1608 }
1609 CreateAndAddLeaf2();
1610 }
1611 break;
1612
1613 case 0xBA: //, DrawLineList, anaDrawLineList, 0 )
1614 {
1615 // int base = ulEndianReadLittle16(fp);
1616 // int dummycount = ulEndianReadLittle16(fp);
1617 ulEndianReadLittle16(fp);
1618 ulEndianReadLittle16(fp);
1619
1620 int wkcount = ulEndianReadLittle16(fp);
1621 wkcount = wkcount / 2;
1622 fseek(fp, 2*2*wkcount, SEEK_CUR);
1623 }
1624 break;
1625
1626 case 0xBB: //, DrawPointList, anaDrawPointList, 0 )
1627 {
1628 // int base = ulEndianReadLittle16(fp);
1629 // int dummycount = ulEndianReadLittle16(fp);
1630 ulEndianReadLittle16(fp);
1631 ulEndianReadLittle16(fp);
1632
1633 int wkcount = ulEndianReadLittle16(fp);
1634 wkcount = wkcount / 1;
1635 fseek(fp, 2*1*wkcount, SEEK_CUR);
1636 }
1637 break;
1638
1639 case 0xBC: // BGL_BEGIN / BGLVersion
1640 {
1641 // long v = ulEndianReadLittle32(fp);
1642 ulEndianReadLittle32(fp);
1643
1644 PRINT_STRUCTURE("BGLVersion %lx\n", v)
1645 }
1646 break;
1647 case 0xB8: // SetMaterial
1648 {
1649 ulEndianReadLittle16(fp); // word
1650 short TheTextureIndex = ulEndianReadLittle16(fp); // word
1651 if (TheTextureIndex != -1)
1652 {
1653 char *s = TheTextureList[TheTextureIndex].fname;
1654 int j = 0;
1655 static char tex_filename[64];
1656
1657 for(int i = 0; i < 64; i++)
1658 {
1659 if(!isspace(s[i]))
1660 tex_filename[j++] = tolower(s[i]);
1661 }
1662 tex_filename[j] = '\0';
1663 //DEBUGPRINT( "Set texture: name = " << tex_filename << std::endl);
1664 setTexture(tex_filename);
1665 }
1666 else
1667 curr_tex_name_ = NULL;
1668 }
1669 break;
1670 case 0xB4: // TextureSize
1671 ulEndianReadLittle32(fp); // float
1672 break;
1673 case 0xBD: // BGL_END / EndVersion
1674 break;
1675 case 0xAE: // BGL_TRANSFORM_END
1676 sgMakeIdentMat4( curr_matrix_ );
1677
1678 break;
1679 case 0xAF: // BGL_TRANSFORM_MATRIX
1680 {
1681 sgMat4 this_mat;
1682 this_mat[3][0] = ulEndianReadLittleFloat(fp);
1683 this_mat[3][1] = ulEndianReadLittleFloat(fp);
1684 this_mat[3][2] = ulEndianReadLittleFloat(fp);
1685 this_mat[0][0] = ulEndianReadLittleFloat(fp);
1686 this_mat[0][1] = ulEndianReadLittleFloat(fp);
1687 this_mat[0][2] = ulEndianReadLittleFloat(fp);
1688 this_mat[1][0] = ulEndianReadLittleFloat(fp);
1689 this_mat[1][1] = ulEndianReadLittleFloat(fp);
1690 this_mat[1][2] = ulEndianReadLittleFloat(fp);
1691 this_mat[2][0] = ulEndianReadLittleFloat(fp);
1692 this_mat[2][1] = ulEndianReadLittleFloat(fp);
1693 this_mat[2][2] = ulEndianReadLittleFloat(fp);
1694 DEBUGPRINT( "***** Matrix: " << std::endl << "x, y, z = " <<
1695 this_mat[3][0] << ", " << this_mat[3][1] << ", " << this_mat[3][2] << std::endl << "3 x 3 matrix:" << std::endl <<
1696 this_mat[0][0] << ", " << this_mat[0][1] << ", " << this_mat[0][2] << std::endl <<
1697 this_mat[1][0] << ", " << this_mat[1][1] << ", " << this_mat[1][2] << std::endl <<
1698 this_mat[2][0] << ", " << this_mat[2][1] << ", " << this_mat[2][2] << std::endl);
1699 this_mat[0][3] = SG_ZERO ;
1700 this_mat[1][3] = SG_ZERO ;
1701 this_mat[2][3] = SG_ZERO ;
1702 this_mat[3][3] = SG_ONE ;
1703 sgPostMultMat4( curr_matrix_, this_mat);
1704
1705 }
1706 break;
1707
1708 default: // Unknown opcode
1709 {
1710 if (opcode < 256)
1711 {
1712 if ( opcodes[opcode].size != -1)
1713 {
1714 DEBUGPRINT( "** " << opcodes[opcode].name << " (size " <<
1715 opcodes[opcode].size << ")" << std::endl );
1716 skip_offset = opcodes[opcode].size - 2; // opcode already read
1717 }
1718 else
1719 {
1720 DEBUGPRINT( "Unhandled opcode " << opcodes[opcode].name
1721 << " (" << std::hex << opcode << std::dec << ")" <<
1722 std::endl );
1723 }
1724 }
1725 else
1726 {
1727 DEBUGPRINT( "Op-code out of range: " << std::hex << opcode <<
1728 std::dec << std::endl );
1729 }
1730 } // default
1731 break;
1732 } // switch
1733
1734 if (skip_offset > 0)
1735 fseek( fp, skip_offset, SEEK_CUR );
1736
1737 } // while !feof...
1738 }
1739 //===========================================================================
1740
1741 #define MYMAKEFOURCC(a, b, c, d) \
1742 ((unsigned long)(a) | ((unsigned long)(b) << 8) | \
1743 ((unsigned long)(c) << 16) | ((unsigned long)(d) << 24 ))
1744
1745 static unsigned long lRIFF = MYMAKEFOURCC('R', 'I', 'F', 'F');
1746 static unsigned long lMDL8 = MYMAKEFOURCC('M', 'D', 'L', '8');
1747
FindBGLBeginRIFF(FILE * fp)1748 void FindBGLBeginRIFF(FILE *fp)
1749 // place file cursor on the first BGL command.
1750 // if none found, places it on the file end
1751 // This function is for RIFF format used in MSFS2k2 and 2k4 and CFS2 (and other MS sims?)
1752 {
1753 unsigned int l;
1754 while ((lRIFF != (l = ulEndianReadLittle32(fp))) && (!feof(fp)))
1755 ;
1756 if (lRIFF != l) // RIFF not found
1757 {
1758 assert(feof(fp));
1759 return;
1760 }
1761 ulEndianReadLittle32(fp); // ignore file length
1762 l = ulEndianReadLittle32(fp);
1763 if (l != MYMAKEFOURCC('M', 'D', 'L', '8'))
1764 printf("Warning: Not a 'MDL8' RIFF file\n");
1765 else
1766 printf("RIFF file, subtype 'MDL8' recognised\n");
1767 while(!feof(fp))
1768 {
1769 char buffer[5];
1770 buffer[4] = 0;
1771 fread(buffer, 4, 1, fp);
1772 unsigned long offset = ulEndianReadLittle32(fp);
1773 if (offset & 1L)
1774 offset++; // if offset is odd, add one pad byte
1775 printf("RIFF Chunk '%s' found, data length = %ld\n", buffer, offset);
1776 if (0==strcmp(buffer, "BGL "))
1777 {
1778 // Great!!
1779 return;
1780 }
1781 fseek(fp, offset, SEEK_CUR);
1782 }
1783 }
1784
FindBGLBeginOldVersion(FILE * fp)1785 void FindBGLBeginOldVersion(FILE *fp)
1786 // place file cursor on the first BGL command.
1787 // if none found, places it on the file end
1788 // This function is for old MDL files (for FS98, for example)
1789 {
1790 unsigned short op1, op2;
1791 op1 = ulEndianReadLittle16(fp);
1792
1793 while(!feof(fp))
1794 {
1795 op2 = ulEndianReadLittle16(fp);
1796 if(op1 == 0x76 && op2 == 0x3a)
1797 {
1798 fseek(fp, -4, SEEK_CUR);
1799 break;
1800 }
1801 op1 = op2;
1802 }
1803 }
1804
1805
1806
ssgLoadMDL(const char * fname,const ssgLoaderOptions * options)1807 ssgEntity *ssgLoadMDL(const char *fname, const ssgLoaderOptions *options)
1808 {
1809 ssgSetCurrentOptions ( (ssgLoaderOptions*)options ) ;
1810 current_options = ssgGetCurrentOptions () ;
1811
1812 ailerons_grp_ = NULL;
1813 elevator_grp_ = NULL;
1814 rudder_grp_ = NULL;
1815 gear_grp_ = NULL;
1816 spoilers_grp_ = NULL;
1817 flaps_grp_ = NULL;
1818 prop_grp_ = NULL;
1819 TheVertexList = NULL;
1820 TheTextureList = NULL;
1821
1822 char filename [ 1024 ] ;
1823 current_options -> makeModelPath ( filename, fname ) ;
1824
1825 FILE *fp = fopen(filename, "rb");
1826 if(!fp)
1827 {
1828 ulSetError( UL_WARNING, "ssgLoadMDL: Couldn't open MDL file '%s'!",
1829 filename );
1830 return NULL;
1831 }
1832
1833 // Find beginning of BGL Code segment
1834 unsigned long l = ulEndianReadLittle32(fp);
1835 fseek(fp, 0, SEEK_SET);
1836 if (l == lRIFF) // This is somewhat of a kludge, since ther "RIFF" is mostly at the beginning of the file, but not always.
1837 FindBGLBeginRIFF(fp);
1838 else
1839 { FindBGLBeginOldVersion(fp);
1840 if(feof(fp))
1841 { // Ok - so it is not "RIFF" at the beginning of the file and it is not an old file format -
1842 // so search for RIFF anywhere
1843 // I know of at least one file (the Wellesly V1.4, where the V1.4 is important)
1844 // that had two "RIFF"s and ionyl the second one is the one we want.
1845 // So we have to search for a place with "RIFF"
1846 fseek(fp, 0, SEEK_SET);
1847 l = ulEndianReadLittle32(fp);
1848 while(!feof(fp))
1849 {
1850 unsigned char c = fgetc(fp);
1851 l = (l >> 8) | (c << 24);
1852 if ( l == lRIFF )
1853 { // check whether it is a red herring...
1854 ulEndianReadLittle32(fp); // ignore length
1855 unsigned long ll = ulEndianReadLittle32(fp);
1856 if (ll == lMDL8)
1857 { // found it !!
1858 fseek(fp, -12, SEEK_CUR);
1859 unsigned long addr = ftell(fp);
1860 if(addr&1L)
1861 printf("strange... found RIFF, but on an odd adress %lx\n", addr);
1862 else
1863 printf("found a good RIFF header at address %lx\n", addr);
1864 FindBGLBeginRIFF(fp);
1865 break; // breaks the while(!feof(fp))
1866 }
1867 }
1868 }
1869 }
1870 }
1871
1872 if(feof(fp))
1873 {
1874 ulSetError( UL_WARNING, "ssgLoadMDL: No BGL Code found in file '%s'!",
1875 filename );
1876 fclose(fp);
1877 return NULL;
1878 }
1879 // end find begin
1880
1881
1882 // Initialize object graph
1883 model_ = new ssgBranch();
1884 char* model_name = new char[128];
1885 char *ptr = (char*)&fname[strlen(fname) - 1];
1886 while(ptr != &fname[0] && *ptr != '/') ptr--;
1887 if(*ptr == '/') ptr++;
1888 strcpy(model_name, ptr);
1889 ptr = &model_name[strlen(model_name)];
1890 while(*ptr != '.' && ptr != &model_name[0]) ptr--;
1891 *ptr = '\0';
1892 model_->setName(model_name);
1893
1894 // Create group nodes for textured and non-textured objects
1895 curr_vtx_ = new ssgVertexArray();
1896 curr_norm_ = new ssgNormalArray();
1897
1898 vertex_array_ = new ssgVertexArray();
1899 normal_array_ = new ssgNormalArray();
1900
1901 tex_coords_ = new ssgTexCoordArray();
1902
1903 start_idx_ = 0;
1904 last_idx_ = 0;
1905 curr_var_ = 0;
1906 stack_depth_ = 0;
1907 noLoDs = 1; // if there is no "branch" and no "++noLoDs" is called, we have 1 LoD.
1908 // If there is one branch, we have 2, etc.
1909 curr_lod = 0;
1910 sgMakeIdentMat4(curr_matrix_);
1911
1912 // Parse opcodes
1913 #ifdef DEBUG
1914 #ifdef _MSC_VER
1915 wkfp=fopen("c:\\mdl_file_structure.txt", "wt");
1916 #else
1917 wkfp=fopen("mdl_file_structure.txt", "wt");
1918 #endif
1919 #endif
1920
1921 ParseBGL(fp); // "traversing" through the file
1922
1923
1924 fclose(fp);
1925 #ifdef DEBUG
1926 fclose(wkfp);
1927 #endif
1928 // :-((( delete curr_vtx_;
1929 delete curr_norm_;
1930
1931 DEBUGPRINT("\n" << vertex_array_->getNum() << " vertices\n");
1932 printf("NoLoDs = %d\n", (int)noLoDs);
1933 printf("noGT=%d, noLT=%d, no0=%d\n", noGT, noLT, no0);
1934 g_noLoDs = noLoDs;
1935
1936 return model_;
1937 }
1938
1939 #else
1940
ssgLoadMDLTexture(const char * fname,ssgTextureInfo * info)1941 bool ssgLoadMDLTexture ( const char *fname, ssgTextureInfo* info )
1942 {
1943 ulSetError ( UL_WARNING,
1944 "ssgLoadTexture: '%s' - MDL support not configured", fname ) ;
1945 return false ;
1946 }
1947
1948
1949 #endif
1950
1951