summaryrefslogtreecommitdiff
path: root/src/powder.c
diff options
context:
space:
mode:
authorFelix Wallin <nibbler.v1@gmail.com>2010-10-02 15:59:24 (GMT)
committer Felix Wallin <nibbler.v1@gmail.com>2010-10-02 15:59:24 (GMT)
commit6e81c2a88cc9a2bda3189b01b4edd5da1a0bd0a8 (patch)
treeb7b54fb71ec0919079e0b949bc1ba8bd090c6470 /src/powder.c
parent0a9d6adca47eae3b2c06c958a69352adeda4daca (diff)
downloadpowder-6e81c2a88cc9a2bda3189b01b4edd5da1a0bd0a8.zip
powder-6e81c2a88cc9a2bda3189b01b4edd5da1a0bd0a8.tar.gz
Added reflection, thanks to Skylark
Diffstat (limited to 'src/powder.c')
-rw-r--r--src/powder.c305
1 files changed, 236 insertions, 69 deletions
diff --git a/src/powder.c b/src/powder.c
index 15a2afe..f5da09c 100644
--- a/src/powder.c
+++ b/src/powder.c
@@ -22,80 +22,86 @@ int pfree;
unsigned pmap[YRES][XRES];
unsigned cb_pmap[YRES][XRES];
-int try_move(int i, int x, int y, int nx, int ny)
+static int eval_move(int pt, int nx, int ny, unsigned *rr)
{
unsigned r;
if(nx<0 || ny<0 || nx>=XRES || ny>=YRES)
return 0;
- if(x==nx && y==ny)
- return 1;
- r = pmap[ny][nx];
+
+ r = pmap[ny][nx];
if(r && (r>>8)<NPART)
r = (r&~0xFF) | parts[r>>8].type;
+ if(rr)
+ *rr = r;
- if(parts[i].type==PT_PHOT&&((r&0xFF)==PT_GLAS||(r&0xFF)==PT_PHOT||(r&0xFF)==PT_CLNE||(r&0xFF)==PT_PCLN||((r&0xFF)==PT_LCRY&&parts[r>>8].life > 5)))
- {
- return 1;
- }
-
- if((r&0xFF)==PT_VOID)
- {
- parts[i].type=PT_NONE;
- return 0;
- }
- if((r&0xFF)==PT_BHOL)
- {
- parts[i].type=PT_NONE;
- if(!legacy_enable)
- {
- parts[r>>8].temp = restrict_flt(parts[r>>8].temp+parts[i].temp/2, MIN_TEMP, MAX_TEMP);//3.0f;
- }
- return 0;
- }
+ if(pt==PT_PHOT&&((r&0xFF)==PT_GLAS||(r&0xFF)==PT_PHOT||(r&0xFF)==PT_CLNE||((r&0xFF)==PT_LCRY||((r&0xFF)==PT_PCLN&&parts[r>>8].life > 5))))
+ return 2;
- if(parts[i].type==PT_STKM) //Stick man's head shouldn't collide
- {
- return 1;
- }
+ if(pt==PT_STKM) //Stick man's head shouldn't collide
+ {
+ return 2;
+ }
- if(bmap[ny/CELL][nx/CELL]==12 && !emap[y/CELL][x/CELL])
- {
- return 1;
- }
- if(bmap[ny/CELL][nx/CELL]==13 && ptypes[parts[i].type].falldown!=0 && parts[i].type!=PT_FIRE && parts[i].type!=PT_SMKE)
- {
+ if(bmap[ny/CELL][nx/CELL]==13 && ptypes[pt].falldown!=0 && pt!=PT_FIRE && pt!=PT_SMKE)
return 0;
- }
- if((bmap[y/CELL][x/CELL]==12 && !emap[y/CELL][x/CELL]) && (bmap[ny/CELL][nx/CELL]!=12 && !emap[ny/CELL][nx/CELL]))
- {
+ if(ptypes[pt].falldown!=2 && bmap[ny/CELL][nx/CELL]==3)
+ return 0;
+ if((pt==PT_NEUT ||pt==PT_PHOT) && bmap[ny/CELL][nx/CELL]==7 && !emap[ny/CELL][nx/CELL])
return 0;
- }
- if(ptypes[parts[i].type].falldown!=2 && bmap[ny/CELL][nx/CELL]==3)
- return 0;
- if((parts[i].type==PT_NEUT ||parts[i].type==PT_PHOT) && bmap[ny/CELL][nx/CELL]==7 && !emap[ny/CELL][nx/CELL])
+ if(bmap[ny/CELL][nx/CELL]==9)
return 0;
- if(r && (r>>8)<NPART && ptypes[r&0xFF].falldown!=2 && bmap[y/CELL][x/CELL]==3)
+
+ if(ptypes[pt].falldown!=1 && bmap[ny/CELL][nx/CELL]==10)
return 0;
- if(bmap[ny/CELL][nx/CELL]==9)
+ if (r && ((r&0xFF) >= PT_NUM || !can_move[pt][(r&0xFF)]))
return 0;
- if(ptypes[parts[i].type].falldown!=1 && bmap[ny/CELL][nx/CELL]==10)
+ return 1;
+}
+int try_move(int i, int x, int y, int nx, int ny)
+{
+ unsigned r, e;
+
+ if(x==nx && y==ny)
+ return 1;
+ e = eval_move(parts[i].type, nx, ny, &r);
+ if(!e)
+ return 0;
+ if(e == 2)
+ return 1;
+ if(bmap[ny/CELL][nx/CELL]==12 && !emap[y/CELL][x/CELL])
+ return 1;
+ if((bmap[y/CELL][x/CELL]==12 && !emap[y/CELL][x/CELL]) && (bmap[ny/CELL][nx/CELL]!=12 && !emap[ny/CELL][nx/CELL]))
return 0;
- if (r && ((r&0xFF) >= PT_NUM || !can_move[parts[i].type][(r&0xFF)]))
+ if(r && (r>>8)<NPART && ptypes[r&0xFF].falldown!=2 && bmap[y/CELL][x/CELL]==3)
return 0;
- if(parts[i].type==PT_CNCT && y<ny && (pmap[y+1][x]&0xFF)==PT_CNCT)
+ if((r&0xFF)==PT_VOID)
{
+ parts[i].type=PT_NONE;
return 0;
}
+ if((r&0xFF)==PT_BHOL)
+ {
+ parts[i].type=PT_NONE;
+ if(!legacy_enable)
+ {
+ parts[r>>8].temp = restrict_flt(parts[r>>8].temp+parts[i].temp/2, MIN_TEMP, MAX_TEMP);//3.0f;
+ }
+
+ return 0;
+ }
+ if(parts[i].type==PT_CNCT && y<ny && (pmap[y+1][x]&0xFF)==PT_CNCT)
+ return 0;
pmap[ny][nx] = (i<<8)|parts[i].type;
pmap[y][x] = r;
+
if(r && (r>>8)<NPART)
{
r >>= 8;
@@ -105,6 +111,142 @@ int try_move(int i, int x, int y, int nx, int ny)
return 1;
}
+#define SURF_RANGE 10
+#define NORMAL_MIN_EST 3
+#define NORMAL_INTERP 20
+#define NORMAL_FRAC 16
+
+static unsigned direction_to_map(float dx, float dy)
+{
+ return (dx >= 0) |
+ (((dx + dy) >= 0) << 1) | /* 567 */
+ ((dy >= 0) << 2) | /* 4+0 */
+ (((dy - dx) >= 0) << 3) | /* 321 */
+ ((dx <= 0) << 4) |
+ (((dx + dy) <= 0) << 5) |
+ ((dy <= 0) << 6) |
+ (((dy - dx) <= 0) << 7);
+}
+
+static int is_blocking(int t, int x, int y)
+{
+ return eval_move(t, x, y, NULL);
+}
+
+static int is_boundary(int pt, int x, int y)
+{
+ if(!is_blocking(pt,x,y))
+ return 0;
+ if(is_blocking(pt,x,y-1) && is_blocking(pt,x,y+1) && is_blocking(pt,x-1,y) && is_blocking(pt,x+1,y))
+ return 0;
+ return 1;
+}
+
+static int find_next_boundary(int pt, int *x, int *y, int dm, int *em)
+{
+ static int dx[8] = {1,1,0,-1,-1,-1,0,1};
+ static int dy[8] = {0,1,1,1,0,-1,-1,-1};
+ static int de[8] = {0x83,0x07,0x0E,0x1C,0x38,0x70,0xE0,0xC1};
+ int i, ii, i0;
+
+ if(*x <= 0 || *x >= XRES-1 || *y <= 0 || *y >= YRES-1)
+ return 0;
+
+ if(*em != -1) {
+ i0 = *em;
+ dm &= de[i0];
+ } else
+ i0 = 0;
+
+ for(ii=0; ii<8; ii++) {
+ i = (ii + i0) & 7;
+ if((dm & (1 << i)) && is_boundary(pt, *x+dx[i], *y+dy[i])) {
+ *x += dx[i];
+ *y += dy[i];
+ *em = i;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int vec_colinear(float nx, float ny, float vx, float vy)
+{
+ float d = 1.0f/hypot(vx, vy);
+ d *= nx*vx + ny*vy;
+ return (d >= 0.99) || (d <= -0.99);
+}
+
+int get_normal(int pt, int x, int y, float dx, float dy, float *nx, float *ny)
+{
+ int ldm, rdm, lm, rm;
+ int lx, ly, lv, rx, ry, rv;
+ int i, j;
+ float r, ex, ey;
+
+ if(!dx && !dy)
+ return 0;
+
+ if(!is_boundary(pt, x, y))
+ return 0;
+
+ ldm = direction_to_map(-dy, dx);
+ rdm = direction_to_map(dy, -dx);
+ lx = rx = x;
+ ly = ry = y;
+ lv = rv = 1;
+ lm = rm = -1;
+
+ j = 0;
+ for(i=0; i<SURF_RANGE; i++) {
+ if(lv)
+ lv = find_next_boundary(pt, &lx, &ly, ldm, &lm);
+ if(rv)
+ rv = find_next_boundary(pt, &rx, &ry, rdm, &rm);
+ j += lv + rv;
+ if(!lv && !rv)
+ break;
+ }
+
+ if(j < NORMAL_MIN_EST)
+ return 0;
+
+ if((lx == rx) && (ly == ry))
+ return 0;
+
+ ex = rx - lx;
+ ey = ry - ly;
+ r = 1.0f/hypot(ex, ey);
+ *nx = ey * r;
+ *ny = -ex * r;
+
+ if(vec_colinear(*ny, -*nx, dx, dy))
+ return 0;
+
+ return 1;
+}
+
+int get_normal_interp(int pt, float x0, float y0, float dx, float dy, float *nx, float *ny)
+{
+ int x, y, i;
+
+ dx /= NORMAL_FRAC;
+ dy /= NORMAL_FRAC;
+
+ for(i=0; i<NORMAL_INTERP; i++) {
+ x = (int)(x0 + 0.5f);
+ y = (int)(y0 + 0.5f);
+ if(is_boundary(pt, x, y))
+ break;
+ x0 += dx;
+ y0 += dy;
+ }
+ if(i >= NORMAL_INTERP)
+ return 0;
+
+ return get_normal(pt, x, y, dx, dy, nx, ny);
+}
void kill_part(int i)
{
@@ -477,7 +619,7 @@ void update_particles_i(pixel *vid, int start, int inc)
uint16_t tempu1, tempu2;
int16_t temps1, temps2;
float tempf1, tempf2;
- float mv, dx, dy, ix, iy, lx, ly, d, pp;
+ float mv, dx, dy, ix, iy, lx, ly, d, pp, nrx, nry, dp;
float pt = R_TEMP;
float c_heat = 0.0f;
int h_count = 0;
@@ -906,7 +1048,8 @@ void update_particles_i(pixel *vid, int start, int inc)
r = pmap[y+ny][x+nx];
if((r>>8)>=NPART || !r)
continue;
- if(((r&0xFF)==PT_METL || (r&0xFF)==PT_ETRD || (r&0xFF)==PT_PSCN || (r&0xFF)==PT_NSCN || (r&0xFF)==PT_NTCT || (r&0xFF)==PT_PTCT || (r&0xFF)==PT_BMTL || (r&0xFF)==PT_RBDM || (r&0xFF)==PT_LRBD || (r&0xFF)==PT_BRMT||(r&0xFF)==PT_NBLE) || (r&0xFF)==PT_INWR && parts[r>>8].ctype!=PT_SPRK )
+ if(((r&0xFF)==PT_METL || (r&0xFF)==PT_ETRD || (r&0xFF)==PT_PSCN || (r&0xFF)==PT_NSCN || (r&0xFF)==PT_NTCT || (r&0xFF)==PT_PTCT || (r&0xFF)==PT_BMTL || (r&0xFF)==PT_RBDM || (r&0xFF)==PT_LRBD || (r&0xFF)==PT_BRMT||(r&0xFF)==PT_NBLE) || (r&0xFF)==PT_INWR && parts[r>>8].ctype!=PT_SPRK)
+
{
t = parts[i].type = PT_NONE;
parts[r>>8].ctype = parts[r>>8].type;
@@ -2381,33 +2524,57 @@ void update_particles_i(pixel *vid, int start, int inc)
else
{
parts[i].flags |= FLAG_STAGNANT;
- if(nx>x+ISTP) nx=x+ISTP;
- if(nx<x-ISTP) nx=x-ISTP;
- if(ny>y+ISTP) ny=y+ISTP;
- if(ny<y-ISTP) ny=y-ISTP;
if(t==PT_NEUT && 100>(rand()%1000))
{
kill_part(i);
continue;
}
- else if(try_move(i, x, y, 2*x-nx, ny))
- {
- parts[i].x = (float)(2*x-nx);
- parts[i].y = (float)iy;
- parts[i].vx *= ptypes[t].collision;
- }
- else if(try_move(i, x, y, nx, 2*y-ny))
- {
- parts[i].x = (float)ix;
- parts[i].y = (float)(2*y-ny);
- parts[i].vy *= ptypes[t].collision;
- }
- else
- {
- parts[i].vx *= ptypes[t].collision;
- parts[i].vy *= ptypes[t].collision;
- }
- }
+ else if(t==PT_NEUT || t==PT_PHOT)
+ {
+ if(get_normal_interp(t, lx, ly, parts[i].vx, parts[i].vy, &nrx, &nry)) {
+ dp = nrx*parts[i].vx + nry*parts[i].vy;
+ parts[i].vx -= 2.0f*dp*nrx;
+ parts[i].vy -= 2.0f*dp*nry;
+ nx = (int)(parts[i].x + parts[i].vx + 0.5f);
+ ny = (int)(parts[i].y + parts[i].vy + 0.5f);
+ if(try_move(i, x, y, nx, ny)) {
+ parts[i].x = (float)nx;
+ parts[i].y = (float)ny;
+ } else {
+ kill_part(i);
+ continue;
+ }
+ } else {
+ kill_part(i);
+ continue;
+ }
+ }
+
+ else
+ {
+ if(nx>x+ISTP) nx=x+ISTP;
+ if(nx<x-ISTP) nx=x-ISTP;
+ if(ny>y+ISTP) ny=y+ISTP;
+ if(ny<y-ISTP) ny=y-ISTP;
+ if(try_move(i, x, y, 2*x-nx, ny))
+ {
+ parts[i].x = (float)(2*x-nx);
+ parts[i].y = (float)iy;
+ parts[i].vx *= ptypes[t].collision;
+ }
+ else if(try_move(i, x, y, nx, 2*y-ny))
+ {
+ parts[i].x = (float)ix;
+ parts[i].y = (float)(2*y-ny);
+ parts[i].vy *= ptypes[t].collision;
+ }
+ else
+ {
+ parts[i].vx *= ptypes[t].collision;
+ parts[i].vy *= ptypes[t].collision;
+ }
+ }
+ }
}
if(nx<CELL || nx>=XRES-CELL || ny<CELL || ny>=YRES-CELL)
{