ff2add5a731e9d831b2fa437ad1063342395cbc3
[sdk] / ecere / src / gfx / drivers / LFBDisplayDriver.ec
1 namespace gfx::drivers;
2
3 #if (defined(ECERE_VANILLA) || defined(ECERE_ONEDRIVER)) && defined(__WIN32__)
4 #define ECERE_NOTRUETYPE
5 #endif
6
7 #undef __BLOCKS__
8 #define uint _uint
9 #define strlen _strlen
10 #if !defined(ECERE_NOTRUETYPE)
11 #include <ft2build.h>
12 #include FT_FREETYPE_H
13 #include FT_TRUETYPE_TABLES_H
14 #include FT_UNPATENTED_HINTING_H
15 #define property  _property
16 #include "harfbuzz.h"
17 #undef property
18
19 #if defined(__WIN32__)
20 #define WIN32_LEAN_AND_MEAN
21 #define String _String
22 #include <windows.h>
23 #undef String
24 #elif !defined(ECERE_NOTRUETYPE) && !defined(ECERE_NOFONTCONFIG)
25 #define set _set
26 #include <fontconfig/fontconfig.h>
27 static FcConfig * fcConfig;
28 #undef set
29 #endif
30
31 #endif
32 #undef uint
33 #undef strlen
34
35 #ifdef __MSC__
36 #pragma warning(disable:4244)
37 #pragma warning(disable:4018)
38 #endif
39
40 import "File"
41 import "Display"
42
43 public define LIGHTSHIFT = 5;
44 public define LIGHTSTEPS = 1<<LIGHTSHIFT;
45
46 /*#ifndef ECERE_VANILLA
47 import "lfbRGBLookup"
48 static bool rgbLookupSet = true;
49 #else*/
50 /*static */byte defaultRGBLookup[32768];
51 /*static */bool rgbLookupSet = false;
52 //#endif
53
54 import "lfbBlit"
55 import "lfbConvert"
56
57 #if !defined(ECERE_NO3D) && !defined(ECERE_VANILLA) && defined(__WIN32__)
58 import "OpenGLDisplayDriver"
59 import "Direct3D8DisplayDriver"
60 import "Direct3D9DisplayDriver"
61 #endif
62
63 #if !defined(ECERE_NOTRUETYPE)
64
65 #if !defined(ECERE_VANILLA)
66 import "edtaa3func"
67
68 static void ComputeOutline(byte *out, byte *src, uint w, uint h, float size, float fade)
69 {
70    uint i, numPixels = w * h;
71    short * distx = new short[2 * numPixels], * disty = distx + numPixels;
72    float * data = new0 float[4 * numPixels], * gx = data + numPixels, * gy = gx + numPixels, * dist = gy + numPixels;
73    float rb = Max(1.5f, size), ra = rb - (rb-1)*fade - 1;
74    float inv_rw = 1/(rb-ra);
75
76    for(i = 0; i < numPixels; i++)
77       data[i] = src[i] / 255;
78
79    computegradient(data, w, h, gx, gy);
80    edtaa3(data, gx, gy, w, h, distx, disty, dist);
81
82    for(i = 0; i < numPixels; i++)
83    {
84       float value = 1 - Max(0.0f, Min(1.0f, (dist[i]-ra)*inv_rw));
85       out[i] = (byte)(255 * value * value);
86    }
87    delete distx;
88    delete data;
89 }
90
91 static void BlitOutline(byte * dst, int dx, int dy, int w, int h, byte * src, int sx, int sy, int sw, int sh, int srcStride)
92 {
93    sh = Min(h - dy, sh);
94    sw = Min(w - dx, sw);
95    if(sw > 0 && sh > 0)
96    {
97       int y;
98       for(y = 0; y < sh; y++)
99          memcpy(dst + w * (dy+y) + dx, src + srcStride * (sy+y) + sx, sw);
100    }
101 }
102
103 static void MeasureOutline(byte * image, int w, int h, int * _x1, int * _y1, int * _x2, int * _y2)
104 {
105    int x1 = MAXINT, y1 = MAXINT, x2 = MININT, y2 = MININT;
106    int x, y;
107    for(x = 0; x < w && x1 == MAXINT; x++)
108    {
109       for(y = 0; y < h; y++)
110          if(image[(y*w)+x])
111          {
112             x1 = x;
113             break;
114          }
115    }
116    for(x = w-1; x >= 0 && x2 == MININT; x--)
117    {
118       for(y = 0; y < h; y++)
119          if(image[(y*w)+x])
120          {
121             x2 = x;
122             break;
123          }
124    }
125    for(y = 0; y < h && y1 == MAXINT; y++)
126    {
127       for(x = 0; x < w; x++)
128          if(image[(y*w)+x])
129          {
130             y1 = y;
131             break;
132          }
133    }
134    for(y = h-1; y >= 0 && y2 == MININT; y--)
135    {
136       for(x = 0; x < w; x++)
137          if(image[(y*w)+x])
138          {
139             y2 = y;
140             break;
141          }
142    }
143    *_x1 = x1;
144    *_y1 = y1;
145    *_x2 = x2;
146    *_y2 = y2;
147 }
148
149 #endif
150
151 /*
152 static byte * MakeDistanceMap( byte *out, byte *img, uint width, uint height, int k, int t )
153 {
154     short * xdist = new short[ width * height];
155     short * ydist = new short[ width * height];
156     float * gx   = new float[ width * height];
157     float * gy      = new float[ width * height];
158     float * data    = new float[ width * height];
159     float * outside = new float[ width * height];
160     float * inside  = new float[ width * height];
161     int i;
162     k = 80;
163     t = 0;
164
165     // Convert img into float (data)
166     float img_min = 255, img_max = -255;
167     for( i=0; i<width*height; ++i)
168     {
169         float v = img[i];
170         data[i] = v;
171         if (v > img_max) img_max = v;
172         if (v < img_min) img_min = v;
173     }
174
175     if(img_max > 0)
176     {
177        // Rescale image levels between 0 and 1
178        for( i=0; i<width*height; ++i)
179        {
180            data[i] = (img[i]-img_min)/img_max;
181        }
182
183        // Compute outside = edtaa3(bitmap); % Transform background (0's)
184        computegradient( data, width, height, gx, gy);
185        edtaa3(data, gx, gy, width, height, xdist, ydist, outside);
186        for( i=0; i<width*height; ++i)
187            if( outside[i] < 0 )
188                outside[i] = 0.0;
189
190        // Compute inside = edtaa3(1-bitmap); % Transform foreground (1's)
191        memset(gx, 0, sizeof(float)*width*height );
192        memset(gy, 0, sizeof(float)*width*height );
193        for( i=0; i<width*height; ++i)
194            data[i] = 1 - data[i];
195        computegradient( data, width, height, gx, gy);
196        edtaa3(data, gx, gy, width, height, xdist, ydist, inside);
197        for( i=0; i<width*height; ++i)
198            if( inside[i] < 0 )
199                inside[i] = 0.0;
200
201        // distmap = outside - inside; % Bipolar distance field
202        for( i=0; i<width*height; ++i)
203        {
204            outside[i] -= inside[i];
205            outside[i] = t+outside[i]* k;
206            if( outside[i] < 0 ) outside[i] = 0;
207            if( outside[i] > 255 ) outside[i] = 255;
208            out[i] = 255 - (byte) outside[i];
209            //out[i] = (byte) outside[i];
210        }
211     }
212     else
213       memset(out, 0, width * height);
214
215     delete xdist;
216     delete ydist;
217     delete gx;
218     delete gy;
219     delete data;
220     delete outside;
221     delete inside;
222     return out;
223 }
224 */
225
226 #define MAX_FONT_LINK_ENTRIES   10
227
228 static HB_Script theCurrentScript;
229
230 static unichar UTF16GetChar(const uint16 *string, int * nw)
231 {
232    unichar ch;
233    if(HB_IsHighSurrogate(string[0]) && HB_IsLowSurrogate(string[1]))
234    {
235       ch = HB_SurrogateToUcs4(string[0], string[1]);
236       *nw = 2;
237    }
238    else
239    {
240       ch = *string;
241       *nw = 1;
242    }
243    return ch;
244 }
245
246 static HB_Bool hb_stringToGlyphs(HB_Font font, const uint16 * string, uint length, HB_Glyph *glyphs, uint *numGlyphs, HB_Bool rightToLeft)
247 {
248    FT_Face face = ((FontEntry)font->userData).face;
249    int glyph_pos = 0;
250    int c, nw;
251
252    if (length > *numGlyphs)
253       return 0;
254
255    for (c = 0; c < length; c += nw)
256    {
257       unichar ch = UTF16GetChar(string + c, &nw);
258       glyphs[glyph_pos++] = FT_Get_Char_Index(face, ch);
259    }
260    *numGlyphs = glyph_pos;
261    return 1;
262 }
263
264 static void hb_getAdvances(HB_Font font, const HB_Glyph * glyphs, uint numGlyphs, HB_Fixed *advances, int flags)
265 {
266    FontEntry entry = font->userData;
267    Font glFont = entry.font;
268    int c;
269    uint lastPack = 0;
270    GlyphPack pack = glFont.asciiPack;
271    int fontEntryNum;
272    for(fontEntryNum = 0; fontEntryNum < MAX_FONT_LINK_ENTRIES; fontEntryNum++)
273    {
274       if(glFont.fontEntries[fontEntryNum] == entry)
275          break;
276    }
277
278    for(c = 0; c < numGlyphs; c++)
279    {
280       GlyphInfo * glyph;
281       uint glyphNo = glyphs[c] | 0x80000000 | (theCurrentScript << 24);
282       uint packNo = glyphNo & 0xFFFFFF80;
283       if(packNo != lastPack)
284       {
285          pack = (GlyphPack)glFont.glyphPacks.Find((uintptr)packNo);
286          if(!pack)
287          {
288             glFont.glyphPacks.Add((pack = GlyphPack { key = (uintptr)packNo }));
289             pack.Render(glFont, fontEntryNum, glFont.displaySystem);
290             pack.bitmap.alphaBlend = true;
291          }
292          lastPack = packNo;
293       }
294       glyph = &pack.glyphs[glyphNo & 0x7F];
295       advances[c] = glyph->ax;
296    }
297 }
298
299 static HB_Bool hb_canRender(HB_Font font, const uint16 * string, uint length)
300 {
301    FT_Face face = ((FontEntry)font->userData).face;
302    int c, nw;
303
304    for (c = 0; c < length; c += nw)
305    {
306       unichar ch = UTF16GetChar(string + c, &nw);
307       if(!FT_Get_Char_Index(face, ch))
308          return 0;
309    }
310    return 1;
311 }
312
313 static HB_Error hb_getSFntTable(void *font, HB_Tag tableTag, HB_Byte *buffer, HB_UInt *length)
314 {
315     FT_Face face = (FT_Face)font;
316     FT_ULong ftlen = *length;
317     FT_Error error = 0;
318
319     if (!FT_IS_SFNT(face))
320         return HB_Err_Invalid_Argument;
321
322     error = FT_Load_Sfnt_Table(face, tableTag, 0, buffer, &ftlen);
323     *length = (uint)ftlen;
324     return (HB_Error)error;
325 }
326
327 static HB_Error hb_getPointInOutline(HB_Font font, HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
328 {
329     HB_Error error = HB_Err_Ok;
330     FT_Face face = (FT_Face)font->userData;
331
332     int load_flags = (flags & HB_ShaperFlag_UseDesignMetrics) ? FT_LOAD_NO_HINTING : FT_LOAD_DEFAULT;
333
334     if ((error = (HB_Error)FT_Load_Glyph(face, glyph, load_flags)))
335         return error;
336
337     if (face->glyph->format != ft_glyph_format_outline)
338         return (HB_Error)HB_Err_Invalid_SubTable;
339
340     *nPoints = face->glyph->outline.n_points;
341     if (!(*nPoints))
342         return HB_Err_Ok;
343
344     if (point > *nPoints)
345         return (HB_Error)HB_Err_Invalid_SubTable;
346
347     *xpos = (int)face->glyph->outline.points[point].x;
348     *ypos = (int)face->glyph->outline.points[point].y;
349
350     return HB_Err_Ok;
351 }
352
353 static void hb_getGlyphMetrics(HB_Font font, HB_Glyph theGlyph, HB_GlyphMetrics *metrics)
354 {
355    FontEntry entry = font->userData;
356    Font glFont = entry.font;
357    uint lastPack = 0;
358    GlyphPack pack = glFont.asciiPack;
359    int fontEntryNum;
360    for(fontEntryNum = 0; fontEntryNum < MAX_FONT_LINK_ENTRIES; fontEntryNum++)
361    {
362       if(glFont.fontEntries[fontEntryNum] == entry)
363          break;
364    }
365    {
366       GlyphInfo * glyph;
367       uint glyphNo = theGlyph | 0x80000000 | (theCurrentScript << 24);
368       uint packNo = glyphNo & 0xFFFFFF80;
369       if(packNo != lastPack)
370       {
371          pack = (GlyphPack)glFont.glyphPacks.Find((uintptr)packNo);
372          if(!pack)
373          {
374             pack = { key = (uintptr)packNo };
375             glFont.glyphPacks.Add(pack);
376             pack.Render(glFont, fontEntryNum, glFont.displaySystem);
377             pack.bitmap.alphaBlend = true;
378          }
379          lastPack = packNo;
380       }
381       glyph = &pack.glyphs[glyphNo & 0x7F];
382
383       metrics->x = glyph->ax;
384       metrics->y = 0;
385       metrics->width = glyph->w;
386       metrics->height = glyph->h;
387       metrics->xOffset = glyph->bx;
388       metrics->yOffset = glyph->by;
389    }
390 }
391
392 static HB_Fixed hb_getFontMetric(HB_Font font, HB_FontMetric metric)
393 {
394    FontEntry entry = font->userData;
395    FT_Face face = entry.face;
396
397    // Note that we aren't scanning the VDMX table which we probably would in
398    // an ideal world.
399    if(metric == HB_FontAscent)
400       return face->ascender;
401    return 0;
402 }
403
404 static HB_FontClass hb_fontClass =
405 {
406    hb_stringToGlyphs, hb_getAdvances, hb_canRender,
407    hb_getPointInOutline, hb_getGlyphMetrics, hb_getFontMetric
408 };
409
410 static uint FT_stream_load(FT_Stream stream, long offset, byte * buffer, long count)
411 {
412     File f = stream->descriptor.pointer;
413     f.Seek((int)offset, start);
414     return count ? f.Read(buffer, 1, (uint)count) : 0;
415 }
416
417 static void FT_stream_close(FT_Stream stream)
418 {
419    File f = stream->descriptor.pointer;
420    delete f;
421    delete stream;
422 }
423
424 static FT_Library ftLibrary;
425 static int numFonts;
426 #undef CompareString
427 static BinaryTree loadedFonts
428 {
429    CompareKey = (void *)BinaryTree::CompareString
430 };
431
432 class FontEntry : BTNode
433 {
434    FT_Face face;
435    HB_FontRec hbFont;
436    HB_Face hbFace;
437
438    int used;
439    byte * buffer;
440
441    //If we don't save the FT_Stream before sacrificing it to FreeType, the garbage collector (if one is used) will destroy it prematurely
442    FT_Stream stream;
443    Font font;
444    float scale;
445
446    ~FontEntry()
447    {
448       delete (char *)key;
449       delete buffer;
450       if(hbFace)
451          HB_FreeFace(hbFace);
452       if(face)
453       {
454          FT_Done_Face(face);
455          numFonts--;
456          if(!numFonts)
457          {
458             FT_Done_FreeType(ftLibrary);
459             ftLibrary = null;
460          }
461       }
462    }
463 }
464
465 static float FaceSetCharSize(FT_Face face, float size)
466 {
467    float scale = 1;
468    if(FT_Set_Char_Size(face, (int)(size * 64), (int)(size * 64), 96, 96))
469    {
470       if(face->num_fixed_sizes)
471       {
472          int c;
473          int bestDiff = MAXINT, best = 0;
474          FT_Bitmap_Size * sizes = face->available_sizes;
475          int wishedHeight = (int)(size * 96 / 72);
476          for(c = 0; c < face->num_fixed_sizes; c++)
477          {
478             int diff = abs(sizes[c].height - wishedHeight);
479             if(diff < bestDiff)
480             {
481                best = c;
482                bestDiff = diff;
483             }
484          }
485          FT_Set_Pixel_Sizes(face, sizes[best].width, sizes[best].height);
486
487          if(!face->ascender)
488             face->ascender = sizes[best].height;
489          scale = (float)wishedHeight / sizes[best].height;
490       }
491    }
492    return scale;
493 }
494
495 #endif
496
497 struct GlyphInfo
498 {
499    int ax, ay;
500    int x, y;
501    int w, h;
502    int left, top;
503    int bx, by;
504    int glyphNo;
505    float scale;
506 };
507
508 class GlyphPack : BTNode
509 {
510    GlyphInfo glyphs[256];
511    Bitmap bitmap { };
512    BinaryTree outlines { };
513    int cellWidth, cellHeight;
514
515    void Render(Font font, int startFontEntry, DisplaySystem displaySystem)
516    {
517 #if !defined(ECERE_NOTRUETYPE)
518       unichar c;
519       int maxWidth, maxHeight;
520       int cellWidth, cellHeight;
521       int width, height;
522       FontEntry fontEntry = null;
523       FT_Face faces[128];
524       float scales[128];
525       bool isGlyph = ((uint)key & 0x80000000) != 0;
526       //int curScript = ((uint)key & 0x7F000000) >> 24;
527       unichar testChar = 0;
528       /*
529       if(isGlyph)
530       {
531          switch(curScript)
532          {
533             case HB_Script_Arabic:
534                testChar = 0x621;
535                // printf("\nRendering arabic in %s (%d)\n", font.faceName, key & 0xFFFFFF);
536                break;
537             case HB_Script_Devanagari:
538                testChar = 0x905;
539                break;
540             case 60: testChar = 'あ'; break;
541             case 61: testChar = 0x3400; break;
542          }
543       }
544       */
545       /*
546       FT_GlyphSlot slot;
547       FT_Matrix matrix;
548       FT_Vector pen = { 0, 0 };
549       if(font.fakeItalic)
550       {
551          matrix.xx = (FT_Fixed)( 1.0 * 0x10000L );
552          matrix.xy = (FT_Fixed)( 0.3 * 0x10000L );
553          matrix.yx = (FT_Fixed)( 0.0 * 0x10000L );
554          matrix.yy = (FT_Fixed)( 1.0 * 0x10000L );
555          FT_Set_Transform( fontEntry.face, &matrix, &pen );
556       }
557       FT_Set_Char_Size( fontEntry.face, (int)(font.size * 64), (int)(font.size * 64), 96, 96);
558       */
559
560       maxWidth = 0;
561       maxHeight = 0;
562
563       for(c = 0; c < MAX_FONT_LINK_ENTRIES; c++)
564       {
565          fontEntry = font.fontEntries[c];
566          if(fontEntry)
567          {
568             FT_Matrix matrix;
569             FT_Vector pen = { 0, 0 };
570
571             if(font.fakeItalic)
572             {
573                matrix.xx = (FT_Fixed)( 1.0 * 0x10000L );
574                matrix.xy = (FT_Fixed)( 0.3 * 0x10000L );
575                matrix.yx = (FT_Fixed)( 0.0 * 0x10000L );
576                matrix.yy = (FT_Fixed)( 1.0 * 0x10000L );
577                FT_Set_Transform(fontEntry.face, &matrix, &pen);
578             }
579             //FT_Set_Char_Size(fontEntry.face, (int)(font.size * 64), (int)(font.size * 64), 96, 96);
580             fontEntry.scale = FaceSetCharSize(fontEntry.face, font.size);
581             if(!font.scale)
582                font.scale = fontEntry.scale;
583             if(!c)
584             {
585                if(!fontEntry.face->units_per_EM)
586                   font.ascent = (int)((double)fontEntry.face->ascender);
587                else
588                   font.ascent = (int)((double)fontEntry.face->ascender * fontEntry.face->size->metrics.y_ppem / fontEntry.face->units_per_EM);
589             }
590
591             fontEntry.hbFont.x_ppem  = fontEntry.face->size->metrics.x_ppem;
592             fontEntry.hbFont.y_ppem  = fontEntry.face->size->metrics.y_ppem;
593             fontEntry.hbFont.x_scale = (int)fontEntry.face->size->metrics.x_scale;
594             fontEntry.hbFont.y_scale = (int)fontEntry.face->size->metrics.y_scale;
595          }
596       }
597
598       fontEntry = null;
599       for(c = 0; c < 128; c++)
600       {
601          int entry = 0;
602          if(isGlyph)
603          {
604             uint glyph = ((uint)key | c) & 0xFFFFFF;
605             for(entry = startFontEntry; entry < MAX_FONT_LINK_ENTRIES; entry++)
606             {
607                fontEntry = font.fontEntries[entry];
608                if(fontEntry && (FT_Get_Char_Index(fontEntry.face, testChar) || !testChar || entry == MAX_FONT_LINK_ENTRIES-1 || !font.fontEntries[entry+1]))
609                {
610                   if(!FT_Load_Glyph(fontEntry.face, glyph, FT_LOAD_DEFAULT /*FT_LOAD_NO_HINTING*/) || entry == MAX_FONT_LINK_ENTRIES-1 || !font.fontEntries[entry+1])
611                   {
612                      //printf("%s: Accepted entry %d ", font.faceName, entry);
613                      break;
614                   }
615                }
616             }
617          }
618          else
619          {
620             for(entry = startFontEntry; ; entry++)
621             {
622                uint glyph;
623                fontEntry = font.fontEntries[entry];
624                if((glyph = FT_Get_Char_Index(fontEntry.face, ((uint)key | c) & 0xFFFFFF)) || entry == MAX_FONT_LINK_ENTRIES-1 || !font.fontEntries[entry+1])
625                {
626                   if(!FT_Load_Glyph(fontEntry.face, glyph, FT_LOAD_DEFAULT /*FT_LOAD_NO_HINTING*/) || entry == MAX_FONT_LINK_ENTRIES-1 || !font.fontEntries[entry+1])
627                      break;
628                }
629             }
630          }
631          scales[c] = fontEntry.scale;
632          faces[c] = fontEntry.face;
633          maxWidth = Max(maxWidth, ((faces[c]->glyph->metrics.width + 64 + (64 - (faces[c]->glyph->metrics.width & 0x3F))) >> 6));
634          maxHeight = Max(maxHeight, ((faces[c]->glyph->metrics.height + 64 + (64 - (faces[c]->glyph->metrics.height & 0x3F))) >> 6));
635          //maxHeight = Max(maxHeight, ((faces[c]->glyph->metrics.height) >> 6));
636       }
637       this.cellWidth = cellWidth = maxWidth;
638       this.cellHeight = cellHeight = maxHeight;
639
640       width = maxWidth * 16;
641       height = maxHeight * 8;
642
643       if(true)
644       {
645          width = pow2i(height * 16);
646          height = pow2i(height * 8);
647       }
648
649       if(bitmap.Allocate(null, width, height, 0, pixelFormatAlpha, false /*true*/))
650       {
651          Bitmap bitmap = this.bitmap;
652
653          bitmap.transparent = true;
654
655          for(c = 0; c < 128; c++)
656          {
657             FT_Int i, j, p, q;
658             FT_Int xMax, yMax;
659             int sx = (c % 16) * cellWidth;
660             int sy = (c / 16) * cellHeight;
661             int x, y;
662             byte * picture = (byte *)bitmap.picture;
663             GlyphInfo * glyph = &glyphs[c];
664             FT_GlyphSlot slot = faces[c]->glyph;
665             double em_size = 1.0 * faces[c]->units_per_EM;
666             //double x_scale = faces[c]->size->metrics.x_ppem / em_size;
667             double y_scale = em_size ? (faces[c]->size->metrics.y_ppem / em_size) : 1;
668             double ascender = faces[c]->ascender * y_scale;
669             int glyphNo = isGlyph ? (((uint)key | c) & 0x00FFFFFF) : FT_Get_Char_Index(faces[c], (uint)key | c);
670
671             FT_Load_Glyph(faces[c], glyphNo, /*FT_LOAD_DEFAULT | FT_LOAD_FORCE_AUTOHINT*/ FT_LOAD_DEFAULT /*FT_LOAD_NO_HINTING*/); // FT_LOAD_RENDER // FT_LOAD_NO_HINTING
672
673             FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL);
674
675             x = sx;
676             y = sy;
677             //printf("%d, %d\n", maxHeight, faces[c]->size->metrics.height >> 6);
678
679             glyph->left = slot->bitmap_left;
680             // glyph->top = ((64 + (64 - faces[c]->glyph->metrics.height & 0x3F)) >> 6) + (int)(ascender - slot->bitmap_top) + font.height - (faces[c]->size->metrics.height >> 6);
681             // glyph->top = (int)(ascender - slot->bitmap_top) + 2 * (font.height - maxHeight);
682             //glyph->top = (int)(ascender - slot->bitmap_top) + 2 * ((((faces[c]->size->metrics.height + 64 + (64 - faces[c]->size->metrics.height & 0x3F)) >> 6)) - font.height);
683             //glyph->top = (int)(ascender - slot->bitmap_top) + (font.height - (faces[c]->size->metrics.height >> 6));
684
685             //glyph->top = (int)(ascender + (font.height *64 - /*faces[0]->size->metrics.height - */faces[c]->size->metrics.height) / 64.0  + 0.5) - slot->bitmap_top;
686             //glyph->top = (int)(ascender + (font.height *64 - /*faces[0]->size->metrics.height - */faces[c]->size->metrics.height) / 64.0  + 0.5) - slot->bitmap_top;
687
688             //glyph->top = (int)((ascender - slot->bitmap_top) + (font.height * 64 - maxHeight * 64 + faces[c]->glyph->metrics.height - faces[c]->glyph->metrics.height) / 64);
689
690             //glyph->top = (int)(ascender - slot->bitmap_top); // + ((faces[c]->size->metrics.height >> 6) - (faces[0]->size->metrics.height >> 6)) + (font.height - (faces[c]->size->metrics.height >> 6));
691             //glyph->top = (int)(ascender - slot->bitmap_top); // + ((faces[c]->size->metrics.height >> 6) - (faces[0]->size->metrics.height >> 6)) + (font.height - (faces[c]->size->metrics.height >> 6));
692
693             //glyph->top = (int)(ascender - slot->bitmap_top);// + (font.height - maxHeight);
694             glyph->top = (int)(ascender - slot->bitmap_top) + (int)(font.height - (faces[c]->size->metrics.height >> 6)) / 2;
695
696             // printf("[char: %d] mode: %d, width: %d, height: %d, pitch: %d\n", key + c, slot->bitmap.pixel_mode, slot->bitmap.width, slot->bitmap.rows, slot->bitmap.pitch);
697             xMax = x + slot->bitmap.width;
698             yMax = y + slot->bitmap.rows;
699
700             {
701                int total = 0;
702                int numPixels = 0;
703                //int max;
704                if(slot->bitmap.pixel_mode != FT_PIXEL_MODE_MONO)
705                {
706                   for(j = y, q = 0; j<yMax; j++)
707                   {
708                      for(p = 0, i = x; i<xMax; i++)
709                      {
710                         byte value = ((byte *)slot->bitmap.buffer)[q + p++];
711                         if(value > 32)
712                         {
713                            total += value;
714                            numPixels++;
715                         }
716                      }
717                      q += slot->bitmap.pitch;
718                   }
719                }
720                //max = numPixels ? (total / numPixels) : 1;
721
722                for(j = y, q = 0; j<yMax; j++)
723                {
724                   int bit = 0x80;
725                   for(p = 0, i = x; i<xMax; i++)
726                   {
727                      if(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO)
728                      {
729                         picture[j * bitmap.stride + i] = (slot->bitmap.buffer[q + p] & bit) ? 255 : 0;
730                         bit >>= 1;
731                         if(!bit) { bit = 0x80; p++; }
732                      }
733                      else
734                      {
735                         byte value = ((byte *)slot->bitmap.buffer)[q + p++];
736                         picture[j * bitmap.stride + i] = /*(max < 192) ? Min(255, value * 192/max) :*/ value;
737                      }
738                   }
739                   q += slot->bitmap.pitch;
740                }
741             }
742             glyph->x = sx;
743             glyph->y = sy;
744             glyph->w = slot->bitmap.width;
745             glyph->h = slot->bitmap.rows;
746             glyph->glyphNo = glyphNo;
747             glyph->bx = (int)faces[c]->glyph->metrics.horiBearingX;
748             glyph->by = (int)faces[c]->glyph->metrics.horiBearingY;
749             glyph->scale = scales[c];
750
751             glyph->ax = (int)slot->advance.x;
752             glyph->ay = (int)(slot->advance.y + (64 - slot->advance.y % 64));
753          }
754          #if 0
755          {
756             int c;
757             char fileName[256];
758             static int fid = 0;
759             for(c = 0; c<256; c++)
760                bitmap.palette[c] = ColorAlpha { 255, { (byte)c,(byte)c,(byte)c } };
761             bitmap.pixelFormat = pixelFormat8;
762
763             /*
764             //strcpy(fileName, faceName);
765             if(flags)
766                strcat(fileName, "Bold");
767             */
768             sprintf(fileName, "font%d", fid++);
769             ChangeExtension(fileName, "pcx", fileName);
770
771             bitmap.Save(fileName, null, 0);
772             bitmap.pixelFormat = pixelFormatAlpha;
773          }
774          #endif
775
776          if(displaySystem && displaySystem.pixelFormat != pixelFormat4) // TODO: Add none PixelFormat
777          {
778             bitmap.keepData = true; // For outlines
779             displaySystem.Lock();
780 #if defined(__WIN32__)
781             // Is this check still required?
782             if(displaySystem.driver == class(OpenGLDisplayDriver) ||
783                displaySystem.driver == class(Direct3D8DisplayDriver) ||
784                displaySystem.driver == class(Direct3D9DisplayDriver))
785 #endif
786                bitmap.MakeDD(displaySystem);
787             displaySystem.Unlock();
788          }
789       }
790 #endif
791    }
792
793    void RenderOutline(GlyphPack outline, Font font, DisplaySystem displaySystem)
794    {
795 #if !defined(ECERE_NOTRUETYPE) && !defined(ECERE_VANILLA)
796       unichar c;
797       int pCellWidth = this.cellWidth, pCellHeight = this.cellHeight;
798       int cellWidth, cellHeight;
799       int width, height;
800       uintptr key = outline.key;
801       float outlineSize = (float)(key >> 16);
802       float fade = ((uint32)key & 0xFFFF) / 255.f;
803       GlyphInfo * widest = null, * highest = null;
804       uint widestIndex = 0, highestIndex = 0;
805       GlyphInfo * glyph;
806       int minX1 = MAXINT, minY1 = MAXINT;
807       int maxX2 = MININT, maxY2 = MININT;
808       int timesBigger = 2;
809       byte * bigger = new byte[pCellWidth * pCellHeight * timesBigger*timesBigger];
810       byte * field = new byte[pCellWidth * pCellHeight * timesBigger*timesBigger];
811       int ox, oy;
812
813       // Test biggest glyphs to determine cell width & height:
814       for(c = 0; c < 128; c++)
815       {
816          glyph = &glyphs[c];
817          if(glyph->w > (widest ? widest->w : 0))
818             widest = glyph, widestIndex = c;
819          if(glyph->h > (highest ? highest->h : 0))
820             highest = glyph, highestIndex = c;
821       }
822
823       cellWidth = 0;
824       cellHeight = 0;
825       for(glyph = widest; glyph; glyph = (glyph == widest && glyph != highest) ? highest : null)
826       {
827          int index = (glyph == widest) ? widestIndex : highestIndex;
828          int x = (index & 0xF) * pCellWidth, y = (index >> 4) * pCellHeight;
829          int w = pCellWidth * timesBigger, h = pCellHeight * timesBigger;
830          int x1,y1,x2,y2;
831
832          memset(bigger, 0, w * h);
833          BlitOutline(bigger, (w - pCellWidth)/2, (h - pCellHeight)/2, w, h, bitmap.picture, x, y, pCellWidth, pCellHeight, bitmap.width);
834          ComputeOutline(field, bigger, w, h, outlineSize, fade);
835          MeasureOutline(field, w, h, &x1, &y1, &x2, &y2);
836          minX1 = Min(minX1, x1);
837          minY1 = Min(minY1, y1);
838          maxX2 = Max(maxX2, x2);
839          maxY2 = Max(maxY2, y2);
840       }
841       {
842          int x1 = (timesBigger*pCellWidth - pCellWidth)  / 2,  x2 = x1 + pCellWidth-1;
843          int y1 = (timesBigger*pCellHeight - pCellHeight) / 2,  y2 = y1 + pCellHeight-1;
844          ox = -Max(0, x1 - minX1);
845          oy = -Max(0, y1 - minY1);
846          cellWidth  = pCellWidth  - ox + Max(0, (maxX2 > x2) ? (maxX2 - x2) : 0);
847          cellHeight = pCellHeight - oy + Max(0, (maxY2 > y2) ? (maxY2 - y2) : 0);
848       }
849
850       width = cellWidth * 16;
851       height = cellHeight * 8;
852       if(true) //TEXTURES_MUST_BE_POWER_OF_2)
853       {
854           width = pow2i(width);
855           height = pow2i(height);
856       }
857
858       if(outline.bitmap.Allocate(null, width, height, 0, pixelFormatAlpha, false))
859       {
860          Bitmap bitmap = outline.bitmap;
861          byte * picture = (byte *)bitmap.picture;
862          memset(picture, 0, width * height);
863
864          for(c = 0; c < 128; c++)
865          {
866             GlyphInfo * glyph = &outline.glyphs[c];
867             int x1 = MAXINT, y1 = MAXINT, x2 = MININT, y2 = MININT;
868             int w = 0, h = 0;
869             memset(bigger, 0, cellWidth * cellHeight);
870             BlitOutline(bigger, -ox, -oy, cellWidth, cellHeight,
871                  this.bitmap.picture,
872                  (c & 0xF) * pCellWidth, (c >> 4) * pCellHeight,
873                  pCellWidth, pCellHeight,
874                  this.bitmap.width);
875
876             // Don't waste time on empty glyphs
877             if(glyphs[c].w)
878             {
879                ComputeOutline(field, bigger, cellWidth, cellHeight, outlineSize, fade);
880                MeasureOutline(field, cellWidth, cellHeight, &x1, &y1, &x2, &y2);
881                if(x2 > x1) w = x2-x1+1;
882                if(y2 > y1) h = y2-y1+1;
883             }
884             else
885                memset(field, 0, cellWidth * cellHeight);
886
887             glyph->x = (c & 0xF) * cellWidth;
888             glyph->y = (c >> 4)  * cellHeight;
889             BlitOutline(picture, glyph->x, glyph->y, width, height, field, 0, 0, cellWidth, cellHeight, cellWidth);
890
891             glyph->glyphNo = glyphs[c].glyphNo;
892             glyph->scale = glyphs[c].scale;
893             glyph->left = glyphs[c].left + ox;
894             glyph->top = glyphs[c].top + oy;
895             if(w) { glyph->x += x1; glyph->left += x1; }
896             if(h) { glyph->y += y1; glyph->top  += y1; }
897             glyph->w = w;
898             glyph->h = h;
899             glyph->bx = glyphs[c].bx;
900             glyph->by = glyphs[c].by;
901             glyph->ax = glyphs[c].ax;
902             glyph->ay = glyphs[c].ay;
903          }
904
905    #if 0
906          {
907             int c;
908             char fileName[256];
909             static int fid = 0;
910             for(c = 0; c<256; c++)
911                outline.bitmap.palette[c] = ColorAlpha { 255, { (byte)c,(byte)c,(byte)c } };
912             outline.bitmap.pixelFormat = pixelFormat8;
913
914             /*
915             //strcpy(fileName, faceName);
916             if(flags)
917                strcat(fileName, "Bold");
918             */
919             sprintf(fileName, "font%d", fid++);
920             ChangeExtension(fileName, "pcx", fileName);
921
922             outline.bitmap.Save(fileName, null, 0);
923             outline.bitmap.pixelFormat = pixelFormatAlpha;
924          }
925
926          /*{
927             static int num = 0;
928             char fileName[MAX_LOCATION];
929
930             sprintf(fileName, "template%03d.png", num);
931             bitmap.Save(fileName, null, 0);
932             sprintf(fileName, "outline%03d.png", num++);
933             outline.bitmap.Save(fileName, null, 0);
934          }*/
935    #endif
936          if(displaySystem && displaySystem.pixelFormat != pixelFormat4) // TODO: Add none PixelFormat
937          {
938             displaySystem.Lock();
939 #if defined(__WIN32__)
940             // Is this check still required?
941             if(displaySystem.driver == class(OpenGLDisplayDriver) ||
942                displaySystem.driver == class(Direct3D8DisplayDriver) ||
943                displaySystem.driver == class(Direct3D9DisplayDriver))
944 #endif
945                bitmap.MakeDD(displaySystem);
946             displaySystem.Unlock();
947          }
948       }
949       delete bigger;
950       delete field;
951 #endif
952    }
953 }
954
955 #if !defined(ECERE_NOTRUETYPE)
956 static HB_ShaperItem shaper_item;
957
958 static uint * shaping(FontEntry entry, uint16 * string, int len, HB_Script script, int *numGlyphs, bool * rightToLeft)
959 {
960    static uint maxGlyphs = 0;
961    HB_Glyph * glyphs = shaper_item.glyphs;
962
963    shaper_item.kerning_applied = 0;
964    shaper_item.string = string;
965    shaper_item.stringLength = len;
966    shaper_item.item.script = script;
967    shaper_item.item.pos = 0;
968    shaper_item.item.length = shaper_item.stringLength;
969    if(script == HB_Script_Arabic || script == HB_Script_Hebrew || script == HB_Script_Thaana || script == HB_Script_Syriac)
970       shaper_item.item.bidiLevel = 1;
971    else
972       shaper_item.item.bidiLevel = 0;
973    shaper_item.shaperFlags = 0;
974    shaper_item.font = &entry.hbFont;
975    shaper_item.face = entry.hbFace;
976    shaper_item.num_glyphs = shaper_item.item.length;
977    shaper_item.glyphIndicesPresent = 0;
978    shaper_item.initialGlyphCount = 0;
979    shaper_item.num_glyphs = 0;
980    shaper_item.glyphs = null;
981
982    while(!HB_ShapeItem(&shaper_item))
983    {
984       if(shaper_item.num_glyphs > maxGlyphs)
985       {
986          maxGlyphs = shaper_item.num_glyphs;
987          glyphs = shaper_item.glyphs = renew0 glyphs HB_Glyph[maxGlyphs];
988          shaper_item.attributes   = renew0 shaper_item.attributes HB_GlyphAttributes[maxGlyphs];
989          shaper_item.advances     = renew0 shaper_item.advances HB_Fixed[maxGlyphs];
990          shaper_item.offsets      = renew0 shaper_item.offsets HB_FixedPoint[maxGlyphs];
991          shaper_item.log_clusters = renew0 shaper_item.log_clusters unsigned short[maxGlyphs];
992       }
993       else
994       {
995          shaper_item.glyphs = glyphs;
996          shaper_item.num_glyphs = maxGlyphs;
997       }
998   }
999
1000    *numGlyphs = shaper_item.num_glyphs;
1001    *rightToLeft = (bool)(shaper_item.item.bidiLevel % 2);
1002    return shaper_item.glyphs;
1003 }
1004
1005 /*
1006    delete shaper_item.glyphs;
1007    delete shaper_item.attributes;
1008    delete shaper_item.advances;
1009    delete shaper_item.offsets;
1010    delete shaper_item.log_clusters;
1011 */
1012 #endif
1013
1014 public class Font : struct
1015 {
1016    BinaryTree glyphPacks { };
1017    GlyphPack asciiPack { };
1018 #if !defined(ECERE_NOTRUETYPE)
1019    FontEntry fontEntries[MAX_FONT_LINK_ENTRIES];
1020 #endif
1021    float size;
1022    bool fakeItalic;
1023    int height;
1024    FontFlags flags;
1025    char faceName[512];
1026    DisplaySystem displaySystem;
1027    int ascent;
1028    float scale;
1029
1030    ~Font()
1031    {
1032 #if !defined(ECERE_NOTRUETYPE)
1033       GlyphPack pack;
1034       while((pack = (GlyphPack)glyphPacks.root))
1035       {
1036          glyphPacks.Remove(pack);
1037          delete pack;
1038       }
1039 #endif
1040    }
1041    public property int ascent
1042    {
1043       get { return (int)(this ? ascent * scale : 0); }
1044    }
1045 };
1046
1047 public class LFBDisplay : struct
1048 {
1049 public:
1050    Bitmap bitmap { };
1051    byte rgbLookup[32768];
1052    byte lightTable[256][LIGHTSTEPS];
1053    OldList updateBoxes;
1054    int x,y;
1055    bool selfManaged;
1056    void (* displayCallback)(Display display, Box updateBox);
1057 };
1058
1059 public class LFBSystem : struct
1060 {
1061 public:
1062    int format;
1063    ColorAlpha * palette;
1064    byte rgbLookup[32768];
1065
1066    LFBSystem()
1067    {
1068       if(!rgbLookupSet)
1069       {
1070          int c, r, g, b;
1071          ColorAlpha * palette = GetDefaultPalette();
1072          for(c = 16; c < 232; c++)
1073          {
1074             Color555 color = palette[c].color;
1075             for(r = Max(0, color.r - 2); r <= Min(31, color.r + 4); r++)
1076                for(g = Max(0, color.g - 2); g <= Min(31, color.g + 4); g++)
1077                   for(b = Max(0, color.b - 2); b <= Min(31, color.b + 4); b++)
1078                      defaultRGBLookup[r * 32 * 32 + g * 32 + b] = (byte)c;
1079          }
1080          for(c = 232; c < 246; c++)
1081          {
1082             Color555 color = palette[c].color;
1083             defaultRGBLookup[color] = (byte)c;
1084          }
1085          /*
1086          for(c = 246; c < 256; c++)
1087          {
1088             Color555 color = palette[c].color;
1089             defaultRGBLookup[color] = (byte)c;
1090          }
1091          for(c = 0; c < 16; c++)
1092          {
1093             Color555 color = palette[c].color;
1094             defaultRGBLookup[color] = (byte)c;
1095          }*/
1096          /*
1097          for(c = 0; c<32768; c++)
1098          {
1099             Color color = (Color)(Color555)c;
1100             defaultRGBLookup[c] = 16 + (color.r * 5 / 255) * 36 + (color.g * 5 / 255) * 6 + (color.b * 5 / 255);
1101             // defaultRGBLookup[c] = (byte)BestColorMatch(palette, 0, 255, (Color)(Color555)c);
1102          }
1103          */
1104          rgbLookupSet = true;
1105       }
1106    }
1107 };
1108
1109 public class LFBSurface : struct
1110 {
1111 public:
1112    // For compatibility with 3D drivers as well
1113    Font font;
1114    bool opaqueText;
1115    int xOffset;
1116    bool writingText;
1117    bool writingOutline;
1118
1119    Bitmap bitmap;
1120
1121    // Drawing attributes
1122    uint foreground, background;
1123    ColorAlpha foregroundRgb;
1124    uint16 stipple;
1125    byte drawingChar;
1126    byte * paletteShades;
1127    bool clearing;
1128 };
1129
1130 /*
1131 static int CompareHit(GLHitRecord * recordA, GLHitRecord * recordB, const void * nothing)
1132 {
1133    if(recordA->zMin > recordB->zMin)
1134       return  1;
1135    else if(recordA->zMin < recordB->zMin)
1136       return -1;
1137    else if(recordA > recordB)
1138       return 1;
1139    else if(recordA < recordB)
1140       return -1;
1141    else
1142       return  0;
1143 }
1144 */
1145
1146 #if defined(__WIN32__) && !defined(ECERE_NOTRUETYPE)
1147 struct FontData
1148 {
1149    char fileName[MAX_FILENAME];
1150    FontFlags flags;
1151    bool forgive;
1152 };
1153
1154 static int CALLBACK MyFontProc(ENUMLOGFONTEX * font, NEWTEXTMETRICEX *lpntme, int fontType, LPARAM lParam)
1155 {
1156    //if(fontType == TRUETYPE_FONTTYPE)
1157    {
1158       FontData * fontData = (FontData *) lParam;
1159       char * fileName = (char *)lParam;
1160       HKEY key;
1161       int weight = (fontData->flags.bold) ? FW_BOLD : FW_NORMAL;
1162       int italic = (fontData->flags.italic) ? 1 : 0;
1163       if((fontData->forgive || weight == font->elfLogFont.lfWeight) && italic == (font->elfLogFont.lfItalic != 0))
1164       {
1165          if(!RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts",0,KEY_READ,&key) ||
1166             !RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts",0,KEY_READ,&key))
1167          {
1168             int value = 0;
1169             while(true)
1170             {
1171                char entryName[1024];
1172                char fontFileName[1024];
1173                DWORD type;
1174                DWORD size = 1024;
1175                DWORD sizeFileName = 1024;
1176                char * occurence;
1177                if(RegEnumValue(key, value++, entryName, &size, null, (PDWORD)&type, (LPBYTE)fontFileName, &sizeFileName) != ERROR_SUCCESS)
1178                   break;
1179                if((occurence = SearchString(entryName, 0, (const char *)font->elfFullName, false, false)))
1180                {
1181                   int c;
1182                   for(c = (int)(occurence - entryName) - 1; c >= 0; c--)
1183                   {
1184                      char ch = entryName[c];
1185                      if(ch == '&') { c = -1; break; }
1186                      else if(ch != ' ') break;
1187                   }
1188                   if(c >= 0) continue;
1189                   for(c = (int)(occurence - entryName) + strlen((char *)font->elfFullName); ; c++)
1190                   {
1191                      char ch = entryName[c];
1192                      if(ch == 0 || ch == '&' || ch == '(') { c = -1; break; }
1193                      else if(ch != ' ') break;
1194                   }
1195
1196                   if(atoi(entryName + c))
1197                      c = -1;
1198                   if(c >= 0) continue;
1199
1200                   strcpy(fileName, fontFileName);
1201                   RegCloseKey(key);
1202                   return 0;
1203                }
1204             }
1205             RegCloseKey(key);
1206             return 1;
1207          }
1208       }
1209    }
1210    return 1;
1211 }
1212 #endif
1213
1214 #if !defined(ECERE_NOTRUETYPE)
1215 static int utf16BufferSize = 0;
1216 static uint16 * utf16 = null;
1217 #endif
1218
1219 public class LFBDisplayDriver : DisplayDriver
1220 {
1221    class_property(name) = "LFB";
1222
1223    bool CreateDisplaySystem(DisplaySystem displaySystem)
1224    {
1225       displaySystem.flags.memBackBuffer = true;
1226       // displaySystem.pixelFormat = pixelFormat888;
1227       return true;
1228    }
1229
1230    void DestroyDisplaySystem(DisplaySystem displaySystem)
1231    {
1232    }
1233
1234    void FreeBitmap(DisplaySystem displaySystem, Bitmap bitmap)
1235    {
1236       delete bitmap.picture;
1237       if(bitmap.allocatePalette)
1238          delete bitmap.palette;
1239    }
1240
1241    bool AllocateBitmap(DisplaySystem displaySystem, Bitmap bitmap, int width, int height, int stride, PixelFormat format, bool allocatePalette)
1242    {
1243       bool result = false;
1244       if(!stride)
1245       {
1246          switch(GetColorDepthShifts(format))
1247          {
1248             case 0: stride = (width + 3) & 0xFFFFFFFC; break;
1249             case 1: stride = (width + 1) & 0xFFFFFFFE; break;
1250             case 2: stride = width;                    break;
1251          }
1252       }
1253       bitmap.stride = stride;
1254       bitmap.width = width;
1255       bitmap.height = height;
1256       bitmap.size = (uint32) stride * (uint32)height;
1257       bitmap.sizeBytes = bitmap.size << GetColorDepthShifts(format);
1258       bitmap.pixelFormat = format;
1259       bitmap.transparent = false;
1260    /*
1261       surface.box.left = surface.box.top = 0;
1262       surface.box.right = width - 1;
1263       surface.box.bottom = height - 1;
1264    */
1265       bitmap.picture = new0 byte[bitmap.sizeBytes];
1266       if(bitmap.picture)
1267       {
1268          bitmap.allocatePalette = allocatePalette;
1269          if(allocatePalette)
1270          {
1271             bitmap.palette = new ColorAlpha[256];
1272             if(bitmap.palette)
1273             {
1274                CopyBytesBy4(bitmap.palette, GetDefaultPalette(), 256);
1275                result = true;
1276             }
1277          }
1278          else
1279          {
1280             bitmap.palette = GetDefaultPalette();
1281             result = true;
1282          }
1283       }
1284       if(!result)
1285          FreeBitmap(displaySystem, bitmap);
1286       return result;
1287    }
1288
1289    bool ConvertBitmap(DisplaySystem displaySystem, Bitmap src, PixelFormat format, ColorAlpha * palette)
1290    {
1291       bool result = false;
1292       LFBSystem lfbSystem = displaySystem ? displaySystem.driverData : null;
1293
1294       if(src)
1295       {
1296          if((src.pixelFormat == format) && (format != pixelFormat8 || !palette))
1297          {
1298             if(src.transparent && src.pixelFormat == pixelFormat888)
1299             {
1300                /*
1301                DWORD c;
1302                DWORD * picture = (DWORD *)src.picture;
1303
1304                for(c = 0; c<src.size; c++, picture++)
1305                {
1306                   if(*picture & 0xFFFFFF)
1307                      *picture =  *picture | 0xFF000000;
1308                   else
1309                      *picture = *picture & 0xFFFFFF;
1310                }
1311                */
1312             }
1313             result = true;
1314          }
1315          else
1316          {
1317             Bitmap bitmap { };
1318             if(bitmap.Allocate(null, src.width, src.height, 0, format, false))
1319             {
1320                if(format == pixelFormat8)
1321                {
1322                   if(palette)
1323                      bitmap.palette = palette;
1324                   else if(lfbSystem && lfbSystem.palette)
1325                      bitmap.palette = lfbSystem.palette;
1326                   else
1327                      bitmap.palette = src.palette;
1328                }
1329
1330                if(converters_table[src.pixelFormat][bitmap.pixelFormat])
1331                {
1332                   converters_table[src.pixelFormat][bitmap.pixelFormat](lfbSystem, src, bitmap);
1333                   bitmap.transparent = src.transparent;
1334                   bitmap.alphaBlend = src.alphaBlend && format != pixelFormat8;
1335                   delete src.picture;
1336                   if(src.palette != bitmap.palette)
1337                   {
1338                      if(src.allocatePalette)
1339                         delete src.palette;
1340                      src.allocatePalette = false;
1341                   }
1342                   src.picture = bitmap.picture;
1343                   src.palette = bitmap.palette;
1344                   src.stride = bitmap.stride;
1345                   src.size = bitmap.size;
1346                   src.sizeBytes = bitmap.sizeBytes;
1347                   src.pixelFormat = bitmap.pixelFormat;
1348
1349                   result = true;
1350                }
1351
1352                bitmap.palette = null;
1353                bitmap.picture = null;
1354             }
1355             delete bitmap;
1356          }
1357       }
1358       return result;
1359    }
1360
1361    void DestroyDisplay(Display display)
1362    {
1363       LFBDisplay lfbDisplay = display.driverData;
1364       delete lfbDisplay.bitmap.palette;
1365    }
1366
1367    bool CreateDisplay(Display display)
1368    {
1369       bool result = false;
1370       LFBDisplay lfbDisplay = display.driverData;
1371       if(!lfbDisplay)
1372       {
1373          lfbDisplay = display.driverData = LFBDisplay { };
1374          lfbDisplay.selfManaged = true;
1375          lfbDisplay.bitmap.pixelFormat = pixelFormatRGBA;
1376       }
1377
1378       if((lfbDisplay.bitmap.palette = new ColorAlpha[256]))
1379       {
1380          CopyBytesBy4(lfbDisplay.bitmap.palette, GetDefaultPalette(), 256);
1381          result = true;
1382       }
1383       return result;
1384    }
1385
1386    bool DisplaySize(Display display, int width, int height)
1387    {
1388       LFBDisplay lfbDisplay = display.driverData;
1389       //display.width = width;
1390       //display.height = height;
1391       lfbDisplay.bitmap.width = width;
1392       lfbDisplay.bitmap.height = height;
1393       /*
1394       lfbDisplay.updateBox.left = display.width;
1395       lfbDisplay.updateBox.top = display.height;
1396       lfbDisplay.updateBox.right = 0;
1397       lfbDisplay.updateBox.bottom = 0;
1398       */
1399
1400       if(lfbDisplay.selfManaged)
1401       {
1402          lfbDisplay.bitmap.picture = (byte *)renew lfbDisplay.bitmap.picture int[width * height];
1403          lfbDisplay.bitmap.stride = width;
1404       }
1405       lfbDisplay.bitmap.size = lfbDisplay.bitmap.stride * lfbDisplay.bitmap.height;
1406       return true;
1407    }
1408
1409    void DisplayPosition(Display display, int x, int y)
1410    {
1411       LFBDisplay lfbDisplay = display.driverData;
1412       lfbDisplay.x = x;
1413       lfbDisplay.y = y;
1414    }
1415
1416    void SetPalette(Display display, ColorAlpha * palette, bool colorMatch)
1417    {
1418       LFBDisplay lfbDisplay = display.driverData;
1419       if(colorMatch)
1420       {
1421          int c;
1422
1423          if(!palette)
1424          {
1425             LFBSystem lfbSystem = display.displaySystem ? display.displaySystem.driverData : null;
1426             palette = lfbSystem ? lfbSystem.palette : GetDefaultPalette();
1427             CopyBytes(lfbDisplay.rgbLookup, defaultRGBLookup, 32768);
1428          }
1429          else
1430             for(c = 0; c<32768; c++)
1431                lfbDisplay.rgbLookup[c] = (byte)BestColorMatch(palette, 1, 255, (Color)(Color555)c);
1432
1433          for(c=0; c<256; c++)
1434          {
1435             int i;
1436             for(i=0; i<LIGHTSTEPS; i++)
1437             {
1438                lfbDisplay.lightTable[c][i] = lfbDisplay.rgbLookup[(uint16)(Color555) Color {
1439                           (byte)(((uint16)palette[c].color.r * i) >> LIGHTSHIFT),
1440                           (byte)(((uint16)palette[c].color.g * i) >> LIGHTSHIFT),
1441                           (byte)(((uint16)palette[c].color.b * i) >> LIGHTSHIFT) }];
1442             }
1443          }
1444       }
1445       if(lfbDisplay.bitmap.palette)
1446          CopyBytesBy4(lfbDisplay.bitmap.palette, palette ? palette : GetDefaultPalette(), 256);
1447    }
1448
1449    void Update(Display display, Box updateBox)
1450    {
1451       LFBDisplay lfbDisplay = display.driverData;
1452       if(lfbDisplay.displayCallback)
1453       {
1454          if(updateBox == null)
1455          {
1456             Box box { 0,0, display.width,display.height };
1457             lfbDisplay.displayCallback(display, box);
1458          }
1459          else
1460             lfbDisplay.displayCallback(display, updateBox);
1461       }
1462    }
1463
1464    bool MakeDDBitmap(DisplaySystem displaySystem, Bitmap bitmap, bool mipMaps)
1465    {
1466       if(bitmap.pixelFormat != pixelFormatAlpha)
1467       {
1468          if(!ConvertBitmap(displaySystem, bitmap, /*bitmap.alphaBlend ? pixelFormat888 : */displaySystem.pixelFormat, null))
1469          {
1470             FreeBitmap(displaySystem, bitmap);
1471             return false;
1472          }
1473       }
1474       return true;
1475    }
1476
1477    void ReleaseSurface(Display display, Surface surface)
1478    {
1479       LFBSurface lfbSurface = surface.driverData;
1480       delete lfbSurface;
1481       surface.driverData = null;
1482    }
1483
1484    bool GetSurface(Display display, Surface surface, int x, int y, Box clip)
1485    {
1486       LFBDisplay lfbDisplay = display.driverData;
1487       LFBSurface lfbSurface = surface.driverData;
1488       if(!lfbSurface)
1489       {
1490          lfbSurface = surface.driverData = LFBSurface { };
1491       }
1492
1493       lfbSurface.bitmap = lfbDisplay.bitmap;
1494
1495       surface.offset.x = x;
1496       surface.offset.y = y;
1497       surface.box = clip;
1498       if(lfbDisplay.bitmap.pixelFormat == pixelFormatText)
1499       {
1500          surface.offset.x /= textCellW;
1501          surface.offset.y /= textCellH;
1502          surface.box.left /= textCellW;
1503          surface.box.top /= textCellH;
1504          surface.box.right /= textCellW;
1505          surface.box.bottom /= textCellH;
1506       }
1507
1508       /*
1509       lfbDisplay.updateBox.left = Min(x + clip.left, lfbDisplay.updateBox.left);
1510       lfbDisplay.updateBox.top = Min(y + clip.top, lfbDisplay.updateBox.top);
1511       lfbDisplay.updateBox.right = Max(x + clip.right, lfbDisplay.updateBox.right);
1512       lfbDisplay.updateBox.bottom = Max(y + clip.bottom, lfbDisplay.updateBox.bottom);
1513       */
1514
1515       surface.unclippedBox = surface.box;
1516       lfbSurface.drawingChar = 219;
1517       return true;
1518    }
1519
1520    bool GetBitmapSurface(DisplaySystem displaySystem, Surface surface, Bitmap bitmap, int x,int y, Box clip)
1521    {
1522       bool result = false;
1523       LFBSurface lfbSurface = surface.driverData;
1524       if(lfbSurface || (surface.driverData = lfbSurface = LFBSurface { }))
1525       {
1526          lfbSurface.bitmap = bitmap;
1527
1528          surface.offset.x = x;
1529          surface.offset.y = y;
1530          surface.box = clip;
1531          if(bitmap.pixelFormat == pixelFormatText)
1532          {
1533             surface.offset.x /= textCellW;
1534             surface.offset.y /= textCellH;
1535             surface.box.left /= textCellW;
1536             surface.box.top /= textCellH;
1537             surface.box.right /= textCellW;
1538             surface.box.bottom /= textCellH;
1539          }
1540
1541          surface.unclippedBox = *&surface.box;
1542          lfbSurface.drawingChar = 219;
1543
1544          result = true;
1545       }
1546       return result;
1547    }
1548
1549    void Clip(Display display, Surface surface, Box clip)
1550    {
1551       LFBSurface lfbSurface = surface.driverData;
1552       if(clip != null)
1553       {
1554          Box box = clip;
1555
1556          if(lfbSurface.bitmap.pixelFormat == pixelFormatText)
1557          {
1558             box.left /= textCellW;
1559             box.top /= textCellH;
1560             box.right /= textCellW;
1561             box.bottom /= textCellH;
1562          }
1563          box.Clip(surface.unclippedBox);
1564          surface.box = box;
1565       }
1566       else
1567          surface.box = surface.unclippedBox;
1568    }
1569
1570    void SetForeground(Display display, Surface surface, ColorAlpha color)
1571    {
1572       LFBDisplay lfbDisplay = display ? display.driverData : null;
1573       LFBSurface lfbSurface = surface.driverData;
1574       uint index;
1575       //if(display) color = color & 0xFFFFFF;
1576       lfbSurface.foregroundRgb = color;
1577
1578       if(lfbSurface.font && lfbDisplay)
1579       {
1580          index = lfbDisplay.rgbLookup[(uint16)(Color555)lfbSurface.foregroundRgb];
1581          lfbSurface.paletteShades = lfbDisplay.lightTable[index];
1582       }
1583
1584       switch(lfbSurface.bitmap.pixelFormat)
1585       {
1586          case pixelFormat8:
1587             if(display)
1588                lfbSurface.foreground = lfbDisplay.rgbLookup[(uint16)(Color555)color];
1589             else
1590                lfbSurface.foreground = BestColorMatch(lfbSurface.bitmap.palette,0,255,color);
1591             break;
1592          case pixelFormat444:  lfbSurface.foreground = (Color444)color; break;
1593          case pixelFormat555:  lfbSurface.foreground = (Color555)color; break;
1594          case pixelFormat565:  lfbSurface.foreground = (Color565)color; break;
1595          case pixelFormat888:  lfbSurface.foreground = color; break;
1596          case pixelFormatRGBA: lfbSurface.foreground = (ColorRGBA)color; break;
1597          case pixelFormatText:
1598             if(display)
1599                lfbSurface.foreground = BestColorMatch(lfbDisplay.bitmap.palette,0,15,color) << 8;
1600             else
1601                lfbSurface.foreground = BestColorMatch(lfbSurface.bitmap.palette,0,15,color) << 8;
1602             break;
1603       }
1604    }
1605
1606    void SetBackground(Display display, Surface surface, ColorAlpha color)
1607    {
1608       LFBDisplay lfbDisplay = display ? display.driverData : null;
1609       LFBSurface lfbSurface = surface.driverData;
1610       //color = color & 0xFFFFFF;
1611       switch(lfbSurface.bitmap.pixelFormat)
1612       {
1613          case pixelFormat8:
1614             if(display)
1615                lfbSurface.background = lfbDisplay.rgbLookup[(uint16)(Color555)color];
1616             else
1617                lfbSurface.background = BestColorMatch(lfbSurface.bitmap.palette,0,255,color);
1618             break;
1619          case pixelFormat444:  lfbSurface.background = (Color444)color; break;
1620          case pixelFormat555:  lfbSurface.background = (Color555)color; break;
1621          case pixelFormat565:  lfbSurface.background = (Color565)color; break;
1622          case pixelFormat888:  lfbSurface.background = color; break;
1623          case pixelFormatRGBA: lfbSurface.background = (ColorRGBA)color; break;
1624          case pixelFormatText:
1625             if(display)
1626                lfbSurface.background = BestColorMatch(lfbDisplay.bitmap.palette,0,15,color) << 12;
1627             else
1628                lfbSurface.background = BestColorMatch(lfbSurface.bitmap.palette,0,15,color) << 12;
1629             break;
1630       }
1631    }
1632
1633    ColorAlpha GetPixel(Display display, Surface surface, int x, int y)
1634    {
1635       LFBSurface lfbSurface = surface.driverData;
1636       if(lfbSurface.bitmap.pixelFormat == pixelFormatText)
1637       {
1638          x /= textCellW;
1639          y /= textCellH;
1640       }
1641       if((x <= surface.box.right) && (y <= surface.box.bottom) && (x >= surface.box.left) && (y >= surface.box.top))
1642       {
1643          x += surface.offset.x;
1644          y += surface.offset.y;
1645          if(lfbSurface.bitmap.picture)
1646          {
1647             switch(lfbSurface.bitmap.pixelFormat)
1648             {
1649                case pixelFormatText:
1650                case pixelFormat8:
1651                   if(!lfbSurface.bitmap.palette) return 0;
1652                   return lfbSurface.bitmap.palette[((byte *)lfbSurface.bitmap.picture)[(uint) y * lfbSurface.bitmap.stride + x]];
1653                case pixelFormat444:  return ((Color444 *)lfbSurface.bitmap.picture)[(uint) y * lfbSurface.bitmap.stride + x];
1654                case pixelFormat555:  return ((Color555 *)lfbSurface.bitmap.picture)[(uint) y * lfbSurface.bitmap.stride + x];
1655                case pixelFormat565:  return ((Color565 *)lfbSurface.bitmap.picture)[(uint) y * lfbSurface.bitmap.stride + x];
1656                case pixelFormat888:  return ((ColorAlpha *)lfbSurface.bitmap.picture)[(uint) y * lfbSurface.bitmap.stride+x];
1657             }
1658          }
1659       }
1660       return 0;
1661    }
1662
1663    void PutPixel(Display display, Surface surface,int x,int y)
1664    {
1665       LFBSurface lfbSurface = surface.driverData;
1666       if(lfbSurface.bitmap.pixelFormat == pixelFormatText)
1667       {
1668          x /= textCellW;
1669          y /= textCellH;
1670       }
1671       if((x <= surface.box.right) && (y <= surface.box.bottom) && (x >= surface.box.left) && (y >= surface.box.top))
1672       {
1673          x += surface.offset.x;
1674          y += surface.offset.y;
1675          if(lfbSurface.bitmap.picture)
1676          {
1677             switch(GetColorDepthShifts(lfbSurface.bitmap.pixelFormat))
1678             {
1679                case 0:
1680                   ((byte *)lfbSurface.bitmap.picture)[(uint) y * lfbSurface.bitmap.stride + x] = (byte)lfbSurface.foreground;
1681                   break;
1682                case 1:
1683                   ((uint16 *)lfbSurface.bitmap.picture)[(uint)y * lfbSurface.bitmap.stride + x] = (uint16)lfbSurface.foreground;
1684                   break;
1685                case 2:
1686                   if(((uint32 *)lfbSurface.bitmap.picture)[(uint32) y * lfbSurface.bitmap.stride + x] != (uint32)lfbSurface.foreground)
1687                      ((uint32 *)lfbSurface.bitmap.picture)[(uint32) y * lfbSurface.bitmap.stride + x] = (uint32)lfbSurface.foreground;
1688                   break;
1689             }
1690          }
1691       }
1692    }
1693
1694    void DrawLine(Display display, Surface surface, int x1, int y1, int x2, int y2)
1695    {
1696       LFBSurface lfbSurface = surface.driverData;
1697
1698       int xd, yd;
1699       int xu,yu;
1700       int errorterm;
1701       uint offset;
1702       uint color = lfbSurface.foreground;
1703       uint16 stipple = lfbSurface.stipple ? lfbSurface.stipple : 0xFFFF;
1704       bool invert = false;
1705       if(!lfbSurface.bitmap.picture) return;
1706       if(lfbSurface.bitmap.pixelFormat == pixelFormatText)
1707       {
1708          x1 /= textCellW;
1709          x2 /= textCellW;
1710          y1 /= textCellH;
1711          y2 /= textCellH;
1712          if(surface.textOpacity)
1713             color |= lfbSurface.background;
1714          color |= lfbSurface.drawingChar;
1715       }
1716       if(y1 == y2)
1717       {
1718          if(x1>x2) { int tmp = x2; x2 = x1; x1 = tmp; invert = true; }
1719
1720          if((y1>surface.box.bottom)||(y1<surface.box.top))return;
1721          if((x1>surface.box.right)||(x2<surface.box.left))return;
1722          if(x1<surface.box.left)x1=surface.box.left;
1723          if(x2>surface.box.right)x2=surface.box.right;
1724
1725          if(x2 < x1) return;
1726
1727          offset=(y1+surface.offset.y)*lfbSurface.bitmap.stride+x1+surface.offset.x;
1728          if(stipple != 0xFFFF)
1729          {
1730             int x;
1731             switch(GetColorDepthShifts(lfbSurface.bitmap.pixelFormat))
1732             {
1733                case 0:
1734                   for(x=x1; x<=x2; x++, offset++)
1735                   {
1736                      if(stipple & 0x8000)
1737                         ((byte *)lfbSurface.bitmap.picture)[offset]=(byte)color;
1738                      if(invert)
1739                         stipple = ((stipple & 0x7FFF)<<1) | ((stipple & 0x8000)>>15);
1740                      else
1741                         stipple = ((stipple & 0xFFFE)>>1) | ((stipple & 0x0001)<<15);
1742                   }
1743                   break;
1744                case 1:
1745                   for(x=x1; x<=x2; x++, offset++)
1746                   {
1747                      if(stipple & 0x8000)
1748                         ((uint16 *)lfbSurface.bitmap.picture)[offset] = (uint16)color;
1749                      if(invert)
1750                         stipple = ((stipple & 0x7FFF)<<1) | ((stipple & 0x8000)>>15);
1751                      else
1752                         stipple = ((stipple & 0xFFFE)>>1) | ((stipple & 0x0001)<<15);
1753                   }
1754                   break;
1755                case 2:
1756                   for(x=x1; x<=x2; x++, offset++)
1757                   {
1758                      if(stipple & 0x8000)
1759                         ((uint32 *)lfbSurface.bitmap.picture)[offset] = color;
1760                      if(invert)
1761                         stipple = ((stipple & 0x7FFF)<<1) | ((stipple & 0x8000)>>15);
1762                      else
1763                         stipple = ((stipple & 0xFFFE)>>1) | ((stipple & 0x0001)<<15);
1764                   }
1765                   break;
1766             }
1767          }
1768          else
1769          {
1770             if(lfbSurface.bitmap.pixelFormat != pixelFormatText || surface.textOpacity)
1771             {
1772                switch(GetColorDepthShifts(lfbSurface.bitmap.pixelFormat))
1773                {
1774                   case 0: FillBytes(((byte *)lfbSurface.bitmap.picture)+offset,(byte)color,x2-x1+1); break;
1775                   case 1: FillBytesBy2(((uint16 *)lfbSurface.bitmap.picture)+offset,(uint16)color,x2-x1+1); break;
1776                   case 2: FillBytesBy4(((uint32 *)lfbSurface.bitmap.picture)+offset,color,x2-x1+1); break;
1777                }
1778             }
1779             else
1780             {
1781                int x;
1782                for(x = x1; x <= x2; x++, offset++)
1783                {
1784                   ((uint16 *)lfbSurface.bitmap.picture)[offset] =
1785                      (((uint16 *)lfbSurface.bitmap.picture)[offset] & 0xF000) | (uint16)color;
1786                }
1787             }
1788          }
1789       }
1790       else if(x1 == x2)
1791       {
1792          int y;
1793
1794          if(y1>y2) { int tmp = y2; y2 = y1; y1 = tmp; invert = true; }
1795
1796          if((x1>surface.box.right)||(x1<surface.box.left))return;
1797          if((y1>surface.box.bottom)||(y2<surface.box.top))return;
1798          if(y1<surface.box.top)y1=surface.box.top;
1799          if(y2>surface.box.bottom)y2=surface.box.bottom;
1800
1801          offset=(y1+surface.offset.y)*lfbSurface.bitmap.stride+x1+surface.offset.x;
1802          switch(GetColorDepthShifts(lfbSurface.bitmap.pixelFormat))
1803          {
1804             case 0:
1805                for(y=y1; y<=y2; y++, offset+=lfbSurface.bitmap.stride)
1806                {
1807                   if(stipple & 0x8000)
1808                      ((byte *)lfbSurface.bitmap.picture)[offset]=(byte)color;
1809                   if(invert)
1810                      stipple = ((stipple & 0x7FFF)<<1) | ((stipple & 0x8000)>>15);
1811                   else
1812                      stipple = ((stipple & 0xFFFE)>>1) | ((stipple & 0x0001)<<15);
1813                }
1814                break;
1815             case 1:
1816                for(y=y1; y<=y2; y++, offset+=lfbSurface.bitmap.stride)
1817                {
1818                   if(stipple & 0x8000)
1819                   {
1820                      if(lfbSurface.bitmap.pixelFormat != pixelFormatText || surface.textOpacity)
1821                         ((uint16 *)lfbSurface.bitmap.picture)[offset]=(uint16)color;
1822                      else
1823                      {
1824                         ((uint16 *)lfbSurface.bitmap.picture)[offset] =
1825                            (((uint16 *)lfbSurface.bitmap.picture)[offset] & 0xF000) | (uint16)color;
1826                      }
1827                   }
1828                   if(invert)
1829                      stipple = ((stipple & 0x7FFF)<<1) | ((stipple & 0x8000)>>15);
1830                   else
1831                      stipple = ((stipple & 0xFFFE)>>1) | ((stipple & 0x0001)<<15);
1832                }
1833                break;
1834             case 2:
1835                if(stipple != 0xFFFF)
1836                {
1837                   for(y=y1; y<=y2; y++, offset+=lfbSurface.bitmap.stride)
1838                   {
1839                      if(stipple & 0x8000)
1840                         ((uint32*)lfbSurface.bitmap.picture)[offset]=color;
1841                      if(invert)
1842                         stipple = ((stipple & 0x7FFF)<<1) | ((stipple & 0x8000)>>15);
1843                      else
1844                         stipple = ((stipple & 0xFFFE)>>1) | ((stipple & 0x0001)<<15);
1845                   }
1846                }
1847                else
1848                {
1849                   for(y=y1; y<=y2; y++, offset+=lfbSurface.bitmap.stride)
1850                      ((uint32*)lfbSurface.bitmap.picture)[offset]=color;
1851                }
1852                break;
1853          }
1854       }
1855       else
1856       {
1857          if(x2 >= x1)
1858          {
1859             if(x1 < surface.box.left)
1860             {
1861                if(x2 < surface.box.left)
1862                   return;
1863                y1 += (y2 - y1) * (surface.box.left - x1) / (x2 - x1);
1864                x1 = surface.box.left;
1865             }
1866             if(x2 > surface.box.right)
1867             {
1868                if(x1 > surface.box.right)
1869                   return;
1870                y2 -= (y2 - y1) * (x2 - surface.box.right) / (x2 - x1);
1871                x2 = surface.box.right;
1872             }
1873             if(y2 >= y1)
1874             {
1875                if(y1 < surface.box.top)
1876                {
1877                   if(y2 < surface.box.top)
1878                      return;
1879                   x1 += (x2 - x1) * (surface.box.top - y1) / (y2 - y1);
1880                   y1 = surface.box.top;
1881                }
1882                if(y2 > surface.box.bottom)
1883                {
1884                   if(y1 > surface.box.bottom)
1885                      return;
1886                   x2 -= (x2 - x1) * (y2 - surface.box.bottom) / (y2 - y1);
1887                   y2 = surface.box.bottom;
1888                }
1889             }
1890             else
1891             {
1892                if(y1 > surface.box.bottom)
1893                {
1894                   if(y2 > surface.box.bottom)
1895                      return;
1896                   x1 -= (x1 - x2) * (y1 - surface.box.bottom) / (y1 - y2);
1897                   y1 = surface.box.bottom;
1898                }
1899                if(y2 < surface.box.top)
1900                {
1901                   if(y1 < surface.box.top)
1902                      return;
1903                   x2 += (x1 - x2) * (surface.box.top - y2) / (y1 - y2);
1904                   y2 = surface.box.top;
1905                }
1906             }
1907          }
1908          else
1909          {
1910             if(x1 > surface.box.right)
1911             {
1912                if(x2 > surface.box.right)
1913                   return;
1914                y1 -= (y1 - y2) * (x1 - surface.box.right) / (x1 - x2);
1915                x1 = surface.box.right;
1916             }
1917             if(x2 < surface.box.left)
1918             {
1919                if(x1 < surface.box.left)
1920                   return;
1921                y2 += (y1 - y2) * (surface.box.left - x2) / (x1 - x2);
1922                x2 = surface.box.left;
1923             }
1924             if(y2 >= y1)
1925             {
1926                if(y1 < surface.box.top)
1927                {
1928                   if(y2 < surface.box.top)
1929                      return;
1930                   x1 += (x2 - x1) * (surface.box.top - y1) / (y2 - y1);
1931                   y1 = surface.box.top;
1932                }
1933                if(y2 > surface.box.bottom)
1934                {
1935                   if(y1 > surface.box.bottom)
1936                      return;
1937                   x2 -= (x2 - x1) * (y2 - surface.box.bottom) / (y2 - y1);
1938                   y2 = surface.box.bottom;
1939                }
1940             }
1941             else
1942             {
1943                if(y1 > surface.box.bottom)
1944                {
1945                   if(y2 > surface.box.bottom)
1946                      return;
1947                   x1 -= (x1 - x2) * (y1 - surface.box.bottom) / (y1 - y2);
1948                   y1 = surface.box.bottom;
1949                }
1950                if(y2 < surface.box.top)
1951                {
1952                   if(y1 < surface.box.top)
1953                      return;
1954                   x2 += (x1 - x2) * (surface.box.top - y2) / (y1 - y2);
1955                   y2 = surface.box.top;
1956                }
1957             }
1958          }
1959
1960          xd=x2-x1;
1961          yd=y2-y1;
1962
1963          if(xd<0)
1964          {
1965             xd=-xd;
1966             xu=-1;
1967          }
1968          else
1969             xu=1;
1970          if(yd<0)
1971          {
1972             yd=-yd;
1973             yu=-(int)lfbSurface.bitmap.stride;
1974          }
1975          else
1976             yu=lfbSurface.bitmap.stride;
1977
1978          offset=(y1+surface.offset.y)*lfbSurface.bitmap.stride+x1+surface.offset.x;
1979          errorterm=0;
1980
1981          if(xd>yd)
1982          {
1983             int i, length=xd;
1984             for(i=0; i<=length; i++)
1985             {
1986                if(stipple & 0x8000)
1987                   switch(GetColorDepthShifts(lfbSurface.bitmap.pixelFormat))
1988                   {
1989                      case 0: ((byte *)lfbSurface.bitmap.picture)[offset]=(byte)color; break;
1990                      case 1: ((uint16 *)lfbSurface.bitmap.picture)[offset]=(uint16)color; break;
1991                      case 2: ((uint32*)lfbSurface.bitmap.picture)[offset]=(uint32)color; break;
1992                   }
1993                offset+=xu;
1994                errorterm+=yd;
1995                if(errorterm>=xd)
1996                {
1997                   errorterm-=xd;
1998                   offset+=yu;
1999                }
2000                stipple = ((stipple & 0x7FFF)<<1) | ((stipple & 0x8000)>>15);
2001             }
2002          }
2003          else
2004          {
2005             int i, length=yd;
2006             for(i=0; i<=length; i++)
2007             {
2008                if(stipple & 0x8000)
2009                   switch(GetColorDepthShifts(lfbSurface.bitmap.pixelFormat))
2010                   {
2011                      case 0: ((byte *)lfbSurface.bitmap.picture)[offset]=(byte)color; break;
2012                      case 1: ((uint16 *)lfbSurface.bitmap.picture)[offset]=(uint16)color; break;
2013                      case 2: ((uint32*)lfbSurface.bitmap.picture)[offset]=(uint32)color; break;
2014                   }
2015                offset+=yu;
2016                errorterm+=xd;
2017                if(errorterm>=yd)
2018                {
2019                   errorterm-=yd;
2020                   offset+=xu;
2021                }
2022             }
2023          }
2024       }
2025    }
2026
2027    void Rectangle(Display display, Surface surface,int x1,int y1,int x2,int y2)
2028    {
2029       DrawLine(display, surface,x1,y1,x2,y1);
2030       DrawLine(display, surface,x2,y1,x2,y2);
2031       DrawLine(display, surface,x2,y2,x1,y2);
2032       DrawLine(display, surface,x1,y2,x1,y1);
2033    }
2034
2035    #if !defined(__GNUC__)
2036    /*
2037    void memset_32_aligned(void *buf, int val, int dwords)
2038    {
2039             // Qword align
2040             if ((int)(buf) & 4)
2041             {
2042                     *((uint32 *)(buf)) = val;
2043                     buf = ((uint32 *)(buf))+1;
2044                     dwords--;
2045             }
2046
2047             if (dwords > 1)
2048             {
2049                     __asm {
2050                             cld
2051                             mov   edi,  buf
2052                             mov   ecx,  dwords
2053                             shr       ecx,  1
2054                             mov   eax,  val
2055                             movd  mm0,  eax
2056                             movd  mm1,  eax
2057                             psllq mm1,  32
2058                             por   mm0,  mm1
2059                             align 16
2060             repeat:
2061                             movq [edi], mm0
2062                             add   edi,  8
2063                             loop  repeat
2064                             emms
2065                     };
2066             }
2067
2068             // Final dword
2069             if (dwords & 1) *((int*)(buf)) = val;
2070    }*/
2071
2072    //#define USE_SSE
2073
2074 /*
2075    void memset_32_aligned(uint32 *buf, uint32 val, uint32 dwords)
2076    {
2077       dwords <<= 2;
2078    #ifdef USE_SSE
2079       if(((uint32)buf) & 0x7F)
2080       {
2081          for( ; ((uint32)buf) & 0x7F && dwords; buf++)
2082          {
2083             *buf = val;
2084             dwords--;
2085          }
2086       }
2087       if(dwords)
2088    #endif
2089       __asm
2090       {
2091          mov edi, buf
2092          mov eax, val
2093          mov ecx, dwords
2094
2095          mov edx,ecx
2096    #ifdef USE_SSE
2097          shr ecx,7
2098    #else
2099          shr ecx,6
2100    #endif
2101          mov ebx,ecx
2102    #ifdef USE_SSE
2103          shl ebx,7
2104    #else
2105          shl ebx,6
2106    #endif
2107          sub edx,ebx                            ; edx holds # of overflow bytes
2108
2109    #ifdef USE_SSE
2110            mov [edi],eax
2111            mov [edi+4],eax
2112          mov [edi+8],eax
2113          mov [edi+12],eax
2114          movdqa xmm0, [edi]
2115    #else
2116          mov [edi],eax
2117            mov [edi+4],eax
2118          movq mm0, [edi]
2119    #endif
2120            cmp ecx,0
2121            je doneloop
2122    setloop:
2123
2124    #ifdef USE_SSE
2125          movdqa [edi],xmm0
2126          movdqa [edi+16],xmm0
2127          movdqa [edi+32],xmm0
2128          movdqa [edi+48],xmm0
2129          movdqa [edi+64],xmm0
2130          movdqa [edi+80],xmm0
2131          movdqa [edi+96],xmm0
2132          movdqa [edi+112],xmm0
2133          add edi,8*16
2134    #else
2135          movq [edi],mm0
2136          movq [edi+8],mm0
2137          movq [edi+16],mm0
2138          movq [edi+24],mm0
2139          movq [edi+32],mm0
2140          movq [edi+40],mm0
2141          movq [edi+48],mm0
2142          movq [edi+56],mm0
2143          add edi,8*8
2144    #endif
2145          dec ecx
2146            jnz setloop
2147
2148    doneloop:
2149            mov ecx,edx
2150            shr ecx,2
2151            rep stosd
2152
2153            emms
2154       };
2155    }
2156    void memset_32(void *buf, uint32 val, uint32 dwords)
2157    {
2158       int align = 0;
2159       if ((uint32)(buf) & 3)
2160       {
2161          align = 4;
2162          dwords--;
2163
2164          if (((uint32)(buf) & 1))
2165          {
2166             *(byte *)(buf) = (byte)(val&0xFF);
2167             buf = ((byte *)(buf))+1;
2168             val = ((val& 0xFF) << 24) || ((val& 0xFFFFFF00) >> 8);
2169             align --;
2170          }
2171          if (((uint32)(buf) & 2))
2172          {
2173             *(uint16 *)(buf) = (uint16)(val&0xFFFF);
2174             buf = ((uint16 *)(buf))+1;
2175             val = ((val& 0xFFFF) << 16) || ((val& 0xFFFF0000) >> 16);
2176             align-=2;
2177          }
2178       }
2179       memset_32_aligned(buf,val,dwords);
2180       if (align)
2181       {
2182          if (align == 1)
2183          {
2184             *(byte *)(buf) = (byte)(val&0xFF);
2185          }
2186          else
2187          {
2188             *(uint16 *)(buf) = (uint16)(val&0xFFFF);
2189             if (align & 1) *((byte *)(buf)+2) = (byte)((val>>16)&0xFF);
2190          }
2191       }
2192    }
2193    */
2194    #endif
2195
2196    void Area(Display display, Surface surface,int x1,int y1,int x2,int y2)
2197    {
2198       LFBSurface lfbSurface = surface.driverData;
2199       uint32 color = lfbSurface.background;
2200
2201       if(lfbSurface.bitmap.pixelFormat == pixelFormatText)
2202       {
2203          color |= lfbSurface.foreground | lfbSurface.drawingChar;
2204          x1 /= textCellW;
2205          x2 /= textCellW;
2206          y1 /= textCellH;
2207          y2 /= textCellH;
2208       }
2209       if(x1>x2) { int tmp = x2; x2 = x1; x1 = tmp; }
2210
2211       if(x1<surface.box.left)  x1=surface.box.left;
2212       if(x2>surface.box.right) x2=surface.box.right;
2213       if(y1<surface.box.top)   y1=surface.box.top;
2214       if(y2>surface.box.bottom)  y2=surface.box.bottom;
2215
2216       if(x2>=x1 && y2>=y1)
2217       {
2218          int w,y;
2219          byte * theOffset;
2220
2221          w = x2-x1+1;
2222          if(w<1) return;
2223
2224          x1 += surface.offset.x;
2225          x2 += surface.offset.x;
2226          y1 += surface.offset.y;
2227          y2 += surface.offset.y;
2228          if(lfbSurface.bitmap.picture)
2229          {
2230             if(!surface.writeColor)
2231             {
2232                ColorAlpha * picture = (((ColorAlpha *)lfbSurface.bitmap.picture) + y1 * lfbSurface.bitmap.stride + x1);
2233                for(y = y1; y<= y2; y++)
2234                {
2235                   int c;
2236                   for(c = 0; c < w; c++, picture++)
2237                      if(!picture->a)
2238                         picture->a = (byte)((color & 0xFF000000) >> 24);
2239                   picture += lfbSurface.bitmap.stride - w;
2240                }
2241             }
2242             else
2243             {
2244                if(!surface.blend || surface.background.a == 255 || lfbSurface.clearing)
2245                {
2246                   switch(GetColorDepthShifts(lfbSurface.bitmap.pixelFormat))
2247                   {
2248                      case 0:
2249                         theOffset = ((byte *)lfbSurface.bitmap.picture) + y1 * lfbSurface.bitmap.stride + x1;
2250                         for(y = y1; y<= y2; y++)
2251                         {
2252                            FillBytes(theOffset,(byte)color,w);
2253                            theOffset += lfbSurface.bitmap.stride;
2254                         }
2255                         break;
2256                      case 1:
2257                         theOffset = (byte *) (((uint16 *)lfbSurface.bitmap.picture) + y1 * lfbSurface.bitmap.stride + x1);
2258                         for(y = y1; y<= y2; y++)
2259                         {
2260                            FillBytesBy2((uint16 *) theOffset,(uint16)color,w);
2261                            theOffset += lfbSurface.bitmap.stride * sizeof(uint16);
2262                         }
2263                         break;
2264                      case 2:
2265                         theOffset = (byte *) (((uint32 *)lfbSurface.bitmap.picture) + y1 * lfbSurface.bitmap.stride + x1);
2266                         for(y = y1; y<= y2; y++)
2267                         {
2268          #if defined(__GNUC__)
2269                            FillBytesBy4((uint32 *) theOffset,color,w);
2270          #else
2271                            memset_32((uint32 *) theOffset,color,w);
2272          #endif
2273                            theOffset += lfbSurface.bitmap.stride * sizeof(uint32);
2274
2275                         }
2276                         /*
2277                         y = y2-y1+1;
2278                         {
2279                            int bla = (lfbSurface.bitmap.stride - w) * sizeof(uint32);
2280                            //memset_32((uint32 *) theOffset,color,w);
2281                            /-*_asm
2282                            {
2283                               push edi
2284                               push ecx
2285                               push eax
2286                               push ebx
2287                               push edx
2288
2289                               mov ebx,bla
2290
2291                               mov edi,theOffset
2292                               mov eax,color
2293                               mov edx,y
2294                               mov ecx,w
2295
2296                               start:
2297                                  push ecx
2298
2299                                  rep stosd
2300                                  add edi,ebx
2301                                  pop ecx
2302                                  dec edx
2303                                  jnz start
2304                               pop edx
2305                               pop ebx
2306                               pop eax
2307                               pop ecx
2308                               pop edi
2309                            };
2310                         break;
2311                         }*/
2312                   }
2313                }
2314                else
2315                {
2316                   switch(GetColorDepthShifts(lfbSurface.bitmap.pixelFormat))
2317                   {
2318                      case 0:
2319                         theOffset = ((byte *)lfbSurface.bitmap.picture) + y1 * lfbSurface.bitmap.stride + x1;
2320                         for(y = y1; y<= y2; y++)
2321                         {
2322                            // TODO: IMPLEMENT THIS
2323                            FillBytes(theOffset,(byte)color,w);
2324                            theOffset += lfbSurface.bitmap.stride;
2325                         }
2326                         break;
2327                      case 1:
2328                      {
2329                         uint16 * dest = (((uint16 *)lfbSurface.bitmap.picture) + y1 * lfbSurface.bitmap.stride + x1);
2330                         ColorAlpha c = surface.background;
2331                         int a = c.a;
2332                         int cr = c.color.r;
2333                         int cg = c.color.g;
2334                         int cb = c.color.b;
2335                         PixelFormat pixelFormat = lfbSurface.bitmap.pixelFormat;
2336
2337                         for(y = y1; y <= y2; y++)
2338                         {
2339                            int c;
2340                            for(c = 0; c < w; c++, dest++)
2341                            {
2342                               Color destColor = 0;
2343                               if(pixelFormat == pixelFormat565)      { destColor = (Color)*(Color565 *)dest; }
2344                               else if(pixelFormat == pixelFormat555) { destColor = (Color)*(Color555 *)dest; }
2345                               else if(pixelFormat == pixelFormat444) { destColor = (Color)*(Color444 *)dest; }
2346                               {
2347                                  int r = a * cr / 255 + ((255 - a) * destColor.r / 255);
2348                                  int g = a * cg / 255 + ((255 - a) * destColor.g / 255);
2349                                  int b = a * cb / 255 + ((255 - a) * destColor.b / 255);
2350
2351                                  if(r > 255) r = 255;
2352                                  if(g > 255) g = 255;
2353                                  if(b > 255) b = 255;
2354
2355                                  destColor = { (byte)r, (byte)g, (byte)b };
2356
2357                                  if(pixelFormat == pixelFormat565)      { *dest = (Color565)destColor; }
2358                                  else if(pixelFormat == pixelFormat555) { *dest = (Color555)destColor; }
2359                                  else if(pixelFormat == pixelFormat444) { *dest = (Color444)destColor; }
2360                               }
2361                            }
2362                            dest += (lfbSurface.bitmap.stride - w);
2363                         }
2364                         break;
2365                      }
2366                      case 2:
2367                      {
2368                         ColorAlpha * dest = (ColorAlpha *)(((uint32 *)lfbSurface.bitmap.picture) + y1 * lfbSurface.bitmap.stride + x1);
2369                         AlphaWriteMode alphaWrite = surface.alphaWrite;
2370                         ColorAlpha c = surface.background;
2371                         int a = c.a;
2372                         int cr = c.color.r;
2373                         int cg = c.color.g;
2374                         int cb = c.color.b;
2375                         for(y = y1; y <= y2; y++)
2376                         {
2377                            int c;
2378                            for(c = 0; c < w; c++, dest++)
2379                            {
2380                               int dr = dest->color.r;
2381                               int dg = dest->color.g;
2382                               int db = dest->color.b;
2383                               int r = a * cr / 255 + ((255 - a) * dr / 255);
2384                               int g = a * cg / 255 + ((255 - a) * dg / 255);
2385                               int b = a * cb / 255 + ((255 - a) * db / 255);
2386
2387                               if(r > 255) r = 255;
2388                               if(g > 255) g = 255;
2389                               if(b > 255) b = 255;
2390                               dest->color = { (byte)r, (byte)g, (byte)b };
2391
2392                               if(alphaWrite == blend)
2393                               {
2394                                  int ca = (int)(a + ((255 - a) * dest->a / 255));
2395                                  if(ca > 255) ca = 255;
2396                                  dest->a = (byte)ca;
2397                               }
2398                               else if(alphaWrite)
2399                                  dest->a = (byte)a;
2400                            }
2401                            dest += (lfbSurface.bitmap.stride - w);
2402                         }
2403                      }
2404                   }
2405                }
2406             }
2407          }
2408       }
2409    }
2410    void Clear(Display display, Surface surface, ClearType type)
2411    {
2412       LFBSurface lfbSurface = surface.driverData;
2413
2414       lfbSurface.clearing = true;
2415       if(surface.offset.x == 0 && surface.offset.y == 0 &&
2416          surface.box.left == 0 && surface.box.top  == 0 &&
2417          surface.box.right == surface.width-1 &&
2418          surface.box.bottom  == surface.height-1)
2419       {
2420          uint32 color = /*0xFF000000 | */lfbSurface.background;
2421          if(type != depthBuffer)
2422          {
2423             if(lfbSurface.bitmap.stride != surface.width)
2424                Area(display, surface,surface.box.left,surface.box.top,surface.box.right,surface.box.bottom);
2425             else
2426             {
2427                switch(GetColorDepthShifts(lfbSurface.bitmap.pixelFormat))
2428                {
2429                   case 0:
2430                      FillBytes(lfbSurface.bitmap.picture, (byte)color, lfbSurface.bitmap.size);
2431                      break;
2432                   case 1: FillBytesBy2((uint16 *)lfbSurface.bitmap.picture, (uint16)color, lfbSurface.bitmap.size); break;
2433                   case 2: FillBytesBy4((uint32 *)lfbSurface.bitmap.picture, color, lfbSurface.bitmap.size); break;
2434                }
2435             }
2436          }
2437    /*
2438          if((flags & CLEAR_Z) && zbuffer)
2439             FillBytesBy4((DWORD *)zbuffer,0,(sizeof(float)*(DWORD)display.width * display.Height)>>2);
2440    */
2441       }
2442       else
2443       {
2444          if(type != depthBuffer)
2445             Area(display, surface,surface.box.left,surface.box.top,surface.box.right,surface.box.bottom);
2446    /*
2447          if((flags & CLEAR_Z))
2448          {
2449             int y;
2450             uint32 w = surface.box.right-surface.box.left+1;
2451             float * offset = zbuffer + ((surface.box.top +surface.offset.y) * (DWORD)DISPLAY.Width)
2452                              +   surface.box.left+surface.offset.x;
2453             for(y = surface.box.top; y<= surface.box.bottom; y++)
2454             {
2455                FillBytesBy4((uint32 *) offset,0,(sizeof(float)>>2)*w);
2456                offset += DISPLAY.Width;
2457             }
2458          }
2459    */
2460       }
2461       lfbSurface.clearing = false;
2462    }
2463
2464    void Blit(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h)
2465    {
2466       LFBSurface lfbSurface = surface.driverData;
2467       bool flip = false;
2468
2469       if(surface.box.right < surface.box.left || surface.box.bottom < surface.box.top || !src.picture) return;
2470
2471       if(w < 0) { w = -w; flip = true; }
2472
2473       //Clip against the edges of the source
2474       if(sx<0)
2475       {
2476          dx+=-sx;
2477          w-=-sx;
2478          sx=0;
2479       }
2480       if(sy<0)
2481       {
2482          dy+=0-sy;
2483          h-=0-sy;
2484          sy=0;
2485       }
2486       if(sx+w>src.width-1)
2487          w-=sx+w-(src.width-1)-1;
2488       if(sy+h>src.height-1)
2489          h-=sy+h-(src.height-1)-1;
2490       //Clip against the edges of the destination
2491       if(dx<surface.box.left)
2492       {
2493          if(!flip) sx+=surface.box.left-dx;
2494          w-=surface.box.left-dx;
2495          dx=surface.box.left;
2496       }
2497       if(dy<surface.box.top)
2498       {
2499          sy+=surface.box.top-dy;
2500          h-=surface.box.top-dy;
2501          dy=surface.box.top;
2502       }
2503       if((dx+w)>surface.box.right)
2504       {
2505          if(flip) sx+=(uint32)(dx+w)-surface.box.right-1;
2506          w-=((uint32)(dx+w)-surface.box.right-1);
2507       }
2508       if((dy+h)>surface.box.bottom)
2509          h-=((dy+h)-surface.box.bottom-1);
2510       if((w<=0)||(h<=0))
2511          return;
2512
2513       dx += surface.offset.x;
2514       dy += surface.offset.y;
2515
2516       if(lfbSurface.bitmap.picture)
2517       {
2518          AlphaWriteMode alphaWrite = surface.alphaWrite;
2519          if(src.alphaBlend && surface.blend)
2520          {
2521             int x, y;
2522             if(src.pixelFormat == pixelFormatAlpha)
2523             {
2524                if(lfbSurface.bitmap.pixelFormat == pixelFormat888)
2525                {
2526                   ColorAlpha * picture = ((ColorAlpha *)lfbSurface.bitmap.picture) + (lfbSurface.bitmap.stride * dy) + dx;
2527                   byte * source = ((byte *)src.picture) + (src.stride * sy) + sx;
2528                   ColorAlpha color = lfbSurface.writingText ? surface.foreground : surface.blitTint;
2529                   for(y = 0; y < h; y++)
2530                   {
2531                      for(x = 0; x < w; x++, picture++, source++)
2532                      {
2533                         int a = *source * color.a;
2534                         ColorAlpha dest = *picture;
2535                         int r = (a * color.color.r + ((255 * 255 - a) * dest.color.r)) / (255 * 255);
2536                         int g = (a * color.color.g + ((255 * 255 - a) * dest.color.g)) / (255 * 255);
2537                         int b = (a * color.color.b + ((255 * 255 - a) * dest.color.b)) / (255 * 255);
2538                         if(r > 255) r = 255;
2539                         if(g > 255) g = 255;
2540                         if(b > 255) b = 255;
2541                         picture->color = { (byte)r, (byte)g, (byte)b };
2542                         if(alphaWrite == blend)
2543                         {
2544                            int ca = (a * 255 + (255 * 255 - a) * dest.a) / (255 * 255);
2545                            if(ca > 255) ca = 255;
2546                            picture->a = (byte)ca;
2547                         }
2548                         else if(alphaWrite)
2549                            picture->a = (byte)(a / 255);
2550                      }
2551                      picture += lfbSurface.bitmap.stride - w;
2552                      source += src.stride - w;
2553                   }
2554                }
2555                else if(lfbSurface.bitmap.pixelFormat == pixelFormat555)
2556                {
2557                   Color555 * picture = ((Color555 *)lfbSurface.bitmap.picture) + (lfbSurface.bitmap.stride * dy) + dx;
2558                   byte * source = ((byte *)src.picture) + (src.stride * sy) + sx;
2559                   ColorAlpha color = lfbSurface.writingText ? surface.foreground : surface.blitTint;
2560                   for(y = 0; y < h; y++)
2561                   {
2562                      for(x = 0; x < w; x++, picture++, source++)
2563                      {
2564                         int a = *source * color.a;
2565                         Color dest = *picture;
2566                         int r = (a * color.color.r + ((255 * 255 - a) * dest.r)) / (255 * 255);
2567                         int g = (a * color.color.g + ((255 * 255 - a) * dest.g)) / (255 * 255);
2568                         int b = (a * color.color.b + ((255 * 255 - a) * dest.b)) / (255 * 255);
2569                         if(r > 255) r = 255;
2570                         if(g > 255) g = 255;
2571                         if(b > 255) b = 255;
2572                         *picture = Color { (byte)r, (byte)g, (byte)b };
2573                      }
2574                      picture += lfbSurface.bitmap.stride - w;
2575                      source += src.stride - w;
2576                   }
2577                }
2578                else if(lfbSurface.bitmap.pixelFormat == pixelFormat565)
2579                {
2580                   Color565 * picture = ((Color565 *)lfbSurface.bitmap.picture) + (lfbSurface.bitmap.stride * dy) + dx;
2581                   byte * source = ((byte *)src.picture) + (src.stride * sy) + sx;
2582                   ColorAlpha color = lfbSurface.writingText ? surface.foreground : surface.blitTint;
2583                   for(y = 0; y < h; y++)
2584                   {
2585                      for(x = 0; x < w; x++, picture++, source++)
2586                      {
2587                         int a = *source * color.a;
2588                         Color dest = *picture;
2589                         int r = (a * color.color.r + ((255 * 255 - a) * dest.r)) / (255 * 255);
2590                         int g = (a * color.color.g + ((255 * 255 - a) * dest.g)) / (255 * 255);
2591                         int b = (a * color.color.b + ((255 * 255 - a) * dest.b)) / (255 * 255);
2592                         if(r > 255) r = 255;
2593                         if(g > 255) g = 255;
2594                         if(b > 255) b = 255;
2595                         *picture = Color { (byte)r, (byte)g, (byte)b };
2596                      }
2597                      picture += lfbSurface.bitmap.stride - w;
2598                      source += src.stride - w;
2599                   }
2600                }
2601             }
2602             else
2603             {
2604                ColorAlpha * source = ((ColorAlpha *)src.picture) + (src.stride * sy) + sx;
2605                if(lfbSurface.bitmap.pixelFormat == pixelFormat888)
2606                {
2607                   ColorAlpha * picture = ((ColorAlpha *)lfbSurface.bitmap.picture) + (lfbSurface.bitmap.stride * dy) + dx;
2608                   for(y = 0; y < h; y++)
2609                   {
2610                      for(x = 0; x < w; x++, picture++, source++)
2611                      {
2612                         ColorAlpha src = *source;
2613                         ColorAlpha dest = *picture;
2614                         int r = src.a * src.color.r / 255 + ((255 - src.a) * dest.color.r / 255);
2615                         int g = src.a * src.color.g / 255 + ((255 - src.a) * dest.color.g / 255);
2616                         int b = src.a * src.color.b / 255 + ((255 - src.a) * dest.color.b / 255);
2617                         if(r > 255) r = 255;
2618                         if(g > 255) g = 255;
2619                         if(b > 255) b = 255;
2620                         picture->color = { (byte)r, (byte)g, (byte)b };
2621                         if(alphaWrite == blend)
2622                         {
2623                            int a = src.a + ((255 - src.a) * dest.a / 255);
2624                            if(a > 255) a = 255;
2625                            picture->a = (byte)a;
2626                         }
2627                         else if(alphaWrite)
2628                            picture->a = src.a;
2629                      }
2630                      picture += lfbSurface.bitmap.stride - w;
2631                      source += src.stride - w;
2632                   }
2633                }
2634                else if(lfbSurface.bitmap.pixelFormat == pixelFormat565)
2635                {
2636                   Color565 * picture = ((Color565 *)lfbSurface.bitmap.picture) + (lfbSurface.bitmap.stride * dy) + dx;
2637                   for(y = 0; y < h; y++)
2638                   {
2639                      for(x = 0; x < w; x++, picture++, source++)
2640                      {
2641                         ColorAlpha src = *source;
2642                         Color565 dest = *picture;
2643                         int r = src.a * src.color.r * 31 / 255 + ((255 - src.a) * dest.r);
2644                         int g = src.a * src.color.g * 63 / 255 + ((255 - src.a) * dest.g);
2645                         int b = src.a * src.color.b * 31 / 255 + ((255 - src.a) * dest.b);
2646                         if(r > 255 * 31) r = 255 * 31;
2647                         if(g > 255 * 63) g = 255 * 63;
2648                         if(b > 255 * 31) b = 255 * 31;
2649                         *picture = { (byte)(r / 255), (byte)(g / 255), (byte)(b / 255) };
2650                      }
2651                      picture += lfbSurface.bitmap.stride - w;
2652                      source += src.stride - w;
2653                   }
2654                }
2655                else if(lfbSurface.bitmap.pixelFormat == pixelFormat555)
2656                {
2657                   Color555 * picture = ((Color555 *)lfbSurface.bitmap.picture) + (lfbSurface.bitmap.stride * dy) + dx;
2658                   for(y = 0; y < h; y++)
2659                   {
2660                      for(x = 0; x < w; x++, picture++, source++)
2661                      {
2662                         ColorAlpha psrc = *source;
2663                         Color555 dest = *picture;
2664                         int r = psrc.a * psrc.color.r * 31 / 255 + ((255 - psrc.a) * dest.r);
2665                         int g = psrc.a * psrc.color.g * 31 / 255 + ((255 - psrc.a) * dest.g);
2666                         int b = psrc.a * psrc.color.b * 31 / 255 + ((255 - psrc.a) * dest.b);
2667                         if(r > 255 * 31) r = 255 * 31;
2668                         if(g > 255 * 31) g = 255 * 31;
2669                         if(b > 255 * 31) b = 255 * 31;
2670                         *picture = { (byte)(r / 255), (byte)(g / 255), (byte)(b / 255) };
2671                      }
2672                      picture += lfbSurface.bitmap.stride - w;
2673                      source += src.stride - w;
2674                   }
2675                }
2676             }
2677          }
2678          else if(src.paletteShades)
2679             shades_blit_table[lfbSurface.bitmap.pixelFormat][flip](src,lfbSurface.bitmap,dx,dy,sx,sy,w,h);
2680          else if(src.pixelFormat == lfbSurface.bitmap.pixelFormat)
2681             blits_table[lfbSurface.bitmap.pixelFormat][src.transparent][flip](src,lfbSurface.bitmap,dx,dy,sx,sy,w,h);
2682          else if(src.pixelFormat == pixelFormat8)
2683             blits_8bit_table[lfbSurface.bitmap.pixelFormat][src.transparent][flip](src,lfbSurface.bitmap,dx,dy,sx,sy,w,h);
2684       }
2685    }
2686
2687    bool GrabScreen(Display display, Bitmap bitmap, int x, int y, unsigned int w, unsigned int h)
2688    {
2689       bool result = false;
2690       LFBDisplay lfbDisplay = display.driverData;
2691
2692       if(bitmap.pixelFormat != lfbDisplay.bitmap.pixelFormat || bitmap.width < w || bitmap.height < h)
2693       {
2694          bitmap.Free();
2695          bitmap.Allocate(null, w,h,w, lfbDisplay.bitmap.pixelFormat,
2696             (lfbDisplay.bitmap.pixelFormat == pixelFormat8)?true:false);
2697       }
2698       if(bitmap)
2699       {
2700          Surface surface = bitmap.GetSurface(0,0,null);
2701          if(surface)
2702          {
2703             Blit(display, surface, lfbDisplay.bitmap, 0,0,x,y,w,h);
2704             if(bitmap.palette && lfbDisplay.bitmap.pixelFormat == pixelFormat8 && lfbDisplay.bitmap.palette)
2705                CopyBytesBy4(bitmap.palette, lfbDisplay.bitmap.palette, 256);
2706             delete surface;
2707          }
2708          result = true;
2709       }
2710       return result;
2711    }
2712
2713    void Stretch(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
2714    {
2715       LFBSurface lfbSurface = surface.driverData;
2716       bool flip = false;
2717
2718       float s2dw,s2dh,d2sw,d2sh;
2719
2720       if(surface.box.right < surface.box.left || surface.box.bottom < surface.box.top || !src.picture) return;
2721
2722       if(Sgn(w) != Sgn(sw))
2723       {
2724          w = Abs(w);
2725          sw = Abs(sw);
2726          flip = true;
2727       }
2728
2729       s2dw=(float)w / sw;
2730       s2dh=(float)h / sh;
2731       d2sw=(float)sw / w;
2732       d2sh=(float)sh / h;
2733
2734       //Clip against the edges of the source
2735       if(sx<0)
2736       {
2737          dx+=(int)((0-sx) * s2dw);
2738          w-=(int)((0-sx) * s2dw);
2739          sw-=0-sx;
2740          sx=0;
2741       }
2742       if(sy<0)
2743       {
2744          dy+=(int)((0-sy) * s2dh);
2745          h-=(int)((0-sy) * s2dh);
2746
2747          sh-=0-sy;
2748          sy=0;
2749       }
2750       if(sx+sw>src.width-1)
2751       {
2752          w-=(int)((sx+sw-(src.width-1)-1)*s2dw);
2753          sw-=sx+sw-(src.width-1)-1;
2754       }
2755       if(sy+sh>(src.height-1))
2756       {
2757          h-=(int)((sy+sh-(src.height-1)-1)*s2dh);
2758          sh-=sy+sh-(src.height-1)-1;
2759       }
2760       //Clip against the edges of the destination
2761       if(dx<surface.box.left)
2762       {
2763          if(!flip) sx+=(int)((surface.box.left-dx)*d2sw);
2764          sw-=(int)((surface.box.left-dx)*d2sw);
2765          w-=surface.box.left-dx;
2766          dx=surface.box.left;
2767       }
2768       if(dy<surface.box.top)
2769       {
2770          sy+=(int)((surface.box.top-dy)*d2sh);
2771          sh-=(int)((surface.box.top-dy)*d2sh);
2772          h-=surface.box.top-dy;
2773          dy=surface.box.top;
2774       }
2775       if((dx+w)>surface.box.right)
2776       {
2777          if(flip) sx+=(int)(((dx+w)-surface.box.right-1)*d2sw);
2778          sw-=(int)(((dx+w)-surface.box.right-1)*d2sw);
2779          w-=((dx+w)-surface.box.right-1);
2780       }
2781       if((dy+h)>surface.box.bottom)
2782       {
2783          sh-=(int)(((dy+h)-surface.box.bottom-1)*d2sh);
2784          h-=((dy+h)-surface.box.bottom-1);
2785       }
2786       if((w<=0)||(h<=0)||(sw<=0)||(sh<=0)) return;
2787
2788       dx+=surface.offset.x;
2789       dy+=surface.offset.y;
2790
2791       if(lfbSurface.bitmap.picture)
2792       {
2793          AlphaWriteMode alphaWrite = surface.alphaWrite;
2794          if(src.alphaBlend && surface.blend)
2795          {
2796             int x, y;
2797             uint xerr,yerr;
2798             uint adddest = lfbSurface.bitmap.stride, addsource = src.stride;
2799             ColorAlpha * backsrc;
2800             ColorAlpha * source = ((ColorAlpha *) src.picture) + sy * addsource + sx;
2801             ColorAlpha * dest = ((ColorAlpha *) lfbSurface.bitmap.picture) + dy * adddest   + dx;
2802             if(flip) source += sw-1;
2803             adddest -= w;
2804             yerr = 0;
2805             for(y=0; y<sh; y++)
2806             {
2807                yerr+=h;
2808                backsrc = source;
2809                while(yerr >= sh)
2810                {
2811                   yerr-=sh;
2812                   xerr = 0;
2813                   for(x=0; x<sw; x++)
2814                   {
2815                      xerr+=w;
2816                      while(xerr>=sw)
2817                      {
2818                         xerr-=sw;
2819                         {
2820                            ColorAlpha src = *source;
2821                            ColorAlpha dst = *dest;
2822                            int r = src.a * src.color.r / 255 + ((255 - src.a) * dst.color.r / 255);
2823                            int g = src.a * src.color.g / 255 + ((255 - src.a) * dst.color.g / 255);
2824                            int b = src.a * src.color.b / 255 + ((255 - src.a) * dst.color.b / 255);
2825                            if(r > 255) r = 255;
2826                            if(g > 255) g = 255;
2827                            if(b > 255) b = 255;
2828                            dest->color = { (byte)r, (byte)g, (byte)b };
2829                            if(alphaWrite == blend)
2830                            {
2831                               int a = src.a + ((255 - src.a) * dst.a / 255);
2832                               if(a > 255) a = 255;
2833                               dest->a = (byte)a;
2834                            }
2835                            else if(alphaWrite)
2836                               dest->a = src.a;
2837                         }
2838                         dest++;
2839                      }
2840                      source ++;
2841                   }
2842                   dest+=adddest;
2843                   source = backsrc;
2844                }
2845                source += addsource;
2846             }
2847          }
2848          else if(src.paletteShades)
2849             shades_stretch_table[lfbSurface.bitmap.pixelFormat][flip](src,lfbSurface.bitmap,dx,dy,sx,sy,w,h,sw,sh);
2850          else if(src.pixelFormat == lfbSurface.bitmap.pixelFormat)
2851             stretches_table[lfbSurface.bitmap.pixelFormat][src.transparent][flip](src,lfbSurface.bitmap,dx,dy,sx,sy,w,h,sw,sh);
2852          else if(src.pixelFormat == pixelFormat8 && lfbSurface.bitmap.pixelFormat != pixelFormatText)
2853             stretches_8bit_table[lfbSurface.bitmap.pixelFormat][src.transparent][flip](src,lfbSurface.bitmap,dx,dy,sx,sy,w,h,sw,sh);
2854       }
2855    }
2856
2857    void Filter(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
2858    {
2859       LFBSurface lfbSurface = surface.driverData;
2860       bool flip = false;
2861
2862       float s2dw,s2dh,d2sw,d2sh;
2863
2864       if(surface.box.right < surface.box.left || surface.box.bottom < surface.box.top || !src.picture) return;
2865
2866       if(Sgn(w) != Sgn(sw))
2867       {
2868          w = Abs(w);
2869          sw = Abs(sw);
2870          flip = true;
2871       }
2872
2873       s2dw=(float)w / sw;
2874       s2dh=(float)h / sh;
2875       d2sw=(float)sw / w;
2876       d2sh=(float)sh / h;
2877
2878       //Clip against the edges of the source
2879       if(sx<0)
2880       {
2881          dx+=(int)((0-sx) * s2dw);
2882          w-=(int)((0-sx) * s2dw);
2883          sw-=0-sx;
2884          sx=0;
2885       }
2886       if(sy<0)
2887       {
2888          dy+=(int)((0-sy) * s2dh);
2889          h-=(int)((0-sy) * s2dh);
2890
2891          sh-=0-sy;
2892          sy=0;
2893       }
2894       if(sx+sw>src.width-1)
2895       {
2896          w-=(int)((sx+sw-(src.width-1)-1)*s2dw);
2897          sw-=sx+sw-(src.width-1)-1;
2898       }
2899       if(sy+sh>(src.height-1))
2900       {
2901          h-=(int)((sy+sh-(src.height-1)-1)*s2dh);
2902          sh-=sy+sh-(src.height-1)-1;
2903       }
2904       //Clip against the edges of the destination
2905       if(dx<surface.box.left)
2906       {
2907          if(!flip) sx+=(int)((surface.box.left-dx)*d2sw);
2908          sw-=(int)((surface.box.left-dx)*d2sw);
2909          w-=surface.box.left-dx;
2910          dx=surface.box.left;
2911       }
2912       if(dy<surface.box.top)
2913       {
2914          sy+=(int)((surface.box.top-dy)*d2sh);
2915          sh-=(int)((surface.box.top-dy)*d2sh);
2916          h-=surface.box.top-dy;
2917          dy=surface.box.top;
2918       }
2919       if((dx+w)>surface.box.right)
2920       {
2921          if(flip) sx+=(int)(((dx+w)-surface.box.right-1)*d2sw);
2922          sw-=(int)(((dx+w)-surface.box.right-1)*d2sw);
2923          w-=((dx+w)-surface.box.right-1);
2924       }
2925       if((dy+h)>surface.box.bottom)
2926       {
2927          sh-=(int)(((dy+h)-surface.box.bottom-1)*d2sh);
2928          h-=((dy+h)-surface.box.bottom-1);
2929       }
2930       if((w<=0)||(h<=0)||(sw<=0)||(sh<=0)) return;
2931
2932       dx+=surface.offset.x;
2933       dy+=surface.offset.y;
2934
2935       if(lfbSurface.bitmap.picture)
2936       {
2937          AlphaWriteMode alphaWrite = surface.alphaWrite;
2938          if(src.alphaBlend && surface.blend)
2939          {
2940             uint adddest = lfbSurface.bitmap.stride, addsource = src.stride;
2941             ColorAlpha * source = ((ColorAlpha *) src.picture) + sy * addsource + sx;
2942             ColorAlpha * dest = ((ColorAlpha *) lfbSurface.bitmap.picture) + dy * adddest   + dx;
2943             float scaleX = (float)sw / w;
2944             float scaleY = (float)sh / h;
2945             /*if(flip < 0)
2946             {
2947                dest += w-1;
2948                adddest += w;
2949             }
2950             else*/
2951                adddest -= w;
2952             if (w > sw && h > sh)
2953             {
2954                int y;
2955                for (y = 0; y < h; y++)
2956                {
2957                   int y0 = y * sh / h;
2958                   int y1 = Min(y0 + 1, sh - 1);
2959                   float alpha = y * scaleY - y0;
2960                   int x;
2961                   for(x = 0; x < w; x++, dest += 1)
2962                   {
2963                      int x0 = x * sw / w;
2964                      int x1 = Min(x0 + 1, sw - 1);
2965                      float beta = x * scaleX - x0;
2966                      ColorAlpha src00, src01, src10, src11;
2967                      float a1,r1,g1,b1,a2,r2,g2,b2;
2968                      float a,r,g,b;
2969                      src00 = source[y0 * src.stride + x0];
2970                      src01 = source[y0 * src.stride + x1];
2971                      src10 = source[y1 * src.stride + x0];
2972                      src11 = source[y1 * src.stride + x1];
2973                      a1 = (src00.a) * (1.0f - beta) + (src01.a) * beta;
2974                      r1 = (src00.color.r) * (1.0f - beta) + (src01.color.r) * beta;
2975                      g1 = (src00.color.g) * (1.0f - beta) + (src01.color.g) * beta;
2976                      b1 = (src00.color.b) * (1.0f - beta) + (src01.color.b) * beta;
2977                      a2 = (src10.a) * (1.0f - beta) + (src11.a) * beta;
2978                      r2 = (src10.color.r) * (1.0f - beta) + (src11.color.r) * beta;
2979                      g2 = (src10.color.g) * (1.0f - beta) + (src11.color.g) * beta;
2980                      b2 = (src10.color.b) * (1.0f - beta) + (src11.color.b) * beta;
2981                      a = a1 * (1.0f - alpha) + a2 * alpha;
2982                      r = r1 * (1.0f - alpha) + r2 * alpha;
2983                      g = g1 * (1.0f - alpha) + g2 * alpha;
2984                      b = b1 * (1.0f - alpha) + b2 * alpha;
2985                      {
2986                         ColorAlpha dst = *dest;
2987                         int cr = (int)(a * r / 255 + ((255 - a) * dst.color.r / 255));
2988                         int cg = (int)(a * g / 255 + ((255 - a) * dst.color.g / 255));
2989                         int cb = (int)(a * b / 255 + ((255 - a) * dst.color.b / 255));
2990                         if(cr > 255) cr = 255;
2991                         if(cg > 255) cg = 255;
2992                         if(cb > 255) cb = 255;
2993                         dest->color = { (byte)cr, (byte)cg, (byte)cb };
2994
2995                         if(alphaWrite == blend)
2996                         {
2997                            int ca = (int)(a + ((255 - a) * dst.a / 255));
2998                            if(ca > 255) ca = 255;
2999                            dest->a = (byte)ca;
3000                         }
3001                         else if(alphaWrite)
3002                            dest->a = (byte)a;
3003                      }
3004                   }
3005                   dest += adddest;
3006                }
3007             }
3008             else
3009             {
3010                int y;
3011                for (y = 0; y < h; y++)
3012                {
3013                   int y0 = Min((int)((y + 1) * scaleY), sh - 1);
3014                   int y1 = Min(y0 + 1, sh - 1);
3015                   int x;
3016                   for (x = 0; x < w; x++, dest += 1)
3017                   {
3018                      int x0 = Min((int)((x + 1) * scaleX), sw - 1);
3019                      int x1 = Min(x0 + 1, sw - 1);
3020                      float a = 0, r = 0, g = 0, b = 0;
3021                      int numPixels = 0;
3022                      int i, j;
3023                      for (i = y0; i <= y1; i++)
3024                         for (j = x0; j <= x1; j++)
3025                         {
3026                            ColorAlpha pixel = source[i * src.stride + j];
3027                            a += pixel.a;
3028                            r += pixel.color.r;
3029                            g += pixel.color.g;
3030                            b += pixel.color.b;
3031                            numPixels++;
3032                         }
3033                      a /= numPixels;
3034                      r /= numPixels;
3035                      g /= numPixels;
3036                      b /= numPixels;
3037                      {
3038                         ColorAlpha dst = *dest;
3039                         int cr = (int)(a * r / 255 + ((255 - a) * dst.color.r / 255));
3040                         int cg = (int)(a * g / 255 + ((255 - a) * dst.color.g / 255));
3041                         int cb = (int)(a * b / 255 + ((255 - a) * dst.color.b / 255));
3042                         if(cr > 255) cr = 255;
3043                         if(cg > 255) cg = 255;
3044                         if(cb > 255) cb = 255;
3045                         dest->color = { (byte)cr, (byte)cg, (byte)cb };
3046                         if(alphaWrite == blend)
3047                         {
3048                            int ca = (int)(a + ((255 - a) * dst.a / 255));
3049                            if(ca > 255) ca = 255;
3050                            dest->a = (byte)ca;
3051                         }
3052                         else if(alphaWrite)
3053                            dest->a = (byte)a;
3054                      }
3055                   }
3056                   dest += adddest;
3057                }
3058             }
3059          }
3060          else if(!src.paletteShades && src.pixelFormat == lfbSurface.bitmap.pixelFormat)
3061             filters_table[lfbSurface.bitmap.pixelFormat][src.transparent][flip](src,lfbSurface.bitmap,dx,dy,sx,sy,w,h,sw,sh);
3062          // Fail back on Stretch
3063          else if(src.paletteShades)
3064             shades_stretch_table[lfbSurface.bitmap.pixelFormat][flip](src,lfbSurface.bitmap,dx,dy,sx,sy,w,h,sw,sh);
3065          else if(src.pixelFormat == lfbSurface.bitmap.pixelFormat)
3066             stretches_table[lfbSurface.bitmap.pixelFormat][src.transparent][flip](src,lfbSurface.bitmap,dx,dy,sx,sy,w,h,sw,sh);
3067          else if(src.pixelFormat == pixelFormat8 && lfbSurface.bitmap.pixelFormat != pixelFormatText)
3068             stretches_8bit_table[lfbSurface.bitmap.pixelFormat][src.transparent][flip](src,lfbSurface.bitmap,dx,dy,sx,sy,w,h,sw,sh);
3069       }
3070    }
3071
3072    void BlitDI(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h)
3073    {
3074       Blit(display, surface, src, dx, dy, sx, sy, w, h);
3075    }
3076
3077    void StretchDI(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
3078    {
3079       Stretch(display, surface, src, dx, dy, sx, sy, w, h, sw, sh);
3080    }
3081
3082    void FilterDI(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
3083    {
3084       Filter(display, surface, src, dx, dy, sx, sy, w, h, sw, sh);
3085    }
3086
3087    void UnloadFont(DisplaySystem displaySystem, Font font)
3088    {
3089       if(font)
3090       {
3091 #if !defined(ECERE_NOTRUETYPE)
3092          int entry;
3093          for(entry = 0; entry<MAX_FONT_LINK_ENTRIES; entry++)
3094          {
3095             FontEntry fontEntry = font.fontEntries[entry];
3096             if(fontEntry)
3097             {
3098                fontEntry.used--;
3099                if(!fontEntry.used)
3100                {
3101                   loadedFonts.Remove(fontEntry);
3102                   delete fontEntry;
3103                }
3104             }
3105          }
3106 #endif
3107          delete font;
3108       }
3109    }
3110
3111    Font LoadFont(DisplaySystem displaySystem, const char * faceName, float size, FontFlags flags)
3112    {
3113       void * result = null;
3114
3115 #if !defined(ECERE_NOTRUETYPE)
3116       Font font = Font { };
3117       if(font)
3118       {
3119          char fileName[MAX_LOCATION];
3120          bool fakeItalic = flags.italic;
3121          int fontID = 0;
3122 #if !defined(__WIN32__)
3123          File linkCfg;
3124 #endif
3125          const char * ecereFonts = getenv("ECERE_FONTS");
3126          if(!ecereFonts) ecereFonts = "<:ecere>";
3127 #if !defined(__WIN32__)
3128          {
3129             char linkCfgPath[MAX_LOCATION];
3130
3131             strcpy(linkCfgPath, ecereFonts);
3132             PathCat(linkCfgPath, "linking.cfg");
3133             linkCfg = FileOpen(linkCfgPath, read);
3134          }
3135 #endif
3136          strcpy(fileName, faceName);
3137          strcpy(font.faceName, faceName);
3138          font.flags = flags;
3139          font.displaySystem = displaySystem;
3140
3141          if(!FileExists(fileName))
3142          {
3143             strcpy(fileName, ecereFonts);
3144             PathCat(fileName, faceName);
3145             if(flags.bold && flags.italic) strcat(fileName, "bi");
3146             else if(flags.bold) strcat(fileName, "bd");
3147             else if(flags.italic) strcat(fileName, "i");
3148             strcat(fileName, ".ttf");
3149             strlwr(fileName);
3150             fakeItalic = false;
3151
3152             if(flags.italic && !FileExists(fileName))
3153             {
3154                strcpy(fileName, ecereFonts);
3155                PathCat(fileName, faceName);
3156                if(flags.bold) strcat(fileName, "bd");
3157                strcat(fileName, ".ttf");
3158                strlwr(fileName);
3159                fakeItalic = true;
3160             }
3161
3162             // Search in current working directory
3163             if(!FileExists(fileName))
3164             {
3165                strcpy(fileName, faceName);
3166                if(flags.bold && flags.italic) strcat(fileName, "bi");
3167                else if(flags.bold) strcat(fileName, "bd");
3168                else if(flags.italic) strcat(fileName, "i");
3169                strcat(fileName, ".ttf");
3170                strlwr(fileName);
3171                fakeItalic = false;
3172
3173                if(flags.italic && !FileExists(fileName))
3174                {
3175                   strcpy(fileName, faceName);
3176                   if(flags.bold) strcat(fileName, "bd");
3177                   strcat(fileName, ".ttf");
3178                   strlwr(fileName);
3179                   fakeItalic = true;
3180                }
3181             }
3182
3183    #if defined(__WIN32__)
3184             if(!FileExists(fileName))
3185             {
3186                FontData fontData = { { 0 } };
3187                LOGFONT logFont = { 0 };
3188                HDC hdc = GetDC(0);
3189
3190                fakeItalic = false;
3191
3192                logFont.lfCharSet = DEFAULT_CHARSET;
3193                strcpy(logFont.lfFaceName, faceName);
3194                fontData.flags = flags;
3195
3196                EnumFontFamiliesEx(hdc, &logFont, (void *)MyFontProc, (LPARAM)&fontData, 0);
3197                if(!fontData.fileName[0] && flags.bold)
3198                {
3199                   fontData.forgive = true;
3200                   EnumFontFamiliesEx(hdc, &logFont, (void *)MyFontProc, (LPARAM)&fontData, 0);
3201                }
3202                if(!fontData.fileName[0])
3203                {
3204                   // Fake italic
3205                   fontData.flags.italic = false;
3206                   EnumFontFamiliesEx(hdc, &logFont, (void *)MyFontProc, (LPARAM)&fontData, 0);
3207                   fakeItalic = true;
3208                }
3209
3210                if(fontData.fileName[0])
3211                {
3212                   GetWindowsDirectory(fileName, MAX_LOCATION);
3213                   PathCat(fileName, "fonts");
3214                   PathCat(fileName, fontData.fileName);
3215                }
3216                ReleaseDC(0, hdc);
3217             }
3218    #elif !defined(ECERE_NOFONTCONFIG)
3219             {
3220                char * fileName2;
3221                FcResult result = 0;
3222                FcPattern * pattern;
3223                FcPattern * matched;
3224                char * family;
3225                unichar testChar = 0;
3226                FcCharSet * charSet;
3227                if(!fcConfig)
3228                   fcConfig = FcInitLoadConfigAndFonts();
3229
3230                charSet = FcCharSetCreate();
3231
3232                if(!strcmpi(faceName, "Mangal"))
3233                {
3234                   testChar = 0x905;
3235                }
3236
3237                if(testChar)
3238                   FcCharSetAddChar(charSet, testChar);
3239
3240                pattern = FcPatternBuild(null,
3241                                //FC_SOURCE, FcTypeString, "freetype",
3242                                FC_FAMILY, FcTypeString, faceName,
3243                                //FC_SCALABLE, FcTypeBool, 1,
3244                                FC_SIZE, FcTypeDouble, (double)size,
3245                                FC_WEIGHT, FcTypeInteger, flags.bold ? FC_WEIGHT_BOLD : FC_WEIGHT_MEDIUM /*FC_WEIGHT_LIGHT*/,
3246                                FC_SLANT, FcTypeInteger, flags.italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN,
3247                                testChar ? FC_CHARSET : 0,FcTypeCharSet, charSet,
3248                                null);
3249                FcDefaultSubstitute(pattern);
3250                FcConfigSubstitute(fcConfig, pattern, FcMatchPattern); //FcMatchFont);
3251
3252                matched = FcFontMatch (0, pattern, &result);
3253                // printf("Locating %s\n", faceName);
3254                if(matched)
3255                {
3256                   FcPatternGetString(matched, FC_FAMILY, 0, (FcChar8 **)&family);
3257                   //printf("Fontconfig returned %s\n", family);
3258                }
3259                if(matched && (result == FcResultMatch /*|| result == FcResultNoId*/) /*&& !strcmpi(family, faceName)*/)
3260                {
3261                   double fontSize;
3262                   FcPatternGetString (matched, FC_FILE, 0, (FcChar8 **)&fileName2);
3263                   FcPatternGetInteger(matched, FC_INDEX, 0, &fontID);
3264                   FcPatternGetDouble(matched, FC_SIZE, 0, &fontSize);
3265                   strcpy(fileName, fileName2);
3266                   // size = (float)fontSize;
3267
3268                   //printf("Matched to %s, %f\n", fileName, size);
3269                }
3270                else
3271                {
3272                   //printf("Could not find a match for %s, %f, %s %s (%d)\n", faceName, size, flags.bold ? "bold" : "", flags.italic ? "italic" : "", (int)result);
3273                }
3274                if(pattern) FcPatternDestroy(pattern);
3275                if(matched) FcPatternDestroy(matched);
3276                if(charSet) FcCharSetDestroy(charSet);
3277             }
3278    #endif
3279          }
3280
3281          if(!FileExists(fileName))
3282             ChangeExtension(fileName, "otf", fileName);
3283          if(!FileExists(fileName))
3284             ChangeExtension(fileName, "ttc", fileName);
3285
3286          //if(FileExists(fileName))
3287          {
3288             int entry = 0;
3289             char links[1024] = "";
3290             int linksPos = 0;
3291 #if defined(__WIN32__)
3292             HKEY key;
3293             links[0] = 0;
3294             if(!RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink",0,KEY_READ,&key) ||
3295                !RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\FontLink\\SystemLink",0,KEY_READ,&key))
3296             {
3297                // int value = 0;
3298                DWORD type;
3299                DWORD size = 1024;
3300                RegQueryValueEx(key, faceName, null, &type, (LPBYTE)links, &size);
3301                memset(links + size, 0, 1024 - size);
3302                RegCloseKey(key);
3303             }
3304 #else
3305             links[0] = 0;
3306             if(linkCfg)
3307             {
3308                char line[512];
3309                while(linkCfg.GetLine(line, sizeof(line)))
3310                {
3311                   int len = strlen(faceName);
3312                   if(line[0] == '[' && !strncasecmp(line + 1, faceName, len) && line[len + 1] == ']')
3313                   {
3314                      while(linkCfg.GetLine(line, sizeof(line)))
3315                      {
3316                         TrimLSpaces(line, line);
3317                         if(!line[0] || line[0] == '[')
3318                            break;
3319                         len = strlen(line);
3320                         memcpy(links + linksPos, line, len);
3321                         linksPos += len;
3322                         links[linksPos] = 0;
3323                         linksPos++;
3324                      }
3325                   }
3326                }
3327                linksPos = 0;
3328             }
3329 #endif
3330             while(entry < MAX_FONT_LINK_ENTRIES)
3331             {
3332                FontEntry fontEntry = (FontEntry)loadedFonts.FindString(fileName);
3333                if(!fontEntry)
3334                {
3335                   File file = FileOpen/*Buffered*/(fileName, read);
3336                   if(file)
3337                   {
3338                      FileSize fileSize = file.GetSize();
3339                      FT_Open_Args args = { 0 };
3340                      FT_Parameter param = { FT_PARAM_TAG_UNPATENTED_HINTING };
3341                      FT_Stream stream = new0 FT_StreamRec[1];
3342
3343                      if(!ftLibrary)
3344                         FT_Init_FreeType( &ftLibrary );
3345
3346                      fontEntry = FontEntry { key = (uintptr)CopyString(fileName) };
3347                      fontEntry.stream = stream;
3348
3349                      /*
3350                      fontEntry.buffer = new byte[fileSize];
3351                      file.Read(fontEntry.buffer, 1, fileSize);
3352                      */
3353
3354                      //args.num_params = 1;
3355                      args.params = &param;
3356
3357                      stream->size = fileSize;
3358                      stream->descriptor.pointer = file;
3359                      stream->read = FT_stream_load;
3360                      stream->close = FT_stream_close;
3361
3362                      args.flags = /*FT_OPEN_PATHNAME|*//*FT_OPEN_MEMORY|*/FT_OPEN_STREAM/*|FT_OPEN_PARAMS*/;
3363                      args.stream = stream;
3364                      //args.pathname = fileName;
3365                      //args.memory_base = fontEntry.buffer;
3366                      //args.memory_size = fileSize;
3367
3368                      // printf("Opening: %s\n", fileName);
3369                      FT_Open_Face( ftLibrary, &args, fontID, &fontEntry.face );
3370
3371                      // delete file;
3372                      if(fontEntry.face)
3373                      {
3374                         fontEntry.hbFace = HB_NewFace(fontEntry.face, hb_getSFntTable);
3375                         fontEntry.hbFont.klass = &hb_fontClass;
3376                         fontEntry.hbFont.userData = fontEntry; //.face;
3377
3378                         numFonts++;
3379                         loadedFonts.Add(fontEntry);
3380                      }
3381                      else
3382                      {
3383                         delete fontEntry;
3384                         // printf("Error opening font %s\n", fileName);
3385                      }
3386                   }
3387                }
3388                if(fontEntry)
3389                {
3390                   if(!entry)
3391                   {
3392                      FT_Matrix matrix;
3393                      FT_Vector pen = { 0, 0 };
3394                      if(fakeItalic)
3395                      {
3396                         matrix.xx = (FT_Fixed)( 1.0 * 0x10000L );
3397                         matrix.xy = (FT_Fixed)( 0.3 * 0x10000L );
3398                         matrix.yx = (FT_Fixed)( 0.0 * 0x10000L );
3399                         matrix.yy = (FT_Fixed)( 1.0 * 0x10000L );
3400                      }
3401                      else
3402                      {
3403                         matrix.xx = (FT_Fixed)( 1.0 * 0x10000L );
3404                         matrix.xy = (FT_Fixed)( 0.0 * 0x10000L );
3405                         matrix.yx = (FT_Fixed)( 0.0 * 0x10000L );
3406                         matrix.yy = (FT_Fixed)( 1.0 * 0x10000L );
3407                      }
3408                      FT_Set_Transform(fontEntry.face, &matrix, &pen );
3409                      FaceSetCharSize(fontEntry.face, size);
3410                      font.height = (int)((fontEntry.face->size->metrics.height) >> 6); //* y_scale;
3411                      // printf("Font height is %d\n", font.height);
3412                      font.fakeItalic = fakeItalic;
3413                      font.size = size;
3414                      result = font;
3415                   }
3416                   font.fontEntries[entry++] = fontEntry;
3417                   fontEntry.used++;
3418                }
3419
3420                {
3421                   int c;
3422                   char ch;
3423                   char fontName[1024];
3424                   if(!links[linksPos]) break;
3425                   for(c = 0; (ch = links[linksPos + c]); c++)
3426                   {
3427                      fontName[c] = ch;
3428                      if(ch == ',') break;
3429                   }
3430                   fontName[c] = 0;
3431                   if(fontName[0] || ch == ',')
3432                   {
3433 #if defined(__WIN32__)
3434                      GetWindowsDirectory(fileName, MAX_LOCATION);
3435                      PathCat(fileName, "fonts");
3436                      PathCat(fileName, fontName);
3437 #elif !defined(ECERE_NOFONTCONFIG)
3438                      if(getenv("ECERE_FONTS"))
3439                      {
3440                         strcpy(fileName, ecereFonts);
3441                         PathCat(fileName, fontName);
3442                      }
3443                      else
3444                      {
3445                         {
3446                            char * fileName2;
3447                            FcResult result = 0;
3448                            FcPattern * pattern;
3449                            FcPattern * matched;
3450                            char * family;
3451                             pattern = FcPatternBuild(null,
3452                                            //FC_SOURCE, FcTypeString, "freetype",
3453                                            //FC_SCALABLE, FcTypeBool, 1,
3454                                            FC_FAMILY, FcTypeString, links + linksPos + c + 1,
3455                                            FC_SIZE, FcTypeDouble, (double)size,
3456                                            FC_WEIGHT, FcTypeInteger, flags.bold ? FC_WEIGHT_BOLD : FC_WEIGHT_MEDIUM /*FC_WEIGHT_LIGHT*/,
3457                                            FC_SLANT, FcTypeInteger, flags.italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN,
3458                                            null);
3459                            FcDefaultSubstitute(pattern);
3460                            FcConfigSubstitute(fcConfig, pattern, FcMatchPattern); //FcMatchFont);
3461
3462                            //printf("Locating %s\n", links + linksPos + c + 1);
3463                            matched = FcFontMatch (0, pattern, &result);
3464                            if(matched)
3465                            {
3466                               FcPatternGetString(matched, FC_FAMILY, 0, (FcChar8 **)&family);
3467                               // printf("Fontconfig returned %s\n", family);
3468                            }
3469                            if(matched && (result == FcResultMatch /*|| result == FcResultNoId*/) &&
3470                               FcPatternGetString(matched, FC_FAMILY, 0, (FcChar8 **)&family) == FcResultMatch /*&& !strcmpi(family, links + linksPos + c + 1)*/)
3471                            {
3472                               double fontSize;
3473                               FcPatternGetString (matched, FC_FILE, 0, (FcChar8 **)&fileName2);
3474                               FcPatternGetInteger(matched, FC_INDEX, 0, &fontID);
3475                               FcPatternGetDouble(matched, FC_SIZE, 0, &fontSize);
3476                               strcpy(fileName, fileName2);
3477                               //size = (float)fontSize;
3478                               // printf("Matched to %s, %f\n", fileName, size);
3479                            }
3480                            else
3481                            {
3482                               // printf("Could not find a match for %s, %f, %s %s (%d)\n", links + linksPos + c + 1, size, flags.bold ? "bold" : "", flags.italic ? "italic" : "", (int)result);
3483                            }
3484                            if(pattern) FcPatternDestroy(pattern);
3485                            if(matched) FcPatternDestroy(matched);
3486                         }
3487                      }
3488 #endif
3489
3490                   }
3491                   linksPos += c;
3492                   while(links[linksPos] && links[linksPos] != ',') linksPos++;
3493                   linksPos++;
3494                }
3495             }
3496          }
3497
3498          if(!result)
3499             UnloadFont(displaySystem, font);
3500          else
3501          {
3502             font.asciiPack.Render(font, 0, displaySystem);
3503          }
3504 #if !defined(__WIN32__)
3505          delete linkCfg;
3506 #endif
3507       }
3508    #endif
3509       return result;
3510    }
3511
3512 #if !defined(ECERE_NOTRUETYPE)
3513    void ::ProcessString(Font font, DisplaySystem displaySystem, const byte * text, int len,
3514                         void (* callback)(Surface surface, Display display, int x, int y, GlyphInfo * glyph, Bitmap bitmap),
3515                         Surface surface, Display display, int * x, int y)
3516    {
3517       if(font && font.fontEntries && font.fontEntries[0])
3518       {
3519          LFBSurface lfbSurface = surface ? surface.driverData : null;
3520          int previousGlyph = 0;
3521          FT_Face previousFace = 0;
3522          int c, nb, glyphIndex = 0;
3523          unichar lastPack = lfbSurface && lfbSurface.writingOutline ? -1 : 0;
3524          GlyphPack pack = font.asciiPack, outline = null;
3525          int wc = 0;
3526          uint * glyphs = null;
3527          int numGlyphs = 0;
3528          bool rightToLeft = false;
3529          int fontEntryNum = 0;
3530          int glyphScript = 0;
3531          FontEntry curFontEntry;
3532
3533          pack.bitmap.alphaBlend = true;
3534
3535          for(c = 0; c < len || (numGlyphs && (rightToLeft ? (glyphIndex >= 0) : (glyphIndex < numGlyphs)));)
3536          {
3537             uint glyphNo = 0;
3538             uint packNo;
3539             if(numGlyphs && (rightToLeft ? (glyphIndex >= 0) : (glyphIndex < numGlyphs)))
3540             {
3541                glyphNo = glyphs[glyphIndex] | 0x80000000 | (glyphScript << 24);
3542                rightToLeft ? glyphIndex-- : glyphIndex++;
3543             }
3544             else
3545             {
3546                HB_Script curScript = HB_Script_Common;
3547                const byte * scriptStart = text + c;
3548                //unichar nonASCIIch = 0;
3549                unichar ch;
3550                unichar ahead = 0;
3551                unichar testChar = 0;
3552 #if !defined(__WIN32__) && !defined(ECERE_NOFONTCONFIG)
3553                const char * testLang = null;
3554 #endif
3555
3556                while(true)
3557                {
3558                   HB_Script script = HB_Script_Common;
3559                   ch = UTF8GetChar((const char *)text + c, &nb);
3560                   //if(ch > 127) nonASCIIch = ch;
3561                   if(!nb) break;
3562                   if(ch == 32 && curScript)
3563                   {
3564                      if(ahead)
3565                         script = curScript;
3566                      else
3567                      {
3568                         int a;
3569                         for(a = c + 1; a < c + len; a++)
3570                         {
3571                            if(text[a] != 32)
3572                               break;
3573                         }
3574                         if(a < c + len)
3575                         {
3576                            int nb;
3577                            unichar ahead = UTF8GetChar((const char *)text + a, &nb);
3578                            if((ahead >= 0x590 && ahead <= 0x7C0) || (ahead >= 0xFB1D && ahead <= 0xFB4F) || (ahead >= 0xFB50 && ahead <= 0xFDFF))
3579                               script = curScript;
3580                         }
3581                         else
3582                            script = curScript;
3583                      }
3584                   }
3585                   else if(ch < 0x370)
3586                      script = HB_Script_Common;
3587                   else if(ch <= 0x11FF)
3588                   {
3589                      switch(ch & 0xFF00)
3590                      {
3591                         case 0x300: script = HB_Script_Greek; break;
3592                         case 0x400: script = HB_Script_Cyrillic; break;
3593                         case 0x500: script = (ch < 0x530) ? HB_Script_Cyrillic : ((ch < 0x590) ? HB_Script_Armenian : HB_Script_Hebrew); break;
3594                         case 0x600: script = HB_Script_Arabic; break;
3595                         case 0x700: script = (ch < 0x750) ? HB_Script_Syriac : ((ch < 0x780) ? HB_Script_Arabic : ((ch < 0x7C0) ? HB_Script_Thaana : HB_Script_Common)); break;
3596                         case 0x800: script = HB_Script_Common; break;   // NO CHARACTERS ASSIGNED BETWEEN 0x7C0 and 0x8FF?
3597                         case 0x900: script = (ch < 0x980) ? HB_Script_Devanagari : HB_Script_Bengali; break;
3598                         case 0xA00: script = (ch < 0xA80) ? HB_Script_Gurmukhi : HB_Script_Gujarati; break;
3599                         case 0xB00: script = (ch < 0xB80) ? HB_Script_Oriya : HB_Script_Tamil; break;
3600                         case 0xC00: script = (ch < 0xC80) ? HB_Script_Telugu : HB_Script_Kannada; break;
3601                         case 0xD00: script = (ch < 0xD80) ? HB_Script_Malayalam : HB_Script_Sinhala; break;
3602                         case 0xE00: script = (ch < 0xE80) ? HB_Script_Thai : HB_Script_Lao; break;
3603                         case 0xF00: script = HB_Script_Tibetan; break;
3604                         case 0x1000: script = (ch < 0x10A0) ? HB_Script_Myanmar : HB_Script_Georgian; break;
3605                         case 0x1100: script = HB_Script_Hangul; break;
3606                      }
3607                   }
3608                   else if(ch >= 0x1F00 && ch <= 0x1FFF) script = HB_Script_Greek;
3609                   else if((ch >= 0x2D00 && ch <= 0x2D2F) || (ch >= 0x3130 && ch <= 0x318F) || (ch >= 0xAC00 && ch <= 0xD7AF) || (ch >= 0xFFA0 && ch <= 0xFFDC))
3610                      script = HB_Script_Hangul;
3611                   else if(ch >= 0x1680 && ch <= 0x169F) script = HB_Script_Ogham;
3612                   else if(ch >= 0x16A0 && ch <= 0x16FF) script = HB_Script_Runic;
3613                   else if((ch >= 0x1780 && ch <= 0x17FF) || (ch >= 0x19E0 && ch <= 0x19FF)) script = HB_Script_Khmer;
3614                   else if(ch >= 0x3040 && ch <= 0x309F) script = 60;
3615                   else if(ch >= 0x3400 && ch <= 0x9FBF) script = 61;
3616                   //else if(ch >= 0x4E00 && ch <= 0x9FBF) script = 61;
3617                   else if(ch >= 0xFB13 && ch <= 0xFB17) script = HB_Script_Armenian;
3618                   else if(ch >= 0xFB1D && ch <= 0xFB4F) script = HB_Script_Hebrew;
3619                   else if(ch >= 0xFB50 && ch <= 0xFDFF) script = HB_Script_Arabic;
3620                   if(curScript)
3621                   {
3622                      if(!script || (script != curScript))
3623                         break;
3624                      c += nb;
3625                      if(c >= len)
3626                         break;
3627                   }
3628                   else
3629                   {
3630                      if(!script || script > HB_ScriptCount) { c += nb; if(script > HB_ScriptCount) curScript = script; break; }
3631                      if(!script) { c += nb; break; }
3632                      curScript = script;
3633                   }
3634                }
3635                if(!nb) break;
3636                fontEntryNum = 0;
3637
3638                if(curScript == HB_Script_Common || curScript > HB_ScriptCount)
3639                {
3640                   rightToLeft = false;
3641                   glyphNo = ch;
3642                   theCurrentScript = 0;
3643                }
3644                else
3645                {
3646                   int len = c - (int)(scriptStart - text);
3647                   int max = len * 2 + 1;
3648                   if(max > utf16BufferSize)
3649                   {
3650                      utf16 = renew utf16 uint16[max];
3651                      utf16BufferSize = max;
3652                   }
3653                   wc = UTF8toUTF16BufferLen((const char *)scriptStart, utf16, max, len);
3654                   theCurrentScript = glyphScript = curScript;
3655                }
3656                switch(curScript)
3657                {
3658                   case HB_Script_Arabic:        testChar = 0x621; /*testLang = "ar"; */
3659                      //printf("Arabic ");
3660                      break;
3661                   case HB_Script_Devanagari:    testChar = 0x905;
3662 #if !defined(__WIN32__) && !defined(ECERE_NOFONTCONFIG)
3663                      testLang = "sa";
3664 #endif
3665                      //printf("Devanagari ");
3666                      break;
3667                   case HB_Script_Hebrew:        testChar = 0x05EA /*'ת'*/; /*testLang = "he"; */
3668                      //printf("Hebrew ");
3669                      break;
3670                   default:
3671                      testChar = (ch == '\t') ? ' ' : ch;
3672                   /*
3673                   case 60: testChar = 'あ'; break;
3674                   case 61: testChar = 0x3400; break; //'愛'; break;
3675                   */
3676                }
3677
3678                if(testChar)
3679                {
3680                   // printf("Testing for char %x\n", testChar);
3681                   for(fontEntryNum = 0; fontEntryNum<MAX_FONT_LINK_ENTRIES; fontEntryNum++)
3682                   {
3683                      if(font.fontEntries[fontEntryNum] && FT_Get_Char_Index(font.fontEntries[fontEntryNum].face, testChar))
3684                         break;
3685                      /*if(font.fontEntries[fontEntryNum])
3686                         printf("Not found in %s\n", (char *)font.fontEntries[fontEntryNum].key);*/
3687                   }
3688                }
3689
3690                if(fontEntryNum == MAX_FONT_LINK_ENTRIES)
3691                {
3692 #if !defined(__WIN32__) && !defined(ECERE_NOFONTCONFIG)
3693                   int fontID = 0;
3694                   double fontSize = font.size;
3695                   FcResult result = 0;
3696                   FcPattern * pattern;
3697                   FcPattern * matched;
3698                   FcCharSet * charSet;
3699                   char * family;
3700                   FontEntry fontEntry;
3701                   char * fileName = null;
3702                   for(fontEntryNum = 0; fontEntryNum<MAX_FONT_LINK_ENTRIES; fontEntryNum++)
3703                      if(!font.fontEntries[fontEntryNum])
3704                         break;
3705                   if(fontEntryNum == MAX_FONT_LINK_ENTRIES)
3706 #endif
3707                      continue;
3708
3709 #if !defined(__WIN32__) && !defined(ECERE_NOFONTCONFIG)
3710                   {
3711                      charSet = FcCharSetCreate();
3712                      FcCharSetAddChar(charSet, testChar);
3713                      //printf("Loading with char %x\n", testChar);
3714
3715                      pattern = FcPatternBuild(null,
3716                                      //FC_SOURCE, FcTypeString, "freetype",
3717                                      //FC_SCALABLE, FcTypeBool, 1,
3718                                      FC_FAMILY, FcTypeString, font.faceName,
3719                                      FC_SIZE, FcTypeDouble, (double)font.size,
3720                                      FC_WEIGHT, FcTypeInteger, font.flags.bold ? FC_WEIGHT_BOLD : FC_WEIGHT_MEDIUM,
3721                                      FC_SLANT, FcTypeInteger, font.flags.italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN,
3722                                      FC_CHARSET,FcTypeCharSet, charSet,
3723                                      testLang ? FC_LANG : 0, FcTypeString,testLang,
3724                                      null);
3725                      FcDefaultSubstitute(pattern);
3726                      FcConfigSubstitute(fcConfig, pattern, FcMatchPattern); //FcMatchFont);
3727
3728                      //printf("Locating %s for script %d\n", font.faceName, curScript);
3729                      matched = FcFontMatch (0, pattern, &result);
3730                      if(matched)
3731                      {
3732                         FcPatternGetString(matched, FC_FAMILY, 0, (FcChar8 **)&family);
3733                         //printf("Fontconfig returned %s\n", family);
3734                      }
3735                      if(matched && (result == FcResultMatch) && FcPatternGetString(matched, FC_FAMILY, 0, (FcChar8 **)&family) == FcResultMatch)
3736                      {
3737                         FcPatternGetString (matched, FC_FILE, 0, (FcChar8 **)&fileName);
3738                         FcPatternGetInteger(matched, FC_INDEX, 0, &fontID);
3739                         FcPatternGetDouble(matched, FC_SIZE, 0, &fontSize);
3740                         // printf("\nMatched to %s, %f\n", fileName, fontSize);
3741                      }
3742                      else
3743                      {
3744                         //printf("Could not find a match for %s, %f, %s %s (%d)\n", font.faceName, font.size, font.flags.bold ? "bold" : "", font.flags.italic ? "italic" : "", (int)result);
3745                      }
3746                   }
3747                   if(fileName)
3748                   {
3749                      fontEntry = (FontEntry)loadedFonts.FindString(fileName);
3750                      if(!fontEntry)
3751                      {
3752                         File file = FileOpen(fileName, read);
3753                         if(file)
3754                         {
3755                            FileSize fileSize = file.GetSize();
3756                            FT_Open_Args args = { 0 };
3757                            FT_Parameter param = { FT_PARAM_TAG_UNPATENTED_HINTING };
3758                            FT_Stream stream = new0 FT_StreamRec[1];
3759
3760                            if(!ftLibrary)
3761                               FT_Init_FreeType( &ftLibrary );
3762
3763                            fontEntry = FontEntry { key = (uintptr)CopyString(fileName) };
3764                            fontEntry.stream = stream;
3765
3766                            //args.num_params = 1;
3767                            args.params = &param;
3768
3769                            stream->size = fileSize;
3770                            stream->descriptor.pointer = file;
3771                            stream->read = FT_stream_load;
3772                            stream->close = FT_stream_close;
3773
3774                            args.flags = FT_OPEN_STREAM;
3775                            args.stream = stream;
3776                            //args.pathname = fileName;
3777                            //args.memory_base = fontEntry.buffer;
3778                            //args.memory_size = fileSize;
3779
3780                            // printf("Opening: %s\n", fileName);
3781                            FT_Open_Face( ftLibrary, &args, fontID, &fontEntry.face );
3782
3783                            // delete file;
3784                            if(fontEntry.face)
3785                            {
3786                               fontEntry.hbFace = HB_NewFace(fontEntry.face, hb_getSFntTable);
3787                               fontEntry.hbFont.klass = &hb_fontClass;
3788                               fontEntry.hbFont.userData = fontEntry; //.face;
3789
3790                               numFonts++;
3791                               loadedFonts.Add(fontEntry);
3792                            }
3793                            else
3794                            {
3795                               delete fontEntry;
3796                               // printf("Error opening font %s\n", fileName);
3797                            }
3798                         }
3799                      }
3800                      if(fontEntry)
3801                      {
3802                         FaceSetCharSize(fontEntry.face, font.size);
3803
3804                         font.fontEntries[fontEntryNum] = fontEntry;
3805                         fontEntry.used++;
3806                      }
3807                   }
3808                   if(pattern) FcPatternDestroy(pattern);
3809                   if(matched) FcPatternDestroy(matched);
3810                   if(charSet) FcCharSetDestroy(charSet);
3811 #endif
3812                }
3813                if(curScript > HB_ScriptCount) curScript = HB_Script_Common;
3814                if(curScript != HB_Script_Common && curScript < HB_ScriptCount)
3815                {
3816                   font.fontEntries[fontEntryNum].font = font;
3817                   glyphs = shaping(font.fontEntries[fontEntryNum], utf16, wc, curScript, &numGlyphs, &rightToLeft);
3818                   if(!numGlyphs)
3819                      continue;
3820
3821                   glyphIndex = rightToLeft ? (numGlyphs - 1) : 0;
3822                   glyphNo = glyphs[glyphIndex] | 0x80000000 | (glyphScript << 24);
3823                   rightToLeft ? glyphIndex-- : glyphIndex++;
3824                }
3825             }
3826
3827             curFontEntry = font.fontEntries[fontEntryNum];
3828
3829             packNo = glyphNo & 0xFFFFFF80;
3830
3831             if(packNo != lastPack)
3832             {
3833                if(glyphNo < 128)
3834                   pack = font.asciiPack;
3835                else
3836                {
3837                   pack = (GlyphPack)font.glyphPacks.Find((uintptr)packNo);
3838                   if(!pack)
3839                   {
3840                      pack = GlyphPack { key = (uintptr)packNo };
3841                      font.glyphPacks.Add(pack);
3842                      pack.Render(font, fontEntryNum, displaySystem);
3843                   }
3844                }
3845                pack.bitmap.alphaBlend = true;
3846                lastPack = packNo;
3847 #if !defined(ECERE_VANILLA)
3848                if(lfbSurface && lfbSurface.writingOutline)
3849                {
3850                   uint outlineNo = (((uint)surface.outline.size) << 16) | (uint16)(Min(surface.outline.fade, 257.0f) * 255);
3851                   outline = (GlyphPack)pack.outlines.Find(outlineNo);
3852                   if(!outline)
3853                   {
3854                      outline = { key = outlineNo };
3855                      pack.outlines.Add(outline);
3856                      pack.RenderOutline(outline, font, displaySystem);
3857                   }
3858                }
3859 #endif
3860             }
3861             if(pack)
3862             {
3863                int index = rightToLeft ? (glyphIndex + 1) : (glyphIndex-1);
3864                GlyphInfo * glyph = &(outline ? outline : pack).glyphs[glyphNo & 0x7F];
3865
3866                int ax = (int)((numGlyphs ? shaper_item.advances[index] : glyph->ax) * glyph->scale);
3867                int offset = numGlyphs ? shaper_item.offsets[index].x : 0;
3868                int oy = 0;//numGlyphs ? shaper_item.offsets[index].y : 0;
3869
3870                ax += offset;
3871
3872                if(previousGlyph && curFontEntry.face == previousFace)
3873                {
3874                   FT_Vector delta = { 0, 0 };
3875                   FT_Get_Kerning(curFontEntry.face, previousGlyph, glyph->glyphNo, FT_KERNING_UNFITTED, &delta );
3876                   if(delta.x < 0)  delta.x += (-delta.x) % 64;
3877                   else if(delta.x) delta.x += 64 - (delta.x % 64);
3878                   *x += delta.x * glyph->scale;
3879                }
3880                else
3881                   FaceSetCharSize(curFontEntry.face, font.size);
3882
3883                previousGlyph = glyph->glyphNo;
3884                previousFace = curFontEntry.face;
3885
3886                if(callback)
3887                   callback(surface, display, ((*x) >> 6), y + (oy >> 6), glyph, (outline ? outline : pack).bitmap);
3888                *x += ax;
3889             }
3890             if(numGlyphs && (rightToLeft ? (glyphIndex < 0) : (glyphIndex == numGlyphs)))
3891                numGlyphs = 0;
3892          }
3893       }
3894       if(surface)
3895       {
3896          LFBSurface lfbSurface = surface.driverData;
3897          lfbSurface.xOffset = 0;
3898       }
3899    }
3900
3901 #endif
3902    void FontExtent(DisplaySystem displaySystem, Font font, const char * text, int len, int * width, int * height)
3903    {
3904       if(displaySystem && displaySystem.flags.text && len)
3905       {
3906          if(width)
3907          {
3908             int num = len;
3909             *width = num * textCellW;
3910          }
3911          if(height) *height = textCellH;
3912       }
3913       else if(font && len)
3914       {
3915          if(width)
3916          {
3917             int w = 0;
3918 #if !defined(ECERE_NOTRUETYPE)
3919             ProcessString(font, displaySystem, (const byte *)text, len, null, null, null, &w, 0);
3920 #endif
3921             //*width = (w + 64 - w % 64) >> 6;
3922             *width = w >> 6;
3923          }
3924          if(height)
3925             *height = font.height;
3926       }
3927       else
3928       {
3929          if(width) *width = 0;
3930          if(height) *height = 0;
3931       }
3932    }
3933
3934 #if !defined(ECERE_NOTRUETYPE)
3935    void ::OutputGlyph(Surface surface, Display display, int x, int y, GlyphInfo * glyph, Bitmap bitmap)
3936    {
3937       surface.driver.Blit(display, surface, bitmap, x + glyph->left, y + glyph->top, glyph->x, glyph->y, glyph->w, glyph->h);
3938    }
3939 #endif
3940
3941    void WriteText(Display display, Surface surface, int x, int y, const char * text, int len)
3942    {
3943       LFBSurface lfbSurface = surface.driverData;
3944       if(display && display.displaySystem.flags.text)
3945       {
3946          LFBDisplay lfbDisplay = display.driverData;
3947          uint16 * coffset = (uint16 *)lfbDisplay.bitmap.picture;
3948          int c;
3949
3950          x /= textCellW;
3951          y /= textCellH;
3952
3953          if(y > surface.box.bottom || y < surface.box.top)
3954             return;
3955          coffset += (y+surface.offset.y) * lfbSurface.bitmap.stride + x + surface.offset.x;
3956          for(c=0; (c<len && x < surface.box.left); c++, x++,coffset++);
3957          for(; (c<len && x <= surface.box.right); c++, x++,coffset++)
3958          {
3959             if(surface.textOpacity)
3960                *coffset = (uint16) (lfbSurface.background|lfbSurface.foreground|text[c]);
3961             else
3962                *coffset = (uint16) (((*coffset)&0xF000)|lfbSurface.foreground|text[c]);
3963          }
3964       }
3965       else
3966       {
3967          lfbSurface.writingText = true;
3968 #if !defined(ECERE_NOTRUETYPE)
3969          x <<= 6;
3970          ProcessString(lfbSurface.font, surface.displaySystem, (const byte *)text, len, OutputGlyph, surface, display, &x, y);
3971 #endif
3972          lfbSurface.writingText = false;
3973       }
3974    }
3975
3976    void TextFont(Display display, Surface surface, Font font)
3977    {
3978       LFBSurface lfbSurface = surface.driverData;
3979       lfbSurface.font = font;
3980    }
3981
3982    void TextOpacity(Display display, Surface surface, bool opaque)
3983    {
3984
3985    }
3986
3987    void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height)
3988    {
3989       LFBSurface lfbSurface = surface.driverData;
3990       FontExtent(surface.displaySystem, lfbSurface.font, text, len, width, height);
3991    }
3992
3993    void DrawingChar(Display display, Surface surface, byte character)
3994    {
3995       LFBSurface lfbSurface = surface.driverData;
3996       lfbSurface.drawingChar = character;
3997    }
3998
3999    void LineStipple(Display display, Surface surface, uint32 stipple)
4000    {
4001       LFBSurface lfbSurface = surface.driverData;
4002       lfbSurface.stipple = (uint16)stipple;
4003    }
4004
4005 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
4006    void FreeMesh(DisplaySystem displaySystem, Mesh mesh)
4007    {
4008       if(mesh.vertices && !mesh.flags.vertices)
4009          delete mesh.vertices;
4010       if(mesh.normals && !mesh.flags.normals)
4011          delete mesh.normals;
4012       if(mesh.texCoords && !mesh.flags.texCoords1)
4013          delete mesh.texCoords;
4014    }
4015
4016    bool AllocateMesh(DisplaySystem displaySystem, Mesh mesh, MeshFeatures flags, int nVertices)
4017    {
4018       bool result = false;
4019       if(mesh.nVertices == nVertices)
4020       {
4021          result = true;
4022          // Same number of vertices, adding features (Leaves the other features pointers alone)
4023          if(mesh.flags != flags)
4024          {
4025             if(!mesh.flags.vertices && flags.vertices)
4026             {
4027                if(flags.doubleVertices)
4028                {
4029                   mesh.vertices = (Vector3Df *)new Vector3D[nVertices];
4030                }
4031                else
4032                   mesh.vertices = new Vector3Df[nVertices];
4033             }
4034             if(!mesh.flags.normals && flags.normals)
4035             {
4036                if(flags.doubleNormals)
4037                {
4038                   mesh.normals = (Vector3Df *)new Vector3D[nVertices];
4039                }
4040                else
4041                   mesh.normals = new Vector3Df[nVertices];
4042             }
4043             if(!mesh.flags.texCoords1 && flags.texCoords1)
4044                mesh.texCoords = new Pointf[nVertices];
4045             if(!mesh.flags.colors && flags.colors)
4046                mesh.colors = new ColorRGBAf[nVertices];
4047          }
4048       }
4049       else
4050       {
4051          result = true;
4052          // New number of vertices, reallocate all current and new features
4053          flags |= mesh.flags;
4054          if(flags.vertices)
4055          {
4056             if(flags.doubleVertices)
4057             {
4058                mesh.vertices = (Vector3Df *)renew mesh.vertices Vector3D[nVertices];
4059             }
4060             else
4061                mesh.vertices = renew mesh.vertices Vector3Df[nVertices];
4062          }
4063          if(flags.normals)
4064          {
4065             if(flags.doubleNormals)
4066             {
4067                mesh.normals = (Vector3Df *)renew mesh.normals Vector3D[nVertices];
4068             }
4069             else
4070                mesh.normals = renew mesh.normals Vector3Df[nVertices];
4071          }
4072          if(flags.texCoords1)
4073             mesh.texCoords = renew mesh.texCoords Pointf[nVertices];
4074          if(flags.colors)
4075             mesh.colors = renew mesh.colors ColorRGBAf[nVertices];
4076       }
4077       return result;
4078    }
4079
4080    bool LockMesh(DisplaySystem displaySystem, Mesh mesh, MeshFeatures features)
4081    {
4082       return true;
4083    }
4084
4085    void FreeIndices(DisplaySystem displaySystem, uint16 * indices)
4086    {
4087       delete indices;
4088    }
4089
4090    uint16 * AllocateIndices(DisplaySystem displaySystem, int nIndices, bool indices32bit)
4091    {
4092       return (void *)(indices32bit ? new uint32[nIndices] : new uint16[nIndices]);
4093    }
4094    uint16 * LockIndices(DisplaySystem displaySystem, void * indices)
4095    {
4096       return indices;
4097    }
4098 #endif
4099 }