compiler: More compatible handling of stdint.h inclusion
[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 0x0500
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       int returnValue;
401       if(display.alphaBlend && display.pixelFormat == pixelFormat888)
402       {
403          HDC hdc = GetDC(0);
404          POINT point = { gdiDisplay.offset.x, gdiDisplay.offset.y};
405          POINT srcPoint = { 0, 0 };
406          BLENDFUNCTION blend = { 0 };
407          SIZE size;
408          size.cx = display.width;
409          size.cy = display.height;
410          blend.BlendOp = AC_SRC_OVER;
411          blend.BlendFlags = 0;
412          blend.SourceConstantAlpha = 255;
413          blend.AlphaFormat = AC_SRC_ALPHA;
414          UpdateLayeredWindow(display.window, hdc, &point, &size, gdiDisplay.memDC, &srcPoint, 0, &blend, ULW_ALPHA);
415          ReleaseDC(0, hdc);
416       }
417       else
418       {
419          BitBlt(gdiDisplay.hdc, 
420             updateBox.left,updateBox.top, 
421             updateBox.right - updateBox.left + 1, updateBox.bottom - updateBox.top + 1,
422             gdiDisplay.memDC, updateBox.left, updateBox.top, SRCCOPY);
423       }
424    }
425
426    void EndUpdate(Display display)
427    {
428       GDIDisplay gdiDisplay = display.driverData;
429       DeleteObject(gdiDisplay.rgn);
430       if(!display.alphaBlend || display.pixelFormat != pixelFormat888)
431          ReleaseDC(display.window,gdiDisplay.hdc);
432
433       // delete gdiDisplay.data;
434    }
435
436    void FreeBitmap(DisplaySystem displaySystem, Bitmap bitmap)
437    {
438       GDIBitmap gdiBitmap = bitmap.driverData;
439       if(gdiBitmap)
440       {
441          if(gdiBitmap.memDC)
442          {
443             DeleteDC(gdiBitmap.memDC);
444             gdiBitmap.memDC = null;
445          }
446          if(gdiBitmap.memBitmap)
447          {
448             DeleteObject(gdiBitmap.memBitmap);
449             gdiBitmap.memBitmap = null;
450          }
451          delete gdiBitmap;
452          bitmap.driverData = null;
453          bitmap.picture = null;
454          if(bitmap.palette && bitmap.allocatePalette)
455             delete bitmap.palette;
456          else
457             bitmap.palette = null;
458       }
459       else
460          ((subclass(DisplayDriver))class(LFBDisplayDriver)).FreeBitmap(displaySystem, bitmap);
461    }
462
463    bool MakeDDBitmap(DisplaySystem displaySystem, Bitmap bitmap, bool mipMaps)
464    {
465       /*if(bitmap.alphaBlend)
466          return true;
467       else*/
468          return (((subclass(DisplayDriver))class(LFBDisplayDriver)).MakeDDBitmap(displaySystem, bitmap, mipMaps);
469    }
470
471    void ReleaseSurface(Display display, Surface surface)
472    {
473       GDISurface gdiSurface = surface.driverData;
474       GDIDisplay gdiDisplay = display ? display.driverData : null;
475
476       if(gdiSurface.rgn)
477       {
478          SelectClipRgn(gdiSurface.hdc,null);
479          DeleteObject(gdiSurface.rgn);
480          gdiSurface.rgn = null;
481       }
482       ((subclass(DisplayDriver))class(LFBDisplayDriver)).ReleaseSurface(display, surface);
483       // delete gdiSurface; THIS IS ALREDY DONE IN LFB
484       surface.driverData = null;
485    }
486
487    bool GetBitmapSurface(DisplaySystem displaySystem, Surface surface, Bitmap bitmap, int x, int y, Box clip)
488    {
489       bool result = false;
490       GDIBitmap gdiBitmap = bitmap.driverData;
491       GDISurface gdiSurface;
492
493       if((surface.driverData = gdiSurface = GDISurface { }))
494       {
495          if(((subclass(DisplayDriver))class(LFBDisplayDriver)).GetBitmapSurface(displaySystem, surface, bitmap, x, y, clip))
496          {
497             gdiSurface.hdc = gdiBitmap.memDC;
498             gdiSurface.rgn = CreateRectRgn(x+clip.left,y+clip.top,x+clip.right+1,y+clip.bottom+1);
499             //if(gdiSurface.rgn)
500             {
501                if(gdiSurface.rgn)
502                   SelectClipRgn(gdiSurface.hdc,gdiSurface.rgn);
503                surface.offset.x = x;
504                surface.offset.y = y;
505                surface.unclippedBox = surface.box = clip;
506          
507                result = true;
508             }
509          }
510       }
511       return result;
512    }
513
514    bool GetSurface(Display display, Surface surface, int x,int y, Box clip)
515    {
516       bool result = false;
517       GDIDisplay gdiDisplay = display.driverData;
518       GDISurface gdiSurface;
519       GDISystem gdiSystem = display.displaySystem.driverData;
520
521       if((surface.driverData = gdiSurface = GDISurface { }))
522       {
523          if(((subclass(DisplayDriver))class(LFBDisplayDriver)).GetSurface(display, surface, x, y, clip))
524          {
525             gdiSurface.hdc = gdiDisplay.memDC ? gdiDisplay.memDC : gdiSystem.tmpDC;
526             gdiSurface.rgn = CreateRectRgn(x+clip.left,y+clip.top,x+clip.right+1,y+clip.bottom+1);
527             //if(gdiSurface.rgn)
528             {
529                if(gdiSurface.rgn)
530                   SelectClipRgn(gdiSurface.hdc,gdiSurface.rgn);
531                surface.offset.x = x;
532                surface.offset.y = y;
533                surface.unclippedBox = surface.box = clip;
534          
535                SetDCBrushColor(gdiSurface.hdc, RGB(0,0,0));
536                SetDCPenColor(gdiSurface.hdc, RGB(255,255,255));
537
538                result = true;
539             }
540          }
541       }
542       return result;
543    }
544
545    void Clip(Display display, Surface surface, Box clip)
546    {
547       GDISurface gdiSurface = surface.driverData;
548       HRGN clippedRgn = null; 
549       if(clip != null)
550       {
551          Box box = clip;
552
553          box.Clip(surface.unclippedBox);
554
555          surface.box = box;
556
557          if(box.right > box.left && box.bottom > box.top)
558          {
559             box.left += surface.offset.x;
560             box.top  += surface.offset.y;
561             box.right+= surface.offset.x;
562             box.bottom += surface.offset.y;
563             clippedRgn = CreateRectRgn(box.left, box.top, box.right+1, box.bottom+1);
564          }
565          else
566             clippedRgn = CreateRectRgn(0, 0, 0, 0);
567          
568          if(clippedRgn)
569             SelectClipRgn(gdiSurface.hdc,clippedRgn);
570       }
571       else if(gdiSurface.clippedRgn)
572       {
573          surface.box = surface.unclippedBox;
574          SelectClipRgn(gdiSurface.hdc,gdiSurface.rgn);
575       }
576       if(gdiSurface.clippedRgn)
577          DeleteObject(gdiSurface.clippedRgn);
578       gdiSurface.clippedRgn = clippedRgn;
579    }
580
581    bool GrabScreen(Display display, Bitmap bitmap, int x, int y, unsigned int w, unsigned int h)
582    {
583       bool result = false;
584       if(display)
585       {
586          GDIDisplay gdiDisplay = display.driverData;
587          result = ((subclass(DisplayDriver))class(LFBDisplayDriver)).GrabScreen(display, bitmap, x,y, w,h);
588       }
589       else
590       {
591          PixelFormat format = theDisplaySystem.pixelFormat;
592          if(bitmap.Allocate(null, w, h, 0, format, false))
593          {
594             BITMAPINFO *info = (BITMAPINFO *)new0 byte[sizeof(BITMAPINFO)+sizeof(RGBQUAD)*256];
595             HDC hdc = GetDC(HWND_DESKTOP);
596             HDC memDC = CreateCompatibleDC(hdc);
597             HBITMAP screenBmp = CreateCompatibleBitmap(hdc, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
598             HBITMAP back = SelectObject(memDC, screenBmp);
599             uint16 depth;
600             
601             switch(format)
602             {
603                case pixelFormat8: depth = 8; break;
604                case pixelFormat555: depth = 16; break;
605                case pixelFormat888:
606                default:
607                   depth = 32;
608                   format = pixelFormat888;
609             }
610             BitBlt(memDC, 0,0, w,h, hdc,x,y,SRCCOPY);
611
612             info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
613             info->bmiHeader.biPlanes = 1;
614             info->bmiHeader.biCompression = BI_RGB;
615             info->bmiHeader.biBitCount = depth;
616             info->bmiHeader.biWidth = bitmap.width;
617             info->bmiHeader.biHeight = -bitmap.height;
618             GetDIBits(memDC, screenBmp, 0, bitmap.height, bitmap.picture, info, DIB_RGB_COLORS);
619             // TODO: Proper indexed mode support
620             if(format == pixelFormat8)
621                bitmap.palette = GetDefaultPalette();
622             delete info;
623
624             ReleaseDC(HWND_DESKTOP, hdc);
625             SelectObject(memDC, back);
626             DeleteObject(screenBmp);
627             DeleteDC(memDC);
628
629             result = true;
630          }   
631       }
632       return result;
633    }
634
635    void SetForeground(Display display, Surface surface, ColorAlpha color)
636    {
637       ((subclass(DisplayDriver))class(LFBDisplayDriver)).SetForeground(display, surface, color);
638       if(true) //display.alphaBlend)
639       {
640          GDISurface gdiSurface = surface.driverData;
641          GDIDisplay gdiDisplay = display ? display.driverData : null;
642          COLORREF rgb = RGB(color.color.r, color.color.g, color.color.b);
643          
644          SetTextColor(gdiSurface.hdc, rgb);
645          gdiSurface.color = rgb;
646       }
647    }
648
649    void SetBackground(Display display, Surface surface, ColorAlpha color)
650    {
651       ((subclass(DisplayDriver))class(LFBDisplayDriver)).SetBackground(display, surface, color);
652
653       if(display && (!display.alphaBlend || display.pixelFormat != pixelFormat888))
654       { 
655          GDISurface gdiSurface = surface.driverData;
656          GDIDisplay gdiDisplay = display ? display.driverData : null;
657          COLORREF rgb;
658          
659          if(gdiSurface.bitmap.pixelFormat == pixelFormat8 && display)
660             color = gdiSurface.bitmap.palette[gdiDisplay.rgbLookup[(uint16)(Color555) color]];
661          rgb = RGB(color.color.r, color.color.g, color.color.b);
662
663          SetBkColor(gdiSurface.hdc, rgb);
664          SetDCBrushColor(gdiSurface.hdc, rgb);
665          SetDCPenColor(gdiSurface.hdc, rgb);
666       }
667    }
668
669    ColorAlpha GetPixel(Display display, Surface surface, int x, int y)
670    {
671       return 0;
672    }
673
674    void PutPixel(Display display, Surface surface, int x, int y)
675    {
676       GDIDisplay gdiDisplay = display ? display.driverData : null;
677       //GDISurface gdiSurface = surface.driverData;
678       // SetPixel(gdiSurface.hdc, x + surface.offset.x, y + surface.offset.y, gdiSurface.color);
679       ((subclass(DisplayDriver))class(LFBDisplayDriver)).PutPixel(display, surface, x,y);
680    }
681
682    void DrawLine(Display display, Surface surface, int x1, int y1, int x2, int y2)
683    {
684       GDIDisplay gdiDisplay = display ? display.driverData : null;
685       ((subclass(DisplayDriver))class(LFBDisplayDriver)).DrawLine(display, surface, x1,y1,x2,y2);
686    }
687
688    void Rectangle(Display display, Surface surface,int x1,int y1,int x2,int y2)
689    {
690       GDIDisplay gdiDisplay = display ? display.driverData : null;
691       ((subclass(DisplayDriver))class(LFBDisplayDriver)).Rectangle(display, surface, x1,y1,x2,y2);
692    }
693
694    void Area(Display display, Surface surface,int x1,int y1,int x2,int y2)
695    {
696       GDIDisplay gdiDisplay = display ? display.driverData : null;
697       ((subclass(DisplayDriver))class(LFBDisplayDriver)).Area(display, surface, x1,y1,x2,y2);
698
699       /*
700       GDISurface gdiSurface = surface.driverData;
701       x1 += surface.offset.x;
702       x2 += surface.offset.x;
703       y1 += surface.offset.y;
704       y2 += surface.offset.y;
705       SetBkMode(gdiSurface.hdc, OPAQUE);
706       //SetDCBrushColor(gdiSurface.hdc, BGR(eSystem_GetRandom(0,255), eSystem_GetRandom(0,255), eSystem_GetRandom(0,255)));
707       PatBlt(gdiSurface.hdc,x1,y1,x2-x1+1,y2-y1+1,PATCOPY);
708       SetBkMode(gdiSurface.hdc, surface.textOpacity ? OPAQUE : TRANSPARENT);
709       */
710    }
711
712    void Clear(Display display, Surface surface, ClearType type)
713    {
714       /*if(type != depthBuffer)
715          Area(display, surface,surface.box.left,surface.box.top,surface.box.right,surface.box.bottom);*/
716       ((subclass(DisplayDriver))class(LFBDisplayDriver)).Clear(display, surface, type);
717    }
718
719    bool ConvertBitmap(DisplaySystem displaySystem, Bitmap src, PixelFormat format, ColorAlpha * palette)
720    {
721       if(src.driverData)
722          return true;
723       else
724       {
725          return ((subclass(DisplayDriver))class(LFBDisplayDriver)).ConvertBitmap(displaySystem, src, format, palette);
726       } 
727    }
728
729    bool AllocateBitmap(DisplaySystem displaySystem, Bitmap bitmap, int width, int height, int stride, PixelFormat format, bool allocatePalette)
730    {
731       bool result = false;
732       HWND hwnd = displaySystem ? displaySystem.window : GetDesktopWindow();
733       HDC hdc = GetDC(hwnd);
734       if(hdc)
735       {
736          GDIBitmap gdiBitmap = bitmap.driverData = GDIBitmap { };
737          if(gdiBitmap)
738          {
739             BITMAPINFO *info = (BITMAPINFO *)new0 byte[sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*256];
740
741             if(info)
742             {
743                int c;
744                uint16 depth;
745
746                switch(format)
747                {
748                   case pixelFormat8: depth = 8; break;
749                   case pixelFormat555: depth = 16; break;
750                   case pixelFormat888:
751                   default:
752                      depth = 32;
753                      format = pixelFormat888;
754                }
755
756                if(!stride)
757                {
758                   switch(GetColorDepthShifts(format))
759                   {
760                      case 0: stride = (width + 3) & 0xFFFFFFFC; break;
761                      case 1: stride = (width + 1) & 0xFFFFFFFE; break;
762                      case 2: stride = width;                    break;
763                   }
764                }
765
766                bitmap.stride=stride;   
767                bitmap.width=width;
768                bitmap.height=height;
769                bitmap.size=(uint)stride*(uint)height;
770                bitmap.sizeBytes = bitmap.size << GetColorDepthShifts(format);
771                bitmap.pixelFormat = format;
772                bitmap.transparent = false;
773                bitmap.allocatePalette = allocatePalette;
774                if(allocatePalette)
775                {
776                   bitmap.palette = new0 ColorAlpha[256];
777                   if(bitmap.palette)
778                      CopyBytesBy4(bitmap.palette, GetDefaultPalette(), 256);
779                }
780                else
781                   bitmap.palette = GetDefaultPalette();
782
783                gdiBitmap.memDC = CreateCompatibleDC(hdc);
784
785                info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
786                info->bmiHeader.biPlanes = 1;
787                info->bmiHeader.biCompression = BI_RGB;
788                info->bmiHeader.biBitCount = depth;
789                info->bmiHeader.biWidth = bitmap.stride;
790                info->bmiHeader.biHeight = -height;
791     
792                for(c=0; c<256; c++)
793                {
794                   info->bmiColors[c].rgbReserved = 0;
795                   info->bmiColors[c].rgbRed = bitmap.palette[c].color.r;
796                   info->bmiColors[c].rgbGreen = bitmap.palette[c].color.g;
797                   info->bmiColors[c].rgbBlue = bitmap.palette[c].color.b;
798                }
799
800                gdiBitmap.memBitmap = CreateDIBSection(hdc, info, DIB_RGB_COLORS, &bitmap.picture, null, 0);
801                if(gdiBitmap.memBitmap)
802                {
803                   SelectObject(gdiBitmap.memDC, gdiBitmap.memBitmap);
804                   SetBkMode(gdiBitmap.memDC, TRANSPARENT);
805                   result = true;
806                }
807                delete info;
808             }
809             if(!result)
810                FreeBitmap(displaySystem, bitmap);
811          }
812       }
813       ReleaseDC(hwnd, hdc);
814
815       return result;
816    }
817
818    void Blit(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h)
819    {
820       GDIDisplay gdiDisplay = display ? display.driverData : null;
821       ((subclass(DisplayDriver))class(LFBDisplayDriver)).Blit(display, surface, src, dx, dy, sx, sy, w, h);
822    }
823
824    void Stretch(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
825    {
826       GDIDisplay gdiDisplay = display ? display.driverData : null;
827       ((subclass(DisplayDriver))class(LFBDisplayDriver)).Stretch(display, surface, src, dx, dy, sx, sy, w, h, sw, sh);
828    }
829
830    void Filter(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
831    {
832       GDIDisplay gdiDisplay = display ? display.driverData : null;
833       ((subclass(DisplayDriver))class(LFBDisplayDriver)).Filter(display, surface, src, dx, dy, sx, sy, w, h, sw, sh);
834    }
835
836    void BlitDI(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h)
837    {
838       Blit(display,surface,src,dx,dy,sx,sy,w,h);
839    }
840
841    void StretchDI(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
842    {
843       Stretch(display, surface, src, dx, dy, sx, sy, w, h, sw, sh);
844    }
845
846    void FilterDI(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
847    {
848       Filter(display, surface, src, dx, dy, sx, sy, w, h, sw, sh);
849    }
850
851    Font LoadFont(DisplaySystem displaySystem, char * faceName, float size, FontFlags flags)
852    {
853       if(false) //display.alphaBlend)
854          return ((subclass(DisplayDriver))class(LFBDisplayDriver)).LoadFont(displaySystem, faceName, size, flags);
855       else
856       {
857          GDIFont font { };
858          HDC hdc = GetDC(null);
859          int pixels = GetDeviceCaps(hdc, LOGPIXELSY);
860          strcpy(font.faceName, faceName);
861          font.size = size;
862          font.flags = flags;
863          font.gdiFont = CreateFontA(-(int)((float)size * pixels / 72 + 0.5),
864             0,0,0, flags.bold ? FW_BOLD : FW_NORMAL, flags.italic ? TRUE : FALSE,
865                flags.underline ? TRUE : FALSE, 0, DEFAULT_CHARSET,
866                            OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
867                            DEFAULT_PITCH|FF_DONTCARE, faceName);
868
869          ReleaseDC(null, hdc);
870          return (Font)font;
871       }
872    }
873
874    void UnloadFont(DisplaySystem displaySystem, Font font)
875    {
876       GDIFont gdiFont = (GDIFont) font;
877       if(false) //display.alphaBlend)
878          ((subclass(DisplayDriver))class(LFBDisplayDriver)).UnloadFont(displaySystem, font);
879       else if(gdiFont)
880       {
881          if(gdiFont.gdiFont)
882             DeleteObject(gdiFont.gdiFont);
883          if(gdiFont.font) 
884             ((subclass(DisplayDriver))class(LFBDisplayDriver)).UnloadFont(displaySystem, gdiFont.font);
885          delete gdiFont; 
886       }
887    }
888
889    void TextFont(Display display, Surface surface, Font font)
890    {
891       GDIFont gdiFont = (GDIFont) font;
892       if(display.alphaBlend && display.pixelFormat == pixelFormat888)
893       {
894          if(!gdiFont.font)
895          {
896             gdiFont.font = ((subclass(DisplayDriver))class(LFBDisplayDriver)).LoadFont(display.displaySystem, 
897                gdiFont.faceName, gdiFont.size, gdiFont.flags);         
898          }
899          ((subclass(DisplayDriver))class(LFBDisplayDriver)).TextFont(display, surface, gdiFont.font);          
900       } 
901       else 
902       {
903          GDISurface gdiSurface = surface.driverData;
904          SelectObject(gdiSurface.hdc, gdiFont.gdiFont);
905       }      
906    }
907
908    void TextOpacity(Display display, Surface surface, bool opaque)
909    {
910       ((subclass(DisplayDriver))class(LFBDisplayDriver)).TextOpacity(display, surface, opaque);
911       if(display && (!display.alphaBlend || display.pixelFormat != pixelFormat888))
912       {
913          GDISurface gdiSurface = surface.driverData;
914          SetBkMode(gdiSurface.hdc, opaque ? OPAQUE : TRANSPARENT);
915       }      
916    }
917
918    void WriteText(Display display, Surface surface, int x, int y, char * text, int len)
919    {
920       if(display.alphaBlend && display.pixelFormat == pixelFormat888)
921       {
922          GDIFont gdiFont = (GDIFont)surface.font;
923          if(!gdiFont.font)
924          {
925             gdiFont.font = ((subclass(DisplayDriver))class(LFBDisplayDriver)).LoadFont(display.displaySystem, 
926                gdiFont.faceName, gdiFont.size, gdiFont.flags);         
927          }
928          if(surface.textOpacity)
929          {
930             int w, h;
931             ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(display.displaySystem, gdiFont.font, text, len, &w, &h);
932             Area(display, surface, x, y, x+w-1, y+h-1);
933          }
934          ((subclass(DisplayDriver))class(LFBDisplayDriver)).WriteText(display, surface, x, y, text, len);
935       }
936       else
937       {
938          GDISurface gdiSurface = surface.driverData;
939          int wordCount;
940          uint16 * u16text = UTF8toUTF16Len(text, len, &wordCount);
941
942          TextOut(gdiSurface.hdc, x + surface.offset.x, y + surface.offset.y, u16text, wordCount);
943          if(display.alphaBlend && display.pixelFormat == pixelFormat888)
944          {
945             int w, h;
946             FontExtent(display.displaySystem, surface.font, text, len, &w, &h);
947             surface.writeColor = false;
948             SetBackground(display, surface, surface.foreground);
949             Area(display, surface,x-2,y-2,x+w+1,y+h+1);
950             SetBackground(display, surface, surface.background);
951             surface.writeColor = true;
952          }
953          delete u16text;
954       }
955    }
956
957    void TextExtent(Display display, Surface surface, char * text, int len, int * width, int * height)
958    {
959       if(display && display.alphaBlend && display.pixelFormat == pixelFormat888)
960          ((subclass(DisplayDriver))class(LFBDisplayDriver)).TextExtent(display, surface, text, len, width, height);
961       else
962       {
963          GDISurface gdiSurface = surface.driverData;
964          SIZE space, size;
965          uint realLen;
966          int wordCount;
967          uint16 * u16text = UTF8toUTF16Len(text, len, &wordCount);
968
969          for(realLen = 0; realLen<wordCount && u16text[realLen]; realLen++);
970          GetTextExtentPoint32A(gdiSurface.hdc, " ", 1, &space);
971          GetTextExtentPoint32(gdiSurface.hdc, u16text, realLen, &size);
972          delete u16text;
973
974          // UNICODE FIX: proper space computation
975          if(width) *width = size.cx + (wordCount - realLen) * space.cx;
976          if(height) 
977          {
978             if(realLen)
979                *height = size.cy;
980             else
981                *height = wordCount ? space.cy : 0;
982          }
983       }      
984    }
985
986    void FontExtent(DisplaySystem displaySystem, Font font, char * text, int len, int * width, int * height)
987    {
988       if(false) //display.alphaBlend)
989         ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(displaySystem, font, text, len, width, height);
990       else
991       {
992          GDISystem gdiSystem = displaySystem.driverData;
993          if(gdiSystem.tmpDC)
994          {
995             Surface surface { };
996             GDIFont gdiFont = (GDIFont)font;
997             GDISurface gdiSurface { };
998
999             surface.driverData = gdiSurface;
1000             gdiSurface.hdc = gdiSystem.tmpDC;
1001
1002             SelectObject(gdiSurface.hdc, gdiFont ? gdiFont.gdiFont : null);
1003             TextExtent(null, surface, text, len, width, height);
1004
1005             delete surface;
1006             delete gdiSurface;
1007          }
1008          else
1009          {
1010             if(width) *width = 0;
1011             if(height) *height = 0;
1012          }
1013       }      
1014    }
1015
1016    void DrawingChar(Display display, Surface surface, byte character)
1017    {
1018
1019    }
1020
1021    void LineStipple(Display display, Surface surface, uint stipple)
1022    {
1023       GDIDisplay gdiDisplay = display ? display.driverData : null;
1024       ((subclass(DisplayDriver))class(LFBDisplayDriver)).LineStipple(display, surface, stipple);
1025    }
1026
1027    bool Lock(Display display)
1028    {
1029       return true;
1030    }
1031
1032    void Unlock(Display display)
1033    {
1034    }
1035 }
1036
1037 #endif