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

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

imlib: image::Pixel and image::PutPixel? now use vec2i arguments.

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