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

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

imlib: minor refactoring.

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