//
//  ANBevelNormalInlineFunc.h
//  AvisNocturnaCrossCore
//
//  Created by Mendel Kucharzeck on 10.01.12.
//  Copyright (c) 2012 AvisNocturna Software. All rights reserved.
//

enum _ANBevelType
{
    ANBevelType_Round = 0,
    ANBevelType_Linear
    
}typedef ANBevelType;

FOUNDATION_STATIC_INLINE float heightmapAtPoint(float *heightmap,NSInteger width,NSInteger height, NSInteger x, NSInteger y,NSInteger smoothFactor)
{
    /*if(x>=0 && y>=0 && y<height && x<width)
        return heightmap[x+y*width];
    return 0;*/
    
    float value = 0;
    float valuesAdded = 0;
    
    NSInteger dx = -smoothFactor;
    while(dx<=smoothFactor)
    {
        NSInteger dy = -smoothFactor;
        while(dy<=smoothFactor)
        {
            if(dx+x>=0 && dy+y>=0 && dx+x<width && dy+y<height)
            {
                float v = heightmap[x+dx+(y+dy)*width];
                
                float a = 1.0f/(float)(fabs(dx/2.0f)+fabs(dy/2.0f)+1);
                valuesAdded += a;
                value += v*a;
            }
            
            dy++;
        }
        
        dx++;
    }
    
    return value/valuesAdded;
}

FOUNDATION_STATIC_INLINE void applyBevelCalcNormal(float *heightmap,NSInteger width,NSInteger height,NSInteger x,NSInteger y, float *nx, float *ny, float *nz, ANBevelType type, float radius, float smoothFactor, float aboveBevelRounding)
{
    NSUInteger position = x+y*width;
    float currentHeight = heightmap[position];
    
    if(aboveBevelRounding==0.0f && (type == ANBevelType_Linear || type == ANBevelType_Round))
    {
        if(currentHeight>radius)
        {
            *nx = *ny = 0.0f;
            *nz = 1.0f;
            
            return;
        }
    }
    
    float xp1 = currentHeight-heightmapAtPoint(heightmap, width, height, x+1, y,smoothFactor);
    float xm1 = currentHeight-heightmapAtPoint(heightmap, width, height, x-1, y,smoothFactor);
    float yp1 = currentHeight-heightmapAtPoint(heightmap, width, height, x, y+1,smoothFactor);
    float ym1 = currentHeight-heightmapAtPoint(heightmap, width, height, x, y-1,smoothFactor);
    
    float factor = 3;
    xp1 *= factor;
    xm1 *= factor;
    yp1 *= factor;
    ym1 *= factor;
    
    if(x-1>=0 && y-1>=0)
    {
        float n1x = -1;
        float n1y = 0;
        float n1z = currentHeight-xm1;

        float n2x = 0;
        float n2y = -1;
        float n2z = currentHeight-ym1;
        
        *nx += (n1y*n2z-n1z*n2y);
        *ny += (n1z*n2x-n1x*n2z);
        *nz += (n1x*n2y-n1y*n2x);
    }
    
    if(x+1<width && y-1>=0)
    {
        float n1x = -1;
        float n1y = 0;
        float n1z = xp1-currentHeight;
        
        float n2x = 0;
        float n2y = -1;
        float n2z = currentHeight-ym1;
        
        *nx += (n1y*n2z-n1z*n2y);
        *ny += (n1z*n2x-n1x*n2z);
        *nz += (n1x*n2y-n1y*n2x);
    }
    
    if(x-1>=0 && y+1<height)
    {
        float n1x = -1;
        float n1y = 0;
        float n1z = currentHeight-xm1;
        
        float n2x = 0;
        float n2y = -1;
        float n2z = yp1-currentHeight;
        
        *nx += (n1y*n2z-n1z*n2y);
        *ny += (n1z*n2x-n1x*n2z);
        *nz += (n1x*n2y-n1y*n2x);
    }
    
    if(x+1<width && y+1<height)
    {
        float n1x = -1;
        float n1y = 0;
        float n1z = xp1-currentHeight;
        
        float n2x = 0;
        float n2y = -1;
        float n2z = yp1-currentHeight;
        
        *nx += (n1y*n2z-n1z*n2y);
        *ny += (n1z*n2x-n1x*n2z);
        *nz += (n1x*n2y-n1y*n2x);
    }
    
    float nlength = sqrtf(*nx**nx+*ny**ny+*nz**nz);
    if(nlength>0.0f)
    {
        *nx /= nlength;
        *ny /= nlength;
        *nz /= nlength;
    }
    
    if(type == ANBevelType_Round)
    {
        float round = (radius-currentHeight)/radius;
        
        if(round<aboveBevelRounding)
            round = aboveBevelRounding;
        
        *nx = *nx*round;
        *ny = *ny*round;
        *nz = *nz*round+(1.0f-round);
    }else if(type == ANBevelType_Linear)
    {
        float round = (radius-currentHeight)/radius;
        if(round>0.2f)
            round = 1.0f;
        else if(round>=0.0f)
            round = round*5;
        
        if(round<0.0f)
            round = 0.0f;
        else if(round>1.0f)
            round = 1.0f;
        
        if(round<aboveBevelRounding)
            round = aboveBevelRounding;
        
        *nx = *nx*round;
        *ny = *ny*round;
        *nz = *nz*round+(1.0f-round);
    }
};
