<!doctype html>
<html>
    <head>
        <style>
            html, body
            {
                margin:0;
            }
            canvas
            {
                position:absolute;
                top:0;
                left:0;
                display:block;
                width:100%;
                height:100%;
            }
        </style>
    </head>
    <body>
        <canvas></canvas>
<script type="module">
import { Scene, THREE } from './scene.js';
import { Region } from "./region.js";

let surfaceTest = () =>
{
    let limit = (x, y, z, ax, ay, az) =>
    {
        let centerX = Math.round(x);
        let centerY = Math.round(y);
        let centerZ = Math.round(z);

        let deltaX = ax-centerX;
        let deltaY = ay-centerY;
        let deltaZ = az-centerZ;

        let absDeltaX = Math.abs(deltaX);
        let absDeltaY = Math.abs(deltaY);
        let absDeltaZ = Math.abs(deltaZ);

        let max = absDeltaX;
        if(absDeltaY > max){ max = absDeltaY; }
        if(absDeltaZ > max){ max = absDeltaZ; }

        let lerp = 0.49/max;

        if(lerp <= 1)
        {
            return [
                centerX + deltaX*lerp,
                centerY + deltaY*lerp,
                centerZ + deltaZ*lerp
            ];
        }
        else
        {
            return [ax, ay, az];
        }
    }
    let average = (inArray, inPointInd, inOthersIndArray) =>
    {
        let sum = [0, 0, 0];
        for(let i=0; i<inOthersIndArray.length; i++)
        {
            let otherInd = inOthersIndArray[i]*3;
            sum[0] += inArray[otherInd+0];
            sum[1] += inArray[otherInd+1];
            sum[2] += inArray[otherInd+2];
        }
        
        let pointX = inPointInd*3 + 0;
        let pointY = inPointInd*3 + 1;
        let pointZ = inPointInd*3 + 2;
        let reducer = inOthersIndArray.length;

        let limited = limit(inArray[pointX], inArray[pointY], inArray[pointZ], sum[0]/reducer, sum[1]/reducer, sum[2]/reducer);

        inArray[pointX] = limited[0];
        inArray[pointY] = limited[1];
        inArray[pointZ] = limited[2];
    };
    let smooth = (inVertsArray, inNeighborsArray, inTimes) =>
    {
        let count = inVertsArray.length/3;
        for(let t=0; t<inTimes; t++)
        {
            for(let i=0; i<count; i++)
            {
                average(inVertsArray, i, inNeighborsArray[i]);
            }
        }
        return inVertsArray;
    }

    let voxels = [];
    voxels[Region.I(0, 0, 0)] = true;
    voxels[Region.I(1, 0, 0)] = true;
    voxels[Region.I(2, 0, 0)] = true;
    voxels[Region.I(0, 1, 0)] = true;
    voxels[Region.I(1, 1, 0)] = true;
    voxels[Region.I(0, 2, 0)] = true;

    /*
    voxels[Region.I(0, 0, 1)] = true;
    voxels[Region.I(1, 0, 1)] = true;
    voxels[Region.I(2, 0, 1)] = true;
    voxels[Region.I(0, 1, 1)] = true;
    voxels[Region.I(1, 1, 1)] = true;
    voxels[Region.I(0, 2, 1)] = true;

    voxels[Region.I(0, 0, 2)] = true;
    voxels[Region.I(1, 0, 2)] = true;
    voxels[Region.I(2, 0, 2)] = true;
    voxels[Region.I(0, 1, 2)] = true;
    voxels[Region.I(1, 1, 2)] = true;
    voxels[Region.I(0, 2, 2)] = true;

    voxels[Region.I(0, 0, 3)] = true;
    voxels[Region.I(1, 0, 3)] = true;
    voxels[Region.I(2, 0, 3)] = true;
    voxels[Region.I(0, 1, 3)] = true;
    voxels[Region.I(1, 1, 3)] = true;
    voxels[Region.I(0, 2, 3)] = true;
    */


/*
    let testGeometry = new THREE.BufferGeometry();
    let testAttribute = new THREE.BufferAttribute(new Float32Array(0));
    testGeometry.setAttribute("position", testAttribute, 3);

    console.log(testGeometry);
    testAttribute.array = new Float32Array([1, 2, 3]);
    testAttribute.needsUpdate = true;
    console.log(testGeometry);
*/

    let surfaceCubeGeometry = new THREE.BufferGeometry();
    let surfaceCubeObject = new THREE.Mesh(
        surfaceCubeGeometry,
        new THREE.MeshPhongMaterial({color:0x666666, wireframe:false, flatShading:true, side:THREE.DoubleSide})
    );
    
    let rebuildSurface = inVoxels =>
    {
        let surface = Region.Surface(inVoxels);
        let vertsCube = new Float32Array(surface.vertices.flat());
        
        surfaceCubeGeometry.setAttribute("position", new THREE.BufferAttribute(vertsCube, 3));
        surfaceCubeGeometry.setIndex(surface.triPointVert);
        surfaceCubeGeometry.computeVertexNormals(true);
    };
    rebuildSurface(voxels);

    return {
        DOM:"canvas",
        Init(inScene)
        {   
            let light = new THREE.PointLight(0xffffff, 1, 100)
            light.position.set(5, 5, -5);
            inScene.add(light)
            inScene.add(surfaceCubeObject);
            //inScene.add(surfaceSmoothObject);

            inScene.add(new THREE.GridHelper(10, 10));
            inScene.add(new THREE.AxesHelper( 5 ));
        },
        Update(inScene, inScreen, inDelta)
        {
            var i, hits, hit, index;
            if(inScreen.Drag > 0)
            {
                hits = inScreen.Ray.intersectObject(surfaceCubeObject);
                if(hits.length)
                {
                    hit = hits[0];
                    for(i=1; i<hits.length; i++)
                    {
                        if(hits[i].distance < hit.distance)
                        {
                            hit = hits[i];
                        }
                    }
                    index = Region.I(Math.floor(hit.point.x), Math.floor(hit.point.y), Math.floor(hit.point.z));
                    voxels[index] = true;
                    rebuildSurface(voxels);
                    console.log(hit);
                }
            }
        }
    };

}

Scene(surfaceTest());

</script>

    </body>
</html>