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

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

Fuck the history, I'm renaming all .hpp files to .h for my own sanity.

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.