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

Last change on this file since 513 was 513, checked in by Sam Hocevar, 11 years ago

imlib: some more vec2i transition for simplicity.

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