/[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 208 - (show annotations)
Sat Jan 23 15:55:45 2010 UTC (10 years, 2 months ago) by dbug
File size: 17021 byte(s)
Updated the OSDK codebase with the latest changed, which mostly add Atari ST support.
1
2 #define _CRT_SECURE_NO_WARNINGS
3
4 #include <assert.h>
5
6 #include <io.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
310 if (m_format==FORMAT_SINGLE_PALETTE)
311 {
312 m_flagPalettePerScanline=false;
313 if (m_palette_mode==PALETTE_FROM_LAST_PIXELS)
314 {
315 // Can's use this mode if only one palette should be exported
316 std::cout << "-p2 (Last pixels of each line of the picture contains the palette) requires -f1 (Multi palette format)";
317 return false;
318 }
319 }
320 else
321 {
322 m_flagPalettePerScanline=true;
323 }
324
325 switch (m_palette_mode)
326 {
327 case PALETTE_AUTOMATIC:
328 // Nothing to do
329 break;
330
331 case PALETTE_FROM_LAST_LINE:
332 {
333 // Cut the first line, and extract the palette
334 ImageContainer lockedPalette;
335 if (!lockedPalette.CreateFromImage(convertedPicture,0,convertedPicture.GetHeight()-2,convertedPicture.GetWidth(),2))
336 {
337 return false;
338 }
339
340 if (!convertedPicture.CreateFromImage(convertedPicture,0,0,convertedPicture.GetWidth(),convertedPicture.GetHeight()-2))
341 {
342 return false;
343 }
344
345 unsigned int clut_start=0;
346 unsigned int clut_end=1;
347 if (m_format==FORMAT_MULTIPLE_PALETTE)
348 {
349 clut_end=convertedPicture.GetHeight();
350 }
351
352 RgbColor ignoreColor=lockedPalette.ReadColor(0,0);
353 for (unsigned int index=0;index<16;index++)
354 {
355 RgbColor rgbColor=lockedPalette.ReadColor(index,1);
356 if (rgbColor!=ignoreColor)
357 {
358 // This color should be locked for this index
359 for (unsigned int line=clut_start;line<clut_end;line++)
360 {
361 AtariClut& clut=GetClut(line);
362 clut.SetColor(rgbColor,index);
363 }
364 }
365 }
366
367 }
368 break;
369
370 case PALETTE_FROM_LAST_PIXELS:
371 {
372 // Cut the first 16 pixels on the left, and extract the palette for each
373 ImageContainer lockedPalette;
374 if (!lockedPalette.CreateFromImage(convertedPicture,convertedPicture.GetWidth()-17,0,17,convertedPicture.GetHeight()))
375 {
376 return false;
377 }
378
379 if (!convertedPicture.CreateFromImage(convertedPicture,0,0,convertedPicture.GetWidth()-17,convertedPicture.GetHeight()))
380 {
381 return false;
382 }
383
384 for (unsigned int line=0;line<lockedPalette.GetHeight();line++)
385 {
386 AtariClut& clut=GetClut(line);
387 RgbColor ignoreColor=lockedPalette.ReadColor(0,0);
388 for (unsigned int index=0;index<16;index++)
389 {
390 RgbColor rgbColor=lockedPalette.ReadColor(1+index,line);
391 if (rgbColor!=ignoreColor)
392 {
393 // This color should be locked for this index
394 clut.SetColor(rgbColor,index);
395 #ifdef ENABLE_PALETTE_TRACKING
396 if (line==0)
397 {
398 std::cout << "AtariPictureConverter::SetColor:" << (int)rgbColor.m_red << (int)rgbColor.m_green << (int)rgbColor.m_blue << "/" << index << "\r\n";
399 }
400 #endif
401 }
402 }
403 #ifdef ENABLE_PALETTE_TRACKING
404
405 {
406 // ------- debug start
407 std::string clutAsText;
408 //AtariClut& clut=GetClut(0);
409 clut.SaveClutAsText(clutAsText);
410 clutAsText+="\r\n";
411 std::cout << "AtariPictureConverter::ConvertLoopForLine:" << line << "=" << clutAsText;
412 // ------- debug end
413 }
414 #endif
415 //_BREAK_IF_((line==5));
416 }
417 }
418 break;
419 }
420
421
422 #ifdef ENABLE_PALETTE_TRACKING
423 {
424 // ------- debug start
425 std::string clutAsText;
426 AtariClut& clut=GetClut(0);
427 clut.SaveClutAsText(clutAsText);
428 clutAsText+="\r\n";
429 std::cout << "AtariPictureConverter::Convert:" << clutAsText;
430 // ------- debug end
431 }
432 #endif
433
434 set_buffer_size(convertedPicture.GetWidth(),convertedPicture.GetHeight());
435
436 clear_screen();
437
438 switch (m_format)
439 {
440 case FORMAT_SINGLE_PALETTE:
441 convertedPicture.ReduceColorDepth(&GetClut(0));
442 convert_shifter(convertedPicture);
443 break;
444
445 case FORMAT_MULTIPLE_PALETTE:
446 m_flagPalettePerScanline=true;
447 convertedPicture.ReduceColorDepthPerScanline(&m_cluts);
448 convert_shifter(convertedPicture);
449 break;
450
451 default:
452 // Oops
453 return false;
454 break;
455 }
456 return true;
457 }
458
459
460 AtariClut& AtariPictureConverter::GetClut(unsigned int scanline)
461 {
462 if (m_flagPalettePerScanline) return m_cluts[scanline];
463 else return m_cluts[0];
464 }
465
466
467 void AtariPictureConverter::convert_shifter(const ImageContainer& sourcePicture)
468 {
469 //
470 // Perform the Atari ST bitplan conversion
471 // We proceed in three phases for the multi palette pictures, because we want the
472 // colors to stay about the same between one line and another, to avoid horrible
473 // color glitches when moving the pictures horizontally.
474
475 #ifdef ENABLE_PALETTE_TRACKING
476 // ------- debug start
477 std::string clutAsText;
478 AtariClut& clut=GetClut(0);
479 clut.SaveClutAsText(clutAsText);
480 clutAsText+="\r\n";
481 std::cout << "AtariPictureConverter::convert_shifter(start):" << clutAsText;
482 // ------- debug end
483 #endif
484 if (m_flagPalettePerScanline)
485 {
486 // Phase one: Collect palettes
487 {
488 for (unsigned int y=0;y<m_buffer_height;y++)
489 {
490 AtariClut& clut=GetClut(y);
491
492 for (unsigned int x=0;x<m_buffer_width;x++)
493 {
494 //_BREAK_IF_((y==5) && (x==565));
495 RgbColor rgb=sourcePicture.ReadColor(x,y);
496 clut.convert_pixel_shifter(rgb);
497 }
498 }
499 }
500
501 // Phase two: Optimize the palette
502 {
503 /*
504 for (unsigned int y=0;y<m_buffer_height-1;y++)
505 {
506 AtariClut& clut1=GetClut(y);
507 AtariClut& clut2=GetClut(y+1);
508 clut2.Reorder(clut1);
509 }
510 */
511 }
512 }
513
514
515 // Phase three: Generate the atari format bitplan
516 {
517 unsigned char *ptr_hires=(unsigned char*)m_buffer;
518 for (unsigned int y=0;y<m_buffer_height;y++)
519 {
520 //_BREAK_IF_(y==110);
521
522 AtariClut& clut=GetClut(y);
523
524 unsigned int x=0;
525 while (x<m_buffer_width)
526 {
527 unsigned int p0=0;
528 unsigned int p1=0;
529 unsigned int p2=0;
530 unsigned int p3=0;
531
532 for (int bit=0;bit<16;bit++)
533 {
534 p0<<=1;
535 p1<<=1;
536 p2<<=1;
537 p3<<=1;
538 RgbColor rgb=sourcePicture.ReadColor(x,y);
539 int color=clut.convert_pixel_shifter(rgb);
540 if (color&1)
541 {
542 p0|=1;
543 }
544 if (color&2)
545 {
546 p1|=1;
547 }
548 if (color&4)
549 {
550 p2|=1;
551 }
552 if (color&8)
553 {
554 p3|=1;
555 }
556 x++;
557 }
558 *ptr_hires++=static_cast<unsigned char>((p0>>8)&255);
559 *ptr_hires++=static_cast<unsigned char>(p0&255);
560 *ptr_hires++=static_cast<unsigned char>((p1>>8)&255);
561 *ptr_hires++=static_cast<unsigned char>(p1&255);
562 *ptr_hires++=static_cast<unsigned char>((p2>>8)&255);
563 *ptr_hires++=static_cast<unsigned char>(p2&255);
564 *ptr_hires++=static_cast<unsigned char>((p3>>8)&255);
565 *ptr_hires++=static_cast<unsigned char>(p3&255);
566 }
567 }
568 }
569
570 #ifdef ENABLE_PALETTE_TRACKING
571 {
572 // ------- debug start
573 std::string clutAsText;
574 AtariClut& clut=GetClut(0);
575 clut.SaveClutAsText(clutAsText);
576 clutAsText+="\r\n";
577 std::cout << "AtariPictureConverter::convert_shifter(end):" << clutAsText;
578 // ------- debug end
579 }
580 #endif
581 }
582
583
584 bool AtariPictureConverter::TakeSnapShot(ImageContainer& sourcePicture)
585 {
586 if (!sourcePicture.Allocate(m_buffer_width,m_buffer_height,24))
587 {
588 return false;
589 }
590
591 #ifdef ENABLE_PALETTE_TRACKING
592 {
593 // ------- debug start
594 std::string clutAsText;
595 AtariClut& clut=GetClut(0);
596 clut.SaveClutAsText(clutAsText);
597 clutAsText+="\r\n";
598 std::cout << "AtariPictureConverter::TakeSnapShot:" << clutAsText;
599 // ------- debug end
600 }
601 #endif
602
603 unsigned short* pShort=(unsigned short*)m_buffer;
604 for (unsigned int y=0;y<m_buffer_height;y++)
605 {
606 AtariClut& clut=GetClut(y);
607
608 for (unsigned int x=0;x<m_buffer_width;x+=16)
609 {
610 unsigned short p0=*pShort++;
611 unsigned short p1=*pShort++;
612 unsigned short p2=*pShort++;
613 unsigned short p3=*pShort++;
614
615 p0=((p0&255)<<8) | (p0>>8);
616 p1=((p1&255)<<8) | (p1>>8);
617 p2=((p2&255)<<8) | (p2>>8);
618 p3=((p3&255)<<8) | (p3>>8);
619
620 for (int xx=0;xx<16;xx++)
621 {
622 int index=(p0&1) | ((p1&1)<<1) | ((p2&1)<<2) | ((p3&1)<<3);
623
624 ShifterColor shifterColor=clut.m_clut_index_to_color[index];
625
626 RgbColor rgb(shifterColor.GetRgb());
627
628 sourcePicture.WriteColor(rgb,x+15-xx,y);
629
630 p0>>=1;
631 p1>>=1;
632 p2>>=1;
633 p3>>=1;
634 }
635 }
636 }
637 return true;
638 }
639
640
641
642 void AtariPictureConverter::SaveToFile(long handle,int output_format)
643 {
644 switch (output_format)
645 {
646 case DEVICE_FORMAT_RAWBUFFER_WITH_XYHEADER:
647 {
648 unsigned short x=static_cast<unsigned short>(get_buffer_width());
649 unsigned short y=static_cast<unsigned short>(get_buffer_height());
650
651 _write(handle,&x,2);
652 _write(handle,&y,2);
653 }
654 break;
655
656 case DEVICE_FORMAT_RAWBUFFER_WITH_PALETTE:
657 {
658 std::string clutAsText;
659 if (m_flagPalettePerScanline)
660 {
661 assert(m_cluts.size()==get_buffer_height());
662 std::map<int,AtariClut>::iterator it=m_cluts.begin();
663 while (it!=m_cluts.end())
664 {
665 AtariClut& clut=it->second;
666 clut.SaveClut(handle);
667 clut.SaveClutAsText(clutAsText);
668 clutAsText+="\r\n";
669 ++it;
670 }
671 }
672 else
673 {
674 AtariClut& clut=m_cluts[0];
675 clut.SaveClut(handle);
676 clut.SaveClutAsText(clutAsText);
677 }
678 clutAsText+="\r\n";
679 }
680 break;
681
682 case DEVICE_FORMAT_RAWBUFFER:
683 // No header for raw
684 break;
685 }
686 _write(handle,(unsigned char*)m_buffer,GetBufferSize());
687 }
688

  ViewVC Help
Powered by ViewVC 1.1.26