Fixed more warnings.
[sdk] / ecere / src / gfx / Bitmap.ec
1 namespace gfx;
2
3 import "Display"
4
5 public class BitmapFormat
6 {
7    class_data const char ** extensions;
8
9    class_property const char ** extensions
10    {
11       get { return class_data(extensions); }
12       set { class_data(extensions) = value; }   }
13
14
15    virtual bool ::Load(Bitmap bitmap, File f);
16    virtual bool ::Save(Bitmap bitmap, const char * fileName, void * options);
17    virtual ColorAlpha * ::LoadPalette(const char * fileName, const char * type);
18 };
19
20 static const char * typesToTry[] =
21 {
22    "gif", "jpg", "png", "bmp", "pcx", "memorybmp"
23 };
24
25 #define NUM_TYPES_TO_TRY   ((int)(sizeof(typesToTry) / sizeof(char *)))
26
27 static subclass(BitmapFormat) FindFormat(const char * type)
28 {
29    subclass(BitmapFormat) format = null;
30    if(type)
31    {
32       OldLink link;
33       for(link = class(BitmapFormat).derivatives.first; link; link = link.next)
34       {
35          const char ** extensions;
36          format = link.data;
37          extensions = format.extensions;
38          if(extensions)
39          {
40             int c;
41             for(c = 0; extensions[c] && extensions[c][0]; c++)
42                if(!strcmp(extensions[c], type))
43                   break;
44             if(extensions[c] && extensions[c][0])
45                break;
46          }
47       }
48       if(!link) format = null;
49    }
50    return format;
51 }
52
53 public ColorAlpha * LoadPalette(const char * fileName, const char * type)
54 {
55    char ext[MAX_EXTENSION];
56    subclass(BitmapFormat) format = null;
57    ColorAlpha * palette = null;
58    int typeToTry = -1;
59    Bitmap bitmap { };
60
61    if(!type)
62       type = strlwr(GetExtension(fileName, ext));
63
64    if(type)
65       format = FindFormat(type);
66
67    if(!format)
68       typeToTry = 0;
69
70    for(; typeToTry < NUM_TYPES_TO_TRY; typeToTry++)
71    {
72       if(typeToTry >= 0)
73          format = FindFormat(typesToTry[typeToTry]);
74
75       if(format)
76       {
77          palette = format.LoadPalette(fileName, type);
78          if(palette)
79             break;
80       }
81       if(!palette)
82       {
83
84          if(bitmap.Load(fileName, type, null))
85          {
86             palette = bitmap.Quantize(0, 255);
87             bitmap.allocatePalette = false;
88             break;
89          }
90       }
91       if(typeToTry == -1) break;
92    }
93
94    delete bitmap;
95
96    if(!palette)
97       ; //eGraphics_LogErrorCode(GERR_LOAD_BITMAP_FAILED, fileName);
98    return palette;
99 }
100
101 static define GRANULARITY = 4;
102
103 static class QuantNode : struct
104 {
105    QuantNode prev, next;
106    QuantNode parent;
107    QuantNode nodes[2][2][2];
108    int index;
109    byte minR, maxR;
110    byte minG, maxG;
111    byte minB, maxB;
112    int n2;
113    float e;
114    float sr, sg, sb;
115    int level;
116
117    void AddColor(int r, int g, int b, OldList nodeList, int * nonZeroN2)
118    {
119       int size = maxR - minR + 1;
120       int mr = (maxR - minR) / 2;
121       int mg = (maxG - minG) / 2;
122       int mb = (maxB - minB) / 2;
123       e += ((r-mr) * (r-mr) + (g-mg) * (g-mg) + (b-mb) * (b-mb)) >> level;
124
125       if(size > GRANULARITY)
126       {
127          int ri = (r - minR) / (size >> 1);
128          int gi = (g - minG) / (size >> 1);
129          int bi = (b - minB) / (size >> 1);
130          QuantNode child = nodes[ri][gi][bi];
131          if(!child)
132          {
133             child = nodes[ri][gi][bi] = QuantNode { };
134             nodeList.Add(child);
135
136             child.level = level + 1;
137             child.parent = this;
138             child.minR = (byte)(minR + ri * (size >> 1));
139             child.maxR = (byte)(child.minR + (size >> 1) - 1);
140             child.minG = (byte)(minG + gi * (size >> 1));
141             child.maxG = (byte)(child.minG + (size >> 1) - 1);
142             child.minB = (byte)(minB + bi * (size >> 1));
143             child.maxB = (byte)(child.minB + (size >> 1) - 1);
144          }
145          child.AddColor(r, g, b, nodeList, nonZeroN2);
146       }
147       else
148       {
149          if(!n2)
150             (*nonZeroN2)++;
151          n2 ++;
152          sr += r;
153          sg += g;
154          sb += b;
155       }
156    }
157
158    void PruneNode(OldList nodeList, int * nonZeroN2)
159    {
160       int r,g,b;
161       QuantNode parent = this.parent;
162       int ri = (minR != parent.minR);
163       int gi = (minG != parent.minG);
164       int bi = (minB != parent.minB);
165
166       for(r = 0; r<2; r++)
167          for(g = 0; g<2; g++)
168             for(b = 0; b<2; b++)
169             {
170                QuantNode child = nodes[r][g][b];
171                if(child)
172                   child.PruneNode(nodeList, nonZeroN2);
173             }
174
175       this.parent.nodes[ri][gi][bi] = null;
176
177       if(n2 && parent.n2)
178          (*nonZeroN2)--;
179
180       parent.sr += sr;
181       parent.sg += sg;
182       parent.sb += sb;
183       parent.n2 += n2;
184
185       nodeList.Delete(this);
186    }
187
188    int FindColor(ColorAlpha * palette, int r, int g, int b)
189    {
190       int size = maxR - minR + 1;
191       if(size > GRANULARITY)
192       {
193          int ri = (r - minR) / (size >> 1);
194          int gi = (g - minG) / (size >> 1);
195          int bi = (b - minB) / (size >> 1);
196          QuantNode child = nodes[ri][gi][bi];
197          if(child)
198             return child.FindColor(palette, r, g, b);
199       }
200       return index;
201    }
202
203    int Compare(const QuantNode b, void * data)
204    {
205       return (e > b.e) ? -1 : (e < b.e);
206    }
207
208    void AddNodeToColorTable(ColorAlpha * palette, int * c)
209    {
210       int r, g, b;
211
212       if(n2 > 0)
213       {
214          r = (int)(sr / n2);
215          g = (int)(sg / n2);
216          b = (int)(sb / n2);
217          r = Max(Min(r,255),0);
218          g = Max(Min(g,255),0);
219          b = Max(Min(b,255),0);
220
221          palette[*c] = { 255, Color { (byte)r, (byte)g, (byte)b } };
222          index = *c;
223          (*c)++;
224       }
225
226       for(r = 0; r<2; r++)
227          for(g = 0; g<2; g++)
228             for(b = 0; b<2; b++)
229             {
230                QuantNode child = nodes[r][g][b];
231                if(child)
232                   child.AddNodeToColorTable(palette, c);
233             }
234    }
235 };
236
237 public class Bitmap
238 {
239    class_no_expansion
240    ~Bitmap()
241    {
242       Free();
243    }
244 public:
245    int width, height;
246
247    // Data representation
248    PixelFormat pixelFormat;
249    byte * picture;
250    uint stride;
251    uint size, sizeBytes;
252    ColorAlpha * palette;
253    bool allocatePalette;
254
255    // Appearance
256    bool transparent;
257    // TODO: byte shadeShift;
258    int shadeShift;
259    byte * paletteShades;
260    bool alphaBlend;
261
262    // Hidden Data
263    DisplaySystem displaySystem;
264    subclass(DisplayDriver) driver;
265    void * driverData;
266    bool keepData;
267
268 public:
269
270    /*property byte * picture { get { return picture; } set { picture = value; } };
271    property int width { get { return width; }  set { width = value; } };
272    property int height { get { return height; }  set { height = value; } };
273    property int stride { get { return stride; }  set { stride = value; } };
274    property int size { get { return size; } };
275    property ColorAlpha * palette { set { palette = value; } get { return palette; } };
276    property bool transparent { set { transparent = value; } get { return transparent; } };
277    property bool alphaBlend { set { alphaBlend = value; } get { return alphaBlend; } };
278    property byte * paletteShades { set { paletteShades = value; } get { return paletteShades; } };
279    property PixelFormat pixelFormat { get { return pixelFormat; }  set { pixelFormat = value; } };
280    property bool keepData { set { keepData = value; } get { return keepData; } };*/
281
282    Surface GetSurface(int x, int y, Box clip)
283    {
284       Surface result = null;
285       Surface surface { };
286       if(surface)
287       {
288          Box box { 0, 0, width - 1, height - 1 };
289          box.Clip(clip);
290
291          surface.width = (clip != null) ? (clip.right - clip.left + 1) : width;
292          surface.height = (clip != null) ? (clip.bottom - clip.top + 1) : height;
293          surface.driver = (driver != null) ? driver : ((subclass(DisplayDriver))class(LFBDisplayDriver));
294          surface.displaySystem = displaySystem;
295          surface.display = null; // For now... with render to textures, the texture should have a display...
296
297          if(surface.driver.GetBitmapSurface(displaySystem, surface, this, x, y, box))
298          {
299             surface.TextOpacity(false);
300             surface.SetForeground(white);
301             surface.SetBackground(black);
302             result = surface;
303          }
304          if(!result)
305             delete surface;
306       }
307       return result;
308    }
309
310    void SmoothEdges(int size)
311    {
312       Surface surface = GetSurface(0, 0, null);
313       if(surface)
314       {
315          int cx,cy;
316          int acrossX = width / size;
317          int acrossY = height / size;
318
319          for(cy = 0; cy < acrossY; cy++)
320             for(cx = 0; cx < acrossX; cx++)
321             {
322                int x,y;
323                Color in1, in2, res;
324    /*
325                Color color { GetRandom(0,255), GetRandom(0,255), GetRandom(0,255)) };
326                surface.SetForeground(color);
327                for(y = 0; y<size; y++)
328                   for(x = 0; x<size; x++)
329                      surface.PutPixel(cx * size + x, cy * size + y);
330    */
331                // Corner
332                if(cx > 0 || cy > 0)
333                {
334                   int r = 0, g = 0, b = 0, num = 0;
335                   if(cx > 0)
336                   {
337                      in1 = surface.GetPixel(cx * size - 1, cy * size);
338                      in2 = surface.GetPixel(cx * size,  cy * size);
339                      r += in1.r + in2.r;
340                      g += in1.g + in2.g;
341                      b += in1.b + in2.b;
342                      num += 2;
343                   }
344                   if(cy > 0)
345                   {
346                      in1 = surface.GetPixel(cx * size, cy * size - 1);
347                      in2 = surface.GetPixel(cx * size, cy * size);
348                      r += in1.r + in2.r;
349                      g += in1.g + in2.g;
350                      b += in1.b + in2.b;
351                      num += 2;
352                   }
353                   surface.SetForeground(Color { (byte)(r/num), (byte)(g/num), (byte)(b/num) });
354                   surface.PutPixel(cx * size, cy * size);
355                   if(cx > 0) surface.PutPixel(cx * size - 1, cy * size);
356                   if(cy > 0) surface.PutPixel(cx * size, cy * size - 1);
357                   if(cx > 0 && cy > 0) surface.PutPixel(cx * size - 1, cy * size - 1);
358                }
359
360                // Left
361                if(cx>0)
362                   for(y = 1; y<size; y++)
363                   {
364                      in1 = surface.GetPixel(cx * size - 1, cy * size + y);
365                      in2 = surface.GetPixel(cx * size,  cy * size + y);
366                      res = Color { (in1.r + in2.r) / 2, (in1.g + in2.g) / 2, (in1.b + in2.b) / 2 };
367                      surface.SetForeground(res);
368                      surface.PutPixel(cx * size - 1, cy * size + y);
369                      surface.PutPixel(cx * size, cy * size + y);
370                   }
371
372                // Top
373                if(cy>0)
374                   for(x = 1; x<size; x++)
375                   {
376                      in1 = surface.GetPixel(cx * size + x, cy * size - 1);
377                      in2 = surface.GetPixel(cx * size + x, cy * size);
378                      res = Color { (in1.r + in2.r) / 2, (in1.g + in2.g) / 2, (in1.b + in2.b) / 2 };
379                      surface.SetForeground(res);
380                      surface.PutPixel(cx * size + x, cy * size - 1);
381                      surface.PutPixel(cx * size + x, cy * size);
382                   }
383             }
384          delete surface;
385       }
386    }
387
388    // --- Bitmap conversion ---
389
390    bool Convert(DisplaySystem displaySystem, PixelFormat format, ColorAlpha * palette)
391    {
392       if(driver)
393          return driver.ConvertBitmap(displaySystem, this, format, palette);
394       return false;
395    }
396
397    bool Copy(Bitmap source)
398    {
399       bool result = false;
400       if(source)
401       {
402          // TODO: Watch out for inst stuff
403          width = source.width;
404          height = source.height;
405          pixelFormat = source.pixelFormat;
406          picture = source.picture;
407          stride = source.stride;
408          size = source.stride;
409          transparent = source.transparent;
410          shadeShift = source.shadeShift;
411          paletteShades = source.paletteShades;
412          sizeBytes = source.sizeBytes;
413          displaySystem = source.displaySystem;
414          driver = source.driver;
415          driverData = source.driverData;
416
417          picture = new byte[sizeBytes];
418          palette = source.palette;
419          allocatePalette = false;
420
421          if(picture)
422          {
423             memcpy(picture, source.picture, sizeBytes);
424             result = true;
425          }
426          else
427             memset(picture, 0, sizeBytes);
428
429          if(!result)
430             Free();
431       }
432       return result;
433    }
434
435    bool MakeDD(DisplaySystem displaySystem)
436    {
437       bool result = false;
438       if(this && displaySystem && (!driver || driver == class(LFBDisplayDriver)))
439       {
440          if(displaySystem.driver.MakeDDBitmap(displaySystem, this, false))
441          {
442             this.displaySystem = displaySystem;
443             driver = displaySystem ? displaySystem.driver : ((subclass(DisplayDriver))class(LFBDisplayDriver));
444             result = true;
445          }
446       }
447       return result;
448    }
449
450    bool MakeMipMaps(DisplaySystem displaySystem)
451    {
452       bool result = false;
453       if(this && displaySystem && (!driver || driver == class(LFBDisplayDriver)))
454       {
455          if(displaySystem.driver.MakeDDBitmap(displaySystem, this, true))
456          {
457             this.displaySystem = displaySystem;
458             result = true;
459          }
460       }
461       return result;
462    }
463
464    // --- Bitmap loading ---
465    bool LoadFromFile(File file, const char * type, DisplaySystem displaySystem)
466    {
467       bool result = false;
468       if(file)
469       {
470          subclass(BitmapFormat) format = null;
471          int typeToTry = -1;
472          uintsize pos = file.Tell();
473
474          if(type)
475             format = FindFormat(type);
476
477          if(!format)
478             typeToTry = 0;
479
480          for(; typeToTry < NUM_TYPES_TO_TRY; typeToTry++)
481          {
482             file.Seek(pos, start);
483             if(typeToTry >= 0)
484                format = FindFormat(typesToTry[typeToTry]);
485
486             if(format)
487             {
488                if((result = format.Load(this, file)))
489                {
490                   if(displaySystem)
491                   {
492                      if(!MakeDD(displaySystem))
493                      {
494                         Free();
495                         result = false;
496                      }
497                   }
498                   break;
499                }
500             }
501             if(typeToTry == -1) break;
502          }
503       }
504
505       if(!result)
506           ; // eGraphics_LogErrorCode(GERR_LOAD_BITMAP_FAILED, null);
507       return result;
508    }
509
510    bool Load(const char * fileName, const char * type, DisplaySystem displaySystem)
511    {
512       bool result = false;
513       char ext[MAX_EXTENSION];
514       subclass(BitmapFormat) format = null;
515       int typeToTry = -1;
516       const char * guessedType = type;
517
518       if(!fileName) return false;
519       if(!guessedType)
520          guessedType = strlwr(GetExtension(fileName, ext));
521
522       if(guessedType)
523          format = FindFormat(guessedType);
524       if(!format)
525          typeToTry = 0;
526
527       for(; typeToTry < NUM_TYPES_TO_TRY; typeToTry++)
528       {
529          if(typeToTry >= 0)
530             format = FindFormat(typesToTry[typeToTry]);
531
532          if(format)
533          {
534             File f = FileOpen(fileName, read);
535             if(f)
536             {
537                if((result = format.Load(this, f)))
538                {
539                   if(displaySystem)
540                   {
541                      if(!MakeDD(displaySystem))
542                      {
543                         Free();
544                         result = false;
545                      }
546                   }
547                   delete f;
548                   break;
549                }
550                delete f;
551             }
552          }
553          if(typeToTry == -1)
554          {
555             if(type) break;
556             typeToTry = 0;
557          }
558       }
559
560       if(!result)
561           ; //eGraphics_LogErrorCode(GERR_LOAD_BITMAP_FAILED, fileName);
562       return result;
563    }
564
565    bool LoadT(const char * fileName, const char * type, DisplaySystem displaySystem)
566    {
567       bool result = Load(fileName, type, null);
568       if(result)
569       {
570          transparent = true;
571          if(displaySystem)
572             if(!MakeDD(displaySystem))
573             {
574                Free();
575                result = false;
576             }
577       }
578       return result;
579    }
580
581    #define TRESHOLD  384
582
583    bool LoadGrayed(const char * fileName, const char * type, DisplaySystem displaySystem)
584    {
585       bool result = Load(fileName, type, null);
586       if(result)
587       {
588          if(pixelFormat == pixelFormatRGBA)
589          {
590             int c;
591             int x, y;
592             Bitmap grayed { };
593
594             grayed.Allocate(null, width, height, 0, pixelFormat888, false);
595
596             for(y = 0;  y <height - 1; y++)
597             {
598                for(x = 0; x < width - 1; x++)
599                {
600                   ColorRGBA b = ((ColorRGBA *)picture)[y * stride + x];
601                   //if(b && !(palette[b].color))
602                   if(/*b.a > 128 && */(b.r + b.g + b.b) < TRESHOLD)
603                   {
604                      // TODO: Precomp syntax error here without brackets
605                      ((ColorAlpha *)grayed.picture)[(y + 1) * grayed.stride + (x + 1)] =
606                         ColorAlpha { b.a, white };
607                   }
608                }
609             }
610
611             for(c = 0; c<size; c++)
612             {
613                ColorRGBA b = ((ColorRGBA *)picture)[c];
614                //if(b.a > 128)
615                {
616                   ((ColorAlpha *)grayed.picture)[c] =
617                      (/*b.a > 128 && */b.r + b.g + b.b < TRESHOLD) ?
618                         ColorAlpha { b.a, { 128, 128, 128 } } : ColorAlpha { b.a, { 212, 208, 200 } };
619                }
620             }
621
622             Free();
623
624             pixelFormat = grayed.pixelFormat;
625             picture = grayed.picture;
626             grayed.picture = null;
627             transparent = true;
628             alphaBlend = true;
629             driver = grayed.driver;
630
631             delete grayed;
632
633             if(displaySystem)
634                if(!MakeDD(displaySystem))
635                {
636                   Free();
637                   result = false;
638                }
639             return result;
640          }
641          if(pixelFormat != pixelFormat8)
642          {
643             transparent = true;
644             palette = Quantize(1, 255);
645          }
646          if(pixelFormat == pixelFormat8)
647          {
648             int c;
649             int x, y;
650             Bitmap grayed { };
651
652             grayed.Allocate(null, width, height, 0, pixelFormat888, false);
653
654
655             for(y = 0;  y <height - 1; y++)
656             {
657                for(x = 0; x < width - 1; x++)
658                {
659                   byte b = picture[y * stride + x];
660                   //if(b && !(palette[b].color))
661                   if(b && (palette[b].color.r + palette[b].color.g + palette[b].color.b) < TRESHOLD)
662                   {
663                      // TODO: Precomp syntax error here without brackets
664                      ((ColorAlpha *)grayed.picture)[(y + 1) * grayed.stride + (x + 1)] =
665                         ColorAlpha { 255, white };
666                   }
667                }
668             }
669
670             for(c = 0; c<size; c++)
671             {
672                byte b = picture[c];
673                if(b)
674                {
675                   ((ColorAlpha *)grayed.picture)[c] =
676                      //(bitmap.palette[b].color) ? Color { 212, 208, 200 } : Color { 128,128,128 };
677                      (palette[b].color.r + palette[b].color.g + palette[b].color.b < TRESHOLD) ?
678                         ColorAlpha { 255, { 128, 128, 128 } } : ColorAlpha { 255, { 212, 208, 200 } };
679                }
680             }
681
682             Free();
683
684             pixelFormat = grayed.pixelFormat;
685             picture = grayed.picture;
686             grayed.picture = null;
687             transparent = true;
688             driver = grayed.driver;
689
690             delete grayed;
691
692             if(displaySystem)
693                if(!MakeDD(displaySystem))
694                {
695                   Free();
696                   result = false;
697                }
698          }
699          else
700          {
701             Free();
702             result = false;
703          }
704       }
705
706       return result;
707    }
708
709    bool LoadMonochrome(const char * fileName, const char * type, DisplaySystem displaySystem)
710    {
711       bool result = Load(fileName, type, null);
712       if(result)
713       {
714          if(pixelFormat != pixelFormat8)
715             Convert(null, pixelFormat8, null);
716          if(pixelFormat == pixelFormat8)
717          {
718             int x, y;
719             Bitmap grayed { };
720
721             grayed.Allocate(null, width, height, 0, pixelFormat888, false);
722
723             for(y = 0; y<height - 1; y++)
724             {
725                for(x = 0; x<width - 1; x++)
726                {
727                   byte b = picture[y * stride + x];
728                   if(b && !palette[b].color)
729                   {
730                      ((ColorAlpha *)grayed.picture)[(y + 1) * grayed.stride + (x + 1)] = white;
731                   }
732                }
733             }
734             Free();
735
736             pixelFormat = grayed.pixelFormat;
737             size = grayed.size;
738             sizeBytes = grayed.sizeBytes;
739             stride = grayed.stride;
740             picture = grayed.picture;
741             grayed.picture = null;
742             transparent = true;
743
744             delete grayed;
745
746             if(displaySystem)
747                if(!MakeDD(displaySystem))
748                {
749                   Free();
750                   result = false;
751                }
752          }
753          else
754          {
755             Free();
756             result = false;
757          }
758       }
759       return result;
760    }
761
762    bool LoadMipMaps(const char * fileName, const char * type, DisplaySystem displaySystem)
763    {
764       bool result = Load(fileName, type, null);
765       if(result)
766          if(!MakeMipMaps(displaySystem))
767          {
768             Free();
769             result = false;
770          }
771       return result;
772    }
773
774    bool LoadTMipMaps(const char * fileName, const char * type, DisplaySystem displaySystem)
775    {
776       bool result = Load(fileName, type, null);
777       if(result)
778       {
779          transparent = true;
780          if(displaySystem)
781             if(!MakeMipMaps(displaySystem))
782                result = false;
783       }
784       return result;
785    }
786
787    bool Save(const char * fileName, const char * type, void * options)
788    {
789       char ext[MAX_EXTENSION];
790       subclass(BitmapFormat) format = null;
791
792       if(!type)
793          type = strlwr(GetExtension(fileName, ext));
794
795       if(type)
796          format = FindFormat(type);
797
798       if(format)
799          return format.Save(this, fileName, options);
800       return false;
801    }
802
803    // --- Memory bitmaps ---
804
805    bool AllocateDD(DisplaySystem displaySystem, int width, int height)
806    {
807       bool result = false;
808       PixelFormat pixelFormat = displaySystem ? displaySystem.pixelFormat : pixelFormat888;
809       driver = displaySystem ? displaySystem.driver : ((subclass(DisplayDriver))class(LFBDisplayDriver));
810       this.displaySystem = displaySystem;
811       if(driver.AllocateBitmap(displaySystem, this, width, height, 0, pixelFormat, true))
812          result = true;
813       else
814       {
815          paletteShades = null;
816          palette = null;
817          allocatePalette = false;
818          transparent = false;
819
820          // FillBytes(bitmap, 0, sizeof(Bitmap));
821
822          driver = ((subclass(DisplayDriver))class(LFBDisplayDriver));
823          displaySystem = null;
824          if(driver.AllocateBitmap(null, this, width, height, 0, pixelFormat, true))
825          {
826             result = true;
827          }
828       }
829       if(!result)
830          Free();
831       return result;
832    }
833
834    bool Allocate(const char * driverName, int width, int height, int stride, PixelFormat format, bool allocatePalette)
835    {
836       bool result = false;
837       subclass(DisplayDriver) displayDriver = driverName ? GetDisplayDriver(driverName) : ((subclass(DisplayDriver))class(LFBDisplayDriver));
838       Free();
839       if(displayDriver)
840       {
841          driver = displayDriver;
842          if(driver.AllocateBitmap(null, this, width, height, stride, format, allocatePalette))
843             result = true;
844          if(!result)
845             Free();
846       }
847       return result;
848    }
849
850    void Free()
851    {
852       if(this && driver)
853       {
854          driver.FreeBitmap(displaySystem, this);
855          driverData = null;
856       }
857       if(this && keepData)
858          delete picture;
859    }
860
861    void Grab(Bitmap src, int x, int y)
862    {
863       Surface surface = GetSurface(0, 0, null);
864       surface.blend = false;
865       surface.Blit(src, 0,0, x, y, width, height);
866       delete surface;
867    }
868
869    ColorAlpha * Quantize(uint start, uint end)
870    {
871       ColorAlpha * palette = new ColorAlpha[256];
872       if(palette)
873       {
874          int c;
875          OldList nodeList { };
876          QuantNode mainNode { maxR = 255, maxG = 255, maxB = 255 };
877          QuantNode node;
878          Color * picture;
879          int nonZeroN2 = 0;
880
881          nodeList.Add(mainNode);
882
883          Convert(null, pixelFormat888, null);
884
885          for(picture = (Color *)this.picture, c = 0; c<size; c++, picture++)
886          {
887             Color color = *picture;
888             mainNode.AddColor(color.r, color.g, color.b, nodeList, &nonZeroN2);
889          }
890
891          nodeList.Sort(QuantNode::Compare, null);
892
893          while(nonZeroN2 > end - start + 1)
894          {
895             for(node = nodeList.last; node; node = node.prev)
896             {
897                if(node.n2 > 0)
898                {
899                   ((QuantNode)nodeList.last).PruneNode(nodeList, &nonZeroN2);
900                   break;
901                }
902             }
903          }
904
905          c = 0;
906          mainNode.AddNodeToColorTable(palette + start, &c);
907
908          {
909             Bitmap newBitmap { };
910             if(newBitmap.Allocate(null, width, height, 0, pixelFormat8, false))
911             {
912                int y, x;
913                ColorAlpha * picture = (ColorAlpha *)this.picture;
914                byte * newPicture = newBitmap.picture;
915
916                for(y = 0; y < height; y++)
917                   for(x = 0; x < width; x++, picture++, newPicture++)
918                   {
919                      byte color;
920
921                      if(transparent && start > 0 && !picture->a)
922                         color = 0;
923                      else
924                         color = (byte)(mainNode.FindColor(palette + start, picture->color.r, picture->color.g, picture->color.b) + start);
925                      *newPicture = color;
926                   }
927
928                delete this.picture;
929                this.picture = newBitmap.picture;
930                this.palette = palette;
931                allocatePalette = true;
932                pixelFormat = pixelFormat8;
933
934                newBitmap.picture = null;
935             }
936             delete newBitmap;
937          }
938          nodeList.Free(null);
939       }
940       return palette;
941    }
942 };