source: abuse/branches/pd/imlib/image.c @ 597

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