/[projet1]/public/pc/tools/osdk/main/pictconv/sources/atari_converter.cpp
Defence Force logotype

Contents of /public/pc/tools/osdk/main/pictconv/sources/atari_converter.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 899 - (show annotations)
Sat Sep 29 18:43:44 2012 UTC (7 years, 1 month ago) by dbug
File size: 17169 byte(s)
Fixed an unfortunate <io.h>
1
2 #define _CRT_SECURE_NO_WARNINGS
3
4 #include <assert.h>
5 #include <string.h>
6 #include <stdio.h>
7
8 #include <iostream>
9
10 #include "common.h"
11
12 #include "defines.h"
13 #include "getpixel.h"
14
15 #include "atari_converter.h"
16 #include "shifter_color.h"
17
18 #include "image.h"
19
20 #include "FreeImage.h"
21
22 //#define ENABLE_PALETTE_TRACKING
23
24
25 // ============================================================================
26 //
27 // AtariClut
28 //
29 // ============================================================================
30
31 int AtariClut::convert_pixel_shifter(const ShifterColor& color)
32 {
33 assert(m_clut_index_to_color.size()==m_clut_color_to_index.size());
34 std::map<ShifterColor,int>::iterator it=m_clut_color_to_index.find(color);
35 if (it==m_clut_color_to_index.end())
36 {
37 // Not found - need to search the first free slot...
38 //int index=m_clut_color_to_index.size();
39 for (int index=0;index<16;index++)
40 {
41 std::map<int,ShifterColor>::iterator it=m_clut_index_to_color.find(index);
42 if (it==m_clut_index_to_color.end())
43 {
44 //assert(index<16);
45 m_clut_color_to_index[color]=index;
46 m_clut_index_to_color[index]=color;
47 assert(m_clut_color_to_index[m_clut_index_to_color[index]]==index);
48 assert(m_clut_index_to_color[m_clut_color_to_index[color]]==color);
49 assert(m_clut_index_to_color.size()==m_clut_color_to_index.size());
50 return index;
51 }
52 }
53 // Color not found, we have a problem... like we have more than 16 colors Oo
54 assert(0);
55 return 0; // assert ?
56 }
57 else
58 {
59 // Return existing index
60 return it->second;
61 }
62 }
63
64 int AtariClut::convert_pixel_shifter(const RgbColor& rgb)
65 {
66 ShifterColor color(rgb);
67 return convert_pixel_shifter(color);
68 }
69
70 void AtariClut::SetColor(const ShifterColor& color,int index)
71 {
72 assert(index<16);
73
74 m_clut_color_to_index[color]=index;
75 m_clut_index_to_color[index]=color;
76 }
77
78 void AtariClut::SetColor(const RgbColor& rgb,int index)
79 {
80 ShifterColor color(rgb);
81 SetColor(color,index);
82 }
83
84
85
86 // The idea is to reorder the colors in a way that limits the differences
87 // from one clut to another. An obvious fix is to make the identical colors
88 // stay on the same index.
89 void AtariClut::Reorder(AtariClut& baseClut)
90 {
91 #if 1
92 AtariClut newClut;
93
94 // Code that computes the error between colors and choose the closest one
95 std::map<int,ShifterColor>::iterator it=baseClut.m_clut_index_to_color.begin();
96 while (it!=baseClut.m_clut_index_to_color.end())
97 {
98 ShifterColor baseColor=it->second;
99
100 std::map<int,ShifterColor>::iterator foundIt=m_clut_index_to_color.end();
101 int foundDifference=0;
102
103 std::map<int,ShifterColor>::iterator searchIt=m_clut_index_to_color.begin();
104 while (searchIt!=m_clut_index_to_color.end())
105 {
106 ShifterColor searchColor=searchIt->second;
107
108 int difference=baseColor.ComputeDifference(searchColor);
109 if ((foundIt==m_clut_index_to_color.end()) || (difference<=foundDifference))
110 {
111 foundIt =searchIt;
112 foundDifference =difference;
113 }
114 ++searchIt;
115 }
116
117 if (foundIt!=m_clut_index_to_color.end())
118 {
119 // Found a match
120 ShifterColor foundColor=foundIt->second;
121 newClut.convert_pixel_shifter(foundColor);
122
123 std::map<ShifterColor,int>::iterator deleteIt=m_clut_color_to_index.find(foundColor);
124 assert(deleteIt!=m_clut_color_to_index.end());
125
126 m_clut_index_to_color.erase(foundIt);
127 m_clut_color_to_index.erase(deleteIt);
128 }
129
130 ++it;
131 }
132 m_clut_index_to_color.swap(newClut.m_clut_index_to_color);
133 m_clut_color_to_index.swap(newClut.m_clut_color_to_index);
134 #else
135 // Code that performs exact match
136 std::map<ShifterColor,int>::iterator it=baseClut.m_clut_color_to_index.begin();
137 while (it!=baseClut.m_clut_color_to_index.end())
138 {
139 ShifterColor baseColor=(*it).first;
140 int baseIndex=(*it).second;
141
142 std::map<ShifterColor,int>::iterator findIt=m_clut_color_to_index.find(baseColor);
143 if (findIt!=m_clut_color_to_index.end())
144 {
145 // Found a match
146 int foundIndex=findIt->second;
147 if (foundIndex!=baseIndex)
148 {
149 // Different indexes in the palette, we need to swap
150 ShifterColor swappedColor=m_clut_index_to_color[baseIndex];
151 m_clut_index_to_color[foundIndex]=swappedColor;
152 m_clut_color_to_index[swappedColor] =foundIndex;
153
154 m_clut_index_to_color[baseIndex]=baseColor;
155 m_clut_color_to_index[baseColor]=baseIndex;
156 }
157 }
158 ++it;
159 }
160 #endif
161 }
162
163 void AtariClut::SaveClut(long handle) const
164 {
165 unsigned short clut[16];
166 memset(clut,0,sizeof(clut));
167
168 assert(m_clut_color_to_index.size()<=16);
169 std::map<ShifterColor,int>::const_iterator it=m_clut_color_to_index.begin();
170 while (it!=m_clut_color_to_index.end())
171 {
172 int index=it->second;
173 assert(index<16);
174 const ShifterColor& color=it->first;
175 if (index<16)
176 {
177 // Atari ST is a big endian machine
178 clut[index]=color.GetBigEndianValue();
179 }
180 ++it;
181 }
182 write(handle,clut,32);
183 }
184
185
186 void AtariClut::SaveClutAsText(std::string& text) const
187 {
188 unsigned short clut[16];
189 memset(clut,0,sizeof(clut));
190
191 assert(m_clut_color_to_index.size()<=16);
192 std::map<ShifterColor,int>::const_iterator it=m_clut_color_to_index.begin();
193 while (it!=m_clut_color_to_index.end())
194 {
195 int index=it->second;
196 assert(index<16);
197 const ShifterColor& color=it->first;
198 if (index<16)
199 {
200 clut[index]=color.GetValue();
201 }
202 ++it;
203 }
204
205 char buffer[64];
206 for (int index=0;index<16;index++)
207 {
208 if (index!=0)
209 {
210 text+=",";
211 }
212 sprintf(buffer,"$%04x",clut[index]);
213 text+=buffer;
214 }
215 }
216
217
218 void AtariClut::GetColors(std::vector<RGBQUAD>& colors) const
219 {
220 const std::map<ShifterColor,int>& reservedColor=m_clut_color_to_index;
221 assert(m_clut_color_to_index.size()==m_clut_index_to_color.size());
222
223 unsigned int color_count=reservedColor.size();
224 if (color_count)
225 {
226 colors.resize(color_count);
227
228 std::vector<RGBQUAD>::iterator itDest=colors.begin();
229 std::map<ShifterColor,int>::const_iterator itSource=reservedColor.begin();
230 while (itSource!=reservedColor.end())
231 {
232 const ShifterColor& sourceColor=itSource->first;
233 RgbColor rgbColor=sourceColor.GetRgb();
234
235 RGBQUAD& destColor=*itDest;
236 destColor.rgbRed =rgbColor.m_red;
237 destColor.rgbGreen =rgbColor.m_green;
238 destColor.rgbBlue =rgbColor.m_blue;
239
240 ++itSource;
241 ++itDest;
242 }
243 }
244 }
245
246
247 // ============================================================================
248 //
249 // AtariPictureConverter
250 //
251 // ============================================================================
252
253 AtariPictureConverter::AtariPictureConverter() :
254 PictureConverter(MACHINE_ATARIST),
255 m_format(FORMAT_SINGLE_PALETTE),
256 m_palette_mode(PALETTE_AUTOMATIC),
257 m_buffer(0)
258 {
259 set_buffer_size(320,200); // Default size
260
261 clear_screen();
262 }
263
264 AtariPictureConverter::~AtariPictureConverter()
265 {
266 delete[] m_buffer;
267 }
268
269
270 void AtariPictureConverter::set_buffer_size(int width,int height)
271 {
272 m_buffer_width =width;
273 m_buffer_height =height;
274 m_buffer_cols =((width+15)/16)*2*4; // *wordsize*bitplanscount
275 m_buffer_size=m_buffer_height*m_buffer_cols;
276
277 delete[] m_buffer;
278 m_buffer=new unsigned char[m_buffer_size];
279 }
280
281
282
283 void AtariPictureConverter::clear_screen()
284 {
285 for (unsigned int i=0;i<m_buffer_size;i++)
286 {
287 m_buffer[i]=0;
288 }
289 }
290
291
292 bool AtariPictureConverter::Convert(const ImageContainer& sourcePicture)
293 {
294 ImageContainer convertedPicture(sourcePicture);
295
296 #ifdef ENABLE_PALETTE_TRACKING
297 {
298 // ------- debug start
299 std::string clutAsText;
300 AtariClut& clut=GetClut(0);
301 clut.SaveClutAsText(clutAsText);
302 clutAsText+="\r\n";
303 std::cout << "AtariPictureConverter::Convert:" << clutAsText;
304 // ------- debug end
305 }
306 std::cout << "AtariPictureConverter::Convert:PaletteMode" << m_palette_mode << "\r\n";
307 #endif
308
309 if (m_blockmode!=BLOCKMODE_DISABLED)
310 {
311 std::cout << "-b1 (block mode) not supported on this machine";
312 return false;
313 }
314
315 if (m_format==FORMAT_SINGLE_PALETTE)
316 {
317 m_flagPalettePerScanline=false;
318 if (m_palette_mode==PALETTE_FROM_LAST_PIXELS)
319 {
320 // Can's use this mode if only one palette should be exported
321 std::cout << "-p2 (Last pixels of each line of the picture contains the palette) requires -f1 (Multi palette format)";
322 return false;
323 }
324 }
325 else
326 {
327 m_flagPalettePerScanline=true;
328 }
329
330 switch (m_palette_mode)
331 {
332 case PALETTE_AUTOMATIC:
333 // Nothing to do
334 break;
335
336 case PALETTE_FROM_LAST_LINE:
337 {
338 // Cut the first line, and extract the palette
339 ImageContainer lockedPalette;
340 if (!lockedPalette.CreateFromImage(convertedPicture,0,convertedPicture.GetHeight()-2,convertedPicture.GetWidth(),2))
341 {
342 return false;
343 }
344
345 if (!convertedPicture.CreateFromImage(convertedPicture,0,0,convertedPicture.GetWidth(),convertedPicture.GetHeight()-2))
346 {
347 return false;
348 }
349
350 unsigned int clut_start=0;
351 unsigned int clut_end=1;
352 if (m_format==FORMAT_MULTIPLE_PALETTE)
353 {
354 clut_end=convertedPicture.GetHeight();
355 }
356
357 RgbColor ignoreColor=lockedPalette.ReadColor(0,0);
358 for (unsigned int index=0;index<16;index++)
359 {
360 RgbColor rgbColor=lockedPalette.ReadColor(index,1);
361 if (rgbColor!=ignoreColor)
362 {
363 // This color should be locked for this index
364 for (unsigned int line=clut_start;line<clut_end;line++)
365 {
366 AtariClut& clut=GetClut(line);
367 clut.SetColor(rgbColor,index);
368 }
369 }
370 }
371
372 }
373 break;
374
375 case PALETTE_FROM_LAST_PIXELS:
376 {
377 // Cut the first 16 pixels on the left, and extract the palette for each
378 ImageContainer lockedPalette;
379 if (!lockedPalette.CreateFromImage(convertedPicture,convertedPicture.GetWidth()-17,0,17,convertedPicture.GetHeight()))
380 {
381 return false;
382 }
383
384 if (!convertedPicture.CreateFromImage(convertedPicture,0,0,convertedPicture.GetWidth()-17,convertedPicture.GetHeight()))
385 {
386 return false;
387 }
388
389 for (unsigned int line=0;line<lockedPalette.GetHeight();line++)
390 {
391 AtariClut& clut=GetClut(line);
392 RgbColor ignoreColor=lockedPalette.ReadColor(0,0);
393 for (unsigned int index=0;index<16;index++)
394 {
395 RgbColor rgbColor=lockedPalette.ReadColor(1+index,line);
396 if (rgbColor!=ignoreColor)
397 {
398 // This color should be locked for this index
399 clut.SetColor(rgbColor,index);
400 #ifdef ENABLE_PALETTE_TRACKING
401 if (line==0)
402 {
403 std::cout << "AtariPictureConverter::SetColor:" << (int)rgbColor.m_red << (int)rgbColor.m_green << (int)rgbColor.m_blue << "/" << index << "\r\n";
404 }
405 #endif
406 }
407 }
408 #ifdef ENABLE_PALETTE_TRACKING
409
410 {
411 // ------- debug start
412 std::string clutAsText;
413 //AtariClut& clut=GetClut(0);
414 clut.SaveClutAsText(clutAsText);
415 clutAsText+="\r\n";
416 std::cout << "AtariPictureConverter::ConvertLoopForLine:" << line << "=" << clutAsText;
417 // ------- debug end
418 }
419 #endif
420 //_BREAK_IF_((line==5));
421 }
422 }
423 break;
424 }
425
426
427 #ifdef ENABLE_PALETTE_TRACKING
428 {
429 // ------- debug start
430 std::string clutAsText;
431 AtariClut& clut=GetClut(0);
432 clut.SaveClutAsText(clutAsText);
433 clutAsText+="\r\n";
434 std::cout << "AtariPictureConverter::Convert:" << clutAsText;
435 // ------- debug end
436 }
437 #endif
438
439 set_buffer_size(convertedPicture.GetWidth(),convertedPicture.GetHeight());
440
441 clear_screen();
442
443 switch (m_format)
444 {
445 case FORMAT_SINGLE_PALETTE:
446 convertedPicture.ReduceColorDepth(&GetClut(0));
447 convert_shifter(convertedPicture);
448 break;
449
450 case FORMAT_MULTIPLE_PALETTE:
451 m_flagPalettePerScanline=true;
452 convertedPicture.ReduceColorDepthPerScanline(&m_cluts);
453 convert_shifter(convertedPicture);
454 break;
455
456 default:
457 // Oops
458 return false;
459 break;
460 }
461 return true;
462 }
463
464
465 AtariClut& AtariPictureConverter::GetClut(unsigned int scanline)
466 {
467 if (m_flagPalettePerScanline) return m_cluts[scanline];
468 else return m_cluts[0];
469 }
470
471
472 void AtariPictureConverter::convert_shifter(const ImageContainer& sourcePicture)
473 {
474 //
475 // Perform the Atari ST bitplan conversion
476 // We proceed in three phases for the multi palette pictures, because we want the
477 // colors to stay about the same between one line and another, to avoid horrible
478 // color glitches when moving the pictures horizontally.
479
480 #ifdef ENABLE_PALETTE_TRACKING
481 // ------- debug start
482 std::string clutAsText;
483 AtariClut& clut=GetClut(0);
484 clut.SaveClutAsText(clutAsText);
485 clutAsText+="\r\n";
486 std::cout << "AtariPictureConverter::convert_shifter(start):" << clutAsText;
487 // ------- debug end
488 #endif
489 if (m_flagPalettePerScanline)
490 {
491 // Phase one: Collect palettes
492 {
493 for (unsigned int y=0;y<m_buffer_height;y++)
494 {
495 AtariClut& clut=GetClut(y);
496
497 for (unsigned int x=0;x<m_buffer_width;x++)
498 {
499 //_BREAK_IF_((y==5) && (x==565));
500 RgbColor rgb=sourcePicture.ReadColor(x,y);
501 clut.convert_pixel_shifter(rgb);
502 }
503 }
504 }
505
506 // Phase two: Optimize the palette
507 {
508 /*
509 for (unsigned int y=0;y<m_buffer_height-1;y++)
510 {
511 AtariClut& clut1=GetClut(y);
512 AtariClut& clut2=GetClut(y+1);
513 clut2.Reorder(clut1);
514 }
515 */
516 }
517 }
518
519
520 // Phase three: Generate the atari format bitplan
521 {
522 unsigned char *ptr_hires=(unsigned char*)m_buffer;
523 for (unsigned int y=0;y<m_buffer_height;y++)
524 {
525 //_BREAK_IF_(y==110);
526
527 AtariClut& clut=GetClut(y);
528
529 unsigned int x=0;
530 while (x<m_buffer_width)
531 {
532 unsigned int p0=0;
533 unsigned int p1=0;
534 unsigned int p2=0;
535 unsigned int p3=0;
536
537 for (int bit=0;bit<16;bit++)
538 {
539 p0<<=1;
540 p1<<=1;
541 p2<<=1;
542 p3<<=1;
543 RgbColor rgb=sourcePicture.ReadColor(x,y);
544 int color=clut.convert_pixel_shifter(rgb);
545 if (color&1)
546 {
547 p0|=1;
548 }
549 if (color&2)
550 {
551 p1|=1;
552 }
553 if (color&4)
554 {
555 p2|=1;
556 }
557 if (color&8)
558 {
559 p3|=1;
560 }
561 x++;
562 }
563 *ptr_hires++=static_cast<unsigned char>((p0>>8)&255);
564 *ptr_hires++=static_cast<unsigned char>(p0&255);
565 *ptr_hires++=static_cast<unsigned char>((p1>>8)&255);
566 *ptr_hires++=static_cast<unsigned char>(p1&255);
567 *ptr_hires++=static_cast<unsigned char>((p2>>8)&255);
568 *ptr_hires++=static_cast<unsigned char>(p2&255);
569 *ptr_hires++=static_cast<unsigned char>((p3>>8)&255);
570 *ptr_hires++=static_cast<unsigned char>(p3&255);
571 }
572 }
573 }
574
575 #ifdef ENABLE_PALETTE_TRACKING
576 {
577 // ------- debug start
578 std::string clutAsText;
579 AtariClut& clut=GetClut(0);
580 clut.SaveClutAsText(clutAsText);
581 clutAsText+="\r\n";
582 std::cout << "AtariPictureConverter::convert_shifter(end):" << clutAsText;
583 // ------- debug end
584 }
585 #endif
586 }
587
588
589 bool AtariPictureConverter::TakeSnapShot(ImageContainer& sourcePicture)
590 {
591 if (!sourcePicture.Allocate(m_buffer_width,m_buffer_height,24))
592 {
593 return false;
594 }
595
596 #ifdef ENABLE_PALETTE_TRACKING
597 {
598 // ------- debug start
599 std::string clutAsText;
600 AtariClut& clut=GetClut(0);
601 clut.SaveClutAsText(clutAsText);
602 clutAsText+="\r\n";
603 std::cout << "AtariPictureConverter::TakeSnapShot:" << clutAsText;
604 // ------- debug end
605 }
606 #endif
607
608 unsigned short* pShort=(unsigned short*)m_buffer;
609 for (unsigned int y=0;y<m_buffer_height;y++)
610 {
611 AtariClut& clut=GetClut(y);
612
613 for (unsigned int x=0;x<m_buffer_width;x+=16)
614 {
615 unsigned short p0=*pShort++;
616 unsigned short p1=*pShort++;
617 unsigned short p2=*pShort++;
618 unsigned short p3=*pShort++;
619
620 p0=((p0&255)<<8) | (p0>>8);
621 p1=((p1&255)<<8) | (p1>>8);
622 p2=((p2&255)<<8) | (p2>>8);
623 p3=((p3&255)<<8) | (p3>>8);
624
625 for (int xx=0;xx<16;xx++)
626 {
627 int index=(p0&1) | ((p1&1)<<1) | ((p2&1)<<2) | ((p3&1)<<3);
628
629 ShifterColor shifterColor=clut.m_clut_index_to_color[index];
630
631 RgbColor rgb(shifterColor.GetRgb());
632
633 sourcePicture.WriteColor(rgb,x+15-xx,y);
634
635 p0>>=1;
636 p1>>=1;
637 p2>>=1;
638 p3>>=1;
639 }
640 }
641 }
642 return true;
643 }
644
645
646
647 void AtariPictureConverter::SaveToFile(long handle,int output_format)
648 {
649 switch (output_format)
650 {
651 case DEVICE_FORMAT_RAWBUFFER_WITH_XYHEADER:
652 {
653 unsigned short x=static_cast<unsigned short>(get_buffer_width());
654 unsigned short y=static_cast<unsigned short>(get_buffer_height());
655
656 write(handle,&x,2);
657 write(handle,&y,2);
658 }
659 break;
660
661 case DEVICE_FORMAT_RAWBUFFER_WITH_PALETTE:
662 {
663 std::string clutAsText;
664 if (m_flagPalettePerScanline)
665 {
666 assert(m_cluts.size()==get_buffer_height());
667 std::map<int,AtariClut>::iterator it=m_cluts.begin();
668 while (it!=m_cluts.end())
669 {
670 AtariClut& clut=it->second;
671 clut.SaveClut(handle);
672 clut.SaveClutAsText(clutAsText);
673 clutAsText+="\r\n";
674 ++it;
675 }
676 }
677 else
678 {
679 AtariClut& clut=m_cluts[0];
680 clut.SaveClut(handle);
681 clut.SaveClutAsText(clutAsText);
682 }
683 clutAsText+="\r\n";
684 }
685 break;
686
687 case DEVICE_FORMAT_RAWBUFFER:
688 // No header for raw
689 break;
690 }
691 write(handle,(unsigned char*)m_buffer,GetBufferSize());
692 }
693

  ViewVC Help
Powered by ViewVC 1.1.26