Panda3D
Loading...
Searching...
No Matches
pnmBrush.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file pnmBrush.cxx
10 * @author drose
11 * @date 2007-02-01
12 */
13
14#include "pnmBrush.h"
15#include "pnmImage.h"
16#include "config_pnmimage.h"
17#include "cmath.h"
18
19using std::max;
20using std::min;
21
22// A PNMTransparentBrush doesn't draw or fill anything.
23class EXPCL_PANDA_PNMIMAGE PNMTransparentBrush : public PNMBrush {
24public:
25 PNMTransparentBrush() :
26 PNMBrush(0.0, 0.0) { }
27
28 virtual void draw(PNMImage &, int, int, float) {
29 }
30
31 virtual void fill(PNMImage &, int, int, int, int, int) {
32 }
33};
34
35// A PNMPixelBrush is a family of brushes that draw one pixel at a time.
36class EXPCL_PANDA_PNMIMAGE PNMPixelBrush : public PNMBrush {
37protected:
38 PNMPixelBrush(const LColorf &color) :
39 PNMBrush(0.5, 0.5), _color(color) { }
40
41 LColorf _color;
42};
43
44// Arbitrarily sets the pixel to a particular color, with no antialiasing.
45class EXPCL_PANDA_PNMIMAGE PNMSetPixelBrush : public PNMPixelBrush {
46public:
47 PNMSetPixelBrush(const LColorf &color) : PNMPixelBrush(color) { }
48
49 virtual void draw(PNMImage &image, int x, int y, float pixel_scale) {
50 if (x >= 0 && x < image.get_x_size() &&
51 y >= 0 && y < image.get_y_size() &&
52 pixel_scale >= 0.5) {
53 image.set_xel_a(x, y, _color);
54 }
55 }
56
57 virtual void fill(PNMImage &image, int xfrom, int xto, int y,
58 int xo, int yo) {
59 if (y >= 0 && y < image.get_y_size()) {
60 xfrom = max(xfrom, 0);
61 xto = min(xto, image.get_x_size() - 1);
62 for (int x = xfrom; x <= xto; ++x) {
63 image.set_xel_a(x, y, _color);
64 }
65 }
66 }
67};
68
69// Blends the pixel in to the existing background.
70class EXPCL_PANDA_PNMIMAGE PNMBlendPixelBrush : public PNMPixelBrush {
71public:
72 PNMBlendPixelBrush(const LColorf &color) : PNMPixelBrush(color) { }
73
74 virtual void draw(PNMImage &image, int x, int y, float pixel_scale) {
75 if (x >= 0 && x < image.get_x_size() &&
76 y >= 0 && y < image.get_y_size()) {
77 image.blend(x, y, _color[0], _color[1], _color[2], _color[3] * pixel_scale);
78 }
79 }
80
81 virtual void fill(PNMImage &image, int xfrom, int xto, int y,
82 int xo, int yo) {
83 if (y >= 0 && y < image.get_y_size()) {
84 xfrom = max(xfrom, 0);
85 xto = min(xto, image.get_x_size() - 1);
86 for (int x = xfrom; x <= xto; ++x) {
87 image.blend(x, y, _color[0], _color[1], _color[2], _color[3]);
88 }
89 }
90 }
91};
92
93// Darkens the pixel in the existing background.
94class EXPCL_PANDA_PNMIMAGE PNMDarkenPixelBrush : public PNMPixelBrush {
95public:
96 PNMDarkenPixelBrush(const LColorf &color) : PNMPixelBrush(color) { }
97
98 virtual void draw(PNMImage &image, int x, int y, float pixel_scale) {
99 if (x >= 0 && x < image.get_x_size() &&
100 y >= 0 && y < image.get_y_size()) {
101
102 LColorf p = (_color - 1.0f) * pixel_scale + 1.0f;
103 image.set_xel_a(x, y, p.fmin(image.get_xel_a(x, y)));
104 }
105 }
106
107 virtual void fill(PNMImage &image, int xfrom, int xto, int y,
108 int xo, int yo) {
109 if (y >= 0 && y < image.get_y_size()) {
110 xfrom = max(xfrom, 0);
111 xto = min(xto, image.get_x_size() - 1);
112 for (int x = xfrom; x <= xto; ++x) {
113 image.set_xel_a(x, y, _color.fmin(image.get_xel_a(x, y)));
114 }
115 }
116 }
117};
118
119// Lightens the pixel in the existing background.
120class EXPCL_PANDA_PNMIMAGE PNMLightenPixelBrush : public PNMPixelBrush {
121public:
122 PNMLightenPixelBrush(const LColorf &color) : PNMPixelBrush(color) { }
123
124 virtual void draw(PNMImage &image, int x, int y, float pixel_scale) {
125 if (x >= 0 && x < image.get_x_size() &&
126 y >= 0 && y < image.get_y_size()) {
127 image.set_xel_a(x, y,
128 image.get_xel_a(x, y).fmax(_color * pixel_scale));
129 }
130 }
131
132 virtual void fill(PNMImage &image, int xfrom, int xto, int y,
133 int xo, int yo) {
134 if (y >= 0 && y < image.get_y_size()) {
135 xfrom = max(xfrom, 0);
136 xto = max(xto, image.get_x_size() - 1);
137 for (int x = xfrom; x <= xto; ++x) {
138 image.set_xel_a(x, y,
139 image.get_xel_a(x, y).fmax(_color));
140 }
141 }
142 }
143};
144
145// A PNMImageBrush is a family of brushes that draw an image at a time.
146class EXPCL_PANDA_PNMIMAGE PNMImageBrush : public PNMBrush {
147protected:
148 PNMImageBrush(const PNMImage &image, float xc, float yc) :
149 PNMBrush(xc, yc),
150 _image(image)
151 {
152 }
153
154 virtual void fill(PNMImage &image, int xfrom, int xto, int y,
155 int xo, int yo) {
156 if (y >= 0 && y < image.get_y_size()) {
157 xfrom = max(xfrom, 0);
158 xto = min(xto, image.get_x_size() - 1);
159
160 int x_pat = (xfrom + xo) % _image.get_x_size();
161 int y_pat = (y + yo) % _image.get_y_size();
162
163 // Copy the first (right half) of the image scanline.
164 int x = xfrom;
165 do_scanline(image, x, y, x_pat, y_pat, xto - x + 1, 1);
166 // Now repeatedly make more copies of the image scanline.
167 x += _image.get_x_size() - x_pat;
168 while (x <= xto) {
169 do_scanline(image, x, y, 0, y_pat, xto - x + 1, 1);
170 x += _image.get_x_size();
171 }
172 }
173 }
174
175 virtual void do_scanline(PNMImage &image, int xto, int yto,
176 int xfrom, int yfrom, int x_size, int y_size)=0;
177
178 PNMImage _image;
179};
180
181// Sets the pixels from the rectangular image, with no antialiasing.
182class EXPCL_PANDA_PNMIMAGE PNMSetImageBrush : public PNMImageBrush {
183public:
184 PNMSetImageBrush(const PNMImage &image, float xc, float yc) :
185 PNMImageBrush(image, xc, yc) { }
186
187 virtual void draw(PNMImage &image, int x, int y, float pixel_scale) {
188 if (pixel_scale >= 0.5) {
189 image.copy_sub_image(_image, x, y);
190 }
191 }
192
193 virtual void do_scanline(PNMImage &image, int xto, int yto,
194 int xfrom, int yfrom, int x_size, int y_size) {
195 image.copy_sub_image(_image, xto, yto, xfrom, yfrom, x_size, y_size);
196 }
197};
198
199// Blends the pixels in using alpha.
200class EXPCL_PANDA_PNMIMAGE PNMBlendImageBrush : public PNMImageBrush {
201public:
202 PNMBlendImageBrush(const PNMImage &image, float xc, float yc) :
203 PNMImageBrush(image, xc, yc) { }
204
205 virtual void draw(PNMImage &image, int x, int y, float pixel_scale) {
206 image.blend_sub_image(_image, x, y, 0, 0, -1, -1, pixel_scale);
207 }
208
209 virtual void do_scanline(PNMImage &image, int xto, int yto,
210 int xfrom, int yfrom, int x_size, int y_size) {
211 image.blend_sub_image(_image, xto, yto, xfrom, yfrom, x_size, y_size);
212 }
213};
214
215// Darkens the pixels
216class EXPCL_PANDA_PNMIMAGE PNMDarkenImageBrush : public PNMImageBrush {
217public:
218 PNMDarkenImageBrush(const PNMImage &image, float xc, float yc) :
219 PNMImageBrush(image, xc, yc) { }
220
221 virtual void draw(PNMImage &image, int x, int y, float pixel_scale) {
222 image.darken_sub_image(_image, x, y, 0, 0, -1, -1, pixel_scale);
223 }
224
225 virtual void do_scanline(PNMImage &image, int xto, int yto,
226 int xfrom, int yfrom, int x_size, int y_size) {
227 image.darken_sub_image(_image, xto, yto, xfrom, yfrom, x_size, y_size);
228 }
229};
230
231// Lightens the pixels
232class EXPCL_PANDA_PNMIMAGE PNMLightenImageBrush : public PNMImageBrush {
233public:
234 PNMLightenImageBrush(const PNMImage &image, float xc, float yc) :
235 PNMImageBrush(image, xc, yc) { }
236
237 virtual void draw(PNMImage &image, int x, int y, float pixel_scale) {
238 image.lighten_sub_image(_image, x, y, 0, 0, -1, -1, pixel_scale);
239 }
240
241 virtual void do_scanline(PNMImage &image, int xto, int yto,
242 int xfrom, int yfrom, int x_size, int y_size) {
243 image.lighten_sub_image(_image, xto, yto, xfrom, yfrom, x_size, y_size);
244 }
245};
246
247/**
248 *
249 */
250PNMBrush::
251~PNMBrush() {
252}
253
254/**
255 * Returns a new brush that does not paint anything. Can be used as either a
256 * pen or a fill brush to make borderless or unfilled shapes, respectively.
257 */
258PT(PNMBrush) PNMBrush::
259make_transparent() {
260 return new PNMTransparentBrush();
261}
262
263/**
264 * Returns a new brush that paints a single pixel of the indicated color on a
265 * border, or paints a solid color in an interior.
266 */
267PT(PNMBrush) PNMBrush::
268make_pixel(const LColorf &color, PNMBrush::BrushEffect effect) {
269 switch (effect) {
270 case BE_set:
271 return new PNMSetPixelBrush(color);
272
273 case BE_blend:
274 return new PNMBlendPixelBrush(color);
275
276 case BE_darken:
277 return new PNMDarkenPixelBrush(color);
278
279 case BE_lighten:
280 return new PNMLightenPixelBrush(color);
281 }
282
283 pnmimage_cat.error()
284 << "**Invalid BrushEffect (" << (int)effect << ")**\n";
285 return new PNMSetPixelBrush(color);
286}
287
288/**
289 * Returns a new brush that paints a spot of the indicated color and radius.
290 * If fuzzy is true, the spot is fuzzy; otherwise, it is hard-edged.
291 */
292PT(PNMBrush) PNMBrush::
293make_spot(const LColorf &color, float radius, bool fuzzy,
294 BrushEffect effect) {
295 LColorf bg;
296
297 switch (effect) {
298 case BE_set:
299 bg.set(0, 0, 0, 0);
300 break;
301
302 case BE_blend:
303 bg.set(color[0], color[1], color[2], 0.0f);
304 break;
305
306 case BE_darken:
307 bg.set(1, 1, 1, 1);
308 break;
309
310 case BE_lighten:
311 bg.set(0, 0, 0, 0);
312 break;
313
314 default:
315 pnmimage_cat.error()
316 << "**Invalid BrushEffect (" << (int)effect << ")**\n";
317 }
318
319 int size = (int)cceil(radius * 2.0f);
320 float half_size = (float)size * 0.5f;
321 PNMImage spot(size, size, 4);
322 float r = half_size / radius;
323
324 if (fuzzy) {
325 spot.render_spot(color, bg, 0.0f, r);
326 } else {
327 spot.render_spot(color, bg, r, r);
328 }
329 return make_image(spot, half_size, half_size, effect);
330}
331
332/**
333 * Returns a new brush that paints with the indicated image. xc and yc
334 * indicate the pixel in the center of the brush.
335 *
336 * The brush makes a copy of the image; it is safe to deallocate or modify the
337 * image after making this call.
338 */
339PT(PNMBrush) PNMBrush::
340make_image(const PNMImage &image, float xc, float yc,
341 PNMBrush::BrushEffect effect) {
342 switch (effect) {
343 case BE_set:
344 return new PNMSetImageBrush(image, xc, yc);
345
346 case BE_blend:
347 return new PNMBlendImageBrush(image, xc, yc);
348
349 case BE_darken:
350 return new PNMDarkenImageBrush(image, xc, yc);
351
352 case BE_lighten:
353 return new PNMLightenImageBrush(image, xc, yc);
354 }
355
356 pnmimage_cat.error()
357 << "**Invalid BrushEffect (" << (int)effect << ")**\n";
358 return new PNMSetImageBrush(image, xc, yc);
359}
This class is used to control the shape and color of the drawing operations performed by a PNMPainter...
Definition pnmBrush.h:36
int get_x_size() const
Returns the number of pixels in the X direction.
int get_y_size() const
Returns the number of pixels in the Y direction.
The name of this class derives from the fact that we originally implemented it as a layer on top of t...
Definition pnmImage.h:58
void copy_sub_image(const PNMImage &copy, int xto, int yto, int xfrom=0, int yfrom=0, int x_size=-1, int y_size=-1)
Copies a rectangular area of another image into a rectangular area of this image.
void blend_sub_image(const PNMImage &copy, int xto, int yto, int xfrom=0, int yfrom=0, int x_size=-1, int y_size=-1, float pixel_scale=1.0)
Behaves like copy_sub_image(), except the alpha channel of the copy is used to blend the copy into th...
void set_xel_a(int x, int y, const LColorf &value)
Changes the RGBA color at the indicated pixel.
Definition pnmImage.I:675
void lighten_sub_image(const PNMImage &copy, int xto, int yto, int xfrom=0, int yfrom=0, int x_size=-1, int y_size=-1, float pixel_scale=1.0)
Behaves like copy_sub_image(), but the resulting color will be the lighter of the source and destinat...
void blend(int x, int y, const LRGBColorf &val, float alpha)
Smoothly blends the indicated pixel value in with whatever was already in the image,...
Definition pnmImage.I:900
LColorf get_xel_a(int x, int y) const
Returns the RGBA color at the indicated pixel.
Definition pnmImage.I:608
void darken_sub_image(const PNMImage &copy, int xto, int yto, int xfrom=0, int yfrom=0, int x_size=-1, int y_size=-1, float pixel_scale=1.0)
Behaves like copy_sub_image(), but the resulting color will be the darker of the source and destinati...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.