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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  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*/,
  78. int /*x*/, int /*y*/, int /*w*/, int /*h*/,
  79. int /*a*/)
  80. {
  81. // Compositing doesn't work properly for window DC:s
  82. assert(false);
  83. }
  84. void Surface::blend(Surface* dst, int src_x, int src_y, int x, int y, int w, int h, int a)
  85. {
  86. HDC dstdc, srcdc;
  87. BLENDFUNCTION blend;
  88. dstdc = CreateCompatibleDC(NULL);
  89. if (!dstdc)
  90. throw rdr::SystemException("CreateCompatibleDC", GetLastError());
  91. srcdc = CreateCompatibleDC(NULL);
  92. if (!srcdc)
  93. throw rdr::SystemException("CreateCompatibleDC", GetLastError());
  94. if (!SelectObject(dstdc, dst->bitmap))
  95. throw rdr::SystemException("SelectObject", GetLastError());
  96. if (!SelectObject(srcdc, bitmap))
  97. throw rdr::SystemException("SelectObject", GetLastError());
  98. blend.BlendOp = AC_SRC_OVER;
  99. blend.BlendFlags = 0;
  100. blend.SourceConstantAlpha = a;
  101. blend.AlphaFormat = AC_SRC_ALPHA;
  102. if (!AlphaBlend(dstdc, x, y, w, h, srcdc, src_x, src_y, w, h, blend)) {
  103. // If the desktop we're rendering to is inactive (like when the screen
  104. // is locked or the UAC is active), then GDI calls will randomly fail.
  105. // This is completely undocumented so we have no idea how best to deal
  106. // with it. For now, we've only seen this error and for this function
  107. // so only ignore this combination.
  108. if (GetLastError() != ERROR_INVALID_HANDLE)
  109. throw rdr::SystemException("BitBlt", GetLastError());
  110. }
  111. DeleteDC(srcdc);
  112. DeleteDC(dstdc);
  113. }
  114. void Surface::alloc()
  115. {
  116. BITMAPINFOHEADER bih;
  117. data = new RGBQUAD[width() * height()];
  118. memset(&bih, 0, sizeof(bih));
  119. bih.biSize = sizeof(BITMAPINFOHEADER);
  120. bih.biBitCount = 32;
  121. bih.biPlanes = 1;
  122. bih.biWidth = width();
  123. bih.biHeight = -height(); // Negative to get top-down
  124. bih.biCompression = BI_RGB;
  125. bitmap = CreateDIBSection(NULL, (BITMAPINFO*)&bih,
  126. DIB_RGB_COLORS, (void**)&data, NULL, 0);
  127. if (!bitmap)
  128. throw rdr::SystemException("CreateDIBSection", GetLastError());
  129. }
  130. void Surface::dealloc()
  131. {
  132. DeleteObject(bitmap);
  133. }
  134. void Surface::update(const Fl_RGB_Image* image)
  135. {
  136. const unsigned char* in;
  137. RGBQUAD* out;
  138. int x, y;
  139. assert(image->w() == width());
  140. assert(image->h() == height());
  141. // Convert data and pre-multiply alpha
  142. in = (const unsigned char*)image->data()[0];
  143. out = data;
  144. for (y = 0;y < image->w();y++) {
  145. for (x = 0;x < image->h();x++) {
  146. switch (image->d()) {
  147. case 1:
  148. out->rgbBlue = in[0];
  149. out->rgbGreen = in[0];
  150. out->rgbRed = in[0];
  151. out->rgbReserved = 0xff;
  152. break;
  153. case 2:
  154. out->rgbBlue = (unsigned)in[0] * in[1] / 255;
  155. out->rgbGreen = (unsigned)in[0] * in[1] / 255;
  156. out->rgbRed = (unsigned)in[0] * in[1] / 255;
  157. out->rgbReserved = in[1];
  158. break;
  159. case 3:
  160. out->rgbBlue = in[2];
  161. out->rgbGreen = in[1];
  162. out->rgbRed = in[0];
  163. out->rgbReserved = 0xff;
  164. break;
  165. case 4:
  166. out->rgbBlue = (unsigned)in[2] * in[3] / 255;
  167. out->rgbGreen = (unsigned)in[1] * in[3] / 255;
  168. out->rgbRed = (unsigned)in[0] * in[3] / 255;
  169. out->rgbReserved = in[3];
  170. break;
  171. }
  172. in += image->d();
  173. out++;
  174. }
  175. if (image->ld() != 0)
  176. in += image->ld() - image->w() * image->d();
  177. }
  178. }