using Godot; using System.Collections.Generic; namespace Rokojori { [Tool] [GlobalClass, Icon("res://addons/rokojori_action_library/Icons/FlareVFX.svg") ] public partial class FlareLayer:Resource { [Export] public string layerName = ""; [Export] public bool solo = false; [Export] public bool hide = false; [Export( PropertyHint.Range, "0,1" )] public float opacity = 1f; [Export] public int numLayers = 1; [Export] public FlareType flareType; [ExportGroup("Color/Overwrite")] [Export] public Color overwriteColor = Colors.White; [Export( PropertyHint.Range, "0,1" )] public float overwriteAmount = 0f; [ExportGroup("Color")] [Export( PropertyHint.Range, "-180,180" )] public float minHueRandom = 0; [Export( PropertyHint.Range, "-180,180" )] public float maxHueRandom = 0; [Export] public CurveTexture opacityCurvePerLayer = null; [Export] public Color tint = Colors.White; [Export( PropertyHint.Range, "-180,180" )] public float hueShift = 0; [Export( PropertyHint.Range, "-180,180" )] public float temparatureShift = 0; [Export( PropertyHint.Range, "-100,100" )] public float saturationShift = 0; [Export( PropertyHint.Range, "-100,100" )] public float lighntessShift = 0; [ExportGroup("Size")] [Export] public float size = 1; [Export( PropertyHint.Range, "0,1" )] public float sizeScale = 1; [Export( PropertyHint.Range, "0,1" )] public float sizeXScale = 1f; [Export( PropertyHint.Range, "0,1" )] public float sizeYScale = 1f; [Export( PropertyHint.Range, "0,2" )] public float worldSizeScale = 1f; [Export( PropertyHint.Range, "0,2" )] public float screenSizeScale = 1f; [Export( PropertyHint.Range, "0,1" )] public float worldSize_vs_screenSize = 1f; [Export( PropertyHint.Range, "0,2" )] public float randomScaleMin = 1f; [Export( PropertyHint.Range, "0,2" )] public float randomScaleMax = 1f; [Export] public bool overwriteExtension = false; [Export( PropertyHint.Range, "1,10" )] public float extension = 1f; [ExportGroup("ScreenOffset")] [Export] public Vector2 screenOffset = Vector2.Zero; [Export( PropertyHint.Range, "0,1" )] public float screenOffsetStaticScale = 1f; [Export] public Vector2 screenOffsetStaticDirection = Vector2.Zero; [Export( PropertyHint.Range, "0,1" )] public float screenOffsetLayerScale = 1f; [Export] public Vector2 screenOffsetLayerDirection = Vector2.Zero; [ExportGroup("Rotation")] [Export( PropertyHint.Range, "-180,180" )] public float rotation = 0; [Export( PropertyHint.Range, "-180,180" )] public float rotationOverX = 0; [Export( PropertyHint.Range, "-180,180" )] public float rotationOverY = 0f; [Export( PropertyHint.Range, "-180,180" )] public float rotationPerLayer = 0f; [ExportGroup("Overwrites")] [Export] public FlareFading fading = null; [Export] public FlareChromaticAberation chromaticAberation = null; [Export] public FlareOcclusion occlusion = null; [Export] public FlareBlendMode blendMode = null; [Export] public FlareStencilMode stencilMode = null; [Export] public int renderPriority = 0; public Data Create( FlareVFX vfx ) { return new Data( vfx, this ); } public class Data { public FlareLayer layer; public FlareVFX vfx; public MeshInstance3D meshInstance; public ShaderMaterial material; public FlareBlendMode.BlendModeType GetBlendMode() { return layer.blendMode != null ? layer.blendMode.blendMode : vfx.preset.blendMode; } public Data( FlareVFX vfx, FlareLayer layer ) { this.vfx = vfx; this.layer = layer; } public void Update() { if ( meshInstance == null || layer.flareType == null ) { return; } EnsureMesh(); EnsureMaterial(); if ( material == null ) { return; } layer.flareType.ApplyShape( this ); ApplyColor(); ApplySize(); ApplyScreenOffset(); ApplyRotation(); ApplyFading(); ApplyChromaticAberation(); ApplyOcclusion(); material.RenderPriority = layer.renderPriority; } void EnsureMesh() { var arrayMesh = meshInstance.Mesh as ArrayMesh; if ( arrayMesh != null && arrayMesh.SurfaceGetArrayLen( 0 ) == layer.numLayers * 4 ) { return; } var gen = new UnitBillboardQuadsGenerator(); gen.num = layer.numLayers; meshInstance.Mesh = gen.Generate(); } void EnsureMaterial() { var miMaterial = meshInstance.GetSurfaceOverrideMaterial( 0 ) as ShaderMaterial; if ( material != null && miMaterial != null && miMaterial.Shader == layer.flareType.GetShader( this ) ) { return; } material = layer.flareType.CreateMaterial( this ); meshInstance.SetSurfaceOverrideMaterial( 0, material ); } void ApplyColor() { var preset = vfx.preset; var color = preset.mainColor; if ( layer.overwriteAmount > 0 ) { color = color.Lerp( layer.overwriteColor, layer.overwriteAmount ); } color *= layer.tint; var scale = color.GetColorScale(); var hsl = color.ToHSL( scale ); hsl.h += layer.hueShift + preset.hueShift; hsl.h = MathX.Repeat( hsl.h, 360f ); hsl.h = HSLColor.ShiftTemparatureOfHue( hsl.h, preset.temparatureShift + layer.temparatureShift ); hsl.s += ( layer.saturationShift + preset.saturationShift ) / 100f; hsl.l += ( layer.lighntessShift + preset.lightnessShift ) / 100f; hsl.ClampToLimits(); color = hsl.ToRGBA( scale ); // color = preset.mainColor; BaseFlareShader.color.Set( material, color ); BaseFlareShader.opacity.Set( material, preset.opacity * layer.opacity ); BaseFlareShader.opacityCurve.Set( material, layer.opacityCurvePerLayer ); BaseFlareShader.minHueRandom.Set( material, layer.minHueRandom / 360f ); BaseFlareShader.maxHueRandom.Set( material, layer.maxHueRandom / 360f ); } void ApplySize() { var preset = vfx.preset; var size = Vector2.One * preset.scale; size *= layer.size * layer.sizeScale * new Vector2( layer.sizeXScale, layer.sizeYScale ); BaseFlareShader.sizeX.Set( material, size.X ); BaseFlareShader.sizeY.Set( material, size.Y ); BaseFlareShader.worldSizeScale.Set( material, layer.worldSizeScale ); BaseFlareShader.screenSizeScale.Set( material, layer.screenSizeScale ); BaseFlareShader.worldSizeVsScreenSize.Set( material, layer.worldSize_vs_screenSize ); BaseFlareShader.randomScaleMin.Set( material, layer.randomScaleMin ); BaseFlareShader.randomScaleMax.Set( material, layer.randomScaleMax ); BaseFlareShader.extension.Set( material, layer.overwriteExtension ? layer.extension : preset.extension ); } void ApplyScreenOffset() { BaseFlareShader.screenOffset.Set( material, layer.screenOffset ); BaseFlareShader.screenOffsetScale.Set( material, layer.screenOffsetStaticDirection * layer.screenOffsetStaticScale ); BaseFlareShader.screenOffsetLayerSpread.Set( material, layer.screenOffsetLayerDirection * layer.screenOffsetLayerScale ); } void ApplyRotation() { BaseFlareShader.rotation.Set( material, layer.rotation ); BaseFlareShader.rotationOverX.Set( material, layer.rotationOverX ); BaseFlareShader.rotationOverY.Set( material, layer.rotationOverY ); BaseFlareShader.rotationPerLayer.Set( material, layer.rotationPerLayer ); // BaseFlareShader.vertexRotation.Set( material, layer.vertexRotation ); // BaseFlareShader.vertexRotationOverX.Set( material, layer.vertexRotationOverX ); // BaseFlareShader.vertexRotationOverY.Set( material, layer.vertexRotationOverY ); // BaseFlareShader.vertexRotationPerLayer.Set( material, layer.vertexRotationPerLayer ); } void ApplyFading() { var preset = vfx.preset; var fading = preset.fading; if ( layer.fading != null ) { fading = layer.fading; } if ( fading == null ) { BaseFlareShader.fadingMode.Set( material, 0 ); return; } fading.ApplyFading( this ); } void ApplyChromaticAberation() { var preset = vfx.preset; var chromaticAberation = preset.chromaticAberation; if ( layer.chromaticAberation != null ) { chromaticAberation = layer.chromaticAberation; } if ( chromaticAberation == null ) { BaseFlareShader.chromaticAberationMode.Set( material, 0 ); return; } chromaticAberation.ApplyChromaticAberation( this ); } void ApplyOcclusion() { var preset = vfx.preset; var occlusion = preset.occlusion; if ( layer.occlusion != null ) { occlusion = layer.occlusion; } if ( occlusion == null ) { BaseFlareShader.occlusionMode.Set( material, 0 ); return; } occlusion.ApplyOcclusion( this ); } } } }