[56] | 1 | /* |
---|
| 2 | * Abuse - dark 2D side-scrolling platform game |
---|
| 3 | * Copyright (c) 1995 Crack dot Com |
---|
[494] | 4 | * Copyright (c) 2005-2011 Sam Hocevar <sam@hocevar.net> |
---|
[56] | 5 | * |
---|
| 6 | * This software was released into the Public Domain. As with most public |
---|
[555] | 7 | * domain software, no warranty is made or implied by Crack dot Com, by |
---|
| 8 | * Jonathan Clark, or by Sam Hocevar. |
---|
[56] | 9 | */ |
---|
| 10 | |
---|
[555] | 11 | #if defined HAVE_CONFIG_H |
---|
| 12 | # include "config.h" |
---|
| 13 | #endif |
---|
[56] | 14 | |
---|
[512] | 15 | #include "common.h" |
---|
| 16 | |
---|
[481] | 17 | #include "supmorph.h" |
---|
| 18 | #include "specs.h" |
---|
[541] | 19 | #include "transimage.h" |
---|
[481] | 20 | #include "timing.h" |
---|
| 21 | #include "filter.h" |
---|
| 22 | #include "video.h" |
---|
| 23 | #include "jrand.h" |
---|
[2] | 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 | |
---|
[541] | 29 | super_morph::super_morph(TransImage *hint1, TransImage *hint2, |
---|
[124] | 30 | int aneal_steps, void (*stat_fun)(int)) |
---|
[2] | 31 | { |
---|
[527] | 32 | int x,y,w1=hint1->Size().x, |
---|
| 33 | h1=hint1->Size().y, |
---|
| 34 | w2=hint2->Size().x, |
---|
| 35 | h2=hint2->Size().y; |
---|
[2] | 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 | |
---|
[527] | 45 | dp=hint1->Data(); |
---|
[494] | 46 | for (y=0; y<h1; y++) |
---|
[2] | 47 | { |
---|
| 48 | x=0; |
---|
| 49 | while (x<w1) |
---|
[124] | 50 | { |
---|
[2] | 51 | x+=*dp; // skip over space |
---|
| 52 | dp++; |
---|
| 53 | if (x<w1) |
---|
| 54 | { |
---|
[124] | 55 | int rl=*(dp++); |
---|
| 56 | while (rl--) { hints1[*(dp++)]++; x++; } |
---|
[2] | 57 | } |
---|
| 58 | } |
---|
| 59 | } |
---|
| 60 | |
---|
| 61 | // hint2 image2 |
---|
[527] | 62 | dp=hint2->Data(); |
---|
[494] | 63 | for (y=0; y<h2; y++) |
---|
[2] | 64 | { |
---|
| 65 | x=0; |
---|
| 66 | while (x<w2) |
---|
[124] | 67 | { |
---|
[2] | 68 | x+=*dp; // skip over space |
---|
| 69 | dp++; |
---|
| 70 | if (x<w2) |
---|
| 71 | { |
---|
[124] | 72 | int rl=*(dp++); |
---|
| 73 | while (rl--) { hints2[*(dp++)]++; x++; } |
---|
[2] | 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 | |
---|
[494] | 85 | for (y=0; y<256; y++,h1p++,h2p++) |
---|
[2] | 86 | if (*h1p) |
---|
| 87 | { |
---|
[124] | 88 | if (*h2p==0) |
---|
[2] | 89 | { |
---|
[124] | 90 | t=0; |
---|
| 91 | return ; |
---|
[2] | 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]; |
---|
[124] | 98 | hint_color[total_hints++]=y; |
---|
[2] | 99 | } |
---|
| 100 | |
---|
| 101 | t=start; |
---|
[129] | 102 | movers=(unsigned char *)malloc(t*4); |
---|
[124] | 103 | |
---|
| 104 | |
---|
[2] | 105 | /**************** Now scan the images again setup hints *********************/ |
---|
[527] | 106 | dp=hint1->Data(); |
---|
[494] | 107 | for (y=0; y<h1; y++) |
---|
[2] | 108 | { |
---|
| 109 | x=0; |
---|
| 110 | while (x<w1) |
---|
[124] | 111 | { |
---|
[2] | 112 | x+=*dp; // skip over space |
---|
| 113 | dp++; |
---|
| 114 | if (x<w1) |
---|
| 115 | { |
---|
[124] | 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 | } |
---|
[2] | 124 | } |
---|
| 125 | } |
---|
[124] | 126 | } |
---|
[2] | 127 | |
---|
[527] | 128 | dp=hint2->Data(); |
---|
[494] | 129 | for (y=0; y<h2; y++) |
---|
[2] | 130 | { |
---|
| 131 | x=0; |
---|
| 132 | while (x<w2) |
---|
[124] | 133 | { |
---|
[2] | 134 | x+=*dp; // skip over space |
---|
| 135 | dp++; |
---|
| 136 | if (x<w2) |
---|
| 137 | { |
---|
[124] | 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 | } |
---|
[2] | 146 | } |
---|
| 147 | } |
---|
[124] | 148 | } |
---|
[2] | 149 | |
---|
| 150 | /********* if hint sizes don't match duplicate the smaller until sizes are equal **********/ |
---|
[494] | 151 | for (start=0,x=0; x<total_hints; x++) |
---|
[2] | 152 | { |
---|
| 153 | y=hint_color[x]; |
---|
| 154 | int dups; |
---|
[494] | 155 | for (dp=movers+start1[y]*4,dups=totals[y]-hints1[y]; dups; dups--) |
---|
[2] | 156 | { |
---|
| 157 | *dp=*(dp-4); dp++; // copy previous x,y position |
---|
| 158 | *dp=*(dp-4); dp++; |
---|
[494] | 159 | dp+=2; |
---|
[2] | 160 | } |
---|
| 161 | start1[y]-=2*totals[y]-hints1[y]; // set the start back to the begining of hint range |
---|
| 162 | } |
---|
| 163 | |
---|
[494] | 164 | for (start=0,x=0; x<total_hints; x++) |
---|
[2] | 165 | { |
---|
| 166 | y=hint_color[x]; |
---|
| 167 | int dups; |
---|
[494] | 168 | for (dp=movers+start2[y]*4+2,dups=totals[y]-hints2[y]; dups; dups--) |
---|
[2] | 169 | { |
---|
| 170 | *dp=*(dp-4); dp++; // copy previous x,y position |
---|
| 171 | *dp=*(dp-4); dp++; |
---|
[494] | 172 | dp+=2; |
---|
[2] | 173 | } |
---|
| 174 | start2[y]-=hints2[y]; // set the start back to the begining of hint range |
---|
| 175 | } |
---|
| 176 | |
---|
| 177 | |
---|
[124] | 178 | /******* Now apply simulated annealing to solve for a smaller total distance ********/ |
---|
[2] | 179 | int rand_on=0; |
---|
[494] | 180 | for (y=0; y<aneal_steps; y++) |
---|
[2] | 181 | { |
---|
| 182 | if (stat_fun) |
---|
| 183 | stat_fun(y); |
---|
[124] | 184 | dp=movers; |
---|
[494] | 185 | for (x=0; x<total_hints; x++) |
---|
[2] | 186 | { |
---|
| 187 | int hc=hint_color[x]; |
---|
| 188 | int a,z=totals[hc]; |
---|
| 189 | unsigned char *range_start=dp; |
---|
[494] | 190 | for (a=0; a<z; a++,dp+=4) |
---|
[2] | 191 | { |
---|
[124] | 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 | } |
---|
[2] | 203 | } |
---|
| 204 | } |
---|
| 205 | |
---|
| 206 | smorph_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; |
---|
[129] | 211 | p=steps=(stepper *)malloc(sizeof(stepper)*m->t); |
---|
[2] | 212 | f_left=frames; |
---|
| 213 | frames--; |
---|
| 214 | t=m->t; |
---|
| 215 | w=m->w; h=m->h; |
---|
| 216 | |
---|
[494] | 217 | for (i=0; i<t; i++,p++) |
---|
[124] | 218 | { |
---|
[2] | 219 | x1=*(d++); |
---|
| 220 | y1=*(d++); |
---|
| 221 | x2=*(d++); |
---|
| 222 | y2=*(d++); |
---|
[124] | 223 | |
---|
[2] | 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++); |
---|
[124] | 229 | |
---|
[2] | 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 | |
---|
[129] | 254 | hole=(unsigned char *)malloc(w*h); |
---|
[2] | 255 | } |
---|
| 256 | |
---|
| 257 | |
---|
| 258 | |
---|
| 259 | |
---|
| 260 | |
---|
| 261 | int smorph_player::show(image *screen, int x, int y, color_filter *fil, palette *pal, |
---|
[124] | 262 | int blur_threshold) |
---|
| 263 | { |
---|
[2] | 264 | if (f_left) |
---|
| 265 | { |
---|
| 266 | int i,px,py,ix,iy; |
---|
[518] | 267 | int x1, y1, x2, y2; |
---|
| 268 | screen->GetClip(x1, y1, x2, y2); |
---|
| 269 | screen->AddDirty(x, y, x + w, y + h); |
---|
[2] | 270 | stepper *ss; |
---|
| 271 | memset(hole,0,w*h); |
---|
| 272 | unsigned char *paddr=(unsigned char *)pal->addr(); |
---|
[494] | 273 | for (ss=steps,i=0; i<t; i++,ss++) |
---|
[2] | 274 | { |
---|
| 275 | ix=(ss->x>>(16)); |
---|
| 276 | iy=(ss->y>>(16)); |
---|
| 277 | px=ix+x; |
---|
| 278 | py=iy+y; |
---|
[518] | 279 | if (px>=x1 && px < x2 && py>=y1 && py < y2) |
---|
[2] | 280 | { |
---|
| 281 | hole[ix+iy*w]=*(screen->scan_line(py)+px)=fil->lookup_color(ss->r>>(19), |
---|
[124] | 282 | ss->g>>(19), |
---|
| 283 | ss->b>>(19)); |
---|
[2] | 284 | } |
---|
| 285 | ss->x+=ss->dx; |
---|
| 286 | ss->y+=ss->dy; |
---|
| 287 | ss->r+=ss->dr; |
---|
| 288 | ss->g+=ss->dg; |
---|
[124] | 289 | ss->b+=ss->db; |
---|
[2] | 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; |
---|
[494] | 296 | for (iy=1; iy<h-1; iy++) // now scan the for holes to fill |
---|
[2] | 297 | { |
---|
[494] | 298 | for (ix=1; ix<w-1; ix++,ll++,tl++,nl++) |
---|
[2] | 299 | { |
---|
[518] | 300 | if (x+ix>=x1 && x+ix < x2 && y+iy>=y1 && y+iy < y2) |
---|
[124] | 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++; |
---|
[494] | 308 | if (*nl) t++; */ |
---|
[2] | 309 | |
---|
[124] | 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++); } |
---|
[494] | 313 | if (*(nl)) { t++; pa=paddr+(*nl)*3; r+=*(pa++); g+=*(pa++); b+=*(pa++); } |
---|
[2] | 314 | |
---|
[124] | 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_color(r>>3,g>>3,b>>3); |
---|
| 326 | } else *(tl)=*(screen->scan_line(y+iy)+x+ix)=0; // kill single pixels |
---|
[2] | 327 | } |
---|
[124] | 328 | else if (t>=3) |
---|
| 329 | *(tl)=*(screen->scan_line(y+iy)+x+ix)=fil->lookup_color((r/t)>>3,(g/t)>>3,(b/t)>>3); |
---|
| 330 | } |
---|
| 331 | } |
---|
[2] | 332 | ll+=2; |
---|
| 333 | tl+=2; |
---|
[124] | 334 | nl+=2; |
---|
[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 | |
---|
| 345 | main(int argc, char **argv) |
---|
| 346 | { |
---|
| 347 | image_init(); |
---|
| 348 | jrand_init(); |
---|
[124] | 349 | FILE *fp=fopen("art/mrphmask.spe","rb"); |
---|
[2] | 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); |
---|
[124] | 356 | color_filter *fil=new color_filter(sd.find(SPEC_COLOR_TABLE),fp); |
---|
[2] | 357 | |
---|
| 358 | int steps=atoi(argv[1]); |
---|
| 359 | if (steps<2) steps=50; |
---|
[541] | 360 | TransImage *hh1=new TransImage(h1,"hint1"),*hh2=new TransImage(h2,"hint2"); |
---|
[2] | 361 | |
---|
| 362 | time_marker time1; |
---|
[124] | 363 | super_morph sm(hh1,hh2,steps); |
---|
[2] | 364 | int frames=atoi(argv[2]); |
---|
| 365 | if (frames<2) frames=16; |
---|
[124] | 366 | smorph_player sp(&sm,pal,i1,i2,frames,-1); |
---|
[2] | 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); |
---|
[124] | 376 | while (sp.show(screen,30,30,fil,pal)) |
---|
[2] | 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 | |
---|