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

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

imlib: started refactoring the dirty rectangle system.

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