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

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