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

Last change on this file since 682 was 682, checked in by Sam Hocevar, 8 years ago

core: rename vec2i to ivec2 and update matrix.h from Lol Engine.

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