Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

FrontierMesh.cpp

Go to the documentation of this file.
00001 
00002 /*
00003     TSGL - Teddy Space Game Library
00004     Copyright (C) 2002 Timo Suoranta
00005     tksuoran@cc.helsinki.fi
00006 
00007     This library is free software; you can redistribute it and/or
00008     modify it under the terms of the GNU Lesser General Public
00009     License as published by the Free Software Foundation; either
00010     version 2.1 of the License, or (at your option) any later version.
00011 
00012     This library is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015     Lesser General Public License for more details.
00016 
00017     You should have received a copy of the GNU Lesser General Public
00018     License along with this library; if not, write to the Free Software
00019     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020 
00021     $Id: FrontierMesh.cpp,v 1.1 2002/01/08 20:47:05 tksuoran Exp $
00022 */
00023 
00024 
00025 #include "Teddy/SpaceGame/FrontierMesh.h"
00026 #include "Teddy/SpaceGame/FrontierFile.h"
00027 #include "Teddy/Graphics/Features.h"
00028 #include "Teddy/Materials/Material.h"
00029 #include "Teddy/Materials/Render.h"
00030 #include "Teddy/Models/Line.h"
00031 #include "Teddy/Models/Mesh.h"
00032 #include "Teddy/Models/Vertex.h"
00033 #include "Teddy/Models/Face.h"
00034 #include "Teddy/SysSupport/Exception.h"
00035 #include "Teddy/SysSupport/Messages.h"
00036 using namespace Teddy::Materials;
00037 
00038 
00039 #define USE_FRONTIER_SCALE  1
00040 #define SCALE               1.0f
00041 
00042 
00043 namespace Teddy     {
00044 namespace SpaceGame {
00045 
00046 
00047 void FrontierMesh::faceBegin(){
00048     face_good = true;
00049     face_open = true;
00050     face      = new Face();
00051 }
00052 
00053 void FrontierMesh::faceInsertVertex( int index ){
00054     if( !face_open ){
00055         faceBegin();
00056 //      return;
00057     }
00058     Vertex                  *vertex;
00059     int_to_Vertex::iterator  v_it;
00060 
00061     v_it = vertices.find( index );
00062     if( v_it!=vertices.end() ){
00063         vertex = (*v_it).second;
00064         if( vertex == NULL ){
00065             face_good = false;
00066         }
00067     }else{
00068         vertex = NULL;
00069         face_good = false;
00070     }
00071 
00072     if( face_good ){
00073         face_num_vertices++;
00074         face->append( vertex );
00075         last_vertex_index = index;
00076     }
00077 
00078 }
00079 
00080 void FrontierMesh::faceInsertSpline( int pi1, int pi2, int ci1, int ci2 ){
00081     if( !face_open ){
00082 //      faceBegin();
00083         ffe_debug_msg( "face not open" );
00084         return;
00085     }
00086     int_to_Vertex::iterator  v_it;
00087     bool                     spline_good = true;
00088     Vertex                  *p1          = NULL;
00089     Vertex                  *p2          = NULL;
00090     Vertex                  *c1          = NULL;
00091     Vertex                  *c2          = NULL;
00092 
00093     v_it = vertices.find( pi1 );
00094     if( v_it!=vertices.end() ){
00095         p1 = (*v_it).second;
00096         if( p1 == NULL ){
00097             spline_good = false;
00098         }
00099     }else{
00100         spline_good = false;
00101     }
00102 
00103     v_it = vertices.find( pi2 );
00104     if( v_it!=vertices.end() ){
00105         p2 = (*v_it).second;
00106         if( p2 == NULL ){
00107             spline_good = false;
00108         }
00109     }else{
00110         spline_good = false;
00111     }
00112 
00113     v_it = vertices.find( ci1 );
00114     if( v_it!=vertices.end() ){
00115         c1 = (*v_it).second;
00116         if( c1 == NULL ){
00117             spline_good = false;
00118         }
00119     }else{
00120         spline_good = false;
00121     }
00122 
00123     v_it = vertices.find( ci2 );
00124     if( v_it!=vertices.end() ){
00125         c2 = (*v_it).second;
00126         if( c2 == NULL ){
00127             spline_good = false;
00128         }
00129     }else{
00130         spline_good = false;
00131     }
00132 
00133     if( spline_good == false ){
00134         ffe_debug_msg( "spline is not good" );
00135         return;
00136     }
00137 
00138     for( int i=1; i<=16; i++ ){
00139         double u = (double)(i)/(16.0f);
00140 
00141         Vertex a = (*p1) * (                  ::pow(       u , 3.0f )  );
00142         Vertex b = (*c1) * (3.0f * (1.0f-u) * ::pow(       u , 2.0f )  );
00143         Vertex c = (*c2) * (3.0f *       u  * ::pow( (1.0f-u), 2.0f )  );
00144         Vertex d = (*p2) * (                  ::pow( (1.0f-u), 3.0f )  );
00145 
00146         Vertex *v = new Vertex();
00147         *v = a + b + c + d;
00148         face_num_vertices++;
00149         face->append( v );
00150     }
00151     last_vertex_index = pi2;
00152 }
00153 
00154 void FrontierMesh::faceClose( int normal_index ){
00155     if( face_open ){
00156         if( face_good ){
00157             if( normal_index == -1 ){
00158                 face->makeNormal();
00159             }else{
00160                 Vertex                  *normal;
00161                 int_to_Vertex::iterator  v_it;
00162 
00163                 v_it = normals.find( normal_index );
00164                 if( v_it!=normals.end() ){
00165                     normal = (*v_it).second;
00166                     if( normal != NULL ){
00167                         face->setNormal( &normal->getVertex() );
00168                     }else{
00169                         ffe_debug_msg( "null normal" );
00170                         face->makeNormal();
00171                     }
00172                 }else{
00173                     ffe_debug_msg( "normal %d not found", normal_index );
00174                     face->makeNormal();
00175                 }
00176             }
00177             this->insert( face );
00178             face      = NULL;
00179             face_open = false;
00180             face_good = false;
00181         }else{
00182 //          cout << "Face not good" << endl;
00183         }
00184     }else{
00185 //      cout << "Face not open" << endl;
00186     }
00187 }
00188 
00189 void FrontierMesh::makeVertex( Vertex &v1, Vertex &v2 ){
00190     int_to_Vertex::iterator  v_it;
00191     int b0;
00192     int b1;
00193     int b2;
00194     int b3;
00195     int b4;
00196     int b5;
00197 
00198     int mode_1;
00199     int mode_2;
00200     int x;
00201     int y;
00202     int z;
00203     int w;
00204 
00205     mode_1 = b0 = f->get_byte_low( false );
00206     mode_2 = b1 = f->get_byte();
00207     x      = b2 = f->read_Sint8();
00208     y      = b3 = f->read_Sint8();
00209     z      = b4 = f->read_Sint8();
00210     w      = b5 = f->read_Sint8();
00211 
00212     switch( mode_1 ){
00213     case 0x00:  //  Normal vertex, b2 = x, b3 = y, b4 = z
00214     case 0x01:
00215     case 0x02:
00216         v1 = Vertex(  x, y, z );
00217         v2 = Vertex( -x, y, z );
00218         break;
00219     case 0x09:  //  3d average of vertices indexed by b3, b4
00220     case 0x0a:
00221     case 0x03:  //  2d average of vertices indexed by b3, b4
00222     case 0x04:
00223     case 0x0b:  //  2d average of vertices indexed by b3, b4
00224     case 0x0c:
00225         v_it = vertices.find( b3 );
00226         if( v_it==vertices.end() ){
00227             //printf( "!" );
00228             return;
00229         }
00230         v1 = *(*v_it).second;
00231         v_it = vertices.find( b4 );
00232         if( v_it==vertices.end() ){
00233             //printf( "!" );
00234             return;
00235         }
00236         v1 += *(*v_it).second;
00237         v1 *= 0.5;
00238         v2 = v1;
00239         v2.flipX();
00240         break;
00241 
00242     case 0x05:  //  Negative of vertex indexed by b3
00243     case 0x06:
00244         v_it = vertices.find( b3 );
00245         if( v_it==vertices.end() ){
00246 //          cout << "!";
00247             return;
00248         }
00249         v1 = *(*v_it).second;  //  Copy vertex
00250         v1.neg();
00251         v2   = v1;
00252         v2.flipX();
00253         break;
00254 
00255     case 0x07:
00256     case 0x08:
00257         v1 = Vertex(  x, y, z );
00258         v2 = Vertex(  0, y, z );
00259         break;
00260 
00261     case 0x0d:  //  3d arith: vertex b2 + vertex b3 - vertex b4
00262     case 0x0e:
00263         v_it = vertices.find( b2 );
00264         if( v_it==vertices.end() ){
00265             //printf( "!" );
00266             return;
00267         }
00268         v1 = *(*v_it).second;  //  Copy vertex
00269         v_it = vertices.find( b3 );
00270         if( v_it==vertices.end() ){
00271             //printf( "!" );
00272             return;
00273         }
00274         v1   += *(*v_it).second;
00275         v_it  = vertices.find( b4 );
00276         if( v_it==vertices.end() ){
00277             //printf( "!" );
00278             return;
00279         }
00280         v1 -= *(*v_it).second;
00281         v2 = v1;
00282         v2.flipX();
00283         break;
00284 
00285     case 0x0f:  //  3d arith: vertex b3 + vertex b4 
00286     case 0x10:
00287         v_it = vertices.find( b3 );
00288         if( v_it==vertices.end() ){
00289 //          cout << "!";
00290             return;
00291         }
00292         v1   = *(*v_it).second;
00293         v_it = vertices.find( b4 );
00294         if( v_it==vertices.end() ){
00295 //          cout << "!";
00296             return;
00297         }
00298         v1 += *(*v_it).second;
00299         v2  = v1;
00300         v2.flipX();
00301         break;
00302     default:
00303     case 0x13:  //  Linear interpolation between vertices b3, b4
00304     case 0x14:
00305         //  cout << "!";
00306         v1 = Vertex( 0, 0, 0 );
00307         v2 = Vertex( 0, 0, 0 );
00308         break;
00309     }
00310 }
00311 
00312 
00314 /*virtual*/ void FrontierMesh::debug( Uint32 command, void *data ){
00315 /*  debug_selected_element_it++;
00316     if( debug_selected_element_it==elements.end() ){
00317         debug_selected_element_it = elements.begin();
00318     }*/
00319 }
00320 
00321 
00323 FrontierMesh::FrontierMesh( FrontierFile *f, int ob_id, const char *name ):Mesh(name){
00324     int   object_index;
00325 
00326     material = new Material(
00327         "Frontier Test Material",
00328         RENDER_MODE_LINE,
00329         RENDER_LIGHTING_COLOR,
00330         RENDER_OPTION_DEPTH_TEST_M |
00331         RENDER_OPTION_DIFFUSE_M    
00332     );
00333     material->setAmbient  ( Color::BLACK );
00334     material->setDiffuse  ( Color::GRAY_75 );
00335     material->setSpecular ( Color::WHITE );
00336     material->setShininess( 8.0f );
00337 
00338     this->f = f;
00339 
00340     object_index = ob_id-1;
00341 
00342     parseObject  ( object_index );
00343     parseSpecs   ();
00344     parseVertices();
00345     parseNormals ();
00346     parseElements();
00347 
00348     this->setClipRadius( 2*radius );
00349 //  debug_selected_element_it = this->elements.begin();
00350 
00351 //  printf(cout << name << " has " << submeshes.size() << " submeshes" << endl;
00352 }
00353 
00354 
00356 void FrontierMesh::parseObject( const int object_index ){
00357     char *object_pointer = "";
00358     char *tmp;
00359     int   i;
00360 
00361     //  Seek to object directory
00362     f->reset();
00363     f->seek( "DATA_004681:" ); tmp = f->get_label_def();
00364 
00365     //  Skip until we are at correct object index
00366     for( i=0; i<object_index+1; i++ ){
00367         object_pointer = f->get_label_ref();
00368     }
00369     strcat( object_pointer,  ":" );
00370 
00371     f->reset();
00372     f->seek( object_pointer ); tmp = f->get_label_def();
00373 
00374     mesh_pointer      = f->get_label_ref();
00375     vertex_pointer    = f->get_label_ref();
00376     vertex_count      = f->read_Uint32  ();
00377     normal_pointer    = f->get_label_ref();
00378     normal_count      = f->read_Uint32  ();  //  normals + 2
00379     unknown_2         = f->read_Uint32  ();
00380     unknown_3         = f->read_Uint32  ();
00381     radius            = f->read_Uint32  ();
00382     primitive_count   = f->read_Uint32  ();
00383     unknown_4         = f->read_Uint32  ();
00384     unknown_5         = f->read_Uint32  ();
00385     unknown_6         = f->read_Uint32  ();
00386     unknown_7         = f->read_Uint32  ();
00387     collision_pointer = f->get_label_ref();
00388     spec_pointer      = f->get_label_ref();
00389     unknown_8         = f->read_Uint32  ();
00390     unknown_9         = f->read_Uint32  ();
00391 
00392     strcat( mesh_pointer,      ":" );
00393     strcat( vertex_pointer,    ":" );
00394     strcat( normal_pointer,    ":" );
00395     strcat( collision_pointer, ":" );
00396     strcat( spec_pointer,      ":" );
00397 
00398 /*
00399     cout << "\n-- OBJECT -- " << ob_name << " --" << endl;  
00400     cout << "Mesh           " << mesh_pointer      << endl;
00401     cout << "Vertices       " << vertex_pointer    << endl;
00402     cout << "Vertices       " << vertex_count      << endl;
00403     cout << "Normals        " << normal_pointer    << endl;
00404     cout << "Normals        " << normal_count      << endl;
00405     cout << "unknown_2      " << unknown_2         << endl;
00406     cout << "unknown_3      " << unknown_3         << endl;
00407     cout << "Radius         " << radius            << endl;
00408     cout << "Primitives     " << primitive_count   << endl;
00409     cout << "unknown_4      " << unknown_4         << endl;
00410     cout << "unknown_5      " << unknown_5         << endl;
00411     cout << "unknown_6      " << unknown_6         << endl;
00412     cout << "unknown_7      " << unknown_7         << endl;
00413     cout << "Collision data " << collision_pointer << endl;
00414     cout << "Specifications " << spec_pointer      << endl;
00415     cout << "unknown_8      " << unknown_8         << endl;
00416     cout << "unknown_9      " << unknown_9         << endl;
00417 */
00418 }
00419 
00420 
00421 void FrontierMesh::parseSpecs(){
00422     char *name_pointer = "";
00423     char *tmp;
00424     int   i;
00425 
00426     if( strcmp( spec_pointer, "NULL:" ) == 0 ){
00427         // cout << "Object has no ship specifications" << endl;
00428         return;
00429     }
00430 
00431     f->reset();                  //  Rewind to start of file
00432     f->seek( spec_pointer ); tmp = f->get_label_def();
00433 
00434     Uint16 foward_thrust     = f->read_Uint16();  // 0 1
00435     Uint16 reverse_thrust    = f->read_Uint16();  // 2 3
00436     Uint8  gm                = f->read_Uint8();   // 4
00437     Uint8  sm                = f->read_Uint8();   // 5
00438     Uint16 mass              = f->read_Uint16();  // 6 7
00439     Uint16 internal_capacity = f->read_Uint16();  // 8 9
00440     Uint16 price             = f->read_Uint16();  // a b  10 11
00441     Uint16 zoom_factor       = f->read_Uint16();  // c d  12 13
00442     Uint8  id                = f->read_Uint8();   // e    14
00443     Uint8  s_unknown_1       = f->read_Uint8();   // f    15
00444     Uint8  crew              = f->read_Uint8();   // 10   16
00445     Uint8  s_unknown_2       = f->read_Uint8();   // 11   17
00446     Uint8  missiles          = f->read_Uint8();   // 12   18
00447     Uint8  s_unknown_3       = f->read_Uint8();   // 13   19
00448     Uint8  drive             = f->read_Uint8();   // 14   20
00449     Uint8  integral_drive    = f->read_Uint8();   // 15   21
00450     /*
00451 DATA_002568: ; StowMaster Fighter
00452             [F.Thrust]    [R.Thrust]   [GM]   [SM]     [Mass]
00453         db [0xef, 0x1f], [0xb6, 0xea], [0x1], [0x0], [0xe, 0x0]
00454            [Int.Cap.]    [Price]      [ZoomF]    [ID]
00455         db [0xc, 0x0], [0x19, 0x0], [0x2d, 0x0], [0xc], 0x40
00456            [Crew]      [Mis]      [Drive] [IntegralDrive]
00457         db [0x1], 0x0, [0x0], 0x0, [0x2],      [0x80], 0x0, 0x1
00458         db 0xc0, 0x3, 0x0, 0x0, 0x80, 0x2, 0x0, 0x0
00459         db 0x60, 0x3, 0xa0, 0xff, 0x5c, 0x0, 0x1e, 0x0
00460         db 0xc0, 0x2, 0x4a, 0x0, 0x14, 0x0, 0x7, 0x0
00461 */
00462     f->reset();                  //  Rewind to start of file
00463     f->seek( "DATA_004682:" );   //  Seek to name directory
00464     for( i=0; i<id+2; i++ ){
00465         name_pointer = f->get_label_ref();
00466     }
00467     strcat( name_pointer, ":" );
00468     f->reset();                  //  Rewind to start of file
00469     f->seek( name_pointer );
00470     tmp = f->get_label_def();
00471     char *object_name = f->get_string();
00472     setName( object_name );
00473 }
00474 
00475 
00477 void FrontierMesh::parseVertices(){
00478     Vertex *v1;
00479     Vertex *v2;
00480     char   *tmp;
00481     int     i;
00482 
00483     f->reset();
00484     f->seek( vertex_pointer ); tmp = f->get_label_def();
00485     for( i=0; i<vertex_count; i++ ){
00486         if( f->get_type() == FF_BYTE ){
00487             v1 = new Vertex();
00488             v2 = new Vertex();
00489             makeVertex( *v1, *v2 );
00490             this->vertices.insert( pair<int,Vertex*>(i,v1) ); i++;
00491             this->vertices.insert( pair<int,Vertex*>(i,v2) ); 
00492         }else{
00493             ffe_debug_msg( "Problems at %d", i );
00494             break;
00495         }
00496     }
00497 }
00498 
00499 
00501 void FrontierMesh::parseNormals(){
00502     Vertex *v1;
00503     Vertex *v2;
00504     char   *tmp;
00505     int     i;
00506 
00507     if( strcmp( normal_pointer, "NULL:" ) != 0 ){
00508         f->reset();
00509         f->seek( normal_pointer ); tmp = f->get_label_def();
00510         i = 0;
00511         v1 = new Vertex(  0,  1, 0 );
00512         v2 = new Vertex(  0, -1, 0 );
00513         this->normals.insert( pair<int,Vertex*>(i,v1) ); i++;
00514         this->normals.insert( pair<int,Vertex*>(i,v2) ); i++;
00515         while( f->get_type() == FF_BYTE ){
00516             v1 = new Vertex();
00517             v2 = new Vertex();
00518             makeVertex( *v1, *v2 );
00519             v1->normalize();
00520             v2->normalize();
00521             this->normals.insert( pair<int,Vertex*>(i,v1) ); i++;
00522             this->normals.insert( pair<int,Vertex*>(i,v2) ); i++;
00523         }
00524     }
00525 }
00526 
00527 
00528 void FrontierMesh::printVertices(){
00529     int_to_Vertex::iterator  v_it;
00530     Vertex                  *vertex;
00531     int                      i;
00532 
00533     for( i=0; i<vertex_count; i++ ){
00534         v_it = vertices.find( i );
00535         vertex = (*v_it).second;
00536         ffe_debug_msg( "Vertex %d is ", i );
00537 //      vertex->debug();
00538     }
00539 }
00540 
00541 void FrontierMesh::parseElements(){
00542     int        byte;
00543     int        count         =  0;     //  Pos on line for formatted output
00544     int        par_count     =  0;     //  Parameter number
00545     int        prev_block_id =  0;     //  ID of previous (finished) block
00546     int        block_id      =  0;     //  ID of current block
00547     int        block_left    =  0;     //  How many bytes are left in this block
00548     int        elements      =  0;     //  How many elements we have found in this model?
00549     bool       null_term     = false;  //  Is current block null-terminating?
00550     bool       out_of_sync   = false;  //  Have we lost sync in the file?
00551     int        par[256];               //  Parameter buffer
00552     bool       open;                   //  For 0500 primitive: is the face closed or open?
00553     bool       good;                   //  Are all face vertices good?
00554     Face      *face          = NULL;   //  Face to be added
00555     char      *tmp;
00556 
00557     //  Read in elements
00558     f->reset();
00559     f->seek( mesh_pointer ); tmp = f->get_label_def();
00560 
00561     while( f->get_type() == FF_BYTE ){
00562         byte = f->get_byte_low( false );
00563 
00564         if( !out_of_sync && !null_term ){
00565             //  If we are in sync, simply get next byte
00566             block_left--;
00567 
00568             //  If was first after last block, store first byte of next block id
00569             if( (block_left == -1) ){
00570 //              cout << endl;
00571                 count = 0;
00572                 block_id = byte;
00573             }
00574         }
00575 
00576         //  Null terminating element?
00577         if( null_term && par_count>1 ){
00578             if( byte==0 ){               //  Zero?
00579                 if( (par_count&1)==0 && (block_left == -1) ){  //  First zero?
00580                     block_left = -3;
00581                 }else if( (par_count&1)==1 && (block_left == -3) ){
00582                     block_left = 0;
00583                     null_term = false;
00584                 }else{
00585                     block_left = -1;
00586                 }
00587             }else{                       //  Not zero?
00588                 block_left = -1;
00589             }
00590         }
00591 
00592         //  Printing with formatting
00593 /*        char out[80];
00594         sprintf( out, "%02x ", byte );
00595         if( count&1 == 1 ){
00596             cout << out << " ";
00597         }else{
00598             cout << out;
00599         }*/
00600         count++;
00601 
00602         //  Formatting
00603         if( out_of_sync ){
00604             if( count >= 8 ){
00605 //              cout << endl;
00606                 count = 0;
00607             }
00608             continue;
00609         }else{
00610             if( count >= 16 ){
00611 //              cout << endl << "               "; cout.flush();
00612                 count = 0;
00613             }
00614         }
00615 
00616         //  Are we getting (last byte of) ID of next block?
00617         //  This would be case of second byte after previous block
00618         if( (block_left == -2) && (!null_term) ){
00619 
00620 //  Material
00621             Uint16 mat              = (par[0]) + (par[1]<<8);
00622             Uint32 texture_id       = 0;
00623             bool   use_texture      = false;
00624             bool   use_lighting     = true;
00625             bool   use_object_color = false;
00626             Uint8  r = 128;
00627             Uint8  g = 128;
00628             Uint8  b = 128;
00629 
00630             if( ((mat & 0x4000) == 0x4000) ){ // 0x4000  - if set, low twelve bits are texture index, otherwise RGB
00631                 use_texture = true;
00632                 texture_id  = (mat & 0x0fff);
00633             }else{
00634                 r = (mat & 0x0f00)>>16;
00635                 g = (mat & 0x00f0)>> 8;
00636                 b = (mat & 0x000f);
00637                 float rf = (float)(r)/16.0f;
00638                 float gf = (float)(g)/16.0f;
00639                 float bf = (float)(b)/16.0f;
00640 //              material->setDiffuse( Color(rf,gf,bf) );
00641 //              cout << "Set diffuse to " << (int)(r) << ", " << int(g) << ", " << int(b) << endl;
00642             }
00643             if( ((mat & 0x2000) == 0x2000) ){ // 0x2000  - if set, surface should not be lit
00644                 use_lighting = false;
00645             }
00646             if( ((mat & 0x1000) == 0x1000) ){ // 0x1000  - if set, surface colours should depend on object colour
00647                 use_object_color = true;
00648             }
00649 
00650 //  Process previous block
00651             switch( prev_block_id ){
00652             case 0x0200:   //  ThinLine
00653             case 0x1100: { //  WideLine
00654                 bool line_good = true;
00655 
00656                 Vertex                  *v1;
00657                 Vertex                  *v2;
00658                 int_to_Vertex::iterator  v_it;
00659 
00660                 v_it = vertices.find( par[2] );
00661                 if( v_it!=vertices.end() ){
00662                     v1 = (*v_it).second;
00663                     if( v1 == NULL ){
00664                         line_good = false;
00665                     }
00666                 }else{
00667                     v1 = NULL;
00668                     line_good = false;
00669                 }
00670 
00671                 v_it = vertices.find( par[2+1] );
00672                 if( v_it!=vertices.end() ){
00673                     v2 = (*v_it).second;
00674                     if( v2 == NULL ){
00675                         line_good = false;
00676                     }
00677                 }else{
00678                     v2 = NULL;
00679                     line_good = false;
00680                 }
00681 
00682                 if( line_good ){
00683                     Line *l = new Line( v1, v2 );
00684                     this->insert( l );
00685 //                  cout << "ok line" << endl;
00686                 }else{
00687 //                  cout << "line not ok" << endl;
00688                 }
00689                 break;
00690             }
00691             case 0x0300:  //  Triangle              
00692                 faceBegin();
00693                 faceInsertVertex( par[2+0] );
00694                 faceInsertVertex( par[2+3] );
00695                 faceInsertVertex( par[2+1] );
00696                 faceClose( par[2+2] );
00697                 break;
00698 
00699             case 0x0700:  //  MirrorTriangle                
00700                 faceBegin();
00701                 faceInsertVertex( par[2+0] );
00702                 faceInsertVertex( par[2+3] );
00703                 faceInsertVertex( par[2+1] );
00704                 faceClose( par[2+2] );
00705                 faceBegin();
00706                 faceInsertVertex( par[2+0]+1 );
00707                 faceInsertVertex( par[2+3]+1 );
00708                 faceInsertVertex( par[2+1]+1 );
00709                 faceClose( par[2+2]+1 );
00710                 break;
00711 
00712             case 0x0400:  //  Quad
00713                 faceBegin();
00714                 faceInsertVertex( par[2+0] );
00715                 faceInsertVertex( par[2+2] );
00716                 faceInsertVertex( par[2+1] );
00717                 faceInsertVertex( par[2+3] );
00718                 faceClose( par[2+4] );
00719                 break;
00720 
00721             case 0x0800:  //  MirrorQuad
00722                 faceBegin();
00723                 faceInsertVertex( par[2+0] );
00724                 faceInsertVertex( par[2+2] );
00725                 faceInsertVertex( par[2+1] );
00726                 faceInsertVertex( par[2+3] );
00727                 faceClose( par[2+4] );
00728                 faceBegin();
00729                 faceInsertVertex( par[2+0]+1 );
00730                 faceInsertVertex( par[2+2]+1 );
00731                 faceInsertVertex( par[2+1]+1 );
00732                 faceInsertVertex( par[2+3]+1 );
00733                 faceClose( par[2+4]+1 );
00734                 break;
00735 
00736             case 0:
00737                 break;
00738 
00739             case 0x0500: {  //  Complex
00740                 Uint8 code;
00741                 Uint8 ppos = 2;
00742                 open       = true;
00743                 good       = true;
00744 
00745                 while( ppos<par_count ){
00746                     ppos += 2;
00747                     code = par[ppos+1];
00748 /*                  cout.setf( ios::hex, ios::basefield );
00749                     cout.width( 2 );
00750                     cout << "par[" << (int)(ppos+1) << "] = " << (int)(code) << endl;
00751 */
00752                     switch( code ){
00753                     case 0x00:
00754                         // Type 0x0: Length 2 bytes. Terminates stream.
00755                         // Surface will be closed off if not already terminated.
00756                         faceClose();
00757                         break;
00758 
00759                     case 0x02:
00760                         // Type 0x2: Length 6 bytes. Format v1, 02, v2, v1, v4, v3
00761                         // Starts a surface with a spline. v1 and v4 are end points, v2 and v3 are
00762                         // intermediate control points. Note that the first byte is a copy of the
00763                         // third. Only the third is used for processing, but the first can be used
00764                         // as the depth-sort index.
00765                         faceBegin();
00766                         faceInsertSpline( par[ppos], par[ppos+4], par[ppos+2], par[ppos+5] );
00767 //                      faceInsertVertex( par[ppos] );
00768                         ppos += 2;
00769                         ppos += 2;
00770 //                      faceInsertVertex( par[ppos] );
00771                         break;
00772 
00773                     case 0x04:
00774                         // Type 0x4: Length 4 bytes. Format v1, 04, v2, 00
00775                         // Starts a surface with a line. v1 and v2 are end points.
00776                         faceBegin();
00777                         faceInsertVertex( par[ppos] );
00778                         ppos += 2;
00779                         faceInsertVertex( par[ppos] );
00780                         break;
00781 
00782                     case 0x06:
00783                         // Type 0x6: Length 2 bytes. Format v2, 06
00784                         // Continues a surface with a line. v1 is taken from the previous element
00785                         // in the stream. v1 and v2 are end points.
00786                         faceInsertVertex( par[ppos] );
00787                         break;
00788 
00789                     case 0x08:
00790                         // Type 0x8: Length 4 bytes. Format v2, 08, v4, v3
00791                         // Continues a surface with a spline. v1 is taken from the previous element
00792                         // in the stream. v1 and v4 are end points, v2 and v3 are intermediate
00793                         // control points.
00794                         faceInsertSpline( last_vertex_index, par[ppos+2], par[ppos], par[ppos+4] );
00795 //                      faceInsertVertex( par[ppos] );
00796                         ppos += 2;
00797 //                      faceInsertVertex( par[ppos] );
00798                         break;
00799 
00800                     case 0x0a:
00801                         // Type 0xa: Length 2 bytes. Format 00, 0a
00802                         // Terminates a surface, completing with a line as necessary. Note that
00803                         // multiple surfaces can be defined in a single stream as a result.
00804                         faceClose();
00805                         break;
00806 
00807                     case 0x0c:
00808                         // Type 0xc: Length 4 bytes. Format vc, 0c, n, r
00809                         // Creates a complete 3d circle surface (ellipse in 2d) using two splines.
00810                         // vc is centre vertex index, n is surface normal index, r is radius in
00811                         // model units.
00812                         break;
00813                     }
00814                 }
00815                 break;
00816             }
00817             case 0x1600:  //  Basic spline
00818                 // Basic spline: (0x)16, 00, m1, m2, v2, v4, v1, v3, n, 00
00819                 // Used for powerlines etc. m1, m2 are the material word (should be simple
00820                 // colour), v1 and v4 are end vertices, v2 and v3 are control points, n is
00821                 // normal index for lighting only (no culling).
00822                 break;
00823 
00824             case 0x0900:  //  Engine glow
00825                 // Thrust-jet effect: 09, 00, m1, m2, v1, v2, s1, s2
00826                 // m1 and m2 are the material word, usually 0xee, 0x20. v1 and v2 are
00827                 // vertices for start and end of the thrust jet - v2 is generally a linear
00828                 // animated vertex. s1 and s2 are a size word, probably representing the
00829                 // width of the jet.
00830                 break;
00831     
00832             default:
00833                 break;
00834             }
00835 
00836             par_count      = 0;
00837             prev_block_id  = block_id = (block_id<<8) + byte;
00838             null_term      = false;
00839 
00840             int primitive = block_id & 0x1f00;
00841 /*          sprintf( out, ":%04x: ", primitive );
00842             cout << "" << out << " "; cout.flush();*/
00843 
00844             if( (block_id & 0xff) == 0xff ){
00845                 block_left = 0;
00846             }else{
00847             
00848             switch( primitive ){
00849             case 0x0000: block_left = 0 ; break;  //   set
00850             case 0x0100:
00851                 block_left = 3; 
00852                 break;
00853             case 0x0200: block_left = 2 ; break;  //   set ThinLine                                                                                                                                                                          
00854             case 0x0300: block_left = 3 ; break;  //   set
00855             case 0x0400: block_left = 4 ; break;  //   set Quad
00856             case 0x0500: null_term = true;break;  //   set Complex
00857             case 0x0600: block_left = 0 ; break;  //   set
00858             case 0x0700: block_left = 3 ; break;  //   set
00859             case 0x0800: block_left = 4 ; break;  //   set MirrorQuad
00860             case 0x0900: block_left = 3 ; break;  //   set
00861             case 0x0a00: block_left = 4 ; break;  //   set
00862             case 0x0b00: block_left = 1 ; break;  //   set
00863             case 0x0c00: block_left = 1 ; break;  //   set
00864             case 0x0d00: block_left = 1 ; break;  //   set?
00865             case 0x0e00: block_left = 1 ; break;  //   set?
00866             case 0x0f00: block_left = 1 ; break;  //
00867             case 0x1000: block_left = 1 ; break;  //   set
00868             case 0x1100: block_left = 6 ; break;  //   set WideLine
00869             case 0x1200: block_left = 1 ; break;  //   
00870             case 0x1300: block_left = 1 ; break;  //   set
00871             case 0x1400: block_left = 1 ; break;  //   set
00872             case 0x1500: block_left = 0 ; break;  //   set
00873             case 0x1600: block_left = 12; break;  //
00874             case 0x1700: block_left = 1 ; break;  //
00875             case 0x1800: block_left = 0 ; break;  //   set
00876             case 0x1900: block_left = 0 ; break;  //   set
00877             case 0x1a00:
00878                 if( block_id==0x1a00 ){
00879                     block_left = 9;
00880                 }else{
00881                     block_left = 1;
00882                 }
00883                 break;
00884             case 0x1b00: block_left = 3 ; break;  //   set
00885             case 0x1c00: block_left = 3 ; break;  //   set
00886             case 0x1d00: block_left = 1 ; break;  //   set
00887             case 0x1e00: block_left = 0 ; break;  //   set
00888             case 0x1f00: block_left = 1 ; break;  //   set
00889             default:
00890                 ffe_debug_msg( "Unknown block ID - out of sync" );
00891                 out_of_sync = true;
00892                 break;
00893             }
00894 
00895             }
00896 
00897             count = 0;
00898             if( null_term ){
00899                 block_left = -1;
00900             }else{
00901                 block_left *= 2;
00902             }
00903         }else{  //  Not end -- //  Store parameters         
00904             par[par_count++] = byte;
00905             if( null_term && (par_count>4) ){
00906                 if( par[3] == 0xc0 ){
00907                     block_left = 0;
00908                     null_term = false;
00909                 }
00910             }
00911         }
00912     }
00913 
00914 }
00915 
00916 
00917 };  //  namespace SpaceGame
00918 };  //  namespace Teddy
00919 
00920 
00921 /*
00922 
00923 Finally, Stone-D did some work on the specs section:
00924 
00925 DATA_002568: ; StowMaster Fighter
00926             [F.Thrust]    [R.Thrust]   [GM]   [SM]     [Mass]
00927         db [0xef, 0x1f], [0xb6, 0xea], [0x1], [0x0], [0xe, 0x0]
00928            [Int.Cap.]    [Price]      [ZoomF]    [ID]
00929         db [0xc, 0x0], [0x19, 0x0], [0x2d, 0x0], [0xc], 0x40
00930            [Crew]      [Mis]      [Drive] [IntegralDrive]
00931         db [0x1], 0x0, [0x0], 0x0, [0x2],      [0x80], 0x0, 0x1
00932 
00933         db 0xc0, 0x3, 0x0, 0x0, 0x80, 0x2, 0x0, 0x0
00934         db 0x60, 0x3, 0xa0, 0xff, 0x5c, 0x0, 0x1e, 0x0
00935         db 0xc0, 0x2, 0x4a, 0x0, 0x14, 0x0, 0x7, 0x0
00936 
00937 
00938 Ok, I've finished decoding the mysterious primitive 05. As expected, its
00939 purpose is to draw flat-colour complex surfaces with a mixture of spline
00940 and straight-line edges.
00941 
00942 The first six bytes of the primitive are as follows:
00943 
00944 Offset:
00945 0x0     word 0005, primitive identifier
00946 0x2     word for material type, should always be a single colour
00947 0x4     byte containing culling/lighting normal for whole surface in low
00948 7 bits. Top bit is a flag to disable complex z-clipping.
00949 0x5     byte for length of following stream. Only used with normal
00950 culling.
00951 
00952 A stream of sub-primitives of varying lengths follows. The second byte
00953 of each identifies the subfunction. The very first byte of the stream is
00954 used for depth-sorting the entire surface:
00955 
00956 Type 0x2: Length 6 bytes. Format v1, 02, v2, v1, v4, v3
00957 Starts a surface with a spline. v1 and v4 are end points, v2 and v3 are
00958 intermediate control points. Note that the first byte is a copy of the
00959 third. Only the third is used for processing, but the first can be used
00960 as the depth-sort index.
00961 
00962 Type 0x4: Length 4 bytes. Format v1, 04, v2, 00
00963 Starts a surface with a line. v1 and v2 are end points.
00964 
00965 Type 0x6: Length 2 bytes. Format v2, 06
00966 Continues a surface with a line. v1 is taken from the previous element
00967 in the stream. v1 and v2 are end points.
00968 
00969 Type 0x8: Length 4 bytes. Format v2, 08, v4, v3
00970 Continues a surface with a spline. v1 is taken from the previous element
00971 in the stream. v1 and v4 are end points, v2 and v3 are intermediate
00972 control points.
00973 
00974 Type 0xa: Length 2 bytes. Format 00, 0a
00975 Terminates a surface, completing with a line as necessary. Note that
00976 multiple surfaces can be defined in a single stream as a result.
00977 
00978 Type 0xc: Length 4 bytes. Format vc, 0c, n, r
00979 Creates a complete 3d circle surface (ellipse in 2d) using two splines.
00980 vc is centre vertex index, n is surface normal index, r is radius in
00981 model units.
00982 
00983 A little caveat - spline segment vertex order isn't absolutely certain.
00984 I'd need to go through a massive chain of functions to check.
00985 
00986 A little bonus piece on the mysterious material word:
00987 
00988 The material word, used in many primitive types, appears to have a
00989 consistent format independent of the primitive. The top four bits of the
00990 word, or the four most significant bits of the second byte are flags,
00991 while the low twelve bits are either a texture index or a 4.4.4 RGB
00992 colour. Details follow:
00993 
00994 0x4000  - if set, low twelve bits are texture index, otherwise RGB
00995 0x2000  - if set, surface should not be lit
00996 0x1000  - if set, surface colours should depend on object colour
00997 
00998 Texture indices relate to the set of 30-byte structures at D7811. These
00999 structures each contain the following:
01000 
01001 struct TextureData
01002 {
01003 long rawTextureIndex;           ; Index into main bitmap array
01004 long numColours;                ; Usually 7
01005 char pColors[7*3];              ; RGB, only uses 3 bits per byte
01006 char filler = 0;                ; Rounds structure to 30 bytes
01007 };
01008 
01009 Colour operations are all additive (not even lookup table) and truncated
01010 to 4 bits per channel, which is very low precision. This limit is
01011 largely a result of the RGB->dynamic palette conversion routines which
01012 can only handle 4 bits per channel at any speed.
01013 
01014 Example material words:
01015 
01016 0x20f0  - Bright green surface unmodified by light or object colour
01017 0x0707  - Purple surface modified by light but not object colour
01018 0x5009  - Textured surface, index 9, modified by light and object colour
01019 */