source: abuse/trunk/src/imlib/supmorph.cpp @ 579

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

imlib: refactor the Filter and ColorFilter? classes.

File size: 8.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, 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 "common.h"
16
17#include "supmorph.h"
18#include "specs.h"
19#include "transimage.h"
20#include "timing.h"
21#include "filter.h"
22#include "video.h"
23#include "jrand.h"
24
25#define p_swap(x,y) { x^=y; y^=x; x^=y; }
26#define p_dist(x1,y1,x2,y2) (((int)(x1)-(int)x2)*((int)(x1)-(int)x2)+      \
27                             ((int)(y1)-(int)y2)*((int)(y1)-(int)y2))
28
29super_morph::super_morph(TransImage *hint1, TransImage *hint2,
30             int aneal_steps, void (*stat_fun)(int))
31{
32  int x,y,w1=hint1->Size().x,
33          h1=hint1->Size().y,
34          w2=hint2->Size().x,
35          h2=hint2->Size().y;
36  if (w1>w2) w=w1; else w=w2;
37  if (h1>h2) h=h1; else h=h2;
38  unsigned char *dp;
39
40  /************************ count up the number of hints ****************************/
41  unsigned short hints1[256],hints2[256];
42  memset(hints1,0,256*2);
43  memset(hints2,0,256*2);
44
45  dp=hint1->Data();
46  for (y=0; y<h1; y++)
47  {
48    x=0;
49    while (x<w1)
50    {
51      x+=*dp;      // skip over space
52      dp++;
53      if (x<w1)
54      {
55    int rl=*(dp++);
56    while (rl--) { hints1[*(dp++)]++; x++; }
57      }
58    }
59  }
60
61  // hint2 image2
62  dp=hint2->Data();
63  for (y=0; y<h2; y++)
64  {
65    x=0;
66    while (x<w2)
67    {
68      x+=*dp;      // skip over space
69      dp++;
70      if (x<w2)
71      {
72    int rl=*(dp++);
73    while (rl--) { hints2[*(dp++)]++; x++; }
74      }
75    }
76  }
77
78
79  /****************** now sum up hints and alloc memory for movers *************/
80  unsigned short start1[256],start2[256],
81                 totals[256],
82                 start=0,*h1p=hints1,*h2p=hints2;
83  unsigned char hint_color[256],total_hints=0;
84
85  for (y=0; y<256; y++,h1p++,h2p++)
86    if (*h1p)
87    {
88      if (*h2p==0)
89      {
90    t=0;
91    return ;
92      }
93      start1[y]=start2[y]=start;       // specify start of hint range
94      if (*h1p>*h2p)
95        totals[y]=*h1p;
96      else totals[y]=*h2p;
97      start+=totals[y];
98      hint_color[total_hints++]=y;
99    }
100
101  t=start;
102  movers=(unsigned char *)malloc(t*4);
103
104
105  /**************** Now scan the images again setup hints *********************/
106  dp=hint1->Data();
107  for (y=0; y<h1; y++)
108  {
109    x=0;
110    while (x<w1)
111    {
112      x+=*dp;      // skip over space
113      dp++;
114      if (x<w1)
115      {
116    int rl=*(dp++);
117    while (rl--)
118    {
119      int maddr=(start1[*(dp++)]++)*4;
120      movers[(maddr++)]=x;
121      movers[maddr]=y;
122      x++;
123    }
124      }
125    }
126  }
127
128  dp=hint2->Data();
129  for (y=0; y<h2; y++)
130  {
131    x=0;
132    while (x<w2)
133    {
134      x+=*dp;      // skip over space
135      dp++;
136      if (x<w2)
137      {
138    int rl=*(dp++);
139    while (rl--)
140    {
141      int maddr=(start2[*(dp++)]++)*4+2;
142      movers[(maddr++)]=x;
143      movers[maddr]=y;
144      x++;
145    }
146      }
147    }
148  }
149
150  /********* if hint sizes don't match duplicate the smaller until sizes are equal **********/
151  for (start=0,x=0; x<total_hints; x++)
152  {
153    y=hint_color[x];
154    int dups;
155    for (dp=movers+start1[y]*4,dups=totals[y]-hints1[y]; dups; dups--)
156    {
157      *dp=*(dp-4); dp++;      // copy previous x,y position
158      *dp=*(dp-4); dp++;
159      dp+=2;
160    }
161    start1[y]-=2*totals[y]-hints1[y];        // set the start back to the begining of hint range
162  }
163
164  for (start=0,x=0; x<total_hints; x++)
165  {
166    y=hint_color[x];
167    int dups;
168    for (dp=movers+start2[y]*4+2,dups=totals[y]-hints2[y]; dups; dups--)
169    {
170      *dp=*(dp-4); dp++;      // copy previous x,y position
171      *dp=*(dp-4); dp++;
172      dp+=2;
173    }
174    start2[y]-=hints2[y];        // set the start back to the begining of hint range
175  }
176
177
178  /******* Now apply simulated annealing to solve for a smaller total distance ********/
179  int rand_on=0;
180  for (y=0; y<aneal_steps; y++)
181  {
182    if (stat_fun)
183      stat_fun(y);
184    dp=movers;
185    for (x=0; x<total_hints; x++)
186    {
187      int hc=hint_color[x];
188      int a,z=totals[hc];
189      unsigned char *range_start=dp;
190      for (a=0; a<z; a++,dp+=4)
191      {
192    unsigned char *swap=range_start+(rtable[((rand_on++)&(RAND_TABLE_SIZE-1))]%z)*4;
193    int d_old=p_dist(dp[0],dp[1],dp[2],dp[3])+p_dist(swap[0],swap[1],swap[2],swap[3]);
194    int d_new=p_dist(dp[0],dp[1],swap[2],swap[3])+p_dist(swap[0],swap[1],dp[2],dp[3]);
195    if (d_new<d_old)
196    {
197      unsigned char s;
198      s=swap[2]; swap[2]=dp[2]; dp[2]=s;
199      s=swap[3]; swap[3]=dp[3]; dp[3]=s;
200    }
201      }
202    }
203  }
204}
205
206smorph_player::smorph_player(super_morph *m, palette *pal, image *i1, image *i2, int frames, int dir)
207{
208  int i,x1,y1,x2,y2;
209  unsigned char *d=m->movers,*paddr=(unsigned char *)pal->addr(),*pa;
210  stepper *p;
211  p=steps=(stepper *)malloc(sizeof(stepper)*m->t);
212  f_left=frames;
213  frames--;
214  t=m->t;
215  w=m->w; h=m->h;
216
217  for (i=0; i<t; i++,p++)
218  {
219    x1=*(d++);
220    y1=*(d++);
221    x2=*(d++);
222    y2=*(d++);
223
224    unsigned char r1,g1,b1,r2,g2,b2;
225    pa=paddr+(int)(*(i1->scan_line(y1)+x1))*3;
226    r1=*(pa++);
227    g1=*(pa++);
228    b1=*(pa++);
229
230    pa=paddr+(int)(*(i2->scan_line(y2)+x2))*3;
231    r2=*(pa++);
232    g2=*(pa++);
233    b2=*(pa++);
234
235    p->r=r1<<16;
236    p->g=g1<<16;
237    p->b=b1<<16;
238
239    p->dr=(long)(((int)r2-(int)r1)<<16)/frames;
240    p->dg=(long)(((int)g2-(int)g1)<<16)/frames;
241    p->db=(long)(((int)b2-(int)b1)<<16)/frames;
242
243    if (dir<0)
244    {
245      x1=w-x1-1;
246      x2=w-x2-1;
247    }
248    p->dx=((x2-x1)<<16)/frames;
249    p->dy=((y2-y1)<<16)/frames;
250    p->x=x1<<16;
251    p->y=y1<<16;
252  }
253
254  hole=(unsigned char *)malloc(w*h);
255}
256
257
258
259
260
261int smorph_player::show(image *screen, int x, int y, ColorFilter *fil, palette *pal,
262            int blur_threshold)
263{
264  if (f_left)
265  {
266    int i,px,py,ix,iy;
267    int x1, y1, x2, y2;
268    screen->GetClip(x1, y1, x2, y2);
269    screen->AddDirty(x, y, x + w, y + h);
270    stepper *ss;
271    memset(hole,0,w*h);
272    unsigned char *paddr=(unsigned char *)pal->addr();
273    for (ss=steps,i=0; i<t; i++,ss++)
274    {
275      ix=(ss->x>>(16));
276      iy=(ss->y>>(16));
277      px=ix+x;
278      py=iy+y;
279      if (px>=x1 && px < x2 && py>=y1 && py < y2)
280      {
281        hole[ix+iy*w]=*(screen->scan_line(py)+px)=fil->Lookup(ss->r>>(19),
282                                    ss->g>>(19),
283                                    ss->b>>(19));
284      }
285      ss->x+=ss->dx;
286      ss->y+=ss->dy;
287      ss->r+=ss->dr;
288      ss->g+=ss->dg;
289      ss->b+=ss->db;
290    }
291    f_left--;
292    if (!f_left)    // skip hole fills and smoothing on last frame
293      return 1;
294
295    unsigned char *ll=hole+1,*tl=hole+w+1,*nl=hole+w*2+1;
296    for (iy=1; iy<h-1; iy++)    // now scan the for holes to fill
297    {
298      for (ix=1; ix<w-1; ix++,ll++,tl++,nl++)
299      {
300    if (x+ix>=x1 && x+ix < x2 && y+iy>=y1 && y+iy < y2)
301    {
302      int t=0;
303      unsigned char *pa;
304      int r=0,g=0,b=0;
305/*      if (*(tl-1)) t++;
306      if (*(tl+1)) t++;
307      if (*ll) t++;
308      if (*nl) t++; */
309
310      if (*(tl-1)) { t++; pa=paddr+(*(tl-1))*3; r+=*(pa++); g+=*(pa++); b+=*(pa++); }
311      if (*(tl+1)) { t++; pa=paddr+(*(tl+1))*3; r+=*(pa++); g+=*(pa++); b+=*(pa++); }
312      if (*(ll)) { t++; pa=paddr+(*ll)*3; r+=*(pa++); g+=*(pa++); b+=*(pa++); }
313      if (*(nl)) { t++; pa=paddr+(*nl)*3; r+=*(pa++); g+=*(pa++); b+=*(pa++); }
314
315      if (*tl)
316      {
317        if (t)
318        {
319          pa=paddr+(*tl)*3;
320          r/=t; g/=t; b/=t;
321          int dist=((int)(*pa)-r)*((int)(*pa)-r); pa++;
322          dist+=((int)(*pa)-g)*((int)(*pa)-g); pa++;
323          dist+=((int)(*pa)-b)*((int)(*pa)-b);
324          if (dist>blur_threshold)
325            *(tl)=*(screen->scan_line(y+iy)+x+ix)=fil->Lookup(r>>3,g>>3,b>>3);
326        } else *(tl)=*(screen->scan_line(y+iy)+x+ix)=0; // kill single pixels
327      }
328      else if (t>=3)
329        *(tl)=*(screen->scan_line(y+iy)+x+ix)=fil->Lookup((r/t)>>3,(g/t)>>3,(b/t)>>3);
330    }
331      }
332      ll+=2;
333      tl+=2;
334      nl+=2;
335    }
336    return 1;
337  } else return 0;
338}
339
340
341
342
343/*void free_up_memory() { printf("you're screwed\n"); }
344
345main(int argc, char **argv)
346{
347  image_init();
348  jrand_init();
349  FILE *fp=fopen("art/mrphmask.spe","rb");
350  spec_directory sd(fp);
351  image *h1=new image(sd.find("20 h"),fp),
352        *h2=new image(sd.find("1h"),fp),
353        *i1=new image(sd.find("20"),fp),
354        *i2=new image(sd.find("1"),fp);
355  palette *pal=new palette(sd.find(SPEC_PALETTE),fp);
356  color_filter *fil=new color_filter(sd.find(SPEC_COLOR_TABLE),fp);
357
358  int steps=atoi(argv[1]);
359  if (steps<2) steps=50;
360  TransImage *hh1=new TransImage(h1,"hint1"),*hh2=new TransImage(h2,"hint2");
361
362  time_marker time1;
363  super_morph sm(hh1,hh2,steps);
364  int frames=atoi(argv[2]);
365  if (frames<2) frames=16;
366  smorph_player sp(&sm,pal,i1,i2,frames,-1);
367
368  time_marker time2;
369  printf("time = %lf\n",time2.diff_time(&time1));
370
371  set_mode(19,argc,argv);
372  pal->load();
373  i1->put_image(screen,30,30);
374  update_dirty(screen);
375  sleep(2);
376  while (sp.show(screen,30,30,fil,pal))
377  { update_dirty(screen);
378    screen->bar(30,30,30+sp.w,30+sp.h,0);
379  }
380  sleep(2);
381  close_graphics();
382}*/
383
384
Note: See TracBrowser for help on using the repository browser.