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.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  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. #ifdef HAVE_CONFIG_H
  19. #include <config.h>
  20. #endif
  21. #include <assert.h>
  22. #include <FL/Fl_RGB_Image.H>
  23. #include <FL/x.H>
  24. #include <rdr/Exception.h>
  25. #include "Surface.h"
  26. void Surface::clear(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
  27. {
  28. RGBQUAD* out;
  29. int x, y;
  30. r = (unsigned)r * a / 255;
  31. g = (unsigned)g * a / 255;
  32. b = (unsigned)b * a / 255;
  33. out = data;
  34. for (y = 0;y < width();y++) {
  35. for (x = 0;x < height();x++) {
  36. out->rgbRed = r;
  37. out->rgbGreen = g;
  38. out->rgbBlue = b;
  39. out->rgbReserved = a;
  40. out++;
  41. }
  42. }
  43. }
  44. void Surface::draw(int src_x, int src_y, int x, int y, int w, int h)
  45. {
  46. HDC dc;
  47. dc = CreateCompatibleDC(fl_gc);
  48. if (!dc)
  49. throw rdr::SystemException("CreateCompatibleDC", GetLastError());
  50. if (!SelectObject(dc, bitmap))
  51. throw rdr::SystemException("SelectObject", GetLastError());
  52. if (!BitBlt(fl_gc, x, y, w, h, dc, src_x, src_y, SRCCOPY)) {
  53. // If the desktop we're rendering to is inactive (like when the screen
  54. // is locked or the UAC is active), then GDI calls will randomly fail.
  55. // This is completely undocumented so we have no idea how best to deal
  56. // with it. For now, we've only seen this error and for this function
  57. // so only ignore this combination.
  58. if (GetLastError() != ERROR_INVALID_HANDLE)
  59. throw rdr::SystemException("BitBlt", GetLastError());
  60. }
  61. DeleteDC(dc);
  62. }
  63. void Surface::draw(Surface* dst, int src_x, int src_y, int x, int y, int w, int h)
  64. {
  65. HDC origdc, dstdc;
  66. dstdc = CreateCompatibleDC(NULL);
  67. if (!dstdc)
  68. throw rdr::SystemException("CreateCompatibleDC", GetLastError());
  69. if (!SelectObject(dstdc, dst->bitmap))
  70. throw rdr::SystemException("SelectObject", GetLastError());
  71. origdc = fl_gc;
  72. fl_gc = dstdc;
  73. draw(src_x, src_y, x, y, w, h);
  74. fl_gc = origdc;
  75. DeleteDC(dstdc);
  76. }
  77. void Surface::blend(int src_x, int src_y, int x, int y, int w, int h, int a)
  78. {
  79. // Compositing doesn't work properly for window DC:s
  80. assert(false);
  81. }
  82. void Surface::blend(Surface* dst, int src_x, int src_y, int x, int y, int w, int h, int a)
  83. {
  84. HDC dstdc, srcdc;
  85. BLENDFUNCTION blend;
  86. dstdc = CreateCompatibleDC(NULL);
  87. if (!dstdc)
  88. throw rdr::SystemException("CreateCompatibleDC", GetLastError());
  89. srcdc = CreateCompatibleDC(NULL);
  90. if (!srcdc)
  91. throw rdr::SystemException("CreateCompatibleDC", GetLastError());
  92. if (!SelectObject(dstdc, dst->bitmap))
  93. throw rdr::SystemException("SelectObject", GetLastError());
  94. if (!SelectObject(srcdc, bitmap))
  95. throw rdr::SystemException("SelectObject", GetLastError());
  96. blend.BlendOp = AC_SRC_OVER;
  97. blend.BlendFlags = 0;
  98. blend.SourceConstantAlpha = a;
  99. blend.AlphaFormat = AC_SRC_ALPHA;
  100. if (!AlphaBlend(dstdc, x, y, w, h, srcdc, src_x, src_y, w, h, blend)) {
  101. // If the desktop we're rendering to is inactive (like when the screen
  102. // is locked or the UAC is active), then GDI calls will randomly fail.
  103. // This is completely undocumented so we have no idea how best to deal
  104. // with it. For now, we've only seen this error and for this function
  105. // so only ignore this combination.
  106. if (GetLastError() != ERROR_INVALID_HANDLE)
  107. throw rdr::SystemException("BitBlt", GetLastError());
  108. }
  109. DeleteDC(srcdc);
  110. DeleteDC(dstdc);
  111. }
  112. void Surface::alloc()
  113. {
  114. BITMAPINFOHEADER bih;
  115. data = new RGBQUAD[width() * height()];
  116. memset(&bih, 0, sizeof(bih));
  117. bih.biSize = sizeof(BITMAPINFOHEADER);
  118. bih.biBitCount = 32;
  119. bih.biPlanes = 1;
  120. bih.biWidth = width();
  121. bih.biHeight = -height(); // Negative to get top-down
  122. bih.biCompression = BI_RGB;
  123. bitmap = CreateDIBSection(NULL, (BITMAPINFO*)&bih,
  124. DIB_RGB_COLORS, (void**)&data, NULL, 0);
  125. if (!bitmap)
  126. throw rdr::SystemException("CreateDIBSection", GetLastError());
  127. }
  128. void Surface::dealloc()
  129. {
  130. DeleteObject(bitmap);
  131. }
  132. void Surface::update(const Fl_RGB_Image* image)
  133. {
  134. const unsigned char* in;
  135. RGBQUAD* out;
  136. int x, y;
  137. assert(image->w() == width());
  138. assert(image->h() == height());
  139. // Convert data and pre-multiply alpha
  140. in = (const unsigned char*)image->data()[0];
  141. out = data;
  142. for (y = 0;y < image->w();y++) {
  143. for (x = 0;x < image->h();x++) {
  144. switch (image->d()) {
  145. case 1:
  146. out->rgbBlue = in[0];
  147. out->rgbGreen = in[0];
  148. out->rgbRed = in[0];
  149. out->rgbReserved = 0xff;
  150. break;
  151. case 2:
  152. out->rgbBlue = (unsigned)in[0] * in[1] / 255;
  153. out->rgbGreen = (unsigned)in[0] * in[1] / 255;
  154. out->rgbRed = (unsigned)in[0] * in[1] / 255;
  155. out->rgbReserved = in[1];
  156. break;
  157. case 3:
  158. out->rgbBlue = in[2];
  159. out->rgbGreen = in[1];
  160. out->rgbRed = in[0];
  161. out->rgbReserved = 0xff;
  162. break;
  163. case 4:
  164. out->rgbBlue = (unsigned)in[2] * in[3] / 255;
  165. out->rgbGreen = (unsigned)in[1] * in[3] / 255;
  166. out->rgbRed = (unsigned)in[0] * in[3] / 255;
  167. out->rgbReserved = in[3];
  168. break;
  169. }
  170. in += image->d();
  171. out++;
  172. }
  173. if (image->ld() != 0)
  174. in += image->ld() - image->w() * image->d();
  175. }
  176. }