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

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

style: remove trailing spaces, fix copyright statements.

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