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