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