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

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

imlib: refactor dirty_rect clipping coordiantes so that the upper
bound is no longer inclusive. It will make things easier in the future.

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