import gs.plus.input as input
import gs.plus.scene as scene
import gs.plus.clock as clock
from math import pi, cos, sin, asin
import codecs

filename_out = "../src/simulation"
scale_factor = 5.0

gs.plus.create_workers()
gs.LoadPlugins(gs.get_default_plugins_path())

render.init(1280, 720, "../pkg.core")

scn = scene.new_scene()
cam = scene.add_camera(scn,
                       gs.Matrix4.TranslationMatrix(gs.Vector3(0, 3.5, -12.5)))
cam.GetTransform().SetRotation(
    gs.Vector3(pi * 5.0 / 180.0, pi * -5.0 / 180.0, 0))

scene.add_light(scn, gs.Matrix4.RotationMatrix(gs.Vector3(0.65, -0.45, 0)),
                gs.Light.Model_Linear, 150)
scene.add_light(scn,
                gs.Matrix4.RotationMatrix(gs.Vector3(0.55, pi, 0.2)),
                gs.Light.Model_Linear,
                diffuse=gs.Color(0.3, 0.3, 0.4))
scene.add_physic_plane(scn)

# nodes = add_kapla_tower(scn, 0.5, 2, 2, 6, 16)

width, height, length = 1, 1, 1
def convert_folder(folder_path):
    scn = None

    nml_reader = NmlReader()

    for in_file in os.listdir(folder_path):

        if os.path.isdir(os.path.join(folder_path, in_file)):
            convert_folder(os.path.join(folder_path, in_file))
        else:
            if in_file.find(".nms") > -1:
                # Found a NMS file, creates a new scene
                scn = scene.new_scene()
                links = []
                uid_dict = {}

                print("Reading file ", os.path.join(folder_path, in_file))
                nml_reader.LoadingXmlFile(os.path.join(folder_path, in_file))

                in_root = nml_reader.main_node.GetChild("Scene")
                in_items = in_root.GetChilds("Items")

                # ----------- LINKAGE ----------------------
                in_links_root = in_root.GetChild("Links")

                if in_links_root is not None:
                    in_links = in_links_root.GetChilds("Link")

                    for in_link in in_links:
                        child_item = int(get_nml_node_data(in_link.GetChild("Item"), -1))
                        parent_item = int(get_nml_node_data(in_link.GetChild("Link"), -1))

                        if child_item != -1 and parent_item != -1:
                            links.append({"child": child_item, "parent": parent_item})

                            # ----------- INSTANCES ----------------------
                for in_item in in_items:
                    #   Load instances
                    instances = in_item.GetChilds("Instance")

                    for instance in instances:
                        mitem = instance.GetChild("MItem")
                        item = instance.GetChild("Item")
                        template = instance.GetChild("Template")

                        if (
                            mitem is not None
                            and mitem.GetChild("Active") is not None
                            and mitem.GetChild("Helper") is None
                        ):
                            instance_path = get_nml_node_data(instance.GetChild("Template"))

                            if instance_path is not None:
                                # get item name
                                item_name = get_nml_node_data(mitem.GetChild("Id"), "default_name")
                                uid = int(get_nml_node_data(mitem.GetChild("UId"), -1))

                                # transformation
                                position, rotation, scale, rotation_order = parse_transformation(item)

                                new_node = gs.Node(item_name)
                                scn.AddNode(new_node)

                                node_transform = gs.Transform()
                                node_transform.SetPosition(position)
                                node_transform.SetRotation(rotation)
                                node_transform.SetScale(scale)
                                new_node.AddComponent(node_transform)

                                instance_path = instance_path.replace(".nms", ".scn")
                                instance_path = instance_path.replace("scenes/", folder_assets)

                                node_instance = gs.Instance()
                                node_instance.SetPath(instance_path)
                                new_node.AddComponent(node_instance)

                                # ----------- CAMERAS ----------------------
                for in_item in in_items:
                    #   Load cameras
                    mcameras = in_item.GetChilds("MCamera")

                    for mcamera in mcameras:
                        mitem = mcamera.GetChild("MItem")
                        if (
                            mitem is not None
                            and mitem.GetChild("Active") is not None
                            and mitem.GetChild("Helper") is None
                        ):
                            camera = mcamera.GetChild("Camera")
                            item = camera.GetChild("Item")

                            # get item name
                            item_name = get_nml_node_data(mitem.GetChild("Id"), "default_name")
                            uid = int(get_nml_node_data(mitem.GetChild("UId"), -1))

                            # transformation
                            position, rotation, scale, rotation_order = parse_transformation(item)

                            znear = float(get_nml_node_data(item.GetChild("ZNear"), 0.2))
                            zfar = float(get_nml_node_data(item.GetChild("ZFar"), 50000.0))
                            zoom = float(get_nml_node_data(item.GetChild("ZoomFactor"), 5.0)) / 2.0

                            new_node = scene.add_camera(scn)
                            new_node.SetName(item_name)
                            new_node.GetComponentsWithAspect("Transform")[0].SetPosition(position)
                            new_node.GetComponentsWithAspect("Transform")[0].SetRotation(rotation)

                            new_node.GetComponentsWithAspect("Camera")[0].SetZNear(znear)
                            new_node.GetComponentsWithAspect("Camera")[0].SetZFar(zfar)
                            new_node.GetComponentsWithAspect("Camera")[0].SetZoomFactor(zoom)

                            uid_dict[str(uid)] = new_node

                            # ----------- LIGHT ----------------------
                for in_item in in_items:
                    #   Load lights
                    mlights = in_item.GetChilds("MLight")

                    for mlight in mlights:
                        mitem = mlight.GetChild("MItem")
                        if (
                            mitem is not None
                            and mitem.GetChild("Active") is not None
                            and mitem.GetChild("Helper") is None
                        ):
                            light = mlight.GetChild("Light")
                            item = light.GetChild("Item")

                            # get item name
                            item_name = get_nml_node_data(mitem.GetChild("Id"), "default_name")
                            uid = int(get_nml_node_data(mitem.GetChild("UId"), -1))

                            # transformation
                            position, rotation, scale, rotation_order = parse_transformation(item)
                            diffuse_color, specular_color, shadow_color = parse_light_color(light)

                            new_node = scene.add_light(scn)
                            new_node.SetName(item_name)
                            new_node.GetComponentsWithAspect("Transform")[0].SetPosition(position)
                            new_node.GetComponentsWithAspect("Transform")[0].SetRotation(rotation)
                            new_node.GetComponentsWithAspect("Transform")[0].SetScale(scale)

                            # light type
                            light_type = light.GetChild("Type")
                            light_type = get_nml_node_data(light_type, "Point")

                            light_range = float(get_nml_node_data(light.GetChild("Range"), 0.0))

                            if light_type == "Point":
                                new_node.GetComponentsWithAspect("Light")[0].SetModel(gs.Light.Model_Point)
                                new_node.GetComponentsWithAspect("Light")[0].SetRange(light_range)

                            if light_type == "Parallel":
                                new_node.GetComponentsWithAspect("Light")[0].SetModel(gs.Light.Model_Linear)

                            if light_type == "Spot":
                                new_node.GetComponentsWithAspect("Light")[0].SetModel(gs.Light.Model_Spot)
                                new_node.GetComponentsWithAspect("Light")[0].SetRange(light_range)
                                new_node.GetComponentsWithAspect("Light")[0].SetConeAngle(
                                    float(get_nml_node_data(light.GetChild("ConeAngle"), 30.0))
                                )
                                new_node.GetComponentsWithAspect("Light")[0].SetEdgeAngle(
                                    float(get_nml_node_data(light.GetChild("EdgeAngle"), 15.0))
                                )

                            new_node.GetComponentsWithAspect("Light")[0].SetShadowRange(
                                float(get_nml_node_data(light.GetChild("ShadowRange"), 0.0))
                            )
                            new_node.GetComponentsWithAspect("Light")[0].SetClipDistance(
                                float(get_nml_node_data(light.GetChild("ClipDistance"), 300.0))
                            )

                            new_node.GetComponentsWithAspect("Light")[0].SetDiffuseColor(diffuse_color)
                            new_node.GetComponentsWithAspect("Light")[0].SetSpecularColor(specular_color)
                            new_node.GetComponentsWithAspect("Light")[0].SetShadowColor(shadow_color)

                            new_node.GetComponentsWithAspect("Light")[0].SetDiffuseIntensity(
                                float(get_nml_node_data(light.GetChild("DiffuseIntensity"), 1.0))
                            )
                            new_node.GetComponentsWithAspect("Light")[0].SetSpecularIntensity(
                                float(get_nml_node_data(light.GetChild("SpecularIntensity"), 0.0))
                            )

                            new_node.GetComponentsWithAspect("Light")[0].SetZNear(
                                float(get_nml_node_data(light.GetChild("ZNear"), 0.01))
                            )
                            new_node.GetComponentsWithAspect("Light")[0].SetShadowBias(
                                float(get_nml_node_data(light.GetChild("ShadowBias"), 0.01))
                            )

                            uid_dict[str(uid)] = new_node

                            # ----------- GEOMETRIES & NULL OBJECTS ----------------------
                for in_item in in_items:
                    #   Load items with geometry
                    mobjects = in_item.GetChilds("MObject")
                    for mobject in mobjects:
                        mitem = mobject.GetChild("MItem")
                        if (
                            mitem is not None
                            and mitem.GetChild("Active") is not None
                            and mitem.GetChild("Helper") is None
                        ):
                            object = mobject.GetChild("Object")
                            item = object.GetChild("Item")

                            # get item name
                            item_name = get_nml_node_data(mitem.GetChild("Id"), "default_name")
                            uid = int(get_nml_node_data(mitem.GetChild("UId"), -1))

                            # get item geometry
                            geometry_filename = None
                            if object is not None:
                                geometry = object.GetChild("Geometry")
                                if geometry is not None:
                                    geometry_filename = geometry.m_Data
                                    geometry_filename = clean_nml_string(geometry_filename)
                                    if geometry_filename.find("/") > -1:
                                        geometry_filename = geometry_filename.split("/")[-1]
                                    geometry_filename = geometry_filename.replace(".nmg", ".geo")

                                    # transformation
                            position, rotation, scale, rotation_order = parse_transformation(item)

                            new_node = None

                            if geometry_filename is not None and geometry_filename != "":
                                new_node = scene.add_geometry(scn, os.path.join(folder_assets, geometry_filename))
                            else:
                                new_node = scene.add_geometry(scn, "")

                            if new_node is not None:
                                new_node.SetName(item_name)
                                new_node.GetComponentsWithAspect("Transform")[0].SetPosition(position)
                                new_node.GetComponentsWithAspect("Transform")[0].SetRotation(rotation)
                                new_node.GetComponentsWithAspect("Transform")[0].SetScale(scale)

                                # physics
                                physic_item = mitem.GetChild("PhysicItem")
                                if physic_item is not None:
                                    physic_mode = get_nml_node_data(physic_item.GetChild("Mode"), "None")
                                    if physic_mode != "None":
                                        rigid_body = gs.MakeRigidBody()

                                        linear_damping = 1.0 - float(
                                            get_nml_node_data(physic_item.GetChild("LinearDamping_v2"), 1.0)
                                        )
                                        angular_damping = 1.0 - float(
                                            get_nml_node_data(physic_item.GetChild("AngularDamping_v2"), 1.0)
                                        )
                                        rigid_body.SetLinearDamping(linear_damping)
                                        rigid_body.SetAngularDamping(angular_damping)

                                        physic_self_mask = int(get_nml_node_data(physic_item.GetChild("SelfMask"), 1))
                                        physic_collision_mask = int(get_nml_node_data(physic_item.GetChild("Mask"), 1))

                                        new_node.AddComponent(rigid_body)

                                        # iterate on shapes
                                        physic_root_shapes = physic_item.GetChild("Shapes")
                                        if physic_root_shapes is not None:
                                            physic_shapes = physic_root_shapes.GetChilds("GColShape")
                                            if physic_shapes is not None:
                                                for physic_shape in physic_shapes:
                                                    physic_shape_type = get_nml_node_data(
                                                        physic_shape.GetChild("Type"), "Box"
                                                    )

                                                    col_type_dict = {
                                                        "Box": gs.MakeBoxCollision(),
                                                        "Sphere": gs.MakeSphereCollision(),
                                                        "Capsule": gs.MakeCapsuleCollision(),
                                                        "Cylinder": gs.MakeCapsuleCollision(),
                                                        "Mesh": gs.MakeMeshCollision(),
                                                        "Convex": gs.MakeConvexCollision(),
                                                    }

                                                    if physic_shape_type in col_type_dict:
                                                        new_collision_shape = col_type_dict[physic_shape_type]
                                                    else:
                                                        new_collision_shape = gs.MakeBoxCollision()

                                                    new_collision_shape.SetMass(
                                                        float(get_nml_node_data(physic_shape.GetChild("Mass"), 1.0))
                                                    )
                                                    new_collision_shape.SetSelfMask(physic_self_mask)
                                                    new_collision_shape.SetCollisionMask(physic_collision_mask)

                                                    position, rotation, scale, dimensions = parse_collision_shape_transformation(
                                                        physic_shape
                                                    )

                                                    # new_collision_shape.SetMatrix()

                                                    if physic_shape_type == "Box":
                                                        new_collision_shape.SetDimensions(dimensions)
                                                    elif physic_shape_type == "Sphere":
                                                        new_collision_shape.SetRadius(dimensions.x)
                                                    elif (
                                                        physic_shape_type == "Capsule"
                                                        or physic_shape_type == "Cylinder"
                                                    ):
                                                        new_collision_shape.SetRadius(dimensions.x)
                                                        new_collision_shape.SetLength(dimensions.y)

                                                    new_node.AddComponent(new_collision_shape)

                                uid_dict[str(uid)] = new_node

                                # ----------- RE-LINKAGE ----------------------
                for linkage in links:
                    if linkage["parent"] is not None and linkage["child"] is not None:

                        if str(linkage["child"]) in uid_dict and str(linkage["parent"]) in uid_dict:
                            uid_dict[str(linkage["child"])].GetComponentsWithAspect("Transform")[0].SetParent(
                                uid_dict[str(linkage["parent"])]
                            )

                            # ----------- ENVIRONMENT ----------------------
                in_globals = in_root.GetChild("Globals")

                env_global = gs.Environment()
                scn.AddComponent(env_global)

                bg_color, ambient_color, fog_color = parse_globals_color(in_globals)

                ambient_intensity = float(get_nml_node_data(in_globals.GetChild("AmbientIntensity"), 0.5))
                fog_near = float(get_nml_node_data(in_globals.GetChild("FogNear"), 0.5))
                fog_far = float(get_nml_node_data(in_globals.GetChild("FogFar"), 0.5))

                env_global.SetBackgroundColor(bg_color)

                env_global.SetAmbientIntensity(ambient_intensity)
                env_global.SetAmbientColor(ambient_color)

                env_global.SetFogNear(fog_near)
                env_global.SetFogFar(fog_far)
                env_global.SetFogColor(fog_color)

                scn.Commit()
                scn.WaitCommit()

                # Creates the output folder
                folder_out = folder_path.replace(root_in + "\\", "")
                folder_out = folder_out.replace(root_in + "/", "")
                folder_out = folder_out.replace(root_in, "")

                if folder_out != "" and not os.path.exists(os.path.join(root_out, folder_out)):
                    os.makedirs(os.path.join(root_out, folder_out), exist_ok=True)

                    # Saves the scene
                out_file = os.path.join("@out", folder_out, in_file.replace(".nms", ".scn"))
                print("saving to ", out_file)
                scn.Save(out_file, gs.SceneSaveContext(render.get_render_system()))

                # Clears the scene
                scn.Clear()
                scn.Dispose()
                scn = None
