supmorph.c 8.5 KB

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