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

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

style: remove trailing spaces, fix copyright statements.

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