import gs.plus.input as input
import gs.plus.scene as scene
import gs.plus.clock as clock
from math import pi, cos, sin, asin
import codecs

filename_out = "../src/simulation"
scale_factor = 5.0

gs.plus.create_workers()
gs.LoadPlugins(gs.get_default_plugins_path())

render.init(1280, 720, "../pkg.core")

scn = scene.new_scene()
cam = scene.add_camera(scn, gs.Matrix4.TranslationMatrix(gs.Vector3(0, 3.5, -12.5)))
cam.GetTransform().SetRotation(gs.Vector3(pi * 5.0 / 180.0, pi * -5.0 / 180.0, 0))

scene.add_light(scn, gs.Matrix4.RotationMatrix(gs.Vector3(0.65, -0.45, 0)), gs.Light.Model_Linear, 150)
scene.add_light(
    scn, gs.Matrix4.RotationMatrix(gs.Vector3(0.55, pi, 0.2)), gs.Light.Model_Linear, diffuse=gs.Color(0.3, 0.3, 0.4)
)
scene.add_physic_plane(scn)

# nodes = add_kapla_tower(scn, 0.5, 2, 2, 6, 16)

width, height, length = 1, 1, 1

node_list = []
stream_list = []
def tile_quantizer(x):
	x /= sphere_radius
	x = int(x)
	x *= sphere_radius
	return x

