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

Last change on this file since 523 was 523, checked in by Sam Hocevar, 12 years ago

imlib: remove dead code.

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