Friday, June 13, 2008

Attempts at a translucent FOV, partial code

I think I did not explain the algorithm correctly, so here is the code. This wont compile since there are other dependencies, but you can at least understand what I am trying to do.

AnyTranslucentAdapterAlgorithm.java

package sid.rpg.los;

import java.util.Arrays;

import rlforj.los.IFovAlgorithm;
import rlforj.los.ILosAlgorithm;
import rlforj.los.ILosBoard;

import static rlforj.util.MathUtils.*;

public class AnyTranslucentAdapterAlgorithm implements ITranslucentFovAlgorithm
{

IFovAlgorithm algo;
AnyTransAdVisitBoard atvBoard;

public AnyTranslucentAdapterAlgorithm(IFovAlgorithm algo)
{
this.algo=algo;
}

public void visitFieldOfView(ITranslucentBoard b, int x, int y, int distance)
{
System.out.println("called");
atvBoard=new AnyTransAdVisitBoard(x, y, distance, b);

algo.visitFieldOfView(atvBoard, x, y, distance);

b.visit(x, y, ITranslucentFovAlgorithm.MAX_VISIBILITY);

int width, height;
width=height=2*distance+1;
int[] vis=new int[width*height];
Arrays.fill(vis, 0);
vis[(distance)*height+distance]=ITranslucentFovAlgorithm.MAX_VISIBILITY;

int[][] quads={
{ 1 , 1 },
{-1 , 1 },
{ 1 ,-1 },
{-1 ,-1 }
};

for(int q=0; q<4; q++)
{
int i = 0;
int j = 0;
int sgnx=quads[q][0];
int sgny=quads[q][1];
int maxI = distance + distance;
// For each square outline
for (i = 1; i <= maxI ; ++i)
{
int startJ = max(0, i - distance);
int maxJ = min(i, distance);
// Visit the nodes in the outline
for (j = startJ; j <= maxJ; ++j)
{
int adx = i - j;
int ady = j;

int dx=adx*sgnx;
int dy=ady*sgny;
boolean diagonal=false;
if(!atvBoard.wasVisited(x+dx, y+dy))
{
continue;
}

int[] LEFT =new int[]{-1, 0};
int[] UP =new int[]{ 0,-1};
int[] LEFTUP=new int[]{-1,-1};

int[][] preferences;
if(adx>ady) //Bresenham preferences, now not used
{
if(2*ady-adx>=0) {
preferences=new int[][]{LEFTUP, LEFT, UP};
diagonal=true;
} else {
preferences=new int[][]{LEFT, LEFTUP, UP};
}
} else {
if(2*adx-ady>=0) {
preferences=new int[][]{LEFTUP, UP, LEFT};
diagonal=true;
} else {
preferences=new int[][]{UP, LEFTUP, LEFT};
}
}
int pf, x1=adx, y1=ady;

// Select preferred logic
// for(pf=0; pf<3; pf++) {
// x1=adx+preferences[pf][0]; y1=ady+preferences[pf][1];
// x1*=sgnx; y1*=sgny;
// if (atvBoard.wasVisited(x + x1, y + y1)
// && vis[(x1+distance)*height+y1+distance]>0)/* Source location visible */
//// && b.transmitFractionLos(x + x1, y + y1)>0)/* not opaque */
// {
// break;
// }
// }
// if(pf==3) //all blocked ??!! Shouldnt happen!
// continue;
// int pv=vis[(x1+distance)*height+y1+distance];

// //max logic
int pv=0, maxPf=-1;
for(pf=0; pf<3; pf++) {
x1=adx+preferences[pf][0]; y1=ady+preferences[pf][1];
x1*=sgnx; y1*=sgny;
int pv1=vis[(x1+distance)*height+y1+distance];
if(atvBoard.wasVisited(x + x1, y + y1) && pv1>pv)
{
maxPf=pf;
pv=pv1;
}
}

if(maxPf>-1 && preferences[maxPf]==LEFTUP)
diagonal=true;// wont work
//avg logic, bad
// int pv=0;
// for(pf=0; pf<3; pf++) {
// x1=adx+preferences[pf][0]; y1=ady+preferences[pf][1];
// x1*=sgnx; y1*=sgny;
// int pv1=vis[(x1+distance)*height+y1+distance];
// pv+=pv1;
// }
// pv/=3;
int v=0;
int tf=b.transmitFractionLos(x+dx, y+dy);
if(tf==0)
v=pv;
else
v=(pv*tf)>>15;

if(diagonal && v<ITranslucentFovAlgorithm.MAX_VISIBILITY) {
v=(v*90)>>7;//divide by root 2 is 45/64, good value 58/64 or 117/128
if(v>ITranslucentFovAlgorithm.MAX_VISIBILITY)
v=ITranslucentFovAlgorithm.MAX_VISIBILITY;
}
vis[(dx+distance)*height+dy+distance] = v;

// System.out.println("dx dy "+dx+" "+dy+" x y "+(x+dx)+" "+(y+dy));
// System.out.println("vis calc "+v+" from x1 y1 pv "+x1+" "+y1+" "+pv);

if(v>0)
b.visit(x+dx, y+dy, v);
}
}
}
atvBoard=null; //free it

}

public void visitFieldOfView(ILosBoard b, int x, int y, int distance)
{
// TODO Auto-generated method stub
throw new RuntimeException("Not Implemented");
}

}


Just for reference:
AnyTransAdVisitBoard.java


package sid.rpg.los;

import java.util.Arrays;

import rlforj.los.ILosBoard;
import rlforj.los.GenericCalculateProjection.VisitedBoard;
import rlforj.util.MathUtils;

public class AnyTransAdVisitBoard implements ILosBoard, VisitedBoard
{

int visitingQuadrant;
int sgnx, sgny;
int radius;
int centerx, centery;

protected int width, height;
protected boolean[] visited;
ITranslucentBoard board;

public AnyTransAdVisitBoard(int sx, int sy, int radius, ITranslucentBoard originalBoard)
{
this.radius=radius;
height=width=2*radius+1;
visited=new boolean[width*height];
Arrays.fill(visited, false);

board=originalBoard;
centerx=sx; centery=sy;
}

public boolean contains(int x, int y)
{
return board.contains(x, y) &&
MathUtils.abs(x-centerx)<=radius && MathUtils.abs(y-centery)<=radius;
}

public boolean isObstacle(int x, int y)
{
if(!board.contains(x, y))
return false;
return board.transmitFractionLos(x, y)==0;
}

public void visit(int x, int y)
{
visited[(x-centerx+radius)*height+(y-centery+radius)]=true;

}

public boolean wasVisited(int x, int y)
{
if(!contains(x, y))
return false;

return visited[(x-centerx+radius)*height+(y-centery+radius)];
}

}