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

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

ps3: make everything compile on the PS3. Of course, nothing links yet
because so much support is missing.

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