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

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

imlib: refactor a few image methods so that they use vec2i.

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