gfx/gui (win32): Fixed warning with latest MinGW-w64 headers
[sdk] / ecere / src / gfx / drivers / GDIDisplayDriver.ec
1 namespace gfx::drivers;
2
3 import "instance"
4
5 #if defined(__WIN32__)
6
7 #define UNICODE
8
9 #undef _WIN32_WINNT
10 #define _WIN32_WINNT 0x0502
11 #define WIN32_LEAN_AND_MEAN
12 #define Method _Method
13 #define String _String
14
15 #include <windows.h>
16
17 #undef Method
18 #undef String
19
20 import "Display"
21 import "Win32Interface"
22
23 class GDIDisplay : LFBDisplay
24 {
25    HBITMAP memBitmap;
26    HDC memDC;
27    HPALETTE palette;
28    LOGPALETTE * logPalette;
29    Point offset;
30
31    HDC hdc;
32    HRGN rgn;
33    RGNDATA * data;
34
35    ~GDIDisplay()
36    {
37       if(memDC) DeleteDC(memDC);
38       if(memBitmap) DeleteObject(memBitmap);
39       if(palette) DeleteObject(palette);
40       delete logPalette;
41    }
42 };
43 /*
44 static byte defaultRGBLookup[32768];
45 static bool rgbLookupSet = false;
46 */
47 class GDISystem : LFBSystem
48 {
49    HDC tmpDC;
50    int depth;
51
52    ~GDISystem()
53    {
54       if(tmpDC)
55          ReleaseDC(0, tmpDC);
56    }
57 };
58
59 class GDISurface : LFBSurface
60 {
61    HDC hdc;
62    HRGN rgn, clippedRgn;
63    COLORREF color;
64 };
65
66 class GDIBitmap : struct
67 {
68    HBITMAP memBitmap;
69    HDC memDC;
70 };
71
72 static class GDIFont
73 {
74    char faceName[512];
75    FontFlags flags;
76    float size;
77
78    void * gdiFont;
79    Font font;
80 };
81
82 static PixelFormat GetColorFormat(int depth)
83 {
84    if(depth == 8)
85       return pixelFormat8;
86    else if(depth == 16)
87       return pixelFormat555;
88    else
89       return pixelFormat888;
90 }
91
92 // TOFIX: Quick fix for GrabScreen called with a null Display
93 static DisplaySystem theDisplaySystem;
94
95 class GDIDisplayDriver : DisplayDriver
96 {
97    class_property(name) = "GDI";
98
99    bool CreateDisplaySystem(DisplaySystem displaySystem)
100    {
101       GDISystem gdiSystem = displaySystem.driverData = GDISystem { };
102       HDC hdc = GetDC(GetDesktopWindow());
103       if(hdc)
104       {
105          gdiSystem.tmpDC = GetDC(0);
106          gdiSystem.depth = GetDeviceCaps(hdc, BITSPIXEL);
107          displaySystem.pixelFormat = GetColorFormat(gdiSystem.depth);
108          if(displaySystem.pixelFormat == pixelFormat8)
109          {
110             int reserved = 10;
111             int c;
112             ColorAlpha realPalette[256];
113             gdiSystem.palette = new ColorAlpha[256];
114             GetSystemPaletteEntries(hdc,0,256,(PALETTEENTRY *)realPalette);
115             for(c = 0; c<256; c++)
116                gdiSystem.palette[c] = { 255, RGB(realPalette[c].color.r, realPalette[c].color.g, realPalette[c].color.b) };
117             CopyBytesBy4(gdiSystem.palette + reserved, GetDefaultPalette() + reserved, 256 - 2 * reserved);
118             /*
119             if(!rgbLookupSet)
120                for(c = 0; c<32768; c++)
121                   defaultRGBLookup[c] = (byte)BestColorMatch(gdiSystem.palette, 0, 255, (Color555)c);
122             rgbLookupSet = true;
123             */
124             CopyBytes(gdiSystem.rgbLookup, defaultRGBLookup, 32768);
125          }
126          ReleaseDC(GetDesktopWindow(), hdc);
127       }
128       if(!theDisplaySystem) theDisplaySystem = displaySystem;
129       displaySystem.flags.memBackBuffer = true;
130       displaySystem.flags.scrolling = true;
131       displaySystem.flags.alpha = true;
132       return true;
133    }
134
135    void DestroyDisplaySystem(DisplaySystem displaySystem)
136    {
137       GDISystem gdiSystem = displaySystem.driverData;
138       delete gdiSystem.palette;
139       delete gdiSystem;
140       displaySystem.driverData = null;
141       if(theDisplaySystem == displaySystem) theDisplaySystem = null;
142    }
143
144    void DestroyDisplay(Display display)
145    {
146       GDIDisplay gdiDisplay = display.driverData;
147       ((subclass(DisplayDriver))class(LFBDisplayDriver)).DestroyDisplay(display);
148       delete gdiDisplay;
149       display.driverData = null;
150    }
151
152    void SetPalette(Display display, ColorAlpha * palette, bool colorMatch)
153    {
154       GDIDisplay gdiDisplay = display.driverData;
155       if(gdiDisplay.bitmap.pixelFormat == pixelFormat8)
156       {
157          int c;
158          ColorAlpha realPalette[256];
159          int reserved = (display.flags.fullScreen) ? 1 : 10;
160          HDC hdc = GetDC(display.window);
161          if(hdc)
162          {
163             if(reserved > 1)
164             {
165                GetSystemPaletteEntries(hdc,0,256,(PALETTEENTRY *)realPalette);
166                for(c = 0; c<256; c++)
167                   realPalette[c] = RGB(realPalette[c].color.r, realPalette[c].color.g, realPalette[c].color.b);
168
169                // *** Reserved Palette Handling ***
170                if(!palette)
171                {
172                   palette = GetDefaultPalette();
173                   CopyBytesBy4(realPalette+reserved,palette+reserved,256-2*reserved);
174                   CopyBytes(gdiDisplay.rgbLookup, defaultRGBLookup, 32768);
175                   for(c=0; c<256; c++)
176                   {
177                      int i;
178                      for(i=0; i<LIGHTSTEPS; i++)
179                      {
180                         gdiDisplay.lightTable[c][i] = gdiDisplay.rgbLookup[(uint16)Color555 {
181                                 (byte)(((uint16)realPalette[c].color.r*i) >> LIGHTSHIFT),
182                                 (byte)(((uint16)realPalette[c].color.g*i) >> LIGHTSHIFT),
183                                 (byte)(((uint16)realPalette[c].color.b*i) >> LIGHTSHIFT) }];
184                      }
185                   }
186                   CopyBytesBy4(gdiDisplay.bitmap.palette, realPalette, 256);
187                }
188                else
189                {
190                   CopyBytesBy4(realPalette+reserved,palette+reserved,256-2*reserved);
191                   ((subclass(DisplayDriver))class(LFBDisplayDriver)).SetPalette(display, realPalette, colorMatch);
192                }
193             }
194             else
195                ((subclass(DisplayDriver))class(LFBDisplayDriver)).SetPalette(display, palette, colorMatch);
196             // *********************************
197
198             gdiDisplay.logPalette->palVersion = 0x300;
199             gdiDisplay.logPalette->palNumEntries = 256;
200
201             for(c = 0; c < 256; c++)
202             {
203                gdiDisplay.logPalette->palPalEntry[c].peFlags = PC_NOCOLLAPSE;
204                gdiDisplay.logPalette->palPalEntry[c].peRed   = gdiDisplay.bitmap.palette[c].color.r;
205                gdiDisplay.logPalette->palPalEntry[c].peGreen = gdiDisplay.bitmap.palette[c].color.g;
206                gdiDisplay.logPalette->palPalEntry[c].peBlue  = gdiDisplay.bitmap.palette[c].color.b;
207             }
208
209             if(!gdiDisplay.palette)
210                gdiDisplay.palette = CreatePalette(gdiDisplay.logPalette);
211             else
212                SetPaletteEntries(gdiDisplay.palette, 0, 256, gdiDisplay.logPalette->palPalEntry);
213
214             SelectPalette(hdc, gdiDisplay.palette, FALSE);
215             RealizePalette(hdc);
216
217             SetDIBColorTable(gdiDisplay.memDC, 0, 256, (RGBQUAD *)gdiDisplay.bitmap.palette);
218
219             ReleaseDC(display.window, hdc);
220          }
221       }/*
222       else
223          (((subclass(DisplayDriver))class(LFBDisplayDriver)).SetPalette(display, palette, colorMatch);*/
224    }
225
226    bool CreateDisplay(Display display)
227    {
228       bool result = false;
229
230       if(display)
231       {
232          GDIDisplay gdiDisplay = display.driverData = GDIDisplay { };
233          if((gdiDisplay.logPalette = (LOGPALETTE *)new0 byte[sizeof(LOGPALETTE)+sizeof(PALETTEENTRY)*256]) &&
234             ((subclass(DisplayDriver))class(LFBDisplayDriver)).CreateDisplay(display))
235          {
236             gdiDisplay.bitmap.pixelFormat = /*display.alphaBlend ? pixelFormat888 : */display.displaySystem.pixelFormat;
237             result = true;
238          }
239       }
240       return result;
241    }
242
243    bool DisplaySize(Display display, int width, int height)
244    {
245       GDISystem gdiSystem = display.displaySystem.driverData;
246       GDIDisplay gdiDisplay = display.driverData;
247       bool result = false;
248       HDC hdc = GetDC(display.window);
249
250       display.width = width;
251       display.height = height;
252
253       if(!width || !height)
254          result = true;
255       else if(hdc)
256       {
257          BITMAPINFO * info;
258
259          if((info = (BITMAPINFO *)new0 byte[sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*256]))
260          {
261             HBITMAP newBitmap;
262             int c;
263
264             if(gdiDisplay.memDC) DeleteDC(gdiDisplay.memDC);
265             gdiDisplay.memDC = CreateCompatibleDC(hdc);
266             SetMapMode(gdiDisplay.memDC, MM_TEXT);
267
268             gdiDisplay.bitmap.pixelFormat = /*display.alphaBlend ? pixelFormat888 : */display.displaySystem.pixelFormat;
269
270             switch(GetColorDepthShifts(gdiDisplay.bitmap.pixelFormat))
271             {
272                case 0: gdiDisplay.bitmap.stride = (width + 3) & 0xFFFFFFFC; break;
273                case 1: gdiDisplay.bitmap.stride = (width + 1) & 0xFFFFFFFE; break;
274                case 2: gdiDisplay.bitmap.stride = width;                    break;
275             }
276             info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
277             info->bmiHeader.biPlanes = 1;
278             info->bmiHeader.biCompression = BI_RGB;
279             info->bmiHeader.biBitCount = (uint16)gdiSystem.depth;
280             info->bmiHeader.biWidth = gdiDisplay.bitmap.stride;
281             info->bmiHeader.biHeight = -height;
282
283             for(c=0; c<256; c++)
284             {
285                info->bmiColors[c].rgbReserved = 0;
286                info->bmiColors[c].rgbRed = gdiDisplay.bitmap.palette[c].color.r;
287                info->bmiColors[c].rgbGreen = gdiDisplay.bitmap.palette[c].color.g;
288                info->bmiColors[c].rgbBlue = gdiDisplay.bitmap.palette[c].color.b;
289             }
290
291             newBitmap = CreateDIBSection(hdc, info, DIB_RGB_COLORS, &gdiDisplay.bitmap.picture, null, 0);
292             if(newBitmap)
293             {
294                SelectObject(gdiDisplay.memDC, newBitmap);
295                if(gdiDisplay.memBitmap) DeleteObject(gdiDisplay.memBitmap);
296                gdiDisplay.memBitmap = newBitmap;
297
298                //SelectObject(gdiDisplay.memDC,GetStockObject(DC_PEN));
299                //SelectObject(gdiDisplay.memDC,GetStockObject(DC_BRUSH));
300
301                result = ((subclass(DisplayDriver))class(LFBDisplayDriver)).DisplaySize(display, width, height);
302             }
303             else
304                Log("Error creating DIB Section\n");
305             delete info;
306          }
307          ReleaseDC(display.window, hdc);
308       }
309       return result;
310    }
311
312    void DisplayPosition(Display display, int x, int y)
313    {
314       GDIDisplay gdiDisplay = display.driverData;
315       gdiDisplay.offset.x = x;
316       gdiDisplay.offset.y = y;
317
318    }
319
320    void RestorePalette(Display display)
321    {
322       GDIDisplay gdiDisplay = display.driverData;
323       HDC hdc = GetDC(display.window);
324       if(hdc)
325       {
326          if(gdiDisplay.palette)
327          {
328             SelectPalette(hdc, gdiDisplay.palette, FALSE);
329             RealizePalette(hdc);
330          }
331          ReleaseDC(display.window,hdc);
332       }
333    }
334
335    #define MAX_EXPOSED  50
336
337    void StartUpdate(Display display)
338    {
339       GDIDisplay gdiDisplay = display.driverData;
340       if(!display.alphaBlend || display.pixelFormat != pixelFormat888)
341       {
342          GdiSetBatchLimit(1000);
343          gdiDisplay.hdc = GetDC(display.window);
344       }
345       gdiDisplay.rgn = CreateRectRgn(0,0,0,0);
346       //gdiDisplay.data = (RGNDATA *) new0 byte[(sizeof(RGNDATAHEADER) + sizeof(RECT) * MAX_EXPOSED)];
347       if(gdiDisplay.palette)
348          SelectPalette(gdiDisplay.hdc, gdiDisplay.palette, FALSE);
349    }
350
351    void Scroll(Display display, Box scroll, int x, int y, Extent dirty)
352    {
353       GDIDisplay gdiDisplay = display.driverData;
354       int i;
355       uint numBytes;
356       Box box = scroll;
357
358       box.right += 1;
359       box.bottom += 1;
360
361       if(!display.alphaBlend || display.pixelFormat != pixelFormat888)
362       {
363          // printf("Box: %d, %d, %d, %d\n", box.left, box.top, box.right, box.bottom);
364          ScrollDC(gdiDisplay.hdc, -x, -y, (RECT *)&box, (RECT *)&box, gdiDisplay.rgn, null);
365       }
366       ScrollDC(gdiDisplay.memDC, -x, -y, (RECT *)&box, (RECT *)&box, null, null);
367
368       numBytes = GetRegionData(gdiDisplay.rgn, 0, null);
369       gdiDisplay.data = (RGNDATA *) new0 byte[numBytes];
370       GetRegionData(gdiDisplay.rgn, numBytes, gdiDisplay.data);
371       /*
372       // gdiDisplay.data = (RGNDATA *) new0 byte[(sizeof(RGNDATAHEADER) + sizeof(RECT) * MAX_EXPOSED)];
373       printf("Number of bytes needed: %d\n", numBytes);
374       gdiDisplay.data = (RGNDATA *) new0 byte[numBytes];
375       printf("Data: %X\n", gdiDisplay.data);
376       printf("Return Value: %d, Count: %d\n", numBytes, gdiDisplay.data->rdh.nCount);
377       if(!numBytes)
378       {
379          int error = GetLastError();
380          printf("GetLastError Returned: %d\n", error);
381       }
382       */
383
384       for(i = 0; i<gdiDisplay.data->rdh.nCount; i++)
385       {
386          Extent temp { };
387          Box box = ((Box *)gdiDisplay.data->Buffer)[i];
388          //box.bottom -= 1;
389          //box.right -= 1;
390          temp.Clear();
391          dirty.UnionBox(box, temp);
392          temp.Free(null);
393       }
394       delete gdiDisplay.data;
395    }
396
397    void Update(Display display, Box updateBox)
398    {
399       GDIDisplay gdiDisplay = display.driverData;
400       if(display.alphaBlend && display.pixelFormat == pixelFormat888)
401       {
402          HDC hdc = GetDC(0);
403          POINT point = { gdiDisplay.offset.x, gdiDisplay.offset.y};
404          POINT srcPoint = { 0, 0 };
405          BLENDFUNCTION blend = { 0 };
406          SIZE size;
407          size.cx = display.width;
408          size.cy = display.height;
409          blend.BlendOp = AC_SRC_OVER;
410          blend.BlendFlags = 0;
411          blend.SourceConstantAlpha = 255;
412          blend.AlphaFormat = AC_SRC_ALPHA;
413          UpdateLayeredWindow(display.window, hdc, &point, &size, gdiDisplay.memDC, &srcPoint, 0, &blend, ULW_ALPHA);
414          ReleaseDC(0, hdc);
415       }
416       else
417       {
418          BitBlt(gdiDisplay.hdc,
419             updateBox.left,updateBox.top,
420             updateBox.right - updateBox.left + 1, updateBox.bottom - updateBox.top + 1,
421             gdiDisplay.memDC, updateBox.left, updateBox.top, SRCCOPY);
422       }
423    }
424
425    void EndUpdate(Display display)
426    {
427       GDIDisplay gdiDisplay = display.driverData;
428       DeleteObject(gdiDisplay.rgn);
429       if(!display.alphaBlend || display.pixelFormat != pixelFormat888)
430          ReleaseDC(display.window,gdiDisplay.hdc);
431
432       // delete gdiDisplay.data;
433    }
434
435    void FreeBitmap(DisplaySystem displaySystem, Bitmap bitmap)
436    {
437       GDIBitmap gdiBitmap = bitmap.driverData;
438       if(gdiBitmap)
439       {
440          if(gdiBitmap.memDC)
441          {
442             DeleteDC(gdiBitmap.memDC);
443             gdiBitmap.memDC = null;
444          }
445          if(gdiBitmap.memBitmap)
446          {
447             DeleteObject(gdiBitmap.memBitmap);
448             gdiBitmap.memBitmap = null;
449          }
450          delete gdiBitmap;
451          bitmap.driverData = null;
452          bitmap.picture = null;
453          if(bitmap.palette && bitmap.allocatePalette)
454             delete bitmap.palette;
455          else
456             bitmap.palette = null;
457       }
458       else
459          ((subclass(DisplayDriver))class(LFBDisplayDriver)).FreeBitmap(displaySystem, bitmap);
460    }
461
462    bool MakeDDBitmap(DisplaySystem displaySystem, Bitmap bitmap, bool mipMaps)
463    {
464       /*if(bitmap.alphaBlend)
465          return true;
466       else*/
467          return ((subclass(DisplayDriver))class(LFBDisplayDriver)).MakeDDBitmap(displaySystem, bitmap, mipMaps);
468    }
469
470    void ReleaseSurface(Display display, Surface surface)
471    {
472       GDISurface gdiSurface = surface.driverData;
473       //GDIDisplay gdiDisplay = display ? display.driverData : null;
474
475       if(gdiSurface.rgn)
476       {
477          SelectClipRgn(gdiSurface.hdc,null);
478          DeleteObject(gdiSurface.rgn);
479          gdiSurface.rgn = null;
480       }
481       ((subclass(DisplayDriver))class(LFBDisplayDriver)).ReleaseSurface(display, surface);
482       // delete gdiSurface; THIS IS ALREDY DONE IN LFB
483       surface.driverData = null;
484    }
485
486    bool GetBitmapSurface(DisplaySystem displaySystem, Surface surface, Bitmap bitmap, int x, int y, Box clip)
487    {
488       bool result = false;
489       GDIBitmap gdiBitmap = bitmap.driverData;
490       GDISurface gdiSurface;
491
492       if((surface.driverData = gdiSurface = GDISurface { }))
493       {
494          if(((subclass(DisplayDriver))class(LFBDisplayDriver)).GetBitmapSurface(displaySystem, surface, bitmap, x, y, clip))
495          {
496             gdiSurface.hdc = gdiBitmap.memDC;
497             gdiSurface.rgn = CreateRectRgn(x+clip.left,y+clip.top,x+clip.right+1,y+clip.bottom+1);
498             //if(gdiSurface.rgn)
499             {
500                if(gdiSurface.rgn)
501                   SelectClipRgn(gdiSurface.hdc,gdiSurface.rgn);
502                surface.offset.x = x;
503                surface.offset.y = y;
504                surface.unclippedBox = surface.box = clip;
505
506                result = true;
507             }
508          }
509       }
510       return result;
511    }
512
513    bool GetSurface(Display display, Surface surface, int x,int y, Box clip)
514    {
515       bool result = false;
516       GDIDisplay gdiDisplay = display.driverData;
517       GDISurface gdiSurface;
518       GDISystem gdiSystem = display.displaySystem.driverData;
519
520       if((surface.driverData = gdiSurface = GDISurface { }))
521       {
522          if(((subclass(DisplayDriver))class(LFBDisplayDriver)).GetSurface(display, surface, x, y, clip))
523          {
524             gdiSurface.hdc = gdiDisplay.memDC ? gdiDisplay.memDC : gdiSystem.tmpDC;
525             gdiSurface.rgn = CreateRectRgn(x+clip.left,y+clip.top,x+clip.right+1,y+clip.bottom+1);
526             //if(gdiSurface.rgn)
527             {
528                if(gdiSurface.rgn)
529                   SelectClipRgn(gdiSurface.hdc,gdiSurface.rgn);
530                surface.offset.x = x;
531                surface.offset.y = y;
532                surface.unclippedBox = surface.box = clip;
533
534                SetDCBrushColor(gdiSurface.hdc, RGB(0,0,0));
535                SetDCPenColor(gdiSurface.hdc, RGB(255,255,255));
536
537                result = true;
538             }
539          }
540       }
541       return result;
542    }
543
544    void Clip(Display display, Surface surface, Box clip)
545    {
546       GDISurface gdiSurface = surface.driverData;
547       HRGN clippedRgn = null;
548       if(clip != null)
549       {
550          Box box = clip;
551
552          box.Clip(surface.unclippedBox);
553
554          surface.box = box;
555
556          if(box.right >= box.left && box.bottom >= box.top)
557          {
558             box.left += surface.offset.x;
559             box.top  += surface.offset.y;
560             box.right+= surface.offset.x;
561             box.bottom += surface.offset.y;
562             clippedRgn = CreateRectRgn(box.left, box.top, box.right+1, box.bottom+1);
563          }
564          else
565             clippedRgn = CreateRectRgn(0, 0, 0, 0);
566
567          if(clippedRgn)
568             SelectClipRgn(gdiSurface.hdc,clippedRgn);
569       }
570       else if(gdiSurface.clippedRgn)
571       {
572          surface.box = surface.unclippedBox;
573          SelectClipRgn(gdiSurface.hdc,gdiSurface.rgn);
574       }
575       if(gdiSurface.clippedRgn)
576          DeleteObject(gdiSurface.clippedRgn);
577       gdiSurface.clippedRgn = clippedRgn;
578    }
579
580    bool GrabScreen(Display display, Bitmap bitmap, int x, int y, unsigned int w, unsigned int h)
581    {
582       bool result = false;
583       if(display)
584       {
585          //GDIDisplay gdiDisplay = display.driverData;
586          result = ((subclass(DisplayDriver))class(LFBDisplayDriver)).GrabScreen(display, bitmap, x,y, w,h);
587       }
588       else
589       {
590          PixelFormat format = theDisplaySystem.pixelFormat;
591          if(bitmap.Allocate(null, w, h, 0, format, false))
592          {
593             BITMAPINFO *info = (BITMAPINFO *)new0 byte[sizeof(BITMAPINFO)+sizeof(RGBQUAD)*256];
594             HDC hdc = GetDC(HWND_DESKTOP);
595             HDC memDC = CreateCompatibleDC(hdc);
596             HBITMAP screenBmp = CreateCompatibleBitmap(hdc, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
597             HBITMAP back = SelectObject(memDC, screenBmp);
598             uint16 depth;
599
600             switch(format)
601             {
602                case pixelFormat8: depth = 8; break;
603                case pixelFormat555: depth = 16; break;
604                case pixelFormat888:
605                default:
606                   depth = 32;
607                   format = pixelFormat888;
608             }
609             BitBlt(memDC, 0,0, w,h, hdc,x,y,SRCCOPY);
610
611             info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
612             info->bmiHeader.biPlanes = 1;
613             info->bmiHeader.biCompression = BI_RGB;
614             info->bmiHeader.biBitCount = depth;
615             info->bmiHeader.biWidth = bitmap.width;
616             info->bmiHeader.biHeight = -bitmap.height;
617             GetDIBits(memDC, screenBmp, 0, bitmap.height, bitmap.picture, info, DIB_RGB_COLORS);
618             // TODO: Proper indexed mode support
619             if(format == pixelFormat8)
620                bitmap.palette = GetDefaultPalette();
621             delete info;
622
623             ReleaseDC(HWND_DESKTOP, hdc);
624             SelectObject(memDC, back);
625             DeleteObject(screenBmp);
626             DeleteDC(memDC);
627
628             result = true;
629          }
630       }
631       return result;
632    }
633
634    void SetForeground(Display display, Surface surface, ColorAlpha color)
635    {
636       ((subclass(DisplayDriver))class(LFBDisplayDriver)).SetForeground(display, surface, color);
637       if(true) //display.alphaBlend)
638       {
639          GDISurface gdiSurface = surface.driverData;
640          //GDIDisplay gdiDisplay = display ? display.driverData : null;
641          COLORREF rgb = RGB(color.color.r, color.color.g, color.color.b);
642
643          SetTextColor(gdiSurface.hdc, rgb);
644          gdiSurface.color = rgb;
645       }
646    }
647
648    void SetBackground(Display display, Surface surface, ColorAlpha color)
649    {
650       ((subclass(DisplayDriver))class(LFBDisplayDriver)).SetBackground(display, surface, color);
651
652       if(display && (!display.alphaBlend || display.pixelFormat != pixelFormat888))
653       {
654          GDISurface gdiSurface = surface.driverData;
655          GDIDisplay gdiDisplay = display ? display.driverData : null;
656          COLORREF rgb;
657
658          if(gdiSurface.bitmap.pixelFormat == pixelFormat8 && display)
659             color = gdiSurface.bitmap.palette[gdiDisplay.rgbLookup[(uint16)(Color555) color]];
660          rgb = RGB(color.color.r, color.color.g, color.color.b);
661
662          SetBkColor(gdiSurface.hdc, rgb);
663          SetDCBrushColor(gdiSurface.hdc, rgb);
664          SetDCPenColor(gdiSurface.hdc, rgb);
665       }
666    }
667
668    ColorAlpha GetPixel(Display display, Surface surface, int x, int y)
669    {
670       return 0;
671    }
672
673    void PutPixel(Display display, Surface surface, int x, int y)
674    {
675       //GDIDisplay gdiDisplay = display ? display.driverData : null;
676       //GDISurface gdiSurface = surface.driverData;
677       // SetPixel(gdiSurface.hdc, x + surface.offset.x, y + surface.offset.y, gdiSurface.color);
678       ((subclass(DisplayDriver))class(LFBDisplayDriver)).PutPixel(display, surface, x,y);
679    }
680
681    void DrawLine(Display display, Surface surface, int x1, int y1, int x2, int y2)
682    {
683       //GDIDisplay gdiDisplay = display ? display.driverData : null;
684       ((subclass(DisplayDriver))class(LFBDisplayDriver)).DrawLine(display, surface, x1,y1,x2,y2);
685    }
686
687    void Rectangle(Display display, Surface surface,int x1,int y1,int x2,int y2)
688    {
689       //GDIDisplay gdiDisplay = display ? display.driverData : null;
690       ((subclass(DisplayDriver))class(LFBDisplayDriver)).Rectangle(display, surface, x1,y1,x2,y2);
691    }
692
693    void Area(Display display, Surface surface,int x1,int y1,int x2,int y2)
694    {
695       //GDIDisplay gdiDisplay = display ? display.driverData : null;
696       ((subclass(DisplayDriver))class(LFBDisplayDriver)).Area(display, surface, x1,y1,x2,y2);
697
698       /*
699       GDISurface gdiSurface = surface.driverData;
700       x1 += surface.offset.x;
701       x2 += surface.offset.x;
702       y1 += surface.offset.y;
703       y2 += surface.offset.y;
704       SetBkMode(gdiSurface.hdc, OPAQUE);
705       //SetDCBrushColor(gdiSurface.hdc, BGR(eSystem_GetRandom(0,255), eSystem_GetRandom(0,255), eSystem_GetRandom(0,255)));
706       PatBlt(gdiSurface.hdc,x1,y1,x2-x1+1,y2-y1+1,PATCOPY);
707       SetBkMode(gdiSurface.hdc, surface.textOpacity ? OPAQUE : TRANSPARENT);
708       */
709    }
710
711    void Clear(Display display, Surface surface, ClearType type)
712    {
713       /*if(type != depthBuffer)
714          Area(display, surface,surface.box.left,surface.box.top,surface.box.right,surface.box.bottom);*/
715       ((subclass(DisplayDriver))class(LFBDisplayDriver)).Clear(display, surface, type);
716    }
717
718    bool ConvertBitmap(DisplaySystem displaySystem, Bitmap src, PixelFormat format, ColorAlpha * palette)
719    {
720       if(src.driverData)
721          return true;
722       else
723       {
724          return ((subclass(DisplayDriver))class(LFBDisplayDriver)).ConvertBitmap(displaySystem, src, format, palette);
725       }
726    }
727
728    bool AllocateBitmap(DisplaySystem displaySystem, Bitmap bitmap, int width, int height, int stride, PixelFormat format, bool allocatePalette)
729    {
730       bool result = false;
731       HWND hwnd = displaySystem ? displaySystem.window : GetDesktopWindow();
732       HDC hdc = GetDC(hwnd);
733       if(hdc)
734       {
735          GDIBitmap gdiBitmap = bitmap.driverData = GDIBitmap { };
736          if(gdiBitmap)
737          {
738             BITMAPINFO *info = (BITMAPINFO *)new0 byte[sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*256];
739
740             if(info)
741             {
742                int c;
743                uint16 depth;
744
745                switch(format)
746                {
747                   case pixelFormat8: depth = 8; break;
748                   case pixelFormat555: depth = 16; break;
749                   case pixelFormat888:
750                   default:
751                      depth = 32;
752                      format = pixelFormat888;
753                }
754
755                if(!stride)
756                {
757                   switch(GetColorDepthShifts(format))
758                   {
759                      case 0: stride = (width + 3) & 0xFFFFFFFC; break;
760                      case 1: stride = (width + 1) & 0xFFFFFFFE; break;
761                      case 2: stride = width;                    break;
762                   }
763                }
764
765                bitmap.stride=stride;
766                bitmap.width=width;
767                bitmap.height=height;
768                bitmap.size=(uint)stride*(uint)height;
769                bitmap.sizeBytes = bitmap.size << GetColorDepthShifts(format);
770                bitmap.pixelFormat = format;
771                bitmap.transparent = false;
772                bitmap.allocatePalette = allocatePalette;
773                if(allocatePalette)
774                {
775                   bitmap.palette = new0 ColorAlpha[256];
776                   if(bitmap.palette)
777                      CopyBytesBy4(bitmap.palette, GetDefaultPalette(), 256);
778                }
779                else
780                   bitmap.palette = GetDefaultPalette();
781
782                gdiBitmap.memDC = CreateCompatibleDC(hdc);
783
784                info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
785                info->bmiHeader.biPlanes = 1;
786                info->bmiHeader.biCompression = BI_RGB;
787                info->bmiHeader.biBitCount = depth;
788                info->bmiHeader.biWidth = bitmap.stride;
789                info->bmiHeader.biHeight = -height;
790
791                for(c=0; c<256; c++)
792                {
793                   info->bmiColors[c].rgbReserved = 0;
794                   info->bmiColors[c].rgbRed = bitmap.palette[c].color.r;
795                   info->bmiColors[c].rgbGreen = bitmap.palette[c].color.g;
796                   info->bmiColors[c].rgbBlue = bitmap.palette[c].color.b;
797                }
798
799                gdiBitmap.memBitmap = CreateDIBSection(hdc, info, DIB_RGB_COLORS, &bitmap.picture, null, 0);
800                if(gdiBitmap.memBitmap)
801                {
802                   SelectObject(gdiBitmap.memDC, gdiBitmap.memBitmap);
803                   SetBkMode(gdiBitmap.memDC, TRANSPARENT);
804                   result = true;
805                }
806                delete info;
807             }
808             if(!result)
809                FreeBitmap(displaySystem, bitmap);
810          }
811       }
812       ReleaseDC(hwnd, hdc);
813
814       return result;
815    }
816
817    void Blit(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h)
818    {
819       //GDIDisplay gdiDisplay = display ? display.driverData : null;
820       ((subclass(DisplayDriver))class(LFBDisplayDriver)).Blit(display, surface, src, dx, dy, sx, sy, w, h);
821    }
822
823    void Stretch(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
824    {
825       //GDIDisplay gdiDisplay = display ? display.driverData : null;
826       ((subclass(DisplayDriver))class(LFBDisplayDriver)).Stretch(display, surface, src, dx, dy, sx, sy, w, h, sw, sh);
827    }
828
829    void Filter(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
830    {
831       //GDIDisplay gdiDisplay = display ? display.driverData : null;
832       ((subclass(DisplayDriver))class(LFBDisplayDriver)).Filter(display, surface, src, dx, dy, sx, sy, w, h, sw, sh);
833    }
834
835    void BlitDI(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h)
836    {
837       Blit(display,surface,src,dx,dy,sx,sy,w,h);
838    }
839
840    void StretchDI(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
841    {
842       Stretch(display, surface, src, dx, dy, sx, sy, w, h, sw, sh);
843    }
844
845    void FilterDI(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
846    {
847       Filter(display, surface, src, dx, dy, sx, sy, w, h, sw, sh);
848    }
849
850    Font LoadFont(DisplaySystem displaySystem, const char * faceName, float size, FontFlags flags)
851    {
852       if(false) //display.alphaBlend)
853          return ((subclass(DisplayDriver))class(LFBDisplayDriver)).LoadFont(displaySystem, faceName, size, flags);
854       else
855       {
856          GDIFont font { };
857          HDC hdc = GetDC(null);
858          int pixels = GetDeviceCaps(hdc, LOGPIXELSY);
859          strcpy(font.faceName, faceName);
860          font.size = size;
861          font.flags = flags;
862          font.gdiFont = CreateFontA(-(int)((float)size * pixels / 72 + 0.5),
863             0,0,0, flags.bold ? FW_BOLD : FW_NORMAL, flags.italic ? TRUE : FALSE,
864                flags.underline ? TRUE : FALSE, 0, DEFAULT_CHARSET,
865                            OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
866                            DEFAULT_PITCH|FF_DONTCARE, faceName);
867
868          ReleaseDC(null, hdc);
869          return (Font)font;
870       }
871    }
872
873    void UnloadFont(DisplaySystem displaySystem, Font font)
874    {
875       GDIFont gdiFont = (GDIFont) font;
876       if(false) //display.alphaBlend)
877          ((subclass(DisplayDriver))class(LFBDisplayDriver)).UnloadFont(displaySystem, font);
878       else if(gdiFont)
879       {
880          if(gdiFont.gdiFont)
881             DeleteObject(gdiFont.gdiFont);
882          if(gdiFont.font)
883             ((subclass(DisplayDriver))class(LFBDisplayDriver)).UnloadFont(displaySystem, gdiFont.font);
884          delete gdiFont;
885       }
886    }
887
888    void TextFont(Display display, Surface surface, Font font)
889    {
890       GDIFont gdiFont = (GDIFont) font;
891       if(display.alphaBlend && display.pixelFormat == pixelFormat888)
892       {
893          if(!gdiFont.font)
894          {
895             gdiFont.font = ((subclass(DisplayDriver))class(LFBDisplayDriver)).LoadFont(display.displaySystem,
896                gdiFont.faceName, gdiFont.size, gdiFont.flags);
897          }
898          ((subclass(DisplayDriver))class(LFBDisplayDriver)).TextFont(display, surface, gdiFont.font);
899       }
900       else
901       {
902          GDISurface gdiSurface = surface.driverData;
903          SelectObject(gdiSurface.hdc, gdiFont.gdiFont);
904       }
905    }
906
907    void TextOpacity(Display display, Surface surface, bool opaque)
908    {
909       ((subclass(DisplayDriver))class(LFBDisplayDriver)).TextOpacity(display, surface, opaque);
910       if(display && (!display.alphaBlend || display.pixelFormat != pixelFormat888))
911       {
912          GDISurface gdiSurface = surface.driverData;
913          SetBkMode(gdiSurface.hdc, opaque ? OPAQUE : TRANSPARENT);
914       }
915    }
916
917    void WriteText(Display display, Surface surface, int x, int y, const char * text, int len)
918    {
919       if(display.alphaBlend && display.pixelFormat == pixelFormat888)
920       {
921          GDIFont gdiFont = (GDIFont)surface.font;
922          if(!gdiFont.font)
923          {
924             gdiFont.font = ((subclass(DisplayDriver))class(LFBDisplayDriver)).LoadFont(display.displaySystem,
925                gdiFont.faceName, gdiFont.size, gdiFont.flags);
926          }
927          if(surface.textOpacity)
928          {
929             int w, h;
930             ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(display.displaySystem, gdiFont.font, text, len, &w, &h);
931             Area(display, surface, x, y, x+w-1, y+h-1);
932          }
933          ((subclass(DisplayDriver))class(LFBDisplayDriver)).WriteText(display, surface, x, y, text, len);
934       }
935       else
936       {
937          GDISurface gdiSurface = surface.driverData;
938          int wordCount;
939          uint16 * u16text = UTF8toUTF16Len(text, len, &wordCount);
940
941          TextOut(gdiSurface.hdc, x + surface.offset.x, y + surface.offset.y, u16text, wordCount);
942          if(display.alphaBlend && display.pixelFormat == pixelFormat888)
943          {
944             int w, h;
945             FontExtent(display.displaySystem, surface.font, text, len, &w, &h);
946             surface.writeColor = false;
947             SetBackground(display, surface, surface.foreground);
948             Area(display, surface,x-2,y-2,x+w+1,y+h+1);
949             SetBackground(display, surface, surface.background);
950             surface.writeColor = true;
951          }
952          delete u16text;
953       }
954    }
955
956    void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height)
957    {
958       if(display && display.alphaBlend && display.pixelFormat == pixelFormat888)
959          ((subclass(DisplayDriver))class(LFBDisplayDriver)).TextExtent(display, surface, text, len, width, height);
960       else
961       {
962          GDISurface gdiSurface = surface.driverData;
963          SIZE space, size;
964          uint realLen;
965          int wordCount;
966          uint16 * u16text = UTF8toUTF16Len(text, len, &wordCount);
967
968          for(realLen = 0; realLen<wordCount && u16text[realLen]; realLen++);
969          GetTextExtentPoint32A(gdiSurface.hdc, " ", 1, &space);
970          GetTextExtentPoint32(gdiSurface.hdc, u16text, realLen, &size);
971          delete u16text;
972
973          // UNICODE FIX: proper space computation
974          if(width) *width = size.cx + (wordCount - realLen) * space.cx;
975          if(height)
976          {
977             if(realLen)
978                *height = size.cy;
979             else
980                *height = wordCount ? space.cy : 0;
981          }
982       }
983    }
984
985    void FontExtent(DisplaySystem displaySystem, Font font, const char * text, int len, int * width, int * height)
986    {
987       if(false) //display.alphaBlend)
988         ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(displaySystem, font, text, len, width, height);
989       else
990       {
991          GDISystem gdiSystem = displaySystem.driverData;
992          if(gdiSystem.tmpDC)
993          {
994             Surface surface { };
995             GDIFont gdiFont = (GDIFont)font;
996             GDISurface gdiSurface { };
997
998             surface.driverData = gdiSurface;
999             gdiSurface.hdc = gdiSystem.tmpDC;
1000
1001             SelectObject(gdiSurface.hdc, gdiFont ? gdiFont.gdiFont : null);
1002             TextExtent(null, surface, text, len, width, height);
1003
1004             delete surface;
1005             delete gdiSurface;
1006          }
1007          else
1008          {
1009             if(width) *width = 0;
1010             if(height) *height = 0;
1011          }
1012       }
1013    }
1014
1015    void DrawingChar(Display display, Surface surface, byte character)
1016    {
1017
1018    }
1019
1020    void LineStipple(Display display, Surface surface, uint stipple)
1021    {
1022       //GDIDisplay gdiDisplay = display ? display.driverData : null;
1023       ((subclass(DisplayDriver))class(LFBDisplayDriver)).LineStipple(display, surface, stipple);
1024    }
1025
1026    bool Lock(Display display)
1027    {
1028       return true;
1029    }
1030
1031    void Unlock(Display display)
1032    {
1033    }
1034 }
1035
1036 #endif