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

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

imlib: remove a lot of dead code, especially from the linked list and
the WAV reader.

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