123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- /* Copyright 2016 Pierre Ossman for Cendio AB
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
-
- #include <assert.h>
-
- #include <FL/Fl_RGB_Image.H>
- #include <FL/x.H>
-
- #include <rdr/Exception.h>
-
- #include "Surface.h"
-
- void Surface::clear(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
- {
- RGBQUAD* out;
- int x, y;
-
- r = (unsigned)r * a / 255;
- g = (unsigned)g * a / 255;
- b = (unsigned)b * a / 255;
-
- out = data;
- for (y = 0;y < width();y++) {
- for (x = 0;x < height();x++) {
- out->rgbRed = r;
- out->rgbGreen = g;
- out->rgbBlue = b;
- out->rgbReserved = a;
- out++;
- }
- }
- }
-
- void Surface::draw(int src_x, int src_y, int x, int y, int w, int h)
- {
- HDC dc;
-
- dc = CreateCompatibleDC(fl_gc);
- if (!dc)
- throw rdr::SystemException("CreateCompatibleDC", GetLastError());
-
- if (!SelectObject(dc, bitmap))
- throw rdr::SystemException("SelectObject", GetLastError());
-
- if (!BitBlt(fl_gc, x, y, w, h, dc, src_x, src_y, SRCCOPY)) {
- // If the desktop we're rendering to is inactive (like when the screen
- // is locked or the UAC is active), then GDI calls will randomly fail.
- // This is completely undocumented so we have no idea how best to deal
- // with it. For now, we've only seen this error and for this function
- // so only ignore this combination.
- if (GetLastError() != ERROR_INVALID_HANDLE)
- throw rdr::SystemException("BitBlt", GetLastError());
- }
-
- DeleteDC(dc);
- }
-
- void Surface::draw(Surface* dst, int src_x, int src_y, int x, int y, int w, int h)
- {
- HDC origdc, dstdc;
-
- dstdc = CreateCompatibleDC(NULL);
- if (!dstdc)
- throw rdr::SystemException("CreateCompatibleDC", GetLastError());
-
- if (!SelectObject(dstdc, dst->bitmap))
- throw rdr::SystemException("SelectObject", GetLastError());
-
- origdc = fl_gc;
- fl_gc = dstdc;
- draw(src_x, src_y, x, y, w, h);
- fl_gc = origdc;
-
- DeleteDC(dstdc);
- }
-
- void Surface::blend(int /*src_x*/, int /*src_y*/,
- int /*x*/, int /*y*/, int /*w*/, int /*h*/,
- int /*a*/)
- {
- // Compositing doesn't work properly for window DC:s
- assert(false);
- }
-
- void Surface::blend(Surface* dst, int src_x, int src_y, int x, int y, int w, int h, int a)
- {
- HDC dstdc, srcdc;
- BLENDFUNCTION blend;
-
- dstdc = CreateCompatibleDC(NULL);
- if (!dstdc)
- throw rdr::SystemException("CreateCompatibleDC", GetLastError());
- srcdc = CreateCompatibleDC(NULL);
- if (!srcdc)
- throw rdr::SystemException("CreateCompatibleDC", GetLastError());
-
- if (!SelectObject(dstdc, dst->bitmap))
- throw rdr::SystemException("SelectObject", GetLastError());
- if (!SelectObject(srcdc, bitmap))
- throw rdr::SystemException("SelectObject", GetLastError());
-
- blend.BlendOp = AC_SRC_OVER;
- blend.BlendFlags = 0;
- blend.SourceConstantAlpha = a;
- blend.AlphaFormat = AC_SRC_ALPHA;
-
- if (!AlphaBlend(dstdc, x, y, w, h, srcdc, src_x, src_y, w, h, blend)) {
- // If the desktop we're rendering to is inactive (like when the screen
- // is locked or the UAC is active), then GDI calls will randomly fail.
- // This is completely undocumented so we have no idea how best to deal
- // with it. For now, we've only seen this error and for this function
- // so only ignore this combination.
- if (GetLastError() != ERROR_INVALID_HANDLE)
- throw rdr::SystemException("BitBlt", GetLastError());
- }
-
- DeleteDC(srcdc);
- DeleteDC(dstdc);
- }
-
- void Surface::alloc()
- {
- BITMAPINFOHEADER bih;
-
- data = new RGBQUAD[width() * height()];
-
- memset(&bih, 0, sizeof(bih));
-
- bih.biSize = sizeof(BITMAPINFOHEADER);
- bih.biBitCount = 32;
- bih.biPlanes = 1;
- bih.biWidth = width();
- bih.biHeight = -height(); // Negative to get top-down
- bih.biCompression = BI_RGB;
-
- bitmap = CreateDIBSection(NULL, (BITMAPINFO*)&bih,
- DIB_RGB_COLORS, (void**)&data, NULL, 0);
- if (!bitmap)
- throw rdr::SystemException("CreateDIBSection", GetLastError());
- }
-
- void Surface::dealloc()
- {
- DeleteObject(bitmap);
- }
-
- void Surface::update(const Fl_RGB_Image* image)
- {
- const unsigned char* in;
- RGBQUAD* out;
- int x, y;
-
- assert(image->w() == width());
- assert(image->h() == height());
-
- // Convert data and pre-multiply alpha
- in = (const unsigned char*)image->data()[0];
- out = data;
- for (y = 0;y < image->w();y++) {
- for (x = 0;x < image->h();x++) {
- switch (image->d()) {
- case 1:
- out->rgbBlue = in[0];
- out->rgbGreen = in[0];
- out->rgbRed = in[0];
- out->rgbReserved = 0xff;
- break;
- case 2:
- out->rgbBlue = (unsigned)in[0] * in[1] / 255;
- out->rgbGreen = (unsigned)in[0] * in[1] / 255;
- out->rgbRed = (unsigned)in[0] * in[1] / 255;
- out->rgbReserved = in[1];
- break;
- case 3:
- out->rgbBlue = in[2];
- out->rgbGreen = in[1];
- out->rgbRed = in[0];
- out->rgbReserved = 0xff;
- break;
- case 4:
- out->rgbBlue = (unsigned)in[2] * in[3] / 255;
- out->rgbGreen = (unsigned)in[1] * in[3] / 255;
- out->rgbRed = (unsigned)in[0] * in[3] / 255;
- out->rgbReserved = in[3];
- break;
- }
- in += image->d();
- out++;
- }
- if (image->ld() != 0)
- in += image->ld() - image->w() * image->d();
- }
- }
|