source: abuse/trunk/src/imlib/image.cpp @ 39

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