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

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

imlib: remove dead code.

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