using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEditor;
using UnityEditor.SceneManagement;

namespace Embatte.Glacier
{
    // Original surfaces and terrain, authored for the actual game camera.
    public static class GlacierAssets
    {
        const string Root="Assets/Glacier";
        static string Output=>Path.GetFullPath("../artifacts/glacier-v2");
        static readonly Dictionary<string,Material> Materials=new Dictionary<string,Material>();
        static readonly System.Random Random=new System.Random(92127);
        static Vector3 V(float x,float y,float z)=>new Vector3(x,y,z);
        static Color C(string s){ColorUtility.TryParseHtmlString("#"+s,out var c);return c;}
        static float Rand(float a,float b)=>a+(b-a)*(float)Random.NextDouble();
        static float Noise(float x,float y,float z)=> (Mathf.PerlinNoise(x+13.71f,y+8.21f)+Mathf.PerlinNoise(y+37.9f,z+2.3f)+Mathf.PerlinNoise(z+9.11f,x+23.47f))/3;
        static float Fbm(float x,float y,float z){float sum=0,amplitude=.55f;for(int i=0;i<4;i++){sum+=Noise(x,y,z)*amplitude;x=x*2.13f+2.1f;y=y*2.13f+5.4f;z=z*2.13f+7.6f;amplitude*=.49f;}return sum;}
        static GameObject Group(string name,Transform parent=null){var g=new GameObject(name);if(parent)g.transform.SetParent(parent,false);return g;}
        static GameObject MeshObject(string name,Mesh mesh,Material mat,Transform parent=null)
        {var g=Group(name,parent);g.AddComponent<MeshFilter>().sharedMesh=mesh;var r=g.AddComponent<MeshRenderer>();r.sharedMaterial=mat;r.shadowCastingMode=ShadowCastingMode.On;r.receiveShadows=true;return g;}
        static Mesh Mesh(List<Vector3> vertices,List<Vector2> uv,List<int> triangles,string name)
        {var m=new Mesh{name=name,indexFormat=IndexFormat.UInt32};m.SetVertices(vertices);m.SetUVs(0,uv);m.SetTriangles(triangles,0);m.RecalculateNormals();var normals=m.normals;for(int i=0;i<normals.Length;i++)if(normals[i].sqrMagnitude<.01f)normals[i]=vertices[i].sqrMagnitude>.01f?vertices[i].normalized:Vector3.up;m.normals=normals;m.RecalculateBounds();m.RecalculateTangents();return m;}
        static void SaveTexture(string path,Color[] pixels,int n,bool normal=false)
        {
            var texture=new Texture2D(n,n,TextureFormat.RGB24,false);texture.SetPixels(pixels);texture.Apply();File.WriteAllBytes(path,texture.EncodeToPNG());UnityEngine.Object.DestroyImmediate(texture);AssetDatabase.ImportAsset(path);
            var importer=(TextureImporter)AssetImporter.GetAtPath(path);importer.isReadable=true;importer.wrapMode=TextureWrapMode.Repeat;importer.textureCompression=TextureImporterCompression.Uncompressed;importer.maxTextureSize=1024;importer.mipmapEnabled=true;
            if(normal){importer.textureType=TextureImporterType.NormalMap;importer.sRGBTexture=false;}else if(path.Contains("Roughness"))importer.sRGBTexture=false;importer.SaveAndReimport();
        }
        static void Stroke(float[] field,int n,Vector2 a,Vector2 b,float width,float strength)
        {
            int minX=Mathf.Max(0,Mathf.FloorToInt(Mathf.Min(a.x,b.x)-width-2)),maxX=Mathf.Min(n-1,Mathf.CeilToInt(Mathf.Max(a.x,b.x)+width+2));
            int minY=Mathf.Max(0,Mathf.FloorToInt(Mathf.Min(a.y,b.y)-width-2)),maxY=Mathf.Min(n-1,Mathf.CeilToInt(Mathf.Max(a.y,b.y)+width+2));var d=b-a;float len=d.sqrMagnitude;
            for(int y=minY;y<=maxY;y++)for(int x=minX;x<=maxX;x++){var p=new Vector2(x,y);float t=len>0?Mathf.Clamp01(Vector2.Dot(p-a,d)/len):0,dist=Vector2.Distance(p,a+d*t);field[y*n+x]=Mathf.Max(field[y*n+x],Mathf.Clamp01((width+1-dist)/1.4f)*strength);}
        }
        static Material Surface(string name,string type,Color tint,float roughness,float metal=0,int n=512)
        {
            var height=new float[n*n];var crack=new float[n*n];var pixels=new Color[n*n];var normals=new Color[n*n];var rough=new Color[n*n];
            bool snow=type.StartsWith("snow"),ice=type.StartsWith("ice");
            if(ice){var rand=new System.Random(421+name.Length);for(int k=0;k<18;k++){
                var p=new Vector2((float)rand.NextDouble()*n,(float)rand.NextDouble()*n);float angle=(float)rand.NextDouble()*Mathf.PI*2;int segments=5+rand.Next(8);
                for(int j=0;j<segments;j++){angle+=((float)rand.NextDouble()-.5f)*.8f;var next=p+new Vector2(Mathf.Cos(angle),Mathf.Sin(angle))*(12+rand.Next(38));Stroke(crack,n,p,next,k%5==0?1.8f:.5f,k%3==0?.8f:.45f);if(j==2){var branch=p+new Vector2(Mathf.Cos(angle+.85f),Mathf.Sin(angle+.85f))*34;Stroke(crack,n,p,branch,.4f,.4f);}p=next;}
            }}
            for(int y=0;y<n;y++)for(int x=0;x<n;x++){
                int i=y*n+x;float u=(float)x/n,v=(float)y/n,grain=(float)Random.NextDouble(),cloud=Fbm(u*9,0,v*9),value=1,h=0,r=roughness;
                if(snow){
                    float latitude=v*Mathf.PI,longitude=u*Mathf.PI*2;var q=V(Mathf.Sin(latitude)*Mathf.Cos(longitude),Mathf.Cos(latitude),Mathf.Sin(latitude)*Mathf.Sin(longitude));
                    float broad=Fbm(q.x*8,q.y*8,q.z*8),crystals=Noise(q.x*155,q.y*155,q.z*155),fine=Noise(q.x*360,q.y*360,q.z*360);
                    h=broad*.13f+crystals*.18f+fine*.08f;value=.9f+broad*.11f+fine*.035f;r=Mathf.Clamp01(.8f+crystals*.22f);if(type=="snow-packed"){h*=.7f;value-=Mathf.Max(0,.38f-broad)*.12f;r-=.1f;}
                    if(type=="snow-wind"){float drift=Mathf.Sin((u*28+cloud*3)*Mathf.PI)*.024f;h+=drift;value+=drift*.3f;}
                }else if(ice){
                    float layers=Mathf.PerlinNoise(u*5+cloud*.7f,v*(type=="ice-wall"?42:12)),bubbles=Mathf.Pow(Mathf.Max(0,Mathf.PerlinNoise(u*150,v*150)-.64f)*3,3);
                    h=cloud*.07f+layers*.035f+grain*.006f-crack[i]*.07f;value=.73f+cloud*.26f+layers*.1f+bubbles*.05f;r=Mathf.Clamp01(roughness+layers*.15f-crack[i]*.15f);
                }else if(type=="cloth"){
                    float warp=(x%4==0||y%4==0)?-.025f:.01f;h=.15f*cloud+warp+grain*.015f;value=.78f+cloud*.22f+warp*.6f;r=.86f+grain*.09f;
                }else if(type=="leather"){float pores=Mathf.PerlinNoise(u*105,v*105);h=cloud*.055f+pores*.08f;value=.7f+cloud*.2f+pores*.1f;r=.52f+pores*.22f;}
                else if(type=="wood"){float fibres=Mathf.PerlinNoise(u*65+cloud*4,v*2);h=fibres*.12f+cloud*.08f;value=.62f+fibres*.3f+cloud*.12f;r=.72f+fibres*.18f;}
                else {h=cloud*.12f+Mathf.PerlinNoise(u*90,v*90)*.04f;value=.67f+cloud*.28f+grain*.08f;r=roughness+grain*.06f;}
                height[i]=h;var color=tint*value;color.a=1;if(ice)color=Color.Lerp(color,C("d9eff0"),crack[i]*.62f);pixels[i]=color;rough[i]=new Color(1,Mathf.Clamp01(r),1,1);
            }
            for(int y=0;y<n;y++)for(int x=0;x<n;x++){float dx=height[y*n+(x+1)%n]-height[y*n+(x+n-1)%n],dy=height[((y+1)%n)*n+x]-height[((y+n-1)%n)*n+x];var normal=V(-dx*(snow?6:5),-dy*(snow?6:5),1).normalized;normals[y*n+x]=new Color(normal.x*.5f+.5f,normal.y*.5f+.5f,normal.z*.5f+.5f);}
            string basePath=Root+"/Textures/"+name;SaveTexture(basePath+"-Color.png",pixels,n);SaveTexture(basePath+"-Normal.png",normals,n,true);SaveTexture(basePath+"-Roughness.png",rough,n);
            var m=new Material(Shader.Find("Standard")){name=name,color=Color.white,enableInstancing=true};m.SetFloat("_Metallic",metal);m.SetFloat("_Glossiness",1-roughness);m.mainTexture=AssetDatabase.LoadAssetAtPath<Texture2D>(basePath+"-Color.png");m.SetTexture("_BumpMap",AssetDatabase.LoadAssetAtPath<Texture2D>(basePath+"-Normal.png"));m.SetFloat("_BumpScale",snow?.9f:.7f);m.EnableKeyword("_NORMALMAP");m.SetOverrideTag("EmbatteRoughness",Path.GetFullPath(basePath+"-Roughness.png"));
            string path=Root+"/Materials/"+name+".mat";if(File.Exists(path))AssetDatabase.DeleteAsset(path);AssetDatabase.CreateAsset(m,path);Materials[name]=m;return m;
        }
        static void MakeMaterials()
        {
            Surface("FreshSnow","snow",C("f6f8f7"),.95f);Surface("PackedSnow","snow-packed",C("e4edf0"),.86f);Surface("WindSnow","snow-wind",C("edf2f2"),.94f);
            Surface("GlacierTop","ice-floor",C("b5dce3"),.31f,0,1024);Surface("BlueIce","ice-wall",C("73b7d0"),.34f,0,1024);Surface("DeepIce","ice-wall",C("48849e"),.4f);Surface("Stone","stone",C("747d7c"),.92f);
            Surface("Canvas","cloth",C("d7d8d0"),.9f);Surface("Hide","leather",C("796459"),.7f);Surface("Timber","wood",C("aa9480"),.85f);
        }
        static GameObject Snowball(string name,int type)
        {
            int cols=64,rows=40;var vertices=new List<Vector3>();var uv=new List<Vector2>();var indices=new List<int>();
            for(int y=0;y<=rows;y++)for(int x=0;x<=cols;x++){
                float u=(float)x/cols,v=(float)y/rows,lat=v*Mathf.PI,lon=u*Mathf.PI*2;var p=V(Mathf.Sin(lat)*Mathf.Cos(lon),Mathf.Cos(lat),Mathf.Sin(lat)*Mathf.Sin(lon));
                float uneven=(Fbm(p.x*5,p.y*5,p.z*5)-.48f)*.06f+(Noise(p.x*32,p.y*32,p.z*32)-.5f)*.014f;float radius=1+uneven*(type==1?.6f:1);vertices.Add(p*radius);uv.Add(new Vector2(u,1-v));
                if(y<rows&&x<cols){int a=y*(cols+1)+x,b=a+cols+1;indices.AddRange(new[]{a,a+1,b,a+1,b+1,b});}
            }
            var mesh=Mesh(vertices,uv,indices,name+"_NaturalSnow");var normals=mesh.normals;for(int y=0;y<=rows;y++){int a=y*(cols+1),b=a+cols;var n=(normals[a]+normals[b]).normalized;normals[a]=normals[b]=n;}for(int x=0;x<=cols;x++){normals[x]=Vector3.up;normals[rows*(cols+1)+x]=Vector3.down;}mesh.normals=normals;
            var g=Group(name);MeshObject("Natural snow — scalable radius",mesh,Materials[type==0?"FreshSnow":type==1?"PackedSnow":"WindSnow"],g.transform);return g;
        }
        static float Rim(float a,int variant)=>9.1f+.25f*Mathf.Sin(a*3+variant)+.17f*Mathf.Sin(a*7.1f+.8f);
        static GameObject Platform(Transform parent,int variant)
        {
            const int segments=128,rings=22;var vertices=new List<Vector3>();var uv=new List<Vector2>();var indices=new List<int>();
            for(int r=0;r<=rings;r++)for(int i=0;i<=segments;i++){float a=i*Mathf.PI*2/segments,rad=Rim(a,variant)*r/rings,x=Mathf.Sin(a)*rad,z=Mathf.Cos(a)*rad,h=(Noise(x*.6f,0,z*.6f)-.5f)*.055f;vertices.Add(V(x,h,z));uv.Add(new Vector2(x/18f+.5f,z/18f+.5f));if(r<rings&&i<segments){int p=r*(segments+1)+i,q=p+segments+1;indices.AddRange(new[]{p,q,p+1,p+1,q,q+1});}}
            var top=MeshObject("PlayableIceSurface",Mesh(vertices,uv,indices,"Continuous glacial ice"),Materials["GlacierTop"],parent);
            vertices.Clear();uv.Clear();indices.Clear();
            for(int j=0;j<=5;j++)for(int i=0;i<=segments;i++){float a=i*Mathf.PI*2/segments,rad=Rim(a,variant)+(j==0?0:Mathf.Sin(a*13+j*.7f)*.14f),x=Mathf.Sin(a)*rad,z=Mathf.Cos(a)*rad;vertices.Add(V(x,-j*.6f,z));uv.Add(new Vector2(i/14f,1-j/5f));if(j<5&&i<segments){int p=j*(segments+1)+i,q=p+segments+1;indices.AddRange(new[]{p,q,p+1,p+1,q,q+1});}}
            MeshObject("Layered ice shelf edge",Mesh(vertices,uv,indices,"Exposed blue ice"),Materials["BlueIce"],parent);return top;
        }
        static float RidgeHeight(float angle,float across,int variant)
        {
            float back=(1-Mathf.Cos(angle))*.5f,side=Mathf.Abs(Mathf.Sin(angle));float front=Mathf.Cos(angle)>.65f?.18f:1;
            float peaks=.9f+Mathf.Pow(Mathf.Abs(Mathf.Sin(angle*4.4f+variant)),2)*2.8f+Noise(Mathf.Cos(angle)*5,variant,Mathf.Sin(angle)*5)*2.5f;
            return Mathf.Sin(Mathf.Clamp01(across)*Mathf.PI)*peaks*front*(variant==1?1.35f:1)+(variant==2?.3f:0);
        }
        static float WallHeight(float a,int variant)
        {
            float front=Mathf.SmoothStep(0,1,(.7f-Mathf.Cos(a))*1.9f);
            float broken=.5f+Noise(Mathf.Sin(a)*12,variant*4,Mathf.Cos(a)*12)*2.2f+Mathf.Pow(Mathf.Abs(Mathf.Sin(a*4.3f+.6f)),3)*2.7f;
            return .2f+front*broken*(variant==1?1.3f:1);
        }
        static float WallRadius(float a,int variant)=>10.2f+.3f*Mathf.Sin(a*3.1f+variant)+.16f*Mathf.Sin(a*17)+.15f*Mathf.Sin(a*31.7f);
        static void Ridges(Transform parent,int variant)
        {
            const int segments=240,levels=8,strips=28;var vertices=new List<Vector3>();var uv=new List<Vector2>();var indices=new List<int>();
            // Continuous fractured blue wall, under a continuous wind-shaped snowfield.
            for(int j=0;j<=levels;j++)for(int i=0;i<=segments;i++){
                float a=i*Mathf.PI*2/segments,t=(float)j/levels,rad=WallRadius(a,variant)+(1-t)*.1f+Mathf.Sin(a*47+j*.45f)*.09f*t;
                float height=WallHeight(a,variant);vertices.Add(V(Mathf.Sin(a)*rad,Mathf.Lerp(-2.2f,height,t),Mathf.Cos(a)*rad));uv.Add(new Vector2(i/32f,t*1.3f));
                if(j<levels&&i<segments){int p=j*(segments+1)+i,q=p+segments+1;indices.AddRange(new[]{p,q,p+1,p+1,q,q+1});}
            }
            MeshObject("Continuous fractured glacier wall",Mesh(vertices,uv,indices,"Compressed blue glacial wall"),Materials["BlueIce"],parent);
            vertices.Clear();uv.Clear();indices.Clear();
            for(int k=0;k<=strips;k++)for(int i=0;i<=segments;i++){
                float a=i*Mathf.PI*2/segments,t=(float)k/strips,radius=WallRadius(a,variant)+t*9.4f;
                float baseHeight=WallHeight(a,variant),mountain=Noise(Mathf.Sin(a)*8,variant,Mathf.Cos(a)*8)*5;
                float wave=Mathf.Sin(t*Mathf.PI)*mountain*.65f;float height=Mathf.Lerp(baseHeight,.25f,t*t)+wave;
                float noise=(Noise(Mathf.Sin(a)*radius*.38f,t*1.3f,Mathf.Cos(a)*radius*.38f)-.5f)*t*.45f;
                float x=Mathf.Sin(a)*radius,z=Mathf.Cos(a)*radius;vertices.Add(V(x,height+noise+.025f,z));uv.Add(new Vector2(x/14f,z/14f));
                if(k<strips&&i<segments){int p=k*(segments+1)+i,q=p+segments+1;indices.AddRange(new[]{p,q,p+1,p+1,q,q+1});}
            }
            MeshObject("Continuous wind packed snowfield",Mesh(vertices,uv,indices,"Natural snow dunes"),Materials["WindSnow"],parent);
        }
        static void Serac(Transform parent,Vector3 position,Vector3 size,float angle,int seed)
        {
            const int sides=12,levels=7;var vertices=new List<Vector3>();var uv=new List<Vector2>();var indices=new List<int>();
            for(int j=0;j<=levels;j++)for(int i=0;i<=sides;i++){
                float a=i*Mathf.PI*2/sides,t=(float)j/levels;float sx=Mathf.Sin(a),sz=Mathf.Cos(a),radius=1+(Noise(sx*4+seed,t*3,sz*4)-.5f)*.35f;
                float lean=t*t*.12f;float x=(sx*radius+lean)*size.x,z=sz*radius*size.z,y=t*size.y*(1+.1f*Mathf.Sin(a*3+seed));vertices.Add(V(x,y,z));uv.Add(new Vector2((float)i/sides*1.8f,t*1.5f));
                if(j<levels&&i<sides){int p=j*(sides+1)+i,q=p+sides+1;indices.AddRange(new[]{p,p+1,q,p+1,q+1,q});}
            }
            var root=Group("Fractured ice ridge",parent);root.transform.localPosition=position;root.transform.localRotation=Quaternion.Euler(0,angle,0);
            MeshObject("Striated ice face",Mesh(vertices,uv,indices,"Natural serac"),Materials[seed%3==0?"DeepIce":"BlueIce"],root.transform);
            var capVertices=new List<Vector3>{V(size.x*.12f,size.y*1.015f,0)};var capUv=new List<Vector2>{new Vector2(.5f,.5f)};var capIndices=new List<int>();
            for(int i=0;i<=sides;i++){var v=vertices[levels*(sides+1)+i]+V(0,.025f,0);capVertices.Add(v);capUv.Add(new Vector2(v.x/size.x*.5f+.5f,v.z/size.z*.5f+.5f));if(i<sides)capIndices.AddRange(new[]{0,i+1,i+2});}
            MeshObject("Wind packed snowcap",Mesh(capVertices,capUv,capIndices,"Irregular snowcap"),Materials["PackedSnow"],root.transform);
        }
        static void Crevasse(Transform parent,Vector3 start,float heading,float length,int variant)
        {
            var verts=new List<Vector3>();var uv=new List<Vector2>();var indices=new List<int>();int steps=22;
            for(int i=0;i<=steps;i++){float t=(float)i/steps;var p=start+V(Mathf.Sin(heading)*length*t,0,Mathf.Cos(heading)*length*t);float waviness=Mathf.Sin(t*19+variant)*.18f,half=(.08f+Mathf.Sin(t*Mathf.PI)*.09f);var across=V(Mathf.Cos(heading),0,-Mathf.Sin(heading));p+=across*waviness;verts.Add(p-across*half+V(0,.045f,0));verts.Add(p+across*half+V(0,.045f,0));uv.Add(new Vector2(0,t));uv.Add(new Vector2(1,t));if(i<steps){int k=i*2;indices.AddRange(new[]{k,k+2,k+1,k+1,k+2,k+3});}}
            MeshObject("Deep blue hairline crevasse",Mesh(verts,uv,indices,"Ice fracture"),Materials["DeepIce"],parent);
        }
        static GameObject Glacier(string name,int variant)
        {
            var root=Group(name);var parent=root.transform;Platform(parent,variant);Ridges(parent,variant);
            
            // Fractures stay shallow on the playing area. All deep geometry lies outside it.
            
            var water=GameObject.CreatePrimitive(PrimitiveType.Cylinder);water.name="Water below glacier";water.transform.SetParent(parent,false);water.transform.localPosition=V(0,-2.6f,0);water.transform.localScale=V(40,.03f,40);UnityEngine.Object.DestroyImmediate(water.GetComponent<Collider>());var waterMat=new Material(Shader.Find("Standard")){name="GlacialWater",color=C("244b63")};waterMat.SetFloat("_Glossiness",.72f);AssetDatabase.CreateAsset(waterMat,AssetDatabase.GenerateUniqueAssetPath(Root+"/Materials/GlacialWater.mat"));water.GetComponent<Renderer>().sharedMaterial=waterMat;
            return root;
        }
        static Material DetailedMaterial(Material original)
        {
            string n=original.name.ToLowerInvariant(),type=n.Contains("cloth")||n.Contains("azure")||n.Contains("coral")||n.Contains("team")?"Canvas":n.Contains("leather")||n.Contains("rubber")?"Hide":n.Contains("wood")||n.Contains("straw")?"Timber":n.Contains("stone")||n.Contains("basalt")||n.Contains("concrete")||n.Contains("brick")?"Stone":null;
            if(type==null)return original;var mat=new Material(Materials[type]){name=original.name+"_Detailed",color=original.color};mat.SetFloat("_Metallic",original.HasProperty("_Metallic")?original.GetFloat("_Metallic"):0);AssetDatabase.CreateAsset(mat,AssetDatabase.GenerateUniqueAssetPath(Root+"/Materials/"+mat.name+".mat"));return mat;
        }
        static GameObject DetailExisting(string source,string name)
        {
            var original=AssetDatabase.LoadAssetAtPath<GameObject>(source);var g=UnityEngine.Object.Instantiate(original);g.name=name;var mats=new Dictionary<Material,Material>();
            foreach(var renderer in g.GetComponentsInChildren<MeshRenderer>()){var mat=renderer.sharedMaterial;if(!mats.ContainsKey(mat))mats[mat]=DetailedMaterial(mat);renderer.sharedMaterial=mats[mat];}
            // More restrained adult head proportions on the existing silhouettes.
            if(name.StartsWith("Painter")||name.StartsWith("Witch"))foreach(var filter in g.GetComponentsInChildren<MeshFilter>()){
                var mesh=UnityEngine.Object.Instantiate(filter.sharedMesh);var points=mesh.vertices;var normals=mesh.normals;Matrix4x4 transform=g.transform.worldToLocalMatrix*filter.transform.localToWorldMatrix,back=transform.inverse;
                for(int i=0;i<points.Length;i++){var world=transform.MultiplyPoint3x4(points[i]);if(name.StartsWith("Painter")&&world.y>1.46f&&world.z>-.28f){float blend=Mathf.SmoothStep(0,1,(world.y-1.46f)/.1f);world.x*=Mathf.Lerp(1,.79f,blend);world.z=(world.z-.04f)*Mathf.Lerp(1,.82f,blend)+.04f;world.y=1.46f+(world.y-1.46f)*.86f;}else if(name.StartsWith("Witch")&&world.y>1.46f&&world.y<1.89f){float blend=Mathf.Sin(Mathf.Clamp01((world.y-1.46f)/.43f)*Mathf.PI);world.x*=1-blend*.15f;world.z=(world.z-.04f)*(1-blend*.11f)+.04f;}points[i]=back.MultiplyPoint3x4(world);}
                mesh.vertices=points;mesh.RecalculateBounds();mesh.RecalculateTangents();filter.sharedMesh=mesh;
            }
            return g;
        }
        static void Save(GameObject g)
        {
            foreach(var filter in g.GetComponentsInChildren<MeshFilter>())if(!AssetDatabase.Contains(filter.sharedMesh))AssetDatabase.CreateAsset(filter.sharedMesh,AssetDatabase.GenerateUniqueAssetPath(Root+"/Meshes/"+g.name+"_"+filter.name+".asset"));
            PrefabUtility.SaveAsPrefabAsset(g,Root+"/Prefabs/"+g.name+".prefab");Tinta.Editor.NativeExport.Write(g,Output+"/"+g.name+".json");
        }
        static Camera Lighting()
        {
            RenderSettings.ambientMode=AmbientMode.Trilight;RenderSettings.ambientSkyColor=C("b5d2e4")*.78f;RenderSettings.ambientEquatorColor=C("849fad")*.55f;RenderSettings.ambientGroundColor=C("384451")*.4f;
            var sun=new GameObject("Cold clear daylight").AddComponent<Light>();sun.type=LightType.Directional;sun.color=C("fff1dc");sun.intensity=1.05f;sun.transform.rotation=Quaternion.Euler(42,-38,0);sun.shadows=LightShadows.Soft;sun.shadowBias=.035f;sun.shadowNormalBias=.18f;
            var fill=new GameObject("Blue glacier bounce").AddComponent<Light>();fill.type=LightType.Directional;fill.color=C("a5cced");fill.intensity=.35f;fill.transform.rotation=Quaternion.Euler(25,135,0);
            var camera=new GameObject("Asset review camera").AddComponent<Camera>();camera.clearFlags=CameraClearFlags.SolidColor;camera.backgroundColor=C("213543");camera.fieldOfView=36;camera.farClipPlane=200;return camera;
        }
        static void Capture(Camera camera,string path,int width=900,int height=900)
        {
            var target=new RenderTexture(width,height,24){antiAliasing=4};target.Create();camera.targetTexture=target;camera.Render();var previous=RenderTexture.active;RenderTexture.active=target;var texture=new Texture2D(width,height,TextureFormat.RGB24,false);texture.ReadPixels(new Rect(0,0,width,height),0,0);texture.Apply();File.WriteAllBytes(path,texture.EncodeToPNG());camera.targetTexture=null;RenderTexture.active=previous;target.Release();UnityEngine.Object.DestroyImmediate(target);UnityEngine.Object.DestroyImmediate(texture);
        }
        public static void GenerateMaps()
        {
            EditorSceneManager.NewScene(NewSceneSetup.EmptyScene,NewSceneMode.Single);PlayerSettings.colorSpace=ColorSpace.Linear;
            foreach(var name in new[]{"GlacierTop","BlueIce","DeepIce","WindSnow","PackedSnow"})Materials[name]=AssetDatabase.LoadAssetAtPath<Material>(Root+"/Materials/"+name+".mat");
            var camera=Lighting();var assets=new[]{Glacier("BorealLake",0),Glacier("GlacialFjord",1),Glacier("MidnightLake",2)};foreach(var g in assets){Save(g);g.SetActive(false);}
            foreach(var g in assets){g.SetActive(true);camera.transform.position=V(0,35,39);camera.transform.LookAt(V(0,.3f,0));Capture(camera,Output+"/"+g.name+".png");g.SetActive(false);}
            assets[0].SetActive(true);var snow=UnityEngine.Object.Instantiate(AssetDatabase.LoadAssetAtPath<GameObject>(Root+"/Prefabs/SnowballClassic.prefab"));snow.transform.position=V(-2.1f,.9f,2.6f);snow.transform.localScale=Vector3.one*.9f;camera.transform.position=V(22,27,32);camera.transform.LookAt(V(0,.5f,0));Capture(camera,Output+"/glacier-game-view.png",1400,1000);
            EditorSceneManager.SaveScene(UnityEngine.SceneManagement.SceneManager.GetActiveScene(),Root+"/Scenes/GeleiraAzul.unity");AssetDatabase.SaveAssets();AssetDatabase.ExportPackage(new[]{Root,"Assets/Tinta","Assets/Vassouras","Assets/EmbatteStudio"},Output+"/Embatte-Assets-Naturais-v2.unitypackage",ExportPackageOptions.Recurse);Debug.Log("EMBATTE_GLACIER_MAPS_OK");
        }
        [MenuItem("Embatte/Gerar geleira e neve natural")]
        public static void Generate()
        {
            foreach(string folder in new[]{"Materials","Textures","Meshes","Prefabs","Scenes"})Directory.CreateDirectory(Root+"/"+folder);Directory.CreateDirectory(Output);AssetDatabase.Refresh();EditorSceneManager.NewScene(NewSceneSetup.EmptyScene,NewSceneMode.Single);PlayerSettings.colorSpace=ColorSpace.Linear;GraphicsSettings.defaultRenderPipeline=null;QualitySettings.renderPipeline=null;MakeMaterials();
            var assets=new List<GameObject>{Snowball("SnowballClassic",0),Snowball("SnowballGlacier",1),Snowball("SnowballExpedition",2),Glacier("BorealLake",0),Glacier("GlacialFjord",1),Glacier("MidnightLake",2)};
            foreach(var entry in new[]{("Tinta","PainterAzure"),("EmbatteStudio","PainterHazmat"),("EmbatteStudio","PainterEngineer"),("Vassouras","WitchAmber"),("EmbatteStudio","WitchVerdant"),("EmbatteStudio","WitchFrost")})assets.Add(DetailExisting("Assets/"+entry.Item1+"/Prefabs/"+entry.Item2+".prefab",entry.Item2));
            foreach(var g in assets){Save(g);g.SetActive(false);}AssetDatabase.SaveAssets();var camera=Lighting();
            if(SystemInfo.graphicsDeviceType!=GraphicsDeviceType.Null)foreach(var g in assets){g.SetActive(true);var renderers=g.GetComponentsInChildren<Renderer>();var bounds=renderers[0].bounds;foreach(var r in renderers)bounds.Encapsulate(r.bounds);bool map=g.name.EndsWith("Lake")||g.name=="GlacialFjord";var center=map?V(0,.4f,0):bounds.center;float distance=map?53:Mathf.Max(bounds.size.x,bounds.size.y,bounds.size.z)*2.1f;camera.transform.position=center+(map?V(.08f,.95f,.86f):V(.65f,.35f,1)).normalized*distance;camera.transform.LookAt(center);Capture(camera,Output+"/"+g.name+".png");g.SetActive(false);}
            assets[3].SetActive(true);var snow=UnityEngine.Object.Instantiate(assets[0]);snow.name="Growing snowball demonstration";snow.SetActive(true);snow.transform.position=V(-2.1f,.9f,2.6f);snow.transform.localScale=Vector3.one*.9f;camera.transform.position=V(22,27,32);camera.transform.LookAt(V(0,.5f,0));EditorSceneManager.SaveScene(UnityEngine.SceneManagement.SceneManager.GetActiveScene(),Root+"/Scenes/GeleiraAzul.unity");if(SystemInfo.graphicsDeviceType!=GraphicsDeviceType.Null)Capture(camera,Output+"/glacier-game-view.png",1400,1000);
            AssetDatabase.ExportPackage(new[]{Root,"Assets/Tinta","Assets/Vassouras","Assets/EmbatteStudio"},Output+"/Embatte-Assets-Naturais-v2.unitypackage",ExportPackageOptions.Recurse);Debug.Log("EMBATTE_GLACIER_V2_OK");
        }
    }
}
