source: abuse/branches/pd/macabuse/imlib/image.c @ 636

Last change on this file since 636 was 49, checked in by Sam Hocevar, 15 years ago
  • Imported original public domain release, for future reference.
  • Property svn:keywords set to Id
File size: 30.8 KB
Line 
1#include "emm.hpp"
2#include "image.hpp"
3#include "macs.hpp"
4#include "system.h"
5#include "dos.h"
6#include "system.h"
7#include "exitproc.hpp"
8#include "dprint.hpp"
9
10#include <math.h>
11#ifdef __DOS
12  #include <dir.h>
13#else
14  #include <unistd.h>
15#endif
16#include <stdlib.h>
17
18extern unsigned char current_background;
19char *imerr_messages[]={"No error",
20                        "Error occured while reading",
21                        "Incorrect file type",
22                        "File is corrupted",
23                        "File not found",
24                        "Memory allocation trouble",
25                        "Operation/file type not supported",
26                        "Error occured while writing, (disk full?)"};
27                       
28                         
29short imerror=0;
30short swpfile_num=0;
31
32short current_error()
33{ return imerror; }
34
35void clear_errors()
36{
37  if (imerror)
38  { dprintf("Program stopped, error : ");
39    if (imerror<=imMAX_ERROR)
40      dprintf("%s\n",imerr_messages[imerror]);
41    else
42      dprintf("Unsonsponsered error code, you got trouble\n");
43#ifdef __DOS_ONLY
44    sound(300);
45    delay(100);
46    nosound();
47#else
48    dprintf("%c%c\n",7,8);
49#endif
50    exit(1);
51  }
52}
53
54void set_error(short x)
55{ imerror=x; }
56
57short last_error()
58{
59  short ec;
60  ec=imerror;
61  imerror=0;
62  return ec;
63}
64
65linked_list image_list;
66
67
68image_descriptor::image_descriptor(short length, short height,
69                                   int keep_dirties, int static_memory)
70
71{ clipx1=0; clipy1=0;
72  l=length; h=height;
73  clipx2=l-1; clipy2=h-1;
74  keep_dirt=keep_dirties;
75  static_mem=static_memory; 
76}
77
78void image::change_size(short new_width, short new_height, unsigned char *page)
79{
80  delete_page();
81  w=new_width;
82  h=new_height;
83  make_page(new_width,new_height,page);
84}
85
86image::~image()
87{
88  image_list.unlink((linked_node *)this);
89  delete_page();
90  if (special)
91    delete special;
92
93}
94
95
96void make_block(size_t size)
97{
98  void *dat=jmalloc(size,"make_block : tmp");
99  CONDITION(dat,"Memory error : could not make block\n");
100  if (dat) jfree((char *)dat);
101}
102
103unsigned char image::pixel(short x, short y)
104{
105  CONDITION(x>=0 && x<width() && y>=0 && y<height(),
106     "image::pixel Bad pixel xy");
107  return (*(scan_line(y)+x));
108}
109
110void image::putpixel(short x, short y, char color)
111{
112  CONDITION(x>=0 && x<width() && y>=0 && y<height(),
113     "image::putpixel Bad pixel xy");
114  if (special)
115  { if (x>=special->x1_clip() && x<=special->x2_clip() &&
116        y>=special->y1_clip() && y<=special->y2_clip())
117      (*(scan_line(y)+x))=color;
118  } else (*(scan_line(y)+x))=color;
119}
120
121
122image::image(short width, short height, unsigned char *page_buffer, short create_descriptor)
123{
124  w=width;
125  h=height; 
126  if (create_descriptor || page_buffer)
127  {
128    if (create_descriptor==2)
129      special=new image_descriptor(width,height,1,(page_buffer!=NULL));
130    else special=new image_descriptor(width,height,0,(page_buffer!=NULL));
131  } else special=NULL;
132  make_page(width,height,page_buffer);
133  //  image_list.add_end((linked_node *) this);
134}
135
136image::image(spec_entry *e, bFILE *fp)
137{
138  short i;
139  fp->seek(e->offset,0);
140  w=fp->read_short();
141  h=fp->read_short();
142  special=NULL;
143  make_page(w,h,NULL);
144  for (i=0;i<h;i++)
145    fp->read(scan_line(i),w);
146  //  image_list.add_end((linked_node *) this);
147}
148
149image::image(bFILE *fp)
150{
151  short i;
152  w=fp->read_short();
153  h=fp->read_short();
154  special=NULL;
155  make_page(w,h,NULL);
156  for (i=0;i<h;i++)
157    fp->read(scan_line(i),w);
158  //  image_list.add_end((linked_node *) this);
159}
160
161void image_uninit()
162{
163/*  image *im;
164  while (image_list.first())
165  {
166    im=(image *)image_list.first();
167    image_list.unlink((linked_node *)im);
168    delete im;
169  } */
170}
171
172
173void image_cleanup(int ret, void *arg)
174{ image_uninit(); }
175
176void image_init()
177{
178  unsigned char bt[2];
179  unsigned short wrd,*up;
180  bt[0]=1;
181  bt[1]=0;
182  up=(unsigned short *)bt;
183  wrd=int_to_intel(*up);
184  if (wrd!=0x01)
185  { dprintf("Compiled under wrong ENDING-nes, edit system.h and try again\n");
186    dprintf("1 (intel) = %d\n",(int)wrd);
187    exit(1);
188  }
189  imerror=0;
190  exit_proc(image_cleanup,image_uninit); // important that possible shared memory is deallocated!
191}
192
193
194long image::total_pixels(unsigned char background)
195{
196  short i,j;
197  long co;
198  unsigned char *c;
199  for (co=0,i=height()-1;i>=0;i--)
200  { c=scan_line(i);
201    for (j=width()-1;j>=0;j--,c++)
202      if (*c!=background) co++;
203  }
204  return co;
205}
206
207void image::clear(short color)
208{
209  short i;
210  if (color==-1) color=current_background;
211  if (special)
212  { if (special->x1_clip()<=special->x2_clip())
213      for (i=special->y2_clip();i>=special->y1_clip();i--)
214        memset(scan_line(i)+special->x1_clip(),color,
215               special->x2_clip()-special->x1_clip()+1);
216  }
217  else
218    for (i=height()-1;i>=0;i--)
219      memset(scan_line(i),color,width());
220  add_dirty(0,0,width()-1,height()-1);
221}
222
223
224image *image::copy()
225{
226  image *im;
227  unsigned char *c,*dat;
228  int i;
229  dat=(unsigned char *)jmalloc(width(),"image copy");
230  im=new image(width(),height());
231  for (i=height()-1;i>=0;i--)
232  { c=scan_line(i);
233    memcpy(dat,c,width());
234    c=im->scan_line(i);
235    memcpy(c,dat,width());
236  }
237  jfree((char *)dat);
238  return im;
239}
240
241
242
243void image::line(short x1, short y1,short x2, short y2, unsigned char color)
244{
245  short i,xc,yc,er,n,m,xi,yi,xcxi,ycyi,xcyi;
246  unsigned dcy,dcx;
247  // check to make sure that both endpoint are on the screen
248
249  short cx1,cy1,cx2,cy2;
250
251  // check to see if the line is completly clipped off
252  get_clip(cx1,cy1,cx2,cy2); 
253  if ((x1<cx1 && x2<cx1) || (x1>cx2 && x2>cx2) ||
254      (y1<cy1 && y2<cy1) || (y1>cy2 && y2>cy2))
255    return ;
256 
257  if (x1>x2)        // make sure that x1 is to the left
258  {   
259    i=x1; x1=x2; x2=i;  // if not swap points
260    i=y1; y1=y2; y2=i;
261  } 
262
263  // clip the left side
264  if (x1<cx1)
265  { 
266    int my=(y2-y1);       
267    int mx=(x2-x1),b;
268    if (!mx) return ;
269    if (my)
270    {
271      b=y1-(y2-y1)*x1/mx;     
272      y1=my*cx1/mx+b;
273      x1=cx1;     
274    }
275    else x1=cx1;
276  }
277
278  // clip the right side
279  if (x2>cx2)
280  { 
281    int my=(y2-y1);       
282    int mx=(x2-x1),b;
283    if (!mx) return ;
284    if (my)
285    {
286      b=y1-(y2-y1)*x1/mx;     
287      y2=my*cx2/mx+b;
288      x2=cx2;     
289    }
290    else x2=cx2;
291  }
292
293  if (y1>y2)        // make sure that y1 is on top
294  {   
295    i=x1; x1=x2; x2=i;  // if not swap points
296    i=y1; y1=y2; y2=i;
297  } 
298
299  // clip the bottom
300  if (y2>cy2)
301  { 
302    int mx=(x2-x1);       
303    int my=(y2-y1),b;
304    if (!my)
305      return ;
306    if (mx)
307    {
308      b=y1-(y2-y1)*x1/mx;     
309      x2=(cy2-b)*mx/my;
310      y2=cy2;
311    }
312    else y2=cy2;
313  }
314
315  // clip the top
316  if (y1<cy1)
317  { 
318    int mx=(x2-x1);       
319    int my=(y2-y1),b;
320    if (!my) return ;
321    if (mx)
322    {
323      b=y1-(y2-y1)*x1/mx;     
324      x1=(cy1-b)*mx/my;
325      y1=cy1;
326    }
327    else y1=cy1;
328  }
329
330
331  // see if it got cliped into the box, out out
332  if (x1<cx1 || x2<cx1 || x1>cx2 || x2>cx2 || y1<cy1 || y2 <cy1 || y1>cy2 || y2>cy2)
333    return ;
334 
335   
336
337  if (x1>x2)
338  { xc=x2; xi=x1; }
339  else { xi=x2; xc=x1; }
340
341
342  // assume y1<=y2 from above swap operation
343  yi=y2; yc=y1;
344
345  add_dirty(xc,yc,xi,yi);
346  dcx=x1; dcy=y1;
347  xc=(x2-x1); yc=(y2-y1);
348  if (xc<0) xi=-1; else xi=1;
349  if (yc<0) yi=-1; else yi=1;
350  n=abs(xc); m=abs(yc);
351  ycyi=abs(2*yc*xi);
352  er=0;
353
354  if (n>m)
355  {
356    xcxi=abs(2*xc*xi);
357    for (i=0;i<=n;i++)
358    {
359      *(scan_line(dcy)+dcx)=color;
360      if (er>0)
361      { dcy+=yi;
362        er-=xcxi;
363      }
364      er+=ycyi;
365      dcx+=xi;
366    }
367  }
368  else
369  {
370    xcyi=abs(2*xc*yi);
371    for (i=0;i<=m;i++)
372    {
373      *(scan_line(dcy)+dcx)=color;
374      if (er>0)
375      { dcx+=xi;
376        er-=ycyi;
377      }
378      er+=xcyi;
379      dcy+=yi;
380    }
381  }
382}
383
384
385void image::put_image(image *screen, short x, short y, char transparent)
386{
387  short i,j,xl,yl;
388  unsigned char *pg1,*pg2,*source,*dest;
389  if (screen->special)  // the screen is clipped then we onl want to put
390                    // part of the image
391    put_part(screen,x,y,0,0,width()-1,height()-1,transparent);
392  else
393  {
394    if (x<screen->width() && y<screen->height())
395    {
396      xl=width();
397      if (x+xl>screen->width())     // clip to the border of the screen
398                                xl=screen->width()-x;
399      yl=height();
400      if (y+yl>screen->height())
401                                yl=screen->height()-y;
402
403      int startx=0,starty=0;
404      if (x<0) { startx=-x; x=0; }
405      if (y<0) { starty=-y; y=0; }
406
407      if (xl<0 || yl<0) return ;
408
409      screen->add_dirty(x,y,x+xl-1,y+yl-1);
410      for (j=starty;j<yl;j++,y++)
411      {
412                                pg1=screen->scan_line(y);
413                                pg2=scan_line(j);
414                                if (transparent)
415                                {
416                                  for (i=startx,source=pg2+startx,dest=pg1+x;i<xl;i++,source++,dest++)
417                                    if (*source!=current_background) *dest=*source;
418                                } else memcpy(&pg1[x],pg2,xl);   // strait copy
419      }
420    }
421  }
422}
423
424void image::fill_image(image *screen, short x1, short y1, short x2, short y2, short allign)
425{
426  short i,j,w,xx,start,xl,starty;
427  unsigned char *pg1,*pg2;
428  CHECK(x1<=x2 && y1<=y2);  // we should have gotten this
429
430  if (screen->special)
431  { x1=screen->special->bound_x1(x1);
432    y1=screen->special->bound_y1(y1);
433    x2=screen->special->bound_x2(x2);
434    y2=screen->special->bound_y2(y2);
435  }
436  else
437  { if (x1<0) x1=0;
438    if (y2<0) y1=0;
439    if (x2>=screen->width())  x2=screen->width()-1;
440    if (y2>=screen->height()) y2=screen->height()-1;
441  }
442  if (x2<0 || y2<0 || x1>=screen->width() || y1>=screen->height())
443    return ;
444  screen->add_dirty(x1,y1,x2,y2);
445  w=width();
446  if (allign)
447  {
448    start=x1%w;
449    starty=y1%height();
450  }
451  else
452  { start=0;
453    starty=0;
454  }
455  for (j=y1;j<=y2;j++)
456  {
457    pg1=screen->scan_line(j);
458    pg2=scan_line(starty++);
459    if (starty>=height()) starty=0;
460    i=x1;
461    xx=start;
462    while (i<=x2)
463    {
464      xl=min(w-xx,x2-i+1);
465
466      memcpy(&pg1[i],&pg2[xx],xl);
467      xx=0;
468      i+=xl;
469    }
470  }
471}
472
473
474void image::put_part(image *screen, short x, short y,
475                short x1, short y1, short x2, short y2, char transparent)
476{
477  short xl,yl,j,i;
478  short cx1,cy1,cx2,cy2;
479  unsigned char *pg1,*pg2,*source,*dest;
480  CHECK(x1<=x2 && y1<=y2);
481
482  screen->get_clip(cx1,cy1,cx2,cy2);
483
484
485  // see if the are to be put is outside of actual image, if so adjust
486  // to fit in the image
487  if (x1<0) { x+=-x1; x1=0; } 
488  if (y1<0) { y+=-y1; y1=0; } 
489  if (x2>=width()) x2=width()-1;
490  if (y2>=height()) y2=height()-1;
491  if (x1>x2 || y1>y2) return ;      // return if it was adjusted so that nothing will be put
492   
493
494  // see if the image gets clipped of the screen
495  if (x>cx2 || y>cy2 || x+(x2-x1)<cx1 || y+(y2-y1)<cy1) return ;
496
497 
498  if (x<cx1)
499  { x1+=(cx1-x); x=cx1; }
500  if (y<cy1)
501  { y1+=(cy1-y); y=cy1; }
502
503  if (x+x2-x1+1>cx2)
504  { x2=cx2-x+x1; }
505
506  if (y+y2-y1+1>cy2)
507  { y2=cy2-y+y1; }
508  if (x1>x2 || y1>y2) return ;   
509
510 
511
512
513  xl=x2-x1+1;
514  yl=y2-y1+1;
515
516  screen->add_dirty(x,y,x+xl-1,y+yl-1);
517
518  pg1=screen->scan_line(y);
519  pg2=scan_line(y1);
520
521  if (transparent)
522  {
523    for (j=0;j<yl;j++)       
524    {
525      for (i=0,source=&pg2[x1],dest=&pg1[x];i<xl;i++,source++,dest++)   
526        if (*source!=current_background) *dest=*source;
527      pg1=screen->next_line(y+j,pg1); 
528      pg2=next_line(y1+j,pg2);
529    }     
530  }
531  else
532  for (j=0;j<yl;j++)
533  {     
534    memcpy(&pg1[x],&pg2[x1],xl);   // strait copy
535    pg1=screen->next_line(y+j,pg1); 
536    pg2=next_line(y1+j,pg2);
537  }   
538}
539
540void image::put_part_xrev(image *screen, short x, short y,
541                short x1, short y1, short x2, short y2, char transparent)
542{
543  short xl,yl,j,i;
544  short cx1,cy1,cx2,cy2;
545  unsigned char *pg1,*pg2,*source,*dest;
546  CHECK(x1<=x2 && y1<=y2);
547
548  i=x1; x1=width()-x2-1;  // reverse the x locations
549  x2=width()-i-1;
550
551  if (x1<0)
552  { x-=x1; x1=0; }
553  if (y1<0)
554  { y-=y1; y1=0; }
555
556  if (screen->special)
557  {
558    screen->special->get_clip(cx1,cy1,cx2,cy2);
559    if (x>cx2 || y>cy2 || x+(x2-x1)<0 || y+(y2-y1)<0) return ;
560    if (x<cx1)
561    { x1+=(cx1-x); x=cx1; }
562    if (y<cy1)
563    { y1+=(cy1-y); y=cy1; }
564    if (x+x2-x1+1>cx2)
565    { x2=cx2-x+x1; }
566    if (y+y2-y1+1>cy2)
567    { y2=cy2-y+y1; }
568  }
569  else  if (x>screen->width() || y>screen->height() || x+x2<0 || y+y2<0)
570    return ;
571
572  if (x<screen->width() && y<screen->height() && x1<width() && y1<height() &&
573      x1<=x2 && y1<=y2)
574  {
575    if (x2>=width())
576      x2=width()-1;
577    if (y2>=height())
578      y2=height()-1;
579    xl=x2-x1+1;
580    if (x+xl>screen->width())
581      xl=screen->width()-x;
582    yl=y2-y1+1;
583    if (y+yl>screen->height())
584      yl=screen->height()-y;
585    screen->add_dirty(x,y,x+xl-1,y+yl-1);
586    for (j=0;j<yl;j++)
587    {
588      pg1=screen->scan_line(y+j);
589      pg2=scan_line(y1+j);
590      if (transparent)
591      {
592                                for (i=0,source=&pg2[x1],dest=&pg1[x+xl-1];i<xl;i++,source++,dest--)
593          if (*source!=current_background) *dest=*source;
594      }
595      else
596                                for (i=0,source=&pg2[x1],dest=&pg1[x+xl-1];i<xl;i++,source++,dest++)
597          *dest=*source;
598    }
599  }
600}
601
602
603void image::put_part_masked(image *screen, image *mask, short x, short y,
604                short maskx, short masky,
605                short x1, short y1, short x2, short y2)
606{
607  short xl,yl,j,i,ml,mh;
608  short cx1,cy1,cx2,cy2;
609  unsigned char *pg1,*pg2,*pg3;
610  CHECK(x1<=x2 && y1<=y2);
611
612  if (screen->special)
613  {
614    screen->special->get_clip(cx1,cy1,cx2,cy2);
615    if (x>cx2 || y>cy2 || x+(x2-x1)<0 || y+(y2-y1)<0) return ;
616    if (x<cx1)
617    { x1+=(cx1-x); x=cx1; }
618    if (y<cy1)
619    { y1+=(cy1-y); y=cy1; }
620    if (x+x2-x1>cx2)
621    { x2=cx2+x1-x; }
622    if (y+y2-y1>cy2)
623    { y2=cy2+y1-y; }
624  }
625  else  if (x>screen->width() || y>screen->height() || x+x1<0 || y+y1<0)
626    return ;
627
628  ml=mask->width();
629  mh=mask->height();
630  if (x<screen->width() && y<screen->height() && x1<width() && y1<height() &&
631      maskx<ml && masky<mh && x1<=x2 && y1<=y2)
632  {
633
634    if (x2>=width())
635      x2=width()-1;
636    if (y2>=height())
637      y2=height()-1;
638    xl=x2-x1+1;
639    if (x+xl>screen->width())
640      xl=screen->width()-x-1;
641    yl=y2-y1+1;
642    if (y+yl>screen->height())
643      yl=screen->height()-y-1;
644    screen->add_dirty(x,y,x+xl-1,y+yl-1);
645    for (j=0;j<yl;j++)
646    {
647      pg1=screen->scan_line(y+j);
648      pg2=scan_line(y1+j);
649      pg3=mask->scan_line(masky++);
650      if (masky>=mh)           // wrap the mask around if out of bounds
651                                masky=0;
652      for (i=0;i<xl;i++)
653      {
654                                if (pg3[maskx+i])          // check to make sure not 0 before putting
655                                  pg1[x+i]=pg2[x1+i];
656                                if (maskx>=ml)            // wrap x around if it goes to far
657                                  maskx=0;
658      }
659    }
660  }
661}
662
663
664
665unsigned char image::brightest_color(palette *pal)
666{ unsigned char *p,r,g,b,bri;
667  short i,j;
668  long brv;
669  brv=0; bri=0;
670  for (j=0;j<h;j++)
671  {
672    p=scan_line(j);
673    for (i=0;i<w;i++)
674    { pal->get(p[i],r,g,b);
675      if ((long)r*(long)g*(long)b>brv)
676      { brv=(long)r*(long)g*(long)b;
677        bri=p[i];
678      }
679    }
680  }
681  return bri;
682}
683
684unsigned char image::darkest_color(palette *pal, short noblack)
685{ unsigned char *p,r,g,b,bri;
686  short i,j;
687  long brv,x;
688  brv=(long)258*(long)258*(long)258; bri=0;
689  for (j=0;j<h;j++)
690  {
691    p=scan_line(j);
692    for (i=0;i<w;i++)
693    { pal->get(p[i],r,g,b);
694      x=(long)r*(long)g*(long)b;
695      if (x<brv && (x || !noblack))
696      { brv=x;
697        bri=p[i];
698      }
699    }
700  }
701  return bri;
702}
703
704void image::rectangle(short x1, short y1,short x2, short y2, unsigned char color)
705{
706  line(x1,y1,x2,y1,color);
707  line(x2,y1,x2,y2,color);
708  line(x1,y2,x2,y2,color);
709  line(x1,y1,x1,y2,color);
710}
711
712void image::set_clip(short x1, short y1, short x2, short y2)
713{
714  // If the image does not already have an Image descriptor, allocate one.
715
716  if (!special)
717  {
718    // create a new image descriptor withj no dirty rectangle keeping
719    special=new image_descriptor(width(),height(),0);
720  }
721  special->set_clip(x1,y1,x2,y2);  // set the image descriptor what the clip
722                       // should be it will adjust to fit wiothin the image.
723}
724
725void image::get_clip (short &x1, short &y1, short &x2, short &y2)
726{
727  if (special)
728    special->get_clip(x1,y1,x2,y2);
729  else
730  { x1=0; y1=0; x2=width()-1; y2=height()-1; }
731}
732
733void image::in_clip  (short x1, short y1, short x2, short y2)
734{
735  if (special)
736  {
737    if (x1<special->x1_clip())
738      x1=special->x1_clip();
739    if (y1<special->y1_clip())
740      y1=special->y1_clip();
741    if (x2>special->x2_clip())
742      x2=special->x2_clip();
743    if (y2>special->y2_clip())
744      y2=special->y2_clip();
745  }
746  set_clip(x1,y1,x2,y2);
747}
748// this function reduces the number of dirty rectanges
749// to 1 by find the minmum area that can contain all the rectangles and
750// making this the new dirty area
751void image_descriptor::reduce_dirties()
752{
753  dirty_rect *p,*q;
754  short x1,y1,x2,y2,nn;
755  x1=6000; y1=6000;
756  x2=0; y2=0;
757  p=(dirty_rect *)dirties.first();
758  nn=dirties.number_nodes();
759  while (nn>0)
760  {
761    if (p->dx1<x1) x1=p->dx1;
762    if (p->dy1<y1) y1=p->dy1;
763    if (p->dx2>x2) x2=p->dx2;
764    if (p->dy2>y2) y2=p->dy2;
765    q=p;
766    p=(dirty_rect *)p->next();
767    dirties.unlink((linked_node *)q);
768    delete q;
769    nn--;
770  }
771  dirties.add_front((linked_node *) new dirty_rect(x1,y1,x2,y2));
772}
773
774void image_descriptor::delete_dirty(int x1, int y1, int x2, int y2)
775{
776  short i,ax1,ay1,ax2,ay2;
777  dirty_rect *p,*next;
778  if (keep_dirt)
779  {
780    if (x1<0) x1=0;
781    if (y1<0) y1=0;
782    if (x2>=(int)l) x2=l-1;
783    if (y2>=(int)h) y2=h-1;
784    if (x1>x2) return;
785    if (y1>y2) return ;
786
787    i=dirties.number_nodes();
788    if (!i)
789      return ;
790    else
791    {
792      for (p=(dirty_rect *)dirties.first();i;i--,p=(dirty_rect *)next)
793      {
794        next=(dirty_rect *)p->next();
795        // are the two touching?
796        if (!(x2<p->dx1 || y2<p->dy1 || x1>p->dx2 || y1>p->dy2))
797        {
798          // does it take a x slice off? (across)
799          if (x2>=p->dx2 && x1<=p->dx1)
800          {
801            if (y2>=p->dy2 && y1<=p->dy1)
802            {
803              dirties.unlink((linked_node *)p);
804              delete p;
805            }
806            else if (y2>=p->dy2)
807              p->dy2=y1-1;
808            else if (y1<=p->dy1)
809              p->dy1=y2+1;
810            else
811            {
812              dirties.add_front((linked_node *) new dirty_rect(p->dx1,p->dy1,p->dx2,y1-1));
813              p->dy1=y2+1;
814            }
815          }
816          // does it take a y slice off (down)
817          else if (y2>=p->dy2 && y1<=p->dy1)
818          {
819            if (x2>=p->dx2)
820              p->dx2=x1-1;
821            else if (x1<=p->dx1)
822              p->dx1=x2+1;
823            else
824            {
825              dirties.add_front((linked_node *) new dirty_rect(p->dx1,p->dy1,x1-1,p->dy2));
826              p->dx1=x2+1;
827            }
828          }
829          // otherwise it just takes a little chunk off
830          else
831          {
832            if (x2>=p->dx2)      { ax1=p->dx1; ax2=x1-1; }
833            else if (x1<=p->dx1) { ax1=x2+1; ax2=p->dx2; }
834            else                { ax1=p->dx1; ax2=x1-1; }
835            if (y2>=p->dy2)      { ay1=y1; ay2=p->dy2; }
836            else if (y1<=p->dy1) { ay1=p->dy1; ay2=y2; }
837            else                { ay1=y1; ay2=y2; }
838            dirties.add_front((linked_node *) new dirty_rect(ax1,ay1,ax2,ay2));
839         
840            if (x2>=p->dx2 || x1<=p->dx1)  { ax1=p->dx1; ax2=p->dx2; }
841            else                         { ax1=x2+1; ax2=p->dx2; }
842
843            if (y2>=p->dy2)
844            { if (ax1==p->dx1) { ay1=p->dy1; ay2=y1-1; }
845                          else { ay1=y1; ay2=p->dy2;   } }
846            else if (y1<=p->dy1) { if (ax1==p->dx1) { ay1=y2+1; ay2=p->dy2; }
847                                             else  { ay1=p->dy1; ay2=y2; } }
848            else           { if (ax1==p->dx1) { ay1=p->dy1; ay2=y1-1; }
849                             else { ay1=y1; ay2=y2; } }
850            dirties.add_front((linked_node *) new dirty_rect(ax1,ay1,ax2,ay2));
851
852            if (x1>p->dx1 && x2<p->dx2)
853            {
854              if (y1>p->dy1 && y2<p->dy2)
855              {
856                dirties.add_front((linked_node *) new dirty_rect(p->dx1,p->dy1,p->dx2,y1-1));
857                dirties.add_front((linked_node *) new dirty_rect(p->dx1,y2+1,p->dx2,p->dy2));
858              } else if (y1<=p->dy1)
859                dirties.add_front((linked_node *) new dirty_rect(p->dx1,y2+1,p->dx2,p->dy2));
860              else
861                dirties.add_front((linked_node *) new dirty_rect(p->dx1,p->dy1,p->dx2,y1-1));
862            } else if (y1>p->dy1 && y2<p->dy2)
863              dirties.add_front((linked_node *) new dirty_rect(p->dx1,y2+1,p->dx2,p->dy2));
864            dirties.unlink((linked_node *) p);
865            delete p;
866          }
867        }
868      }
869    }
870  }
871}
872
873// specifies that an area is a dirty
874void image_descriptor::add_dirty(int x1, int y1, int x2, int y2)
875{
876  short i;
877  dirty_rect *p;
878  if (keep_dirt)
879  {
880    if (x1<0) x1=0;
881    if (y1<0) y1=0;
882    if (x2>=(int)l) x2=l-1;
883    if (y2>=(int)h) y2=h-1;
884    if (x1>x2) return;
885    if (y1>y2) return ;
886   
887    i=dirties.number_nodes();
888    if (!i)
889      dirties.add_front((linked_node *) new dirty_rect(x1,y1,x2,y2));
890    else if (i>=MAX_DIRTY)
891    {
892      dirties.add_front((linked_node *) new dirty_rect(x1,y1,x2,y2));
893      reduce_dirties();  // reduce to one dirty rectangle, we have to many
894    }
895    else
896    { 
897      for (p=(dirty_rect *)dirties.first();i>0;i--)
898      {
899
900        // check to see if this new rectangle completly encloses the check rectangle
901                                if (x1<=p->dx1 && y1<=p->dy1 && x2>=p->dx2 && y2>=p->dy2)
902                                {
903                                  dirty_rect *tmp=(dirty_rect*) p->next();
904                                  dirties.unlink((linked_node *)p);
905                                  delete p;
906                                  if (!dirties.first())
907                                    i=0;
908                                  else p=tmp;     
909                                }       
910                                else if (!(x2<p->dx1 || y2<p->dy1 || x1>p->dx2 || y1>p->dy2))
911                                {         
912                       
913                       
914                                 
915                        /*          if (x1<=p->dx1) { a+=p->dx1-x1; ax1=x1; } else ax1=p->dx1;
916                                  if (y1<=p->dy1) { a+=p->dy1-y1; ay1=y1; } else ay1=p->dy1;
917                                  if (x2>=p->dx2) { a+=x2-p->dx2; ax2=x2; } else ax2=p->dx2;
918                                  if (y2>=p->dy2) { a+=y2-p->dy2; ay2=y2; } else ay2=p->dy2;
919                                 
920                                  if (a<50)
921                                  { p->dx1=ax1;                                // then expand the dirty
922                                    p->dy1=ay1;
923                                    p->dx2=ax2;
924                                    p->dy2=ay2;
925                                    return ;
926                                  }
927                                  else */
928                                    {
929                                      if (x1<p->dx1)
930                                        add_dirty(x1,max(y1,p->dy1),p->dx1-1,min(y2,p->dy2));
931                                      if (x2>p->dx2)
932                                        add_dirty(p->dx2+1,max(y1,p->dy1),x2,min(y2,p->dy2));
933                                      if (y1<p->dy1)
934                                        add_dirty(x1,y1,x2,p->dy1-1);
935                                      if (y2>p->dy2)
936                                        add_dirty(x1,p->dy2+1,x2,y2);
937                                      return ;
938                                    }
939                                    p=(dirty_rect *)p->next();
940                                  } else p=(dirty_rect *)p->next();     
941       
942      }
943      CHECK(x1<=x2 && y1<=y2);
944      dirties.add_end((linked_node *)new dirty_rect(x1,y1,x2,y2));
945    }
946  }
947}
948
949void image::bar      (short x1, short y1, short x2, short y2, unsigned char color)
950{
951  short y;
952  if (x1>x2 || y1>y2) return ;
953  if (special)
954  { x1=special->bound_x1(x1);
955    y1=special->bound_y1(y1);
956    x2=special->bound_x2(x2);
957    y2=special->bound_y2(y2);
958  }
959  else
960  { if (x1<0) x1=0;
961    if (y1<0) y1=0;
962    if (x2>=width())  x2=width()-1;
963    if (y2>=height()) y2=height()-1;
964  }
965  if (x2<0 || y2<0 || x1>=width() || y1>=height() || x2<x1 || y2<y1)
966    return ;
967  for (y=y1;y<=y2;y++)
968    memset(scan_line(y)+x1,color,(x2-x1+1));
969  add_dirty(x1,y1,x2,y2);
970}
971
972void image::xor_bar  (short x1, short y1, short x2, short y2, unsigned char color)
973{
974  short y,x;
975  if (x1>x2 || y1>y2) return ;
976  if (special)
977  { x1=special->bound_x1(x1);
978    y1=special->bound_y1(y1);
979    x2=special->bound_x2(x2);
980    y2=special->bound_y2(y2);
981  }
982  else
983  { if (x1<0) x1=0;
984    if (y1<0) y1=0;
985    if (x2>=width())  x2=width()-1;
986    if (y2>=height()) y2=height()-1;
987  }
988  if (x2<0 || y2<0 || x1>=width() || y1>=height() || x2<x1 || y2<y1)
989    return ;
990
991  unsigned char *sl=scan_line(y1)+x1;
992  for (y=y1;y<=y2;y++)
993  {
994    unsigned char *s=sl;
995    for (x=x1;x<=x2;x++,s++)
996      *s=(*s)^color;
997    sl+=w;
998  }
999
1000  add_dirty(x1,y1,x2,y2);
1001}
1002
1003
1004void image::unpack_scanline(short line, char bitsperpixel)
1005{
1006  short x;
1007  unsigned char *sl,*ex,mask,bt,sh;
1008  ex=(unsigned char *)jmalloc(width(),"image::unpacked scanline");
1009  sl=scan_line(line);
1010  memcpy(ex,sl,width());
1011
1012  if (bitsperpixel==1)      { mask=128;           bt=8; }
1013  else if (bitsperpixel==2) { mask=128+64;        bt=4; }
1014  else                      {  mask=128+64+32+16; bt=2; }
1015
1016  for (x=0;x<width();x++)
1017  { sh=((x%bt)<<(bitsperpixel-1));
1018    sl[x]=(ex[x/bt]&(mask>>sh))>>(bt-sh-1);
1019  }
1020
1021  jfree((char *)ex);
1022}
1023
1024void image::dither(palette *pal)
1025{
1026  short x,y,i,j;
1027  unsigned char dt_matrix[]={0,  136,24, 170,
1028                   68, 204,102,238,
1029                   51, 187, 17,153,
1030                   119,255, 85,221};
1031
1032  unsigned char *sl;
1033  for (y=height()-1;y>=0;y--)
1034  {
1035    sl=scan_line(y);
1036    for (i=0,j=y%4,x=width()-1;x>=0;x--)
1037    {
1038      if (pal->red(sl[x])>dt_matrix[j*4+i])
1039        sl[x]=255;
1040      else sl[x]=0;
1041      if (i==3) i=0; else i++;
1042    }
1043  }
1044}
1045
1046void image_descriptor::clear_dirties()
1047{
1048  dirty_rect *dr;
1049  dr=(dirty_rect *)dirties.first(); 
1050  while (dr)
1051  { dirties.unlink(dr);
1052    delete dr;
1053    dr=(dirty_rect *)dirties.first();
1054  }
1055}
1056
1057void image::resize(short new_width, short new_height)
1058{
1059  int old_width=width(),old_height=height();
1060  unsigned char *im=(unsigned char *)jmalloc(width()*height(),"image::resized");
1061  memcpy(im,scan_line(0),width()*height());
1062
1063  delete_page();
1064  make_page(new_width,new_height,NULL);
1065  w=new_width;      // set the new hieght and width
1066  h=new_height;
1067
1068  unsigned char *sl1,*sl2;
1069  short y,y2,x2;
1070  double yc,xc,yd,xd;
1071
1072
1073
1074  yc=(double)old_height/(double)new_height;
1075  xc=(double)old_width/(double)new_width;
1076  for (y2=0,yd=0;y2<new_height;yd+=yc,y2++)
1077  {
1078    y=(int)yd;
1079    sl1=im+y*old_width;
1080    sl2=scan_line(y2);
1081    for (xd=0,x2=0;x2<new_width;xd+=xc,x2++)
1082    { sl2[x2]=sl1[(int)xd]; }
1083  }
1084  jfree(im);
1085  if (special) special->resize(new_width,new_height);
1086}
1087
1088void image::scroll(short x1, short y1, short x2, short y2, short xd, short yd)
1089{
1090  short cx1,cy1,cx2,cy2;
1091  CHECK(x1>=0 && y1>=0 && x1<x2 && y1<y2 && x2<width() && y2<height());
1092  if (special)
1093  {
1094    special->get_clip(cx1,cy1,cx2,cy2);
1095    x1=max(x1,cx1); y1=max(cy1,y1); x2=min(x2,cx2); y2=min(y2,cy2);
1096  }
1097  short xsrc,ysrc,xdst,ydst,xtot=x2-x1-abs(xd)+1,ytot,xt;
1098  unsigned char *src,*dst;
1099  if (xd<0) { xsrc=x1-xd; xdst=x1; } else { xsrc=x2-xd; xdst=x2; }
1100  if (yd<0) { ysrc=y1-yd; ydst=y1; } else { ysrc=y2-yd; ydst=y2; }
1101  for (ytot=y2-y1-abs(yd)+1;ytot;ytot--)
1102  { src=scan_line(ysrc)+xsrc;
1103    dst=scan_line(ydst)+xdst;
1104    if (xd<0)
1105      for (xt=xtot;xt;xt--)
1106        *(dst++)=*(src++);
1107      else for (xt=xtot;xt;xt--)
1108        *(dst--)=*(src--);
1109    if (yd<0) { ysrc++; ydst++; } else { ysrc--; ydst--; }
1110  }
1111  add_dirty(x1,y1,x2,y2);
1112}
1113
1114
1115image *image::create_smooth(short smoothness)
1116{
1117  short i,j,k,l,t,d;
1118  image *im;
1119  CHECK(smoothness>=0);
1120  if (!smoothness) return NULL;
1121  d=smoothness*2+1;
1122  d=d*d;
1123  im=new image(width(),height());
1124  for (i=0;i<width();i++)
1125    for (j=0;j<height();j++)
1126    {
1127      for (t=0,k=-smoothness;k<=smoothness;k++)
1128        for (l=-smoothness;l<=smoothness;l++)
1129          if (i+k>smoothness && i+k<width()-smoothness && j+l<height()-smoothness && j+l>smoothness)
1130            t+=pixel(i+k,j+l);
1131          else t+=pixel(i,j);
1132      im->putpixel(i,j,t/d);
1133    }
1134  return im;
1135}
1136
1137void image::wiget_bar(short x1, short y1, short x2, short y2,
1138        unsigned char light, unsigned char med, unsigned char dark)
1139{
1140  line(x1,y1,x2,y1,light);
1141  line(x1,y1,x1,y2,light);
1142  line(x2,y1+1,x2,y2,dark);
1143  line(x1+1,y2,x2-1,y2,dark);
1144  bar(x1+1,y1+1,x2-1,y2-1,med);
1145}
1146
1147class fill_rec
1148{
1149public :
1150  short x,y;
1151  fill_rec *last;
1152  fill_rec(short X, short Y, fill_rec *Last)
1153  { x=X; y=Y; last=Last; }
1154} ;
1155
1156void image::flood_fill(short x, short y, unsigned char color)
1157{
1158  unsigned char *sl,*above,*below;
1159  fill_rec *recs=NULL,*r;
1160  unsigned char fcolor;
1161  sl=scan_line(y);
1162  fcolor=sl[x];
1163  if (fcolor==color) return ;
1164  do
1165  {
1166    if (recs)
1167    { r=recs;
1168      recs=recs->last;
1169      x=r->x; y=r->y;
1170      delete r;
1171    }
1172    sl=scan_line(y);
1173    if (sl[x]==fcolor)
1174    {
1175      while (sl[x]==fcolor && x>0) x--;
1176      if (sl[x]!=fcolor) x++;
1177      if (y>0)
1178      {
1179        above=scan_line(y-1);
1180        if (above[x]==fcolor)
1181        { r=new fill_rec(x,y-1,recs);
1182          recs=r; 
1183        }
1184      }
1185      if (y<height()-1)
1186      {
1187        above=scan_line(y+1);
1188        if (above[x]==fcolor)
1189        { r=new fill_rec(x,y+1,recs);
1190          recs=r;
1191        }
1192      }
1193
1194
1195
1196      do
1197      {
1198        sl[x]=color;
1199        if (y>0)
1200        { above=scan_line(y-1);
1201          if (x>0 && above[x-1]!=fcolor && above[x]==fcolor)
1202          { r=new fill_rec(x,y-1,recs);
1203            recs=r; 
1204          }
1205        }
1206        if (y<height()-1)
1207        { below=scan_line(y+1);
1208          if (x>0 && below[x-1]!=fcolor && below[x]==fcolor)
1209          { r=new fill_rec(x,y+1,recs);
1210            recs=r; 
1211          }
1212        }
1213        x++;
1214      } while (sl[x]==fcolor && x<width());
1215      x--;
1216      if (y>0)
1217      {
1218        above=scan_line(y-1);
1219        if (above[x]==fcolor)
1220        { r=new fill_rec(x,y-1,recs);
1221          recs=r;
1222        }
1223      }
1224      if (y<height()-1)
1225      {
1226        above=scan_line(y+1);
1227        if (above[x]==fcolor)
1228        { r=new fill_rec(x,y+1,recs);
1229          recs=r;
1230        }
1231      }
1232    }
1233  } while (recs);
1234}
1235
1236
1237#define LED_L 5
1238#define LED_H 5
1239void image::burn_led(short x, short y, long num, short color, short scale)
1240{
1241  char st[100];
1242  short ledx[]={1,2,1,2,3,3,3,3,1,2,0,0,0,0};
1243  short ledy[]={3,3,0,0,1,2,4,6,7,7,4,6,1,2};
1244
1245  short dig[]={2+4+8+16+32+64,4+8,2+4+1+32+16,2+4+1+8+16,64+1+4+8,
1246             2+64+1+8+16,64+32+1+8+16,2+4+8,1+2+4+8+16+32+64,64+2+4+1+8,1};
1247  short xx,yy,zz;
1248  sprintf(st,"%8ld",num);
1249  for (xx=0;xx<8;xx++)
1250  {
1251    if (st[xx]!=' ')
1252    {
1253      if (st[xx]=='-')
1254        zz=10;
1255      else
1256        zz=st[xx]-'0';
1257      for (yy=0;yy<7;yy++)
1258        if ((1<<yy)&dig[zz])
1259          line(x+ledx[yy*2]*scale,y+ledy[yy*2]*scale,x+ledx[yy*2+1]*scale,
1260            y+ledy[yy*2+1]*scale,color);
1261    }
1262    x+=6*scale;
1263  }
1264}
1265
1266unsigned char dither_matrix[]={0,  136,24, 170,
1267                     68, 204,102,238,
1268                     51, 187, 17,153,
1269                     119,255, 85,221};
1270
1271image *image::copy_part_dithered (short x1, short y1, short x2, short y2)
1272{
1273  short x,y,cx1,cy1,cx2,cy2,ry,rx,bo,dity,ditx;
1274  image *ret;
1275  unsigned char *sl1,*sl2;
1276  get_clip(cx1,cy1,cx2,cy2);
1277  if (y1<cy1) y1=cy1;
1278  if (x1<cx1) x1=cx1;
1279  if (y2>cy2) y2=cy2;
1280  if (x2>cx2) x2=cx2;
1281  CHECK(x2>=x1 && y2>=y1);
1282  if (x2<x1 || y2<y1) return NULL;
1283  ret=new image((x2-x1+8)/8,(y2-y1+1));
1284  if (!last_loaded())
1285    ret->clear();
1286  else
1287    for (y=y1,ry=0,dity=(y1%4)*4;y<=y2;y++,ry++)
1288    {
1289      sl1=ret->scan_line(ry);     // sl1 is the scan linefo the return image
1290      sl2=scan_line(y);          // sl2 is the orginal image scan line
1291      memset(sl1,0,(x2-x1+8)/8);
1292      for (bo=7,rx=0,x=x1,ditx=x1%4;x<=x2;x++)
1293      {
1294        if (last_loaded()->red(sl2[x])>dither_matrix[ditx+dity])
1295          sl1[rx]|=1<<bo;
1296        if (bo!=0)
1297        bo--;
1298        else
1299        {
1300          rx++;
1301          bo=7;
1302        }
1303        ditx+=1; if (ditx>3) ditx=0;
1304      }
1305      dity+=4; if (dity>12) dity=0;
1306    }
1307  return ret;
1308}
1309
1310void image::flip_x()
1311{
1312  unsigned char *rev=(unsigned char *)jmalloc(width(),"image tmp::flipped_x"),*sl;
1313  CONDITION(rev,"memory allocation");
1314  int y,x,i;
1315  for (y=0;y<height();y++)
1316  { sl=scan_line(y);
1317    for (i=0,x=width()-1;x>=0;x--,i++)
1318      rev[i]=sl[x];
1319    memcpy(sl,rev,width());
1320  }
1321  jfree(rev);
1322}
1323
1324void image::flip_y()
1325{
1326  unsigned char *rev=(unsigned char *)jmalloc(width(),"image::flipped_y"),*sl;
1327  CONDITION(rev,"memory allocation");
1328  int y;
1329  for (y=0;y<height()/2;y++)
1330  { sl=scan_line(y);
1331    memcpy(rev,sl,width());
1332    memcpy(sl,scan_line(height()-y-1),width());
1333    memcpy(scan_line(height()-y-1),rev,width());
1334  }
1335}
1336
1337void image::make_color(unsigned char color)
1338{
1339  unsigned char *sl;
1340  int y,x;
1341  for (y=0;y<height();y++)
1342  {
1343    sl=scan_line(y);
1344    for (x=width();x;x--,sl++)
1345      if (*sl)
1346        *sl=color;
1347  }
1348}
Note: See TracBrowser for help on using the repository browser.