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

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

imlib: refactor GetClip?, SetClip? etc. to use vec2i.

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