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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 881 - (hide annotations)
Tue Sep 25 23:44:44 2012 UTC (7 years, 6 months ago) by mmu_man
File size: 17190 byte(s)
POSIXify + Fix includes

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

  ViewVC Help
Powered by ViewVC 1.1.26