diff options
author | Pierre Ossman <ossman@cendio.se> | 2017-01-02 17:00:41 +0100 |
---|---|---|
committer | Pierre Ossman <ossman@cendio.se> | 2017-02-10 17:02:13 +0100 |
commit | 403ac27d2377df4fed8bf5039125f6d89aaa6955 (patch) | |
tree | 00e740d165f0aedff234e50b2303581efe6805d5 /vncviewer/Surface_Win32.cxx | |
parent | 13548819fa30b58f8d007a367d48934c7f064914 (diff) | |
download | tigervnc-403ac27d2377df4fed8bf5039125f6d89aaa6955.tar.gz tigervnc-403ac27d2377df4fed8bf5039125f6d89aaa6955.zip |
Abstract platform rendering to "surfaces"
This will allow us to render more things than just the framebuffer.
Diffstat (limited to 'vncviewer/Surface_Win32.cxx')
-rw-r--r-- | vncviewer/Surface_Win32.cxx | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/vncviewer/Surface_Win32.cxx b/vncviewer/Surface_Win32.cxx new file mode 100644 index 00000000..5a9a6546 --- /dev/null +++ b/vncviewer/Surface_Win32.cxx @@ -0,0 +1,146 @@ +/* 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. + */ + +#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::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(); + } +} + |