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

Last change on this file since 490 was 490, checked in by Sam Hocevar, 12 years ago

lisp: implement LispList::GetLength?.

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