blob: c51e47f5993cbd272e600268ed3423811e689771 [file] [log] [blame]
Pierre Ossman403ac272017-01-02 17:00:41 +01001/* 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
19#include <assert.h>
20
21#include <ApplicationServices/ApplicationServices.h>
22
23#include <FL/Fl_RGB_Image.H>
24#include <FL/Fl_Window.H>
25#include <FL/x.H>
26
27#include <rdr/Exception.h>
28
29#include "Surface.h"
30
31void Surface::clear(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
32{
33 unsigned char* out;
34 int x, y;
35
36 r = (unsigned)r * a / 255;
37 g = (unsigned)g * a / 255;
38 b = (unsigned)b * a / 255;
39
40 out = data;
41 for (y = 0;y < width();y++) {
42 for (x = 0;x < height();x++) {
43 *out++ = b;
44 *out++ = g;
45 *out++ = r;
46 *out++ = a;
47 }
48 }
49}
50
51void Surface::draw(int src_x, int src_y, int x, int y, int w, int h)
52{
53 CGRect rect;
54
55 CGContextSaveGState(fl_gc);
56
57 // Reset the transformation matrix back to the default identity
58 // matrix as otherwise we get a massive performance hit
59 CGContextConcatCTM(fl_gc, CGAffineTransformInvert(CGContextGetCTM(fl_gc)));
60
61 // macOS Coordinates are from bottom left, not top left
62 src_y = height() - (src_y + h);
63 y = Fl_Window::current()->h() - (y + h);
64
65 // We have to use clipping to partially display an image
66 rect.origin.x = x;
67 rect.origin.y = y;
68 rect.size.width = w;
69 rect.size.height = h;
70
71 CGContextClipToRect(fl_gc, rect);
72
73 rect.origin.x = x - src_x;
74 rect.origin.y = y - src_y;
75 rect.size.width = width();
76 rect.size.height = height();
77
78 CGContextDrawImage(fl_gc, rect, image);
79
80 CGContextRestoreGState(fl_gc);
81}
82
83void Surface::alloc()
84{
85 CGColorSpaceRef lut;
86 CGDataProviderRef provider;
87
88 data = new unsigned char[width() * height() * 4];
89
90 lut = CGDisplayCopyColorSpace(kCGDirectMainDisplay);
91 if (!lut) {
92 lut = CGColorSpaceCreateDeviceRGB();
93 if (!lut)
94 throw rdr::Exception("CGColorSpaceCreateDeviceRGB");
95 }
96
97 provider = CGDataProviderCreateWithData(NULL, data,
98 width() * height() * 4, NULL);
99 if (!provider)
100 throw rdr::Exception("CGDataProviderCreateWithData");
101
102 image = CGImageCreate(width(), height(), 8, 32, width() * 4, lut,
103 kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little,
104 provider, NULL, false, kCGRenderingIntentDefault);
105 CGColorSpaceRelease(lut);
106 CGDataProviderRelease(provider);
107 if (!image)
108 throw rdr::Exception("CGImageCreate");
109}
110
111void Surface::dealloc()
112{
113 CGImageRelease(image);
114 delete [] data;
115}
116
117void Surface::update(const Fl_RGB_Image* image)
118{
119 int x, y;
120 const unsigned char* in;
121 unsigned char* out;
122
123 assert(image->w() == width());
124 assert(image->h() == height());
125
126 // Convert data and pre-multiply alpha
127 in = (const unsigned char*)image->data()[0];
128 out = data;
129 for (y = 0;y < image->h();y++) {
130 for (x = 0;x < image->w();x++) {
131 switch (image->d()) {
132 case 1:
133 *out++ = in[0];
134 *out++ = in[0];
135 *out++ = in[0];
136 *out++ = 0xff;
137 break;
138 case 2:
139 *out++ = (unsigned)in[0] * in[1] / 255;
140 *out++ = (unsigned)in[0] * in[1] / 255;
141 *out++ = (unsigned)in[0] * in[1] / 255;
142 *out++ = in[1];
143 break;
144 case 3:
145 *out++ = in[2];
146 *out++ = in[1];
147 *out++ = in[0];
148 *out++ = 0xff;
149 break;
150 case 4:
151 *out++ = (unsigned)in[2] * in[3] / 255;
152 *out++ = (unsigned)in[1] * in[3] / 255;
153 *out++ = (unsigned)in[0] * in[3] / 255;
154 *out++ = in[3];
155 break;
156 }
157 in += image->d();
158 }
159 if (image->ld() != 0)
160 in += image->ld() - image->w() * image->d();
161 }
162}