gs.plus.create_workers()
gs.LoadPlugins(gs.get_default_plugins_path())

render.init(1024, int(1024 * md_screen_h / md_screen_w), "../pkg.core")

scn = scene.new_scene()
scn.GetPhysicSystem().SetDefaultRigidBodyAxisLock(gs.LockZ + gs.LockRotX + gs.LockRotY)
scn.GetPhysicSystem().SetDebugVisuals(True)

cam = scene.add_camera(scn, gs.Matrix4.TranslationMatrix(gs.Vector3(0, 0.0, -md_screen_w * 1.15)))

screen = scene.add_plane(scn, mat=gs.Matrix4.TransformationMatrix(gs.Vector3(0,0,0), gs.Vector3(radians(-90),0,0)), width=md_screen_w, depth=md_screen_h)

scene.add_light(scn, gs.Matrix4.RotationMatrix(gs.Vector3(0.65, -0.45, 0)), gs.Light.Model_Linear, 150)
scene.add_light(scn, gs.Matrix4.RotationMatrix(gs.Vector3(0.55, pi, 0.2)), gs.Light.Model_Linear, diffuse=gs.Color(0.3, 0.3, 0.4))
ground = scene.add_physic_plane(scn, mat=gs.Matrix4.TransformationMatrix(gs.Vector3(0,-md_screen_h / 2,0), gs.Vector3(0,0,0)))


def enable_ground(flag):
	global ground, node_list
	ground[1].SetEnabled(flag)

	# if flag is False:
	# 	for _node in node_list:
	# 		if _node.GetComponent("RigidBody").GetIsSleeping():