00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "pnmBrush.h"
00016 #include "config_pnmimage.h"
00017 #include "cmath.h"
00018
00019
00020 class EXPCL_PANDA_PNMIMAGE PNMTransparentBrush : public PNMBrush {
00021 public:
00022 PNMTransparentBrush() :
00023 PNMBrush(0.0, 0.0) { }
00024
00025 virtual void draw(PNMImage &, int, int, double) {
00026 }
00027
00028 virtual void fill(PNMImage &, int, int, int, int, int) {
00029 }
00030 };
00031
00032
00033 class EXPCL_PANDA_PNMIMAGE PNMPixelBrush : public PNMBrush {
00034 protected:
00035 PNMPixelBrush(const LColord &color) :
00036 PNMBrush(0.5, 0.5), _rgb(color[0], color[1], color[2]), _a(color[3]) { }
00037
00038 LRGBColord _rgb;
00039 double _a;
00040 };
00041
00042
00043 class EXPCL_PANDA_PNMIMAGE PNMSetPixelBrush : public PNMPixelBrush {
00044 public:
00045 PNMSetPixelBrush(const LColord &color) : PNMPixelBrush(color) { }
00046
00047 virtual void draw(PNMImage &image, int x, int y, double pixel_scale) {
00048 if (x >= 0 && x < image.get_x_size() &&
00049 y >= 0 && y < image.get_y_size() &&
00050 pixel_scale >= 0.5) {
00051 image.set_xel(x, y, _rgb);
00052 if (image.has_alpha()) {
00053 image.set_alpha(x, y, _a);
00054 }
00055 }
00056 }
00057
00058 virtual void fill(PNMImage &image, int xfrom, int xto, int y,
00059 int xo, int yo) {
00060 if (y >= 0 && y < image.get_y_size()) {
00061 xfrom = max(xfrom, 0);
00062 xto = min(xto, image.get_x_size() - 1);
00063 for (int x = xfrom; x <= xto; ++x) {
00064 image.set_xel(x, y, _rgb);
00065 }
00066 if (image.has_alpha()) {
00067 for (int x = xfrom; x <= xto; ++x) {
00068 image.set_alpha(x, y, _a);
00069 }
00070 }
00071 }
00072 }
00073 };
00074
00075
00076 class EXPCL_PANDA_PNMIMAGE PNMBlendPixelBrush : public PNMPixelBrush {
00077 public:
00078 PNMBlendPixelBrush(const LColord &color) : PNMPixelBrush(color) { }
00079
00080 virtual void draw(PNMImage &image, int x, int y, double pixel_scale) {
00081 if (x >= 0 && x < image.get_x_size() &&
00082 y >= 0 && y < image.get_y_size()) {
00083 image.blend(x, y, _rgb, _a * pixel_scale);
00084 }
00085 }
00086
00087 virtual void fill(PNMImage &image, int xfrom, int xto, int y,
00088 int xo, int yo) {
00089 if (y >= 0 && y < image.get_y_size()) {
00090 xfrom = max(xfrom, 0);
00091 xto = min(xto, image.get_x_size() - 1);
00092 for (int x = xfrom; x <= xto; ++x) {
00093 image.blend(x, y, _rgb, _a);
00094 }
00095 }
00096 }
00097 };
00098
00099
00100 class EXPCL_PANDA_PNMIMAGE PNMDarkenPixelBrush : public PNMPixelBrush {
00101 public:
00102 PNMDarkenPixelBrush(const LColord &color) : PNMPixelBrush(color) { }
00103
00104 virtual void draw(PNMImage &image, int x, int y, double pixel_scale) {
00105 if (x >= 0 && x < image.get_x_size() &&
00106 y >= 0 && y < image.get_y_size()) {
00107 LRGBColord rgb = image.get_xel(x, y);
00108 LRGBColord p;
00109 p.set(min(1.0 - (1.0 - _rgb[0]) * pixel_scale, rgb[0]),
00110 min(1.0 - (1.0 - _rgb[1]) * pixel_scale, rgb[1]),
00111 min(1.0 - (1.0 - _rgb[2]) * pixel_scale, rgb[2]));
00112 image.set_xel(x, y, p);
00113
00114 if (image.has_alpha()) {
00115 double a = image.get_alpha(x, y);
00116 image.set_alpha(x, y, min(1.0 - (1.0 - _a) * pixel_scale, a));
00117 }
00118 }
00119 }
00120
00121 virtual void fill(PNMImage &image, int xfrom, int xto, int y,
00122 int xo, int yo) {
00123 if (y >= 0 && y < image.get_y_size()) {
00124 xfrom = max(xfrom, 0);
00125 xto = min(xto, image.get_x_size() - 1);
00126 for (int x = xfrom; x <= xto; ++x) {
00127 LRGBColord rgb = image.get_xel(x, y);
00128 LRGBColord p;
00129 p.set(min(_rgb[0], rgb[0]),
00130 min(_rgb[1], rgb[1]),
00131 min(_rgb[2], rgb[2]));
00132 image.set_xel(x, y, p);
00133 }
00134 if (image.has_alpha()) {
00135 for (int x = xfrom; x <= xto; ++x) {
00136 double a = image.get_alpha(x, y);
00137 image.set_alpha(x, y, min(_a, a));
00138 }
00139 }
00140 }
00141 }
00142 };
00143
00144
00145 class EXPCL_PANDA_PNMIMAGE PNMLightenPixelBrush : public PNMPixelBrush {
00146 public:
00147 PNMLightenPixelBrush(const LColord &color) : PNMPixelBrush(color) { }
00148
00149 virtual void draw(PNMImage &image, int x, int y, double pixel_scale) {
00150 if (x >= 0 && x < image.get_x_size() &&
00151 y >= 0 && y < image.get_y_size()) {
00152 LRGBColord rgb = image.get_xel(x, y);
00153 LRGBColord p;
00154 p.set(max(_rgb[0] * pixel_scale, rgb[0]),
00155 max(_rgb[1] * pixel_scale, rgb[1]),
00156 max(_rgb[2] * pixel_scale, rgb[2]));
00157 image.set_xel(x, y, p);
00158
00159 if (image.has_alpha()) {
00160 double a = image.get_alpha(x, y);
00161 image.set_alpha(x, y, max(_a * pixel_scale, a));
00162 }
00163 }
00164 }
00165
00166 virtual void fill(PNMImage &image, int xfrom, int xto, int y,
00167 int xo, int yo) {
00168 if (y >= 0 && y < image.get_y_size()) {
00169 xfrom = max(xfrom, 0);
00170 xto = max(xto, image.get_x_size() - 1);
00171 for (int x = xfrom; x <= xto; ++x) {
00172 LRGBColord rgb = image.get_xel(x, y);
00173 LRGBColord p;
00174 p.set(max(_rgb[0], rgb[0]),
00175 max(_rgb[1], rgb[1]),
00176 max(_rgb[2], rgb[2]));
00177 image.set_xel(x, y, p);
00178 }
00179 if (image.has_alpha()) {
00180 for (int x = xfrom; x <= xto; ++x) {
00181 double a = image.get_alpha(x, y);
00182 image.set_alpha(x, y, max(_a, a));
00183 }
00184 }
00185 }
00186 }
00187 };
00188
00189
00190 class EXPCL_PANDA_PNMIMAGE PNMImageBrush : public PNMBrush {
00191 protected:
00192 PNMImageBrush(const PNMImage &image, double xc, double yc) :
00193 PNMBrush(xc, yc),
00194 _image(image)
00195 {
00196 }
00197
00198 virtual void fill(PNMImage &image, int xfrom, int xto, int y,
00199 int xo, int yo) {
00200 if (y >= 0 && y < image.get_y_size()) {
00201 xfrom = max(xfrom, 0);
00202 xto = min(xto, image.get_x_size() - 1);
00203
00204 int x_pat = (xfrom + xo) % _image.get_x_size();
00205 int y_pat = (y + yo) % _image.get_y_size();
00206
00207
00208 int x = xfrom;
00209 do_scanline(image, x, y, x_pat, y_pat, xto - x + 1, 1);
00210
00211 x += _image.get_x_size() - x_pat;
00212 while (x <= xto) {
00213 do_scanline(image, x, y, 0, y_pat, xto - x + 1, 1);
00214 x += _image.get_x_size();
00215 }
00216 }
00217 }
00218
00219 virtual void do_scanline(PNMImage &image, int xto, int yto,
00220 int xfrom, int yfrom, int x_size, int y_size)=0;
00221
00222 PNMImage _image;
00223 };
00224
00225
00226 class EXPCL_PANDA_PNMIMAGE PNMSetImageBrush : public PNMImageBrush {
00227 public:
00228 PNMSetImageBrush(const PNMImage &image, double xc, double yc) :
00229 PNMImageBrush(image, xc, yc) { }
00230
00231 virtual void draw(PNMImage &image, int x, int y, double pixel_scale) {
00232 if (pixel_scale >= 0.5) {
00233 image.copy_sub_image(_image, x, y);
00234 }
00235 }
00236
00237 virtual void do_scanline(PNMImage &image, int xto, int yto,
00238 int xfrom, int yfrom, int x_size, int y_size) {
00239 image.copy_sub_image(_image, xto, yto, xfrom, yfrom, x_size, y_size);
00240 }
00241 };
00242
00243
00244 class EXPCL_PANDA_PNMIMAGE PNMBlendImageBrush : public PNMImageBrush {
00245 public:
00246 PNMBlendImageBrush(const PNMImage &image, double xc, double yc) :
00247 PNMImageBrush(image, xc, yc) { }
00248
00249 virtual void draw(PNMImage &image, int x, int y, double pixel_scale) {
00250 image.blend_sub_image(_image, x, y, 0, 0, -1, -1, pixel_scale);
00251 }
00252
00253 virtual void do_scanline(PNMImage &image, int xto, int yto,
00254 int xfrom, int yfrom, int x_size, int y_size) {
00255 image.blend_sub_image(_image, xto, yto, xfrom, yfrom, x_size, y_size);
00256 }
00257 };
00258
00259
00260 class EXPCL_PANDA_PNMIMAGE PNMDarkenImageBrush : public PNMImageBrush {
00261 public:
00262 PNMDarkenImageBrush(const PNMImage &image, double xc, double yc) :
00263 PNMImageBrush(image, xc, yc) { }
00264
00265 virtual void draw(PNMImage &image, int x, int y, double pixel_scale) {
00266 image.darken_sub_image(_image, x, y, 0, 0, -1, -1, pixel_scale);
00267 }
00268
00269 virtual void do_scanline(PNMImage &image, int xto, int yto,
00270 int xfrom, int yfrom, int x_size, int y_size) {
00271 image.darken_sub_image(_image, xto, yto, xfrom, yfrom, x_size, y_size);
00272 }
00273 };
00274
00275
00276 class EXPCL_PANDA_PNMIMAGE PNMLightenImageBrush : public PNMImageBrush {
00277 public:
00278 PNMLightenImageBrush(const PNMImage &image, double xc, double yc) :
00279 PNMImageBrush(image, xc, yc) { }
00280
00281 virtual void draw(PNMImage &image, int x, int y, double pixel_scale) {
00282 image.lighten_sub_image(_image, x, y, 0, 0, -1, -1, pixel_scale);
00283 }
00284
00285 virtual void do_scanline(PNMImage &image, int xto, int yto,
00286 int xfrom, int yfrom, int x_size, int y_size) {
00287 image.lighten_sub_image(_image, xto, yto, xfrom, yfrom, x_size, y_size);
00288 }
00289 };
00290
00291
00292
00293
00294
00295
00296 PNMBrush::
00297 ~PNMBrush() {
00298 }
00299
00300
00301
00302
00303
00304
00305
00306
00307 PT(PNMBrush) PNMBrush::
00308 make_transparent() {
00309 return new PNMTransparentBrush();
00310 }
00311
00312
00313
00314
00315
00316
00317
00318
00319 PT(PNMBrush) PNMBrush::
00320 make_pixel(const LColord &color, PNMBrush::BrushEffect effect) {
00321 switch (effect) {
00322 case BE_set:
00323 return new PNMSetPixelBrush(color);
00324
00325 case BE_blend:
00326 return new PNMBlendPixelBrush(color);
00327
00328 case BE_darken:
00329 return new PNMDarkenPixelBrush(color);
00330
00331 case BE_lighten:
00332 return new PNMLightenPixelBrush(color);
00333 }
00334
00335 pnmimage_cat.error()
00336 << "**Invalid BrushEffect (" << (int)effect << ")**\n";
00337 return new PNMSetPixelBrush(color);
00338 }
00339
00340
00341
00342
00343
00344
00345
00346
00347 PT(PNMBrush) PNMBrush::
00348 make_spot(const LColord &color, double radius, bool fuzzy,
00349 BrushEffect effect) {
00350 LColord bg;
00351
00352 switch (effect) {
00353 case BE_set:
00354 bg.set(0, 0, 0, 0);
00355 break;
00356
00357 case BE_blend:
00358 bg.set(color[0], color[1], color[2], 0.0);
00359 break;
00360
00361 case BE_darken:
00362 bg.set(1, 1, 1, 1);
00363 break;
00364
00365 case BE_lighten:
00366 bg.set(0, 0, 0, 0);
00367 break;
00368
00369 default:
00370 pnmimage_cat.error()
00371 << "**Invalid BrushEffect (" << (int)effect << ")**\n";
00372 }
00373
00374 int size = (int)cceil(radius * 2.0);
00375 double half_size = (double)size * 0.5;
00376 PNMImage spot(size, size, 4);
00377 double r = half_size / radius;
00378
00379 if (fuzzy) {
00380 spot.render_spot(color, bg, 0.0, r);
00381 } else {
00382 spot.render_spot(color, bg, r, r);
00383 }
00384 return make_image(spot, half_size, half_size, effect);
00385 }
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398 PT(PNMBrush) PNMBrush::
00399 make_image(const PNMImage &image, double xc, double yc,
00400 PNMBrush::BrushEffect effect) {
00401 switch (effect) {
00402 case BE_set:
00403 return new PNMSetImageBrush(image, xc, yc);
00404
00405 case BE_blend:
00406 return new PNMBlendImageBrush(image, xc, yc);
00407
00408 case BE_darken:
00409 return new PNMDarkenImageBrush(image, xc, yc);
00410
00411 case BE_lighten:
00412 return new PNMLightenImageBrush(image, xc, yc);
00413 }
00414
00415 pnmimage_cat.error()
00416 << "**Invalid BrushEffect (" << (int)effect << ")**\n";
00417 return new PNMSetImageBrush(image, xc, yc);
00418 }