root/simulator/trunk/src/utilities/msts2blender/mstsace.cpp

Revision 1317, 20.2 kB (checked in by sehenley, 10 months ago)

Documentation

  • Property WBS set to 1.3.4.2.1
  • Property svn:keywords set to
    Url
    Rev
    Author
    Date
    Id
Line 
1 //    OSRail -- a network enabled railroad operations simulator and utilities
2 //    Copyright (C) 2007,2008 Samuel E. Henley sehenley@comcast.net
3 //
4 //    This program is free software; you can redistribute it and/or modify
5 //    it under the terms of the GNU General Public License as published by
6 //    the Free Software Foundation; either version 2 of the License, or
7 //    (at your option) any later version.
8 //
9 //    This program is distributed in the hope that it will be useful,
10 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //    GNU General Public License for more details.
13 //
14 //    You should have received a copy of the GNU General Public License along
15 //    with this program; if not, write to the Free Software Foundation, Inc.,
16 //    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 //
18 //
19 #include "premsts2blender.h"
20
21 #include "mstsace.h"
22
23 /// \addtogroup tools "Conversion Tools and Utilities"
24 /// @{
25     /// \addtogroup msts2blender "Msts2Blender Conversion Utility"
26     /// @{
27
28 namespace mstsace
29 {
30
31     // Context
32     Context::Context() : type(UNKNOWN), compressed(false), width(0), height(0),
33                     file_size(0), uncompressed_size(0) {}
34
35     Context::~Context()
36     {
37         for( size_t i = 0; i<images.size(); i++ )delete images[i];
38         images.clear();
39     }
40
41     #ifdef DUMP_ACE_HEADER
42         // Debug
43         /// Used to test ace format - 512x512 square with a red, blue, green and black square line, filled with gray.
44         static void dumpace( Context& context )
45         {
46             std::vector<char> buffer;
47             buffer.resize( 65536 );
48
49             DUMP( "Msts2Blender", context.path.c_str(), "%s", context.path.c_str() );
50             ace* header = reinterpret_cast<ace*>( context.top );
51             unsigned char* start = reinterpret_cast<unsigned char*>(header);
52             unsigned char* p = context.top;
53             DUMP( "Msts2Blender", context.path, "%6.6d %8.8x unknown_1 %d", p - start, p, header->unknown_1 );
54             p += sizeof( int );
55             DUMP( "Msts2Blender", context.path, "%6.6d %8.8x flags %d", p - start, p, header->unknown_2 );
56             p += sizeof( int );
57             DUMP( "Msts2Blender", context.path, "%6.6d %8.8x width %d", p - start, p, header->width );
58             p += sizeof( int );
59             DUMP( "Msts2Blender", context.path, "%6.6d %8.8x height %d", p - start, p, header->height );
60             p += sizeof( int );
61             DUMP( "Msts2Blender", context.path, "%6.6d %8.8x type %d", p - start, p, header->type );
62             p += sizeof( int );
63             DUMP( "Msts2Blender", context.path, "%6.6d %8.8x channels %d", p - start, p, header->channels );
64             p += sizeof( int );
65             DUMP( "Msts2Blender", context.path, "%6.6d %8.8x unknown_4 %d", p - start, p, header->unknown_4 );
66             p += sizeof( int );
67             DUMP( "Msts2Blender", context.path, "%6.6d %8.8x name %16s", p - start, p, header->name );
68             p += 16;
69             DUMP( "Msts2Blender", context.path, "%6.6d %8.8x copyright %72s", p - start, p, header->copyright );
70             p += 72;
71             DUMP( "Msts2Blender", context.path, "%6.6d %8.8x unknown_5 %d", p - start, p, header->unknown_5 );
72             p += sizeof( int );
73             DUMP( "Msts2Blender", context.path, "" );
74
75             unsigned char* q = p;
76
77             switch( context.type )
78             {
79             case UNKNOWN :
80                 DUMP( "Msts2Blender", context.path, "Unknown ace format found" );
81                 p = context.top + 512; //temp
82                 break;
83             case RGBA8 :
84                 DUMP( "Msts2Blender", "Msts2Blender", context.path, "24 bit 8 alpha ace format found" );
85                 p = context.top + 232;
86                 break;
87             case RGBA1 :
88                 DUMP( "Msts2Blender", context.path, "24 bit 1 alpha ace format found" );
89                 p = context.top + 216;
90                 break;
91             case RGB :
92                 DUMP( "Msts2Blender", context.path, "24 bit no-alpha ace format found" );
93                 p = context.top + 200;
94                 break;
95             case DXT1 :
96                 DUMP( "Msts2Blender", context.path, "dtx1 ace format found" );
97                 p = context.top + 244;
98                 break;
99             case DXT1A1 :
100                 DUMP( "Msts2Blender", context.path, "dtx1 + alph ace format found" );
101                 p = context.top + 244;
102                 break;
103             }
104
105             for( int i=0; i<256; i++ )
106             {
107                 unsigned short h = *(reinterpret_cast<unsigned short*>(q));
108                 DUMP( "Msts2Blender", context.path, "%6.6d %8.8x %4.4x %d", q - start, q, h, h );
109                 q += 2;
110             }
111
112         }
113
114     #endif //DUMP_ACE_HEADER
115
116     static void getRows( std::vector<int>& indices, Context& context )
117     {
118         indices.clear();
119         int size = context.height;
120         while( size > 0 )
121         {
122             for( int i=0; i< size; i++ )
123             {
124                 int* q = reinterpret_cast<int*>(context.stop+(i*sizeof(int)));
125                 indices.push_back( *q );
126             }
127             context.stop += (size*sizeof(int));
128             size >>= 1;
129         }
130     }
131
132
133     static void convertRGB( Context& context )
134     {
135         std::vector<int> indices;
136         getRows( indices, context );
137
138         context.images.push_back( new wxImage( context.width, context.height ) );
139
140         //assemble into wxwidgets image
141         //reassemble into a 24 bit, bitmap structure with file header
142         unsigned char* q = context.images.back()->GetData();
143         for( int k = 0; k < context.height; k++ )
144         {
145             unsigned char* r = context.top + indices[k]; //next scan line
146             unsigned char* g = r + context.width;
147             unsigned char* b = g + context.width;
148             for( int j=0; j < context.width; j++ )
149             {
150                 *q++ = *r++;
151                 *q++ = *g++;
152                 *q++ = *b++;
153             }
154         }
155     }
156
157     static void convertRGBA1( Context& context )
158     {
159         std::vector<int> indices;
160         getRows( indices, context );
161         context.images.push_back( new wxImage( context.width, context.height ) );
162         context.images[0]->SetAlpha();
163
164         //assemble into wxwidgets image
165         //reassemble into a 24 bit, bitmap structure with file header
166         unsigned char* q = context.images.back()->GetData();
167         unsigned char* p = context.images.back()->GetAlpha();
168         for( int k = 0; k < context.height; k++ )
169         {
170             unsigned char* r = context.top + indices[k]; //next scan line
171             unsigned char* g = r + context.width;
172             unsigned char* b = g + context.width;
173             unsigned char* a = b + context.width;
174
175             unsigned char index = 0x80;
176
177             for( int j=0; j < context.width; j++ )
178             {
179                 *q++ = *r++;
180                 *q++ = *g++;
181                 *q++ = *b++;
182                 if( *a & index ) *p++ = 255;
183                 else *p++ = 0;
184                 index >>= 1;
185                 if( index == 0 )
186                 {
187                     index = 0x80;
188                     a++;
189                 }
190             }
191         }
192     }
193
194     static void convertRGBA8( Context& context )
195     {
196         std::vector<int> indices;
197         getRows( indices, context );
198         context.images.push_back( new wxImage( context.width, context.height ) );
199         context.images[0]->SetAlpha();
200
201         //assemble into wxwidgets image
202         //reassemble into a 24 bit, bitmap structure with file header
203         unsigned char* q = context.images.back()->GetData();
204         unsigned char* p = context.images.back()->GetAlpha();
205         for( int k = 0; k < context.height; k++ )
206         {
207             unsigned char* r = context.top + indices[k]; //next scan line
208             unsigned char* g = r + context.width;
209             unsigned char* b = g + context.width;
210             unsigned char* a = context.top + indices[k+1] - context.width;
211
212             for( int j=0; j < context.width; j++ )
213             {
214                 *q++ = *r++;
215                 *q++ = *g++;
216                 *q++ = *b++;
217                 *p++ = *a++;
218             }
219         }
220     }
221
222     static void convertDXT1( Context& context )
223     {
224         context.images.push_back( new wxImage( context.width, context.height ) );
225         unsigned char* p = context.stop;
226         float table[4][3];  //bit,rgb
227
228         for( int i = 0; i<context.height; i +=4 )
229         {
230             for( int j = 0; j<context.width; j+=4 )
231             {
232                 mstsace::Color first = *reinterpret_cast<mstsace::Color*>(p);
233                 table[0][0] = float(first.red)/32.0f;
234                 table[0][1] = float(first.green)/64.0f;
235                 table[0][2] = float(first.blue)/32.0f;
236                 p += 2;
237                 mstsace::Color second = *reinterpret_cast<mstsace::Color*>(p);
238                 table[1][0] = float(second.red)/32.0f;
239                 table[1][1] = float(second.green)/64.0f;
240                 table[1][2] = float(second.blue)/32.0f;
241                 p += 2;
242                 Bits bits = *reinterpret_cast<Bits*>(p);
243                 p += 4;
244
245                 for( int m=0; m<3; m++ )
246                 {
247                     table[2][m] = ( 0.6666f * table[0][m] ) + ( 0.3333f * table[1][m] );
248                     table[3][m] = ( 0.3333f * table[0][m] ) + ( 0.6666f * table[1][m] );
249                 }
250
251                 unsigned char colors[4][3];
252
253                 for( int m=0; m<4; m++ )
254                     for( int k=0; k<3; k++ )
255                     {
256                         colors[m][k] = static_cast<unsigned char>( table[m][k] * 255.0f );
257                     }
258
259                 unsigned char* q = context.images.back()->GetData();
260
261                 q += ( i * context.width * 3 );
262                 q += ( j * 3 );
263
264                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b00][m] );
265                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b01][m] );
266                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b02][m] );
267                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b03][m] );
268                 q -= 12;
269                 q += context.width * 3;
270                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b10][m] );
271                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b11][m] );
272                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b12][m] );
273                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b13][m] );
274                 q -= 12;
275                 q += context.width * 3;
276                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b20][m] );
277                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b21][m] );
278                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b22][m] );
279                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b23][m] );
280                 q -= 12;
281                 q += context.width * 3;
282                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b30][m] );
283                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b31][m] );
284                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b32][m] );
285                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b33][m] );
286             }
287         }
288     }
289
290     static void convertDXT1A1( Context& context )
291     {
292         context.images.push_back( new wxImage( context.width, context.height ) );
293         unsigned char* p = context.stop;
294
295         context.images[0]->SetAlpha();
296         unsigned char* a = 0;
297
298         float table[4][3];  //color#,rgb
299
300         for( int i = 0; i<context.height; i +=4 )
301         {
302             for( int j = 0; j<context.width; j+=4 )
303             {
304                 mstsace::Color first = *reinterpret_cast<mstsace::Color*>(p);
305                 table[0][0] = float(first.red)/32.0f;
306                 table[0][1] = float(first.green)/64.0f;
307                 table[0][2] = float(first.blue)/32.0f;
308                 p += 2;
309                 mstsace::Color second = *reinterpret_cast<mstsace::Color*>(p);
310                 table[1][0] = float(second.red)/32.0f;
311                 table[1][1] = float(second.green)/64.0f;
312                 table[1][2] = float(second.blue)/32.0f;
313                 p += 2;
314                 Bits bits = *reinterpret_cast<Bits*>(p);
315                 p += 4;
316
317                 /// \note yes folks it's <= not < as the documentation on dxt1 would
318                 /// leave any normal reader of english to believe.
319                 if( first.value <= second.value ) //alpha mask
320                 {
321                     for( int m=0; m<3; m++ )
322                     {
323                         table[2][m] = ( 0.5f * table[0][m] ) + ( 0.5f * table[1][m] );
324                         table[3][m] = 1.0f;
325                     }
326
327                 }
328                 else
329                 {
330                     for( int m=0; m<3; m++ )
331                     {
332                         table[2][m] = ( 0.6666f * table[0][m] ) + ( 0.3333f * table[1][m] );
333                         table[3][m] = ( 0.3333f * table[0][m] ) + ( 0.6666f * table[1][m] );
334                     }
335                 }
336
337                 unsigned char colors[4][3];
338
339                 for( int m=0; m<4; m++ )
340                     for( int k=0; k<3; k++ )
341                     {
342                         colors[m][k] = static_cast<unsigned char>( table[m][k] * 255.0f );
343                     }
344
345
346                 unsigned char* q = context.images.back()->GetData();
347                 q += ( i * context.width * 3 );
348                 q += ( j * 3 );
349
350                 a = context.images[0]->GetAlpha();
351                 a += ( i * context.width );
352                 a += j;
353
354
355                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b00][m] );
356                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b01][m] );
357                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b02][m] );
358                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b03][m] );
359                 q -= 12;
360                 q += context.width * 3;
361                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b10][m] );
362                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b11][m] );
363                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b12][m] );
364                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b13][m] );
365                 q -= 12;
366                 q += context.width * 3;
367                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b20][m] );
368                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b21][m] );
369                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b22][m] );
370                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b23][m] );
371                 q -= 12;
372                 q += context.width * 3;
373                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b30][m] );
374                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b31][m] );
375                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b32][m] );
376                 for( int m = 0; m < 3; m++ ) *q++ = static_cast<unsigned char>( colors[bits.b33][m] );
377
378                 if( first.value <= second.value )
379                 {
380                     *a++ = bits.b00 == 3 ? 0 : 255;
381                     *a++ = bits.b01 == 3 ? 0 : 255;
382                     *a++ = bits.b02 == 3 ? 0 : 255;
383                     *a++ = bits.b03 == 3 ? 0 : 255;
384                     a -=4;
385                     a += context.width;
386                     *a++ = bits.b10 == 3 ? 0 : 255;
387                     *a++ = bits.b11 == 3 ? 0 : 255;
388                     *a++ = bits.b12 == 3 ? 0 : 255;
389                     *a++ = bits.b13 == 3 ? 0 : 255;
390                     a -=4;
391                     a += context.width;
392                     *a++ = bits.b20 == 3 ? 0 : 255;
393                     *a++ = bits.b21 == 3 ? 0 : 255;
394                     *a++ = bits.b22 == 3 ? 0 : 255;
395                     *a++ = bits.b23 == 3 ? 0 : 255;
396                     a -=4;
397                     a += context.width;
398                     *a++ = bits.b30 == 3 ? 0 : 255;
399                     *a++ = bits.b31 == 3 ? 0 : 255;
400                     *a++ = bits.b32 == 3 ? 0 : 255;
401                     *a++ = bits.b33 == 3 ? 0 : 255;
402                 }
403                 else
404                 {
405                     *a++ = 255;
406                     *a++ = 255;
407                     *a++ = 255;
408                     *a++ = 255;
409                     a -=4;
410                     a += context.width;
411                     *a++ = 255;
412                     *a++ = 255;
413                     *a++ = 255;
414                     *a++ = 255;
415                     a -=4;
416                     a += context.width;
417                     *a++ = 255;
418                     *a++ = 255;
419                     *a++ = 255;
420                     *a++ = 255;
421                     a -=4;
422                     a += context.width;
423                     *a++ = 255;
424                     *a++ = 255;
425                     *a++ = 255;
426                     *a++ = 255;
427                 }
428
429             }
430         }
431     }
432
433     void ace2Image( Context& context )
434     {
435         ace* header;
436
437         //skip msts file header, point to ace header
438         context.stop = context.top;
439
440         header = reinterpret_cast<ace*>(context.top);
441
442         if( header->unknown_1 != 1 )
443         {
444             throw unknown_1_ne_1();
445         }
446
447         if( header->unknown_2 != 5 && header->unknown_2 != 1 && header->unknown_2 != 0
448             && header->unknown_2 != 17 && header->unknown_2 != 21 ) //17, 21-dtx1
449         {
450             throw unknown_2_ne_0_or_1_or_5_or_17_or_21();
451         }
452
453         context.width  = header->width;
454         context.height = header->height;
455
456         if( header->width == 0 || header->height == 0 || header->width > 1024 || header->height > 1024 )
457         {
458             throw width_or_height_eq_0_or_gt_1024();
459         }
460
461         switch( header->type )
462         {
463         case 14 : context.type = RGB; break;
464         case 16 : context.type = RGBA1; break;
465         case 17 : context.type = RGBA8; break;
466         case 18 : context.type = DXT1; break;
467         default : throw type_ne_14_or_16_or_17_or_18();
468         };
469
470         if( context.type == DXT1 && header->channels == 4 )context.type = DXT1A1;
471
472         context.channels = header->channels;
473
474         if( header->channels != 3 && header->channels != 4 && header->channels != 5 )
475         {
476             throw channels_ne_3_or_4_or_5();
477         }
478
479         if( header->unknown_4 != 0 )
480         {
481             throw unknown_4_ne_0();
482         }
483
484         #ifdef DUMP_ACE_HEADER
485             dumpace( context ); //dump the header
486         #endif //DUMP_ACE_HEADER
487         switch( context.type )
488         {
489         case RGB   :
490             context.stop = context.top + 200;
491             convertRGB( context );
492             break;
493         case RGBA1 :
494             context.stop = context.top + 216;
495             convertRGBA1( context );
496             break;
497         case RGBA8 :
498              context.stop = context.top + 232;
499              convertRGBA8( context );
500              break;
501         case DXT1  :
502             {
503             short offset = *(reinterpret_cast<short*>( context.top + 200 ));
504             context.stop = context.top + offset + 4;
505             convertDXT1( context );
506             }
507             break;
508         case DXT1A1 :
509             {
510             short offset = *(reinterpret_cast<short*>( context.top + 216 ));
511             context.stop = context.top + offset + 4;
512             convertDXT1A1( context );
513             }
514             break;
515         default:
516            throw file_format_unknown();
517         }
518
519     }
520
521 } // namespace mstsace
522
523         /// @}   group msts2blender
524     /// @}   group tools
Note: See TracBrowser for help on using the browser.