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

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

starting GetClip? refactoring

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