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

Last change on this file since 112 was 112, checked in by Sam Hocevar, 11 years ago
  • Fix spelling errors all over the place.
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 occurred 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 occurred 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 with wrong endianness, 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    // with no dirty rectangle keeping.
726    if(!special)
727        special = new image_descriptor(width(), height(), 0);
728
729    // set the image descriptor what the clip
730    // should be it will adjust to fit within the image.
731    special->set_clip(x1, y1, x2, y2);
732}
733
734void image::get_clip (int16_t &x1, int16_t &y1, int16_t &x2, int16_t &y2)
735{
736  if (special)
737    special->get_clip(x1,y1,x2,y2);
738  else
739  { x1=0; y1=0; x2=width()-1; y2=height()-1; }
740}
741
742void image::in_clip  (int16_t x1, int16_t y1, int16_t x2, int16_t y2)
743{
744  if (special)
745  {
746    if (x1<special->x1_clip())
747      x1=special->x1_clip();
748    if (y1<special->y1_clip())
749      y1=special->y1_clip();
750    if (x2>special->x2_clip())
751      x2=special->x2_clip();
752    if (y2>special->y2_clip())
753      y2=special->y2_clip();
754  }
755  set_clip(x1,y1,x2,y2);
756}
757
758//
759// reduce the number of dirty rectanges to 1 by finding the minmum area that
760// can contain all the rectangles and making this the new dirty area
761//
762void image_descriptor::reduce_dirties()
763{
764  dirty_rect *p,*q;
765  int16_t x1,y1,x2,y2,nn;
766  x1=6000; y1=6000;
767  x2=0; y2=0;
768  p=(dirty_rect *)dirties.first();
769  nn=dirties.number_nodes();
770  while (nn>0)
771  {
772    if (p->dx1<x1) x1=p->dx1;
773    if (p->dy1<y1) y1=p->dy1;
774    if (p->dx2>x2) x2=p->dx2;
775    if (p->dy2>y2) y2=p->dy2;
776    q=p;
777    p=(dirty_rect *)p->next();
778    dirties.unlink((linked_node *)q);
779    delete q;
780    nn--;
781  }
782  dirties.add_front((linked_node *) new dirty_rect(x1,y1,x2,y2));
783}
784
785void image_descriptor::delete_dirty(int x1, int y1, int x2, int y2)
786{
787  int16_t i,ax1,ay1,ax2,ay2;
788  dirty_rect *p,*next;
789  if (keep_dirt)
790  {
791    if (x1<0) x1=0;
792    if (y1<0) y1=0;
793    if (x2>=(int)l) x2=l-1;
794    if (y2>=(int)h) y2=h-1;
795    if (x1>x2) return;
796    if (y1>y2) return ;
797
798    i=dirties.number_nodes();
799    if (!i)
800      return ;
801    else
802    {
803      for (p=(dirty_rect *)dirties.first();i;i--,p=(dirty_rect *)next)
804      {
805        next=(dirty_rect *)p->next();
806        // are the two touching?
807        if (!(x2<p->dx1 || y2<p->dy1 || x1>p->dx2 || y1>p->dy2))
808        {
809          // does it take a x slice off? (across)
810          if (x2>=p->dx2 && x1<=p->dx1)
811          {
812            if (y2>=p->dy2 && y1<=p->dy1)
813            {
814              dirties.unlink((linked_node *)p);
815              delete p;
816            }
817            else if (y2>=p->dy2)
818              p->dy2=y1-1;
819            else if (y1<=p->dy1)
820              p->dy1=y2+1;
821            else
822            {
823              dirties.add_front((linked_node *) new dirty_rect(p->dx1,p->dy1,p->dx2,y1-1));
824              p->dy1=y2+1;
825            }
826          }
827          // does it take a y slice off (down)
828          else if (y2>=p->dy2 && y1<=p->dy1)
829          {
830            if (x2>=p->dx2)
831              p->dx2=x1-1;
832            else if (x1<=p->dx1)
833              p->dx1=x2+1;
834            else
835            {
836              dirties.add_front((linked_node *) new dirty_rect(p->dx1,p->dy1,x1-1,p->dy2));
837              p->dx1=x2+1;
838            }
839          }
840          // otherwise it just takes a little chunk off
841          else
842          {
843            if (x2>=p->dx2)      { ax1=p->dx1; ax2=x1-1; }
844            else if (x1<=p->dx1) { ax1=x2+1; ax2=p->dx2; }
845            else                { ax1=p->dx1; ax2=x1-1; }
846            if (y2>=p->dy2)      { ay1=y1; ay2=p->dy2; }
847            else if (y1<=p->dy1) { ay1=p->dy1; ay2=y2; }
848            else                { ay1=y1; ay2=y2; }
849            dirties.add_front((linked_node *) new dirty_rect(ax1,ay1,ax2,ay2));
850         
851            if (x2>=p->dx2 || x1<=p->dx1)  { ax1=p->dx1; ax2=p->dx2; }
852            else                         { ax1=x2+1; ax2=p->dx2; }
853
854            if (y2>=p->dy2)
855            { if (ax1==p->dx1) { ay1=p->dy1; ay2=y1-1; }
856                          else { ay1=y1; ay2=p->dy2;   } }
857            else if (y1<=p->dy1) { if (ax1==p->dx1) { ay1=y2+1; ay2=p->dy2; }
858                                             else  { ay1=p->dy1; ay2=y2; } }
859            else           { if (ax1==p->dx1) { ay1=p->dy1; ay2=y1-1; }
860                             else { ay1=y1; ay2=y2; } }
861            dirties.add_front((linked_node *) new dirty_rect(ax1,ay1,ax2,ay2));
862
863            if (x1>p->dx1 && x2<p->dx2)
864            {
865              if (y1>p->dy1 && y2<p->dy2)
866              {
867                dirties.add_front((linked_node *) new dirty_rect(p->dx1,p->dy1,p->dx2,y1-1));
868                dirties.add_front((linked_node *) new dirty_rect(p->dx1,y2+1,p->dx2,p->dy2));
869              } else if (y1<=p->dy1)
870                dirties.add_front((linked_node *) new dirty_rect(p->dx1,y2+1,p->dx2,p->dy2));
871              else
872                dirties.add_front((linked_node *) new dirty_rect(p->dx1,p->dy1,p->dx2,y1-1));
873            } else if (y1>p->dy1 && y2<p->dy2)
874              dirties.add_front((linked_node *) new dirty_rect(p->dx1,y2+1,p->dx2,p->dy2));
875            dirties.unlink((linked_node *) p);
876            delete p;
877          }
878        }
879      }
880    }
881  }
882}
883
884// specifies that an area is a dirty
885void image_descriptor::add_dirty(int x1, int y1, int x2, int y2)
886{
887  int16_t i;
888  dirty_rect *p;
889  if (keep_dirt)
890  {
891    if (x1<0) x1=0;
892    if (y1<0) y1=0;
893    if (x2>=(int)l) x2=l-1;
894    if (y2>=(int)h) y2=h-1;
895    if (x1>x2) return;
896    if (y1>y2) return ;
897    i=dirties.number_nodes();
898    if (!i)
899      dirties.add_front((linked_node *) new dirty_rect(x1,y1,x2,y2));
900    else if (i>=MAX_DIRTY)
901    {
902      dirties.add_front((linked_node *) new dirty_rect(x1,y1,x2,y2));
903      reduce_dirties();  // reduce to one dirty rectangle, we have to many
904    }
905    else
906    { 
907      for (p=(dirty_rect *)dirties.first();i>0;i--)
908      {
909
910        // check to see if this new rectangle completly encloses the check rectangle
911        if (x1<=p->dx1 && y1<=p->dy1 && x2>=p->dx2 && y2>=p->dy2)
912        {
913          dirty_rect *tmp=(dirty_rect*) p->next();
914          dirties.unlink((linked_node *)p);
915          delete p;
916          if (!dirties.first())
917            i=0;
918          else p=tmp;     
919        }       
920        else if (!(x2<p->dx1 || y2<p->dy1 || x1>p->dx2 || y1>p->dy2))
921        {         
922
923
924         
925/*          if (x1<=p->dx1) { a+=p->dx1-x1; ax1=x1; } else ax1=p->dx1;
926          if (y1<=p->dy1) { a+=p->dy1-y1; ay1=y1; } else ay1=p->dy1;
927          if (x2>=p->dx2) { a+=x2-p->dx2; ax2=x2; } else ax2=p->dx2;
928          if (y2>=p->dy2) { a+=y2-p->dy2; ay2=y2; } else ay2=p->dy2;
929         
930          if (a<50)
931          { p->dx1=ax1;                                // then expand the dirty
932            p->dy1=ay1;
933            p->dx2=ax2;
934            p->dy2=ay2;
935            return ;
936          }
937          else */
938            {
939              if (x1<p->dx1)
940                add_dirty(x1,max(y1,p->dy1),p->dx1-1,min(y2,p->dy2));
941              if (x2>p->dx2)
942                add_dirty(p->dx2+1,max(y1,p->dy1),x2,min(y2,p->dy2));
943              if (y1<p->dy1)
944                add_dirty(x1,y1,x2,p->dy1-1);
945              if (y2>p->dy2)
946                add_dirty(x1,p->dy2+1,x2,y2);
947              return ;
948            }
949            p=(dirty_rect *)p->next();
950          } else p=(dirty_rect *)p->next();     
951       
952      }
953      CHECK(x1<=x2 && y1<=y2);
954      dirties.add_end((linked_node *)new dirty_rect(x1,y1,x2,y2));
955    }
956  }
957}
958
959void image::bar      (int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t color)
960{
961  int16_t y;
962  if (x1>x2 || y1>y2) return ;
963  if (special)
964  { x1=special->bound_x1(x1);
965    y1=special->bound_y1(y1);
966    x2=special->bound_x2(x2);
967    y2=special->bound_y2(y2);
968  }
969  else
970  { if (x1<0) x1=0;
971    if (y1<0) y1=0;
972    if (x2>=width())  x2=width()-1;
973    if (y2>=height()) y2=height()-1;
974  }
975  if (x2<0 || y2<0 || x1>=width() || y1>=height() || x2<x1 || y2<y1)
976    return ;
977  for (y=y1;y<=y2;y++)
978    memset(scan_line(y)+x1,color,(x2-x1+1));
979  add_dirty(x1,y1,x2,y2);
980}
981
982void image::xor_bar  (int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t color)
983{
984  int16_t y,x;
985  if (x1>x2 || y1>y2) return ;
986  if (special)
987  { x1=special->bound_x1(x1);
988    y1=special->bound_y1(y1);
989    x2=special->bound_x2(x2);
990    y2=special->bound_y2(y2);
991  }
992  else
993  { if (x1<0) x1=0;
994    if (y1<0) y1=0;
995    if (x2>=width())  x2=width()-1;
996    if (y2>=height()) y2=height()-1;
997  }
998  if (x2<0 || y2<0 || x1>=width() || y1>=height() || x2<x1 || y2<y1)
999    return ;
1000
1001  uint8_t *sl=scan_line(y1)+x1;
1002  for (y=y1;y<=y2;y++)
1003  {
1004    uint8_t *s=sl;
1005    for (x=x1;x<=x2;x++,s++)
1006      *s=(*s)^color;
1007    sl+=w;
1008  }
1009
1010  add_dirty(x1,y1,x2,y2);
1011}
1012
1013
1014void image::unpack_scanline(int16_t line, char bitsperpixel)
1015{
1016  int16_t x;
1017  uint8_t *sl,*ex,mask,bt,sh;
1018  ex=(uint8_t *)jmalloc(width(),"image::unpacked scanline");
1019  sl=scan_line(line);
1020  memcpy(ex,sl,width());
1021
1022  if (bitsperpixel==1)      { mask=128;           bt=8; }
1023  else if (bitsperpixel==2) { mask=128+64;        bt=4; }
1024  else                      {  mask=128+64+32+16; bt=2; }
1025
1026  for (x=0;x<width();x++)
1027  { sh=((x%bt)<<(bitsperpixel-1));
1028    sl[x]=(ex[x/bt]&(mask>>sh))>>(bt-sh-1);
1029  }
1030
1031  jfree((char *)ex);
1032}
1033
1034void image::dither(palette *pal)
1035{
1036  int16_t x,y,i,j;
1037  uint8_t dt_matrix[]={0,  136,24, 170,
1038                   68, 204,102,238,
1039                   51, 187, 17,153,
1040                   119,255, 85,221};
1041
1042  uint8_t *sl;
1043  for (y=height()-1;y>=0;y--)
1044  {
1045    sl=scan_line(y);
1046    for (i=0,j=y%4,x=width()-1;x>=0;x--)
1047    {
1048      if (pal->red(sl[x])>dt_matrix[j*4+i])
1049        sl[x]=255;
1050      else sl[x]=0;
1051      if (i==3) i=0; else i++;
1052    }
1053  }
1054}
1055
1056void image_descriptor::clear_dirties()
1057{
1058  dirty_rect *dr;
1059  dr=(dirty_rect *)dirties.first(); 
1060  while (dr)
1061  { dirties.unlink(dr);
1062    delete dr;
1063    dr=(dirty_rect *)dirties.first();
1064  }
1065}
1066
1067void image::resize(int16_t new_width, int16_t new_height)
1068{
1069  int old_width=width(),old_height=height();
1070  uint8_t *im=(uint8_t *)jmalloc(width()*height(),"image::resized");
1071  memcpy(im,scan_line(0),width()*height());
1072
1073  delete_page();
1074  make_page(new_width,new_height,NULL);
1075  w=new_width;      // set the new hieght and width
1076  h=new_height;
1077
1078  uint8_t *sl1,*sl2;
1079  int16_t y,y2,x2;
1080  double yc,xc,yd,xd;
1081
1082
1083
1084  yc=(double)old_height/(double)new_height;
1085  xc=(double)old_width/(double)new_width;
1086  for (y2=0,yd=0;y2<new_height;yd+=yc,y2++)
1087  {
1088    y=(int)yd;
1089    sl1=im+y*old_width;
1090    sl2=scan_line(y2);
1091    for (xd=0,x2=0;x2<new_width;xd+=xc,x2++)
1092    { sl2[x2]=sl1[(int)xd]; }
1093  }
1094  jfree(im);
1095  if (special) special->resize(new_width,new_height);
1096}
1097
1098void image::scroll(int16_t x1, int16_t y1, int16_t x2, int16_t y2, int16_t xd, int16_t yd)
1099{
1100  int16_t cx1,cy1,cx2,cy2;
1101  CHECK(x1>=0 && y1>=0 && x1<x2 && y1<y2 && x2<width() && y2<height());
1102  if (special)
1103  {
1104    special->get_clip(cx1,cy1,cx2,cy2);
1105    x1=max(x1,cx1); y1=max(cy1,y1); x2=min(x2,cx2); y2=min(y2,cy2);
1106  }
1107  int16_t xsrc,ysrc,xdst,ydst,xtot=x2-x1-abs(xd)+1,ytot,xt;
1108  uint8_t *src,*dst;
1109  if (xd<0) { xsrc=x1-xd; xdst=x1; } else { xsrc=x2-xd; xdst=x2; }
1110  if (yd<0) { ysrc=y1-yd; ydst=y1; } else { ysrc=y2-yd; ydst=y2; }
1111  for (ytot=y2-y1-abs(yd)+1;ytot;ytot--)
1112  { src=scan_line(ysrc)+xsrc;
1113    dst=scan_line(ydst)+xdst;
1114    if (xd<0)
1115      for (xt=xtot;xt;xt--)
1116        *(dst++)=*(src++);
1117      else for (xt=xtot;xt;xt--)
1118        *(dst--)=*(src--);
1119    if (yd<0) { ysrc++; ydst++; } else { ysrc--; ydst--; }
1120  }
1121  add_dirty(x1,y1,x2,y2);
1122}
1123
1124
1125image *image::create_smooth(int16_t smoothness)
1126{
1127  int16_t i,j,k,l,t,d;
1128  image *im;
1129  CHECK(smoothness>=0);
1130  if (!smoothness) return NULL;
1131  d=smoothness*2+1;
1132  d=d*d;
1133  im=new image(width(),height());
1134  for (i=0;i<width();i++)
1135    for (j=0;j<height();j++)
1136    {
1137      for (t=0,k=-smoothness;k<=smoothness;k++)
1138        for (l=-smoothness;l<=smoothness;l++)
1139          if (i+k>smoothness && i+k<width()-smoothness && j+l<height()-smoothness && j+l>smoothness)
1140            t+=pixel(i+k,j+l);
1141          else t+=pixel(i,j);
1142      im->putpixel(i,j,t/d);
1143    }
1144  return im;
1145}
1146
1147void image::widget_bar(int16_t x1, int16_t y1, int16_t x2, int16_t y2,
1148        uint8_t light, uint8_t med, uint8_t dark)
1149{
1150  line(x1,y1,x2,y1,light);
1151  line(x1,y1,x1,y2,light);
1152  line(x2,y1+1,x2,y2,dark);
1153  line(x1+1,y2,x2-1,y2,dark);
1154  bar(x1+1,y1+1,x2-1,y2-1,med);
1155}
1156
1157class fill_rec
1158{
1159public :
1160  int16_t x,y;
1161  fill_rec *last;
1162  fill_rec(int16_t X, int16_t Y, fill_rec *Last)
1163  { x=X; y=Y; last=Last; }
1164} ;
1165
1166void image::flood_fill(int16_t x, int16_t y, uint8_t color)
1167{
1168  uint8_t *sl,*above,*below;
1169  fill_rec *recs=NULL,*r;
1170  uint8_t fcolor;
1171  sl=scan_line(y);
1172  fcolor=sl[x];
1173  if (fcolor==color) return ;
1174  do
1175  {
1176    if (recs)
1177    { r=recs;
1178      recs=recs->last;
1179      x=r->x; y=r->y;
1180      delete r;
1181    }
1182    sl=scan_line(y);
1183    if (sl[x]==fcolor)
1184    {
1185      while (sl[x]==fcolor && x>0) x--;
1186      if (sl[x]!=fcolor) x++;
1187      if (y>0)
1188      {
1189        above=scan_line(y-1);
1190        if (above[x]==fcolor)
1191        { r=new fill_rec(x,y-1,recs);
1192          recs=r; 
1193        }
1194      }
1195      if (y<height()-1)
1196      {
1197        above=scan_line(y+1);
1198        if (above[x]==fcolor)
1199        { r=new fill_rec(x,y+1,recs);
1200          recs=r;
1201        }
1202      }
1203
1204
1205
1206      do
1207      {
1208        sl[x]=color;
1209        if (y>0)
1210        { above=scan_line(y-1);
1211          if (x>0 && above[x-1]!=fcolor && above[x]==fcolor)
1212          { r=new fill_rec(x,y-1,recs);
1213            recs=r; 
1214          }
1215        }
1216        if (y<height()-1)
1217        { below=scan_line(y+1);
1218          if (x>0 && below[x-1]!=fcolor && below[x]==fcolor)
1219          { r=new fill_rec(x,y+1,recs);
1220            recs=r; 
1221          }
1222        }
1223        x++;
1224      } while (sl[x]==fcolor && x<width());
1225      x--;
1226      if (y>0)
1227      {
1228        above=scan_line(y-1);
1229        if (above[x]==fcolor)
1230        { r=new fill_rec(x,y-1,recs);
1231          recs=r;
1232        }
1233      }
1234      if (y<height()-1)
1235      {
1236        above=scan_line(y+1);
1237        if (above[x]==fcolor)
1238        { r=new fill_rec(x,y+1,recs);
1239          recs=r;
1240        }
1241      }
1242    }
1243  } while (recs);
1244}
1245
1246
1247#define LED_L 5
1248#define LED_H 5
1249void image::burn_led(int16_t x, int16_t y, int32_t num, int16_t color, int16_t scale)
1250{
1251  char st[100];
1252  int16_t ledx[]={1,2,1,2,3,3,3,3,1,2,0,0,0,0};
1253  int16_t ledy[]={3,3,0,0,1,2,4,6,7,7,4,6,1,2};
1254
1255  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,
1256             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};
1257  int16_t xx,yy,zz;
1258  sprintf(st,"%8ld",(long int)num);
1259  for (xx=0;xx<8;xx++)
1260  {
1261    if (st[xx]!=' ')
1262    {
1263      if (st[xx]=='-')
1264        zz=10;
1265      else
1266        zz=st[xx]-'0';
1267      for (yy=0;yy<7;yy++)
1268        if ((1<<yy)&dig[zz])
1269          line(x+ledx[yy*2]*scale,y+ledy[yy*2]*scale,x+ledx[yy*2+1]*scale,
1270            y+ledy[yy*2+1]*scale,color);
1271    }
1272    x+=6*scale;
1273  }
1274}
1275
1276uint8_t dither_matrix[]={0,  136,24, 170,
1277                     68, 204,102,238,
1278                     51, 187, 17,153,
1279                     119,255, 85,221};
1280
1281image *image::copy_part_dithered (int16_t x1, int16_t y1, int16_t x2, int16_t y2)
1282{
1283  int16_t x,y,cx1,cy1,cx2,cy2,ry,rx,bo,dity,ditx;
1284  image *ret;
1285  uint8_t *sl1,*sl2;
1286  get_clip(cx1,cy1,cx2,cy2);
1287  if (y1<cy1) y1=cy1;
1288  if (x1<cx1) x1=cx1;
1289  if (y2>cy2) y2=cy2;
1290  if (x2>cx2) x2=cx2;
1291  CHECK(x2>=x1 && y2>=y1);
1292  if (x2<x1 || y2<y1) return NULL;
1293  ret=new image((x2-x1+8)/8,(y2-y1+1));
1294  if (!last_loaded())
1295    ret->clear();
1296  else
1297    for (y=y1,ry=0,dity=(y1%4)*4;y<=y2;y++,ry++)
1298    {
1299      sl1=ret->scan_line(ry);     // sl1 is the scan linefo the return image
1300      sl2=scan_line(y);          // sl2 is the orginal image scan line
1301      memset(sl1,0,(x2-x1+8)/8);
1302      for (bo=7,rx=0,x=x1,ditx=x1%4;x<=x2;x++)
1303      {
1304        if (last_loaded()->red(sl2[x])>dither_matrix[ditx+dity])
1305          sl1[rx]|=1<<bo;
1306        if (bo!=0)
1307        bo--;
1308        else
1309        {
1310          rx++;
1311          bo=7;
1312        }
1313        ditx+=1; if (ditx>3) ditx=0;
1314      }
1315      dity+=4; if (dity>12) dity=0;
1316    }
1317  return ret;
1318}
1319
1320void image::flip_x()
1321{
1322  uint8_t *rev=(uint8_t *)jmalloc(width(),"image tmp::flipped_x"),*sl;
1323  CONDITION(rev,"memory allocation");
1324  int y,x,i;
1325  for (y=0;y<height();y++)
1326  { sl=scan_line(y);
1327    for (i=0,x=width()-1;x>=0;x--,i++)
1328      rev[i]=sl[x];
1329    memcpy(sl,rev,width());
1330  }
1331  jfree(rev);
1332}
1333
1334void image::flip_y()
1335{
1336  uint8_t *rev=(uint8_t *)jmalloc(width(),"image::flipped_y"),*sl;
1337  CONDITION(rev,"memory allocation");
1338  int y;
1339  for (y=0;y<height()/2;y++)
1340  { sl=scan_line(y);
1341    memcpy(rev,sl,width());
1342    memcpy(sl,scan_line(height()-y-1),width());
1343    memcpy(scan_line(height()-y-1),rev,width());
1344  }
1345}
1346
1347void image::make_color(uint8_t color)
1348{
1349  uint8_t *sl;
1350  int y,x;
1351  for (y=0;y<height();y++)
1352  {
1353    sl=scan_line(y);
1354    for (x=width();x;x--,sl++)
1355      if (*sl)
1356        *sl=color;
1357  }
1358}
Note: See TracBrowser for help on using the repository browser.