public FloatBuffer[] writeTangentArray(FloatBuffer normalBuffer, FloatBuffer tangentStore, FloatBuffer binormalStore, FloatBuffer textureBuffer, Vector3f scale) {
        if (!isLoaded()) {
            throw new IllegalStateException("The Geomap data is not loaded.");
        }

        if (tangentStore != null) {
            if (tangentStore.remaining() < getWidth() * getHeight() * 3) {
                throw new BufferUnderflowException();
            }
        } else {
            tangentStore = BufferUtils.createFloatBuffer(getWidth() * getHeight() * 3);
        }
        tangentStore.rewind();

        if (binormalStore != null) {
            if (binormalStore.remaining() < getWidth() * getHeight() * 3) {
                throw new BufferUnderflowException();
            }
        } else {
            binormalStore = BufferUtils.createFloatBuffer(getWidth() * getHeight() * 3);
        }
        binormalStore.rewind();

        Vector3f normal = new Vector3f();
        Vector3f tangent = new Vector3f();
        Vector3f binormal = new Vector3f();
        /*Vector3f v1 = new Vector3f();
        Vector3f v2 = new Vector3f();
        Vector3f v3 = new Vector3f();
        Vector2f t1 = new Vector2f();
        Vector2f t2 = new Vector2f();
        Vector2f t3 = new Vector2f();*/

        for (int r = 0; r < getHeight(); r++) {
            for (int c = 0; c < getWidth(); c++) {
                
                int idx = (r * getWidth() + c) * 3;
                normal.set(normalBuffer.get(idx), normalBuffer.get(idx+1), normalBuffer.get(idx+2));
                tangent.set(normal.cross(new Vector3f(0,0,1)));
                binormal.set(new Vector3f(1,0,0).cross(normal));
                
                BufferUtils.setInBuffer(tangent.normalizeLocal(), tangentStore, (r * getWidth() + c)); // save the tangent
                BufferUtils.setInBuffer(binormal.normalizeLocal(), binormalStore, (r * getWidth() + c)); // save the binormal
            }
        }

/*        for (int r = 0; r < getHeight(); r++) {
            for (int c = 0; c < getWidth(); c++) {

                int texIdx = ((getHeight() - 1 - r) * getWidth() + c) * 2; // pull from the end
                int texIdxAbove = ((getHeight() - 1 - (r - 1)) * getWidth() + c) * 2; // pull from the end
                int texIdxNext = ((getHeight() - 1 - (r + 1)) * getWidth() + c) * 2; // pull from the end

                v1.set(c, getValue(c, r), r);
                t1.set(textureBuffer.get(texIdx), textureBuffer.get(texIdx + 1));

                // below
                if (r == getHeight()-1) { // last row
                    v3.set(c, getValue(c, r), r + 1);
                    float u = textureBuffer.get(texIdx) - textureBuffer.get(texIdxAbove);
                    u += textureBuffer.get(texIdx);
                    float v = textureBuffer.get(texIdx + 1) - textureBuffer.get(texIdxAbove + 1);
                    v += textureBuffer.get(texIdx + 1);
                    t3.set(u, v);
                } else {
                    v3.set(c, getValue(c, r + 1), r + 1);
                    t3.set(textureBuffer.get(texIdxNext), textureBuffer.get(texIdxNext + 1));
                }
                
                //right
                if (c == getWidth()-1) { // last column
                    v2.set(c + 1, getValue(c, r), r);
                    float u = textureBuffer.get(texIdx) - textureBuffer.get(texIdx - 2);
                    u += textureBuffer.get(texIdx);
                    float v = textureBuffer.get(texIdx + 1) - textureBuffer.get(texIdx - 1);
                    v += textureBuffer.get(texIdx - 1);
                    t2.set(u, v);
                } else {
                    v2.set(c + 1, getValue(c + 1, r), r); // one to the right
                    t2.set(textureBuffer.get(texIdx + 2), textureBuffer.get(texIdx + 3));
                }

                calculateTangent(new Vector3f[]{v1.mult(scale), v2.mult(scale), v3.mult(scale)}, new Vector2f[]{t1, t2, t3}, tangent, binormal);
                BufferUtils.setInBuffer(tangent, tangentStore, (r * getWidth() + c)); // save the tangent
                BufferUtils.setInBuffer(binormal, binormalStore, (r * getWidth() + c)); // save the binormal
            }
        }
        */
        return new FloatBuffer[]{tangentStore, binormalStore};
    }
calculate how many indexes there will be.
This isn't that precise and there might be a couple extra.
jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/LODGeomap.java