"""

Uses mitsuba to generate the environment brdf

"""

from __future__ import print_function

import os
import sys
import math
from panda3d.core import PNMImage, load_prc_file_data, Vec3

load_prc_file_data("", "notify-level error")
load_prc_file_data("", "notify-level-pnmimage error")

configs = {
    "normal": {
        "out_dir": "slices",
        "out_name": "env_brdf_{}.png",
        "template_suffix": "",
        "sequence": xrange(7),
        "samples": 32,
    },
    "metallic": {
        "out_dir": "slices_metal",
        "out_name": "env_brdf.png",
        "template_suffix": "-metal",
        "sequence": [1],
        "samples": 32,
    },
    "clearcoat": {
        "out_dir": "slices_coat",
        "out_name": "env_brdf.png",
        "template_suffix": "-coat",
        "sequence": [1],
        "samples": 2048,
    }
}

# configs_to_run = ["normal", "metallic", "clearcoat"]
configs_to_run = ["clearcoat"]

for config_name in configs_to_run:

    config = configs[config_name]

    if not os.path.isdir(config["out_dir"]):
        os.makedirs(config["out_dir"])

    for pass_index in config["sequence"]:

        ior = 1.01 + 0.2 * pass_index

        dest_size = 512
        dest_h = 32
        dest = PNMImage(dest_size, dest_h)

        # run mitsuba
        print("Running mitsuba for ior =", ior, "( index =", pass_index, ")")
        with open("res/scene" + config["template_suffix"] + ".templ.xml", "r") as handle:
            content = handle.read()

        content = content.replace("%IOR%", str(ior))
        content = content.replace("%SAMPLES%", str(config["samples"]))

        with open("res/scene.xml", "w") as handle:
            handle.write(content)

        os.system("run_mitsuba.bat")

        img = PNMImage("scene.png")
        source_w = img.get_x_size()

        print("Converting ..")

        indices = []
        nxv_values = []

        # Generate nonlinear NxV sequence
        for i in xrange(source_w):
            v = 1 - i / float(source_w)
            NxV = math.sqrt(1 - v * v)
            nxv_values.append(NxV)

        # Generate lerp indices and weights
        for x in xrange(dest_size):
            NxV = (x) / float(dest_size)
            index = 0
            for i, s_nxv in enumerate(reversed(nxv_values)):
                if NxV >= s_nxv:
                    index = i
                    break
            index = len(nxv_values) - index - 1
            next_index = index + 1 if index < dest_size - 1 else index

            curr_nxv = nxv_values[index]
            next_nxv = nxv_values[next_index]

            lerp_factor = (NxV - curr_nxv) / max(1e-10, abs(next_nxv - curr_nxv))
            lerp_factor = max(0.0, min(1.0, lerp_factor))
            indices.append((index, next_index, lerp_factor))

        # Generate the final linear lut using the lerp weights
        for y in xrange(dest_h):
            for x in xrange(dest_size):
                curr_i, next_i, lerp = indices[x]
                curr_v = img.get_xel(curr_i, y)
                next_v = img.get_xel(next_i, y)
                dest.set_xel(x, y, curr_v * (1 - lerp) + next_v * lerp)

        out_name = config["out_name"].replace("{}", str(pass_index))
        dest.write(config["out_dir"] + "/" + out_name)

try:
    os.remove("scene.png")
except:
    pass
