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

Last change on this file since 663 was 663, checked in by Sam Hocevar, 10 years ago

imlib: replace image::PutImage? with a shortcut to image::PutPart?.

File size: 26.7 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    PutPart(im, pos, vec2i(0), im->m_size, transparent);
324}
325
326void image::PutPart(image *im, vec2i pos, vec2i aa, vec2i bb, int transparent)
327{
328    CHECK(aa < bb);
329
330    int cx1, cy1, cx2, cy2;
331    GetClip(cx1, cy1, cx2, cy2);
332
333    // see if the are to be put is outside of actual image, if so adjust
334    // to fit in the image
335    pos += Min(aa, vec2i(0));
336    aa += Min(aa, vec2i(0));
337    bb = Min(bb, im->m_size);
338    // return if it was adjusted so that nothing will be put
339    if (!(aa < bb))
340        return;
341
342    // see if the image gets clipped off the screen
343    if (pos.x >= cx2 || pos.y >= cy2 || pos.x + (bb.x - aa.x) <= cx1 || pos.y + (bb.y - aa.y) <= cy1)
344        return;
345
346    aa += Max(vec2i(cx1, cy1) - pos, vec2i(0));
347    pos += Max(vec2i(cx1, cy1) - pos, vec2i(0));
348    bb = Min(bb, vec2i(cx2, cy2) - pos + aa);
349    if (!(aa < bb))
350        return;
351
352    vec2i span = bb - aa;
353
354    AddDirty(pos.x, pos.y, pos.x + span.x, pos.y + span.y);
355
356    Lock();
357    im->Lock();
358
359    for (int j = 0; j < span.y; j++)
360    {
361        uint8_t *dst = scan_line(pos.y + j) + pos.x;
362        uint8_t *src = im->scan_line(aa.y + j) + aa.x;
363        if (transparent)
364        {
365            for (int i = 0; i < span.x; i++, src++, dst++)
366                if (*src)
367                    *dst = *src;
368        }
369        else
370            memcpy(dst, src, span.x);
371    }
372
373    im->Unlock();
374    Unlock();
375}
376
377void image::PutPartMasked(image *im, vec2i pos, image *mask, vec2i mpos,
378                          vec2i aa, vec2i bb)
379{
380    CHECK(aa < bb);
381
382    if (m_special)
383    {
384        int cx1, cy1, cx2, cy2;
385        m_special->GetClip(cx1, cy1, cx2, cy2);
386
387        if (!(pos < vec2i(cx2, cy2) && pos > aa - bb))
388            return;
389
390        aa += Max(vec2i(cx1, cy1) - pos, vec2i(0));
391        pos += Max(vec2i(cx1, cy1) - pos, vec2i(0));
392        bb = Min(bb, vec2i(cx2, cy2) - pos + aa);
393    }
394    else if (!(pos <= m_size && pos >= -aa))
395        return;
396
397    vec2i mask_size = mask->Size();
398
399    if (!(pos < m_size && aa < im->m_size && mpos < mask_size && aa < bb))
400        return;
401
402    bb = Min(bb, im->m_size);
403
404    vec2i span = bb - aa;
405    span = Min(span, m_size - pos);
406    AddDirty(pos.x, pos.y, pos.x + span.x, pos.y + span.y);
407
408    Lock();
409    mask->Lock();
410    im->Lock();
411
412    for (int j = 0; j < span.y; j++)
413    {
414        uint8_t *dst = scan_line(pos.y + j) + pos.x;
415        uint8_t *src = im->scan_line(aa.y + j) + aa.x;
416        uint8_t *pg3 = mask->scan_line(mpos.y) + mpos.x;
417
418        if (++mpos.y >= mask_size.y) // wrap mask y around
419            mpos.y = 0;
420
421        for (int i = 0; i < span.x; i++, dst++, src++, pg3++)
422        {
423            if (mpos.x + i >= mask_size.x) // wrap mask x around
424                pg3 -= mask_size.x;
425
426            if (pg3[mpos.x + i]) // check to make sure not 0 before putting
427                *dst = *src;
428        }
429    }
430
431    im->Unlock();
432    mask->Unlock();
433    Unlock();
434}
435
436void image::Rectangle(vec2i p1, vec2i p2, uint8_t color)
437{
438    Line(p1, vec2i(p2.x, p1.y), color);
439    Line(vec2i(p2.x, p1.y), p2, color);
440    Line(vec2i(p1.x, p2.y), p2, color);
441    Line(p1, vec2i(p1.x, p2.y), color);
442}
443
444void image::SetClip(int x1, int y1, int x2, int y2)
445{
446    // If the image does not already have an Image descriptor, allocate one
447    // with no dirty rectangle keeping.
448    if (!m_special)
449        m_special = new image_descriptor(m_size.x, m_size.y, 0);
450
451    // set the image descriptor what the clip
452    // should be it will adjust to fit within the image.
453    m_special->SetClip(x1, y1, x2, y2);
454}
455
456void image::GetClip(int &x1, int &y1, int &x2, int &y2)
457{
458    if (m_special)
459        m_special->GetClip(x1, y1, x2, y2);
460    else
461    {
462        x1 = 0; y1 = 0; x2 = m_size.x; y2 = m_size.y;
463    }
464}
465
466void image::InClip(int x1, int y1, int x2, int y2)
467{
468    if (m_special)
469    {
470        x1 = Min(x1, m_special->x1_clip());
471        y1 = Min(y1, m_special->y1_clip());
472        x2 = Max(x2, m_special->x2_clip());
473        y2 = Max(y2, m_special->y2_clip());
474    }
475
476    SetClip(x1, y1, x2, y2);
477}
478
479//
480// reduce the number of dirty rectanges to 1 by finding the minmum area that
481// can contain all the rectangles and making this the new dirty area
482//
483void image_descriptor::ReduceDirties()
484{
485    dirty_rect *p = (dirty_rect *)dirties.first();
486    int x1 = 6000, y1 = 6000, x2 = -1, y2 = -1;
487
488    for (int i = dirties.Count(); i--; )
489    {
490        x1 = Min(x1, p->dx1); y1 = Min(y1, p->dy1);
491        x2 = Max(x1, p->dx1); y2 = Max(y1, p->dy1);
492        dirty_rect *tmp = (dirty_rect *)p->Next();
493        dirties.unlink(p);
494        delete p;
495        p = tmp;
496    }
497    dirties.add_front(new dirty_rect(x1, y1, x2, y2));
498}
499
500void image_descriptor::delete_dirty(int x1, int y1, int x2, int y2)
501{
502    int ax1, ay1, ax2, ay2;
503    dirty_rect *p, *next;
504
505    if (!keep_dirt)
506        return;
507
508    x1 = Max(0, x1); x2 = Min(m_l, x2);
509    y1 = Max(0, y1); y2 = Min(m_h, y2);
510
511    if (x1 >= x2 || y1 >= y2)
512        return;
513
514    int i = dirties.Count();
515    if (!i)
516        return;
517
518    for (p = (dirty_rect *)dirties.first(); i; i--, p = next)
519    {
520        next = (dirty_rect *)p->Next();
521
522        // are the two touching?
523        if (x2 <= p->dx1 || y2 <= p->dy1 || x1 > p->dx2 || y1 > p->dy2)
524            continue;
525
526        // does it take a x slice off? (across)
527        if (x2 >= p->dx2 + 1 && x1 <= p->dx1)
528        {
529            if (y2 >= p->dy2 + 1 && y1 <= p->dy1)
530            {
531                dirties.unlink(p);
532                delete p;
533            }
534            else if (y2 >= p->dy2 + 1)
535                p->dy2 = y1 - 1;
536            else if (y1 <= p->dy1)
537                p->dy1 = y2;
538            else
539            {
540                dirties.add_front(new dirty_rect(p->dx1, p->dy1, p->dx2, y1-1));
541                p->dy1 = y2;
542            }
543        }
544        // does it take a y slice off (down)
545        else if (y2 - 1>=p->dy2 && y1<=p->dy1)
546        {
547            if (x2 - 1>=p->dx2)
548                p->dx2=x1-1;
549            else if (x1<=p->dx1)
550                p->dx1=x2;
551            else
552            {
553                dirties.add_front(new dirty_rect(p->dx1, p->dy1, x1-1, p->dy2));
554                p->dx1=x2;
555            }
556        }
557        // otherwise it just takes a little chunk off
558        else
559        {
560            if (x2 - 1>=p->dx2)      { ax1=p->dx1; ax2=x1; }
561            else if (x1<=p->dx1) { ax1=x2; ax2=p->dx2+1; }
562            else                { ax1=p->dx1; ax2=x1; }
563            if (y2 - 1>=p->dy2)      { ay1=y1; ay2=p->dy2+1; }
564            else if (y1<=p->dy1) { ay1=p->dy1; ay2=y2; }
565            else                { ay1=y1; ay2=y2; }
566            dirties.add_front(new dirty_rect(ax1, ay1, ax2-1, ay2-1));
567
568            if (x2 - 1>=p->dx2 || x1<=p->dx1)  { ax1=p->dx1; ax2=p->dx2+1; }
569            else                         { ax1=x2; ax2=p->dx2+1; }
570
571            if (y2 - 1>=p->dy2)
572            { if (ax1==p->dx1) { ay1=p->dy1; ay2=y1; }
573                          else { ay1=y1; ay2=p->dy2+1;   } }
574            else if (y1<=p->dy1) { if (ax1==p->dx1) { ay1=y2; ay2=p->dy2+1; }
575                                             else  { ay1=p->dy1; ay2=y2; } }
576            else           { if (ax1==p->dx1) { ay1=p->dy1; ay2=y1; }
577                             else { ay1=y1; ay2=y2; } }
578            dirties.add_front(new dirty_rect(ax1, ay1, ax2 - 1, ay2 - 1));
579
580            if (x1>p->dx1 && x2 - 1<p->dx2)
581            {
582                if (y1>p->dy1 && y2 - 1<p->dy2)
583                {
584                    dirties.add_front(new dirty_rect(p->dx1, p->dy1, p->dx2, y1-1));
585                    dirties.add_front(new dirty_rect(p->dx1, y2, p->dx2, p->dy2));
586                }
587                else if (y1<=p->dy1)
588                    dirties.add_front(new dirty_rect(p->dx1, y2, p->dx2, p->dy2));
589                else
590                    dirties.add_front(new dirty_rect(p->dx1, p->dy1, p->dx2, y1-1));
591            }
592            else if (y1>p->dy1 && y2 - 1<p->dy2)
593                dirties.add_front(new dirty_rect(p->dx1, y2, p->dx2, p->dy2));
594            dirties.unlink(p);
595            delete p;
596        }
597    }
598}
599
600// specifies that an area is a dirty
601void image_descriptor::AddDirty(int x1, int y1, int x2, int y2)
602{
603    dirty_rect *p;
604    if (!keep_dirt)
605        return;
606
607    x1 = Max(0, x1); x2 = Min(m_l, x2);
608    y1 = Max(0, y1); y2 = Min(m_h, y2);
609
610    if (x1 >= x2 || y1 >= y2)
611        return;
612
613    int i = dirties.Count();
614    if (!i)
615        dirties.add_front(new dirty_rect(x1, y1, x2 - 1, y2 - 1));
616    else if (i >= MAX_DIRTY)
617    {
618        dirties.add_front(new dirty_rect(x1, y1, x2 - 1, y2 - 1));
619        ReduceDirties();  // reduce to one dirty rectangle, we have to many
620    }
621    else
622    {
623      for (p=(dirty_rect *)dirties.first(); i>0; i--)
624      {
625
626        // check to see if this new rectangle completly encloses the check rectangle
627        if (x1<=p->dx1 && y1<=p->dy1 && x2>=p->dx2+1 && y2>=p->dy2+1)
628        {
629          dirty_rect *tmp=(dirty_rect*) p->Next();
630          dirties.unlink(p);
631          delete p;
632          if (!dirties.first())
633              i=0;
634          else p=tmp;
635        }
636        else if (!(x2 - 1 <p->dx1 || y2 - 1 <p->dy1 || x1>p->dx2 || y1>p->dy2))
637        {
638
639
640
641/*          if (x1<=p->dx1) { a+=p->dx1-x1; ax1=x1; } else ax1=p->dx1;
642          if (y1<=p->dy1) { a+=p->dy1-y1; ay1=y1; } else ay1=p->dy1;
643          if (x2 - 1 >=p->dx2) { a+=x2 - 1 -p->dx2; ax2=x2 - 1; } else ax2=p->dx2;
644          if (y2 - 1 >=p->dy2) { a+=y2 - 1 -p->dy2; ay2=y2 - 1; } else ay2=p->dy2;
645
646      if (a<50)
647      { p->dx1=ax1;                         // then expand the dirty
648        p->dy1=ay1;
649        p->dx2=ax2;
650        p->dy2=ay2;
651        return ;
652      }
653      else */
654            {
655              if (x1<p->dx1)
656                AddDirty(x1, Max(y1, p->dy1), p->dx1, Min(y2, p->dy2 + 1));
657              if (x2>p->dx2+1)
658                AddDirty(p->dx2+1, Max(y1, p->dy1), x2, Min(y2, p->dy2 + 1));
659              if (y1<p->dy1)
660                AddDirty(x1, y1, x2, p->dy1);
661              if (y2 - 1>p->dy2)
662                AddDirty(x1, p->dy2+1, x2, y2);
663              return ;
664            }
665            p=(dirty_rect *)p->Next();
666          } else p=(dirty_rect *)p->Next();
667
668      }
669      CHECK(x1 < x2 && y1 < y2);
670      dirties.add_end(new dirty_rect(x1, y1, x2 - 1, y2 - 1));
671    }
672}
673
674void image::Bar(vec2i p1, vec2i p2, uint8_t color)
675{
676    if (p1.x > p2.x || p1.y > p2.y)
677        return;
678    if (m_special)
679    {
680        p1.x = m_special->bound_x1(p1.x);
681        p1.y = m_special->bound_y1(p1.y);
682        p2.x = m_special->bound_x2(p2.x + 1) - 1;
683        p2.y = m_special->bound_y2(p2.y + 1) - 1;
684    }
685    else
686    {
687        p1.x = Max(p1.x, 0);
688        p1.y = Max(p1.y, 0);
689        p2.x = Min(p2.x, m_size.x - 1);
690        p2.y = Min(p2.y, m_size.y - 1);
691    }
692    if (p2.x < 0 || p2.y < 0 || p1.x >= m_size.x || p1.y >= m_size.y
693         || p2.x < p1.x || p2.y < p1.y)
694        return;
695
696    Lock();
697    for (int y = p1.y; y <= p2.y; y++)
698        memset(scan_line(y) + p1.x, color, (p2.x - p1.x + 1));
699    Unlock();
700    AddDirty(p1.x, p1.y, p2.x + 1, p2.y + 1);
701}
702
703void image::xor_bar  (int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t color)
704{
705  int16_t y, x;
706  if (x1>x2 || y1>y2) return ;
707  if (m_special)
708  { x1=m_special->bound_x1(x1);
709    y1=m_special->bound_y1(y1);
710    x2=m_special->bound_x2(x2+1)-1;
711    y2=m_special->bound_y2(y2+1)-1;
712  }
713  else
714  { if (x1<0) x1=0;
715    if (y1<0) y1=0;
716    if (x2>=m_size.x)  x2=m_size.x-1;
717    if (y2>=m_size.y) y2=m_size.y-1;
718  }
719  if (x2<0 || y2<0 || x1>=m_size.x || y1>=m_size.y || x2<x1 || y2<y1)
720    return ;
721
722  Lock();
723  uint8_t *sl=scan_line(y1)+x1;
724  for (y=y1; y<=y2; y++)
725  {
726    uint8_t *s=sl;
727    for (x=x1; x<=x2; x++, s++)
728      *s=(*s)^color;
729    sl+=m_size.x;
730  }
731  Unlock();
732
733  AddDirty(x1, y1, x2 + 1, y2 + 1);
734}
735
736
737void image::unpack_scanline(int16_t line, char bitsperpixel)
738{
739  int16_t x;
740  uint8_t *sl, *ex, mask, bt, sh;
741  ex=(uint8_t *)malloc(m_size.x);
742
743  Lock();
744  sl=scan_line(line);
745  memcpy(ex, sl, m_size.x);
746  Unlock();
747
748  if (bitsperpixel==1)      { mask=128;           bt=8; }
749  else if (bitsperpixel==2) { mask=128+64;        bt=4; }
750  else                 {  mask=128+64+32+16; bt=2; }
751
752  for (x=0; x<m_size.x; x++)
753  { sh=((x%bt)<<(bitsperpixel-1));
754    sl[x]=(ex[x/bt]&(mask>>sh))>>(bt-sh-1);
755  }
756
757  free((char *)ex);
758}
759
760void image::dither(palette *pal)
761{
762  int16_t x, y, j;
763  uint8_t dt_matrix[]={ 0,  136, 24, 170,
764           68, 204, 102, 238,
765           51, 187, 17, 153,
766           119, 255, 85, 221};
767
768  uint8_t *sl;
769  Lock();
770  for (y = 0; y < m_size.y; y++)
771  {
772    sl=scan_line(y);
773    for (j=y%4, x=0; x < m_size.x; x++)
774      sl[x] = (pal->red(sl[x]) > dt_matrix[j * 4 + (x & 3)]) ? 255 : 0;
775  }
776  Unlock();
777}
778
779void image_descriptor::ClearDirties()
780{
781    dirty_rect *dr = (dirty_rect *)dirties.first();
782    while (dr)
783    {
784        dirties.unlink(dr);
785        delete dr;
786        dr = (dirty_rect *)dirties.first();
787    }
788}
789
790void image::Scale(vec2i new_size)
791{
792    vec2i old_size = m_size;
793    uint8_t *im = (uint8_t *)malloc(old_size.x * old_size.y);
794    Lock();
795    memcpy(im, scan_line(0), old_size.x * old_size.y);
796
797    DeletePage();
798    MakePage(new_size, NULL);
799    m_size = new_size; // set the new height and width
800
801    uint8_t *sl1, *sl2;
802    int y, y2, x2;
803    double yc, xc, yd, xd;
804
805    yc = (double)old_size.y / (double)new_size.y;
806    xc = (double)old_size.x / (double)new_size.x;
807    for (y2 = 0, yd = 0; y2 < new_size.y; yd += yc, y2++)
808    {
809        y = (int)yd;
810        sl1 = im + y * old_size.x;
811        sl2 = scan_line(y2);
812        for (xd = 0, x2 = 0; x2 < new_size.x; xd += xc, x2++)
813            sl2[x2] = sl1[(int)xd];
814    }
815    free(im);
816    if (m_special)
817        m_special->Resize(new_size);
818    Unlock();
819}
820
821void image::scroll(int16_t x1, int16_t y1, int16_t x2, int16_t y2, int16_t xd, int16_t yd)
822{
823  CHECK(x1>=0 && y1>=0 && x1<x2 && y1<y2 && x2<m_size.x && y2<m_size.y);
824  if (m_special)
825  {
826    int cx1, cy1, cx2, cy2;
827    m_special->GetClip(cx1, cy1, cx2, cy2);
828    x1=Max(x1, cx1); y1=Max(cy1, y1); x2=Min(x2, cx2 - 1); y2=Min(y2, cy2 - 1);
829  }
830  int16_t xsrc, ysrc, xdst, ydst, xtot=x2-x1-abs(xd)+1, ytot, xt;
831  uint8_t *src, *dst;
832  if (xd<0) { xsrc=x1-xd; xdst=x1; } else { xsrc=x2-xd; xdst=x2; }
833  if (yd<0) { ysrc=y1-yd; ydst=y1; } else { ysrc=y2-yd; ydst=y2; }
834  for (ytot=y2-y1-abs(yd)+1; ytot; ytot--)
835  { src=scan_line(ysrc)+xsrc;
836    dst=scan_line(ydst)+xdst;
837    if (xd<0)
838      for (xt = 0; xt < xtot; xt++)
839        *dst++ = *src++;
840      else for (xt = 0; xt < xtot; xt++)
841        *dst-- = *src--;
842    if (yd<0) { ysrc++; ydst++; } else { ysrc--; ydst--; }
843  }
844  AddDirty(x1, y1, x2 + 1, y2 + 1);
845}
846
847
848image *image::create_smooth(int16_t smoothness)
849{
850  int16_t i, j, k, l, t, d;
851  image *im;
852  CHECK(smoothness>=0);
853  if (!smoothness) return NULL;
854  d=smoothness*2+1;
855  d=d*d;
856  im=new image(m_size);
857  for (i=0; i<m_size.x; i++)
858    for (j=0; j<m_size.y; j++)
859    {
860      for (t=0, k=-smoothness; k<=smoothness; k++)
861    for (l=-smoothness; l<=smoothness; l++)
862      if (i+k>smoothness && i+k<m_size.x-smoothness && j+l<m_size.y-smoothness && j+l>smoothness)
863        t+=Pixel(vec2i(i+k, j+l));
864      else t+=Pixel(vec2i(i, j));
865      im->PutPixel(vec2i(i, j), t/d);
866    }
867  return im;
868}
869
870void image::WidgetBar(vec2i p1, vec2i p2,
871                      uint8_t light, uint8_t med, uint8_t dark)
872{
873    Line(p1, vec2i(p2.x, p1.y), light);
874    Line(p1, vec2i(p1.x, p2.y), light);
875    Line(vec2i(p2.x, p1.y + 1), p2, dark);
876    Line(vec2i(p1.x + 1, p2.y), vec2i(p2.x - 1, p2.y - 1), dark);
877    Bar(p1 + vec2i(1, 1), p2 - vec2i(1, 1), med);
878}
879
880class fill_rec
881{
882public :
883  int16_t x, y;
884  fill_rec *last;
885  fill_rec(int16_t X, int16_t Y, fill_rec *Last)
886  { x=X; y=Y; last=Last; }
887} ;
888
889void image::flood_fill(int16_t x, int16_t y, uint8_t color)
890{
891  uint8_t *sl, *above, *below;
892  fill_rec *recs=NULL, *r;
893  uint8_t fcolor;
894  Lock();
895  sl=scan_line(y);
896  fcolor=sl[x];
897  if (fcolor==color) return ;
898  do
899  {
900    if (recs)
901    { r=recs;
902      recs=recs->last;
903      x=r->x; y=r->y;
904      delete r;
905    }
906    sl=scan_line(y);
907    if (sl[x]==fcolor)
908    {
909      while (sl[x]==fcolor && x>0) x--;
910      if (sl[x]!=fcolor) x++;
911      if (y>0)
912      {
913        above=scan_line(y-1);
914        if (above[x]==fcolor)
915        { r=new fill_rec(x, y-1, recs);
916          recs=r;
917        }
918      }
919      if (y<m_size.y-1)
920      {
921        above=scan_line(y+1);
922        if (above[x]==fcolor)
923        { r=new fill_rec(x, y+1, recs);
924          recs=r;
925        }
926      }
927
928
929
930      do
931      {
932        sl[x]=color;
933        if (y>0)
934        { above=scan_line(y-1);
935          if (x>0 && above[x-1]!=fcolor && above[x]==fcolor)
936          { r=new fill_rec(x, y-1, recs);
937            recs=r;
938          }
939        }
940        if (y<m_size.y-1)
941        { below=scan_line(y+1);
942          if (x>0 && below[x-1]!=fcolor && below[x]==fcolor)
943          { r=new fill_rec(x, y+1, recs);
944            recs=r;
945          }
946        }
947        x++;
948      } while (sl[x]==fcolor && x<m_size.x);
949      x--;
950      if (y>0)
951      {
952        above=scan_line(y-1);
953        if (above[x]==fcolor)
954        { r=new fill_rec(x, y-1, recs);
955          recs=r;
956        }
957      }
958      if (y<m_size.y-1)
959      {
960        above=scan_line(y+1);
961        if (above[x]==fcolor)
962        { r=new fill_rec(x, y+1, recs);
963          recs=r;
964        }
965      }
966    }
967  } while (recs);
968  Unlock();
969}
970
971
972#define LED_L 5
973#define LED_H 5
974void image::burn_led(int16_t x, int16_t y, int32_t num, int16_t color, int16_t scale)
975{
976  char st[100];
977  int16_t ledx[]={ 1, 2, 1, 2, 3, 3, 3, 3, 1, 2, 0, 0, 0, 0};
978  int16_t ledy[]={ 3, 3, 0, 0, 1, 2, 4, 6, 7, 7, 4, 6, 1, 2};
979
980  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,
981             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};
982  int16_t xx, yy, zz;
983  sprintf(st, "%8ld", (long int)num);
984  for (xx=0; xx<8; xx++)
985  {
986    if (st[xx]!=' ')
987    {
988      if (st[xx]=='-')
989    zz=10;
990      else
991    zz=st[xx]-'0';
992      for (yy=0; yy<7; yy++)
993    if ((1<<yy)&dig[zz])
994      Line(vec2i(x+ledx[yy*2]*scale, y+ledy[yy*2]*scale),
995           vec2i(x+ledx[yy*2+1]*scale, y+ledy[yy*2+1]*scale), color);
996    }
997    x+=6*scale;
998  }
999}
1000
1001uint8_t dither_matrix[]={ 0,  136, 24, 170,
1002             68, 204, 102, 238,
1003             51, 187, 17, 153,
1004             119, 255, 85, 221};
1005
1006image *image::copy_part_dithered (int16_t x1, int16_t y1, int16_t x2, int16_t y2)
1007{
1008  int x, y, cx1, cy1, cx2, cy2, ry, rx, bo, dity, ditx;
1009  image *ret;
1010  uint8_t *sl1, *sl2;
1011  GetClip(cx1, cy1, cx2, cy2);
1012  if (y1<cy1) y1=cy1;
1013  if (x1<cx1) x1=cx1;
1014  if (y2>cy2 - 1) y2=cy2 - 1;
1015  if (x2>cx2 - 1) x2=cx2 - 1;
1016  CHECK(x2>=x1 && y2>=y1);
1017  if (x2<x1 || y2<y1) return NULL;
1018  ret=new image(vec2i((x2-x1+8)/8, (y2-y1+1)));
1019  if (!last_loaded())
1020    ret->clear();
1021  else
1022  {
1023    ret->Lock();
1024    Lock();
1025    for (y=y1, ry=0, dity=(y1%4)*4; y<=y2; y++, ry++)
1026    {
1027      sl1=ret->scan_line(ry);     // sl1 is the scan linefo the return image
1028      sl2=scan_line(y);          // sl2 is the orginal image scan line
1029      memset(sl1, 0, (x2-x1+8)/8);
1030      for (bo=7, rx=0, x=x1, ditx=x1%4; x<=x2; x++)
1031      {
1032        if (last_loaded()->red(sl2[x])>dither_matrix[ditx+dity])
1033          sl1[rx]|=1<<bo;
1034        if (bo!=0)
1035      bo--;
1036        else
1037        {
1038        rx++;
1039      bo=7;
1040        }
1041        ditx+=1; if (ditx>3) ditx=0;
1042      }
1043      dity+=4; if (dity>12) dity=0;
1044    }
1045    Unlock();
1046    ret->Unlock();
1047  }
1048  return ret;
1049}
1050
1051void image::FlipX()
1052{
1053    Lock();
1054    for (int y = 0; y < m_size.y; y++)
1055    {
1056        uint8_t *sl = scan_line(y);
1057        for (int x = 0; x < m_size.x / 2; x++)
1058        {
1059            uint8_t tmp = sl[x];
1060            sl[x] = sl[m_size.x - 1 - x];
1061            sl[m_size.x - 1 - x] = tmp;
1062        }
1063    }
1064    Unlock();
1065}
1066
1067void image::FlipY()
1068{
1069    Lock();
1070    for (int y = 0; y < m_size.y / 2; y++)
1071    {
1072        uint8_t *sl1 = scan_line(y);
1073        uint8_t *sl2 = scan_line(m_size.y - 1 - y);
1074        for (int x = 0; x < m_size.x; x++)
1075        {
1076            uint8_t tmp = sl1[x];
1077            sl1[x] = sl2[x];
1078            sl2[x] = tmp;
1079        }
1080    }
1081    Unlock();
1082}
1083
Note: See TracBrowser for help on using the repository browser.