You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Surface_Win32.cxx 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /* Copyright 2016 Pierre Ossman for Cendio AB
  2. *
  3. * This is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation; either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This software is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this software; if not, write to the Free Software
  15. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  16. * USA.
  17. */
  18. #include <assert.h>
  19. #include <FL/Fl_RGB_Image.H>
  20. #include <FL/x.H>
  21. #include <rdr/Exception.h>
  22. #include "Surface.h"
  23. void Surface::clear(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
  24. {
  25. RGBQUAD* out;
  26. int x, y;
  27. r = (unsigned)r * a / 255;
  28. g = (unsigned)g * a / 255;
  29. b = (unsigned)b * a / 255;
  30. out = data;
  31. for (y = 0;y < width();y++) {
  32. for (x = 0;x < height();x++) {
  33. out->rgbRed = r;
  34. out->rgbGreen = g;
  35. out->rgbBlue = b;
  36. out->rgbReserved = a;
  37. out++;
  38. }
  39. }
  40. }
  41. void Surface::draw(int src_x, int src_y, int x, int y, int w, int h)
  42. {
  43. HDC dc;
  44. dc = CreateCompatibleDC(fl_gc);
  45. if (!dc)
  46. throw rdr::SystemException("CreateCompatibleDC", GetLastError());
  47. if (!SelectObject(dc, bitmap))
  48. throw rdr::SystemException("SelectObject", GetLastError());
  49. if (!BitBlt(fl_gc, x, y, w, h, dc, src_x, src_y, SRCCOPY)) {
  50. // If the desktop we're rendering to is inactive (like when the screen
  51. // is locked or the UAC is active), then GDI calls will randomly fail.
  52. // This is completely undocumented so we have no idea how best to deal
  53. // with it. For now, we've only seen this error and for this function
  54. // so only ignore this combination.
  55. if (GetLastError() != ERROR_INVALID_HANDLE)
  56. throw rdr::SystemException("BitBlt", GetLastError());
  57. }
  58. DeleteDC(dc);
  59. }
  60. void Surface::draw(Surface* dst, int src_x, int src_y, int x, int y, int w, int h)
  61. {
  62. HDC origdc, dstdc;
  63. dstdc = CreateCompatibleDC(NULL);
  64. if (!dstdc)
  65. throw rdr::SystemException("CreateCompatibleDC", GetLastError());
  66. if (!SelectObject(dstdc, dst->bitmap))
  67. throw rdr::SystemException("SelectObject", GetLastError());
  68. origdc = fl_gc;
  69. fl_gc = dstdc;
  70. draw(src_x, src_y, x, y, w, h);
  71. fl_gc = origdc;
  72. DeleteDC(dstdc);
  73. }
  74. void Surface::blend(int src_x, int src_y, int x, int y, int w, int h, int a)
  75. {
  76. // Compositing doesn't work properly for window DC:s
  77. assert(false);
  78. }
  79. void Surface::blend(Surface* dst, int src_x, int src_y, int x, int y, int w, int h, int a)
  80. {
  81. HDC dstdc, srcdc;
  82. BLENDFUNCTION blend;
  83. dstdc = CreateCompatibleDC(NULL);
  84. if (!dstdc)
  85. throw rdr::SystemException("CreateCompatibleDC", GetLastError());
  86. srcdc = CreateCompatibleDC(NULL);
  87. if (!srcdc)
  88. throw rdr::SystemException("CreateCompatibleDC", GetLastError());
  89. if (!SelectObject(dstdc, dst->bitmap))
  90. throw rdr::SystemException("SelectObject", GetLastError());
  91. if (!SelectObject(srcdc, bitmap))
  92. throw rdr::SystemException("SelectObject", GetLastError());
  93. blend.BlendOp = AC_SRC_OVER;
  94. blend.BlendFlags = 0;
  95. blend.SourceConstantAlpha = a;
  96. blend.AlphaFormat = AC_SRC_ALPHA;
  97. if (!AlphaBlend(dstdc, x, y, w, h, srcdc, src_x, src_y, w, h, blend)) {
  98. // If the desktop we're rendering to is inactive (like when the screen
  99. // is locked or the UAC is active), then GDI calls will randomly fail.
  100. // This is completely undocumented so we have no idea how best to deal
  101. // with it. For now, we've only seen this error and for this function
  102. // so only ignore this combination.
  103. if (GetLastError() != ERROR_INVALID_HANDLE)
  104. throw rdr::SystemException("BitBlt", GetLastError());
  105. }
  106. DeleteDC(srcdc);
  107. DeleteDC(dstdc);
  108. }
  109. void Surface::alloc()
  110. {
  111. BITMAPINFOHEADER bih;
  112. data = new RGBQUAD[width() * height()];
  113. memset(&bih, 0, sizeof(bih));
  114. bih.biSize = sizeof(BITMAPINFOHEADER);
  115. bih.biBitCount = 32;
  116. bih.biPlanes = 1;
  117. bih.biWidth = width();
  118. bih.biHeight = -height(); // Negative to get top-down
  119. bih.biCompression = BI_RGB;
  120. bitmap = CreateDIBSection(NULL, (BITMAPINFO*)&bih,
  121. DIB_RGB_COLORS, (void**)&data, NULL, 0);
  122. if (!bitmap)
  123. throw rdr::SystemException("CreateDIBSection", GetLastError());
  124. }
  125. void Surface::dealloc()
  126. {
  127. DeleteObject(bitmap);
  128. }
  129. void Surface::update(const Fl_RGB_Image* image)
  130. {
  131. const unsigned char* in;
  132. RGBQUAD* out;
  133. int x, y;
  134. assert(image->w() == width());
  135. assert(image->h() == height());
  136. // Convert data and pre-multiply alpha
  137. in = (const unsigned char*)image->data()[0];
  138. out = data;
  139. for (y = 0;y < image->w();y++) {
  140. for (x = 0;x < image->h();x++) {
  141. switch (image->d()) {
  142. case 1:
  143. out->rgbBlue = in[0];
  144. out->rgbGreen = in[0];
  145. out->rgbRed = in[0];
  146. out->rgbReserved = 0xff;
  147. break;
  148. case 2:
  149. out->rgbBlue = (unsigned)in[0] * in[1] / 255;
  150. out->rgbGreen = (unsigned)in[0] * in[1] / 255;
  151. out->rgbRed = (unsigned)in[0] * in[1] / 255;
  152. out->rgbReserved = in[1];
  153. break;
  154. case 3:
  155. out->rgbBlue = in[2];
  156. out->rgbGreen = in[1];
  157. out->rgbRed = in[0];
  158. out->rgbReserved = 0xff;
  159. break;
  160. case 4:
  161. out->rgbBlue = (unsigned)in[2] * in[3] / 255;
  162. out->rgbGreen = (unsigned)in[1] * in[3] / 255;
  163. out->rgbRed = (unsigned)in[0] * in[3] / 255;
  164. out->rgbReserved = in[3];
  165. break;
  166. }
  167. in += image->d();
  168. out++;
  169. }
  170. if (image->ld() != 0)
  171. in += image->ld() - image->w() * image->d();
  172. }
  173. }