import { PunctualLight, DirectionalLight, PointLight, SpotLight, RectLight } from '../../../scene/light.js';
import { defineProps } from '../types.js';
import { Vector4, AABB, radian2degree, degree2radian } from '@zephyr3d/base';
import '../../../scene/scene.js';
import '../../../values.js';
import '../../../render/render_queue.js';
import '../../../render/primitive.js';
import '@zephyr3d/device';
import '../../../material/shader/helper.js';
import '../../../material/lambert.js';
import '../../../material/blinn.js';
import '../../../material/unlit.js';
import '../../../material/particle.js';
import '../../../material/meshmaterial.js';
import '../../../material/grassmaterial.js';
import '../../../material/terrain-cm.js';
import '../../../material/pbrmr.js';
import '../../../material/pbrsg.js';
import '../../../material/pbrblueprint.js';
import '../../../material/sprite.js';
import '../../../material/sprite_std.js';
import '../../blueprint/material/texture.js';
import '../../../render/rendergraph/forward_plus_builder.js';
import '../../../render/sky.js';
import '../../../render/clipmap.js';
import '../../../shaders/atmosphere.js';
import { SceneNode } from '../../../scene/scene_node.js';
import { Mesh } from '../../../scene/mesh.js';
import '../../../scene/basesprite.js';
import '../../../scene/water.js';
import '../../../scene/particlesys.js';
import '../../../scene/batchgroup.js';
import { ClipmapTerrain } from '../../../scene/terrain-cm/terrain-cm.js';
import '../../../scene/terrain-cm/grass.js';
import '../../../scene/raycast_visitor.js';

