1 // Copyright (C) 2009, 2010, 2011, 2014, 2015, 2020 Ben Asselstine
2 //
3 // This program 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 3 of the License, or
6 // (at your option) any later version.
7 //
8 // This program 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 Library General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 // 02110-1301, USA.
17
18 #include <iostream>
19 #include "defs.h"
20 #include "PixMask.h"
21 #include <string.h>
22 #include <cairomm/cairomm.h>
23 #include <gdkmm.h>
24 #include "ucompose.hpp"
25
26
PixMask(Glib::RefPtr<Gdk::Pixbuf> pixbuf)27 PixMask::PixMask(Glib::RefPtr<Gdk::Pixbuf> pixbuf)
28 : width(0), height(0), unscaled_width(0), unscaled_height(0)
29 {
30 pixmap = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, pixbuf->get_width(), pixbuf->get_height());
31 gc = Cairo::Context::create(pixmap);
32 Gdk::Cairo::set_source_pixbuf(gc, pixbuf, 0, 0);
33 gc->paint();
34 mask = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, pixbuf->get_width(), pixbuf->get_height());
35 unscaled_width = pixbuf->get_width();
36 unscaled_height = pixbuf->get_height();
37 width = unscaled_width;
38 height = unscaled_height;
39 }
40
~PixMask()41 PixMask::~PixMask()
42 {
43 pixmap.clear();
44 mask.clear();
45 gc.clear();
46 }
47
PixMask(Cairo::RefPtr<Cairo::Surface> p,Cairo::RefPtr<Cairo::Surface> m)48 PixMask::PixMask(Cairo::RefPtr<Cairo::Surface> p, Cairo::RefPtr<Cairo::Surface> m)
49 : width(0), height(0)
50 {
51 gc = Cairo::Context::create(p);
52 double x1, x2, y1, y2;
53 gc->get_clip_extents (x1, y1, x2, y2);
54 width = x2 - x1;
55 height = y2 - y1;
56
57 pixmap = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, width, height);
58 if (p)
59 {
60 gc = Cairo::Context::create(pixmap);
61 gc->rectangle(0, 0, width, height);
62 gc->clip();
63 gc->save();
64 gc->set_source (p, 0, 0);
65 gc->rectangle (0, 0, width, height);
66 gc->clip();
67 gc->paint();
68 gc->restore();
69 }
70
71 mask = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, width, height);
72 if (m)
73 {
74 Cairo::RefPtr<Cairo::Context> context = Cairo::Context::create(mask);
75 context->rectangle(0, 0, width, height);
76 context->clip();
77 context->save();
78 context->set_source (m, 0, 0);
79 context->rectangle (0, 0, width, height);
80 context->clip();
81 context->paint();
82 context->restore();
83 }
84 unscaled_width = width;
85 unscaled_height = height;
86 }
87
PixMask(const PixMask & p)88 PixMask::PixMask(const PixMask&p)
89 {
90 width = p.width;
91 height = p.height;
92 unscaled_width = p.unscaled_width;
93 unscaled_height = p.unscaled_height;
94 pixmap = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, width, height);
95 if (p.pixmap)
96 {
97 gc = Cairo::Context::create(pixmap);
98 gc->rectangle(0, 0, width, height);
99 gc->clip();
100 gc->save();
101 gc->set_source (p.pixmap, 0, 0);
102 gc->rectangle (0, 0, width, height);
103 gc->clip();
104 gc->paint();
105 gc->restore();
106 }
107
108 mask = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, width, height);
109 if (p.mask)
110 {
111 Cairo::RefPtr<Cairo::Context> context = Cairo::Context::create(mask);
112 context->rectangle(0, 0, width, height);
113 context->clip();
114 context->save();
115 context->set_source (p.mask, 0, 0);
116 context->rectangle (0, 0, width, height);
117 context->clip();
118 context->paint();
119 context->restore();
120 }
121 }
122
PixMask(Glib::ustring filename,bool & broken)123 PixMask::PixMask(Glib::ustring filename, bool &broken)
124 : width(0), height(0)
125 {
126 if (Gtk::Main::instance() == NULL)
127 {
128 broken = true;
129 return;
130 }
131 Glib::RefPtr<Gdk::Pixbuf> pixbuf;
132 try
133 {
134 pixbuf = Gdk::Pixbuf::create_from_file(filename);
135 }
136 catch (const Glib::Exception &ex)
137 {
138 std::cerr << String::ucompose(_("Could not load image file `%1'."), filename) << std::endl;
139 broken = true;
140 return;
141 }
142 pixmap = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, pixbuf->get_width(), pixbuf->get_height());
143 gc = Cairo::Context::create(pixmap);
144 Gdk::Cairo::set_source_pixbuf(gc, pixbuf, 0, 0);
145 gc->paint();
146 mask = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, pixbuf->get_width(), pixbuf->get_height());
147 width = pixbuf->get_width();
148 height = pixbuf->get_height();
149 unscaled_width = width;
150 unscaled_height = height;
151 }
152
create(Glib::ustring filename,bool & broken)153 PixMask* PixMask::create(Glib::ustring filename, bool &broken)
154 {
155 return new PixMask(filename, broken);
156 }
157
create(Glib::RefPtr<Gdk::Pixbuf> pixbuf)158 PixMask* PixMask::create(Glib::RefPtr<Gdk::Pixbuf> pixbuf)
159 {
160 return new PixMask(pixbuf);
161 }
162
create(Cairo::RefPtr<Cairo::Surface> pixmap,Cairo::RefPtr<Cairo::Surface> mask)163 PixMask* PixMask::create(Cairo::RefPtr<Cairo::Surface> pixmap, Cairo::RefPtr<Cairo::Surface> mask)
164 {
165 return new PixMask(pixmap, mask);
166 }
167
copy()168 PixMask* PixMask::copy()
169 {
170 return new PixMask(*this);
171 }
172
blit_centered(Cairo::RefPtr<Cairo::Surface> dest,Vector<int> pos)173 void PixMask::blit_centered(Cairo::RefPtr<Cairo::Surface> dest, Vector<int> pos)
174 {
175 blit (dest, pos.x - (width/2), pos.y - (height/2));
176 return;
177 }
178
blit(Cairo::RefPtr<Cairo::Surface> dest,Vector<int> pos)179 void PixMask::blit(Cairo::RefPtr<Cairo::Surface> dest, Vector<int> pos)
180 {
181 blit (dest, pos.x, pos.y);
182 return;
183 }
184
blit(Cairo::RefPtr<Cairo::Surface> dest,int dest_x,int dest_y)185 void PixMask::blit(Cairo::RefPtr<Cairo::Surface> dest, int dest_x, int dest_y)
186 {
187 //Here we are the map tile, blitting ourselves to the buffer where other
188 //map tiles live.
189 Cairo::RefPtr<Cairo::Context> context = Cairo::Context::create(dest);
190 context->set_source (pixmap, dest_x, dest_y);
191 context->paint();
192 }
193
blit(LwRectangle src,Cairo::RefPtr<Cairo::Surface> p,Vector<int> dest)194 void PixMask::blit(LwRectangle src, Cairo::RefPtr<Cairo::Surface> p, Vector<int> dest)
195 {
196 Cairo::RefPtr<Cairo::Context> context = Cairo::Context::create(p);
197 // Select the clipping rectangle
198 context->rectangle(dest.x, dest.y, src.w, src.h);
199
200 context->clip();
201 context->save();
202 context->set_source (pixmap, dest.x-src.x, dest.y-src.y);
203 context->rectangle (0, 0, src.w, src.h);
204 context->clip();
205 context->paint();
206 context->restore();
207 }
208
blit(Vector<int> tile,int ts,Cairo::RefPtr<Cairo::Surface> p,Vector<int> dest)209 void PixMask::blit(Vector<int> tile, int ts, Cairo::RefPtr<Cairo::Surface> p, Vector<int> dest)
210 {
211 Vector<int> src = tile * ts;
212 blit (LwRectangle(src.x, src.y, ts, ts), p, dest);
213 }
214
scale(PixMask * & p,int xsize,int ysize,Gdk::InterpType interp)215 void PixMask::scale(PixMask*& p, int xsize, int ysize, Gdk::InterpType interp)
216 {
217 PixMask *scaled = p->scale(xsize, ysize, interp);
218 delete p;
219 p = scaled;
220 p->set_unscaled_width(p->get_unscaled_width());
221 p->set_unscaled_height(p->get_unscaled_height());
222 return;
223 }
224
scale(int xsize,int ysize,Gdk::InterpType interp)225 PixMask * PixMask::scale(int xsize, int ysize, Gdk::InterpType interp)
226 {
227 Glib::RefPtr<Gdk::Pixbuf> pixbuf = to_pixbuf();
228 PixMask *pix = PixMask::create(pixbuf->scale_simple(xsize, ysize, interp));
229 pix->set_unscaled_width(get_unscaled_width());
230 pix->set_unscaled_height(get_unscaled_height());
231 pixbuf.reset();
232 return pix;
233 }
234
to_pixbuf()235 Glib::RefPtr<Gdk::Pixbuf> PixMask::to_pixbuf()
236 {
237 Glib::RefPtr<Gdk::Pixbuf> buf = Gdk::Pixbuf::create(pixmap, 0, 0, width, height);
238 Glib::RefPtr<Gdk::Pixbuf> alphabuf = buf->add_alpha(true, 255, 87, 204);
239 return alphabuf;
240 }
241
draw_pixbuf(Glib::RefPtr<Gdk::Pixbuf> pixbuf,int src_x,int src_y,int dest_x,int dest_y,int w,int h)242 void PixMask::draw_pixbuf(Glib::RefPtr<Gdk::Pixbuf> pixbuf, int src_x, int src_y, int dest_x, int dest_y, int w, int h)
243 {
244
245 Cairo::RefPtr<Cairo::Context> context = Cairo::Context::create(pixmap);
246 // Select the clipping rectangle
247 context->rectangle(dest_x, dest_y, w, h);
248
249 context->clip();
250 context->save();
251 PixMask *p = create(pixbuf);
252 context->set_source (p->get_pixmap(), src_x, src_y);
253 context->rectangle (src_x, src_y, w, h);
254 context->clip();
255 context->paint();
256 context->restore();
257 delete p;
258 }
259
get_depth()260 int PixMask::get_depth()
261 {
262 return 32;
263 }
264
get_dim() const265 Vector<int> PixMask::get_dim() const
266 {
267 return Vector<int>(width, height);
268 }
269
get_unscaled_dim() const270 Vector<int> PixMask::get_unscaled_dim() const
271 {
272 return Vector<int>(unscaled_width, unscaled_height);
273 }
274