/[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 898 - (show annotations)
Sat Sep 29 18:40:02 2012 UTC (7 years, 4 months ago) by dbug
File size: 17186 byte(s)
Fixed some issues on Visual Studio introduced by the posixification...
1
2 #define _CRT_SECURE_NO_WARNINGS
3
4 #include <assert.h>
5 #include <string.h>
6 #include <stdio.h>
7 #include <io.h>
8
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 #include "FreeImage.h"
22
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 write(handle,clut,32);
184 }
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 if (m_blockmode!=BLOCKMODE_DISABLED)
311 {
312 std::cout << "-b1 (block mode) not supported on this machine";
313 return false;
314 }
315
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 write(handle,&x,2);
658 write(handle,&y,2);
659 }
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 write(handle,(unsigned char*)m_buffer,GetBufferSize());
693 }
694

  ViewVC Help
Powered by ViewVC 1.1.26