/** @internal */ function getPunctualLightClass() {
    return {
        ctor: PunctualLight,
        parent: SceneNode,
        name: 'PunctualLight',
        getProps () {
            return defineProps([
                {
                    name: 'Color',
                    description: 'Light color',
                    type: 'rgb',
                    default: [
                        1,
                        1,
                        1
                    ],
                    options: {
                        animatable: true
                    },
                    get (value) {
                        value.num[0] = this.color.x;
                        value.num[1] = this.color.y;
                        value.num[2] = this.color.z;
                    },
                    set (value) {
                        this.color = new Vector4(value.num[0], value.num[1], value.num[2], 1);
                    }
                },
                {
                    name: 'Intensity',
                    description: 'Light intensity',
                    type: 'float',
                    default: 1,
                    options: {
                        animatable: true,
                        minValue: 0,
                        maxValue: 100
                    },
                    get (value) {
                        value.num[0] = this.intensity;
                    },
                    set (value) {
                        this.intensity = value.num[0];
                    }
                },
                {
                    name: 'CastShadow',
                    description: 'if true, the light cast shadows',
                    type: 'bool',
                    phase: 0,
                    default: false,
                    get (value) {
                        value.bool[0] = this.castShadow;
                    },
                    set (value) {
                        this.castShadow = value.bool[0];
                    }
                },
                {
                    name: 'ShadowType',
                    description: 'Which type of shadow this light product',
                    type: 'string',
                    phase: 1,
                    default: 'hard',
                    options: {
                        enum: {
                            labels: [
                                'Hard',
                                'PCF',
                                'PCF-PD',
                                'VSM',
                                'ESM'
                            ],
                            values: [
                                'hard',
                                'pcf-opt',
                                'pcf-pd',
                                'vsm',
                                'esm'
                            ]
                        }
                    },
                    get (value) {
                        value.str[0] = this.shadow.mode;
                    },
                    set (value) {
                        this.shadow.mode = value.str[0];
                    },
                    isValid () {
                        return !!this.castShadow;
                    }
                },
                {
                    name: 'ShadowDistance',
                    description: 'Maximum shadow distance',
                    type: 'float',
                    phase: 1,
                    default: 2000,
                    options: {
                        minValue: 0,
                        maxValue: 5000
                    },
                    get (value) {
                        value.num[0] = this.shadow.shadowDistance;
                    },
                    set (value) {
                        this.shadow.shadowDistance = value.num[0];
                    },
                    isValid () {
                        return !!this.castShadow;
                    }
                },
                {
                    name: 'ShadowMapSize',
                    description: 'Shadow map resolution',
                    phase: 1,
                    type: 'int',
                    default: 1024,
                    options: {
                        enum: {
                            labels: [
                                '128x128',
                                '256x256',
                                '512x512',
                                '1024x1024',
                                '2048x2048',
                                '4096x4096'
                            ],
                            values: [
                                128,
                                256,
                                512,
                                1024,
                                2048,
                                4096
                            ]
                        }
                    },
                    get (value) {
                        value.num[0] = this.shadow.shadowMapSize;
                    },
                    set (value) {
                        this.shadow.shadowMapSize = value.num[0];
                    },
                    isValid () {
                        return !!this.castShadow;
                    }
                },
                {
                    name: 'ShadowRegion',
                    description: 'World space AABB, objects inside this AABB can cast shadows',
                    phase: 1,
                    type: 'object',
                    default: null,
                    options: {
                        edit: 'aabb',
                        objectTypes: [
                            AABB
                        ]
                    },
                    isNullable () {
                        return true;
                    },
                    create () {
                        const aabb = new AABB();
                        aabb.beginExtend();
                        this.scene.rootNode.iterate((child)=>{
                            if (child instanceof Mesh || child instanceof ClipmapTerrain) {
                                if (child.castShadow) {
                                    const bbox = child.getWorldBoundingVolume().toAABB();
                                    aabb.extend(bbox.minPoint);
                                    aabb.extend(bbox.maxPoint);
                                }
                            }
                        });
                        if (!aabb.isValid()) {
                            aabb.minPoint.setXYZ(-1, -1, -1);
                            aabb.maxPoint.setXYZ(1, 1, 1);
                        }
                        return aabb;
                    },
                    get (value) {
                        value.object[0] = this.shadow.shadowRegion;
                    },
                    set (value) {
                        this.shadow.shadowRegion = value.object[0];
                    },
                    isValid () {
                        return !!this.castShadow && this.isDirectionLight();
                    }
                },
                {
                    name: 'ShadowDepthBias',
                    description: 'Shadow depth bias',
                    type: 'float',
                    phase: 1,
                    default: 0.5,
                    options: {
                        minValue: 0,
                        maxValue: 5
                    },
                    get (value) {
                        value.num[0] = this.shadow.depthBias;
                    },
                    set (value) {
                        this.shadow.depthBias = value.num[0];
                    },
                    isValid () {
                        return !!this.castShadow;
                    }
                },
                {
                    name: 'ShadowNormalBias',
                    description: 'Shadow normal bias',
                    type: 'float',
                    phase: 1,
                    default: 0.2,
                    options: {
                        minValue: 0,
                        maxValue: 5
                    },
                    get (value) {
                        value.num[0] = this.shadow.normalBias;
                    },
                    set (value) {
                        this.shadow.normalBias = value.num[0];
                    },
                    isValid () {
                        return !!this.castShadow;
                    }
                },
                {
                    name: 'ShadowCascades',
                    description: 'Cascade count for CSM',
                    type: 'int',
                    phase: 1,
                    default: 1,
                    options: {
                        minValue: 1,
                        maxValue: 4
                    },
                    get (value) {
                        value.num[0] = this.shadow.numShadowCascades;
                    },
                    set (value) {
                        this.shadow.numShadowCascades = value.num[0];
                    },
                    isValid () {
                        return !!this.castShadow;
                    }
                },
                {
                    name: 'PCFKernelSize',
                    description: 'Kernel size for PCF shadow',
                    phase: 2,
                    type: 'int',
                    default: 5,
                    options: {
                        enum: {
                            labels: [
                                '3x3',
                                '5x5',
                                '7x7'
                            ],
                            values: [
                                3,
                                5,
                                7
                            ]
                        }
                    },
                    get (value) {
                        value.num[0] = this.shadow.pcfKernelSize;
                    },
                    set (value) {
                        this.shadow.pcfKernelSize = value.num[0];
                    },
                    isValid () {
                        return !!this.castShadow && this.shadow.mode === 'pcf-opt';
                    }
                },
                {
                    name: 'PCFSampleCount',
                    description: 'Sample count for PCF shadow',
                    type: 'int',
                    phase: 2,
                    options: {
                        minValue: 1,
                        maxValue: 128
                    },
                    default: 12,
                    get (value) {
                        value.num[0] = this.shadow.pdSampleCount;
                    },
                    set (value) {
                        this.shadow.pdSampleCount = value.num[0];
                    },
                    isValid () {
                        return !!this.castShadow && this.shadow.mode === 'pcf-pd';
                    }
                },
                {
                    name: 'PCFSampleRadius',
                    description: 'Sample radius for PCF shadow',
                    type: 'float',
                    phase: 2,
                    options: {
                        minValue: 0,
                        maxValue: 64
                    },
                    default: 4,
                    get (value) {
                        value.num[0] = this.shadow.pdSampleRadius;
                    },
                    set (value) {
                        this.shadow.pdSampleRadius = value.num[0];
                    },
                    isValid () {
                        return !!this.castShadow && this.shadow.mode === 'pcf-pd';
                    }
                },
                {
                    name: 'VSMBlurKernelSize',
                    description: 'Blur kernel size of VSM shadow',
                    type: 'int',
                    phase: 2,
                    options: {
                        minValue: 1,
                        maxValue: 33
                    },
                    default: 5,
                    get (value) {
                        value.num[0] = this.shadow.vsmBlurKernelSize;
                    },
                    set (value) {
                        this.shadow.vsmBlurKernelSize = value.num[0];
                    },
                    isValid () {
                        return !!this.castShadow && this.shadow.mode === 'vsm';
                    }
                },
                {
                    name: 'VSMBlurRadius',
                    description: 'Blur radius for VSM shadow',
                    type: 'float',
                    phase: 2,
                    options: {
                        minValue: 0,
                        maxValue: 32
                    },
                    default: 4,
                    get (value) {
                        value.num[0] = this.shadow.vsmBlurRadius;
                    },
                    set (value) {
                        this.shadow.vsmBlurRadius = value.num[0];
                    },
                    isValid () {
                        return !!this.castShadow && this.shadow.mode === 'vsm';
                    }
                },
                {
                    name: 'VSMDarkness',
                    description: 'Darkness for VSM shadow',
                    type: 'float',
                    phase: 2,
                    options: {
                        minValue: 0,
                        maxValue: 1
                    },
                    default: 0.5,
                    get (value) {
                        value.num[0] = this.shadow.vsmDarkness;
                    },
                    set (value) {
                        this.shadow.vsmDarkness = value.num[0];
                    },
                    isValid () {
                        return !!this.castShadow && this.shadow.mode === 'vsm';
                    }
                },
                {
                    name: 'ESMDepthScale',
                    description: 'Depth scale value for ESM shadow',
                    type: 'float',
                    phase: 2,
                    options: {
                        minValue: 1,
                        maxValue: 2000
                    },
                    default: 200,
                    get (value) {
                        value.num[0] = this.shadow.esmDepthScale;
                    },
                    set (value) {
                        this.shadow.esmDepthScale = value.num[0];
                    },
                    isValid () {
                        return !!this.castShadow && this.shadow.mode === 'esm';
                    }
                },
                {
                    name: 'ESMBlur',
                    description: 'If true, enable bluring for ESM shadow',
                    type: 'bool',
                    phase: 2,
                    default: true,
                    get (value) {
                        value.bool[0] = this.shadow.esmBlur;
                    },
                    set (value) {
                        this.shadow.esmBlur = value.bool[0];
                    },
                    isValid () {
                        return !!this.castShadow && this.shadow.mode === 'esm';
                    }
                },
                {
                    name: 'ESMBlurKernelSize',
                    description: 'Blur kernel size for ESM shadow',
                    type: 'int',
                    phase: 2,
                    default: 5,
                    options: {
                        minValue: 1,
                        maxValue: 33
                    },
                    get (value) {
                        value.num[0] = this.shadow.esmBlurKernelSize;
                    },
                    set (value) {
                        this.shadow.esmBlurKernelSize = value.num[0];
                    },
                    isValid () {
                        return !!this.castShadow && this.shadow.mode === 'esm' && this.shadow.esmBlur;
                    }
                },
                {
                    name: 'ESMBlurRadius',
                    description: 'Blur radius for ESM shadow',
                    type: 'float',
                    phase: 2,
                    default: 4,
                    options: {
                        minValue: 0,
                        maxValue: 32
                    },
                    get (value) {
                        value.num[0] = this.shadow.esmBlurRadius;
                    },
                    set (value) {
                        this.shadow.esmBlurRadius = value.num[0];
                    },
                    isValid () {
                        return !!this.castShadow && this.shadow.mode === 'esm' && this.shadow.esmBlur;
                    }
                }
            ]);
        }
    };
}
/** @internal */ function getDirectionalLightClass() {
    return {
        ctor: DirectionalLight,
        name: 'DirectionalLight',
        parent: PunctualLight,
        createFunc (ctx) {
            const node = new DirectionalLight(ctx.scene);
            node.parent = ctx;
            return {
                obj: node
            };
        },
        getProps () {
            return defineProps([
                {
                    name: 'SunLight',
                    description: 'If true, this light will act as sun light and affect sky atmosphere rendering',
                    type: 'bool',
                    default: false,
                    get (value) {
                        value.bool[0] = this.sunLight;
                    },
                    set (value) {
                        this.sunLight = value.bool[0];
                    }
                }
            ]);
        }
    };
}
/** @internal */ function getPointLightClass() {
    return {
        ctor: PointLight,
        name: 'PointLight',
        parent: PunctualLight,
        createFunc (ctx) {
            const node = new PointLight(ctx.scene);
            node.parent = ctx;
            return {
                obj: node
            };
        },
        getProps () {
            return defineProps([
                {
                    name: 'Range',
                    description: 'Light range in world unit',
                    type: 'float',
                    default: 10,
                    options: {
                        animatable: true,
                        minValue: 0,
                        maxValue: 1000
                    },
                    get (value) {
                        value.num[0] = this.range;
                    },
                    set (value) {
                        this.range = value.num[0];
                    }
                },
                {
                    name: 'DiffuseScale',
                    description: 'Diffuse light intensity multiplier',
                    type: 'float',
                    default: 1,
                    options: {
                        animatable: true,
                        minValue: 0,
                        maxValue: 10
                    },
                    get (value) {
                        value.num[0] = this.diffuseScale;
                    },
                    set (value) {
                        this.diffuseScale = value.num[0];
                    }
                },
                {
                    name: 'SpecularScale',
                    description: 'Specular light intensity multiplier',
                    type: 'float',
                    default: 1,
                    options: {
                        animatable: true,
                        minValue: 0,
                        maxValue: 10
                    },
                    get (value) {
                        value.num[0] = this.specularScale;
                    },
                    set (value) {
                        this.specularScale = value.num[0];
                    }
                },
                {
                    name: 'SourceRadius',
                    description: 'Apparent radius of the light source for soft shadows and highlights',
                    type: 'float',
                    default: 0,
                    options: {
                        animatable: true,
                        minValue: 0,
                        maxValue: 100
                    },
                    get (value) {
                        value.num[0] = this.sourceRadius;
                    },
                    set (value) {
                        this.sourceRadius = value.num[0];
                    }
                }
            ]);
        }
    };
}
/** @internal */ function getSpotLightClass() {
    return {
        ctor: SpotLight,
        name: 'SpotLight',
        parent: PunctualLight,
        createFunc (ctx) {
            const node = new SpotLight(ctx.scene);
            node.parent = ctx;
            return {
                obj: node
            };
        },
        getProps () {
            return defineProps([
                {
                    name: 'Range',
                    description: 'Light range in world unit',
                    type: 'float',
                    default: 10,
                    options: {
                        animatable: true,
                        minValue: 0,
                        maxValue: 1000
                    },
                    get (value) {
                        value.num[0] = this.range;
                    },
                    set (value) {
                        this.range = value.num[0];
                    }
                },
                {
                    name: 'BeamAngle',
                    description: 'Beam angle of cone',
                    type: 'float',
                    default: 90,
                    options: {
                        animatable: true,
                        minValue: 0,
                        maxValue: 180
                    },
                    get (value) {
                        value.num[0] = radian2degree(Math.acos(this.cutoff) * 2);
                    },
                    set (value) {
                        this.cutoff = Math.cos(degree2radian(value.num[0]) * 0.5);
                    }
                }
            ]);
        }
    };
}
/** @internal */ function getRectLightClass() {
    return {
        ctor: RectLight,
        name: 'RectLight',
        parent: PunctualLight,
        createFunc (ctx) {
            const node = new RectLight(ctx.scene);
            node.parent = ctx;
            return {
                obj: node
            };
        },
        getProps () {
            return defineProps([
                {
                    name: 'Range',
                    description: 'Light range in world unit',
                    type: 'float',
                    default: 10,
                    options: {
                        animatable: true,
                        minValue: 0,
                        maxValue: 1000
                    },
                    get (value) {
                        value.num[0] = this.range;
                    },
                    set (value) {
                        this.range = value.num[0];
                    }
                },
                {
                    name: 'Width',
                    description: 'Width of the light',
                    type: 'float',
                    default: 1,
                    options: {
                        animatable: true,
                        minValue: 0,
                        maxValue: 1000
                    },
                    get (value) {
                        value.num[0] = this.width;
                    },
                    set (value) {
                        this.width = value.num[0];
                    }
                },
                {
                    name: 'Height',
                    description: 'Height of the light',
                    type: 'float',
                    default: 1,
                    options: {
                        animatable: true,
                        minValue: 0,
                        maxValue: 1000
                    },
                    get (value) {
                        value.num[0] = this.height;
                    },
                    set (value) {
                        this.height = value.num[0];
                    }
                }
            ]);
        }
    };
}

export { getDirectionalLightClass, getPointLightClass, getPunctualLightClass, getRectLightClass, getSpotLightClass };
//# sourceMappingURL=light.js.map
