1
2 /*
3 * picture-object...
4 * Copyright (c) 2002-2006 by Mattias Hultgren <mattias_hultgren@tele2.se>
5 *
6 * See picture.h
7 */
8
9 /*
10 v16 2006-07-28
11 ---
12
13 Replaced all throw_... function calls (as they no longer exists) with THROW_ERROR
14
15 v15 2006-04-22
16 ---
17
18 Picture's destructor is now virtual
19
20 v14 2005-09-15 - 2005-10-23
21 ---
22
23 Removed the support for delayed picture copying
24 Added function draw_lines (which draws multiple lines with or without antialiasing)
25 Rewrote filled_circle to use Bresenham's algorithm
26 Added support for antialiasing in circle, filled_circle & ellipse
27 Added operator==()
28 Removed PictureType_YCrCb, PictureType_PALETTE as they wasn't supported anyway
29
30 v1.0.12 2005-09-09 - 2005-09-11
31 -------
32
33 Removed class textpicture, as it wasn't used and I will build a vector-based replacer
34 Rewrote circle to use Bresenham's algorithm
35
36 v1.0.11 2005-08-08 - 2005-08-18
37 -------
38
39 Replaced all asin(1.0) with M_PI similarities
40 Added picture::line_antialiasing()
41
42 v1.0.10 2005-02-03 - 2005-02-04
43 -------
44
45 Added support for background pictures (ie pictures without solidness-buffer)
46 Added support for delayed picture copying
47
48 v1.0.9 2004-10-03 & 2004-12-19
49 ------
50
51 Removed unused variables
52 Small fixes in circle, filed_circle & ellipse
53 save_ppm now uses bool for save_as_ascii-argument
54 Fixed some compiler warnings
55
56 v1.0.8 2004-07-14 - 2004-09-06
57 ------
58
59 Removed all appearance of Thrower
60 Added copy constructor to picture
61 Translation support completed
62 Added picture::circle, picture::filled_circle, picture::ellipse
63 Renamed a lot of functions
64 Clear now also sets the solidness to 255 for the whole picture
65
66 v1.0.7 2004-07-03 - 2004-07-13
67 ------
68
69 Added some missed error checking
70 Replaced some throw-lines with Throw_functions, to enable easy translation
71 Fixed a complete check and recalculation of points outside picture in line-function
72 Merged file picture.line.inc.cpp with picture.cpp
73 Added color::ORANGE
74
75 v1.0.6 2004-06-17
76 ------
77
78 Replaced some const-groups with enum's, this changed the 'const'-names...
79
80 v1.0.5 2004-04-13 - 2004-04-17
81 ------
82
83 Added code in line-function so that lines that are totally outside the picture is ignored
84
85 v1.0.4 2003-12-18 - 2003-12-29 & 2004-03-20
86 ------
87
88 Small fix (2004-03-20)
89 Pictures can be saved as PPM-files
90 Added setpixel_grayscale (this function does nothing if the picture isn't grayscale)
91
92 v1.0.3 2003-02-22
93 ------
94
95 Added mirror, upsidedown, rotate90, rotate180 and rotate270
96 The picture type grayscale is supported
97
98 v1.0.2 2003-02-04 - 2003-02-18
99 ------
100
101 textpicture now supports TEXT_RIGHT and TEXT_CENTER aligned text
102 savepcx added to picture
103 Added getwidth(),getheight() to textpicture
104
105 v1.0.1 2003-01-27
106 ------
107
108 Greatly reduced time usage for drawing pictures partly or totaly outside dest
109 A speedup for RGB to RGB-picture-drawing
110 A small speedup for drawshadow-function
111
112 v1.0.0 2002-12-14 - 2003-01-09
113 ------
114
115 Basic functions for the picture object
116 PCX-files can be loaded
117 Textpicture-object works
118 The picture type RGB is supported
119 The picture types YCrCb/grayscale/palette is not supported (but planned)
120 */
121
122 #include "picture.h"
123 #include "keyfile.h"
124 #include <stdio.h>
125 #include <stdlib.h>
126 #include <memory.h>
127 #include <math.h>
128
129 namespace picture_h
130 {
131
132 picture *dest = 0;
133
134
operator ==(const colorrgb & color) const135 bool colorrgb::operator==(const colorrgb &color) const
136 {
137 if( red == color.red && green == color.green && blue == color.blue )
138 return true;
139 return false;
140 }
141
142 namespace color
143 {
144 const colorrgb RED = { 255, 0, 0 };
145 const colorrgb GREEN = { 0, 255, 0 };
146 const colorrgb BLUE = { 0, 0, 255 };
147 const colorrgb DARK_RED = { 170, 0, 0 };
148 const colorrgb DARK_GREEN = { 0, 170, 0 };
149 const colorrgb DARK_BLUE = { 0, 0, 170 };
150 const colorrgb YELLOW = { 255, 255, 0 };
151 const colorrgb WHITE = { 255, 255, 255 };
152 const colorrgb LIGHT_GRAY = { 170, 170, 170 };
153 const colorrgb DARK_GRAY = { 85, 85, 85 };
154 const colorrgb BLACK = { 0, 0, 0 };
155 const colorrgb PURPLE = { 165, 0, 255 };
156 const colorrgb PINK = { 255, 0, 229 };
157 const colorrgb ORANGE = { 255, 147, 0 };
158 }
159
picture()160 picture::picture()
161 {
162 width = 0;
163 height = 0;
164 type = PictureType_RGB;
165
166 isBackground = false;
167
168 data[0].buffer = 0;
169 data[0].buffersize = 0;
170 data[1].buffer = 0;
171 data[1].buffersize = 0;
172 data[2].buffer = 0;
173 data[2].buffersize = 0;
174 solidness.buffer = 0;
175 solidness.buffersize = 0;
176 }
picture(const picture & src)177 picture::picture(const picture &src) throw(error_obj)
178 {
179 width = 0;
180 height = 0;
181 type = PictureType_RGB;
182
183 isBackground = false;
184
185 data[0].buffer = 0;
186 data[0].buffersize = 0;
187 data[1].buffer = 0;
188 data[1].buffersize = 0;
189 data[2].buffer = 0;
190 data[2].buffersize = 0;
191 solidness.buffer = 0;
192 solidness.buffersize = 0;
193
194 *this = src;
195 }
196
~picture()197 picture::~picture()
198 {
199 erase();
200 }
201
set_isBackground(bool value)202 void picture::set_isBackground(bool value) throw(error_obj)
203 {
204 if( value )
205 {
206 delete [] solidness.buffer;
207 solidness.buffer = 0;
208 solidness.buffersize = 0;
209 isBackground = value;
210 }
211 else
212 {
213 if( solidness.buffersize < (width*height) )
214 {
215 delete [] solidness.buffer;
216 solidness.buffer = 0;
217 solidness.buffersize = 0;
218 try
219 {
220 solidness.buffer = new uint8 [ width*height ];
221 solidness.buffersize = width*height;
222 }
223 catch(...)
224 {
225 isBackground = true;
226 THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") );
227 }
228 }
229 isBackground = value;
230 }
231 }
232
233
234 //
235 // erase - freeing all the memory used by picture-object
236 //
erase(void)237 void picture::erase(void)
238 {
239 delete [] data[0].buffer;
240 delete [] data[1].buffer;
241 delete [] data[2].buffer;
242 delete [] solidness.buffer;
243
244 width = 0;
245 height = 0;
246
247 data[0].buffer = 0;
248 data[0].buffersize = 0;
249 data[1].buffer = 0;
250 data[1].buffersize = 0;
251 data[2].buffer = 0;
252 data[2].buffersize = 0;
253 solidness.buffer = 0;
254 solidness.buffersize = 0;
255 }
256
257
258
259 //
260 // setsize - changes the size of the image
261 // Note: this is NOT a resizer, the imagedata will be destroyed
262 //
set_size(int32 newwidth,int32 newheight)263 void picture::set_size(int32 newwidth,int32 newheight) throw(error_obj)
264 {
265 int32 size,i;
266
267 if( newwidth < 0 || newheight < 0 )
268 {
269 THROW_ERROR( ErrorType_General, _("Invalid width and/or height.") );
270 }
271 else if( newwidth == 0 || newheight == 0 )
272 {
273 erase();
274 return;
275 }
276 else if( newwidth == width && newheight == height )
277 return;
278
279 try
280 {
281 size = newwidth * newheight;
282
283 if( !isBackground )
284 {
285 if(solidness.buffersize < size)
286 {
287 delete [] solidness.buffer;
288 solidness.buffer = 0;
289 solidness.buffersize = 0;
290
291 solidness.buffer = new uint8 [size];
292
293 solidness.buffersize = size;
294 }
295 }
296
297 for(i=0;i<3;i++)
298 {
299 if( i != 0 && type == PictureType_GRAYSCALE )
300 break;
301
302 if(data[i].buffersize < size)
303 {
304 delete [] data[i].buffer;
305 data[i].buffer = 0;
306 data[i].buffersize = 0;
307
308 data[i].buffer = new uint8 [size];
309
310 data[i].buffersize = size;
311 }
312 }
313 width = newwidth;
314 height = newheight;
315 }
316 catch(...)
317 {
318 erase();
319 THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") );
320 }
321 }
322
circle(int32 x,int32 y,uint32 r,const colorrgb & color,bool antialiased)323 void picture::circle(int32 x, int32 y, uint32 r, const colorrgb &color, bool antialiased )
324 throw(error_obj)
325 {
326 if( antialiased )
327 {
328 uint32 nroflines,i, *lines=0;
329 double angle,dr,step,dx,dy,dcx,dcy;
330 float *vertex=0;
331
332 dr = double(r);
333 step = M_PI * dr / 2.0;
334
335 if(step > 100.0)
336 nroflines = 100;
337 else
338 nroflines = uint32(step + 0.5);
339 if( nroflines < 6 )
340 nroflines = 6;
341
342 step = 2.0*M_PI / double(nroflines);
343 angle = step;
344
345 try
346 {
347 dcx = double(x);
348 dcy = double(y);
349
350 vertex = new float [nroflines*2+2];
351 lines = new uint32 [nroflines*2];
352
353 vertex[0] = float(dcx+dr);
354 vertex[1] = float(dcy);
355
356 for(i=0;i<nroflines;i++,angle+=step)
357 {
358 dx = cos(angle) * dr;
359 dy = sin(angle) * dr;
360
361 vertex[i*2+2] = float(dx+dcx);
362 vertex[i*2+3] = float(dy+dcy);
363 lines[i*2] = i*2;
364 lines[i*2+1] = i*2+2;
365 }
366 draw_lines( vertex, lines, nroflines, color, true );
367 }
368 catch(...)
369 {
370 delete [] vertex;
371 delete [] lines;
372 THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") );
373 }
374 delete [] vertex;
375 delete [] lines;
376 }
377 else
378 {
379 // Using Bresenham's algorithm
380 if( r != 0 )
381 {
382 int32 d, tx, ty;
383
384 tx = 0;
385 ty = int32(r);
386 d = 3 - 2*ty;
387
388 while(true)
389 {
390 set_pixel( x + tx, y + ty, color );
391 set_pixel( x + tx, y - ty, color );
392 set_pixel( x - tx, y + ty, color );
393 set_pixel( x - tx, y - ty, color );
394 set_pixel( x + ty, y + tx, color );
395 set_pixel( x + ty, y - tx, color );
396 set_pixel( x - ty, y + tx, color );
397 set_pixel( x - ty, y - tx, color );
398
399 if( tx >= ty )
400 break;
401
402 if( d < 0 )
403 d += 4*tx + 6;
404 else
405 {
406 d += 4*(tx - ty) + 10;
407 ty--;
408 }
409 tx++;
410 }
411 }
412 }
413 }
414
ellipse(int32 x,int32 y,uint32 rx,uint32 ry,const colorrgb & color,bool antialiased)415 void picture::ellipse( int32 x, int32 y, uint32 rx, uint32 ry, const colorrgb &color,
416 bool antialiased ) throw(error_obj)
417 {
418 uint32 nroflines,i, *lines=0;
419 int32 nx,ny,prevx,prevy;
420 double angle,drx,dry,step,dx,dy,dcx,dcy;
421 float *vertex=0;
422
423 drx = double(rx);
424 dry = double(ry);
425 step = M_PI * ( (drx > dry) ? drx : dry ) / 2.0;
426
427 if(step > 100.0)
428 nroflines = 100;
429 else
430 nroflines = uint32(step + 0.5);
431 if( nroflines < 6 )
432 nroflines = 6;
433
434 step = 2.0*M_PI / double(nroflines);
435 angle = step;
436
437 try
438 {
439 if( antialiased )
440 {
441 dcx = double(x);
442 dcy = double(y);
443
444 vertex = new float [nroflines*2+2];
445 lines = new uint32 [nroflines*2];
446
447 vertex[0] = float(dcx+drx);
448 vertex[1] = float(dcy);
449 }
450 else
451 {
452 prevx = x + rx;
453 prevy = y;
454 }
455
456 for(i=0;i<nroflines;i++,angle+=step)
457 {
458 dx = cos(angle) * drx;
459 dy = sin(angle) * dry;
460
461 if( antialiased )
462 {
463 vertex[i*2+2] = float(dx+dcx);
464 vertex[i*2+3] = float(dy+dcy);
465 lines[i*2] = i*2;
466 lines[i*2+1] = i*2+2;
467 }
468 else
469 {
470 nx = x + int32(dx + 0.5);
471 ny = y + int32(dy + 0.5);
472 line(prevx,prevy,nx,ny,color);
473
474 prevx = nx;
475 prevy = ny;
476 }
477 }
478 if( antialiased )
479 draw_lines( vertex, lines, nroflines, color, true );
480 }
481 catch(...)
482 {
483 delete [] vertex;
484 delete [] lines;
485 THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") );
486 }
487 delete [] vertex;
488 delete [] lines;
489 }
490
filled_circle(int32 x,int32 y,uint32 r,const colorrgb & color,bool antialiased)491 void picture::filled_circle(int32 x, int32 y, uint32 r, const colorrgb &color, bool antialiased)
492 throw(error_obj)
493 {
494 // Using Bresenham's algorithm
495 if( r != 0 )
496 {
497 if( antialiased )
498 {
499 float cx, cy, fr = float(r), row, fx, fr2, t;
500 cx = float(x) + 0.5f;
501 cy = float(y) + 0.5f;
502 fr2 = fr*fr;
503 fx = fr;
504
505 for( row=0.0f; row<fx; row++ )
506 {
507 fx = sqrt( fr2 - row*row );
508
509 if( fx != trunc(fx) )
510 {
511 t = fx - trunc(fx);
512 fx = trunc(fx);
513
514 set_pixel( int32(cx-fx)-1, y+int32(row), color, uint8( 255.0*t) );
515 set_pixel( int32(cx-fx)-1, y-int32(row), color, uint8( 255.0*t) );
516 set_pixel( y+int32(row), int32(cx-fx)-1, color, uint8( 255.0*t) );
517 set_pixel( y-int32(row), int32(cx-fx)-1, color, uint8( 255.0*t) );
518 if( row != 0.0f )
519 {
520 set_pixel( int32(cx+fx)+1, y+int32(row), color, uint8( 255.0*t) );
521 set_pixel( int32(cx+fx)+1, y-int32(row), color, uint8( 255.0*t) );
522 set_pixel( y+int32(row), int32(cx+fx)+1, color, uint8( 255.0*t) );
523 set_pixel( y-int32(row), int32(cx+fx)+1, color, uint8( 255.0*t) );
524 }
525 }
526
527 line( int32(cx-fx), y+int32(row), int32(cx+fx), y+int32(row), color );
528 line( int32(cx-fx), y-int32(row), int32(cx+fx), y-int32(row), color );
529 line( y+int32(row), int32(cx-fx), y+int32(row), int32(cx+fx), color );
530 line( y-int32(row), int32(cx-fx), y-int32(row), int32(cx+fx), color );
531 }
532 }
533 else
534 {
535 int32 d, tx, ty, oldy;
536
537 tx = 0;
538 ty = int32(r);
539 d = 3 - 2*ty;
540
541 oldy = ty;
542 while(true)
543 {
544 if( oldy != ty )
545 {
546 line( x - (tx-1), y + oldy, x + tx-1, y + oldy, color );
547 line( x - (tx-1), y - oldy, x + tx-1, y - oldy, color );
548 oldy = ty;
549 }
550 line( x - ty, y + tx, x + ty, y + tx, color );
551 line( x - ty, y - tx, x + ty, y - tx, color );
552
553 if( tx >= ty )
554 break;
555
556 if( d < 0 )
557 d += 4*tx + 6;
558 else
559 {
560 d += 4*(tx - ty) + 10;
561 ty--;
562 }
563 tx++;
564 }
565 }
566 }
567 }
568
569 //
570 // line - draws a line on the picture
571 //
line_antialiasing(float x1,float y1,float x2,float y2,const colorrgb & color,uint8 solid)572 void picture::line_antialiasing(float x1,float y1,float x2,float y2,const colorrgb &color,
573 uint8 solid) throw(error_obj)
574 {
575 float dx, dy, gradient, xend, yend, gap, tmp, fheight, fwidth;
576 int32 xpxl1, xpxl2, ypxl1, ypxl2;
577
578 if(y1 > y2) // makes sure that y1 is lower than y2
579 {
580 tmp = x1;
581 x1 = x2;
582 x2 = tmp;
583 tmp = y1;
584 y1 = y2;
585 y2 = tmp;
586 }
587 fheight = float(height);
588 fwidth = float(width);
589
590 // picture_line_calc_p1
591 if(y1 >= fheight)
592 return; // whole line is below the picture
593 if(y1 < 0.0f)
594 {
595 if(y2 < 0.0f)
596 return; // whole line is over the picture
597
598 x1 = x1 - ( y1 * (x2 - x1) ) / (y2 - y1);
599 y1 = 0.0f;
600 }
601 if(x1 < 0.0f)
602 {
603 if(x2 < 0.0f)
604 return; // whole line is to the left of the picture
605
606 y1 = y1 - ( x1 * (y2 - y1) ) / (x2 - x1);
607 x1 = 0.0f;
608 if(y1 >= fheight)
609 return; // the line is to the left and below of the picture
610 }
611 else if(x1 >= fwidth)
612 {
613 if(x2 >= fwidth)
614 return; // the line is to the right...
615
616 y1 = y1 + ( (fwidth - 1.0f - x1) * (y2 - y1) ) / (x2 - x1);
617 x1 = fwidth - 1.0f;
618 if(y1 >= fheight)
619 return; // the line is to the right and below...
620 }
621
622
623 // picture_line_calc_p2
624 if(y2 >= fheight)
625 {
626 x2 = x1 + ( (fheight - 1.0f - y1) * (x2 - x1) ) / (y2 - y1);
627 y2 = fheight - 1.0f;
628 }
629 if(x2 < 0.0f)
630 {
631 y2 = y1 - ( x1 * (y2 - y1) ) / (x2 - x1);
632 x2 = 0.0f;
633 }
634 else if(x2 >= fwidth)
635 {
636 y2 = y1 + ( (fwidth - 1.0f - x1) * (y2 - y1) ) / (x2 - x1);
637 x2 = fwidth - 1.0f;
638 }
639
640 dx = x2 - x1;
641 dy = y2 - y1;
642
643 if( fabs(dx) > fabs(dy) )
644 {
645 if( x2 < x1 )
646 {
647 tmp = x1;
648 x1 = x2;
649 x2 = tmp;
650 tmp = y1;
651 y1 = y2;
652 y2 = tmp;
653 }
654 gradient = dy / dx;
655
656 // handle first endpoint
657 xend = round(x1);
658 yend = y1 + gradient * (xend - x1);
659 gap = 1.0 - (x1+0.5 - trunc(x1 + 0.5));
660 xpxl1 = int32(xend); // this will be used in the main loop
661 ypxl1 = int32( trunc(yend) );
662 set_pixel( xpxl1, ypxl1, color, uint8( float(solid)* (1.0 - (yend - trunc(yend)) * gap) ) );
663 set_pixel( xpxl1, ypxl1 + 1, color, uint8( float(solid)* (yend - trunc(yend)) * gap ) );
664 tmp = yend + gradient; // first y-intersection for the main loop
665
666 // handle second endpoint
667 xend = round(x2);
668 yend = y2 + gradient * (xend - x2);
669 gap = 1.0 - (x2-0.5 - trunc(x2 - 0.5));
670 xpxl2 = int32(xend); // this will be used in the main loop
671 ypxl2 = int32( trunc(yend) );
672 set_pixel( xpxl2, ypxl2, color, uint8( float(solid)* (1.0 - (yend - trunc(yend)) *gap) ) );
673 set_pixel( xpxl2, ypxl2 + 1, color, uint8( float(solid)* (yend - trunc(yend)) *gap ) );
674
675 // main loop
676 for( xpxl1++; xpxl1< xpxl2; xpxl1++ )
677 {
678 set_pixel( xpxl1, int32(trunc(tmp)), color, uint8( float(solid)* (1.0 - (tmp - trunc(tmp))) ) );
679 set_pixel( xpxl1, int32(trunc(tmp)) + 1, color, uint8( float(solid)* (tmp - trunc(tmp)) ) );
680 tmp += gradient;
681 }
682 }
683 else
684 {
685 if( y2 < y1 )
686 {
687 tmp = x1;
688 x1 = x2;
689 x2 = tmp;
690 tmp = y1;
691 y1 = y2;
692 y2 = tmp;
693 }
694 gradient = dx / dy;
695
696 // handle first endpoint
697 yend = round(y1);
698 xend = x1 + gradient * (yend - y1);
699 gap = 1.0 - (y1+0.5 - trunc(y1 + 0.5));
700 ypxl1 = int32(yend); // this will be used in the main loop
701 xpxl1 = int32( trunc(xend) );
702 set_pixel( xpxl1, ypxl1, color, uint8( float(solid)* (1.0 - (xend - trunc(xend)) * gap) ) );
703 set_pixel( xpxl1 + 1, ypxl1, color, uint8( float(solid)* (xend - trunc(xend)) * gap ) );
704 tmp = xend + gradient; // first y-intersection for the main loop
705
706 // handle second endpoint
707 yend = round(y2);
708 xend = x2 + gradient * (yend - y2);
709 gap = 1.0 - (y2-0.5 - trunc(y2 - 0.5));
710 ypxl2 = int32(yend); // this will be used in the main loop
711 xpxl2 = int32( trunc(xend) );
712 set_pixel( xpxl2, ypxl2, color, uint8( float(solid)* (1.0 - (xend - trunc(xend)) *gap) ) );
713 set_pixel( xpxl2 + 1, ypxl2, color, uint8( float(solid)* (xend - trunc(xend)) *gap ) );
714
715 // main loop
716 for( ypxl1++; ypxl1< ypxl2; ypxl1++ )
717 {
718 set_pixel( int32(trunc(tmp)), ypxl1, color, uint8( float(solid)* (1.0 - (tmp - trunc(tmp))) ) );
719 set_pixel( int32(trunc(tmp)) + 1, ypxl1, color, uint8( float(solid)* (tmp - trunc(tmp)) ) );
720 tmp += gradient;
721 }
722 }
723 }
724
725
726
727 //
728 // line - draws a line on the picture
729 //
line(int32 x1,int32 y1,int32 x2,int32 y2,const colorrgb & color,uint8 solid)730 void picture::line(int32 x1,int32 y1,int32 x2,int32 y2,const colorrgb &color,
731 uint8 solid) throw(error_obj)
732 {
733 int32 dx,dy,incr1,incr2,d,x,y,xend,yend,yinc,xinc;
734
735 float fx1,fx2,fy1,fy2,fheight,fwidth; // the calculations are done using float's to avoid
736 // overflows on very large values
737
738 if(y1 == y2)
739 goto picture_line_draw_h_line;
740
741 if(y1 > y2) // makes sure that y1 is lower than y2
742 {
743 xend = x1;
744 x1 = x2;
745 x2 = xend;
746 xend = y1;
747 y1 = y2;
748 y2 = xend;
749 }
750 fx1 = float(x1);
751 fx2 = float(x2);
752 fy1 = float(y1);
753 fy2 = float(y2);
754 fheight = float(height);
755 fwidth = float(width);
756
757 // picture_line_calc_p1
758 if(y1 >= height)
759 return; // whole line is below the picture
760 if(y1 < 0)
761 {
762 if(y2 < 0)
763 return; // whole line is over the picture
764
765 fx1 = fx1 - ( fy1 * (fx2 - fx1) ) / (fy2 - fy1);
766 fy1 = 0.0f;
767 }
768 if(fx1 < 0.0f)
769 {
770 if(fx2 < 0.0f)
771 return; // whole line is to the left of the picture
772
773 fy1 = fy1 - ( fx1 * (fy2 - fy1) ) / (fx2 - fx1);
774 fx1 = 0.0f;
775 if(fy1 >= fheight)
776 return; // the line is to the left and below of the picture
777 }
778 else if(fx1 >= fwidth)
779 {
780 if(fx2 >= fwidth)
781 return; // the line is to the right...
782
783 fy1 = fy1 + ( (fwidth - 1.0f - fx1) * (fy2 - fy1) ) / (fx2 - fx1);
784 fx1 = fwidth - 1.0f;
785 if(fy1 >= fheight)
786 return; // the line is to the right and below...
787 }
788
789
790 // picture_line_calc_p2
791 if( trunc(fy1) != trunc(fy2) )
792 {
793 if( fy2 >= fheight )
794 {
795 fx2 = fx1 + ( (fheight - 1.0f - fy1) * (fx2 - fx1) ) / (fy2 - fy1);
796 fy2 = fheight - 1.0f;
797 }
798 if( fx2 < 0.0f )
799 {
800 fy2 = fy1 - ( fx1 * (fy2 - fy1) ) / (fx2 - fx1);
801 fx2 = 0.0f;
802 }
803 else if( fx2 >= fwidth )
804 {
805 fy2 = fy1 + ( (fwidth - 1.0f - fx1) * (fy2 - fy1) ) / (fx2 - fx1);
806 fx2 = fwidth - 1.0f;
807 }
808
809 x1 = int32(trunc(fx1));
810 x2 = int32(trunc(fx2));
811 y1 = int32(trunc(fy1));
812 y2 = int32(trunc(fy2));
813 }
814 else
815 {
816 x1 = int32(trunc(fx1));
817 x2 = int32(trunc(fx2));
818 y1 = int32(trunc(fy1));
819
820 picture_line_draw_h_line:
821 if( y1 >= height || y1 < 0 )
822 return; // the whole line is over/below the picture
823 if( x1 > x2 )
824 {
825 xend=x1;
826 x1=x2;
827 x2=xend;
828 }
829
830 if( x1 >= width || x2 < 0 )
831 return; // the whole line is to the right/left of the picture
832
833 if( x1 < 0 )
834 x1 = 0;
835 if( x2 >= width )
836 x2 = width-1;
837
838 if( x1 > x2 )
839 return; // the whole line is to the right/left of the picture
840
841 if( solid == 255 && type == PictureType_RGB )
842 {
843 xend = x1 + y1*width; // offset
844 yend = x2 - x1 + 1; // length
845
846 memset( &data[0].buffer[xend], color.red, yend);
847 memset( &data[1].buffer[xend], color.green, yend);
848 memset( &data[2].buffer[xend], color.blue, yend);
849
850 if( !isBackground )
851 memset( &solidness.buffer[xend], 255, yend );
852 }
853 else
854 {
855 for(;x1 <= x2;x1++)
856 set_pixel(x1,y1,color,solid);
857 }
858 return;
859 }
860
861 set_pixel(x1,y1,color,solid);
862 set_pixel(x2,y2,color,solid);
863
864 dx=abs(x2-x1);
865 dy=abs(y2-y1);
866 if(dx>=dy)
867 {
868 if(x1>x2)
869 {
870 x=x2;
871 y=y2;
872 xend=x1;
873 if(dy==0)
874 yinc=0;
875 else
876 {
877 if(y2>y1)
878 yinc=-1;
879 else
880 yinc=1;
881 }
882 }
883 else
884 {
885 x=x1;
886 y=y1;
887 xend=x2;
888 if(dy==0)
889 yinc=0;
890 else
891 {
892 if(y2>y1)
893 yinc=1;
894 else
895 yinc=-1;
896 }
897 }
898 incr1=dy+dy;
899 d=incr1-dx;
900 incr2=(dy-dx)<<1;
901 while(x<xend)
902 {
903 x++;
904 if(d<0)
905 d+=incr1;
906 else
907 {
908 y+=yinc;
909 d+=incr2;
910 }
911 set_pixel(x,y,color,solid);
912 }
913 }
914 else
915 {
916 if(y1>y2)
917 {
918 x=x2;
919 y=y2;
920 yend=y1;
921 if(dx==0)
922 xinc=0;
923 else
924 {
925 if(x2>x1)
926 xinc=-1;
927 else
928 xinc=1;
929 }
930 }
931 else
932 {
933 x=x1;
934 y=y1;
935 yend=y2;
936 if( dx == 0 )
937 xinc=0;
938 else
939 {
940 if(x2>x1)
941 xinc=1;
942 else
943 xinc=-1;
944 }
945 }
946 incr1=dx+dx;
947 d=incr1-dy;
948 incr2=(dx-dy)<<1;
949 while( y < yend )
950 {
951 y++;
952 if( d < 0 )
953 d+=incr1;
954 else
955 {
956 x+=xinc;
957 d+=incr2;
958 }
959 set_pixel(x,y,color,solid);
960 }
961 }
962 }
963
964
965 //
966 // setsolidness - sets the solidness of a specific pixel
967 //
set_solidness(int32 x,int32 y,uint8 newsolidness)968 void picture::set_solidness(int32 x,int32 y,uint8 newsolidness) throw(error_obj)
969 {
970 int32 offset = x + y*width;
971
972 if( !isBackground )
973 {
974 if((x < width) & (y < height) & (x >= 0) & (y >= 0))
975 solidness.buffer[offset] = newsolidness;
976 }
977 }
978
979
980 //
981 // setsolidnesscolor - sets the solidness to one specific color
982 //
set_solidness_color(const colorrgb & color,uint8 newsolidness)983 void picture::set_solidness_color(const colorrgb &color,uint8 newsolidness) throw(error_obj)
984 {
985 int32 x,y;
986
987 if( !isBackground )
988 {
989 for(y=0;y<height;y++)
990 {
991 for(x=0;x<width;x++)
992 {
993 if(color == get_pixel(x,y))
994 set_solidness(x,y,newsolidness);
995 }
996 }
997 }
998 }
999
1000
1001 //
1002 // setsolidnessall - sets the solidness of the whole picture
1003 //
set_solidness_all(uint8 newsolidness)1004 void picture::set_solidness_all(uint8 newsolidness) throw(error_obj)
1005 {
1006 if( !isBackground )
1007 memset(solidness.buffer,newsolidness, height * width);
1008 }
1009
1010
1011 //
1012 // clear - set all pixels to the specified color
1013 //
clear(const colorrgb & color)1014 void picture::clear(const colorrgb &color) throw(error_obj)
1015 {
1016 int32 size = height*width;
1017
1018 if( !isBackground )
1019 memset(solidness.buffer, 255, size );
1020 if( type == PictureType_RGB )
1021 {
1022 memset(data[0].buffer, color.red, size);
1023 memset(data[1].buffer, color.green, size);
1024 memset(data[2].buffer, color.blue, size);
1025 }
1026 else //if( type == PictureType_GRAYSCALE )
1027 {
1028 uint8 grey = uint8(
1029 float(color.red)*0.299f +
1030 float(color.green)*0.587f +
1031 float(color.blue)*0.114f
1032 );
1033 memset(data[0].buffer, grey, size);
1034 }
1035 }
1036
1037
1038 //
1039 // convto_rgb - converts the picture into a rgb-picture
1040 //
convto_rgb(void)1041 void picture::convto_rgb(void) throw(error_obj)
1042 {
1043 if( type == PictureType_GRAYSCALE )
1044 {
1045 set_size(width,height); // fixing space for the green and blue channel
1046 type = PictureType_RGB;
1047 memcpy(data[1].buffer,data[0].buffer,width*height);
1048 memcpy(data[2].buffer,data[0].buffer,width*height);
1049 }
1050 // else if( type == PictureType_RGB ) // this is already a rgb-picture
1051 // { }
1052 }
1053
1054 //
1055 // convto_grayscale - converts the picture into a grayscaled-picture
1056 //
convto_grayscale(void)1057 void picture::convto_grayscale(void) throw(error_obj)
1058 {
1059 //Y = 0.299*R + 0.587*G + 0.114*B
1060 int32 offset = width * height -1;
1061
1062 if( type == PictureType_RGB )
1063 {
1064 for(;offset >= 0;offset--)
1065 data[0].buffer[offset] = uint8(
1066 float(data[0].buffer[offset])*0.299f +
1067 float(data[1].buffer[offset])*0.587f +
1068 float(data[2].buffer[offset])*0.114f
1069 );
1070 type = PictureType_GRAYSCALE;
1071 }
1072 // else if( type == PictureType_GRAYSCALE ) // this is already a grayscale-picture
1073 // { }
1074 }
1075
1076
set_pixel_grayscale(int32 x,int32 y,uint8 grey,uint8 solid)1077 void picture::set_pixel_grayscale(int32 x,int32 y,uint8 grey,uint8 solid) throw(error_obj)
1078 {
1079 if((x < width) & (y < height) & (x > 0) & (y > 0) & (type == PictureType_GRAYSCALE))
1080 {
1081 if(solid == 255)
1082 data[0].buffer[x+y*width] = grey;
1083 else
1084 data[0].buffer[x+y*width] = uint8( (uint16(grey) * uint16(solid) + uint16(data[0].buffer[x+y*width]) * uint16(255 - solid)) / 255);
1085
1086 if( solid != 0 && !isBackground )
1087 solidness.buffer[x+y*width] = 255;
1088 }
1089 }
1090
1091 //
1092 // setpixel - sets a pixel to a specific color
1093 //
1094 // the color will be converted to grayscale/YCrCb/palette if the picture is in those modes
1095 //
1096 // if the point (x,y) is outside the picture nothing will happen
1097 //
1098 // the picture-pixel's solidness will be 255
1099 //
set_pixel(int32 x,int32 y,const colorrgb & color,uint8 solid)1100 void picture::set_pixel(int32 x,int32 y,const colorrgb &color,uint8 solid) throw(error_obj)
1101 {
1102 int32 offset = x + y*width;
1103
1104 if((x < width) & (y < height) & (x >= 0) & (y >= 0))
1105 {
1106 if( type == PictureType_RGB )
1107 {
1108 if(solid == 255)
1109 {
1110 data[0].buffer[offset] = color.red;
1111 data[1].buffer[offset] = color.green;
1112 data[2].buffer[offset] = color.blue;
1113 }
1114 else
1115 {
1116 data[0].buffer[offset] = uint8( (uint16(color.red) * uint16(solid) + uint16(data[0].buffer[offset]) * uint16(255 - solid)) / 255);
1117 data[1].buffer[offset] = uint8( (uint16(color.green) * uint16(solid) + uint16(data[1].buffer[offset]) * uint16(255 - solid)) / 255);
1118 data[2].buffer[offset] = uint8( (uint16(color.blue) * uint16(solid) + uint16(data[2].buffer[offset]) * uint16(255 - solid)) / 255);
1119 }
1120 if( solid != 0 && !isBackground)
1121 solidness.buffer[offset] = 255;
1122 }
1123 else //if( type == PictureType_GRAYSCALE )
1124 {
1125 uint8 gray;
1126
1127 if((color.red == color.green) & (color.red == color.green))
1128 gray = color.red;
1129 else
1130 {
1131 gray = uint8(
1132 float(color.red)*0.299f +
1133 float(color.green)*0.587f +
1134 float(color.blue)*0.114f
1135 );
1136 }
1137 if(solid == 255)
1138 data[0].buffer[offset] = gray;
1139 else
1140 data[0].buffer[offset] = uint8( (uint16(gray) * uint16(solid) + uint16(data[0].buffer[offset]) * uint16(255 - solid)) / 255);
1141 if( solid != 0 && !isBackground )
1142 solidness.buffer[offset] = 255;
1143
1144 }
1145 }
1146 }
1147
1148
box(int32 x,int32 y,int32 width,int32 height,const colorrgb & color,uint8 solid)1149 void picture::box(int32 x,int32 y,int32 width,int32 height,const colorrgb &color,
1150 uint8 solid) throw(error_obj)
1151 {
1152 if( width <= 0 || height <= 0 )
1153 return;
1154 width--;
1155 height--;
1156 line(x,y,x+width,y,color,solid);
1157 line(x,y+height,x+width,y+height,color,solid);
1158 line(x,y,x,y+height,color,solid);
1159 line(x+width,y,x+width,y+height,color,solid);
1160 }
1161
filled_box(int32 x,int32 y,int32 width,int32 height,const colorrgb & color,uint8 solid)1162 void picture::filled_box(int32 x,int32 y,int32 width,int32 height,const colorrgb &color,
1163 uint8 solid) throw(error_obj)
1164 {
1165 int32 ystop,xstop;
1166
1167 if( width <= 0 || height <= 0 )
1168 return;
1169
1170 xstop = x+width-1;
1171 ystop = y+height-1;
1172
1173 for(;y<=ystop;y++)
1174 line(x,y,xstop,y,color,solid);
1175 }
1176
1177
1178
1179 //
1180 // draw - draws this picture on *dest
1181 //
draw(int32 x,int32 y) const1182 void picture::draw(int32 x,int32 y) const throw(error_obj)
1183 {
1184 int32 xt,yt,xstart,ystart,xstop,ystop;
1185 colorrgb color;
1186 uint8 solid;
1187
1188 if(dest == 0)
1189 return;
1190
1191 if(x < 0)
1192 xstart = -x;
1193 else
1194 xstart = 0;
1195
1196 if(y < 0)
1197 ystart = -y;
1198 else
1199 ystart = 0;
1200
1201 if(width > (dest->width - x))
1202 xstop = dest->width - x;
1203 else
1204 xstop = width;
1205
1206 if(height > (dest->height - y))
1207 ystop = dest->height - y;
1208 else
1209 ystop = height;
1210
1211 if( type == PictureType_RGB && dest->type == PictureType_RGB )
1212 {
1213 int32 offset = xstart + ystart*width;
1214 int32 lineskip = xstart + width - xstop;
1215
1216 for(yt=ystart;yt<ystop;yt++,offset += lineskip)
1217 {
1218 for(xt=xstart;xt<xstop;xt++,offset++)
1219 {
1220 dest->set_pixel(xt+x,yt+y,(colorrgb) {data[0].buffer[offset],
1221 data[1].buffer[offset],
1222 data[2].buffer[offset]},
1223 solidness.buffer[offset]);
1224 }
1225 }
1226 }
1227 else
1228 {
1229 for(yt=ystart;yt<ystop;yt++)
1230 {
1231 for(xt=xstart;xt<xstop;xt++)
1232 {
1233 color = get_pixel(xt,yt);
1234 solid = get_solidness(xt,yt);
1235 dest->set_pixel(xt+x,yt+y,color,solid);
1236 }
1237 }
1238 }
1239 }
1240
1241
1242 //
1243 // draw_shadow - draws a shadow of the picture in the specified color
1244 //
draw_shadow(int32 x,int32 y,const colorrgb & color) const1245 void picture::draw_shadow(int32 x,int32 y,const colorrgb &color) const throw(error_obj)
1246 {
1247 int32 xt,yt,xstart,ystart,xstop,ystop;
1248
1249 if(dest == 0)
1250 return;
1251
1252 if(x < 0)
1253 xstart = -x;
1254 else
1255 xstart = 0;
1256
1257 if(y < 0)
1258 ystart = -y;
1259 else
1260 ystart = 0;
1261
1262 if(width > (dest->width - x))
1263 xstop = dest->width - x;
1264 else
1265 xstop = width;
1266
1267 if(height > (dest->height - y))
1268 ystop = dest->height - y;
1269 else
1270 ystop = height;
1271
1272 int32 offset = xstart + ystart*width;
1273 int32 lineskip = xstart + width - xstop;
1274
1275 for(yt=ystart;yt<ystop;yt++, offset += lineskip)
1276 {
1277 for(xt=xstart;xt<xstop;xt++, offset++)
1278 dest->set_pixel(xt+x,yt+y,color,solidness.buffer[offset]);
1279 }
1280 }
1281
1282 //
1283 // get_pixel - returns a colorrgb-struct containing the rgb-values for the pixel
1284 // if picture isn't a RGB-picture the rgb-value will be calculated
1285 //
get_pixel(int32 x,int32 y) const1286 colorrgb picture::get_pixel(int32 x,int32 y) const
1287 {
1288 if( x < 0 || y < 0 || x >= width || y >= height )
1289 return color::BLACK;
1290
1291 int32 offset = x+y*width;
1292 if( type == PictureType_RGB )
1293 return (colorrgb) { data[0].buffer[offset], data[1].buffer[offset], data[2].buffer[offset] };
1294 else //if( type == PictureType_GRAYSCALE )
1295 return (colorrgb) { data[0].buffer[offset], data[0].buffer[offset], data[0].buffer[offset] };
1296 }
1297
1298
1299
get_solidness(int32 x,int32 y) const1300 uint8 picture::get_solidness(int32 x,int32 y) const
1301 {
1302 if( x < 0 || y < 0 || x >= width || y >= height )
1303 return 0;
1304
1305 if( isBackground )
1306 return 255;
1307 else
1308 return solidness.buffer[x+y*width];
1309 }
1310
1311
save_ppm(const char * filename,bool save_as_ascii) const1312 void picture::save_ppm(const char *filename, bool save_as_ascii) const throw(error_obj)
1313 {
1314 FILE *fp;
1315 colorrgb farg;
1316 int32 x,y;
1317
1318 fp = fopen(filename,"wb");
1319 if(fp == NULL)
1320 {
1321 char tmp_err[ERROR_OBJ_MSG_LEN];
1322 snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("Couldn't open/write to file (%s)"), filename );
1323 THROW_ERROR( ErrorType_File_IO, tmp_err );
1324 }
1325
1326 if(save_as_ascii)
1327 fprintf(fp,"P3\n");
1328 else
1329 fprintf(fp,"P6\n");
1330
1331 fprintf(fp,"%ld\n%ld\n255%c",width,height,10);
1332
1333 for(y=0;y<height;y++)
1334 {
1335 for(x=0;x<width;x++)
1336 {
1337 farg = get_pixel(x,y);
1338
1339 if(save_as_ascii)
1340 fprintf(fp,"%lu %lu %lu\n",uint32(farg.red),uint32(farg.green),uint32(farg.blue));
1341 else
1342 {
1343 fputc(farg.red,fp);
1344 fputc(farg.green,fp);
1345 fputc(farg.blue,fp);
1346 }
1347 }
1348 }
1349
1350 if(fclose(fp) != 0)
1351 {
1352 char tmp_err[ERROR_OBJ_MSG_LEN];
1353 snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("Couldn't close file (%s)"), filename );
1354 THROW_ERROR( ErrorType_File_IO, tmp_err );
1355 }
1356 }
1357
1358
save_pcx(const char * filename) const1359 void picture::save_pcx(const char *filename) const throw(error_obj)
1360 {
1361 FILE *fp;
1362 uint8 header[128],tmp,lastbyte;
1363 int32 x,y,i,antal;
1364 colorrgb farg;
1365
1366 fp = fopen(filename,"wb");
1367 if(fp == NULL)
1368 {
1369 char tmp_err[ERROR_OBJ_MSG_LEN];
1370 snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("Couldn't open/write to file (%s)"), filename );
1371 THROW_ERROR( ErrorType_File_IO, tmp_err );
1372 }
1373
1374 memset(header,0,128);
1375
1376 header[0] = 10; //ZSoft .PCX
1377 header[1] = 5; //version 3.0
1378 header[2] = 1; //RLE encoding
1379 header[3] = 8; //bit depth
1380 header[65] = 3; //number of planes
1381
1382 header[4] = 0; //minX
1383 header[5] = 0;
1384
1385 header[6] = 0; //minY
1386 header[7] = 0;
1387
1388 header[8] = uint8((width - 1) % 256); //maxX
1389 header[9] = uint8((width - 1) / 256);
1390
1391 header[10] = uint8((height - 1) % 256);//maxY
1392 header[11] = uint8((height - 1) / 256);
1393
1394 header[66] = uint8(width % 256); //bytes per line per plane
1395 header[67] = uint8(width / 256);
1396
1397 for(i=0;i<128;i++)
1398 fputc(header[i],fp);
1399
1400 // saves picture
1401 for(y=0;y<height;y++)
1402 {
1403 for(i=0;i<3;i++)
1404 {
1405 antal = 1;
1406 farg = get_pixel(0,y);
1407 if(i == 0)
1408 lastbyte = farg.red;
1409 else if(i == 1)
1410 lastbyte = farg.green;
1411 else
1412 lastbyte = farg.blue;
1413
1414
1415 for(x=1;x<width;x++)
1416 {
1417 farg = get_pixel(x,y);
1418 if(i == 0)
1419 tmp = farg.red;
1420 else if(i == 1)
1421 tmp = farg.green;
1422 else
1423 tmp = farg.blue;
1424
1425 if(tmp == lastbyte)
1426 antal++;
1427 else
1428 {
1429 saveit_pcx_picture:
1430 if((antal != 1) | (lastbyte >= uint8(0xC0)))
1431 {
1432 tmp = uint8(antal);
1433 if(antal > int32(0x3F))
1434 tmp = uint8(0x3F);
1435 antal -= int32(tmp);
1436
1437 tmp += uint8(0xC0);
1438 fputc(tmp,fp);
1439 fputc(lastbyte,fp);
1440 if(antal > 0)
1441 goto saveit_pcx_picture;
1442 }
1443 else
1444 fputc(lastbyte,fp);
1445
1446 antal = 1;
1447 farg = get_pixel(x,y);
1448 if(i == 0)
1449 lastbyte = farg.red;
1450 else if(i == 1)
1451 lastbyte = farg.green;
1452 else
1453 lastbyte = farg.blue;
1454 }
1455 if(x == (width - 1))
1456 {
1457 x = width;
1458 goto saveit_pcx_picture;
1459 }
1460 }
1461 }
1462 }
1463 if(fclose(fp) != 0)
1464 {
1465 char tmp_err[ERROR_OBJ_MSG_LEN];
1466 snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("Couldn't close file (%s)"), filename );
1467 THROW_ERROR( ErrorType_File_IO, tmp_err );
1468 }
1469 }
1470
1471
mirror(void)1472 void picture::mirror(void) throw(error_obj)
1473 {
1474 colorrgb color;
1475 uint8 solid;
1476 int32 x,y;
1477
1478 for(y=0;y<height;y++)
1479 {
1480 for(x=0;x<(width/2);x++)
1481 {
1482 color = get_pixel(x,y);
1483 solid = get_solidness(x,y);
1484 set_pixel(x,y,get_pixel(width-1-x,y));
1485 set_solidness(x,y,get_solidness(width-1-x,y));
1486 set_pixel(width-1-x,y,color);
1487 set_solidness(width-1-x,y,solid);
1488 }
1489 }
1490 }
upside_down(void)1491 void picture::upside_down(void) throw(error_obj)
1492 {
1493 colorrgb color;
1494 uint8 solid;
1495 int32 x,y;
1496
1497 for(y=0;y<(height/2);y++)
1498 {
1499 for(x=0;x<width;x++)
1500 {
1501 color = get_pixel(x,y);
1502 solid = get_solidness(x,y);
1503 set_pixel(x,y,get_pixel(x,height-1-y));
1504 set_solidness(x,y,get_solidness(x,height-1-y));
1505 set_pixel(x,height-1-y,color);
1506 set_solidness(x,height-1-y,solid);
1507 }
1508 }
1509 }
rotate90(void)1510 void picture::rotate90(void) throw(error_obj)
1511 {
1512 picture tmp;
1513 int32 x,y;
1514
1515 tmp = *this;
1516
1517 height = tmp.width;
1518 width = tmp.height;
1519
1520 for(y=0;y<height;y++)
1521 {
1522 for(x=0;x<width;x++)
1523 {
1524 set_pixel(x,y,tmp.get_pixel(height-1-y,x));
1525 set_solidness(x,y,tmp.get_solidness(height-1-y,x));
1526 }
1527 }
1528 }
rotate180(void)1529 void picture::rotate180(void) throw(error_obj)
1530 {
1531 mirror();
1532 upside_down();
1533 }
rotate270(void)1534 void picture::rotate270(void) throw(error_obj)
1535 {
1536 rotate90();
1537 rotate180();
1538 }
1539
1540 //
1541 // load_pcx - loads a PCX-picture
1542 // note that the PCX-file must be a 24bit RLE v3.0
1543 //
load_pcx(const char * filename)1544 void picture::load_pcx(const char *filename) throw(error_obj)
1545 {
1546 uint8 header[128],byte,color;
1547 FILE *fp;
1548 int32 i,tmp,x,y;
1549
1550 erase();
1551 type = PictureType_RGB;
1552
1553 fp = fopen(filename,"rb"); // open pcx-file
1554 if(fp == NULL)
1555 {
1556 char tmp_err[ERROR_OBJ_MSG_LEN];
1557 snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("Couldn't open/read from file (%s)"), filename );
1558 THROW_ERROR( ErrorType_File_IO, tmp_err );
1559 }
1560
1561 for(i=0;i<128;i++)
1562 {
1563 header[i] = fgetc(fp); // load pcx-header
1564 if(feof(fp) != 0)
1565 {
1566 fclose(fp);
1567 char tmp_err[ERROR_OBJ_MSG_LEN];
1568 snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("Couldn't open/read from file (%s)"), filename );
1569 THROW_ERROR( ErrorType_File_IO, tmp_err );
1570 }
1571 }
1572
1573 if( header[0] != 10 || // 10 = ZSoft .PCX
1574 header[1] != 5 || // version should be 5 = v3.0
1575 header[2] != 1 || // encoding 1 = .PCX Run Length Encoding (RLE)
1576 header[65] != 3 || // number of planes should be 3 (r,g,b)
1577 header[3] != 8 ) // bits per pixel per plane should be 8 (8 bit)
1578 {
1579 fclose(fp);
1580
1581 char tmp_err[ERROR_OBJ_MSG_LEN];
1582 snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("%s is not a valid PCX file"), filename );
1583 THROW_ERROR( ErrorType_File_IO, tmp_err );
1584 }
1585
1586 tmp = int32(header[4]) + (int32(header[5])<<8); //getting the width
1587 x = int32(header[8]) + (int32(header[9])<<8);
1588 x -= (tmp - 1);
1589
1590
1591 tmp = int32(header[6]) + (int32(header[7])<<8); //getting the height
1592 y = int32(header[10]) + (int32(header[11])<<8);
1593 y -= (tmp - 1);
1594
1595
1596 try{ set_size(x,y); }
1597 catch(error_obj error)
1598 {
1599 fclose(fp);
1600 throw error;
1601 }
1602 if( !isBackground )
1603 memset(solidness.buffer,255,width*height);
1604
1605 tmp = 0;
1606 for(y=0;y<height;y++)
1607 {
1608 for(i=0;i<3;i++)
1609 {
1610 x = 0;
1611 do{
1612 byte = fgetc(fp);
1613 if(feof(fp) != 0)
1614 {
1615 fclose(fp);
1616
1617 char tmp_err[ERROR_OBJ_MSG_LEN];
1618 snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("Couldn't open/read from file (%s)"), filename );
1619 THROW_ERROR( ErrorType_File_IO, tmp_err );
1620 }
1621 if(byte >= uint8(0xc0))
1622 {
1623 color = fgetc(fp);
1624 if(feof(fp) != 0)
1625 {
1626 fclose(fp);
1627
1628 char tmp_err[ERROR_OBJ_MSG_LEN];
1629 snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("Couldn't open/read from file (%s)"), filename );
1630 THROW_ERROR( ErrorType_File_IO, tmp_err );
1631 }
1632
1633 for(byte -= uint8(0xc0);byte!=0;byte--)
1634 {
1635 if(x == width)
1636 {
1637 tmp = 1;
1638 break;
1639 }
1640
1641 data[i].buffer[x + y*width] = color;
1642
1643 x++;
1644 }
1645 }
1646 else
1647 {
1648 data[i].buffer[x + y*width] = byte;
1649
1650 x++;
1651 }
1652 }while(x < width);
1653 }
1654 }
1655
1656 if(fclose(fp) != 0)
1657 {
1658 char tmp_err[ERROR_OBJ_MSG_LEN];
1659 snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("Couldn't close file (%s)"), filename );
1660 THROW_ERROR( ErrorType_File_IO, tmp_err );
1661 }
1662 }
1663
1664
operator =(const picture & source)1665 void picture::operator=(const picture & source) throw(error_obj)
1666 {
1667 int32 size = source.width*source.height;
1668
1669 type = source.type;
1670 set_size(source.width,source.height);
1671
1672 if( !isBackground )
1673 memcpy(solidness.buffer,source.solidness.buffer,size);
1674 memcpy(data[0].buffer,source.data[0].buffer,size);
1675
1676 if( type == PictureType_RGB )
1677 {
1678 memcpy(data[1].buffer,source.data[1].buffer,size);
1679 memcpy(data[2].buffer,source.data[2].buffer,size);
1680 }
1681 }
1682
operator ==(const picture & pic) const1683 bool picture::operator==(const picture &pic) const
1684 {
1685 if( width != pic.width || height != pic.height )
1686 return false;
1687 if( type != pic.type || isBackground != pic.isBackground )
1688 return false;
1689
1690 int32 tot = width*height;
1691 int32 i;
1692
1693 if( !isBackground )
1694 {
1695 for( i=0; i<tot; i++ )
1696 {
1697 if( solidness.buffer[i] != pic.solidness.buffer[i] )
1698 return false;
1699 }
1700 }
1701 for( i=0; i<tot; i++ )
1702 {
1703 if( data[0].buffer[i] != pic.data[0].buffer[i] )
1704 return false;
1705 }
1706
1707 if( type == PictureType_RGB )
1708 {
1709 for( i=0; i<tot; i++ )
1710 {
1711 if( data[1].buffer[i] != pic.data[1].buffer[i] )
1712 return false;
1713 if( data[2].buffer[i] != pic.data[2].buffer[i] )
1714 return false;
1715 }
1716 }
1717 return true;
1718 }
1719
1720 //
1721 // capture - extracts a part of a picture
1722 //
capture(const picture & source,int32 x,int32 y,int32 width,int32 height)1723 void picture::capture(const picture &source,int32 x,int32 y,int32 width,int32 height)
1724 throw(error_obj)
1725 {
1726 int32 xi,yi,tx,x2,y2;
1727
1728 if( width <= 0 || height <= 0 )
1729 return;
1730
1731 x2 = x+width-1;
1732 y2 = y+height-1;
1733
1734 type = PictureType_RGB;
1735 set_isBackground( source.isBackground );
1736 set_size( width, height );
1737
1738 tx = x;
1739 for(yi=0;y<=y2;y++,yi++)
1740 {
1741 for(x=tx,xi=0;x<=x2;x++,xi++)
1742 {
1743 set_pixel(xi,yi,source.get_pixel(x,y));
1744 if( !isBackground )
1745 set_solidness(xi,yi,source.get_solidness(x,y));
1746 }
1747 }
1748 }
1749
1750
draw_lines(const float * vertex,const uint32 * lines,uint32 nroflines,const colorrgb & color,bool antialiased,uint8 solid)1751 void picture::draw_lines( const float *vertex, const uint32 *lines, uint32 nroflines,
1752 const colorrgb &color, bool antialiased, uint8 solid ) throw(error_obj)
1753 {
1754 if( nroflines == 0 )
1755 return;
1756
1757 if( antialiased )
1758 {
1759 float x, y, min_dist, xmax, xmin, ymax, ymin;
1760 float x1, x2, y1, y2, tmp;
1761 uint32 i, i2;
1762
1763 nroflines *= 2;
1764
1765 for( i=0; i<nroflines; i+=2 )
1766 {
1767 xmin = vertex[lines[i]];
1768 ymin = vertex[lines[i]+1];
1769 x2 = vertex[lines[i+1]];
1770 y2 = vertex[lines[i+1]+1];
1771
1772 if( xmin < -1.0f && x2 < -1.0f ) // line to the left of picture
1773 continue;
1774 if( ymin < -1.0f && y2 < -1.0f ) // line above picture
1775 continue;
1776 if( xmin > float(width+1) && x2 > float(width+1) ) // line to the right of picture
1777 continue;
1778 if( ymin > float(height+1) && y2 > float(height+1) ) // line below picture
1779 continue;
1780
1781 xmax = xmin;
1782 ymax = ymin;
1783 xmin = (xmin<x2) ? xmin : x2;
1784 ymin = (ymin<y2) ? ymin : y2;
1785 xmax = (xmax>x2) ? xmax : x2;
1786 ymax = (ymax>y2) ? ymax : y2;
1787
1788 xmin = trunc(xmin);
1789 ymin = trunc(ymin);
1790 xmax = trunc(xmax+1.0f);
1791 ymax = trunc(ymax+1.0f);
1792
1793 xmin = (xmin<0.0f) ? 0.0f : xmin;
1794 ymin = (ymin<0.0f) ? 0.0f : ymin;
1795 xmax = (xmax>float(width-1)) ? float(width-1) : xmax;
1796 ymax = (ymax>float(height-1)) ? float(height-1) : ymax;
1797
1798 for( y=ymin; y<=ymax; y++ )
1799 {
1800 for( x=xmin; x<=xmax; x++ )
1801 {
1802 for( i2=i-2; i2<nroflines; i2-=2 )
1803 {
1804 x1 = vertex[lines[i2]];
1805 y1 = vertex[lines[i2]+1];
1806 x2 = vertex[lines[i2+1]];
1807 y2 = vertex[lines[i2+1]+1];
1808
1809 if( x1 > x2 )
1810 {
1811 tmp = x1;
1812 x1 = x2;
1813 x2 = tmp;
1814 }
1815 if( y1 > y2 )
1816 {
1817 tmp = y1;
1818 y1 = y2;
1819 y2 = tmp;
1820 }
1821 x1 = trunc(x1);
1822 y1 = trunc(y1);
1823 x2 = trunc(x2+1.0f);
1824 y2 = trunc(y2+1.0f);
1825 if( x >= x1 && x <= x2 && y >= y1 && y <= y2 )
1826 break;
1827 }
1828 if( i2 < nroflines )
1829 continue;
1830
1831 for( i2=i, min_dist=1.0f; i2<nroflines; i2+=2 )
1832 {
1833 x1 = vertex[lines[i2]];
1834 y1 = vertex[lines[i2]+1];
1835 x2 = vertex[lines[i2+1]];
1836 y2 = vertex[lines[i2+1]+1];
1837
1838 if( x < (( (x1<x2)?x1:x2 )-1.0f) )
1839 continue;
1840 if( x > (( (x1>x2)?x1:x2 )+1.0f) )
1841 continue;
1842 if( y < (( (y1<y2)?y1:y2)-1.0f) )
1843 continue;
1844 if( y > (( (y1>y2)?y1:y2 )+1.0f) )
1845 continue;
1846
1847 if( x1 == x2 )
1848 {
1849 if( y1 == y2 ) // A point
1850 tmp = -1.0f;
1851 else // A vertical line
1852 tmp = (y-y1) / (y2-y1);
1853 }
1854 else
1855 { // An ordinary line
1856 tmp = (y1-y2)/(x2-x1);
1857 tmp = ( x1 - x - tmp*(y1-y) ) / ( tmp*(y2-y1) - x2 + x1 );
1858 }
1859 if( tmp < 0.0f )
1860 { // Closest point lies below the line
1861 tmp = (x-x1)*(x-x1) + (y-y1)*(y-y1);
1862 if( tmp < min_dist )
1863 min_dist = tmp;
1864 }
1865 else if( tmp > 1.0f )
1866 { // Closest point lies above the line
1867 tmp = (x-x2)*(x-x2) + (y-y2)*(y-y2);
1868 if( tmp < min_dist )
1869 min_dist = tmp;
1870 }
1871 else
1872 { // Closest point lies on the line
1873 x1 += tmp*(x2-x1); // Calculating the point which lies closest to (x,y)
1874 y1 += tmp*(y2-y1);
1875
1876 tmp = (x-x1)*(x-x1) + (y-y1)*(y-y1);
1877 if( tmp < min_dist )
1878 min_dist = tmp;
1879 }
1880 }
1881 if( min_dist < 1.0f )
1882 set_pixel( int32(x), int32(y), color,
1883 uint8( float(solid)* (1.0f-sqrt(min_dist)) ) );
1884 }
1885 }
1886 }
1887 }
1888 else
1889 {
1890 nroflines *= 2;
1891 for( uint32 i=0; i<nroflines; i+=2 )
1892 line( int32(vertex[lines[i]]), int32(vertex[lines[i]+1]),
1893 int32(vertex[lines[i+1]]), int32(vertex[lines[i+1]+1]), color, solid );
1894 }
1895 }
1896
1897 } // end of namespace picture_h
1898