├── .gitattributes ├── .github ├── media │ └── PeriodicTable.jpg └── workflows │ ├── build.yml │ ├── create-release.yml │ ├── publish-to-spacedock.yml │ └── validate-cfg-files.yml ├── .gitignore ├── CHANGELOG.md ├── Firefly.sln ├── GameData └── Firefly │ ├── Assets │ ├── Meshes │ │ ├── Bluedog_DB │ │ │ └── Apollo │ │ │ │ ├── bluedog_Apollo_CrewPod.mu │ │ │ │ └── bluedog_Apollo_Heatshield.mu │ │ ├── CREDITS.txt │ │ ├── SPACE_SHUTTLE_SYSTEM │ │ │ └── ShuttleOrbiter.mu │ │ └── benjee10_shuttleOrbiter │ │ │ ├── OV_deltaWing.mu │ │ │ └── OV_forwardFuselage.mu │ ├── Textures │ │ ├── ChunkSprite.png │ │ ├── ChunkSprite1.png │ │ ├── Icon.png │ │ ├── SmokeSprite.png │ │ └── SparkSprite.png │ └── fireflybundle.ksp │ ├── Configs │ ├── Default.cfg │ ├── FireflyParticles.cfg │ ├── KSRSS.cfg │ ├── Kcalbeloh │ │ ├── Ahtpan.cfg │ │ ├── Anehta.cfg │ │ ├── Arorua.cfg │ │ ├── Efil.cfg │ │ ├── Iomena.cfg │ │ ├── Mehtna.cfg │ │ ├── Norihc.cfg │ │ ├── Noyreg.cfg │ │ ├── Rouqea.cfg │ │ ├── Sedah.cfg │ │ ├── Sera.cfg │ │ ├── Simeht.cfg │ │ ├── Simetra.cfg │ │ ├── Suluco.cfg │ │ └── Uleg.cfg │ ├── MPE │ │ └── Ervo.cfg │ ├── OPM │ │ ├── Neidon.cfg │ │ ├── Sarnus.cfg │ │ ├── Tekto.cfg │ │ ├── Thatmo.cfg │ │ └── Urlum.cfg │ ├── RSS.cfg │ ├── RSS │ │ ├── Earth.cfg │ │ ├── Jupiter.cfg │ │ ├── Mars.cfg │ │ ├── Neptune.cfg │ │ ├── Saturn.cfg │ │ ├── Titan.cfg │ │ ├── Uranus.cfg │ │ └── Venus.cfg │ └── Stock │ │ ├── Duna.cfg │ │ ├── Eve.cfg │ │ ├── Jool.cfg │ │ └── Kerbin.cfg │ ├── Firefly.version │ ├── FireflyChangelog.cfg │ ├── ModSettings.cfg │ ├── Patches │ ├── Bluedog_DB │ │ └── Apollo │ │ │ ├── bluedog_Apollo_CrewPod.cfg │ │ │ └── bluedog_Apollo_Heatshield.cfg │ ├── SPACE_SHUTTLE_SYSTEM │ │ └── ShuttleOrbiter.cfg │ └── benjee10_shuttleOrbiter │ │ ├── OV_deltaWing.cfg │ │ └── OV_forwardFuselage.cfg │ └── Templates │ ├── Aluminum.txt │ └── BoronHeatshield.txt ├── LICENSE ├── README.md ├── Source ├── AssetLoader.cs ├── AtmoFxModule.cs ├── CameraManager.cs ├── ConfigManager.cs ├── DrawingUtils.cs ├── ErrorManager.cs ├── EventManager.cs ├── Firefly.csproj ├── GUI │ ├── ColorPickerWindow.cs │ ├── EffectEditor.cs │ ├── ErrorListWindow.cs │ ├── FireflyWindow.cs │ ├── GuiUtils.cs │ ├── ParticleEditor.cs │ ├── Popup.cs │ ├── StockEffectsWindow.cs │ ├── Window.cs │ └── WindowManager.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Firefly.version │ ├── Firefly.version.props │ └── Firefly.version.props.versiontemplate ├── SettingsManager.cs ├── Utils.cs └── Versioning.cs └── Unity ├── .gitignore └── Assets ├── Firefly ├── Materials │ ├── Chunk.mat │ ├── ChunkAlternate.mat │ ├── Firefly.mat │ ├── Smoke.mat │ └── Spark.mat ├── Prefabs │ ├── AlternateDebrisParticles.prefab │ ├── DebrisParticles.prefab │ ├── SmokeParticles.prefab │ └── SparksParticles.prefab ├── Shaders │ ├── CommonFunctions.cginc │ ├── EffectPasses │ │ ├── BowshockPass.cginc │ │ ├── GlowPass.cginc │ │ └── MainPass.cginc │ ├── FireflyShader.shader │ └── ParticleShader.shader └── Textures │ └── NoiseMap.png └── ReentryColors ├── RSS ├── Reentry Earth.asset ├── Reentry Jupiter.asset ├── Reentry Murs.asset ├── Reentry Neptune.asset ├── Reentry Titan.asset └── Reentry Venus.asset ├── Reentry Aluminum.asset ├── Reentry Duna.asset ├── Reentry Jool.asset ├── Reentry Kerbin.asset ├── Reentry LDR.asset └── Reentry Starship.asset /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.github/media/PeriodicTable.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M1rageDev/Firefly/bea84cd5f78d9ce5a66aec73b56e5106797ca388/.github/media/PeriodicTable.jpg -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | branches: [ master, dev ] 6 | paths: 7 | - 'Source/**/*.cs' 8 | - 'Source/**/*.csproj' 9 | pull_request: 10 | paths: 11 | - '**/*.cs' 12 | - '**/*.csproj' 13 | workflow_dispatch: 14 | workflow_call: 15 | 16 | jobs: 17 | build: 18 | uses: KSPModdingLibs/KSPBuildTools/.github/workflows/build.yml@main 19 | -------------------------------------------------------------------------------- /.github/workflows/create-release.yml: -------------------------------------------------------------------------------- 1 | name: create-release 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | version-string: 7 | type: string 8 | required: true 9 | 10 | jobs: 11 | create-release: 12 | uses: KSPModdingLibs/KSPBuildTools/.github/workflows/create-release.yml@main 13 | with: 14 | version-string: ${{ inputs.version-string }} 15 | changelog-output-file: GameData/Firefly/FireflyChangelog.cfg -------------------------------------------------------------------------------- /.github/workflows/publish-to-spacedock.yml: -------------------------------------------------------------------------------- 1 | name: publish-to-spacedock 2 | 3 | on: 4 | release: 5 | types: [released] 6 | 7 | jobs: 8 | publish-to-spacedock: 9 | uses: KSPModdingLibs/KSPBuildTools/.github/workflows/publish-to-spacedock.yml@main 10 | with: 11 | spacedock-username: ${{ vars.SPACEDOCK_USERNAME }} 12 | mod-id: ${{ vars.SPACEDOCK_MOD_ID }} 13 | secrets: 14 | spacedock-password: ${{ secrets.SPACEDOCK_PASSWORD }} 15 | -------------------------------------------------------------------------------- /.github/workflows/validate-cfg-files.yml: -------------------------------------------------------------------------------- 1 | name: Validate CFG Files 2 | 3 | on: 4 | workflow_call: 5 | workflow_dispatch: 6 | pull_request: 7 | paths: 8 | - '**.cfg' 9 | push: 10 | branches: [ dev, master ] 11 | paths: 12 | - '**.cfg' 13 | 14 | jobs: 15 | validate: 16 | uses: KSPModdingLibs/KSPBuildTools/.github/workflows/validate.yml@main 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Oo]ut/ 33 | [Ll]og/ 34 | [Ll]ogs/ 35 | 36 | # Visual Studio 2015/2017 cache/options directory 37 | .vs/ 38 | # Uncomment if you have tasks that create the project's static files in wwwroot 39 | #wwwroot/ 40 | 41 | # Visual Studio 2017 auto generated files 42 | Generated\ Files/ 43 | 44 | # MSTest test Results 45 | [Tt]est[Rr]esult*/ 46 | [Bb]uild[Ll]og.* 47 | 48 | # NUnit 49 | *.VisualState.xml 50 | TestResult.xml 51 | nunit-*.xml 52 | 53 | # Build Results of an ATL Project 54 | [Dd]ebugPS/ 55 | [Rr]eleasePS/ 56 | dlldata.c 57 | 58 | # Benchmark Results 59 | BenchmarkDotNet.Artifacts/ 60 | 61 | # .NET Core 62 | project.lock.json 63 | project.fragment.lock.json 64 | artifacts/ 65 | 66 | # ASP.NET Scaffolding 67 | ScaffoldingReadMe.txt 68 | 69 | # StyleCop 70 | StyleCopReport.xml 71 | 72 | # Files built by Visual Studio 73 | *_i.c 74 | *_p.c 75 | *_h.h 76 | *.ilk 77 | *.meta 78 | *.obj 79 | *.iobj 80 | *.pch 81 | *.pdb 82 | *.ipdb 83 | *.pgc 84 | *.pgd 85 | *.rsp 86 | *.sbr 87 | *.tlb 88 | *.tli 89 | *.tlh 90 | *.tmp 91 | *.tmp_proj 92 | *_wpftmp.csproj 93 | *.log 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio LightSwitch build output 298 | **/*.HTMLClient/GeneratedArtifacts 299 | **/*.DesktopClient/GeneratedArtifacts 300 | **/*.DesktopClient/ModelManifest.xml 301 | **/*.Server/GeneratedArtifacts 302 | **/*.Server/ModelManifest.xml 303 | _Pvt_Extensions 304 | 305 | # Paket dependency manager 306 | .paket/paket.exe 307 | paket-files/ 308 | 309 | # FAKE - F# Make 310 | .fake/ 311 | 312 | # CodeRush personal settings 313 | .cr/personal 314 | 315 | # Python Tools for Visual Studio (PTVS) 316 | __pycache__/ 317 | *.pyc 318 | 319 | # Cake - Uncomment if you are using it 320 | # tools/** 321 | # !tools/packages.config 322 | 323 | # Tabs Studio 324 | *.tss 325 | 326 | # Telerik's JustMock configuration file 327 | *.jmconfig 328 | 329 | # BizTalk build output 330 | *.btp.cs 331 | *.btm.cs 332 | *.odx.cs 333 | *.xsd.cs 334 | 335 | # OpenCover UI analysis results 336 | OpenCover/ 337 | 338 | # Azure Stream Analytics local run output 339 | ASALocalRun/ 340 | 341 | # MSBuild Binary and Structured Log 342 | *.binlog 343 | 344 | # NVidia Nsight GPU debugger configuration file 345 | *.nvuser 346 | 347 | # MFractors (Xamarin productivity tool) working folder 348 | .mfractor/ 349 | 350 | # Local History for Visual Studio 351 | .localhistory/ 352 | 353 | # BeatPulse healthcheck temp database 354 | healthchecksdb 355 | 356 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 357 | MigrationBackup/ 358 | 359 | # Ionide (cross platform F# VS Code tools) working folder 360 | .ionide/ 361 | 362 | # Fody - auto-generated XML schema 363 | FodyWeavers.xsd 364 | 365 | Resources/ 366 | GameData/Firefly/Plugins/Firefly.dll -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Unreleased 4 | 5 | * Add Space Shuttle System envelope (thanks **@giuliodondi**) 6 | * Fix the particles (again), now they should be done for good 7 | 8 | ## 1.0.3 - 2025-04-10 9 | 10 | * Add particle config 11 | * Add particle editor 12 | * Add Ervo config for MPE (thanks **@SPACEMAN9813**) 13 | * Remove individual particle toggles from settings (replaced by particle editor) 14 | * Improve smoke trail particles 15 | 16 | 17 | ## 1.0.2 - 2025-03-01 18 | 19 | * Add configs for Kcalbeloh and OPM (thanks **@SPACEMAN9813**) 20 | * Add Sol compatibility 21 | * Add temporary workaround for drill envelope 22 | * Make the smoke particles much faster and longer 23 | * Make the dynamic pressure affect the effect strength more, fixing the RSS transition (again) 24 | * Fix particle systems going in wrong direction in certain cases 25 | 26 | 27 | ## 1.0.1 - 2025-02-17 28 | 29 | #### WARNING FOR PLANET PACK MAKERS: 30 | 31 | This update makes some changes to the **planet pack** configs. Please make sure you update them. 32 | 33 | * Add custom envelopes for benjee10's SOCK 34 | * Add error/problem handling and list, warning users about incorrect installs or other issues 35 | * Add warning about enabled stock effects 36 | * Add additional message to the effect editor, informing to not use the simulation sliders in normal gameplay 37 | * Add `transition_offset` to the planet pack configs 38 | * Change planet pack config `speed_multiplier` to `strength_multiplier` 39 | * Fix RSS reentry starting too late 40 | * Fix graphics bug on Linux + Proton (Mac is still broken though), huge thanks to **@bmsbwd, @KlyithSA and @Cypherthe1st** for helping to find the fix 41 | 42 | 43 | ## 1.0.0.0 - 2025-02-05 44 | 45 | * Initial Release -------------------------------------------------------------------------------- /Firefly.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.8.34408.163 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Firefly", "Source\Firefly.csproj", "{0DD486F0-EF12-458B-B0E2-F74C7A90E36A}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{12B60FDF-E2E4-4B1B-A68E-EE02E66E0337}" 9 | ProjectSection(SolutionItems) = preProject 10 | CHANGELOG.md = CHANGELOG.md 11 | LICENSE = LICENSE 12 | README.md = README.md 13 | EndProjectSection 14 | EndProject 15 | Global 16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 17 | Debug|Any CPU = Debug|Any CPU 18 | Release|Any CPU = Release|Any CPU 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {0DD486F0-EF12-458B-B0E2-F74C7A90E36A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 22 | {0DD486F0-EF12-458B-B0E2-F74C7A90E36A}.Debug|Any CPU.Build.0 = Debug|Any CPU 23 | {0DD486F0-EF12-458B-B0E2-F74C7A90E36A}.Release|Any CPU.ActiveCfg = Release|Any CPU 24 | {0DD486F0-EF12-458B-B0E2-F74C7A90E36A}.Release|Any CPU.Build.0 = Release|Any CPU 25 | EndGlobalSection 26 | GlobalSection(SolutionProperties) = preSolution 27 | HideSolutionNode = FALSE 28 | EndGlobalSection 29 | GlobalSection(ExtensibilityGlobals) = postSolution 30 | SolutionGuid = {FD2A1D70-48FC-41A4-981D-2FF777D530DB} 31 | EndGlobalSection 32 | EndGlobal 33 | -------------------------------------------------------------------------------- /GameData/Firefly/Assets/Meshes/Bluedog_DB/Apollo/bluedog_Apollo_CrewPod.mu: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M1rageDev/Firefly/bea84cd5f78d9ce5a66aec73b56e5106797ca388/GameData/Firefly/Assets/Meshes/Bluedog_DB/Apollo/bluedog_Apollo_CrewPod.mu -------------------------------------------------------------------------------- /GameData/Firefly/Assets/Meshes/Bluedog_DB/Apollo/bluedog_Apollo_Heatshield.mu: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M1rageDev/Firefly/bea84cd5f78d9ce5a66aec73b56e5106797ca388/GameData/Firefly/Assets/Meshes/Bluedog_DB/Apollo/bluedog_Apollo_Heatshield.mu -------------------------------------------------------------------------------- /GameData/Firefly/Assets/Meshes/CREDITS.txt: -------------------------------------------------------------------------------- 1 | Bundled envelope mesh credits: 2 | 3 | benjee10_shuttleOrbiter - These are modified versions of the original models made by benjee10, redistributed with permission -------------------------------------------------------------------------------- /GameData/Firefly/Assets/Meshes/SPACE_SHUTTLE_SYSTEM/ShuttleOrbiter.mu: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M1rageDev/Firefly/bea84cd5f78d9ce5a66aec73b56e5106797ca388/GameData/Firefly/Assets/Meshes/SPACE_SHUTTLE_SYSTEM/ShuttleOrbiter.mu -------------------------------------------------------------------------------- /GameData/Firefly/Assets/Meshes/benjee10_shuttleOrbiter/OV_deltaWing.mu: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M1rageDev/Firefly/bea84cd5f78d9ce5a66aec73b56e5106797ca388/GameData/Firefly/Assets/Meshes/benjee10_shuttleOrbiter/OV_deltaWing.mu -------------------------------------------------------------------------------- /GameData/Firefly/Assets/Meshes/benjee10_shuttleOrbiter/OV_forwardFuselage.mu: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M1rageDev/Firefly/bea84cd5f78d9ce5a66aec73b56e5106797ca388/GameData/Firefly/Assets/Meshes/benjee10_shuttleOrbiter/OV_forwardFuselage.mu -------------------------------------------------------------------------------- /GameData/Firefly/Assets/Textures/ChunkSprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M1rageDev/Firefly/bea84cd5f78d9ce5a66aec73b56e5106797ca388/GameData/Firefly/Assets/Textures/ChunkSprite.png -------------------------------------------------------------------------------- /GameData/Firefly/Assets/Textures/ChunkSprite1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M1rageDev/Firefly/bea84cd5f78d9ce5a66aec73b56e5106797ca388/GameData/Firefly/Assets/Textures/ChunkSprite1.png -------------------------------------------------------------------------------- /GameData/Firefly/Assets/Textures/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M1rageDev/Firefly/bea84cd5f78d9ce5a66aec73b56e5106797ca388/GameData/Firefly/Assets/Textures/Icon.png -------------------------------------------------------------------------------- /GameData/Firefly/Assets/Textures/SmokeSprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M1rageDev/Firefly/bea84cd5f78d9ce5a66aec73b56e5106797ca388/GameData/Firefly/Assets/Textures/SmokeSprite.png -------------------------------------------------------------------------------- /GameData/Firefly/Assets/Textures/SparkSprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M1rageDev/Firefly/bea84cd5f78d9ce5a66aec73b56e5106797ca388/GameData/Firefly/Assets/Textures/SparkSprite.png -------------------------------------------------------------------------------- /GameData/Firefly/Assets/fireflybundle.ksp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M1rageDev/Firefly/bea84cd5f78d9ce5a66aec73b56e5106797ca388/GameData/Firefly/Assets/fireflybundle.ksp -------------------------------------------------------------------------------- /GameData/Firefly/Configs/Default.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY 2 | { 3 | name = Default 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | 8 | length_multiplier = 1 9 | opacity_multiplier = 1 10 | wrap_fresnel_modifier = 0 11 | 12 | particle_threshold = 1800 13 | 14 | streak_probability = 0 15 | streak_threshold = 0 16 | 17 | Color 18 | { 19 | glow = 191 80 50 1.4 20 | glow_hot = 191 90 65 2.5 21 | 22 | trail_primary = 191 99 72 3 23 | trail_secondary = 191 70 42 1.5 24 | trail_tertiary = 74 80 191 2 25 | trail_streak = 74 80 191 2 26 | 27 | wrap_layer = 69 69 191 2 28 | wrap_streak = 191 99 72 3 29 | 30 | shockwave = 74 90 191 3 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/FireflyParticles.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_PARTICLES 2 | { 3 | name = FireflyParticles_Default 4 | Sparks 5 | { 6 | isActive = True 7 | prefab = SparksParticles 8 | mainTexture = Firefly/Assets/Textures/ChunkSprite 9 | emissionTexture = Firefly/Assets/Textures/ChunkSprite 10 | offset = 0.5 11 | useHalfOffset = False 12 | rate = 46 46 13 | lifetime = 0.07 0.7 14 | velocity = 30 70 15 | } 16 | Debris 17 | { 18 | isActive = True 19 | prefab = DebrisParticles 20 | mainTexture = Firefly/Assets/Textures/ChunkSprite 21 | emissionTexture = 22 | offset = 1.24 23 | useHalfOffset = False 24 | rate = 20 20 25 | lifetime = 0.25 1.23 26 | velocity = 30 70 27 | } 28 | AlternateDebris 29 | { 30 | isActive = True 31 | prefab = AlternateDebrisParticles 32 | mainTexture = Firefly/Assets/Textures/ChunkSprite1 33 | emissionTexture = 34 | offset = 1.62 35 | useHalfOffset = False 36 | rate = 0.1 2 37 | lifetime = 0.3 1 38 | velocity = 15 20 39 | } 40 | Smoke 41 | { 42 | isActive = True 43 | prefab = SmokeParticles 44 | mainTexture = Firefly/Assets/Textures/SmokeSprite 45 | emissionTexture = 46 | offset = 2 47 | useHalfOffset = True 48 | rate = 206 255 49 | lifetime = 8 10 50 | velocity = 400 400 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/KSRSS.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_PLANET_PACK:NEEDS[KSRSS] 2 | { 3 | name = KSRSS_Configs 4 | 5 | strength_multiplier = 1 6 | transition_offset = 0 7 | 8 | affected_bodies = Venus, Earth, Mars, Jupiter, Saturn, Titan, Uranus, Neptune 9 | } 10 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/Kcalbeloh/Ahtpan.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY:NEEDS[KcalbelohSystem] 2 | { 3 | name = Ahtpan 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | length_multiplier = 1 8 | opacity_multiplier = 1 9 | wrap_fresnel_modifier = 0 10 | particle_threshold = 1200 11 | streak_probability = 0.0700000003 12 | streak_threshold = -0.200000003 13 | Color 14 | { 15 | glow = 191 80 50 1.4 16 | glow_hot = 191 90 65 2.5 17 | trail_primary = 78 17 208 2.5 18 | trail_secondary = 240 26 103 1.613636 19 | trail_tertiary = 17 144 200 3 20 | trail_streak = 66 178 218 2 21 | wrap_layer = 191 124 73 2 22 | wrap_streak = 76 116 191 2.5 23 | shockwave = 176 178 230 1.386364 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/Kcalbeloh/Anehta.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY:NEEDS[KcalbelohSystem] 2 | { 3 | name = Anehta 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | length_multiplier = 1 8 | opacity_multiplier = 1 9 | wrap_fresnel_modifier = 0 10 | particle_threshold = 1200 11 | streak_probability = 0.0700000003 12 | streak_threshold = -0.200000003 13 | Color 14 | { 15 | glow = 191 80 50 1.4 16 | glow_hot = 191 90 65 2.5 17 | trail_primary = 208 17 143 2.5 18 | trail_secondary = 240 26 103 1.613636 19 | trail_tertiary = 17 144 200 3 20 | trail_streak = 66 178 218 2 21 | wrap_layer = 191 124 73 2 22 | wrap_streak = 76 116 191 2.5 23 | shockwave = 176 178 230 1.386364 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/Kcalbeloh/Arorua.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY:NEEDS[KcalbelohSystem] 2 | { 3 | name = Arorua 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | length_multiplier = 1 8 | opacity_multiplier = 1 9 | wrap_fresnel_modifier = 0 10 | particle_threshold = 1200 11 | streak_probability = 0.0700000003 12 | streak_threshold = -0.200000003 13 | Color 14 | { 15 | glow = 191 80 50 1.4 16 | glow_hot = 191 90 65 2.5 17 | trail_primary = 78 17 208 2.5 18 | trail_secondary = 240 26 103 1.613636 19 | trail_tertiary = 17 144 200 3 20 | trail_streak = 66 178 218 2 21 | wrap_layer = 191 124 73 2 22 | wrap_streak = 76 116 191 2.5 23 | shockwave = 176 178 230 1.386364 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/Kcalbeloh/Efil.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY:NEEDS[KcalbelohSystem] 2 | { 3 | name = Efil 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | length_multiplier = 1 8 | opacity_multiplier = 1 9 | wrap_fresnel_modifier = 0 10 | particle_threshold = 1200 11 | streak_probability = 0.0700000003 12 | streak_threshold = -0.200000003 13 | Color 14 | { 15 | glow = 191 80 50 1.4 16 | glow_hot = 191 90 65 2.5 17 | trail_primary = 238 134 65 2.5 18 | trail_secondary = 237 45 9 1.613636 19 | trail_tertiary = 71 51 217 3 20 | trail_streak = 66 78 218 2 21 | wrap_layer = 191 124 73 2 22 | wrap_streak = 76 116 191 2.5 23 | shockwave = 38 67 222 2.340909 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/Kcalbeloh/Iomena.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY:NEEDS[KcalbelohSystem] 2 | { 3 | name = Iomena 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | length_multiplier = 1 8 | opacity_multiplier = 1 9 | wrap_fresnel_modifier = 0 10 | particle_threshold = 1200 11 | streak_probability = 0.0700000003 12 | streak_threshold = -0.200000003 13 | Color 14 | { 15 | glow = 191 80 50 1.4 16 | glow_hot = 191 90 65 2.5 17 | trail_primary = 218 121 91 2.5 18 | trail_secondary = 240 26 103 1.613636 19 | trail_tertiary = 17 144 200 3 20 | trail_streak = 66 178 218 2 21 | wrap_layer = 191 124 73 2 22 | wrap_streak = 76 116 191 2.5 23 | shockwave = 176 178 230 1.386364 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/Kcalbeloh/Mehtna.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY:NEEDS[KcalbelohSystem] 2 | { 3 | name = Mehtna 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | length_multiplier = 1 8 | opacity_multiplier = 1 9 | wrap_fresnel_modifier = 0 10 | particle_threshold = 1200 11 | streak_probability = 0.0700000003 12 | streak_threshold = -0.200000003 13 | Color 14 | { 15 | glow = 191 80 50 1.4 16 | glow_hot = 191 90 65 2.5 17 | trail_primary = 235 45 60 2.5 18 | trail_secondary = 179 166 11 1.613636 19 | trail_tertiary = 17 144 200 3 20 | trail_streak = 66 178 218 2 21 | wrap_layer = 191 124 73 2 22 | wrap_streak = 76 116 191 2.5 23 | shockwave = 11 111 228 2.181818 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/Kcalbeloh/Norihc.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY:NEEDS[KcalbelohSystem] 2 | { 3 | name = Norihc 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | length_multiplier = 1 8 | opacity_multiplier = 1 9 | wrap_fresnel_modifier = 0 10 | particle_threshold = 1200 11 | streak_probability = 0.0700000003 12 | streak_threshold = -0.200000003 13 | Color 14 | { 15 | glow = 191 80 50 1.4 16 | glow_hot = 191 90 65 2.5 17 | trail_primary = 78 17 208 2.5 18 | trail_secondary = 240 26 103 1.613636 19 | trail_tertiary = 17 144 200 3 20 | trail_streak = 66 178 218 2 21 | wrap_layer = 191 124 73 2 22 | wrap_streak = 76 116 191 2.5 23 | shockwave = 176 178 230 1.386364 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/Kcalbeloh/Noyreg.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY:NEEDS[KcalbelohSystem] 2 | { 3 | name = Noyreg 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | length_multiplier = 1 8 | opacity_multiplier = 1 9 | wrap_fresnel_modifier = 0 10 | particle_threshold = 1200 11 | streak_probability = 0.0700000003 12 | streak_threshold = -0.200000003 13 | Color 14 | { 15 | glow = 191 80 50 1.4 16 | glow_hot = 191 90 65 2.5 17 | trail_primary = 33 226 218 1.477273 18 | trail_secondary = 113 180 225 0.6136364 19 | trail_tertiary = 17 144 200 3 20 | trail_streak = 66 178 218 2 21 | wrap_layer = 191 124 73 2 22 | wrap_streak = 76 116 191 2.5 23 | shockwave = 84 206 145 2.886364 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/Kcalbeloh/Rouqea.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY:NEEDS[KcalbelohSystem] 2 | { 3 | name = Rouqea 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | length_multiplier = 1 8 | opacity_multiplier = 1 9 | wrap_fresnel_modifier = 0 10 | particle_threshold = 1200 11 | streak_probability = 0.0700000003 12 | streak_threshold = -0.200000003 13 | Color 14 | { 15 | glow = 191 80 50 1.4 16 | glow_hot = 191 90 65 2.5 17 | trail_primary = 192 70 31 2.5 18 | trail_secondary = 212 80 38 1.613636 19 | trail_tertiary = 53 68 178 3 20 | trail_streak = 63 63 202 2 21 | wrap_layer = 191 124 73 2 22 | wrap_streak = 96 68 29 2.5 23 | shockwave = 16 22 187 1.386364 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/Kcalbeloh/Sedah.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY:NEEDS[KcalbelohSystem] 2 | { 3 | name = Sedah 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | length_multiplier = 1 8 | opacity_multiplier = 1 9 | wrap_fresnel_modifier = 0 10 | particle_threshold = 1200 11 | streak_probability = 0.0700000003 12 | streak_threshold = -0.200000003 13 | Color 14 | { 15 | glow = 191 80 50 1.4 16 | glow_hot = 191 90 65 2.5 17 | trail_primary = 208 17 155 2.5 18 | trail_secondary = 240 26 103 1.613636 19 | trail_tertiary = 17 144 200 3 20 | trail_streak = 121 66 218 2 21 | wrap_layer = 191 124 73 2 22 | wrap_streak = 76 116 191 2.5 23 | shockwave = 46 53 231 1.386364 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/Kcalbeloh/Sera.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY:NEEDS[KcalbelohSystem] 2 | { 3 | name = Sera 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | length_multiplier = 1 8 | opacity_multiplier = 1 9 | wrap_fresnel_modifier = 0 10 | particle_threshold = 1200 11 | streak_probability = 0.0700000003 12 | streak_threshold = -0.200000003 13 | Color 14 | { 15 | glow = 191 80 50 1.4 16 | glow_hot = 191 90 65 2.5 17 | trail_primary = 164 60 24 2.5 18 | trail_secondary = 83 16 114 1.613636 19 | trail_tertiary = 51 68 171 3 20 | trail_streak = 229 211 75 2 21 | wrap_layer = 191 124 73 2 22 | wrap_streak = 76 116 191 2.5 23 | shockwave = 176 178 230 1.386364 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/Kcalbeloh/Simeht.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY:NEEDS[KcalbelohSystem] 2 | { 3 | name = Simeht 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | length_multiplier = 1 8 | opacity_multiplier = 1 9 | wrap_fresnel_modifier = 0 10 | particle_threshold = 1200 11 | streak_probability = 0.0700000003 12 | streak_threshold = -0.200000003 13 | Color 14 | { 15 | glow = 191 80 50 1.4 16 | glow_hot = 191 90 65 2.5 17 | trail_primary = 78 17 208 2.5 18 | trail_secondary = 240 26 103 1.613636 19 | trail_tertiary = 17 144 200 3 20 | trail_streak = 66 178 218 2 21 | wrap_layer = 191 124 73 2 22 | wrap_streak = 76 116 191 2.5 23 | shockwave = 176 178 230 1.386364 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/Kcalbeloh/Simetra.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY:NEEDS[KcalbelohSystem] 2 | { 3 | name = Simetra 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | length_multiplier = 1 8 | opacity_multiplier = 1 9 | wrap_fresnel_modifier = 0 10 | particle_threshold = 1200 11 | streak_probability = 0.0700000003 12 | streak_threshold = -0.200000003 13 | Color 14 | { 15 | glow = 191 80 50 1.4 16 | glow_hot = 191 90 65 2.5 17 | trail_primary = 78 17 208 2.5 18 | trail_secondary = 240 26 103 1.613636 19 | trail_tertiary = 17 144 200 3 20 | trail_streak = 66 178 218 2 21 | wrap_layer = 191 124 73 2 22 | wrap_streak = 76 116 191 2.5 23 | shockwave = 176 178 230 1.386364 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/Kcalbeloh/Suluco.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY:NEEDS[KcalbelohSystem] 2 | { 3 | name = Suluco 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | length_multiplier = 1 8 | opacity_multiplier = 1 9 | wrap_fresnel_modifier = 0 10 | particle_threshold = 1200 11 | streak_probability = 0.0700000003 12 | streak_threshold = -0.200000003 13 | Color 14 | { 15 | glow = 191 80 50 1.4 16 | glow_hot = 191 90 65 2.5 17 | trail_primary = 230 139 84 2.5 18 | trail_secondary = 236 82 39 1.613636 19 | trail_tertiary = 48 58 220 3 20 | trail_streak = 69 66 218 2 21 | wrap_layer = 191 124 73 2 22 | wrap_streak = 76 116 191 2.5 23 | shockwave = 59 97 234 2.659091 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/Kcalbeloh/Uleg.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY:NEEDS[KcalbelohSystem] 2 | { 3 | name = Uleg 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | length_multiplier = 1 8 | opacity_multiplier = 1 9 | wrap_fresnel_modifier = 0 10 | particle_threshold = 1200 11 | streak_probability = 0.0700000003 12 | streak_threshold = -0.200000003 13 | Color 14 | { 15 | glow = 191 80 50 1.4 16 | glow_hot = 191 90 65 2.5 17 | trail_primary = 112 86 32 0.5909091 18 | trail_secondary = 204 128 64 0.4318182 19 | trail_tertiary = 151 225 119 0.75 20 | trail_streak = 66 178 218 0.2045454 21 | wrap_layer = 191 124 73 2 22 | wrap_streak = 76 116 191 2.5 23 | shockwave = 46 177 202 2.227273 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/MPE/Ervo.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY:NEEDS[MPE] 2 | { 3 | name = Ervo 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | length_multiplier = 1 8 | opacity_multiplier = 1 9 | wrap_fresnel_modifier = 0 10 | particle_threshold = 1200 11 | streak_probability = 0.0900000036 12 | streak_threshold = -0.0340909101 13 | Color 14 | { 15 | glow = 191 80 50 1.4 16 | glow_hot = 191 90 65 2.5 17 | trail_primary = 15 121 133 0.2272727 18 | trail_secondary = 127 42 219 0.3409091 19 | trail_tertiary = 140 183 103 2 20 | trail_streak = 46 60 18 0.4772727 21 | wrap_layer = 191 124 73 2 22 | wrap_streak = 76 116 191 2.5 23 | shockwave = 41 113 153 3 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/OPM/Neidon.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY:NEEDS[OPM] 2 | { 3 | name = Neidon 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | length_multiplier = 1 8 | opacity_multiplier = 1 9 | wrap_fresnel_modifier = 0 10 | particle_threshold = 1200 11 | streak_probability = 0.0700000003 12 | streak_threshold = -0.200000003 13 | Color 14 | { 15 | glow = 191 80 50 1.4 16 | glow_hot = 191 90 65 2.5 17 | trail_primary = 78 17 208 2.5 18 | trail_secondary = 240 26 103 1.613636 19 | trail_tertiary = 17 144 200 3 20 | trail_streak = 66 178 218 2 21 | wrap_layer = 191 124 73 2 22 | wrap_streak = 76 116 191 2.5 23 | shockwave = 176 178 230 1.386364 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/OPM/Sarnus.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY:NEEDS[OPM] 2 | { 3 | name = Sarnus 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | length_multiplier = 1 8 | opacity_multiplier = 1 9 | wrap_fresnel_modifier = 0 10 | particle_threshold = 1200 11 | streak_probability = 0.0700000003 12 | streak_threshold = -0.200000003 13 | Color 14 | { 15 | glow = 191 80 50 1.4 16 | glow_hot = 191 90 65 2.5 17 | trail_primary = 117 35 222 2.5 18 | trail_secondary = 227 55 120 1.8 19 | trail_tertiary = 213 210 85 2 20 | trail_streak = 229 190 253 2 21 | wrap_layer = 187 190 55 2 22 | wrap_streak = 76 116 191 2.5 23 | shockwave = 182 185 243 1.090909 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/OPM/Tekto.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY:NEEDS[OPM] 2 | { 3 | name = Tekto 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | length_multiplier = 1 8 | opacity_multiplier = 1 9 | wrap_fresnel_modifier = 0 10 | particle_threshold = 1200 11 | streak_probability = 0.0700000003 12 | streak_threshold = -0.200000003 13 | Color 14 | { 15 | glow = 191 80 50 1.4 16 | glow_hot = 191 90 65 2.5 17 | trail_primary = 184 116 6 0.3181818 18 | trail_secondary = 230 222 128 1.8 19 | trail_tertiary = 215 247 195 2 20 | trail_streak = 219 249 196 2 21 | wrap_layer = 191 124 73 2 22 | wrap_streak = 76 116 191 2.5 23 | shockwave = 61 110 133 3 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/OPM/Thatmo.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY:NEEDS[OPM] 2 | { 3 | name = Thatmo 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | length_multiplier = 1 8 | opacity_multiplier = 1 9 | wrap_fresnel_modifier = 0 10 | particle_threshold = 1200 11 | streak_probability = 0.0700000003 12 | streak_threshold = -0.200000003 13 | Color 14 | { 15 | glow = 191 80 50 1.4 16 | glow_hot = 191 90 65 2.5 17 | trail_primary = 241 187 34 0.2272727 18 | trail_secondary = 127 42 219 0.3409091 19 | trail_tertiary = 140 183 103 2 20 | trail_streak = 46 60 18 0.4772727 21 | wrap_layer = 191 124 73 2 22 | wrap_streak = 76 116 191 2.5 23 | shockwave = 41 113 153 3 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/OPM/Urlum.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY:NEEDS[OPM] 2 | { 3 | name = Urlum 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | length_multiplier = 1 8 | opacity_multiplier = 1 9 | wrap_fresnel_modifier = 0 10 | particle_threshold = 1200 11 | streak_probability = 0.0700000003 12 | streak_threshold = -0.200000003 13 | Color 14 | { 15 | glow = 191 80 50 1.4 16 | glow_hot = 191 90 65 2.5 17 | trail_primary = 167 54 207 2.5 18 | trail_secondary = 222 154 241 1.8 19 | trail_tertiary = 191 124 73 2 20 | trail_streak = 225 158 249 2 21 | wrap_layer = 191 124 73 2 22 | wrap_streak = 76 116 191 2.5 23 | shockwave = 87 49 161 3 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/RSS.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_PLANET_PACK:NEEDS[RealSolarSystem|SolSystem] 2 | { 3 | name = RSS_Configs 4 | 5 | strength_multiplier = 1 6 | transition_offset = 0.2 7 | 8 | affected_bodies = Venus, Earth, Mars, Jupiter, Saturn, Titan, Uranus, Neptune 9 | } 10 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/RSS/Earth.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY:NEEDS[KSRSS|RealSolarSystem|SolSystem] 2 | { 3 | name = Earth 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | 8 | length_multiplier = 1 9 | opacity_multiplier = 1 10 | wrap_fresnel_modifier = 0 11 | 12 | particle_threshold = 1800 13 | 14 | streak_probability = 0 15 | streak_threshold = 0 16 | 17 | Color 18 | { 19 | glow = 191 80 50 1.4 20 | glow_hot = 191 90 65 2.5 21 | 22 | trail_primary = 191 99 72 3 23 | trail_secondary = 191 70 42 1.5 24 | trail_tertiary = 74 80 191 2 25 | trail_streak = 74 80 191 2 26 | 27 | wrap_layer = 69 69 191 2 28 | wrap_streak = 191 99 72 2 29 | 30 | shockwave = 74 90 191 3 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/RSS/Jupiter.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY:NEEDS[KSRSS|RealSolarSystem|SolSystem] 2 | { 3 | name = Jupiter 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | 8 | length_multiplier = 1 9 | opacity_multiplier = 1 10 | wrap_fresnel_modifier = 1.3 11 | 12 | particle_threshold = 1800 13 | 14 | streak_probability = 0.08 15 | streak_threshold = 0 16 | 17 | Color 18 | { 19 | glow = 191 80 50 1.4 20 | glow_hot = 191 90 65 2.5 21 | 22 | trail_primary = 136 98 191 2.5 23 | trail_secondary = 36 7 191 3.5 24 | trail_tertiary = 128 27 191 2 25 | trail_streak = 128 27 191 2 26 | 27 | wrap_layer = 143 25 191 2.8 28 | wrap_streak = 191 21 21 1.5 29 | 30 | shockwave = 11 29 191 3 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/RSS/Mars.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY:NEEDS[KSRSS|RealSolarSystem|SolSystem] 2 | { 3 | name = Mars 4 | config_version = 5 5 | 6 | strength_multiplier = 0.5 7 | length_multiplier = 1 8 | opacity_multiplier = 1 9 | wrap_fresnel_modifier = 0 10 | particle_threshold = 1350 11 | streak_probability = 0.0700000003 12 | streak_threshold = -0.5 13 | Color 14 | { 15 | glow = 191 80 50 1.4 16 | glow_hot = 191 90 65 2.5 17 | trail_primary = 76 116 191 2.5 18 | trail_secondary = 151 130 191 1.8 19 | trail_tertiary = 191 124 73 2 20 | trail_streak = 191 124 73 2 21 | wrap_layer = 191 124 73 2 22 | wrap_streak = 76 116 191 2.5 23 | shockwave = 34 41 191 3 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/RSS/Neptune.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY:NEEDS[KSRSS|RealSolarSystem|SolSystem] 2 | { 3 | name = Neptune 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | 8 | length_multiplier = 1 9 | opacity_multiplier = 1 10 | wrap_fresnel_modifier = 1 11 | 12 | particle_threshold = 1800 13 | 14 | streak_probability = 0.08 15 | streak_threshold = 0 16 | 17 | Color 18 | { 19 | glow = 191 80 50 1.4 20 | glow_hot = 191 90 65 2.5 21 | 22 | trail_primary = 141 91 191 2.5 23 | trail_secondary = 90 8 191 3 24 | trail_tertiary = 191 138 68 2 25 | trail_streak = 191 138 68 2 26 | 27 | wrap_layer = 191 19 110 2 28 | wrap_streak = 191 138 68 2 29 | 30 | shockwave = 64 41 191 3 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/RSS/Saturn.cfg: -------------------------------------------------------------------------------- 1 | +ATMOFX_BODY[Jupiter]:NEEDS[KSRSS|RealSolarSystem|SolSystem] 2 | { 3 | @name = Saturn 4 | 5 | @intensity = 1 6 | } 7 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/RSS/Titan.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY:NEEDS[KSRSS|RealSolarSystem|SolSystem] 2 | { 3 | name = Titan 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | 8 | length_multiplier = 1 9 | opacity_multiplier = 1 10 | wrap_fresnel_modifier = 0 11 | 12 | particle_threshold = 1200 13 | 14 | streak_probability = 0 15 | streak_threshold = 0 16 | 17 | Color 18 | { 19 | glow = 191 80 50 1.4 20 | glow_hot = 191 90 65 2.5 21 | 22 | trail_primary = 191 99 63 3 23 | trail_secondary = 191 70 33 1.5 24 | trail_tertiary = 86 93 191 2 25 | trail_streak = 86 93 191 2 26 | 27 | wrap_layer = 191 127 52 2 28 | wrap_streak = 36 81 191 2 29 | 30 | shockwave = 191 99 62 3 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/RSS/Uranus.cfg: -------------------------------------------------------------------------------- 1 | +ATMOFX_BODY[Neptune]:NEEDS[KSRSS|RealSolarSystem|SolSystem] 2 | { 3 | @name = Uranus 4 | } 5 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/RSS/Venus.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY:NEEDS[KSRSS|RealSolarSystem|SolSystem] 2 | { 3 | name = Venus 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | 8 | length_multiplier = 0.8 9 | opacity_multiplier = 1 10 | wrap_fresnel_modifier = 1 11 | 12 | particle_threshold = 1500 13 | 14 | streak_probability = 0.07 15 | streak_threshold = -0.2 16 | 17 | Color 18 | { 19 | glow = 191 80 50 1.4 20 | glow_hot = 191 90 65 2.5 21 | 22 | trail_primary = 83 92 191 2 23 | trail_secondary = 40 61 191 1.4 24 | trail_tertiary = 167 191 157 2 25 | trail_streak = 167 191 157 2 26 | 27 | wrap_layer = 41 72 191 2 28 | wrap_streak = 191 138 68 1.5 29 | 30 | shockwave = 40 61 191 3 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/Stock/Duna.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY 2 | { 3 | name = Duna 4 | config_version = 5 5 | 6 | strength_multiplier = 0.5 7 | 8 | length_multiplier = 1 9 | opacity_multiplier = 1 10 | wrap_fresnel_modifier = 0 11 | 12 | particle_threshold = 1350 13 | 14 | streak_probability = 0.07 15 | streak_threshold = -0.5 16 | 17 | Color 18 | { 19 | glow = 191 80 50 1.4 20 | glow_hot = 191 90 65 2.5 21 | 22 | trail_primary = 76 116 191 2.5 23 | trail_secondary = 151 130 191 1.8 24 | trail_tertiary = 191 124 73 2 25 | trail_streak = 191 124 73 2 26 | 27 | wrap_layer = 191 124 73 2 28 | wrap_streak = 76 116 191 2.5 29 | 30 | shockwave = 34 41 191 3 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/Stock/Eve.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY 2 | { 3 | name = Eve 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | 8 | length_multiplier = 0.8 9 | opacity_multiplier = 1 10 | wrap_fresnel_modifier = 1 11 | 12 | particle_threshold = 1500 13 | 14 | streak_probability = 0.07 15 | streak_threshold = -0.2 16 | 17 | Color 18 | { 19 | glow = 191 80 50 1.4 20 | glow_hot = 191 90 65 2.5 21 | 22 | trail_primary = 83 92 191 2 23 | trail_secondary = 52 102 191 2 24 | trail_tertiary = 122 191 170 2 25 | trail_streak = 122 191 170 2 26 | 27 | wrap_layer = 125 185 191 2 28 | wrap_streak = 70 95 191 1.5 29 | 30 | shockwave = 96 191 159 3 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/Stock/Jool.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY 2 | { 3 | name = Jool 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | 8 | length_multiplier = 1 9 | opacity_multiplier = 1 10 | wrap_fresnel_modifier = 1 11 | 12 | particle_threshold = 1800 13 | 14 | streak_probability = 0.07 15 | streak_threshold = 0 16 | 17 | Color 18 | { 19 | glow = 191 80 50 1.4 20 | glow_hot = 191 90 65 2.5 21 | 22 | trail_primary = 32 20 191 1.4 23 | trail_secondary = 191 6 6 3 24 | trail_tertiary = 191 191 88 1.7 25 | trail_streak = 191 191 88 1.7 26 | 27 | wrap_layer = 69 69 191 2 28 | wrap_streak = 32 20 191 1.4 29 | 30 | shockwave = 140 191 161 1 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /GameData/Firefly/Configs/Stock/Kerbin.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_BODY 2 | { 3 | name = Kerbin 4 | config_version = 5 5 | 6 | strength_multiplier = 1 7 | 8 | length_multiplier = 1 9 | opacity_multiplier = 1 10 | wrap_fresnel_modifier = 0 11 | 12 | particle_threshold = 1800 13 | 14 | streak_probability = 0 15 | streak_threshold = 0 16 | 17 | Color 18 | { 19 | glow = 191 80 50 1.4 20 | glow_hot = 191 90 65 2.5 21 | 22 | trail_primary = 191 99 72 3 23 | trail_secondary = 191 70 42 1.5 24 | trail_tertiary = 74 80 191 2 25 | trail_streak = 74 80 191 2 26 | 27 | wrap_layer = 69 69 191 2 28 | wrap_streak = 191 99 72 3 29 | 30 | shockwave = 74 90 191 3 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /GameData/Firefly/Firefly.version: -------------------------------------------------------------------------------- 1 | { 2 | "NAME": "Firefly", 3 | "URL": "https://github.com/M1rageDev/Firefly/releases/latest/download/Firefly.version", 4 | "DOWNLOAD": "https://github.com/M1rageDev/Firefly/releases/latest", 5 | "VERSION": "1.0.3", 6 | "KSP_VERSION": "1.12", 7 | "KSP_VERSION_MIN": "1.12", 8 | "KSP_VERSION_MAX": "1.12" 9 | } 10 | -------------------------------------------------------------------------------- /GameData/Firefly/FireflyChangelog.cfg: -------------------------------------------------------------------------------- 1 | // Changelog file generated by yaclog-ksp (https://github.com/drewcassidy/yaclog-ksp) 2 | KERBALCHANGELOG 3 | { 4 | modName = Firefly 5 | VERSION { 6 | version = 1.0.3 7 | versionDate = 2025-04-10 8 | change = Add particle config 9 | change = Add particle editor 10 | change = Add Ervo config for MPE (thanks **@SPACEMAN9813**) 11 | change = Remove individual particle toggles from settings (replaced by particle editor) 12 | change = Improve smoke trail particles 13 | change = There is nothing permanent except change 14 | } 15 | 16 | VERSION { 17 | version = 1.0.2 18 | versionDate = 2025-03-01 19 | change = Add configs for Kcalbeloh and OPM (thanks **@SPACEMAN9813**) 20 | change = Add Sol compatibility 21 | change = Add temporary workaround for drill envelope 22 | change = Make the smoke particles much faster and longer 23 | change = Make the dynamic pressure affect the effect strength more, fixing the RSS transition (again) 24 | change = Fix particle systems going in wrong direction in certain cases 25 | } 26 | 27 | VERSION { 28 | version = 1.0.1 29 | versionDate = 2025-02-17 30 | change = #### WARNING FOR PLANET PACK MAKERS: 31 | change = This update makes some changes to the **planet pack** configs. Please make sure you update them. 32 | change = Add custom envelopes for benjee10's SOCK 33 | change = Add error/problem handling and list, warning users about incorrect installs or other issues 34 | change = Add warning about enabled stock effects 35 | change = Add additional message to the effect editor, informing to not use the simulation sliders in normal gameplay 36 | change = Add `transition_offset` to the planet pack configs 37 | change = Change planet pack config `speed_multiplier` to `strength_multiplier` 38 | change = Fix RSS reentry starting too late 39 | change = Fix graphics bug on Linux + Proton (Mac is still broken though), huge thanks to **@bmsbwd, @KlyithSA and @Cypherthe1st** for helping to find the fix 40 | } 41 | 42 | VERSION { 43 | version = 1.0.0.0 44 | versionDate = 2025-02-05 45 | change = Initial Release 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /GameData/Firefly/ModSettings.cfg: -------------------------------------------------------------------------------- 1 | ATMOFX_SETTINGS 2 | { 3 | hdr_override = True 4 | disable_bowshock = False 5 | disable_particles = False 6 | strength_base = 2800 7 | length_mult = 1 8 | } 9 | -------------------------------------------------------------------------------- /GameData/Firefly/Patches/Bluedog_DB/Apollo/bluedog_Apollo_CrewPod.cfg: -------------------------------------------------------------------------------- 1 | @PART[bluedog_Apollo_CrewPod] 2 | { 3 | MODEL 4 | { 5 | model = Firefly/Assets/Meshes/Bluedog_DB/Apollo/bluedog_Apollo_CrewPod 6 | } 7 | } -------------------------------------------------------------------------------- /GameData/Firefly/Patches/Bluedog_DB/Apollo/bluedog_Apollo_Heatshield.cfg: -------------------------------------------------------------------------------- 1 | @PART[bluedog_Apollo_Heatshield] 2 | { 3 | MODEL 4 | { 5 | model = Firefly/Assets/Meshes/Bluedog_DB/Apollo/bluedog_Apollo_Heatshield 6 | } 7 | } -------------------------------------------------------------------------------- /GameData/Firefly/Patches/SPACE_SHUTTLE_SYSTEM/ShuttleOrbiter.cfg: -------------------------------------------------------------------------------- 1 | @PART[ShuttleOrbiter*] 2 | { 3 | MODEL 4 | { 5 | model = Firefly/Assets/Meshes/SPACE_SHUTTLE_SYSTEM/ShuttleOrbiter 6 | } 7 | } -------------------------------------------------------------------------------- /GameData/Firefly/Patches/benjee10_shuttleOrbiter/OV_deltaWing.cfg: -------------------------------------------------------------------------------- 1 | @PART[benjee10_shuttle_deltaWing] 2 | { 3 | MODEL 4 | { 5 | model = Firefly/Assets/Meshes/benjee10_shuttleOrbiter/OV_deltaWing 6 | } 7 | } -------------------------------------------------------------------------------- /GameData/Firefly/Patches/benjee10_shuttleOrbiter/OV_forwardFuselage.cfg: -------------------------------------------------------------------------------- 1 | @PART[benjee10_shuttle_forwardFuselage] 2 | { 3 | MODEL 4 | { 5 | model = Firefly/Assets/Meshes/benjee10_shuttleOrbiter/OV_forwardFuselage 6 | } 7 | } -------------------------------------------------------------------------------- /GameData/Firefly/Templates/Aluminum.txt: -------------------------------------------------------------------------------- 1 | ATMOFX_PART 2 | { 3 | name = [REPLACE WITH PART NAME] 4 | 5 | Color 6 | { 7 | trail_streak = 191 191 191 5 8 | wrap_streak = 191 191 191 5 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /GameData/Firefly/Templates/BoronHeatshield.txt: -------------------------------------------------------------------------------- 1 | ATMOFX_PART 2 | { 3 | name = [REPLACE WITH PART NAME] 4 | 5 | Color 6 | { 7 | trail_streak = 91 191 74 3 8 | wrap_streak = 91 191 74 3 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Firefly 2 | 3 | A mod for Kerbal Space Program that enhances reentry and aerodynamic effects. 4 | 5 | ## Features 6 | Firefly completely replaces the stock aerodynamic visual effects with its own custom system. 7 | 8 | - Built-in compatibility with popular planet packs like RSS and KSRSS. 9 | - Allows planet pack creators to define custom visual effects for planets and moons. 10 | - Supports custom "envelopes" for individual parts. 11 | - Includes a set of template configs for planet packs, planets, and parts. 12 | 13 | For details on writing configs, creating envelopes, and other information, check the [wiki](https://github.com/M1rageDev/Firefly/wiki). 14 | 15 | ## Dependencies 16 | The only **required** dependency is: 17 | - [ModuleManager](https://github.com/sarbian/ModuleManager) 18 | 19 | ## Installation 20 | We recommend installing the mod via CKAN. If installing manually, place the `GameData` folder inside your Kerbal Space Program directory (merge if prompted). 21 | 22 | ## Credits 23 | The mod's icon and particle sprites were created by **thunderchild**, who has also made incredible concept arts for the mod and helped shape it the way it is now. The effects would definitely not look as good as they do now without him. 24 | 25 | Massive thanks to **JonnyOThan** for making some really awesome optimizations to the mod's plugin and other support. 26 | 27 | The core shader was based on **Leah Lindner's** [paper](https://leah-lindner.com/blog/atmospheric-entry/) describing a method of creating promising reentry VFX. 28 | Without the paper, this mod would definitely not be possible. 29 | 30 | Massive thanks to all the people mentioned above, as well as everyone from the early testing groups, and all the Patrons - without you the mod would probably be much different than it is now, or wouldn't exist at all :) 31 | 32 | ## Licensing 33 | - Firefly and it's source code (both for the plugin and shaders) are licensed under GPL 3.0 (see [LICENSE](https://github.com/M1rageDev/Firefly/blob/dev/LICENSE)). 34 | - All model and texture assets (.mu, .png, .dds etc.) are All Rights Reserved. 35 | -------------------------------------------------------------------------------- /Source/AssetLoader.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using UnityEngine; 4 | 5 | namespace Firefly 6 | { 7 | [KSPAddon(KSPAddon.Startup.MainMenu, true)] 8 | public class AssetLoader : MonoBehaviour 9 | { 10 | // singleton 11 | public static AssetLoader Instance { get; private set; } 12 | 13 | // path to the assets 14 | public const string iconTexturePath = "Firefly/Assets/Textures/Icon"; 15 | public const string bundlePath = "GameData/Firefly/Assets/fireflybundle.ksp"; 16 | 17 | // loaded assets 18 | public Dictionary loadedShaders = new Dictionary(); 19 | public Dictionary loadedMaterials = new Dictionary(); 20 | public Dictionary loadedPrefabs = new Dictionary(); 21 | public Dictionary loadedTextures = new Dictionary(); 22 | 23 | // the actual stuff 24 | public Material globalMaterial; 25 | public bool hasMaterial = false; 26 | 27 | public Shader globalShader; 28 | public bool hasShader = false; 29 | 30 | public Texture2D iconTexture; 31 | 32 | // is everything loaded? 33 | public bool allAssetsLoaded = false; 34 | 35 | // the bundle 36 | AssetBundle bundle; 37 | 38 | public void Awake() 39 | { 40 | Instance = this; 41 | 42 | Logging.Log("AssetLoader Awake"); 43 | 44 | LoadAssets(); 45 | InitAssets(); 46 | 47 | if (!allAssetsLoaded) 48 | { 49 | ErrorManager.Instance.RegisterError(new ModLoadError( 50 | cause: ModLoadError.ProbableCause.IncorrectInstall, 51 | isSerious: true, 52 | sourcePath: "Firefly asset loader", 53 | description: "The asset loader did not load every required asset." 54 | )); 55 | 56 | return; 57 | } 58 | 59 | // disable the stock effects 60 | Logging.Log("Disabling stock effects"); 61 | Logging.Log("Turning the quality down to minimal"); 62 | GameSettings.AERO_FX_QUALITY = 0; 63 | } 64 | 65 | /// 66 | /// Loads all available assets from the asset bundle into the dictionaries 67 | /// 68 | internal void LoadAssets() 69 | { 70 | // load icon and other textures 71 | iconTexture = GameDatabase.Instance.GetTexture(iconTexturePath, false); 72 | for (int i = 0; i < ConfigManager.Instance.texturesToLoad.Count; i++) 73 | { 74 | Texture2D texture = GameDatabase.Instance.GetTexture(ConfigManager.Instance.texturesToLoad[i], false); 75 | if (texture != null) loadedTextures[ConfigManager.Instance.texturesToLoad[i]] = texture; 76 | } 77 | 78 | // load the asset bundle 79 | string loadPath = Path.Combine(KSPUtil.ApplicationRootPath, bundlePath); 80 | bundle = AssetBundle.LoadFromFile(loadPath); 81 | 82 | if (!bundle) 83 | { 84 | Logging.Log($"Bundle couldn't be loaded: {loadPath}"); 85 | ErrorManager.Instance.RegisterError(new ModLoadError( 86 | cause: ModLoadError.ProbableCause.IncorrectInstall, 87 | isSerious: true, 88 | sourcePath: "Firefly asset loader", 89 | description: "The asset loader could not load the asset bundle." 90 | )); 91 | } 92 | else 93 | { 94 | loadedShaders.Clear(); 95 | 96 | Shader[] shaders = bundle.LoadAllAssets(); 97 | foreach (Shader shader in shaders) 98 | { 99 | Logging.Log($"Found shader {shader.name}"); 100 | 101 | loadedShaders.Add(shader.name, shader); 102 | } 103 | 104 | Material[] materials = bundle.LoadAllAssets(); 105 | foreach (Material material in materials) 106 | { 107 | Logging.Log($"Found material {material.name}"); 108 | 109 | loadedMaterials.Add(material.name, material); 110 | } 111 | 112 | GameObject[] prefabs = bundle.LoadAllAssets(); 113 | foreach (GameObject prefab in prefabs) 114 | { 115 | Logging.Log($"Found prefab {prefab.name}"); 116 | 117 | loadedPrefabs.Add(prefab.name, prefab); 118 | } 119 | } 120 | } 121 | 122 | /// 123 | /// Initializes all assets 124 | /// 125 | internal void InitAssets() 126 | { 127 | Logging.Log("Versioning:"); 128 | Logging.Log(Versioning.VersionAuthor(this)); 129 | Logging.Log(Versioning.Version(this)); 130 | 131 | // load shader 132 | bool hasShader = TryGetShader("Firefly/Firefly", out Shader sh); 133 | if (!hasShader) 134 | { 135 | Logging.Log("Failed to load shader, halting startup"); 136 | return; 137 | } 138 | globalShader = sh; 139 | 140 | // load material 141 | bool hasMaterial = TryGetMaterial("Firefly", out Material mt); 142 | if (!hasMaterial) 143 | { 144 | Logging.Log("Failed to load Firefly material, halting startup"); 145 | return; 146 | } 147 | globalMaterial = mt; 148 | 149 | // initialize material 150 | globalMaterial.shader = globalShader; 151 | 152 | allAssetsLoaded = true; 153 | } 154 | 155 | /// 156 | /// Clears all loaded asset dictionaries 157 | /// 158 | internal void ClearAssets() 159 | { 160 | loadedShaders.Clear(); 161 | loadedMaterials.Clear(); 162 | loadedPrefabs.Clear(); 163 | } 164 | 165 | public void ReloadAssets() 166 | { 167 | bundle.Unload(true); 168 | ClearAssets(); 169 | 170 | LoadAssets(); 171 | InitAssets(); 172 | } 173 | 174 | public bool TryGetShader(string name, out Shader shader) 175 | { 176 | if (!loadedShaders.ContainsKey(name)) 177 | { 178 | // shader was not loaded 179 | shader = null; 180 | return false; 181 | } 182 | 183 | // shader was loaded, pass it to the out parameter 184 | shader = loadedShaders[name]; 185 | return true; 186 | } 187 | 188 | public bool TryGetMaterial(string name, out Material shader) 189 | { 190 | if (!loadedMaterials.ContainsKey(name)) 191 | { 192 | // material was not loaded 193 | shader = null; 194 | return false; 195 | } 196 | 197 | // material was loaded, pass it to the out parameter 198 | shader = loadedMaterials[name]; 199 | return true; 200 | } 201 | 202 | public bool TryGetPrefab(string name, out GameObject particle) 203 | { 204 | if (!loadedPrefabs.ContainsKey(name)) 205 | { 206 | // prefab was not loaded 207 | particle = null; 208 | return false; 209 | } 210 | 211 | // prefab was loaded, pass it to the out parameter 212 | particle = loadedPrefabs[name]; 213 | return true; 214 | } 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /Source/CameraManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using UnityEngine; 5 | using UnityEngine.Rendering; 6 | 7 | namespace Firefly 8 | { 9 | [KSPAddon(KSPAddon.Startup.Flight, false)] 10 | internal class CameraManager : MonoBehaviour 11 | { 12 | public static CameraManager Instance { get; private set; } 13 | 14 | public bool isHdr = false; 15 | 16 | List> cameraBuffers = new List>(); 17 | 18 | public bool ActualHdrState { get 19 | { 20 | if (Camera.main != null) return Camera.main.allowHDR; 21 | else return isHdr; 22 | } 23 | } 24 | 25 | public void Awake() 26 | { 27 | Instance = this; 28 | 29 | OverrideHDR((bool)ModSettings.I["hdr_override"]); 30 | } 31 | 32 | /// 33 | /// Adds a command buffer to the flight camera 34 | /// 35 | public void AddCommandBuffer(CameraEvent evt, CommandBuffer buf) 36 | { 37 | for (int i = 0; i < cameraBuffers.Count; i++) 38 | { 39 | if (cameraBuffers[i].Key == evt && cameraBuffers[i].Value == buf) return; 40 | } 41 | 42 | // add the CB 43 | Camera flightCam = FlightCamera.fetch.mainCamera; 44 | if (flightCam == null) return; 45 | 46 | CommandBuffer[] buffers = flightCam.GetCommandBuffers(evt); 47 | if (buffers.Contains(buf)) return; // detect duplicates 48 | 49 | flightCam.AddCommandBuffer(evt, buf); 50 | 51 | // add the CB to the global list 52 | cameraBuffers.Add(new KeyValuePair(evt, buf)); 53 | } 54 | 55 | /// 56 | /// Removes a specified command buffer from the flight camera 57 | /// 58 | public void RemoveCommandBuffer(CameraEvent evt, CommandBuffer buf) 59 | { 60 | FlightCamera.fetch.mainCamera?.RemoveCommandBuffer(evt, buf); 61 | 62 | for (int i = 0; i < cameraBuffers.Count; i++) 63 | { 64 | if (cameraBuffers[i].Key == evt && cameraBuffers[i].Value == buf) 65 | { 66 | cameraBuffers.RemoveAt(i); 67 | break; 68 | } 69 | } 70 | } 71 | 72 | /// 73 | /// Sets the HDR option for the main and IVA cameras 74 | /// 75 | public void OverrideHDR(bool hdr) 76 | { 77 | isHdr = hdr; 78 | 79 | ModSettings.I["hdr_override"] = hdr; 80 | 81 | if (Camera.main != null) 82 | { 83 | Camera.main.allowHDR = hdr; 84 | } 85 | 86 | if (InternalCamera.Instance != null) 87 | { 88 | InternalCamera.Instance.GetComponent().allowHDR = hdr; 89 | } 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /Source/DrawingUtils.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Firefly 4 | { 5 | // https://github.com/DefiantZombie/Collide-o-Scope/blob/master/Collide-o-Scope/DrawTools.cs 6 | internal class DrawingUtils 7 | { 8 | private static Material DrawMaterial = new Material(Shader.Find("Legacy Shaders/Particles/Alpha Blended")); 9 | 10 | private static void GLStart() 11 | { 12 | GL.PushMatrix(); 13 | DrawMaterial.SetPass(0); 14 | GL.LoadPixelMatrix(); 15 | GL.Begin(GL.LINES); 16 | } 17 | 18 | private static void GLEnd() 19 | { 20 | GL.End(); 21 | GL.PopMatrix(); 22 | } 23 | 24 | public static Camera GetCamera() 25 | { 26 | return FlightCamera.fetch.mainCamera; 27 | } 28 | 29 | private static void DrawLine(Vector3 origin, Vector3 destination, Color color) 30 | { 31 | var screenPoint1 = GetCamera().WorldToScreenPoint(origin); 32 | var screenPoint2 = GetCamera().WorldToScreenPoint(destination); 33 | 34 | if (screenPoint1.z <= 0 || screenPoint2.z <= 0) return; // Behind us? 35 | 36 | GL.Color(color); 37 | GL.Vertex3(screenPoint1.x, screenPoint1.y, 0f); 38 | GL.Vertex3(screenPoint2.x, screenPoint2.y, 0f); 39 | } 40 | 41 | private static void DrawRay(Vector3 origin, Vector3 direction, Color color) 42 | { 43 | var screenPoint1 = GetCamera().WorldToScreenPoint(origin); 44 | var screenPoint2 = GetCamera().WorldToScreenPoint(origin + direction); 45 | 46 | if (screenPoint1.z <= 0 || screenPoint2.z <= 0) return; // Behind us? 47 | 48 | GL.Color(color); 49 | GL.Vertex3(screenPoint1.x, screenPoint1.y, 0f); 50 | GL.Vertex3(screenPoint2.x, screenPoint2.y, 0f); 51 | } 52 | 53 | public static void DrawArrow(Vector3 origin, Vector3 fwd, Vector3 rt, Vector3 up, Color color) 54 | { 55 | GLStart(); 56 | 57 | Vector3 target = origin + fwd; 58 | Vector3 sp = origin + rt * 0.3f; 59 | Vector3 sn = origin - rt * 0.3f; 60 | Vector3 tp = origin + up * 0.3f; 61 | Vector3 tn = origin - up * 0.3f; 62 | 63 | DrawRay(origin, fwd, color); 64 | 65 | DrawLine(sp, target, color); 66 | DrawLine(sn, target, color); 67 | DrawLine(tp, target, color); 68 | DrawLine(tn, target, color); 69 | 70 | DrawLine(sp, origin, color); 71 | DrawLine(sn, origin, color); 72 | DrawLine(tp, origin, color); 73 | DrawLine(tn, origin, color); 74 | 75 | GLEnd(); 76 | } 77 | 78 | public static void DrawAxes(Vector3 origin, Vector3 fwd, Vector3 rt, Vector3 up) 79 | { 80 | GLStart(); 81 | 82 | DrawRay(origin, fwd.normalized, Color.blue); 83 | DrawRay(origin, rt.normalized, Color.red); 84 | DrawRay(origin, up.normalized, Color.green); 85 | 86 | GLEnd(); 87 | } 88 | 89 | public static void DrawBounds(Bounds bounds, Color color) 90 | { 91 | var center = bounds.center; 92 | 93 | var x = bounds.extents.x; 94 | var y = bounds.extents.y; 95 | var z = bounds.extents.z; 96 | 97 | var topa = center + new Vector3(x, y, z); 98 | var topb = center + new Vector3(x, y, -z); 99 | var topc = center + new Vector3(-x, y, z); 100 | var topd = center + new Vector3(-x, y, -z); 101 | 102 | var bota = center + new Vector3(x, -y, z); 103 | var botb = center + new Vector3(x, -y, -z); 104 | var botc = center + new Vector3(-x, -y, z); 105 | var botd = center + new Vector3(-x, -y, -z); 106 | 107 | GLStart(); 108 | GL.Color(color); 109 | 110 | // Top 111 | DrawLine(topa, topc, color); 112 | DrawLine(topa, topb, color); 113 | DrawLine(topc, topd, color); 114 | DrawLine(topb, topd, color); 115 | 116 | // Sides 117 | DrawLine(topa, bota, color); 118 | DrawLine(topb, botb, color); 119 | DrawLine(topc, botc, color); 120 | DrawLine(topd, botd, color); 121 | 122 | // Bottom 123 | DrawLine(bota, botc, color); 124 | DrawLine(bota, botb, color); 125 | DrawLine(botc, botd, color); 126 | DrawLine(botd, botb, color); 127 | 128 | GLEnd(); 129 | } 130 | 131 | public static void DrawBox(Vector3[] corners, Color color) 132 | { 133 | GLStart(); 134 | GL.Color(color); 135 | 136 | DrawLine(corners[0], corners[1], color); 137 | DrawLine(corners[2], corners[3], color); 138 | DrawLine(corners[0], corners[2], color); 139 | DrawLine(corners[1], corners[3], color); 140 | 141 | DrawLine(corners[4], corners[5], color); 142 | DrawLine(corners[6], corners[7], color); 143 | DrawLine(corners[4], corners[6], color); 144 | DrawLine(corners[5], corners[7], color); 145 | 146 | DrawLine(corners[4], corners[0], color); 147 | DrawLine(corners[5], corners[1], color); 148 | DrawLine(corners[6], corners[2], color); 149 | DrawLine(corners[7], corners[3], color); 150 | 151 | GLEnd(); 152 | } 153 | 154 | public static void DrawTransformBox(Transform t, Vector3 size, Color color) 155 | { 156 | var center = t.position; 157 | 158 | var x = size.x * 0.5f; 159 | var y = size.y * 0.5f; 160 | var z = size.z * 0.5f; 161 | 162 | var topa = center + t.right * x + t.up * y + t.forward * z; 163 | var topb = center + t.right * x + t.up * y + t.forward * -z; 164 | var topc = center + t.right * -x + t.up * y + t.forward * z; 165 | var topd = center + t.right * -x + t.up * y + t.forward * -z; 166 | 167 | var bota = center + t.right * x + t.up * -y + t.forward * z; 168 | var botb = center + t.right * x + t.up * -y + t.forward * -z; 169 | var botc = center + t.right * -x + t.up * -y + t.forward * z; 170 | var botd = center + t.right * -x + t.up * -y + t.forward * -z; 171 | 172 | GLStart(); 173 | GL.Color(color); 174 | 175 | // Top 176 | DrawLine(topa, topc, color); 177 | DrawLine(topa, topb, color); 178 | DrawLine(topc, topd, color); 179 | DrawLine(topb, topd, color); 180 | 181 | // Sides 182 | DrawLine(topa, bota, color); 183 | DrawLine(topb, botb, color); 184 | DrawLine(topc, botc, color); 185 | DrawLine(topd, botd, color); 186 | 187 | // Bottom 188 | DrawLine(bota, botc, color); 189 | DrawLine(bota, botb, color); 190 | DrawLine(botc, botd, color); 191 | DrawLine(botd, botb, color); 192 | 193 | GLEnd(); 194 | } 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /Source/ErrorManager.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | 4 | namespace Firefly 5 | { 6 | [KSPAddon(KSPAddon.Startup.Instantly, true)] 7 | class ErrorManager : MonoBehaviour 8 | { 9 | public static ErrorManager Instance { get; private set; } 10 | 11 | public List errorList = new List(); 12 | public List seriousErrors = new List(); 13 | public bool anyInstallErrors = false; 14 | 15 | public ErrorManager() 16 | { 17 | Instance = this; 18 | } 19 | 20 | public void RegisterError(ModLoadError error) 21 | { 22 | errorList.Add(error); 23 | 24 | // serious errors 25 | if (error.isSerious) 26 | { 27 | seriousErrors.Add(error); 28 | } 29 | 30 | // install errors 31 | if (error.cause == ModLoadError.ProbableCause.IncorrectInstall) 32 | { 33 | anyInstallErrors = true; 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Source/EventManager.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Firefly 4 | { 5 | [KSPAddon(KSPAddon.Startup.Flight, false)] 6 | internal class EventManager : MonoBehaviour 7 | { 8 | public void Start() 9 | { 10 | if (!AssetLoader.Instance.allAssetsLoaded) return; 11 | 12 | GameEvents.onVesselPartCountChanged.Add(OnVesselPartCountChanged); 13 | GameEvents.onVesselSOIChanged.Add(OnVesselSOIChanged); 14 | GameEvents.OnGameSettingsApplied.Add(OnGameSettingsApplied); 15 | } 16 | 17 | public void OnDestroy() 18 | { 19 | GameEvents.onVesselPartCountChanged.Remove(OnVesselPartCountChanged); 20 | GameEvents.onVesselSOIChanged.Remove(OnVesselSOIChanged); 21 | GameEvents.OnGameSettingsApplied.Remove(OnGameSettingsApplied); 22 | } 23 | 24 | /// 25 | /// Fires everytime a vessel is modified, sends a reload event 26 | /// 27 | void OnVesselPartCountChanged(Vessel vessel) 28 | { 29 | Logging.Log($"Modified vessel {vessel.name}"); 30 | 31 | var module = vessel.FindVesselModuleImplementing(); 32 | 33 | if (module != null) module.OnVesselPartCountChanged(); 34 | else Logging.Log("FX instance not registered"); 35 | } 36 | 37 | /// 38 | /// Fires everytime a vessel changes it's SOI 39 | /// 40 | void OnVesselSOIChanged(GameEvents.HostedFromToAction action) 41 | { 42 | var module = action.host.FindVesselModuleImplementing(); 43 | 44 | if (module != null) module.OnVesselSOIChanged(action.to); 45 | } 46 | 47 | void OnGameSettingsApplied() 48 | { 49 | if (GameSettings.AERO_FX_QUALITY > 0) 50 | { 51 | // user or something else changed the fx quality to bigger than 0 52 | // this means that the stock and Firefly effects will get mixed 53 | // make sure to show a message to the user informing them of thath 54 | GUI.WindowManager.Instance.stockEffectsWindow.Show(); 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Source/Firefly.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | {0DD486F0-EF12-458B-B0E2-F74C7A90E36A} 7 | Library 8 | Firefly 9 | Firefly 10 | net4.8 11 | 512 12 | true 13 | 14 | 15 | true 16 | false 17 | obj\Debug\ 18 | bin\Debug\ 19 | DEBUG;TRACE 20 | prompt 21 | 4 22 | 23 | 24 | true 25 | obj\Release\ 26 | bin\Release\ 27 | TRACE 28 | prompt 29 | 4 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | $(RepoRootPath)/GameData/Firefly/Firefly.version 39 | 1.12 40 | 41 | 42 | 43 | GameData/Firefly/Plugins 44 | true 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Source/GUI/ColorPickerWindow.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Firefly.GUI 4 | { 5 | internal class ColorPickerWindow : Window 6 | { 7 | public delegate void ColorPickerApply(); 8 | 9 | const int pickerSize = 300; 10 | const int sliderSize = 220; 11 | 12 | public ColorPickerApply onApplyColor; 13 | public Color color; 14 | float intensity; 15 | float h, s, v; 16 | 17 | // sliders 18 | bool rgbMode = false; 19 | float[] raw = new float[4]; 20 | string[] ui_raw = new string[4]; 21 | Texture2D[] sliderTex = new Texture2D[4]; 22 | Rect[] sliderRects = new Rect[4]; 23 | 24 | // selectors and textures 25 | Rect hueBarRect; 26 | Rect pickerRect; 27 | Texture2D pickerTex; 28 | Texture2D hueTex; 29 | Texture2D colorTex; 30 | Texture2D hueSelectorTex; 31 | Texture2D pickerSelectorTex; 32 | 33 | // pick state 34 | bool isPicking; 35 | float pickTimer; 36 | 37 | public ColorPickerWindow(float x, float y, Color c) : base("Color picker") 38 | { 39 | windowRect = new Rect(x, y, 300f, 100f); 40 | 41 | Open(c); 42 | Hide(); 43 | } 44 | 45 | /// 46 | /// Opens the window with a specified color 47 | /// 48 | public void Open(Color c) 49 | { 50 | Show(); 51 | 52 | color = c; 53 | Utils.ColorHSV(c, out h, out s, out v); 54 | intensity = c.a; 55 | 56 | // generate initial textures 57 | hueTex = TextureUtils.GenerateHueTexture(120, 20); 58 | pickerTex = TextureUtils.GenerateGradientTexture(pickerSize, pickerSize, h); 59 | colorTex = TextureUtils.GenerateColorTexture(1, 1, color); 60 | 61 | hueSelectorTex = TextureUtils.GenerateSelectorTexture(3, 24, 1, Color.white, Color.black); 62 | pickerSelectorTex = TextureUtils.GenerateSelectorTexture(3, 3, 1, Color.white, Color.black); 63 | 64 | GenerateSliderTextures(); 65 | sliderTex[3] = TextureUtils.GenerateGradientTexture(120, 20, Color.black, Color.white); 66 | 67 | // update raw slider values based on color 68 | if (rgbMode) 69 | { 70 | raw[0] = color.r; 71 | raw[1] = color.g; 72 | raw[2] = color.b; 73 | } 74 | else 75 | { 76 | raw[0] = h; 77 | raw[1] = s; 78 | raw[2] = v; 79 | } 80 | raw[3] = intensity / 5f; 81 | 82 | // update ui text 83 | ui_raw[0] = $"{(raw[0] * 255f):F0}"; 84 | ui_raw[1] = $"{(raw[1] * 255f):F0}"; 85 | ui_raw[2] = $"{(raw[2] * 255f):F0}"; 86 | ui_raw[3] = $"{(raw[3] * 5f):F1}"; 87 | } 88 | 89 | public override void Draw(int id) 90 | { 91 | GUILayout.BeginVertical(); 92 | 93 | DrawColor(); 94 | GUILayout.Space(20); 95 | 96 | DrawHueBar(); 97 | GUILayout.Space(10); 98 | 99 | DrawPicker(); 100 | GUILayout.Space(20); 101 | 102 | DrawSliders(); 103 | DrawBottomControls(); 104 | 105 | GUILayout.EndVertical(); 106 | 107 | // after drawing handle input 108 | HandleInput(); 109 | } 110 | 111 | void DrawBottomControls() 112 | { 113 | // draw rgb toggle 114 | bool previousRgb = rgbMode; 115 | rgbMode = GUILayout.Toggle(rgbMode, "RGB mode"); 116 | if (previousRgb != rgbMode) OnRGBToggle(); 117 | 118 | // draw buttons 119 | GUILayout.Space(20); 120 | if (GUILayout.Button("Apply color")) onApplyColor(); 121 | if (GUILayout.Button("Save and close")) 122 | { 123 | onApplyColor(); 124 | Hide(); 125 | } 126 | if (GUILayout.Button("Close without saving")) Hide(); 127 | } 128 | 129 | // draws color preview 130 | void DrawColor() 131 | { 132 | Rect rect = GUILayoutUtility.GetRect(120f, 20f, GUILayout.Width(pickerSize)); 133 | UnityEngine.GUI.DrawTexture(rect, colorTex); 134 | } 135 | 136 | // draws the hue selection bar 137 | void DrawHueBar() 138 | { 139 | Rect rect = GUILayoutUtility.GetRect(120f, 20f, GUILayout.Width(pickerSize)); 140 | UnityEngine.GUI.DrawTexture(rect, hueTex); 141 | hueBarRect = GUIUtility.GUIToScreenRect(rect); 142 | 143 | // selector 144 | rect = new Rect(rect.x + h * rect.width, rect.y - 1, 3, 22); 145 | UnityEngine.GUI.DrawTexture(rect, hueSelectorTex); 146 | } 147 | 148 | // draws the saturation and value selection field 149 | void DrawPicker() 150 | { 151 | Rect rect = GUILayoutUtility.GetRect(120f, 120f, GUILayout.Width(pickerSize), GUILayout.Height(pickerSize)); 152 | UnityEngine.GUI.DrawTexture(rect, pickerTex); 153 | pickerRect = GUIUtility.GUIToScreenRect(rect); 154 | 155 | // selector 156 | rect = new Rect(rect.x + s * rect.width, rect.y + (1f - v) * rect.height, 3, 3); 157 | UnityEngine.GUI.DrawTexture(rect, pickerSelectorTex); 158 | } 159 | 160 | // draws all color sliders 161 | void DrawSliders() 162 | { 163 | DrawColorSlider(rgbMode ? "R" : "H", 0, true); 164 | DrawColorSlider(rgbMode ? "G" : "S", 1, true); 165 | DrawColorSlider(rgbMode ? "B" : "V", 2, true); 166 | GUILayout.Space(10); 167 | DrawColorSlider("I", 3, false); // HDR intensity 168 | } 169 | 170 | // draws a single color component slider 171 | void DrawColorSlider(string label, int index, bool isColor) 172 | { 173 | GUILayout.BeginHorizontal(); 174 | 175 | // label 176 | GUILayout.Label(label, GUILayout.Width(40)); 177 | 178 | // slider 179 | Rect rect = GUILayoutUtility.GetRect(120f, 20f, GUILayout.Width(sliderSize)); 180 | UnityEngine.GUI.DrawTexture(rect, sliderTex[index]); 181 | sliderRects[index] = GUIUtility.GUIToScreenRect(rect); 182 | 183 | // selector 184 | rect = new Rect(rect.x + raw[index] * rect.width, rect.y - 1, 5, 22); 185 | UnityEngine.GUI.DrawTexture(rect, hueSelectorTex); 186 | 187 | // number input 188 | string newText = GUILayout.TextField(ui_raw[index], GUILayout.Width(40)); 189 | bool hasValue = float.TryParse(newText, out float v); 190 | if (newText != ui_raw[index] && hasValue) // only set the value if it changed and if it's a correct float 191 | { 192 | // if color, use 255 as a base 193 | if (isColor) 194 | { 195 | float clamped = Mathf.Clamp(v, 0f, 255f); 196 | ui_raw[index] = $"{clamped:F0}"; // display the value as an int 197 | raw[index] = clamped / 255f; 198 | } else // otherwise use 5 199 | { 200 | // HDR intensity slider 201 | float clamped = Mathf.Clamp(v, 0f, 5f); 202 | ui_raw[index] = $"{clamped:F1}"; 203 | raw[index] = clamped / 5f; 204 | } 205 | 206 | OnSliderChange(); 207 | } 208 | 209 | GUILayout.EndHorizontal(); 210 | } 211 | 212 | // handles input on the hue bar 213 | void HandleHueInput(Vector2 mouse) 214 | { 215 | bool inBar = GuiUtils.GetRectPoint(mouse, hueBarRect, out Vector2 clickPoint); 216 | 217 | if (inBar) 218 | { 219 | isPicking = true; 220 | 221 | h = clickPoint.x / hueBarRect.width; 222 | 223 | // regenerate picker texture 224 | pickerTex = TextureUtils.GenerateGradientTexture(pickerSize, pickerSize, h); 225 | UpdateColor(); 226 | } 227 | } 228 | 229 | // handles input on the SV field 230 | void HandlePickerInput(Vector2 mouse) 231 | { 232 | bool inBar = GuiUtils.GetRectPoint(mouse, pickerRect, out Vector2 clickPoint); 233 | 234 | if (inBar) 235 | { 236 | isPicking = true; 237 | 238 | Color c = pickerTex.GetPixel((int)clickPoint.x, (int)clickPoint.y); 239 | Utils.ColorHSV(c, out _, out s, out v); 240 | 241 | UpdateColor(); 242 | } 243 | } 244 | 245 | // handles input on the sliders 246 | void HandleSliderInput(Vector2 mouse) 247 | { 248 | for (int i = 0; i < 4; i++) 249 | { 250 | bool inBar = GuiUtils.GetRectPoint(mouse, sliderRects[i], out Vector2 clickPoint); 251 | if (!inBar) continue; 252 | 253 | isPicking = true; 254 | 255 | raw[i] = clickPoint.x / sliderRects[i].width; 256 | 257 | OnSliderChange(); 258 | } 259 | } 260 | 261 | void HandleInput() 262 | { 263 | // handle clicks 264 | if (Input.GetMouseButton(0) && Event.current.type == EventType.Repaint) 265 | { 266 | Vector2 mouse = new Vector2(Input.mousePosition.x, Screen.height - Input.mousePosition.y); 267 | 268 | HandleHueInput(mouse); 269 | HandlePickerInput(mouse); 270 | HandleSliderInput(mouse); 271 | } 272 | 273 | // handle unclicks 274 | if (Input.GetMouseButtonUp(0) && isPicking) 275 | { 276 | isPicking = false; 277 | pickTimer = 0.5f; 278 | } 279 | 280 | if (pickTimer > 0f) pickTimer -= Time.deltaTime; 281 | 282 | // handle drag 283 | if (!isPicking && pickTimer <= 0f) UnityEngine.GUI.DragWindow(); 284 | } 285 | 286 | void UpdateColor() 287 | { 288 | color = Utils.ColorHSV(h, s, v); 289 | color.a = intensity; 290 | colorTex = TextureUtils.GenerateColorTexture(1, 1, color); 291 | 292 | // update sliders 293 | if (rgbMode) 294 | { 295 | raw[0] = color.r; 296 | raw[1] = color.g; 297 | raw[2] = color.b; 298 | } 299 | else 300 | { 301 | raw[0] = h; 302 | raw[1] = s; 303 | raw[2] = v; 304 | } 305 | 306 | // update slider textures 307 | GenerateSliderTextures(); 308 | 309 | // update text fields 310 | ui_raw[0] = $"{(raw[0] * 255f):F0}"; 311 | ui_raw[1] = $"{(raw[1] * 255f):F0}"; 312 | ui_raw[2] = $"{(raw[2] * 255f):F0}"; 313 | ui_raw[3] = $"{(raw[3] * 5f):F1}"; 314 | } 315 | 316 | void OnSliderChange() 317 | { 318 | // update color 319 | if (rgbMode) 320 | { 321 | Utils.ColorHSV(new Color(raw[0], raw[1], raw[2]), out h, out s, out v); 322 | } else 323 | { 324 | h = raw[0]; 325 | s = raw[1]; 326 | v = raw[2]; 327 | } 328 | 329 | // update intensity 330 | intensity = raw[3] * 5f; 331 | 332 | pickerTex = TextureUtils.GenerateGradientTexture(pickerSize, pickerSize, h); 333 | UpdateColor(); 334 | } 335 | 336 | void OnRGBToggle() 337 | { 338 | if (rgbMode) 339 | { 340 | raw[0] = color.r; 341 | raw[1] = color.g; 342 | raw[2] = color.b; 343 | } 344 | else 345 | { 346 | raw[0] = h; 347 | raw[1] = s; 348 | raw[2] = v; 349 | } 350 | 351 | OnSliderChange(); 352 | } 353 | 354 | void GenerateSliderTextures() 355 | { 356 | if (rgbMode) 357 | { 358 | sliderTex[0] = TextureUtils.GenerateGradientTexture(100, 20, new Color(0f, color.g, color.b), new Color(1f, color.g, color.b)); 359 | sliderTex[1] = TextureUtils.GenerateGradientTexture(100, 20, new Color(color.r, 0f, color.b), new Color(color.r, 1f, color.b)); 360 | sliderTex[2] = TextureUtils.GenerateGradientTexture(100, 20, new Color(color.r, color.g, 0f), new Color(color.r, color.g, 1f)); 361 | } else 362 | { 363 | sliderTex[0] = TextureUtils.GenerateHueTexture(100, 20, s, v); 364 | sliderTex[1] = TextureUtils.GenerateGradientTexture(100, 20, Utils.ColorHSV(h, 0f, v), Utils.ColorHSV(h, 1f, v)); 365 | sliderTex[2] = TextureUtils.GenerateGradientTexture(100, 20, Utils.ColorHSV(h, s, 0f), Utils.ColorHSV(h, s, 1f)); 366 | } 367 | } 368 | } 369 | } 370 | -------------------------------------------------------------------------------- /Source/GUI/EffectEditor.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using UnityEngine; 3 | 4 | namespace Firefly.GUI 5 | { 6 | internal class CreateConfigPopup : Window 7 | { 8 | public delegate void popupSaveDelg(); 9 | public popupSaveDelg onPopupSave; 10 | 11 | string[] bodyConfigs; 12 | 13 | // public values 14 | public string selectedName; 15 | public string selectedTemplate; 16 | 17 | // ui 18 | string ui_cfgName; 19 | Vector2 ui_bodyListPosition; 20 | int ui_bodyChoice = 0; 21 | 22 | public CreateConfigPopup() : base("New config") 23 | { 24 | windowRect = new Rect(900f, 100f, 300f, 300f); 25 | } 26 | 27 | public void Init(string[] bodyConfigs) 28 | { 29 | ui_cfgName = "NewBody"; 30 | ui_bodyListPosition = Vector2.zero; 31 | ui_bodyChoice = 0; 32 | 33 | this.bodyConfigs = bodyConfigs; 34 | 35 | Show(); 36 | } 37 | 38 | public override void Draw(int id) 39 | { 40 | GUILayout.BeginVertical(); 41 | 42 | // name input 43 | GuiUtils.DrawStringInput("Config name", ref ui_cfgName); 44 | 45 | // config selector 46 | GUILayout.Label("Select a template config"); 47 | DrawConfigSelector(); 48 | 49 | // cancel/done controls 50 | GUILayout.BeginHorizontal(); 51 | if (GUILayout.Button("Cancel")) Hide(); 52 | if (GUILayout.Button("Done")) Done(); 53 | GUILayout.EndHorizontal(); 54 | 55 | GUILayout.EndVertical(); 56 | UnityEngine.GUI.DragWindow(); 57 | } 58 | 59 | void DrawConfigSelector() 60 | { 61 | ui_bodyListPosition = GUILayout.BeginScrollView(ui_bodyListPosition, GUILayout.Width(300f), GUILayout.Height(125f)); 62 | 63 | ui_bodyChoice = GUILayout.SelectionGrid(ui_bodyChoice, bodyConfigs, Mathf.Min(bodyConfigs.Length, 3)); 64 | 65 | GUILayout.EndScrollView(); 66 | } 67 | 68 | void Done() 69 | { 70 | selectedName = ui_cfgName; 71 | selectedTemplate = bodyConfigs[ui_bodyChoice]; 72 | 73 | onPopupSave(); 74 | 75 | Hide(); 76 | } 77 | } 78 | 79 | internal class EffectEditor : Window 80 | { 81 | public static EffectEditor Instance { get; private set; } 82 | 83 | public Vector3 effectDirection = -Vector3.up; 84 | 85 | public BodyConfig config; 86 | 87 | string[] bodyConfigs; 88 | string currentBody; 89 | 90 | AtmoFxModule fxModule = null; 91 | 92 | // gui 93 | GuiUtils.ConfirmingButton ui_removeConfigBtn = new GuiUtils.ConfirmingButton("Remove selected config"); 94 | GuiUtils.ConfirmingButton ui_saveConfigBtn = new GuiUtils.ConfirmingButton("Save selected to cfg file"); 95 | 96 | Vector2 ui_bodyListPosition; 97 | int ui_bodyChoice; 98 | 99 | string ui_strengthMultiplier; 100 | string ui_lengthMultiplier; 101 | string ui_opacityMultiplier; 102 | string ui_wrapFresnelModifier; 103 | string ui_particleThreshold; 104 | 105 | // dialog windows 106 | public ColorPickerWindow colorPicker; 107 | string currentlyPicking; 108 | 109 | public CreateConfigPopup createConfigPopup; 110 | 111 | public EffectEditor() : base("Effect editor") 112 | { 113 | windowRect = new Rect(300, 100, 300, 100); 114 | Instance = this; 115 | 116 | bodyConfigs = ConfigManager.Instance.bodyConfigs.Keys.ToArray(); 117 | 118 | colorPicker = new ColorPickerWindow(900, 100, Color.red); 119 | colorPicker.onApplyColor = OnApplyColor; 120 | 121 | createConfigPopup = new CreateConfigPopup(); 122 | createConfigPopup.onPopupSave = OnPopupSave; 123 | } 124 | 125 | public override void Show() 126 | { 127 | base.Show(); 128 | 129 | Vessel vessel = FlightGlobals.ActiveVessel; 130 | if (vessel == null) return; 131 | fxModule = vessel.FindVesselModuleImplementing(); 132 | if (fxModule == null) return; 133 | 134 | // select main body 135 | string mainBody = vessel.mainBody.bodyName; 136 | 137 | if (bodyConfigs.Contains(mainBody)) 138 | { 139 | // only select if a config for the body exists 140 | ui_bodyChoice = bodyConfigs.IndexOf(mainBody); 141 | currentBody = mainBody; 142 | config = new BodyConfig(ConfigManager.Instance.bodyConfigs[currentBody]); 143 | } else 144 | { 145 | // otherwise, go with the default 146 | ui_bodyChoice = 0; 147 | currentBody = "Default"; 148 | config = new BodyConfig(ConfigManager.Instance.defaultConfig); 149 | } 150 | 151 | ResetFieldText(); 152 | 153 | // load effects 154 | fxModule.overridePhysics = true; 155 | fxModule.overrideData = OverridePhysicsData.Default(); 156 | fxModule.overrideData.effectStrength = (float)ModSettings.I["strength_base"]; 157 | fxModule.overrideData.effectState = 1f; 158 | fxModule.overrideData.overridenBy = "Effect editor"; 159 | if (!fxModule.isLoaded) fxModule.CreateVesselFx(); 160 | ApplyShipDirection(); 161 | } 162 | 163 | public override void Hide() 164 | { 165 | base.Hide(); 166 | 167 | fxModule.overridePhysics = false; 168 | } 169 | 170 | public override void Draw(int id) 171 | { 172 | GUILayout.BeginVertical(); 173 | GUILayout.Label("Note: the effect editor should not be open during normal gameplay."); 174 | 175 | // split editor into 2 parts 176 | GUILayout.BeginHorizontal(); 177 | 178 | // draw left part 179 | DrawLeftEditor(); 180 | 181 | // draw right part 182 | DrawRightEditor(); 183 | 184 | // end window 185 | GUILayout.EndHorizontal(); 186 | GUILayout.EndVertical(); 187 | UnityEngine.GUI.DragWindow(); 188 | 189 | // apply stuff 190 | fxModule.overrideData.bodyConfig = config; 191 | 192 | // 3d 193 | if (fxModule == null || fxModule.fxVessel == null) return; 194 | Transform camTransform = fxModule.fxVessel.airstreamCamera.transform; 195 | if (!fxModule.debugMode) DrawingUtils.DrawArrow(camTransform.position, camTransform.forward, camTransform.right, camTransform.up, Color.cyan); 196 | } 197 | 198 | void DrawLeftEditor() 199 | { 200 | GUILayout.BeginVertical(); 201 | 202 | // config create 203 | if (GUILayout.Button("Create new config") && !createConfigPopup.show) createConfigPopup.Init(bodyConfigs); 204 | if (ui_removeConfigBtn.Draw(Time.time) && currentBody != "Default") RemoveSelectedConfig(); 205 | 206 | // body selection 207 | GUILayout.Label("Select a config:"); 208 | DrawConfigSelector(); 209 | GUILayout.Space(20); 210 | 211 | // sim configuration 212 | DrawSimConfiguration(); 213 | GUILayout.Space(20); 214 | 215 | // bottom controls 216 | if (GUILayout.Button("Align effects to camera")) ApplyCameraDirection(); 217 | if (GUILayout.Button("Align effects to ship")) ApplyShipDirection(); 218 | if (ui_saveConfigBtn.Draw(Time.time)) SaveConfig(); 219 | 220 | // end 221 | GUILayout.EndVertical(); 222 | } 223 | 224 | void DrawRightEditor() 225 | { 226 | GUILayout.BeginVertical(); 227 | GUILayout.Label("Body configuration:"); 228 | 229 | // body configuration 230 | DrawBodyConfiguration(); 231 | 232 | GUILayout.Space(20); 233 | 234 | // color configuration 235 | DrawColorConfiguration(); 236 | 237 | // end 238 | GUILayout.EndVertical(); 239 | } 240 | 241 | void DrawConfigSelector() 242 | { 243 | // draw the scrollview and selection grid with the configs 244 | ui_bodyListPosition = GUILayout.BeginScrollView(ui_bodyListPosition, GUILayout.Width(300f), GUILayout.Height(125f)); 245 | int newChoice = GUILayout.SelectionGrid(ui_bodyChoice, bodyConfigs, Mathf.Min(bodyConfigs.Length, 3)); 246 | 247 | if (newChoice != ui_bodyChoice) 248 | { 249 | // update ConfigManager 250 | if (currentBody != "Default") ConfigManager.Instance.bodyConfigs[currentBody] = new BodyConfig(config); 251 | else ConfigManager.Instance.defaultConfig = new BodyConfig(config); 252 | 253 | // reset the config stuff 254 | ui_bodyChoice = newChoice; 255 | currentBody = bodyConfigs[newChoice]; 256 | 257 | config = new BodyConfig(ConfigManager.Instance.bodyConfigs[currentBody]); 258 | fxModule.overrideData.bodyConfig = config; 259 | ResetFieldText(); 260 | 261 | fxModule.ReloadVessel(); 262 | } 263 | 264 | GUILayout.EndScrollView(); 265 | } 266 | 267 | void DrawSimConfiguration() 268 | { 269 | GUILayout.Label("These sliders are for previewing the effects while not reentering. Do not use these during normal gameplay!"); 270 | fxModule.overrideData.effectStrength = GuiUtils.LabelSlider("Simulated effect strength", fxModule.overrideData.effectStrength, 0f, (float)ModSettings.I["strength_base"]); 271 | fxModule.overrideData.effectState = GuiUtils.LabelSlider("Simulated effect state", fxModule.overrideData.effectState, 0f, 1f); 272 | } 273 | 274 | void DrawBodyConfiguration() 275 | { 276 | GuiUtils.DrawFloatInput("Strength multiplier", ref ui_strengthMultiplier, ref config.strengthMultiplier, GUILayout.Width(300f)); 277 | GuiUtils.DrawFloatInput("Length multiplier", ref ui_lengthMultiplier, ref config.lengthMultiplier); 278 | GuiUtils.DrawFloatInput("Opacity multiplier", ref ui_opacityMultiplier, ref config.opacityMultiplier); 279 | GuiUtils.DrawFloatInput("Wrap fresnel modifier", ref ui_wrapFresnelModifier, ref config.wrapFresnelModifier); 280 | GuiUtils.DrawFloatInput("Particle threshold", ref ui_particleThreshold, ref config.particleThreshold); 281 | 282 | config.streakProbability = GuiUtils.LabelSlider("Streak probability", config.streakProbability, 0f, 0.09f); 283 | config.streakThreshold = GuiUtils.LabelSlider("Streak threshold", config.streakThreshold, 0f, -0.5f); 284 | } 285 | 286 | void DrawColorConfiguration() 287 | { 288 | DrawColorButton("Glow", "glow"); 289 | DrawColorButton("Hot Glow", "glow_hot"); 290 | 291 | DrawColorButton("Trail Primary", "trail_primary"); 292 | DrawColorButton("Trail Secondary", "trail_secondary"); 293 | DrawColorButton("Trail Tertiary", "trail_tertiary"); 294 | DrawColorButton("Trail Streak", "trail_streak"); 295 | 296 | DrawColorButton("Wrap Layer", "wrap_layer"); 297 | DrawColorButton("Wrap Streak", "wrap_streak"); 298 | 299 | DrawColorButton("Bowshock", "shockwave"); 300 | } 301 | 302 | // draws a button for a config color 303 | void DrawColorButton(string label, string colorKey) 304 | { 305 | HDRColor c = config.colors[colorKey]; 306 | 307 | if (GuiUtils.DrawColorButton(label, Texture2D.whiteTexture, c.baseColor)) 308 | { 309 | currentlyPicking = colorKey; 310 | colorPicker.Open(c.baseColor); 311 | } 312 | } 313 | 314 | // saves config to cfg file 315 | void SaveConfig() 316 | { 317 | // save config to ConfigManager 318 | if (currentBody != "Default") ConfigManager.Instance.bodyConfigs[currentBody] = new BodyConfig(config); 319 | else ConfigManager.Instance.defaultConfig = new BodyConfig(config); 320 | 321 | Logging.Log($"Saving body config {currentBody}"); 322 | 323 | // decide saving path 324 | string path = config.cfgPath; 325 | if (!ConfigManager.Instance.loadedBodyConfigs.Contains(currentBody)) 326 | { 327 | path = KSPUtil.ApplicationRootPath + ConfigManager.NewConfigPath + config.bodyName + ".cfg"; 328 | } 329 | 330 | // create a parent node 331 | ConfigNode parent = new ConfigNode("ATMOFX_BODY"); 332 | 333 | // create the node 334 | ConfigNode node = new ConfigNode("ATMOFX_BODY"); 335 | 336 | config.SaveToNode(ref node); 337 | 338 | // add to parent and save 339 | parent.AddNode(node); 340 | parent.Save(path); 341 | 342 | ScreenMessages.PostScreenMessage($"Saved config to file at path\n{path}", 5f); 343 | Logging.Log("Saved body config " + path); 344 | } 345 | 346 | void RemoveSelectedConfig() 347 | { 348 | ConfigManager.Instance.bodyConfigs.Remove(currentBody); 349 | config = new BodyConfig(ConfigManager.Instance.bodyConfigs["Default"]); 350 | fxModule.overrideData.bodyConfig = config; 351 | currentBody = "Default"; 352 | ui_bodyChoice = 0; 353 | 354 | bodyConfigs = ConfigManager.Instance.bodyConfigs.Keys.ToArray(); 355 | ResetFieldText(); 356 | 357 | fxModule.ReloadVessel(); 358 | } 359 | 360 | // resets the ui input texts 361 | void ResetFieldText() 362 | { 363 | ui_strengthMultiplier = config.strengthMultiplier.ToString(); 364 | ui_lengthMultiplier = config.lengthMultiplier.ToString(); 365 | ui_opacityMultiplier = config.opacityMultiplier.ToString(); 366 | ui_wrapFresnelModifier = config.wrapFresnelModifier.ToString(); 367 | ui_particleThreshold = config.particleThreshold.ToString(); 368 | } 369 | 370 | // sets the direction to the current camera facing 371 | void ApplyCameraDirection() 372 | { 373 | Vessel vessel = FlightGlobals.ActiveVessel; 374 | if (vessel == null) return; 375 | if (FlightCamera.fetch.mainCamera == null) return; 376 | 377 | effectDirection = vessel.transform.InverseTransformDirection(FlightCamera.fetch.mainCamera.transform.forward); 378 | fxModule.overrideData.entryDirection = vessel.transform.TransformDirection(effectDirection); 379 | } 380 | 381 | // sets the direction to the ship's axis 382 | void ApplyShipDirection() 383 | { 384 | Vessel vessel = FlightGlobals.ActiveVessel; 385 | if (vessel == null) return; 386 | 387 | effectDirection = -Vector3.up; 388 | fxModule.overrideData.entryDirection = vessel.transform.TransformDirection(effectDirection); 389 | } 390 | 391 | // gets called when the color picker applies a color 392 | void OnApplyColor() 393 | { 394 | config.colors[currentlyPicking] = new HDRColor(colorPicker.color); 395 | 396 | // reset the commandbuffer, to update colors 397 | fxModule.DestroyCommandBuffer(); 398 | fxModule.InitializeCommandBuffer(); 399 | fxModule.PopulateCommandBuffer(); 400 | } 401 | 402 | // gets called when the config creation popup confirms creation and closes 403 | void OnPopupSave() 404 | { 405 | // update ConfigManager 406 | if (currentBody != "Default") ConfigManager.Instance.bodyConfigs[currentBody] = new BodyConfig(config); 407 | else ConfigManager.Instance.defaultConfig = new BodyConfig(config); 408 | 409 | // get the new config from the selected template 410 | config = new BodyConfig(ConfigManager.Instance.bodyConfigs[createConfigPopup.selectedTemplate]); 411 | currentBody = createConfigPopup.selectedName; 412 | config.bodyName = currentBody; 413 | 414 | // create a new config array and update ConfigManager's one 415 | string[] newBodyArray = new string[bodyConfigs.Length + 1]; 416 | bodyConfigs.CopyTo(newBodyArray, 0); 417 | newBodyArray[bodyConfigs.Length] = currentBody; 418 | ConfigManager.Instance.bodyConfigs.Add(currentBody, new BodyConfig(config)); 419 | 420 | // reset the current body stuff 421 | ui_bodyChoice = bodyConfigs.Length; 422 | 423 | bodyConfigs = newBodyArray; 424 | ResetFieldText(); 425 | 426 | fxModule.overrideData.bodyConfig = config; 427 | fxModule.ReloadVessel(); 428 | } 429 | } 430 | } 431 | -------------------------------------------------------------------------------- /Source/GUI/ErrorListWindow.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Firefly.GUI 4 | { 5 | internal class ErrorListWindow : Window 6 | { 7 | GUIStyle seriousErrorStyle = new GUIStyle(); 8 | 9 | // ui stuff 10 | Vector2 ui_errorListPosition; 11 | 12 | public ErrorListWindow() : base("Firefly Error List") 13 | { 14 | windowRect = new Rect(300, 100, 600, 100); 15 | if (ErrorManager.Instance.errorList.Count > 0) 16 | { 17 | Show(); 18 | } 19 | 20 | seriousErrorStyle.normal.textColor = Color.red; 21 | } 22 | 23 | public override void Draw(int id) 24 | { 25 | GUILayout.BeginVertical(); 26 | 27 | // notification about serious errors 28 | if (ErrorManager.Instance.seriousErrors.Count > 0) 29 | { 30 | GUILayout.Label($"The loader detected {ErrorManager.Instance.seriousErrors.Count} serious errors. These will make the mod NOT function properly or AT ALL.", seriousErrorStyle); 31 | } else 32 | { 33 | GUILayout.Label("These errors are not serious, but will likely make something not work (like custom configs not getting applied)"); 34 | } 35 | 36 | // notification about incorrect install 37 | if (ErrorManager.Instance.anyInstallErrors) 38 | { 39 | GUILayout.Space(20f); 40 | GUILayout.Label("One or more of the errors are probably caused by an incorrect install of the mod. Please make sure you installed it according to the install instructions."); 41 | GUILayout.Label("We highly recommend using CKAN to install mods."); 42 | } 43 | 44 | // draw the scrollview with the errors 45 | DrawErrorList(); 46 | 47 | // draw close button 48 | if (GUILayout.Button("Close error list (ignore errors)")) Hide(); 49 | 50 | GUILayout.EndVertical(); 51 | UnityEngine.GUI.DragWindow(); 52 | } 53 | 54 | void DrawErrorList() 55 | { 56 | GUILayout.Space(20f); 57 | ui_errorListPosition = GUILayout.BeginScrollView(ui_errorListPosition, GUILayout.Height(300f)); 58 | 59 | GUILayout.BeginVertical(); 60 | GuiUtils.DrawHorizontalSeparator(400f); 61 | for (int i = 0; i < ErrorManager.Instance.errorList.Count; i++) 62 | { 63 | DrawError(ErrorManager.Instance.errorList[i]); 64 | GuiUtils.DrawHorizontalSeparator(400f); 65 | } 66 | GUILayout.EndVertical(); 67 | 68 | GUILayout.EndScrollView(); 69 | } 70 | 71 | void DrawError(ModLoadError error) 72 | { 73 | if (error.isSerious) 74 | { 75 | GUILayout.Label("This error is serious. It will likely make the mod not work at all.", seriousErrorStyle); 76 | } 77 | GUILayout.Label("Error source: " + error.sourcePath); 78 | GUILayout.Label("Error description: " + error.description); 79 | GUILayout.Label("Probable cause: " + error.cause.ToString()); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Source/GUI/FireflyWindow.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Firefly.GUI 4 | { 5 | class FireflyWindow : Window 6 | { 7 | // toggling effects 8 | public bool tgl_EffectToggle = true; 9 | 10 | // timer for clicking the reload button 11 | float reloadBtnTime = 0f; 12 | 13 | public FireflyWindow() : base("") 14 | { 15 | title = $"Firefly {Versioning.Version(this)}"; 16 | windowRect = new Rect(0, 100, 300, 100); 17 | 18 | Show(); 19 | } 20 | 21 | public override void Draw(int id) 22 | { 23 | // effect editor open/close 24 | if (GUILayout.Button($"{(EffectEditor.Instance.show ? "Close" : "Open")} config editor")) 25 | { 26 | if (!EffectEditor.Instance.show) EffectEditor.Instance.Show(); 27 | else EffectEditor.Instance.Hide(); 28 | } 29 | 30 | // particle editor open/close 31 | if (GUILayout.Button($"{(ParticleEditor.Instance.show ? "Close" : "Open")} particle editor")) 32 | { 33 | if (!ParticleEditor.Instance.show) ParticleEditor.Instance.Show(); 34 | else ParticleEditor.Instance.Hide(); 35 | } 36 | 37 | // settings 38 | DrawSettings(); 39 | GUILayout.Space(40); 40 | 41 | // init vessel and module 42 | Vessel vessel = FlightGlobals.ActiveVessel; 43 | var fxModule = vessel.FindVesselModuleImplementing(); 44 | if (fxModule == null) return; 45 | 46 | if (!fxModule.isLoaded) 47 | { 48 | GUILayout.BeginVertical(); 49 | 50 | if (!vessel.mainBody.atmosphere) 51 | { 52 | GUILayout.Label("Current body does not have an atmosphere, FX are unloaded."); 53 | } 54 | else if (vessel.altitude > vessel.mainBody.atmosphereDepth) 55 | { 56 | GUILayout.Label("Ship is not in atmosphere, FX are unloaded."); 57 | } 58 | else 59 | { 60 | GUILayout.Label("FX are not loaded for the active vessel"); 61 | } 62 | 63 | GUILayout.Label("Not showing info and quick action sections"); 64 | GUILayout.EndVertical(); 65 | UnityEngine.GUI.DragWindow(); 66 | return; 67 | } 68 | 69 | if (fxModule.overridePhysics) 70 | { 71 | GUILayout.Label("Physics is overriden by " + fxModule.overrideData.overridenBy); 72 | if (EffectEditor.Instance.show) GUILayout.Label("Effect editor open."); 73 | } 74 | 75 | // info 76 | DrawInfo(vessel, fxModule); 77 | GUILayout.Space(40); 78 | 79 | // quick actions 80 | DrawQuickActions(fxModule); 81 | 82 | // end 83 | UnityEngine.GUI.DragWindow(); 84 | } 85 | 86 | void DrawInfo(Vessel vessel, AtmoFxModule fxModule) 87 | { 88 | GUILayout.BeginVertical(); 89 | GUILayout.Label("Info:"); 90 | 91 | GUILayout.Label($"All assets loaded? {AssetLoader.Instance.allAssetsLoaded}"); 92 | GUILayout.Label($"Current config is {fxModule.currentBody.bodyName}"); 93 | GUILayout.Label($"Active vessel is {vessel.vesselName}"); 94 | GUILayout.Label($"Vessel radius is {fxModule.fxVessel.vesselBoundRadius}"); 95 | if (!fxModule.overridePhysics) 96 | { 97 | GUILayout.Label($"Entry strength is {fxModule.GetEntryStrength()}"); 98 | GUILayout.Label($"Dynamic pressure [kPa] {vessel.dynamicPressurekPa}"); 99 | } 100 | 101 | GUILayout.EndVertical(); 102 | } 103 | 104 | void DrawSettings() 105 | { 106 | GUILayout.BeginVertical(); 107 | GUILayout.Label("Settings:"); 108 | GUILayout.Label("Fields that need a reload to update are marked with *"); 109 | 110 | // draw config fields 111 | foreach (string key in ModSettings.I.fields.Keys) 112 | { 113 | ModSettings.Field field = ModSettings.I.fields[key]; 114 | 115 | if (field.valueType == ModSettings.ValueType.Boolean) GuiUtils.DrawConfigFieldBool(key, ModSettings.I.fields); 116 | else if (field.valueType == ModSettings.ValueType.Float) GuiUtils.DrawConfigFieldFloat(key, ModSettings.I.fields); 117 | } 118 | 119 | if (GUILayout.Button("Save overrides to file")) SettingsManager.Instance.SaveModSettings(); 120 | 121 | GUILayout.EndVertical(); 122 | } 123 | 124 | void DrawQuickActions(AtmoFxModule fxModule) 125 | { 126 | GUILayout.BeginVertical(); 127 | GUILayout.Label("Quick actions:"); 128 | 129 | // check if at least a second has passed since last reload click 130 | bool canReload = (Time.realtimeSinceStartup - reloadBtnTime) > 1f; 131 | if (GUILayout.Button("Reload Vessel") && canReload) 132 | { 133 | fxModule.ReloadVessel(); 134 | reloadBtnTime = Time.realtimeSinceStartup; 135 | } 136 | if (GUILayout.Button($"Toggle effects {(tgl_EffectToggle ? "(TURN OFF)" : "(TURN ON)")}")) tgl_EffectToggle = !tgl_EffectToggle; 137 | if (GUILayout.Button($"Toggle debug vis {(fxModule.debugMode ? "(TURN OFF)" : "(TURN ON)")}")) fxModule.debugMode = !fxModule.debugMode; 138 | if (Versioning.IsDev && GUILayout.Button("Reload assetbundle")) AssetLoader.Instance.ReloadAssets(); 139 | 140 | GUILayout.EndVertical(); 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /Source/GUI/GuiUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | namespace Firefly.GUI 6 | { 7 | internal class GuiUtils 8 | { 9 | /// 10 | /// Holds a value and a text input field for it 11 | /// Used for stuff like the effect/particle editor to simplify making the parameter controls 12 | /// 13 | public class UiObjectInput 14 | { 15 | public string[] text; 16 | public object value; 17 | 18 | public UiObjectInput(object value, int textCount = 1) 19 | { 20 | this.text = new string[textCount]; 21 | this.value = value; 22 | } 23 | 24 | public T GetValue() 25 | { 26 | return (T)value; 27 | } 28 | 29 | public void Overwrite(object value) 30 | { 31 | this.value = value; 32 | 33 | // if the value is a floatpair, we need to set both values 34 | if (value is FloatPair pair) 35 | { 36 | this.text[0] = pair.x.ToString(); 37 | this.text[1] = pair.y.ToString(); 38 | } 39 | else 40 | { 41 | this.text[0] = value.ToString(); 42 | } 43 | } 44 | } 45 | 46 | /// 47 | /// Button which will ask for confirmation before doing something 48 | /// 49 | public class ConfirmingButton 50 | { 51 | public enum State 52 | { 53 | Normal, 54 | Confirming 55 | } 56 | 57 | public const string CONFIRM_LABEL = "Are you sure?"; 58 | 59 | public string normalLabel; 60 | public float timeout; 61 | 62 | string currentLabel; 63 | State state; 64 | float t; 65 | 66 | public ConfirmingButton(string normalLabel, float timeout = 4f) 67 | { 68 | this.normalLabel = normalLabel; 69 | this.timeout = timeout; 70 | UpdateState(State.Normal); 71 | } 72 | 73 | // note that this method also ticks the logic 74 | public bool Draw(float time, params GUILayoutOption[] options) 75 | { 76 | bool btn = GUILayout.Button(currentLabel, options); 77 | 78 | // if state is confirming, then tick the time and return the button state 79 | if (state == State.Confirming) 80 | { 81 | if ((time - t) > timeout || btn) 82 | { 83 | UpdateState(State.Normal); // reset state if too much time has passed or button has been pressed 84 | } 85 | 86 | return btn; 87 | } 88 | else 89 | { 90 | // if state is normal, then change label to confirmation and return false 91 | if (btn) UpdateState(State.Confirming, time); 92 | 93 | return false; 94 | } 95 | } 96 | 97 | void UpdateState(State newState, float time = 0f) 98 | { 99 | switch (newState) 100 | { 101 | case State.Normal: 102 | currentLabel = normalLabel; 103 | break; 104 | case State.Confirming: 105 | currentLabel = CONFIRM_LABEL; 106 | t = time; 107 | break; 108 | default: break; 109 | } 110 | 111 | state = newState; 112 | } 113 | } 114 | 115 | // draws a setting bool override field 116 | public static void DrawConfigFieldBool(string label, Dictionary tgl) 117 | { 118 | string needsReload = tgl[label].needsReload ? "*" : ""; 119 | 120 | tgl[label].value = GUILayout.Toggle((bool)tgl[label].value, label + needsReload); 121 | } 122 | 123 | // draws a setting float override field 124 | public static void DrawConfigFieldFloat(string label, Dictionary tgl) 125 | { 126 | string needsReload = tgl[label].needsReload ? "*" : ""; 127 | 128 | GUILayout.BeginHorizontal(); 129 | GUILayout.Label(label + needsReload); 130 | 131 | tgl[label].uiText = GUILayout.TextField(tgl[label].uiText); 132 | bool hasValue = float.TryParse(tgl[label].uiText, out float value); 133 | if (hasValue) tgl[label].value = value; 134 | 135 | GUILayout.EndHorizontal(); 136 | } 137 | 138 | // draws a labeled slider 139 | public static float LabelSlider(string label, float value, float startValue, float endValue) 140 | { 141 | GUILayout.BeginHorizontal(); 142 | GUILayout.Label(label); 143 | 144 | float v = GUILayout.HorizontalSlider(value, startValue, endValue); 145 | 146 | GUILayout.EndHorizontal(); 147 | 148 | return v; 149 | } 150 | 151 | // draws a float input field 152 | public static void DrawFloatInput(string label, ref UiObjectInput uiInput, params GUILayoutOption[] layoutOptions) 153 | { 154 | GUILayout.BeginHorizontal(layoutOptions); 155 | GUILayout.Label(label); 156 | 157 | uiInput.text[0] = GUILayout.TextField(uiInput.text[0]); 158 | bool hasValue = float.TryParse(uiInput.text[0], out float v); 159 | if (hasValue) uiInput.value = v; 160 | 161 | GUILayout.EndHorizontal(); 162 | } 163 | public static void DrawFloatInput(string label, ref string text, ref float value, params GUILayoutOption[] layoutOptions) 164 | { 165 | GUILayout.BeginHorizontal(layoutOptions); 166 | GUILayout.Label(label); 167 | 168 | text = GUILayout.TextField(text); 169 | bool hasValue = float.TryParse(text, out float v); 170 | if (hasValue) value = v; 171 | 172 | GUILayout.EndHorizontal(); 173 | } 174 | 175 | // draws a string input field 176 | public static void DrawStringInput(string label, ref string text, float maxFieldWidth = -1f, params GUILayoutOption[] layoutOptions) 177 | { 178 | GUILayout.BeginHorizontal(layoutOptions); 179 | GUILayout.Label(label); 180 | 181 | if (maxFieldWidth > 0f) 182 | { 183 | text = GUILayout.TextField(text, GUILayout.MaxWidth(maxFieldWidth)); 184 | } else 185 | { 186 | text = GUILayout.TextField(text); 187 | } 188 | 189 | GUILayout.EndHorizontal(); 190 | } 191 | 192 | // draws a boolean input field 193 | public static void DrawBoolInput(string label, ref bool val, params GUILayoutOption[] layoutOptions) 194 | { 195 | GUILayout.BeginHorizontal(layoutOptions); 196 | GUILayout.Label(label); 197 | 198 | val = GUILayout.Toggle(val, ""); 199 | 200 | GUILayout.EndHorizontal(); 201 | } 202 | 203 | // draws a float pair input field (2 float values) 204 | public static void DrawFloatPairInput(string label, ref UiObjectInput uiInput, params GUILayoutOption[] layoutOptions) 205 | { 206 | GUILayout.BeginHorizontal(layoutOptions); 207 | GUILayout.Label(label); 208 | 209 | FloatPair newValue = (FloatPair)uiInput.value; 210 | 211 | uiInput.text[0] = GUILayout.TextField(uiInput.text[0]); 212 | bool hasValue = float.TryParse(uiInput.text[0], out float v); 213 | if (hasValue) newValue.x = v; 214 | 215 | uiInput.text[1] = GUILayout.TextField(uiInput.text[1]); 216 | hasValue = float.TryParse(uiInput.text[1], out v); 217 | if (hasValue) newValue.y = v; 218 | 219 | uiInput.value = newValue; 220 | 221 | GUILayout.EndHorizontal(); 222 | } 223 | 224 | // gets rect point from mouse point 225 | public static bool GetRectPoint(Vector2 point, Rect rect, out Vector2 result) 226 | { 227 | if (rect.Contains(point)) 228 | { 229 | result = new Vector2( 230 | Mathf.Clamp(point.x - rect.xMin, 0f, rect.width), 231 | rect.width - Mathf.Clamp(point.y - rect.yMin, 0f, rect.height) 232 | ); 233 | 234 | return true; 235 | } 236 | 237 | result = Vector2.zero; 238 | return false; 239 | } 240 | 241 | // draws a button with a color 242 | // pix texture should be a 1x1 white texture 243 | public static bool DrawColorButton(string label, Texture2D pix, Color color) 244 | { 245 | GUILayout.BeginHorizontal(); 246 | 247 | GUILayout.Label(label); 248 | 249 | bool b = GUILayout.Button("", GUILayout.Width(60), GUILayout.Height(20)); 250 | Rect rect = GUILayoutUtility.GetLastRect(); 251 | rect = new Rect(rect.x + 4, rect.y + 4, rect.width - 8, rect.height - 8); 252 | UnityEngine.GUI.DrawTexture(rect, pix, ScaleMode.StretchToFill, false, 0f, color, 0f, 0f); 253 | 254 | GUILayout.EndHorizontal(); 255 | 256 | return b; 257 | } 258 | 259 | // draws a 1px thick white line with specified width 260 | public static void DrawHorizontalSeparator(float width) 261 | { 262 | Rect rect = GUILayoutUtility.GetRect(width, 1f, GUILayout.Width(width)); 263 | UnityEngine.GUI.DrawTexture(rect, Texture2D.whiteTexture); 264 | } 265 | 266 | // draws a 1px thick white line with specified height 267 | public static void DrawVerticalSeparator(float height) 268 | { 269 | Rect rect = GUILayoutUtility.GetRect(1f, height, GUILayout.Height(height)); 270 | UnityEngine.GUI.DrawTexture(rect, Texture2D.whiteTexture); 271 | } 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /Source/GUI/ParticleEditor.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.IO; 3 | 4 | namespace Firefly.GUI 5 | { 6 | class ParticleEditor : Window 7 | { 8 | public static ParticleEditor Instance { get; private set; } 9 | 10 | AtmoFxModule fxModule = null; 11 | 12 | string currentConfigName = ""; 13 | ParticleConfig currentConfig = null; 14 | 15 | // ui values 16 | Vector2 ui_configListPosition = Vector2.zero; 17 | 18 | bool ui_cfgIsActive = false; 19 | string ui_prefabName = ""; 20 | string ui_mainTexPath = ""; 21 | string ui_emissionTexPath = ""; 22 | GuiUtils.UiObjectInput ui_offset = new GuiUtils.UiObjectInput(0f); 23 | bool ui_useHalfOffset = false; 24 | GuiUtils.UiObjectInput ui_rateRange = new GuiUtils.UiObjectInput(new FloatPair(), 2); 25 | GuiUtils.UiObjectInput ui_lifetimeRange = new GuiUtils.UiObjectInput(new FloatPair(), 2); 26 | GuiUtils.UiObjectInput ui_velocityRange = new GuiUtils.UiObjectInput(new FloatPair(), 2); 27 | 28 | GuiUtils.ConfirmingButton ui_deleteButton = new GuiUtils.ConfirmingButton("Delete selected config"); 29 | GuiUtils.ConfirmingButton ui_saveButton = new GuiUtils.ConfirmingButton("Save all to file"); 30 | 31 | Popup ui_createPopup; 32 | 33 | public ParticleEditor() : base("Particle Editor") 34 | { 35 | windowRect = new Rect(900f, 100f, 600f, 300f); 36 | 37 | Instance = this; 38 | 39 | ui_createPopup = new Popup("Create from preset", new Vector2(300f, 100f), CreatePopupCallback, CreatePopupDraw); 40 | } 41 | 42 | public override void Draw(int id) 43 | { 44 | GUILayout.BeginVertical(); 45 | GUILayout.Label("Use the Effect Editor's sim sliders to make the particles show"); 46 | 47 | // split editor into 2 parts 48 | GUILayout.BeginHorizontal(); 49 | 50 | // draw left part 51 | DrawLeftEditor(); 52 | 53 | // draw right part 54 | DrawRightEditor(); 55 | 56 | // margin 57 | GUILayout.Space(20f); 58 | 59 | // end window 60 | GUILayout.EndHorizontal(); 61 | GUILayout.EndVertical(); 62 | UnityEngine.GUI.DragWindow(); 63 | } 64 | 65 | void DrawLeftEditor() 66 | { 67 | GUILayout.BeginVertical(); 68 | 69 | GUILayout.Label("Select a config:", GUILayout.Width(300f)); 70 | DrawConfigSelector(); 71 | 72 | GUILayout.Space(20f); 73 | 74 | if (GUILayout.Button("Create new config from preset", GUILayout.Width(300f))) 75 | { 76 | // initialize and show popup 77 | ui_createPopup.customData.Clear(); 78 | ui_createPopup.customData["listPosition"] = Vector2.zero; 79 | ui_createPopup.customData["newName"] = ""; 80 | ui_createPopup.windowRect.position = this.windowRect.position + new Vector2(0f, this.windowRect.height); // position below the window 81 | ui_createPopup.Show(); 82 | } 83 | if (ui_saveButton.Draw(Time.time, GUILayout.Width(300f))) 84 | { 85 | SaveAllToCfg(); 86 | } 87 | if (ui_deleteButton.Draw(Time.time, GUILayout.Width(300f))) 88 | { 89 | DeleteSelected(); 90 | } 91 | 92 | GUILayout.EndVertical(); 93 | } 94 | 95 | void DrawRightEditor() 96 | { 97 | GUILayout.BeginVertical(); 98 | 99 | DrawConfigEditor(); 100 | 101 | GUILayout.EndVertical(); 102 | } 103 | 104 | void DrawConfigSelector() 105 | { 106 | ui_configListPosition = GUILayout.BeginScrollView(ui_configListPosition, GUILayout.Width(300f)); 107 | 108 | foreach (string key in ConfigManager.Instance.particleConfigs.Keys) 109 | { 110 | if (GUILayout.Button(key)) 111 | { 112 | currentConfig = ConfigManager.Instance.particleConfigs[key]; 113 | currentConfigName = key; 114 | UpdateUiValues(); 115 | } 116 | } 117 | 118 | GUILayout.EndScrollView(); 119 | } 120 | 121 | void DrawConfigEditor() 122 | { 123 | if (currentConfig != null) 124 | { 125 | GUILayout.Label($"Current config: {currentConfigName}", GUILayout.Width(300f)); 126 | 127 | // draw all configuration options 128 | GuiUtils.DrawBoolInput("Is active", ref ui_cfgIsActive, GUILayout.Width(300f)); 129 | GuiUtils.DrawStringInput("Unity bundle prefab name", ref ui_prefabName, 300f, GUILayout.Width(300f)); 130 | GUILayout.Space(20f); 131 | GuiUtils.DrawStringInput("Main texture", ref ui_mainTexPath, 300f, GUILayout.Width(300f)); 132 | GuiUtils.DrawStringInput("Emission texture", ref ui_emissionTexPath, 300f, GUILayout.Width(300f)); 133 | GUILayout.Space(20f); 134 | GuiUtils.DrawFloatInput("Emitter offset", ref ui_offset, GUILayout.Width(300f)); 135 | GuiUtils.DrawBoolInput("Use half offset", ref ui_useHalfOffset, GUILayout.Width(300f)); 136 | GUILayout.Space(20f); 137 | GuiUtils.DrawFloatPairInput("Rate range", ref ui_rateRange, GUILayout.Width(300f)); 138 | GuiUtils.DrawFloatPairInput("Lifetime range", ref ui_lifetimeRange, GUILayout.Width(300f)); 139 | GuiUtils.DrawFloatPairInput("Velocity range", ref ui_velocityRange, GUILayout.Width(300f)); 140 | 141 | // saves everything to config and to ConfigManager 142 | if (GUILayout.Button("Apply")) 143 | { 144 | ApplyConfigValues(); 145 | ConfigManager.Instance.particleConfigs[currentConfigName] = currentConfig; 146 | fxModule?.ReloadVessel(); 147 | } 148 | } 149 | } 150 | 151 | private void CreatePopupDraw() 152 | { 153 | GUILayout.Label("Pick a preset particle system to create a new config from"); 154 | 155 | // if selected something, tell what 156 | if (ui_createPopup.customData.ContainsKey("selection")) 157 | GUILayout.Label($"Currently selected: {ui_createPopup.customData["selection"]}"); 158 | 159 | // selection list 160 | ui_createPopup.customData["listPosition"] = GUILayout.BeginScrollView((Vector2)ui_createPopup.customData["listPosition"], GUILayout.Width(300f)); 161 | foreach (string key in ConfigManager.Instance.particleConfigs.Keys) 162 | { 163 | if (GUILayout.Button(key)) 164 | { 165 | ui_createPopup.customData["selection"] = key; 166 | } 167 | } 168 | GUILayout.EndScrollView(); 169 | 170 | // new name 171 | string newConfigName = (string)ui_createPopup.customData["newName"]; 172 | GuiUtils.DrawStringInput("New config name", ref newConfigName); 173 | ui_createPopup.customData["newName"] = newConfigName; 174 | } 175 | 176 | private void CreatePopupCallback(Popup.CallbackType type) 177 | { 178 | // if pressed ok, create a new config from the selected preset 179 | if (type == Popup.CallbackType.Ok) 180 | { 181 | CreateFromPreset((string)ui_createPopup.customData["selection"], (string)ui_createPopup.customData["newName"]); 182 | } 183 | } 184 | 185 | // updates the ui values from the current config 186 | void UpdateUiValues() 187 | { 188 | ui_cfgIsActive = currentConfig.isActive; 189 | ui_prefabName = currentConfig.prefab; 190 | ui_mainTexPath = currentConfig.mainTexture; 191 | ui_emissionTexPath = currentConfig.emissionTexture; 192 | ui_offset.Overwrite(currentConfig.offset); 193 | ui_useHalfOffset = currentConfig.useHalfOffset; 194 | ui_rateRange.Overwrite(currentConfig.rate); 195 | ui_lifetimeRange.Overwrite(currentConfig.lifetime); 196 | ui_velocityRange.Overwrite(currentConfig.velocity); 197 | } 198 | 199 | // updates the current config with the ui values 200 | void ApplyConfigValues() 201 | { 202 | currentConfig.isActive = ui_cfgIsActive; 203 | currentConfig.prefab = ui_prefabName; 204 | currentConfig.mainTexture = ui_mainTexPath; 205 | currentConfig.emissionTexture = ui_emissionTexPath; 206 | currentConfig.offset = ui_offset.GetValue(); 207 | currentConfig.useHalfOffset = ui_useHalfOffset; 208 | currentConfig.rate = ui_rateRange.GetValue(); 209 | currentConfig.lifetime = ui_lifetimeRange.GetValue(); 210 | currentConfig.velocity = ui_velocityRange.GetValue(); 211 | 212 | ConfigManager.Instance.RefreshTextureList(); 213 | AssetLoader.Instance.ReloadAssets(); 214 | } 215 | 216 | void CreateFromPreset(string presetKey, string newName) 217 | { 218 | // create a new config from the preset 219 | ParticleConfig preset = new ParticleConfig(ConfigManager.Instance.particleConfigs[presetKey]); 220 | preset.name = newName; 221 | 222 | // add to configman 223 | ConfigManager.Instance.particleConfigs[newName] = preset; 224 | 225 | // set as current 226 | currentConfig = preset; 227 | currentConfigName = newName; 228 | UpdateUiValues(); 229 | } 230 | 231 | void DeleteSelected() 232 | { 233 | if (currentConfig == null) return; 234 | 235 | // remove from config manager 236 | ConfigManager.Instance.particleConfigs.Remove(currentConfigName); 237 | 238 | // reset 239 | currentConfig = null; 240 | currentConfigName = ""; 241 | ConfigManager.Instance.RefreshTextureList(); 242 | AssetLoader.Instance.ReloadAssets(); 243 | fxModule?.ReloadVessel(); 244 | } 245 | 246 | void SaveAllToCfg() 247 | { 248 | string path = Path.Combine(KSPUtil.ApplicationRootPath, ConfigManager.ParticleConfigPath); 249 | 250 | // create a dummy parent node 251 | ConfigNode parent = new ConfigNode("ATMOFX_PARTICLES"); 252 | 253 | // create the actual node 254 | ConfigNode node = new ConfigNode("ATMOFX_PARTICLES"); 255 | node.AddValue("name", ConfigManager.DefaultParticleNodeName); 256 | 257 | foreach (string key in ConfigManager.Instance.particleConfigs.Keys) 258 | { 259 | ParticleConfig config = ConfigManager.Instance.particleConfigs[key]; 260 | 261 | // create a separate node for each particle system 262 | ConfigNode configNode = new ConfigNode(config.name); 263 | config.SaveToNode(configNode); 264 | node.AddNode(configNode); 265 | } 266 | 267 | // add to parent and save 268 | parent.AddNode(node); 269 | parent.Save(path); 270 | 271 | ScreenMessages.PostScreenMessage("Saved all configs to file", 5f, ScreenMessageStyle.UPPER_CENTER); 272 | Logging.Log($"Saved particle config {ConfigManager.ParticleConfigPath}"); 273 | } 274 | 275 | public override void Show() 276 | { 277 | base.Show(); 278 | 279 | Vessel vessel = FlightGlobals.ActiveVessel; 280 | if (vessel == null) return; 281 | fxModule = vessel.FindVesselModuleImplementing(); 282 | } 283 | } 284 | } 285 | -------------------------------------------------------------------------------- /Source/GUI/Popup.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | 4 | namespace Firefly.GUI 5 | { 6 | class Popup : Window 7 | { 8 | public enum CallbackType 9 | { 10 | Ok, 11 | Cancel 12 | } 13 | 14 | public delegate void PopupCallback(CallbackType type); 15 | public delegate void PopupDraw(); 16 | 17 | public Dictionary customData = new Dictionary(); 18 | PopupCallback callback; 19 | PopupDraw draw; 20 | 21 | public Popup(string title, Vector2 org, PopupCallback callback, PopupDraw draw) : base("") 22 | { 23 | windowRect = new Rect(org.x, org.y, 300, 300); 24 | this.title = title; 25 | 26 | this.callback = callback; 27 | this.draw = draw; 28 | } 29 | 30 | public override void Draw(int id) 31 | { 32 | GUILayout.BeginVertical(); 33 | 34 | // draw additional stuff 35 | draw(); 36 | 37 | // draw controls 38 | GUILayout.BeginHorizontal(); 39 | if (GUILayout.Button("Cancel")) Cancel(); 40 | if (GUILayout.Button("Ok")) Ok(); 41 | GUILayout.EndHorizontal(); 42 | 43 | GUILayout.EndVertical(); 44 | UnityEngine.GUI.DragWindow(); 45 | } 46 | 47 | void Cancel() 48 | { 49 | Hide(); 50 | callback(CallbackType.Cancel); 51 | } 52 | 53 | void Ok() 54 | { 55 | Hide(); 56 | callback(CallbackType.Ok); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Source/GUI/StockEffectsWindow.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Firefly.GUI 4 | { 5 | internal class StockEffectsWindow : Window 6 | { 7 | public StockEffectsWindow() : base("Firefly Stock Effects Warning") 8 | { 9 | windowRect = new Rect(300, 100, 600, 50); 10 | } 11 | 12 | public override void Draw(int id) 13 | { 14 | GUILayout.BeginVertical(); 15 | 16 | GUILayout.Label("The mod detected that the \"Aero effect quality\" setting is set higher than minimal."); 17 | GUILayout.Label("This will make the stock effects mix with the ones from Firefly."); 18 | 19 | // draw controls 20 | GUILayout.BeginHorizontal(); 21 | if (GUILayout.Button("Fix problem")) FixProblem(); 22 | if (GUILayout.Button("Ignore")) Hide(); 23 | GUILayout.EndHorizontal(); 24 | 25 | GUILayout.EndVertical(); 26 | UnityEngine.GUI.DragWindow(); 27 | } 28 | 29 | /// 30 | /// Fix the problem by setting the Aero effect quality to minimal 31 | /// 32 | void FixProblem() 33 | { 34 | GameSettings.AERO_FX_QUALITY = 0; 35 | Hide(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Source/GUI/Window.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | 4 | namespace Firefly.GUI 5 | { 6 | class Window 7 | { 8 | public static List AllWindows = new List(); 9 | 10 | public Rect windowRect = new Rect(900f, 100f, 300f, 300f); 11 | public string title = "FireflyWindow"; 12 | public bool isGlobal = false; // if the window should be drawn even if the app is closed 13 | 14 | public bool show = false; 15 | int id; 16 | 17 | public Window(string title) 18 | { 19 | this.title = title; 20 | this.id = GetHashCode(); 21 | 22 | AllWindows.Add(this); 23 | } 24 | 25 | ~Window() 26 | { 27 | AllWindows.Remove(this); 28 | } 29 | 30 | public virtual void Show() 31 | { 32 | show = true; 33 | } 34 | 35 | public void RunGui() 36 | { 37 | if (!show) return; 38 | 39 | windowRect = GUILayout.Window(this.id, windowRect, Draw, title); 40 | } 41 | 42 | public virtual void Draw(int id) 43 | { 44 | UnityEngine.GUI.DragWindow(); 45 | } 46 | 47 | public virtual void Hide() 48 | { 49 | show = false; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Source/GUI/WindowManager.cs: -------------------------------------------------------------------------------- 1 | using KSP.UI.Screens; 2 | using UnityEngine; 3 | 4 | namespace Firefly.GUI 5 | { 6 | [KSPAddon(KSPAddon.Startup.Flight, false)] 7 | internal class WindowManager : MonoBehaviour 8 | { 9 | public static WindowManager Instance { get; private set; } 10 | 11 | ApplicationLauncherButton appButton = null; 12 | 13 | public bool uiHidden = false; 14 | public bool appToggle = false; 15 | 16 | // windows 17 | public FireflyWindow fireflyWindow; 18 | public EffectEditor effectEditor; 19 | public ParticleEditor particleEditor; 20 | public ErrorListWindow errorListWindow; 21 | public StockEffectsWindow stockEffectsWindow; 22 | 23 | public void Awake() 24 | { 25 | Instance = this; 26 | 27 | fireflyWindow = new FireflyWindow(); 28 | effectEditor = new EffectEditor(); 29 | particleEditor = new ParticleEditor(); 30 | errorListWindow = new ErrorListWindow(); 31 | stockEffectsWindow = new StockEffectsWindow(); 32 | } 33 | 34 | public void Start() 35 | { 36 | // only create the app if there are no serious errors 37 | if (ModLoadError.SeriousErrorCount < 1) 38 | { 39 | appButton = ApplicationLauncher.Instance.AddModApplication( 40 | (() => appToggle = true), 41 | (() => appToggle = false), 42 | null, null, null, null, 43 | ApplicationLauncher.AppScenes.FLIGHT, 44 | AssetLoader.Instance.iconTexture 45 | ); 46 | } 47 | 48 | GameEvents.onHideUI.Add(OnHideUi); 49 | GameEvents.onShowUI.Add(OnShowUi); 50 | 51 | if (GameSettings.AERO_FX_QUALITY > 0) 52 | { 53 | // inform users about conflicting effects when instantiating this class 54 | stockEffectsWindow.Show(); 55 | } 56 | } 57 | 58 | public void OnDestroy() 59 | { 60 | // remove everything associated with the thing 61 | if (appButton != null) ApplicationLauncher.Instance.RemoveModApplication(appButton); 62 | GameEvents.onHideUI.Remove(OnHideUi); 63 | GameEvents.onShowUI.Remove(OnShowUi); 64 | } 65 | 66 | void OnHideUi() 67 | { 68 | uiHidden = true; 69 | } 70 | 71 | void OnShowUi() 72 | { 73 | uiHidden = false; 74 | } 75 | 76 | public void OnGUI() 77 | { 78 | // if F2 or there's no active vessel dont draw anything 79 | if (uiHidden || FlightGlobals.ActiveVessel == null) return; 80 | 81 | // draw all windows 82 | for (int i = 0; i < Window.AllWindows.Count; i++) 83 | { 84 | Window window = Window.AllWindows[i]; 85 | 86 | // always draw global windows, otherwise check if the app is open 87 | if (window.isGlobal || appToggle) window.RunGui(); 88 | } 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Source/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyDescription("Firefly made by MirageDev, thunderchild, Knedlik, JonnyOThan")] 9 | [assembly: AssemblyCopyright("Copyright © MirageDev 2025")] 10 | [assembly: AssemblyTrademark("")] 11 | [assembly: AssemblyCulture("")] 12 | 13 | // Setting ComVisible to false makes the types in this assembly not visible 14 | // to COM components. If you need to access a type in this assembly from 15 | // COM, set the ComVisible attribute to true on that type. 16 | [assembly: ComVisible(false)] 17 | 18 | // The following GUID is for the ID of the typelib if this project is exposed to COM 19 | [assembly: Guid("0dd486f0-ef12-458b-b0e2-f74c7a90e36a")] 20 | -------------------------------------------------------------------------------- /Source/Properties/Firefly.version: -------------------------------------------------------------------------------- 1 | { 2 | "NAME": "Firefly", 3 | "URL": "https://github.com/M1rageDev/Firefly/releases/latest/download/Firefly.version", 4 | "DOWNLOAD": "https://github.com/M1rageDev/Firefly/releases/latest" 5 | } -------------------------------------------------------------------------------- /Source/Properties/Firefly.version.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1.0.3 5 | 6 | -------------------------------------------------------------------------------- /Source/Properties/Firefly.version.props.versiontemplate: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | @VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@ 5 | 6 | -------------------------------------------------------------------------------- /Source/SettingsManager.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using UnityEngine; 4 | 5 | namespace Firefly 6 | { 7 | public class ModSettings 8 | { 9 | public static ModSettings I { get; private set; } 10 | 11 | public enum ValueType 12 | { 13 | Boolean, 14 | Float, 15 | Float3 16 | } 17 | 18 | public class Field 19 | { 20 | public object value; 21 | public ValueType valueType; 22 | 23 | public bool needsReload; 24 | 25 | public string uiText; 26 | 27 | public Field(object value, ValueType valueType, bool needsReload) 28 | { 29 | this.value = value; 30 | this.valueType = valueType; 31 | this.needsReload = needsReload; 32 | 33 | this.uiText = value.ToString(); 34 | } 35 | } 36 | 37 | public Dictionary fields; 38 | 39 | public ModSettings() 40 | { 41 | this.fields = new Dictionary(); 42 | 43 | I = this; 44 | } 45 | 46 | public static ModSettings CreateDefault() 47 | { 48 | ModSettings ms = new ModSettings 49 | { 50 | fields = new Dictionary() 51 | { 52 | { "hdr_override", new Field(true, ValueType.Boolean, false) }, 53 | { "disable_bowshock", new Field(false, ValueType.Boolean, false) }, 54 | { "disable_particles", new Field(false, ValueType.Boolean, true) }, 55 | { "strength_base", new Field(2800f, ValueType.Float, false) }, 56 | { "length_mult", new Field(1f, ValueType.Float, false) } 57 | } 58 | }; 59 | 60 | return ms; 61 | } 62 | 63 | /// 64 | /// Saves every field to a ConfigNode 65 | /// 66 | public void SaveToNode(ref ConfigNode node) 67 | { 68 | for (int i = 0; i < fields.Count; i++) 69 | { 70 | KeyValuePair elem = fields.ElementAt(i); 71 | object val = elem.Value.value; 72 | 73 | // special case for float3 74 | if (elem.Value.valueType == ValueType.Float3) 75 | { 76 | Vector3 vec = (Vector3)val; 77 | 78 | val = string.Join(" ", vec.x, vec.y, vec.z); 79 | } 80 | 81 | // save 82 | node.AddValue(elem.Key, val); 83 | 84 | Logging.Log($"ModSettings - Saved {elem.Key} to node as {val}"); 85 | } 86 | } 87 | 88 | public override string ToString() 89 | { 90 | string result = ""; 91 | 92 | for (int i = 0; i < fields.Count; i++) 93 | { 94 | KeyValuePair element = fields.ElementAt(i); 95 | result += $"<{element.Value.valueType}>{element.Key}"; 96 | result += $": {element.Value.value}"; 97 | result += "\n"; 98 | } 99 | 100 | return result; 101 | } 102 | 103 | /// 104 | /// Gets the type of a field value 105 | /// 106 | public ValueType? GetFieldType(string key) 107 | { 108 | if (fields.ContainsKey(key)) 109 | { 110 | return fields[key].valueType; 111 | } 112 | 113 | return null; 114 | } 115 | 116 | /// 117 | /// Gets a field from the dict specified by a key 118 | /// 119 | public Field GetField(string key) 120 | { 121 | if (fields.ContainsKey(key)) 122 | { 123 | return fields[key]; 124 | } 125 | 126 | return null; 127 | } 128 | 129 | // custom indexer 130 | public object this[string i] 131 | { 132 | get => fields[i].value; 133 | set => fields[i].value = value; 134 | } 135 | } 136 | 137 | /// 138 | /// Class which manages the entire settings system. It is initialized by the ConfigManager. 139 | /// 140 | internal class SettingsManager 141 | { 142 | public static SettingsManager Instance { get; private set; } 143 | public const string SettingsPath = "GameData/Firefly/ModSettings.cfg"; 144 | 145 | public ModSettings modSettings = ModSettings.CreateDefault(); 146 | 147 | public SettingsManager() 148 | { 149 | Instance = this; 150 | 151 | Logging.Log("Initialized SettingsManager"); 152 | } 153 | 154 | /// 155 | /// Saves the mod setting overrides 156 | /// 157 | public void SaveModSettings() 158 | { 159 | Logging.Log("Saving mod settings"); 160 | 161 | // create a parent node 162 | ConfigNode parent = new ConfigNode("ATMOFX_SETTINGS"); 163 | 164 | // create the node 165 | ConfigNode node = new ConfigNode("ATMOFX_SETTINGS"); 166 | 167 | modSettings.SaveToNode(ref node); 168 | 169 | // add to parent and save 170 | parent.AddNode(node); 171 | parent.Save(KSPUtil.ApplicationRootPath + SettingsPath); 172 | } 173 | 174 | /// 175 | /// Loads the mod settings 176 | /// 177 | public void LoadModSettings() 178 | { 179 | // load settings 180 | ConfigNode[] settingsNodes = GameDatabase.Instance.GetConfigNodes("ATMOFX_SETTINGS"); 181 | modSettings = ModSettings.CreateDefault(); 182 | 183 | if (settingsNodes.Length < 1) 184 | { 185 | // we don't have any saved settings or the user deleted the cfg file 186 | Logging.Log("Using default mod settings"); 187 | return; 188 | } 189 | 190 | ConfigNode settingsNode = settingsNodes[0]; 191 | 192 | // load the actual stuff from the ConfigNode 193 | bool isFormatted = true; 194 | for (int i = 0; i < modSettings.fields.Count; i++) 195 | { 196 | KeyValuePair e = modSettings.fields.ElementAt(i); 197 | 198 | modSettings[e.Key] = ReadSettingsField(settingsNode, e.Key, ref isFormatted); 199 | } 200 | 201 | if (!isFormatted) 202 | { 203 | Logging.Log("Settings cfg formatted incorrectly"); 204 | modSettings = ModSettings.CreateDefault(); 205 | } 206 | 207 | Logging.Log("Loaded Mod Settings: \n" + modSettings.ToString()); 208 | } 209 | 210 | /// 211 | /// Reads one boolean value from a node 212 | /// 213 | object ReadSettingsField(ConfigNode node, string field, ref bool isFormatted) 214 | { 215 | string value = node.GetValue(field); 216 | ModSettings.ValueType? type = modSettings.GetFieldType(field); 217 | 218 | if (value == null) 219 | { 220 | isFormatted = false; 221 | return null; 222 | } 223 | 224 | bool success = false; 225 | object result = default; 226 | switch (type) 227 | { 228 | case ModSettings.ValueType.Boolean: 229 | bool result_bool; 230 | success = Utils.EvaluateBool(value, out result_bool); 231 | result = result_bool; 232 | break; 233 | case ModSettings.ValueType.Float: 234 | float result_float; 235 | success = Utils.EvaluateFloat(value, out result_float); 236 | result = result_float; 237 | break; 238 | case ModSettings.ValueType.Float3: 239 | Vector3 result_float3; 240 | success = Utils.EvaluateFloat3(value, out result_float3); 241 | result = result_float3; 242 | break; 243 | default: break; 244 | } 245 | 246 | isFormatted = isFormatted && success; 247 | 248 | return result; 249 | } 250 | } 251 | } 252 | -------------------------------------------------------------------------------- /Source/Utils.cs: -------------------------------------------------------------------------------- 1 | using Steamworks; 2 | using System.Linq; 3 | using UnityEngine; 4 | 5 | namespace Firefly 6 | { 7 | public class ModLoadError 8 | { 9 | public static string BadConfigAdvice = "Check if it has all the required values, and if it's formatted correctly."; 10 | public static string OutdatedConfigAdvice = "The config is outdated, this is likely caused by a planet pack author not having updated their configs to the latest standard."; 11 | public static string OutdatedFireflyAdvice = "The config is made for a newer version of Firefly, please update Firefly to the latest version."; 12 | 13 | public static int SeriousErrorCount = 0; 14 | 15 | public enum ProbableCause 16 | { 17 | IncorrectInstall, 18 | WrongVersionConfig, 19 | BadConfig, 20 | Other 21 | } 22 | 23 | public ProbableCause cause = ProbableCause.Other; 24 | public bool isSerious = false; 25 | public string sourcePath = ""; 26 | public string description = ""; 27 | 28 | public ModLoadError(ProbableCause cause, bool isSerious, string sourcePath, string description) 29 | { 30 | this.cause = cause; 31 | this.isSerious = isSerious; 32 | this.sourcePath = sourcePath; 33 | this.description = description; 34 | 35 | if (isSerious) SeriousErrorCount++; 36 | } 37 | } 38 | 39 | public struct FloatPair 40 | { 41 | public float x; 42 | public float y; 43 | 44 | public FloatPair(float x, float y) 45 | { 46 | this.x = x; 47 | this.y = y; 48 | } 49 | 50 | public override string ToString() 51 | { 52 | return x + " " + y; 53 | } 54 | } 55 | 56 | public static class AtmoFxLayers 57 | { 58 | public const int Spacecraft = 0; 59 | public const int Fx = 23; 60 | } 61 | 62 | public class Logging 63 | { 64 | public const string Prefix = "[Firefly] "; 65 | 66 | public static void Log(object message) 67 | { 68 | Debug.Log(Prefix + message); 69 | } 70 | } 71 | 72 | public class HDRColor 73 | { 74 | public Color baseColor; 75 | public Color hdr; 76 | public float intensity; 77 | 78 | public bool hasValue; 79 | 80 | public HDRColor(Color sdri) 81 | { 82 | baseColor = sdri; 83 | hdr = Utils.SDRI_To_HDR(sdri); 84 | intensity = sdri.a; 85 | } 86 | 87 | public string SDRIString() 88 | { 89 | return $"{Mathf.RoundToInt(baseColor.r * 255f)} {Mathf.RoundToInt(baseColor.g * 255f)} {Mathf.RoundToInt(baseColor.b * 255f)} {baseColor.a}"; 90 | } 91 | 92 | public static implicit operator Color(HDRColor x) 93 | { 94 | return x.hdr; 95 | } 96 | } 97 | 98 | public static class Utils 99 | { 100 | // parses a float 101 | public static bool EvaluateFloat(string text, out float val) 102 | { 103 | return float.TryParse(text, out val); 104 | } 105 | 106 | // parses an int 107 | public static bool EvaluateInt(string text, out int val) 108 | { 109 | return int.TryParse(text, out val); 110 | } 111 | 112 | // parses a boolean 113 | public static bool EvaluateBool(string text, out bool val) 114 | { 115 | return bool.TryParse(text.ToLower(), out val); 116 | } 117 | 118 | // parses a float pair 119 | public static bool EvaluateFloatPair(string text, out FloatPair val) 120 | { 121 | bool isFormatted = true; 122 | val = new FloatPair(0f, 0f); 123 | 124 | string[] channels = text.Split(' '); 125 | if (channels.Length < 2) return false; 126 | 127 | // evaluate the values 128 | isFormatted = isFormatted && EvaluateFloat(channels[0], out val.x); 129 | isFormatted = isFormatted && EvaluateFloat(channels[1], out val.y); 130 | 131 | return isFormatted; 132 | } 133 | 134 | // parses a vector3 135 | public static bool EvaluateFloat3(string text, out Vector3 val) 136 | { 137 | bool isFormatted = true; 138 | val = Vector3.zero; 139 | 140 | string[] channels = text.Split(' '); 141 | if (channels.Length < 3) return false; 142 | 143 | // evaluate the values 144 | isFormatted = isFormatted && EvaluateFloat(channels[0], out val.x); 145 | isFormatted = isFormatted && EvaluateFloat(channels[1], out val.y); 146 | isFormatted = isFormatted && EvaluateFloat(channels[2], out val.z); 147 | 148 | return isFormatted; 149 | } 150 | 151 | // converts an SDRI color (I stored in alpha) to an HDR color 152 | public static Color SDRI_To_HDR(Color sdri) 153 | { 154 | float factor = Mathf.Pow(2f, sdri.a); 155 | return new Color(sdri.r * factor, sdri.g * factor, sdri.b * factor); 156 | } 157 | 158 | // converts an SDRI color to an HDR color 159 | public static Color SDRI_To_HDR(float r, float g, float b, float i) 160 | { 161 | float factor = Mathf.Pow(2f, i); 162 | return new Color(r * factor, g * factor, b * factor); 163 | } 164 | 165 | // parses an HDR color 166 | public static bool EvaluateColorHDR(string text, out Color val, out Color sdr) 167 | { 168 | bool isFormatted = true; 169 | val = Color.magenta; 170 | sdr = Color.magenta; 171 | 172 | string[] channels = text.Split(' '); 173 | if (channels.Length < 4) return false; 174 | 175 | // evaluate the values 176 | float r = 0f; 177 | float g = 0f; 178 | float b = 0f; 179 | float i = 0f; 180 | isFormatted = isFormatted && EvaluateFloat(channels[0], out r); 181 | isFormatted = isFormatted && EvaluateFloat(channels[1], out g); 182 | isFormatted = isFormatted && EvaluateFloat(channels[2], out b); 183 | isFormatted = isFormatted && EvaluateFloat(channels[3], out i); 184 | 185 | // divide by 255 to convert into 0-1 range 186 | r /= 255f; 187 | g /= 255f; 188 | b /= 255f; 189 | 190 | val = SDRI_To_HDR(r, g, b, i); 191 | sdr = new Color(r, g, b, i); 192 | 193 | return isFormatted; 194 | } 195 | 196 | /// 197 | /// Returns the cfg name from a part.partInfo.name field 198 | /// 199 | public static string GetPartCfgName(string name) 200 | { 201 | return name.Replace('.', '_'); 202 | } 203 | 204 | /// 205 | /// Is part legible for bound calculations? 206 | /// 207 | public static bool IsPartBoundCompatible(Part part) 208 | { 209 | return IsPartCompatible(part) && !( 210 | part.Modules.Contains("ModuleParachute") 211 | ); 212 | } 213 | 214 | /// 215 | /// Is part legible for fx envelope calculations? 216 | /// 217 | public static bool IsPartCompatible(Part part) 218 | { 219 | return !( 220 | part.Modules.Contains("ModuleConformalDecal") || 221 | part.Modules.Contains("ModuleConformalFlag") || 222 | part.Modules.Contains("ModuleConformalText") || 223 | part.name.Contains("RadialDrill") // TODO: Actually fix this, instead of making a workaround like this 224 | ); 225 | } 226 | 227 | /// 228 | /// Landing gear have flare meshes for some reason, this function checks if a mesh is a flare or not 229 | /// 230 | public static bool CheckWheelFlareModel(Part part, string model) 231 | { 232 | bool isFlare = string.Equals(model, "flare", System.StringComparison.OrdinalIgnoreCase); 233 | bool isWheel = part.HasModuleImplementing(); 234 | 235 | return isFlare && isWheel; 236 | } 237 | 238 | /// 239 | /// Check if a model's layer is incorrect 240 | /// 241 | public static bool CheckLayerModel(Transform model) 242 | { 243 | return ( 244 | model.gameObject.layer == 1 245 | ); 246 | } 247 | 248 | public static Vector3 VectorDivide(Vector3 a, Vector3 b) 249 | { 250 | return new Vector3(a.x / b.x, a.y / b.y, a.z / b.z); 251 | } 252 | 253 | // note - the output vector is actually a result of (1 / result), to make the shader code use multiplication instead of division 254 | public static Vector3 GetModelEnvelopeScale(Part part, Transform model) 255 | { 256 | if (part.name.Contains("GrapplingDevice") || part.name.Contains("smallClaw")) 257 | { 258 | return VectorDivide(Vector3.one, model.localScale); 259 | } 260 | else 261 | { 262 | return VectorDivide(Vector3.one, model.lossyScale); 263 | } 264 | } 265 | 266 | public static Transform[] FindTaggedTransforms(Part part) 267 | { 268 | // finds transforms tagged with Icon_Hidden and only those with atmofx_envelope in their name 269 | return part.FindModelTransformsWithTag("Icon_Hidden") 270 | .Where(x => x.name.Contains("atmofx_envelope")).ToArray(); 271 | } 272 | 273 | public static Vector3 ConvertNodeToModel(Vector3 node, Part part, Transform model) 274 | { 275 | // convert to world-space 276 | Vector3 worldSpace = part.transform.TransformPoint(node); 277 | 278 | // convert to model-space 279 | return model.transform.InverseTransformPoint(worldSpace); 280 | } 281 | 282 | /// 283 | /// Returns the angle of attack of a vessel 284 | /// Technically this is not the angle of attack, but it's good enough for this project 285 | /// 286 | public static float GetAngleOfAttack(Vessel vessel) 287 | { 288 | Transform transform = vessel.GetTransform(); 289 | Vector3 velocity = vessel.srf_velocity.normalized; 290 | 291 | float angle = Vector3.Angle(transform.forward, velocity) * Mathf.Deg2Rad; 292 | 293 | return angle; 294 | } 295 | 296 | /// 297 | /// Returns the corners of a given Bounds object 298 | /// 299 | public static Vector3[] GetBoundCorners(Bounds bounds) 300 | { 301 | Vector3 center = bounds.center; 302 | float x = bounds.extents.x; 303 | float y = bounds.extents.y; 304 | float z = bounds.extents.z; 305 | 306 | Vector3[] corners = new Vector3[8]; 307 | 308 | corners[0] = center + new Vector3(x, y, z); 309 | corners[1] = center + new Vector3(x, y, -z); 310 | corners[2] = center + new Vector3(-x, y, z); 311 | corners[3] = center + new Vector3(-x, y, -z); 312 | 313 | corners[4] = center + new Vector3(x, -y, z); 314 | corners[5] = center + new Vector3(x, -y, -z); 315 | corners[6] = center + new Vector3(-x, -y, z); 316 | corners[7] = center + new Vector3(-x, -y, -z); 317 | 318 | return corners; 319 | } 320 | 321 | /// 322 | /// Returns a Color from HSV values 323 | /// 324 | public static Color ColorHSV(float h, float s, float v) 325 | { 326 | return Color.HSVToRGB(h, s, v); 327 | } 328 | 329 | /// 330 | /// Returns HSV from a color 331 | /// 332 | public static void ColorHSV(Color c, out float h, out float s, out float v) 333 | { 334 | Color.RGBToHSV(c, out h, out s, out v); 335 | } 336 | } 337 | 338 | internal class TextureUtils 339 | { 340 | public static Texture2D GenerateHueTexture(int width, int height) 341 | { 342 | Texture2D tex = new Texture2D(width, height, TextureFormat.ARGB32, false, false); 343 | 344 | Color c; 345 | for (int x = 0; x < width; x++) 346 | { 347 | c = Utils.ColorHSV((float)x / (float)width, 1f, 1f); 348 | for (int y = 0; y < height; y++) 349 | { 350 | tex.SetPixel(x, y, c); 351 | } 352 | } 353 | 354 | tex.Apply(); 355 | return tex; 356 | } 357 | 358 | public static Texture2D GenerateHueTexture(int width, int height, float s, float v) 359 | { 360 | Texture2D tex = new Texture2D(width, height, TextureFormat.ARGB32, false, false); 361 | 362 | Color c; 363 | for (int x = 0; x < width; x++) 364 | { 365 | c = Utils.ColorHSV((float)x / (float)width, s, v); 366 | for (int y = 0; y < height; y++) 367 | { 368 | tex.SetPixel(x, y, c); 369 | } 370 | } 371 | 372 | tex.Apply(); 373 | return tex; 374 | } 375 | 376 | public static Texture2D GenerateGradientTexture(int width, int height, Color c1, Color c2) 377 | { 378 | Texture2D tex = new Texture2D(width, height, TextureFormat.ARGB32, false, false); 379 | 380 | Color c; 381 | for (int x = 0; x < width; x++) 382 | { 383 | c = Color.Lerp(c1, c2, (float)x / (float)width); 384 | for (int y = 0; y < height; y++) 385 | { 386 | tex.SetPixel(x, y, c); 387 | } 388 | } 389 | 390 | tex.Apply(); 391 | return tex; 392 | } 393 | 394 | public static Texture2D GenerateGradientTexture(int width, int height, float hue) 395 | { 396 | Texture2D tex = new Texture2D(width, height, TextureFormat.ARGB32, false, false); 397 | 398 | Color c; 399 | for (int x = 0; x < width; x++) 400 | { 401 | for (int y = 0; y < height; y++) 402 | { 403 | c = Utils.ColorHSV(hue, (float)x / (float)width, (float)y / (float)height); 404 | tex.SetPixel(x, y, c); 405 | } 406 | } 407 | 408 | tex.Apply(); 409 | return tex; 410 | } 411 | 412 | public static Texture2D GenerateColorTexture(int width, int height, Color c) 413 | { 414 | Texture2D tex = new Texture2D(width, height, TextureFormat.ARGB32, false, false); 415 | 416 | for (int x = 0; x < width; x++) 417 | { 418 | for (int y = 0; y < height; y++) 419 | { 420 | tex.SetPixel(x, y, c); 421 | } 422 | } 423 | 424 | tex.Apply(); 425 | return tex; 426 | } 427 | 428 | public static Texture2D GenerateSelectorTexture(int width, int height, int border, Color insideColor, Color color) 429 | { 430 | Texture2D tex = new Texture2D(width, height, TextureFormat.ARGB32, false, false); 431 | 432 | Color c; 433 | for (int x = 0; x < width; x++) 434 | { 435 | for (int y = 0; y < height; y++) 436 | { 437 | if (x < border || x > width - 1 - border) c = color; 438 | else if (y < border || y > height - 1 - border) c = color; 439 | else c = insideColor; 440 | 441 | tex.SetPixel(x, y, c); 442 | } 443 | } 444 | 445 | tex.Apply(); 446 | return tex; 447 | } 448 | } 449 | } 450 | -------------------------------------------------------------------------------- /Source/Versioning.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Reflection; 3 | 4 | namespace Firefly 5 | { 6 | public class Versioning 7 | { 8 | public static bool IsDev = false; 9 | 10 | public static int ConfigVersion = 5; 11 | 12 | public static string VersionAuthor(object caller) 13 | { 14 | AssemblyDescriptionAttribute attribute = caller.GetType().Assembly 15 | .GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false) 16 | .OfType() 17 | .FirstOrDefault(); 18 | 19 | return attribute.Description; 20 | } 21 | public static string Version(object caller) 22 | { 23 | return caller.GetType().Assembly.GetName().Version.ToString(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Unity/.gitignore: -------------------------------------------------------------------------------- 1 | # This .gitignore file should be placed at the root of your Unity project directory 2 | # 3 | # Get latest from https://github.com/github/gitignore/blob/main/Unity.gitignore 4 | # 5 | /[Ll]ibrary/ 6 | /[Tt]emp/ 7 | /[Oo]bj/ 8 | /[Bb]uild/ 9 | /[Bb]uilds/ 10 | /[Ll]ogs/ 11 | /[Uu]ser[Ss]ettings/ 12 | 13 | # Visual Studio cache directory 14 | .vs/ 15 | 16 | # Gradle cache directory 17 | .gradle/ 18 | 19 | # Autogenerated VS/MD/Consulo solution and project files 20 | ExportedObj/ 21 | .consulo/ 22 | *.csproj 23 | *.unityproj 24 | *.sln 25 | *.suo 26 | *.tmp 27 | *.user 28 | *.userprefs 29 | *.pidb 30 | *.booproj 31 | *.svd 32 | *.pdb 33 | *.mdb 34 | *.opendb 35 | *.VC.db 36 | 37 | # Unity3D generated meta files 38 | *.pidb.meta 39 | *.pdb.meta 40 | *.mdb.meta 41 | 42 | # Unity3D generated file on crash reports 43 | sysinfo.txt 44 | 45 | # My stuff 46 | /[Aa]ssets/Experimental/ 47 | /[Aa]ssets/Experimental.meta 48 | 49 | /[Aa]ssets/PartTools/ 50 | /[Aa]ssets/PartTools.meta 51 | 52 | /[Aa]ssets/Plugins/ 53 | /[Aa]ssets/Plugins.meta 54 | 55 | /[Aa]ssets/XML/ 56 | /[Aa]ssets/XML.meta 57 | 58 | /[Aa]ssets/TestAssets/ 59 | /[Aa]ssets/TestAssets.meta 60 | 61 | /[Aa]ssets/TextMesh Pro/ 62 | /[Aa]ssets/TextMesh Pro.meta 63 | 64 | /[Aa]ssets/SquadCore/ 65 | /[Aa]ssets/SquadCore.meta 66 | 67 | /[Aa]ssets/Scenes/ 68 | /[Aa]ssets/Scenes.meta 69 | 70 | /[Aa]ssets/Scripts/ 71 | /[Aa]ssets/Scripts.meta 72 | 73 | /[Aa]ssets/Editor/ 74 | /[Aa]ssets/Editor.meta 75 | 76 | /[Aa]ssets/BodyColorAsset.* 77 | /[Aa]ssets/Reentry RT.* 78 | /AssetBundles/ 79 | /ProjectSettings/ 80 | /Packages/ 81 | /PartTools.cfg 82 | -------------------------------------------------------------------------------- /Unity/Assets/Firefly/Materials/Chunk.mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 6 6 | m_ObjectHideFlags: 0 7 | m_CorrespondingSourceObject: {fileID: 0} 8 | m_PrefabInstance: {fileID: 0} 9 | m_PrefabAsset: {fileID: 0} 10 | m_Name: Chunk 11 | m_Shader: {fileID: 4800000, guid: 52287257c00b14843b36065f98791b82, type: 3} 12 | m_ShaderKeywords: _ALPHABLEND_ON _EMISSION 13 | m_LightmapFlags: 0 14 | m_EnableInstancingVariants: 0 15 | m_DoubleSidedGI: 0 16 | m_CustomRenderQueue: -1 17 | stringTagMap: {} 18 | disabledShaderPasses: [] 19 | m_SavedProperties: 20 | serializedVersion: 3 21 | m_TexEnvs: 22 | - _AirstreamTex: 23 | m_Texture: {fileID: 8400000, guid: 2dfe58f43e17b8d4ead11de3a11ed275, type: 2} 24 | m_Scale: {x: 1, y: 1} 25 | m_Offset: {x: 0, y: 0} 26 | - _BumpMap: 27 | m_Texture: {fileID: 0} 28 | m_Scale: {x: 1, y: 1} 29 | m_Offset: {x: 0, y: 0} 30 | - _DetailAlbedoMap: 31 | m_Texture: {fileID: 0} 32 | m_Scale: {x: 1, y: 1} 33 | m_Offset: {x: 0, y: 0} 34 | - _DetailMask: 35 | m_Texture: {fileID: 0} 36 | m_Scale: {x: 1, y: 1} 37 | m_Offset: {x: 0, y: 0} 38 | - _DetailNormalMap: 39 | m_Texture: {fileID: 0} 40 | m_Scale: {x: 1, y: 1} 41 | m_Offset: {x: 0, y: 0} 42 | - _EmissionMap: 43 | m_Texture: {fileID: 0} 44 | m_Scale: {x: 1, y: 1} 45 | m_Offset: {x: 0, y: 0} 46 | - _MainTex: 47 | m_Texture: {fileID: 0} 48 | m_Scale: {x: 1, y: 1} 49 | m_Offset: {x: 0, y: 0} 50 | - _MetallicGlossMap: 51 | m_Texture: {fileID: 0} 52 | m_Scale: {x: 1, y: 1} 53 | m_Offset: {x: 0, y: 0} 54 | - _OcclusionMap: 55 | m_Texture: {fileID: 0} 56 | m_Scale: {x: 1, y: 1} 57 | m_Offset: {x: 0, y: 0} 58 | - _ParallaxMap: 59 | m_Texture: {fileID: 0} 60 | m_Scale: {x: 1, y: 1} 61 | m_Offset: {x: 0, y: 0} 62 | m_Floats: 63 | - _AirstreamBlending: 0 64 | - _BlendOp: 0 65 | - _Blending: 1 66 | - _BumpScale: 1 67 | - _CameraFadingEnabled: 0 68 | - _CameraFarFadeDistance: 2 69 | - _CameraNearFadeDistance: 1 70 | - _ColorMode: 0 71 | - _Cull: 0 72 | - _Cutoff: 0.5 73 | - _DetailNormalMapScale: 1 74 | - _DistortionBlend: 0.5 75 | - _DistortionEnabled: 0 76 | - _DistortionStrength: 1 77 | - _DistortionStrengthScaled: 0 78 | - _DstBlend: 10 79 | - _EmissionEnabled: 1 80 | - _FlipbookMode: 0 81 | - _GlossMapScale: 1 82 | - _Glossiness: 0.5 83 | - _GlossyReflections: 1 84 | - _LightingEnabled: 0 85 | - _Metallic: 0 86 | - _Mode: 2 87 | - _OcclusionStrength: 1 88 | - _Parallax: 0.02 89 | - _SmoothnessTextureChannel: 0 90 | - _SoftParticlesEnabled: 0 91 | - _SoftParticlesFarFadeDistance: 1 92 | - _SoftParticlesNearFadeDistance: 0 93 | - _SpecularHighlights: 1 94 | - _SrcBlend: 5 95 | - _UVSec: 0 96 | - _ZWrite: 0 97 | m_Colors: 98 | - _CameraFadeParams: {r: 0, g: Infinity, b: 0, a: 0} 99 | - _Color: {r: 1, g: 1, b: 1, a: 1} 100 | - _ColorAddSubDiff: {r: 1, g: 0, b: 0, a: 0} 101 | - _EmissionColor: {r: 1.1345841, g: 1.1345841, b: 1.1345841, a: 1} 102 | - _SoftParticleFadeParams: {r: 0, g: 0, b: 0, a: 0} 103 | -------------------------------------------------------------------------------- /Unity/Assets/Firefly/Materials/ChunkAlternate.mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 6 6 | m_ObjectHideFlags: 0 7 | m_CorrespondingSourceObject: {fileID: 0} 8 | m_PrefabInstance: {fileID: 0} 9 | m_PrefabAsset: {fileID: 0} 10 | m_Name: ChunkAlternate 11 | m_Shader: {fileID: 4800000, guid: 52287257c00b14843b36065f98791b82, type: 3} 12 | m_ShaderKeywords: _ALPHABLEND_ON 13 | m_LightmapFlags: 0 14 | m_EnableInstancingVariants: 0 15 | m_DoubleSidedGI: 0 16 | m_CustomRenderQueue: -1 17 | stringTagMap: {} 18 | disabledShaderPasses: [] 19 | m_SavedProperties: 20 | serializedVersion: 3 21 | m_TexEnvs: 22 | - _AirstreamTex: 23 | m_Texture: {fileID: 8400000, guid: 2dfe58f43e17b8d4ead11de3a11ed275, type: 2} 24 | m_Scale: {x: 1, y: 1} 25 | m_Offset: {x: 0, y: 0} 26 | - _BumpMap: 27 | m_Texture: {fileID: 0} 28 | m_Scale: {x: 1, y: 1} 29 | m_Offset: {x: 0, y: 0} 30 | - _DetailAlbedoMap: 31 | m_Texture: {fileID: 0} 32 | m_Scale: {x: 1, y: 1} 33 | m_Offset: {x: 0, y: 0} 34 | - _DetailMask: 35 | m_Texture: {fileID: 0} 36 | m_Scale: {x: 1, y: 1} 37 | m_Offset: {x: 0, y: 0} 38 | - _DetailNormalMap: 39 | m_Texture: {fileID: 0} 40 | m_Scale: {x: 1, y: 1} 41 | m_Offset: {x: 0, y: 0} 42 | - _EmissionMap: 43 | m_Texture: {fileID: 0} 44 | m_Scale: {x: 1, y: 1} 45 | m_Offset: {x: 0, y: 0} 46 | - _MainTex: 47 | m_Texture: {fileID: 0} 48 | m_Scale: {x: 1, y: 1} 49 | m_Offset: {x: 0, y: 0} 50 | - _MetallicGlossMap: 51 | m_Texture: {fileID: 0} 52 | m_Scale: {x: 1, y: 1} 53 | m_Offset: {x: 0, y: 0} 54 | - _OcclusionMap: 55 | m_Texture: {fileID: 0} 56 | m_Scale: {x: 1, y: 1} 57 | m_Offset: {x: 0, y: 0} 58 | - _ParallaxMap: 59 | m_Texture: {fileID: 0} 60 | m_Scale: {x: 1, y: 1} 61 | m_Offset: {x: 0, y: 0} 62 | m_Floats: 63 | - _BlendOp: 0 64 | - _Blending: 1 65 | - _BumpScale: 1 66 | - _CameraFadingEnabled: 0 67 | - _CameraFarFadeDistance: 2 68 | - _CameraNearFadeDistance: 1 69 | - _ColorMode: 0 70 | - _Cull: 0 71 | - _Cutoff: 0.5 72 | - _DetailNormalMapScale: 1 73 | - _DistortionBlend: 0.5 74 | - _DistortionEnabled: 0 75 | - _DistortionStrength: 1 76 | - _DistortionStrengthScaled: 0 77 | - _DstBlend: 10 78 | - _EmissionEnabled: 0 79 | - _FlipbookMode: 0 80 | - _GlossMapScale: 1 81 | - _Glossiness: 0.5 82 | - _GlossyReflections: 1 83 | - _LightingEnabled: 0 84 | - _Metallic: 0 85 | - _Mode: 2 86 | - _OcclusionStrength: 1 87 | - _Parallax: 0.02 88 | - _SmoothnessTextureChannel: 0 89 | - _SoftParticlesEnabled: 0 90 | - _SoftParticlesFarFadeDistance: 1 91 | - _SoftParticlesNearFadeDistance: 0 92 | - _SpecularHighlights: 1 93 | - _SrcBlend: 5 94 | - _UVSec: 0 95 | - _ZWrite: 0 96 | m_Colors: 97 | - _CameraFadeParams: {r: 0, g: Infinity, b: 0, a: 0} 98 | - _Color: {r: 0.85800004, g: 0.85800004, b: 0.85800004, a: 1} 99 | - _ColorAddSubDiff: {r: 0, g: 0, b: 0, a: 0} 100 | - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} 101 | - _SoftParticleFadeParams: {r: 0, g: 0, b: 0, a: 0} 102 | -------------------------------------------------------------------------------- /Unity/Assets/Firefly/Materials/Firefly.mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 6 6 | m_ObjectHideFlags: 0 7 | m_CorrespondingSourceObject: {fileID: 0} 8 | m_PrefabInstance: {fileID: 0} 9 | m_PrefabAsset: {fileID: 0} 10 | m_Name: Firefly 11 | m_Shader: {fileID: 4800000, guid: cff24ff0d3324fe4ea45bebfb38b2406, type: 3} 12 | m_ShaderKeywords: 13 | m_LightmapFlags: 4 14 | m_EnableInstancingVariants: 0 15 | m_DoubleSidedGI: 0 16 | m_CustomRenderQueue: -1 17 | stringTagMap: {} 18 | disabledShaderPasses: [] 19 | m_SavedProperties: 20 | serializedVersion: 3 21 | m_TexEnvs: 22 | - _AirstreamTex: 23 | m_Texture: {fileID: 0} 24 | m_Scale: {x: 1, y: 1} 25 | m_Offset: {x: 0, y: 0} 26 | - _BumpMap: 27 | m_Texture: {fileID: 0} 28 | m_Scale: {x: 1, y: 1} 29 | m_Offset: {x: 0, y: 0} 30 | - _DetailAlbedoMap: 31 | m_Texture: {fileID: 0} 32 | m_Scale: {x: 1, y: 1} 33 | m_Offset: {x: 0, y: 0} 34 | - _DetailMask: 35 | m_Texture: {fileID: 0} 36 | m_Scale: {x: 1, y: 1} 37 | m_Offset: {x: 0, y: 0} 38 | - _DetailNormalMap: 39 | m_Texture: {fileID: 0} 40 | m_Scale: {x: 1, y: 1} 41 | m_Offset: {x: 0, y: 0} 42 | - _DitherTex: 43 | m_Texture: {fileID: 0} 44 | m_Scale: {x: 1, y: 1} 45 | m_Offset: {x: 0, y: 0} 46 | - _EmissionMap: 47 | m_Texture: {fileID: 0} 48 | m_Scale: {x: 1, y: 1} 49 | m_Offset: {x: 0, y: 0} 50 | - _MainTex: 51 | m_Texture: {fileID: 0} 52 | m_Scale: {x: 1, y: 1} 53 | m_Offset: {x: 0, y: 0} 54 | - _MetallicGlossMap: 55 | m_Texture: {fileID: 0} 56 | m_Scale: {x: 1, y: 1} 57 | m_Offset: {x: 0, y: 0} 58 | - _NoiseTex: 59 | m_Texture: {fileID: 2800000, guid: d9a1ade6f3368f24fbc2620a6d05ce6c, type: 3} 60 | m_Scale: {x: 1, y: 1} 61 | m_Offset: {x: 0, y: 0} 62 | - _OcclusionMap: 63 | m_Texture: {fileID: 0} 64 | m_Scale: {x: 1, y: 1} 65 | m_Offset: {x: 0, y: 0} 66 | - _ParallaxMap: 67 | m_Texture: {fileID: 0} 68 | m_Scale: {x: 1, y: 1} 69 | m_Offset: {x: 0, y: 0} 70 | m_Floats: 71 | - _BlueMultiplier: 0 72 | - _BumpScale: 1 73 | - _Cutoff: 0.5 74 | - _DetailNormalMapScale: 1 75 | - _DstBlend: 0 76 | - _GlossMapScale: 1 77 | - _Glossiness: 0.5 78 | - _GlossyReflections: 1 79 | - _HeatMultiplier: 1 80 | - _Metallic: 0 81 | - _Mode: 0 82 | - _OcclusionStrength: 1 83 | - _OpacityMultiplier: 1 84 | - _Parallax: 0.02 85 | - _SmoothnessTextureChannel: 0 86 | - _SpecularHighlights: 1 87 | - _SrcBlend: 1 88 | - _StreakProbability: 0.1 89 | - _StreakThreshold: -0.2 90 | - _TrailAlphaMultiplier: 1 91 | - _UVSec: 0 92 | - _WrapFresnelModifier: 0 93 | - _ZWrite: 1 94 | m_Colors: 95 | - _Color: {r: 1, g: 1, b: 1, a: 1} 96 | - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} 97 | - _GlowColor: {r: 0, g: 0, b: 0, a: 1} 98 | - _HotGlowColor: {r: 0, g: 0, b: 0, a: 1} 99 | - _LayerColor: {r: 0, g: 0, b: 0, a: 1} 100 | - _LayerStreakColor: {r: 0, g: 0, b: 0, a: 1} 101 | - _PrimaryColor: {r: 0, g: 0, b: 0, a: 1} 102 | - _RandomnessFactor: {r: 1, g: 1, b: 0, a: 1} 103 | - _SecondaryColor: {r: 0, g: 0, b: 0, a: 1} 104 | - _ShockwaveColor: {r: 0, g: 0, b: 0, a: 1} 105 | - _TertiaryColor: {r: 0, g: 0, b: 0, a: 1} 106 | -------------------------------------------------------------------------------- /Unity/Assets/Firefly/Materials/Smoke.mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 6 6 | m_ObjectHideFlags: 0 7 | m_CorrespondingSourceObject: {fileID: 0} 8 | m_PrefabInstance: {fileID: 0} 9 | m_PrefabAsset: {fileID: 0} 10 | m_Name: Smoke 11 | m_Shader: {fileID: 4800000, guid: 52287257c00b14843b36065f98791b82, type: 3} 12 | m_ShaderKeywords: _ALPHABLEND_ON _COLORADDSUBDIFF_ON 13 | m_LightmapFlags: 0 14 | m_EnableInstancingVariants: 0 15 | m_DoubleSidedGI: 0 16 | m_CustomRenderQueue: -1 17 | stringTagMap: {} 18 | disabledShaderPasses: [] 19 | m_SavedProperties: 20 | serializedVersion: 3 21 | m_TexEnvs: 22 | - _AirstreamTex: 23 | m_Texture: {fileID: 8400000, guid: 2dfe58f43e17b8d4ead11de3a11ed275, type: 2} 24 | m_Scale: {x: 1, y: 1} 25 | m_Offset: {x: 0, y: 0} 26 | - _BumpMap: 27 | m_Texture: {fileID: 0} 28 | m_Scale: {x: 1, y: 1} 29 | m_Offset: {x: 0, y: 0} 30 | - _DetailAlbedoMap: 31 | m_Texture: {fileID: 0} 32 | m_Scale: {x: 1, y: 1} 33 | m_Offset: {x: 0, y: 0} 34 | - _DetailMask: 35 | m_Texture: {fileID: 0} 36 | m_Scale: {x: 1, y: 1} 37 | m_Offset: {x: 0, y: 0} 38 | - _DetailNormalMap: 39 | m_Texture: {fileID: 0} 40 | m_Scale: {x: 1, y: 1} 41 | m_Offset: {x: 0, y: 0} 42 | - _EmissionMap: 43 | m_Texture: {fileID: 0} 44 | m_Scale: {x: 1, y: 1} 45 | m_Offset: {x: 0, y: 0} 46 | - _MainTex: 47 | m_Texture: {fileID: 0} 48 | m_Scale: {x: 1, y: 1} 49 | m_Offset: {x: 0, y: 0} 50 | - _MetallicGlossMap: 51 | m_Texture: {fileID: 0} 52 | m_Scale: {x: 1, y: 1} 53 | m_Offset: {x: 0, y: 0} 54 | - _OcclusionMap: 55 | m_Texture: {fileID: 0} 56 | m_Scale: {x: 1, y: 1} 57 | m_Offset: {x: 0, y: 0} 58 | - _ParallaxMap: 59 | m_Texture: {fileID: 0} 60 | m_Scale: {x: 1, y: 1} 61 | m_Offset: {x: 0, y: 0} 62 | m_Floats: 63 | - _AirstreamBlending: 1 64 | - _BlendOp: 0 65 | - _Blending: 0 66 | - _BumpScale: 1 67 | - _CameraFadingEnabled: 0 68 | - _CameraFarFadeDistance: 2 69 | - _CameraNearFadeDistance: 1 70 | - _ColorMode: 1 71 | - _Cull: 0 72 | - _Cutoff: 0.5 73 | - _DetailNormalMapScale: 1 74 | - _DistortionBlend: 0.5 75 | - _DistortionEnabled: 0 76 | - _DistortionStrength: 1 77 | - _DistortionStrengthScaled: 0.1 78 | - _DstBlend: 10 79 | - _EmissionEnabled: 0 80 | - _FlipbookMode: 0 81 | - _GlossMapScale: 1 82 | - _Glossiness: 0.5 83 | - _GlossyReflections: 1 84 | - _LightingEnabled: 0 85 | - _Metallic: 0 86 | - _Mode: 2 87 | - _OcclusionStrength: 1 88 | - _Parallax: 0.02 89 | - _SmoothnessTextureChannel: 0 90 | - _SoftParticlesEnabled: 0 91 | - _SoftParticlesFarFadeDistance: 1 92 | - _SoftParticlesNearFadeDistance: 0 93 | - _SpecularHighlights: 1 94 | - _SrcBlend: 5 95 | - _UVSec: 0 96 | - _ZWrite: 0 97 | m_Colors: 98 | - _CameraFadeParams: {r: 0, g: Infinity, b: 0, a: 0} 99 | - _Color: {r: 1, g: 1, b: 1, a: 0.18039216} 100 | - _ColorAddSubDiff: {r: 1, g: 0, b: 0, a: 0} 101 | - _EmissionColor: {r: 0.047058824, g: 0.047058824, b: 0.047058824, a: 1} 102 | - _SoftParticleFadeParams: {r: 0, g: 0, b: 0, a: 0} 103 | -------------------------------------------------------------------------------- /Unity/Assets/Firefly/Materials/Spark.mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 6 6 | m_ObjectHideFlags: 0 7 | m_CorrespondingSourceObject: {fileID: 0} 8 | m_PrefabInstance: {fileID: 0} 9 | m_PrefabAsset: {fileID: 0} 10 | m_Name: Spark 11 | m_Shader: {fileID: 4800000, guid: 52287257c00b14843b36065f98791b82, type: 3} 12 | m_ShaderKeywords: _ALPHABLEND_ON _COLORADDSUBDIFF_ON _EMISSION 13 | m_LightmapFlags: 0 14 | m_EnableInstancingVariants: 0 15 | m_DoubleSidedGI: 0 16 | m_CustomRenderQueue: -1 17 | stringTagMap: {} 18 | disabledShaderPasses: [] 19 | m_SavedProperties: 20 | serializedVersion: 3 21 | m_TexEnvs: 22 | - _AirstreamTex: 23 | m_Texture: {fileID: 8400000, guid: 2dfe58f43e17b8d4ead11de3a11ed275, type: 2} 24 | m_Scale: {x: 1, y: 1} 25 | m_Offset: {x: 0, y: 0} 26 | - _AlphaTex: 27 | m_Texture: {fileID: 0} 28 | m_Scale: {x: 1, y: 1} 29 | m_Offset: {x: 0, y: 0} 30 | - _BumpMap: 31 | m_Texture: {fileID: 0} 32 | m_Scale: {x: 1, y: 1} 33 | m_Offset: {x: 0, y: 0} 34 | - _DetailAlbedoMap: 35 | m_Texture: {fileID: 0} 36 | m_Scale: {x: 1, y: 1} 37 | m_Offset: {x: 0, y: 0} 38 | - _DetailMask: 39 | m_Texture: {fileID: 0} 40 | m_Scale: {x: 1, y: 1} 41 | m_Offset: {x: 0, y: 0} 42 | - _DetailNormalMap: 43 | m_Texture: {fileID: 0} 44 | m_Scale: {x: 1, y: 1} 45 | m_Offset: {x: 0, y: 0} 46 | - _EmissionMap: 47 | m_Texture: {fileID: 0} 48 | m_Scale: {x: 1, y: 1} 49 | m_Offset: {x: 0, y: 0} 50 | - _MainTex: 51 | m_Texture: {fileID: 0} 52 | m_Scale: {x: 1, y: 1} 53 | m_Offset: {x: 0, y: 0} 54 | - _MetallicGlossMap: 55 | m_Texture: {fileID: 0} 56 | m_Scale: {x: 1, y: 1} 57 | m_Offset: {x: 0, y: 0} 58 | - _OcclusionMap: 59 | m_Texture: {fileID: 0} 60 | m_Scale: {x: 1, y: 1} 61 | m_Offset: {x: 0, y: 0} 62 | - _ParallaxMap: 63 | m_Texture: {fileID: 0} 64 | m_Scale: {x: 1, y: 1} 65 | m_Offset: {x: 0, y: 0} 66 | m_Floats: 67 | - PixelSnap: 0 68 | - _AirstreamBlending: 0 69 | - _BlendOp: 0 70 | - _Blending: 0 71 | - _BumpScale: 1 72 | - _CameraFadingEnabled: 0 73 | - _CameraFarFadeDistance: 2 74 | - _CameraNearFadeDistance: 1 75 | - _ColorMode: 1 76 | - _Cull: 0 77 | - _Cutoff: 0.5 78 | - _DetailNormalMapScale: 1 79 | - _DistortionBlend: 0.5 80 | - _DistortionEnabled: 0 81 | - _DistortionStrength: 1 82 | - _DistortionStrengthScaled: 0.1 83 | - _DstBlend: 10 84 | - _EmissionEnabled: 1 85 | - _EnableExternalAlpha: 0 86 | - _FlipbookMode: 0 87 | - _Fresnel: 3.62 88 | - _GlossMapScale: 1 89 | - _Glossiness: 0 90 | - _GlossyReflections: 1 91 | - _InvFade: 1 92 | - _LightingEnabled: 0 93 | - _Metallic: 0 94 | - _Mode: 2 95 | - _OcclusionStrength: 1 96 | - _Parallax: 0.02 97 | - _SmoothnessTextureChannel: 0 98 | - _SoftParticlesEnabled: 0 99 | - _SoftParticlesFarFadeDistance: 1 100 | - _SoftParticlesNearFadeDistance: 0 101 | - _SpecularHighlights: 1 102 | - _SrcBlend: 5 103 | - _UVSec: 0 104 | - _UnderwaterFogFactor: 0 105 | - _ZWrite: 0 106 | m_Colors: 107 | - _CameraFadeParams: {r: 0, g: Infinity, b: 0, a: 0} 108 | - _Color: {r: 1, g: 0.8352941, b: 0.7490196, a: 1} 109 | - _ColorAddSubDiff: {r: 1, g: 0, b: 0, a: 0} 110 | - _EmissionColor: {r: 10.432953, g: 8.739647, b: 7.592568, a: 1} 111 | - _Flip: {r: 1, g: 1, b: 1, a: 1} 112 | - _RendererColor: {r: 1, g: 1, b: 1, a: 1} 113 | - _SoftParticleFadeParams: {r: 0, g: 0, b: 0, a: 0} 114 | - _TintColor: {r: 1, g: 1, b: 1, a: 1} 115 | -------------------------------------------------------------------------------- /Unity/Assets/Firefly/Shaders/CommonFunctions.cginc: -------------------------------------------------------------------------------- 1 | Texture2D _AirstreamTex; 2 | SamplerState sampler_AirstreamTex; 3 | 4 | Texture2D _NoiseTex; 5 | SamplerState sampler_NoiseTex; 6 | 7 | Texture2D _DitherTex; 8 | SamplerState sampler_DitherTex; 9 | 10 | float _EntryStrength; 11 | 12 | float3 _ModelScale; 13 | float3 _EnvelopeScaleFactor; 14 | float3 _Velocity; 15 | float4x4 _AirstreamVP; 16 | 17 | float Shadow(float3 airstreamNDC, float bias, float shadowStrength) 18 | { 19 | if (airstreamNDC.x < -1.0f || airstreamNDC.x > 1.0f || airstreamNDC.y < -1.0f || airstreamNDC.y > 1.0f) 20 | { 21 | return 1; 22 | } 23 | 24 | float2 uv = airstreamNDC.xy * 0.5 + 0.5; 25 | float3 lpos = airstreamNDC; 26 | 27 | #ifndef UNITY_REVERSED_Z 28 | lpos.z = -lpos.z * 0.5 + 0.5; 29 | #endif 30 | 31 | #if UNITY_UV_STARTS_AT_TOP 32 | uv.y = 1 - uv.y; 33 | #endif 34 | 35 | lpos.x = lpos.x / 2 + 0.5; 36 | lpos.y = lpos.y / -2 + 0.5; 37 | lpos.z -= bias; 38 | 39 | float sum = 0; 40 | for (float y = -2; y <= 2; y++) 41 | { 42 | for (float x = -2; x <= 2; x++) 43 | { 44 | float sampled = _AirstreamTex.SampleLevel(sampler_AirstreamTex, uv + float2(x / 512, y / 512), 0); 45 | 46 | #ifndef UNITY_REVERSED_Z 47 | sampled = 1 - sampled; 48 | #endif 49 | 50 | if (sampled <= lpos.z) sum++; 51 | } 52 | } 53 | float shadow = sum / 25.0; 54 | return saturate(shadow + 1 - shadowStrength); 55 | } 56 | 57 | float3 TransformObjectToWorld(float3 v) 58 | { 59 | return mul(unity_ObjectToWorld, float4(v, 1.0)); 60 | } 61 | 62 | float3 TransformWorldToObject(float3 v) 63 | { 64 | return mul(unity_WorldToObject, float4(v, 1.0)); 65 | } 66 | 67 | float3 GetAirstreamNDC(float3 positionOS) 68 | { 69 | float3 positionWS = TransformObjectToWorld(positionOS); 70 | 71 | float4 airstreamPosition = mul(_AirstreamVP, float4(positionWS, 1)); 72 | return airstreamPosition.xyz / airstreamPosition.w; 73 | } 74 | 75 | float Noise(float2 uv, int channel) 76 | { 77 | return _NoiseTex.SampleLevel(sampler_NoiseTex, uv + float2(_Time.x*14, _Time.x*7), 0)[channel]; 78 | } 79 | 80 | float NoiseStatic(float2 uv, int channel) 81 | { 82 | return _NoiseTex.SampleLevel(sampler_NoiseTex, uv, 0)[channel]; 83 | } 84 | 85 | float Fresnel(float3 normal, float3 viewDir, float power) 86 | { 87 | return pow((1.0 - saturate(dot(normalize(normal), normalize(viewDir)))), power); 88 | } -------------------------------------------------------------------------------- /Unity/Assets/Firefly/Shaders/EffectPasses/BowshockPass.cginc: -------------------------------------------------------------------------------- 1 | float4 _ShockwaveColor; 2 | float _LengthMultiplier; 3 | 4 | int _DisableBowshock; 5 | 6 | struct VS_INPUT 7 | { 8 | float4 position : POSITION; 9 | float3 normal : NORMAL; 10 | 11 | float2 uv : TEXCOORD0; 12 | }; 13 | 14 | struct GS_INPUT 15 | { 16 | float4 position : POSITION; 17 | float3 normal : NORMAL; 18 | 19 | float2 uv : TEXCOORD0; 20 | 21 | float3 positionWS : TEXCOORD3; 22 | float3 airstreamNDC : TEXCOORD4; 23 | float3 velocityOS : TEXCOORD5; 24 | float3 normalOS : TEXCOORD6; 25 | float3 viewDir : TEXCOORD7; 26 | }; 27 | 28 | struct GS_DATA 29 | { 30 | float4 position : SV_POSITION; 31 | half4 color : COLOR; 32 | 33 | float3 positionWS : TEXCOORD1; 34 | }; 35 | 36 | // Creates a vertex instance that can be added to a triangle stream 37 | GS_DATA CreateVertex(float3 pos, half4 color, half a) 38 | { 39 | GS_DATA o; 40 | 41 | o.position = UnityObjectToClipPos(pos); 42 | o.color = color; 43 | o.color.a = a; 44 | 45 | o.positionWS = TransformObjectToWorld(pos); 46 | 47 | return o; 48 | } 49 | 50 | GS_INPUT gs_vert(VS_INPUT IN) 51 | { 52 | GS_INPUT OUT; 53 | 54 | // scaled position 55 | OUT.position = IN.position * float4(_EnvelopeScaleFactor, 1.0); 56 | OUT.positionWS = TransformObjectToWorld(OUT.position.xyz); 57 | 58 | // world and object space normal 59 | OUT.normal = normalize(UnityObjectToWorldNormal(IN.normal)); 60 | OUT.normalOS = normalize(IN.normal); 61 | 62 | OUT.uv = IN.uv; 63 | 64 | // airstream position 65 | float4 airstreamPosition = mul(_AirstreamVP, float4(OUT.positionWS, 1)); 66 | OUT.airstreamNDC = airstreamPosition.xyz / airstreamPosition.w; 67 | 68 | // object space velocity 69 | OUT.velocityOS = UnityWorldToObjectDir(normalize(_Velocity)); 70 | 71 | OUT.viewDir = WorldSpaceViewDir(IN.position); 72 | 73 | return OUT; 74 | } 75 | 76 | [maxvertexcount(9)] 77 | void gs_geom(triangle GS_INPUT vertex[3], inout TriangleStream triStream) 78 | { 79 | if (_EntryStrength < 1000 || _DisableBowshock > 0) return; 80 | 81 | // Initialize iterator variable 82 | int i = 0; 83 | 84 | // Scale the entry speed 85 | float clampedEntrySpeed = min(_EntryStrength, 2300); 86 | float entrySpeed = min(_EntryStrength / 4000, 0.57); 87 | float scaledEntrySpeed = lerp(0, entrySpeed + 0.55, saturate((entrySpeed - 0.32) * 2)); 88 | 89 | // Get the occlusion for each vertex 90 | float3 occlusion = float3( 91 | Shadow(vertex[0].airstreamNDC, -0.003, 1), 92 | Shadow(vertex[1].airstreamNDC, -0.003, 1), 93 | Shadow(vertex[2].airstreamNDC, -0.003, 1) 94 | ); 95 | 96 | // Calculate the base effect length 97 | float baseLength = clampedEntrySpeed * 0.0005; 98 | 99 | // Sample noise 100 | float3 noise = 0; 101 | for (i = 0; i < 3; i++) noise[i] = Noise(vertex[i].position.xy + vertex[i].uv, 1) * baseLength * Noise(vertex[i].position.xy + vertex[i].uv, 2) * 10; 102 | 103 | // Calculate the outward effect length 104 | float3 effectLength = (baseLength + noise * 0.3) * scaledEntrySpeed * 1.5; 105 | float3 middleLength = effectLength * 0.54; 106 | 107 | // Calculate the forward effect length 108 | float3 effectSideLength = (3 + noise) * scaledEntrySpeed * 0.9; 109 | float3 middleSideLength = effectSideLength * 0.45; 110 | 111 | // Offset the bowshock away from the ship 112 | float3 offset = (vertex[0].velocityOS * 0.4 * entrySpeed) * _ModelScale.y; 113 | float3 trailOffset = offset * 1.1; 114 | 115 | // Fresnel effect 116 | float3 vertFresnel = 0; 117 | for (i = 0; i < 3; i++) vertFresnel[i] = Fresnel(vertex[i].normal, vertex[i].viewDir, 1) * Fresnel(-vertex[i].normal, vertex[i].viewDir, 1) - (Fresnel(vertex[i].normal, vertex[i].viewDir, 3) - 0.3) - (1 - Fresnel(vertex[i].normal, vertex[i].viewDir, 1) - 0.8); 118 | 119 | // Dot product of normal and velocity 120 | float3 velDotInv = 0; 121 | for (i = 0; i < 3; i++) velDotInv[i] = dot(vertex[i].normal, _Velocity); 122 | 123 | // Inverted dot product of normal and velocity 124 | float3 velDot = -velDotInv; 125 | 126 | // Create the "bowl" 127 | if (occlusion[0] > 0.9 && velDotInv[0] > 0.2) 128 | { 129 | for (i = 0; i < 3; i++) 130 | { 131 | // bowl fresnel effect 132 | float fresnel = Fresnel(vertex[i].normal, vertex[i].viewDir, 2); 133 | float fresnelInv = Fresnel(-vertex[i].normal, vertex[i].viewDir, 2); 134 | 135 | // Fresnel value to soften the edges 136 | float softFresnel = Fresnel(vertex[i].normal, vertex[i].viewDir, 2); 137 | 138 | // bowl opacity 139 | float alpha = 0.85 * fresnel * scaledEntrySpeed * (1 - softFresnel); 140 | 141 | // add vertex 142 | triStream.Append(CreateVertex(vertex[i].position + offset, _ShockwaveColor * velDotInv[i] + fresnel * 0.6, alpha)); 143 | } 144 | 145 | triStream.RestartStrip(); 146 | } 147 | 148 | // Scale 149 | effectLength *= _ModelScale.y; 150 | middleLength *= _ModelScale.y; 151 | middleSideLength *= _ModelScale.y; 152 | effectSideLength *= _ModelScale.y; 153 | 154 | // make sure these values dont go negative 155 | effectLength = abs(effectLength); 156 | middleLength = abs(middleLength); 157 | middleSideLength = abs(middleSideLength); 158 | effectSideLength = abs(effectSideLength); 159 | 160 | // Iterate through every vertex 161 | for (uint i = 0; i < 2; i++) 162 | { 163 | if (occlusion[i] > 0.9 && velDot[i] > -0.4 && velDot[i] < 0 && pow(vertFresnel[i], 2) > 0.2) 164 | { 165 | uint j = (i + 1) % 3; // next vertex 166 | uint k = (j + 1) % 3; // another vertex 167 | 168 | // Get the average edge length 169 | float edgeLength_j = length(vertex[i].position - vertex[j].position); 170 | float edgeLength_k = length(vertex[i].position - vertex[k].position); 171 | float edgeLength = ((edgeLength_j + edgeLength_k) / 2) * (1 / _ModelScale.y); 172 | float edgeMul = clamp(edgeLength / 0.1, 0.1, 1); 173 | 174 | // Create the offsets which move the trail a bit inside of the bowl 175 | float3 offset_i = float3(vertex[i].position.x, 0, vertex[i].position.z) * 0.0; 176 | float3 offset_j = float3(vertex[j].position.x, 0, vertex[j].position.z) * 0.0; 177 | 178 | // Sample noise 179 | float vertNoise = Noise(vertex[i].position.xy + vertex[i].uv + _Time.x, 0); 180 | 181 | // Create the vector which will be used to widen the trail segments 182 | float3 sizeVector = -normalize(cross(vertex[i].velocityOS, vertex[i].normalOS)); 183 | 184 | // Width 185 | float3 side = sizeVector * 0.2; // vector pointing to the side, which allows for thicker trails 186 | float3 middleSide = side * 2; 187 | float3 endSide = side * 2; 188 | 189 | // Scale 190 | side *= _ModelScale.x; 191 | middleSide *= _ModelScale.x; 192 | endSide *= _ModelScale.x; 193 | 194 | // Opacity 195 | //float alpha = (0.05 + vertNoise * 0.009) * saturate(pow(vertFresnel[i], 1)) * 0.75 * scaledEntrySpeed; 196 | float alpha = 0.02 * 0.5 * scaledEntrySpeed * saturate(pow(vertFresnel[i], 3)); 197 | float middleAlpha = alpha * 0.6; 198 | alpha *= edgeMul; 199 | middleAlpha *= edgeMul; 200 | 201 | // Define the vertex positions 202 | float3 vertex_b0 = vertex[i].position - offset_i + trailOffset - side; 203 | float3 vertex_b1 = vertex[j].position - offset_j + trailOffset + side; 204 | 205 | float3 vertex_m0 = vertex[i].position - offset_i + trailOffset - middleSide + middleLength[i] * vertex[i].normalOS - vertex[i].velocityOS * middleSideLength[i]; 206 | float3 vertex_m1 = vertex[j].position - offset_j + trailOffset + middleSide + middleLength[j] * vertex[j].normalOS - vertex[j].velocityOS * middleSideLength[j]; 207 | 208 | float3 vertex_t0 = vertex[i].position - offset_i + trailOffset - endSide + effectLength[i] * vertex[i].normalOS - vertex[i].velocityOS * effectSideLength[i]; 209 | float3 vertex_t1 = vertex[j].position - offset_j + trailOffset + endSide + effectLength[j] * vertex[j].normalOS - vertex[j].velocityOS * effectSideLength[j]; 210 | 211 | // add the vertices to the tri strip 212 | triStream.Append(CreateVertex(vertex_b0, _ShockwaveColor, alpha)); 213 | triStream.Append(CreateVertex(vertex_b1, _ShockwaveColor, alpha)); 214 | 215 | triStream.Append(CreateVertex(vertex_m0, _ShockwaveColor, middleAlpha)); 216 | triStream.Append(CreateVertex(vertex_m1, _ShockwaveColor, middleAlpha)); 217 | 218 | triStream.Append(CreateVertex(vertex_t0, _ShockwaveColor, 0)); 219 | triStream.Append(CreateVertex(vertex_t1, _ShockwaveColor, 0)); 220 | 221 | // Restart the strip 222 | triStream.RestartStrip(); 223 | } 224 | } 225 | } 226 | 227 | half4 gs_frag(GS_DATA IN) : SV_Target 228 | { 229 | float4 c = IN.color; 230 | 231 | // Doing alpha blending before Unity can clamp the colors to SDR (if not in HDR mode) 232 | c.rgb *= c.a; 233 | c.a = 1; 234 | 235 | return c; 236 | } -------------------------------------------------------------------------------- /Unity/Assets/Firefly/Shaders/EffectPasses/GlowPass.cginc: -------------------------------------------------------------------------------- 1 | struct VS_INPUT 2 | { 3 | float4 position : POSITION; 4 | float3 normal : NORMAL; 5 | }; 6 | 7 | struct FS_INPUT 8 | { 9 | float4 position : SV_POSITION; 10 | float3 normal : NORMAL; 11 | 12 | float4 screenPos : TEXCOORD2; 13 | float3 worldPosition : TEXCOORD3; 14 | float4 airstreamNDC : TEXCOORD4; 15 | float3 viewDir : TEXCOORD5; 16 | }; 17 | 18 | float _Hdr; 19 | int _UnityEditor; 20 | 21 | float4 _GlowColor; 22 | float4 _HotGlowColor; 23 | float4 _TertiaryColor; 24 | 25 | float _BlueMultiplier; 26 | 27 | float _HeatMultiplier; 28 | 29 | float _FxState; 30 | 31 | float4 GetEntryColor(float4 heat, float4 blue, float strength) 32 | { 33 | float whiteRatio = strength / 0.25; 34 | 35 | float4 col = lerp(heat, blue, strength); 36 | 37 | if (whiteRatio < 2) 38 | { 39 | float t = saturate(whiteRatio - 1); 40 | 41 | col = lerp(1, col, t + _FxState); 42 | } 43 | 44 | return col; 45 | } 46 | 47 | FS_INPUT vert(VS_INPUT IN) 48 | { 49 | FS_INPUT OUT; 50 | 51 | float3 scaledPos = IN.position.xyz * _EnvelopeScaleFactor; 52 | 53 | // World space normal 54 | OUT.normal = UnityObjectToWorldNormal(IN.normal); 55 | 56 | // Position in clip space 57 | OUT.position = UnityObjectToClipPos(scaledPos); 58 | 59 | // Screen POSITION 60 | OUT.screenPos = ComputeScreenPos(OUT.position); 61 | OUT.screenPos = OUT.screenPos / OUT.screenPos.w; 62 | 63 | // Calculating the clip position on the airstream camera 64 | OUT.worldPosition = TransformObjectToWorld(IN.position.xyz); 65 | float4 airstreamPosition = mul(_AirstreamVP, float4(OUT.worldPosition, 1)); 66 | OUT.airstreamNDC = airstreamPosition / airstreamPosition.w; 67 | 68 | // View dir 69 | OUT.viewDir = WorldSpaceViewDir(IN.position); 70 | 71 | return OUT; 72 | } 73 | 74 | half4 frag(FS_INPUT IN) : SV_Target 75 | { 76 | // Occlusion 77 | float shadow = Shadow(IN.airstreamNDC, -0.003, 1); 78 | 79 | // Acquiring the alpha 80 | float entrySpeed = saturate(_EntryStrength / 4000); 81 | float whiteRatio = saturate(entrySpeed / 0.42); // white when below 1680 82 | float faintRatio = saturate(entrySpeed / 0.5) / 2; 83 | 84 | float rawDot = saturate(dot(IN.normal, _Velocity)); 85 | float velDot = saturate(rawDot + 0.2); 86 | 87 | float alpha = saturate(shadow * whiteRatio * _HeatMultiplier * velDot * _FxState); 88 | 89 | // Entry heat color 90 | float3 entryHeat = GetEntryColor(_GlowColor, _HotGlowColor, (entrySpeed + _BlueMultiplier)) * shadow * velDot * lerp(0, 4, faintRatio); 91 | 92 | // Output 93 | //clip(DitherTexture(alpha, IN.screenPos.xy)); 94 | entryHeat = lerp(entryHeat * alpha, entryHeat, _Hdr); // perform alpha blending before the color is clamped to SDR 95 | return float4(entryHeat, alpha); 96 | } -------------------------------------------------------------------------------- /Unity/Assets/Firefly/Shaders/EffectPasses/MainPass.cginc: -------------------------------------------------------------------------------- 1 | float _FxState; 2 | float _AngleOfAttack; 3 | int _Hdr; 4 | int _UnityEditor = 0; 5 | int _VertexSamples = 3; 6 | 7 | float _LengthMultiplier; 8 | 9 | float _TrailAlphaMultiplier; 10 | float _BlueMultiplier; 11 | float _SideMultiplier; 12 | float _OpacityMultiplier; 13 | float _WrapFresnelModifier; 14 | float _StreakProbability; 15 | float _StreakThreshold; 16 | 17 | float4 _SecondaryColor; 18 | float4 _PrimaryColor; 19 | float4 _TertiaryColor; 20 | float4 _StreakColor; 21 | float4 _LayerColor; 22 | float4 _LayerStreakColor; 23 | 24 | float2 _RandomnessFactor; // factor deciding the streak randomness, should be high for asteroids and low for anything else 25 | 26 | struct VS_INPUT 27 | { 28 | float4 position : POSITION; 29 | float3 normal : NORMAL; 30 | 31 | float2 uv : TEXCOORD0; 32 | }; 33 | 34 | struct GS_INPUT 35 | { 36 | float4 position : POSITION; 37 | float3 normal : NORMAL; 38 | 39 | float2 uv : TEXCOORD0; 40 | 41 | float3 positionWS : TEXCOORD3; 42 | float4 airstreamNDC : TEXCOORD4; 43 | float3 velocityOS : TEXCOORD5; 44 | float3 normalOS : TEXCOORD6; 45 | float3 viewDir : TEXCOORD7; 46 | }; 47 | 48 | struct GS_DATA 49 | { 50 | float4 position : SV_POSITION; 51 | half4 color : COLOR; 52 | 53 | float3 positionWS : TEXCOORD1; 54 | float3 positionOS : TEXCOORD2; 55 | float4 screenPos : TEXCOORD4; 56 | 57 | float2 trailPos : TEXCOORD6; 58 | 59 | float layer : TEXCOORD7; 60 | float4 airstreamNDC : TEXCOORD8; 61 | }; 62 | 63 | // Creates a vertex instance that can be added to a triangle stream 64 | GS_DATA CreateVertex(float3 pos, float layer, float4 airstreamNDC, float trailPosX, float trailPosY, half4 color, half a) 65 | { 66 | GS_DATA o; 67 | 68 | o.position = UnityObjectToClipPos(pos); 69 | o.color = color; 70 | o.color.a = a; 71 | 72 | o.positionWS = TransformObjectToWorld(pos); 73 | o.positionOS = pos; 74 | o.screenPos = o.position; 75 | 76 | o.trailPos = float2(trailPosX, trailPosY); 77 | 78 | o.layer = layer; 79 | 80 | o.airstreamNDC = airstreamNDC; 81 | 82 | return o; 83 | } 84 | 85 | GS_INPUT gs_vert(VS_INPUT IN) 86 | { 87 | GS_INPUT OUT; 88 | 89 | // get normal in WS and OS 90 | OUT.normal = UnityObjectToWorldNormal(IN.normal); 91 | OUT.normalOS = normalize(IN.normal); 92 | 93 | // scale vertex 94 | OUT.position = IN.position * float4(_EnvelopeScaleFactor, 1); 95 | 96 | OUT.uv = IN.uv; 97 | 98 | OUT.positionWS = TransformObjectToWorld(OUT.position.xyz); 99 | 100 | // get the airstream position 101 | float4 airstreamPosition = mul(_AirstreamVP, float4(OUT.positionWS, 1)); 102 | OUT.airstreamNDC = float4(airstreamPosition.xyz / airstreamPosition.w, airstreamPosition.w); 103 | 104 | // object space velocity 105 | OUT.velocityOS = normalize(UnityWorldToObjectDir(_Velocity)); 106 | 107 | OUT.viewDir = WorldSpaceViewDir(IN.position); 108 | 109 | return OUT; 110 | } 111 | 112 | [maxvertexcount(12)] 113 | void gs_geom(triangle GS_INPUT vertex[3], inout TriangleStream triStream) 114 | { 115 | // don't draw anything if the speed is low enough 116 | if (_EntryStrength < 50) return; 117 | uint i = 0; 118 | 119 | float entrySpeed = _EntryStrength / 4000 - 0.08 * _FxState; 120 | 121 | // Get the occlusion for each vertex 122 | float3 occlusion = float3( 123 | Shadow(vertex[0].airstreamNDC, -0.003, 1), 124 | Shadow(vertex[1].airstreamNDC, -0.003, 1), 125 | Shadow(vertex[2].airstreamNDC, -0.003, 1) 126 | ); 127 | 128 | // Calculate the dot product between the inverted normal and velocity 129 | float3 velDots = 0; 130 | for (i = 0; i < 3; i++) velDots[i] = dot(-vertex[i].normal, _Velocity); 131 | 132 | // Calculate the base length 133 | float baseLength = _EntryStrength * 0.0013; 134 | float maxBaseLength = 5.2; // 4000 * 0.0013 135 | 136 | // calculate the noise values for each vertex 137 | float3 noise = 0; 138 | for (i = 0; i < 3; i++) noise[i] = Noise(vertex[i].position.xy + vertex[i].uv, 1) * baseLength * Noise(vertex[i].position.xy + vertex[i].uv, 1) * 5; 139 | 140 | // apply noise and calculate the middle vertex's position and outward spread 141 | float3 effectLength = (baseLength + noise) * _LengthMultiplier; 142 | float3 middleLength = effectLength * 0.2; 143 | float middleNormalMultiplier = 0.23 + lerp(0.1 * _FxState, 0, saturate((entrySpeed - 0.2) * 4)); 144 | 145 | // maximum efffect length at peak noise 146 | float maxEffectLength = (maxBaseLength * 6) * _LengthMultiplier; // imitating the effectLength variable, noise is at it's maximum, so 1 * maxBaseLength * 1 * 5, which can be simplified to maxBaseLength * 5 147 | 148 | // scale with model, to avoid huge trails 149 | effectLength *= _ModelScale.y; 150 | middleLength *= _ModelScale.y; 151 | 152 | // iterate through every vertex (probably wrong?) 153 | for (i = 0; i < 3; i++) 154 | { 155 | float velDot = velDots[i]; 156 | 157 | // DEBUG 158 | //triStream.Append(CreateVertex(vertex[i].position, 0, vertex[i].airstreamNDC, 0, 0, 1, 1)); 159 | // DEBUG 160 | 161 | // Only proceed if the vertex isnt occluded and it's at a high enough angle, creating a rim from which the plasma trail is created 162 | if (velDot > -0.1 && occlusion[i] > 0.9) 163 | { 164 | uint j = (i + 1) % 3; // next vertex 165 | uint k = (j + 1) % 3; // another vertex 166 | 167 | // calculate the triangle edge lengths, which then get used to modify the segment width and opacity 168 | float edgeLength_j = length(vertex[i].position - vertex[j].position); 169 | float edgeLength_k = length(vertex[i].position - vertex[k].position); 170 | float edgeLength = (edgeLength_j + edgeLength_k) / 2 * (1 / _ModelScale.y); // world-scaled average edge length 171 | float edgeMul = clamp(edgeLength / 0.05, 0.1, 40); 172 | float sideEdgeMul = 1 - saturate(edgeLength - 0.1); 173 | 174 | // decide the second most dominant vertex 175 | if (occlusion[k] > occlusion[j] || velDots[k] > velDots[j]) j = k; 176 | 177 | // vector determining the side direction of the segment (the width) 178 | float3 sizeVector = normalize(cross(vertex[i].velocityOS, vertex[i].normalOS)); 179 | 180 | // vectors which determine the width of the segment at various points 181 | float3 side = sizeVector * 0.6 * sideEdgeMul; 182 | float3 middleSide = side * 1.4 * clamp(entrySpeed, 0.2, 1); 183 | float3 endSide = side * 2.5 * clamp(entrySpeed, 0.2, 1); 184 | side *= 0.3; 185 | 186 | // different noise values for the current vertex 187 | float vertNoise = Noise(vertex[i].position.xy + vertex[i].uv + _Time.x, 0); 188 | float vertNoise1 = Noise(vertex[i].position.xy - _Time.y * (1 - _RandomnessFactor.x), 1 + round(_RandomnessFactor.x)); 189 | float vertNoise2 = Noise(vertex[i].position.xy - _Time.x, 1); 190 | 191 | // value which determines the outward spread of the segment 192 | float normalMultiplier = 0.8 * pow(_LengthMultiplier, lerp(5, 1, saturate(_LengthMultiplier))) + lerp(2 * _LengthMultiplier * _FxState, 0, saturate((entrySpeed - 0.2) * 4)); 193 | 194 | // colors 195 | float4 col = lerp(_PrimaryColor, _SecondaryColor, vertNoise * 0.3); 196 | float4 middleCol = lerp(col, _SecondaryColor, 0.5); 197 | float4 endCol = lerp(_SecondaryColor, _TertiaryColor, clamp(entrySpeed, 0, 1.7)); 198 | endCol = lerp(middleCol, endCol, _Hdr); 199 | 200 | // opacity of the trail 201 | float alpha = saturate(entrySpeed / 0.025) * (0.004 * _TrailAlphaMultiplier + vertNoise * 0.004); 202 | 203 | // colors and opacity for mach effects 204 | float t = saturate(entrySpeed / 0.25 - 1); 205 | 206 | // reduces the FxState based on if the ship's going up or down 207 | // if it's going up then the state should be reduced 208 | float fxState = lerp(_FxState, _FxState * 0.05, saturate(sign(_Velocity.y))); 209 | float interpolation = saturate(t + _FxState); 210 | 211 | // interpolate between white and the actual color 212 | col = lerp(1, col, interpolation); 213 | middleCol = lerp(1, middleCol, interpolation); 214 | endCol = lerp(1, endCol, interpolation); 215 | 216 | // increase/decrease the opacity based on the angle of attack 217 | float aoa = pow(saturate(_AngleOfAttack / 20), 4); 218 | alpha *= saturate(aoa + t + 0.5); 219 | 220 | // scale the width vectors and the outward spread vector 221 | side *= _ModelScale.x; 222 | middleSide *= _ModelScale.x; 223 | endSide *= _ModelScale.x; 224 | normalMultiplier *= _ModelScale.x; 225 | 226 | // make sure these don't go negative 227 | effectLength = abs(effectLength); 228 | middleLength = abs(middleLength); 229 | 230 | // calculate the normal vector of the segment 231 | float3 trailDir = (vertex[i].position - vertex[i].velocityOS * effectLength[i] + vertex[i].normalOS * normalMultiplier * entrySpeed) - vertex[i].position; 232 | float3 normal = normalize(cross(sizeVector, trailDir)); 233 | 234 | // apply a fresnel effect to soften the trail 235 | float vertFresnel = Fresnel(vertex[i].normal, vertex[i].viewDir, 2); 236 | alpha *= saturate(vertFresnel + 0.5 + vertNoise * 0.3) * edgeMul; 237 | 238 | // random streaks, either standard colored streaks or random ones for asteroids/comets 239 | int streakValue = 0; // value deciding if the current segment is a streak or not 240 | float streakNoise = vertNoise2; 241 | float4 streakColor = lerp(float4(4, 1, 1, 1), float4(1, 4, 1, 1), streakNoise); 242 | if (vertNoise1 > 0.73 - _StreakProbability && entrySpeed > 0.5 + _StreakThreshold) 243 | { 244 | // change color to streak 245 | col = lerp(_StreakColor, streakColor, _RandomnessFactor.x); 246 | middleCol = lerp(_StreakColor, streakColor, _RandomnessFactor.x); 247 | endCol = lerp(_StreakColor, streakColor, _RandomnessFactor.x); 248 | effectLength *= 2; 249 | alpha *= 2; 250 | 251 | streakValue = 1; 252 | } 253 | 254 | // calculate the vertex positions at various points 255 | float3 vertex_b0 = vertex[i].position - side; 256 | float3 vertex_b1 = vertex[j].position + side; 257 | 258 | float3 vertex_m0 = vertex[i].position - middleSide - vertex[i].velocityOS * middleLength[i] + vertex[i].normalOS * normalMultiplier * entrySpeed * middleNormalMultiplier; 259 | float3 vertex_m1 = vertex[j].position + middleSide - vertex[j].velocityOS * middleLength[j] + vertex[j].normalOS * normalMultiplier * entrySpeed * middleNormalMultiplier; 260 | 261 | float3 vertex_t0 = vertex[i].position - endSide - vertex[i].velocityOS * effectLength[i] + vertex[i].normalOS * normalMultiplier * entrySpeed; 262 | float3 vertex_t1 = vertex[j].position + endSide - vertex[j].velocityOS * effectLength[j] + vertex[j].normalOS * normalMultiplier * entrySpeed; 263 | 264 | // limit length 265 | float3 m0_ndc = GetAirstreamNDC(lerp(vertex_b0, vertex_m0, lerp(0.5, 0.1, saturate(entrySpeed - 0.5)))); 266 | float depth = Shadow(m0_ndc, -0.003, 1); 267 | 268 | //if (depth < 0.9) return; 269 | float discardSegment = (depth < 0.9) ? 2.0 : 0.0; 270 | 271 | // add the vertices to the trianglestrip 272 | triStream.Append(CreateVertex(vertex_b0, 0 - discardSegment, vertex[i].airstreamNDC, 0, 0, col, alpha)); 273 | triStream.Append(CreateVertex(vertex_b1, 0 - discardSegment, vertex[j].airstreamNDC, 1, 0, col, alpha)); 274 | 275 | triStream.Append(CreateVertex(vertex_m0, 0 - discardSegment, vertex[i].airstreamNDC, 0, 0.5, middleCol, alpha)); 276 | triStream.Append(CreateVertex(vertex_m1, 0 - discardSegment, vertex[j].airstreamNDC, 1, 0.5, middleCol, alpha)); 277 | 278 | triStream.Append(CreateVertex(vertex_t0, 0 - discardSegment, vertex[i].airstreamNDC, 0, 1, endCol, 0)); 279 | triStream.Append(CreateVertex(vertex_t1, 0 - discardSegment, vertex[j].airstreamNDC, 1, 1, endCol, 0)); 280 | 281 | // restart the trianglestrip, to allow for the next segment 282 | triStream.RestartStrip(); 283 | 284 | // 285 | // SECOND LAYER (WRAP) 286 | // 287 | 288 | // COMMENTED OUT: 289 | // This likely breaks the effects on Linux, with Proton and AMD GPUs 290 | // Instead of doing this, we still add the vertices to the trianglestream, but marked as discarded vertices to not use the fragment shader. 291 | // if the state is low enough, don't draw the wrap layer at all 292 | //if (_FxState < 0.6) 293 | //{ 294 | // return; 295 | //} 296 | 297 | // clamp the entry speed to the max value 298 | entrySpeed = clamp(entrySpeed, 0, 1); 299 | 300 | // recalculate the fresnel value 301 | vertFresnel = Fresnel(vertex[i].normal, vertex[i].viewDir, 1); 302 | vertFresnel += (1 - vertFresnel) * _WrapFresnelModifier; 303 | 304 | // modify the effect length, as well as the outward spread values to create the nice shape 305 | middleLength = clamp(middleLength, 0, maxEffectLength * 0.2); 306 | effectLength = clamp(effectLength * 3.4 * clamp(entrySpeed, 0, 0.6) * _FxState, 0, maxEffectLength * 1.6); 307 | normalMultiplier = -2.325 * saturate(pow(_LengthMultiplier, 3)) * _ModelScale.x; 308 | middleNormalMultiplier = 0.05; 309 | 310 | // change the opacity 311 | alpha *= 0.5 * vertFresnel * min(entrySpeed, 0.7) * _FxState; 312 | 313 | // change the color 314 | // the middle and end colors also get the streak colors 315 | col = _PrimaryColor; 316 | middleCol = lerp(_LayerColor, lerp(_LayerStreakColor, streakColor, _RandomnessFactor.y), streakValue); 317 | endCol = lerp(lerp(_LayerColor, _SecondaryColor, 0.5), lerp(_LayerStreakColor, streakColor, _RandomnessFactor.y), streakValue); 318 | 319 | // calculate the layer offset to move the entire thing away from the ship 320 | float3 layerOffset = vertex[i].velocityOS * -0.05 * _LengthMultiplier * _ModelScale.y; 321 | 322 | // calculate the vertex positions 323 | vertex_b0 = vertex[i].position - side + layerOffset; 324 | vertex_b1 = vertex[j].position + side + layerOffset; 325 | 326 | vertex_m0 = vertex[i].position - middleSide + layerOffset - vertex[i].velocityOS * middleLength[i] + vertex[i].normalOS * normalMultiplier * entrySpeed * middleNormalMultiplier; 327 | vertex_m1 = vertex[j].position + middleSide + layerOffset - vertex[j].velocityOS * middleLength[j] + vertex[j].normalOS * normalMultiplier * entrySpeed * middleNormalMultiplier; 328 | 329 | vertex_t0 = vertex[i].position - endSide + layerOffset - vertex[i].velocityOS * effectLength[i] + vertex[i].normalOS * normalMultiplier * entrySpeed; 330 | vertex_t1 = vertex[j].position + endSide + layerOffset - vertex[j].velocityOS * effectLength[j] + vertex[j].normalOS * normalMultiplier * entrySpeed; 331 | 332 | // should we discard this segment? 333 | float discardWrap = (_FxState < 0.6) ? 2.0 : 0.0; 334 | 335 | // add the set of vertices to the tri strip 336 | // NOTE: the discard variable gets subtracted from the layer, to let the frag shader know if it should clip 337 | triStream.Append(CreateVertex(vertex_b0, 1 - discardWrap, vertex[i].airstreamNDC, 0, 0, col, alpha)); 338 | triStream.Append(CreateVertex(vertex_b1, 1 - discardWrap, vertex[j].airstreamNDC, 1, 0, col, alpha)); 339 | 340 | triStream.Append(CreateVertex(vertex_m0, 1 - discardWrap, vertex[i].airstreamNDC, 0, 0.5, middleCol, alpha)); 341 | triStream.Append(CreateVertex(vertex_m1, 1 - discardWrap, vertex[j].airstreamNDC, 1, 0.5, middleCol, alpha)); 342 | 343 | triStream.Append(CreateVertex(vertex_t0, 1 - discardWrap, vertex[i].airstreamNDC, 0, 1, endCol, 0)); 344 | triStream.Append(CreateVertex(vertex_t1, 1 - discardWrap, vertex[j].airstreamNDC, 1, 1, endCol, 0)); 345 | 346 | // restart the strip again 347 | triStream.RestartStrip(); 348 | } 349 | } 350 | 351 | // DEBUG 352 | //triStream.RestartStrip(); 353 | // DEBUG 354 | } 355 | 356 | half4 gs_frag(GS_DATA IN) : SV_Target 357 | { 358 | float4 c = IN.color; 359 | 360 | // first of all, clip the pixel if it's marked as discarded (layer < 0) 361 | clip(IN.layer); 362 | 363 | float entrySpeed = _EntryStrength / 4000 - 0.08 * _FxState; 364 | float speedScalar = saturate(lerp(0, 2.5, entrySpeed)); 365 | 366 | // fragment angle 367 | float2 circleCoord = GetAirstreamNDC(normalize(IN.positionOS)); 368 | float angle = atan2(circleCoord.y, circleCoord.x); 369 | 370 | // position along the trail in various configurations, used to scale the noise 371 | float2 trailPos = 1 - IN.trailPos; 372 | float trailPosScalar0 = pow(trailPos.y, 2); 373 | float trailPosScalar1 = 0.2; 374 | float trailPosScalar = lerp(trailPosScalar0, trailPosScalar1, IN.layer); 375 | float invTrailPosScalar = 1 - trailPosScalar; 376 | 377 | // calculate the scroll and uv 378 | float2 scrollScale = float2(lerp(0.6, 0.1, IN.layer), lerp(-8, -0.2, IN.layer)); 379 | float2 timeOffset = float2(_Time.y * scrollScale.x, _Time.y * scrollScale.y * (entrySpeed + 0.5)); 380 | float2 scale0 = float2(0.1, 2); 381 | float2 scale1 = float2(lerp(1, 0.2, trailPosScalar0 + 0.5), lerp(1, 0.1, trailPosScalar0 + 0.5)); 382 | float2 uv = lerp(scale0, scale1, IN.layer) * trailPos + float2(angle, 0) - timeOffset; 383 | 384 | // sample the noise, scale it with the entry speed and the position along the trail 385 | float noise = NoiseStatic(uv, lerp(3, 2, IN.layer)) * speedScalar * trailPosScalar; 386 | float noiseSign = lerp(1, -1, IN.layer); 387 | 388 | // clamp the noise so it doesn't go below 0 389 | noise = max(0, noise); 390 | 391 | // define the opacity for both effect layers 392 | float alpha0 = saturate(c.a + noise * 0.05); 393 | float alpha1 = saturate(c.a - (noise * c.a * 7)); 394 | 395 | // opacity multiplier for both layers 396 | float scalar0 = (0.1 + invTrailPosScalar * 0.05); 397 | float scalar1 = 1 - trailPosScalar0; 398 | 399 | // set the fragment alpha to the new opacity with noise 400 | c.a = lerp(alpha0, alpha1, IN.layer) * lerp(scalar0, scalar1, IN.layer) * _OpacityMultiplier; 401 | 402 | // doing alpha blending before Unity can clamp the colors to LDR (if not in HDR mode) 403 | float c_a = saturate(c.a); 404 | c.rgb *= lerp(c_a * 1.3, 1.0, _Hdr); 405 | c.a = lerp(1, c_a, _Hdr); 406 | 407 | // dithering to reduce banding in SDR 408 | float DitheringGrain = 0.5 / 255.0; 409 | float dither = _DitherTex.SampleLevel(sampler_DitherTex, IN.screenPos.xy / _ScreenParams.xy * 500 + _Time.x, 0).r * trailPos.y; 410 | float3 cd = lerp(c.rgb, dither, DitheringGrain); 411 | c.rgb = lerp(cd + (-DitheringGrain / 4), c.rgb, _Hdr); 412 | 413 | return c; 414 | } -------------------------------------------------------------------------------- /Unity/Assets/Firefly/Shaders/FireflyShader.shader: -------------------------------------------------------------------------------- 1 | Shader "Firefly/Firefly" 2 | { 3 | Properties 4 | { 5 | [Header(Textures)] 6 | _AirstreamTex ("Airstream Texture", 2D) = "" {} 7 | _NoiseTex ("Noise Texture", 2D) = "" {} 8 | _DitherTex ("Dither Texture", 2D) = "" {} 9 | 10 | [Space] 11 | [Header(Values)] 12 | _TrailAlphaMultiplier ("Trail Alpha Multiplier", Float) = 1 13 | _BlueMultiplier ("Blue Multiplier", Float) = 0.1 14 | _HeatMultiplier ("Heat Multiplier", Float) = 1 15 | _OpacityMultiplier ("Opacity Multiplier", Float) = 1 16 | _WrapFresnelModifier ("Wrap layer fresnel modifier", Float) = 0 17 | _StreakProbability ("Streak Probability", Float) = 0.1 18 | _StreakThreshold ("Streak Threshold", Float) = -0.2 19 | } 20 | 21 | SubShader 22 | { 23 | Tags { "Queue"="Transparent" "RenderType" = "Transparent" "IgnoreProjector" = "True" } 24 | LOD 100 25 | 26 | HLSLINCLUDE 27 | #include "UnityCG.cginc" 28 | #include "CommonFunctions.cginc" 29 | ENDHLSL 30 | 31 | Pass 32 | { 33 | Name "Glow Pass" 34 | 35 | ZWrite Off 36 | Cull Off 37 | Blend SrcAlpha OneMinusSrcAlpha 38 | 39 | HLSLPROGRAM 40 | 41 | #pragma vertex vert 42 | #pragma fragment frag 43 | 44 | #include "EffectPasses/GlowPass.cginc" 45 | 46 | ENDHLSL 47 | } 48 | 49 | Pass 50 | { 51 | Name "Effects Pass" 52 | 53 | ZWrite Off 54 | ZTest LEqual 55 | Blend SrcAlpha OneMinusSrcAlpha 56 | Cull Off 57 | 58 | HLSLPROGRAM 59 | 60 | #pragma require geometry 61 | 62 | #pragma vertex gs_vert 63 | #pragma geometry gs_geom 64 | #pragma fragment gs_frag 65 | 66 | #include "EffectPasses/MainPass.cginc" 67 | 68 | ENDHLSL 69 | } 70 | 71 | /* 72 | Pass 73 | { 74 | Name "Bowshock Pass" 75 | 76 | ZWrite Off 77 | Cull Off 78 | Blend SrcAlpha One 79 | ZTest LEqual 80 | 81 | HLSLPROGRAM 82 | 83 | #pragma require geometry 84 | 85 | #pragma vertex gs_vert 86 | #pragma geometry gs_geom 87 | #pragma fragment gs_frag 88 | 89 | #include "EffectPasses/BowshockPass.cginc" 90 | 91 | ENDHLSL 92 | } 93 | */ 94 | } 95 | } -------------------------------------------------------------------------------- /Unity/Assets/Firefly/Shaders/ParticleShader.shader: -------------------------------------------------------------------------------- 1 | Shader "Firefly/Particles" 2 | { 3 | Properties 4 | { 5 | _MainTex ("Texture", 2D) = "white" {} 6 | _Color ("Color", Color) = (0, 0, 0) 7 | 8 | _EmissionMap ("Emission Texture", 2D) = "white" {} 9 | [HDR] _EmissionColor ("Emission", Color) = (0, 0, 0) 10 | 11 | _Blending ("Blend: Additive<->Multiply", Range(0, 1)) = 0 12 | 13 | _AirstreamBlending ("Airstream Blending", Range(0, 1)) = 1 14 | _AirstreamTex ("Airstream Texture", 2D) = "white" {} 15 | } 16 | SubShader 17 | { 18 | Tags { "RenderType"="Transparent" "Queue"="Transparent" } 19 | LOD 100 20 | BlendOp Add 21 | Blend SrcAlpha OneMinusSrcAlpha 22 | ZWrite Off 23 | 24 | Pass 25 | { 26 | HLSLPROGRAM 27 | #pragma vertex vert 28 | #pragma fragment frag 29 | 30 | #include "UnityCG.cginc" 31 | #include "CommonFunctions.cginc" 32 | 33 | struct VS_INPUT 34 | { 35 | float4 position : POSITION; 36 | float3 uv : TEXCOORD0; 37 | float center : TEXCOORD1; 38 | half4 color : COLOR; 39 | }; 40 | 41 | struct FS_INPUT 42 | { 43 | float2 uv : TEXCOORD0; 44 | float4 position : SV_POSITION; 45 | half4 color : COLOR; 46 | 47 | float shadow : TEXCOORD1; 48 | float lifetime : TEXCOORD2; 49 | }; 50 | 51 | Texture2D _MainTex; 52 | SamplerState sampler_MainTex; 53 | 54 | Texture2D _EmissionMap; 55 | SamplerState sampler_EmissionMap; 56 | 57 | half4 _Color; 58 | half4 _EmissionColor; 59 | 60 | float _AirstreamBlending; 61 | 62 | int _Blending; 63 | 64 | FS_INPUT vert (VS_INPUT v) 65 | { 66 | FS_INPUT o; 67 | o.position = UnityObjectToClipPos(v.position); 68 | o.uv = v.uv; 69 | o.color = v.color; 70 | 71 | // calculate world space and airstream camera space coordinates for occlusion 72 | float3 worldPosition = TransformObjectToWorld(v.position); 73 | float4 airstreamPosition = mul(_AirstreamVP, float4(worldPosition, 1)); 74 | float4 airstreamNDC = airstreamPosition / airstreamPosition.w; 75 | 76 | // sample the shadowmap for occlusion 77 | o.shadow = saturate(1 - Shadow(airstreamNDC.xyz, -0.003, 1)); 78 | 79 | // pass the lifetime to the fragment shader 80 | o.lifetime = v.uv.z; 81 | 82 | return o; 83 | } 84 | 85 | half4 frag (FS_INPUT i) : SV_Target 86 | { 87 | // sample main texture and blend it with color 88 | half4 col = _MainTex.Sample(sampler_MainTex, i.uv); 89 | col *= _Color; 90 | col.a *= i.color.a; 91 | 92 | // change alpha based on occlusion and lifetime 93 | // particles are less affected by the occlusion the longer they exist 94 | col.a *= lerp(1.0, lerp(i.shadow, 1.0, saturate(i.lifetime)), _AirstreamBlending); 95 | 96 | // blend texture color with particle color 97 | half3 additive = col.rgb + i.color.rgb; // additive blending 98 | half3 multiplicative = col.rgb * i.color.rgb; // multiplicative blending 99 | 100 | // perform the proper color blending, additive or multiplicative 101 | col.rgb = lerp(additive, multiplicative, _Blending); 102 | 103 | // emission 104 | half3 emission = _EmissionMap.Sample(sampler_EmissionMap, i.uv).rgb; 105 | col.rgb += emission * _EmissionColor; 106 | 107 | return col; 108 | } 109 | ENDHLSL 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /Unity/Assets/Firefly/Textures/NoiseMap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M1rageDev/Firefly/bea84cd5f78d9ce5a66aec73b56e5106797ca388/Unity/Assets/Firefly/Textures/NoiseMap.png -------------------------------------------------------------------------------- /Unity/Assets/ReentryColors/RSS/Reentry Earth.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: ae5577b8659e1b547a5381127ccb3554, type: 3} 13 | m_Name: Reentry Earth 14 | m_EditorClassIdentifier: 15 | glow: {r: 1.9766747, g: 0.8250364, b: 0.5174541, a: 1} 16 | glowHot: {r: 4.237095, g: 1.9965369, b: 1.4419433, a: 1} 17 | trailPrimary: {r: 5.992157, g: 3.1058824, b: 3.0117648, a: 1} 18 | trailSecondary: {r: 2.1185474, g: 0.776431, b: 0.46585858, a: 1} 19 | trailTertiary: {r: 1.1607844, g: 1.254902, b: 2.9960785, a: 1} 20 | wrapLayer: {r: 1.082353, g: 1.082353, b: 2.9960785, a: 1} 21 | wrapStreak: {r: 5.992157, g: 3.1058824, b: 3.0117648, a: 1} 22 | shockwave: {r: 0.5803922, g: 0.627451, b: 1.4980392, a: 1} 23 | -------------------------------------------------------------------------------- /Unity/Assets/ReentryColors/RSS/Reentry Jupiter.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: ae5577b8659e1b547a5381127ccb3554, type: 3} 13 | m_Name: Reentry Jupiter 14 | m_EditorClassIdentifier: 15 | glow: {r: 1.9766747, g: 0.8250364, b: 0.5174541, a: 1} 16 | glowHot: {r: 4.237095, g: 1.9965369, b: 1.4419433, a: 1} 17 | trailPrimary: {r: 3.4253037, g: 2.4551313, b: 4.813983, a: 1} 18 | trailSecondary: {r: 0.8156863, g: 0.15686275, b: 4.3607845, a: 1} 19 | trailTertiary: {r: 1.3340966, g: 0.2711717, b: 1.9914774, a: 1} 20 | wrapLayer: {r: 2.2431374, g: 0.39215687, b: 2.9960785, a: 1} 21 | wrapStreak: {r: 5.2164755, g: 0.5735392, b: 0.5462278, a: 1} 22 | shockwave: {r: 0.10142696, g: 0.26527053, b: 1.802279, a: 1} 23 | -------------------------------------------------------------------------------- /Unity/Assets/ReentryColors/RSS/Reentry Murs.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: ae5577b8659e1b547a5381127ccb3554, type: 3} 13 | m_Name: Reentry Murs 14 | m_EditorClassIdentifier: 15 | glow: {r: 1.9766747, g: 0.8250364, b: 0.5174541, a: 1} 16 | glowHot: {r: 4.237095, g: 1.9965369, b: 1.4419433, a: 1} 17 | trailPrimary: {r: 1.6821268, g: 2.5529397, b: 4.237095, a: 1} 18 | trailSecondary: {r: 2.0620098, g: 1.7752404, b: 2.6082377, a: 1} 19 | trailTertiary: {r: 2.9960785, g: 1.932986, b: 1.1385099, a: 1} 20 | wrapLayer: {r: 2.9960785, g: 1.945098, b: 1.1450981, a: 1} 21 | wrapStreak: {r: 1.6821268, g: 2.5529397, b: 4.237095, a: 1} 22 | shockwave: {r: 0.26666668, g: 0.32156864, b: 1.4980392, a: 1} 23 | -------------------------------------------------------------------------------- /Unity/Assets/ReentryColors/RSS/Reentry Neptune.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: ae5577b8659e1b547a5381127ccb3554, type: 3} 13 | m_Name: Reentry Neptune 14 | m_EditorClassIdentifier: 15 | glow: {r: 1.9766747, g: 0.8250364, b: 0.5174541, a: 1} 16 | glowHot: {r: 4.237095, g: 1.9965369, b: 1.4419433, a: 1} 17 | trailPrimary: {r: 3.587312, g: 2.32426, b: 4.893179, a: 1} 18 | trailSecondary: {r: 1.9406632, g: 0.15686275, b: 4.132471, a: 1} 19 | trailTertiary: {r: 3.4039216, g: 2.447059, b: 1.2078432, a: 1} 20 | wrapLayer: {r: 2.5254903, g: 0.2509804, b: 1.4431373, a: 1} 21 | wrapStreak: {r: 3.4039216, g: 2.447059, b: 1.2078432, a: 1} 22 | shockwave: {r: 0.70987976, g: 0.45476672, b: 2.1185474, a: 1} 23 | -------------------------------------------------------------------------------- /Unity/Assets/ReentryColors/RSS/Reentry Titan.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: ae5577b8659e1b547a5381127ccb3554, type: 3} 13 | m_Name: Reentry Titan 14 | m_EditorClassIdentifier: 15 | glow: {r: 1.9766747, g: 0.8250364, b: 0.5174541, a: 1} 16 | glowHot: {r: 4.237095, g: 1.9965369, b: 1.4419433, a: 1} 17 | trailPrimary: {r: 5.992157, g: 3.1058824, b: 1.9764706, a: 1} 18 | trailSecondary: {r: 2.1185474, g: 0.776431, b: 0.36603177, a: 1} 19 | trailTertiary: {r: 1.1607844, g: 1.254902, b: 2.6039217, a: 1} 20 | wrapLayer: {r: 3.7781744, g: 2.512189, b: 1.0286129, a: 1} 21 | wrapStreak: {r: 0.59607846, g: 1.3647059, b: 3.2470589, a: 1} 22 | shockwave: {r: 3.7781744, g: 1.942552, b: 1.2078432, a: 1} 23 | -------------------------------------------------------------------------------- /Unity/Assets/ReentryColors/RSS/Reentry Venus.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: ae5577b8659e1b547a5381127ccb3554, type: 3} 13 | m_Name: Reentry Venus 14 | m_EditorClassIdentifier: 15 | glow: {r: 1.9766747, g: 0.8250364, b: 0.5174541, a: 1} 16 | glowHot: {r: 4.237095, g: 1.9965369, b: 1.4419433, a: 1} 17 | trailPrimary: {r: 1.4026881, g: 1.5410393, b: 3.232, a: 1} 18 | trailSecondary: {r: 0.3149509, g: 0.4803274, b: 1.5199051, a: 1} 19 | trailTertiary: {r: 2.3827527, g: 2.7416008, b: 2.2535672, a: 1} 20 | wrapLayer: {r: 0.7058824, g: 1.254902, b: 3.3411765, a: 1} 21 | wrapStreak: {r: 3.4039216, g: 2.447059, b: 1.2078432, a: 1} 22 | shockwave: {r: 0.3149509, g: 0.4803274, b: 1.5199051, a: 1} 23 | -------------------------------------------------------------------------------- /Unity/Assets/ReentryColors/Reentry Aluminum.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: ae5577b8659e1b547a5381127ccb3554, type: 3} 13 | m_Name: Reentry Aluminum 14 | m_EditorClassIdentifier: 15 | glow: {r: 1.9766747, g: 0.8250364, b: 0.5174541, a: 1} 16 | glowHot: {r: 4.237095, g: 1.9965369, b: 1.4419433, a: 1} 17 | trailPrimary: {r: 5.992157, g: 3.1058824, b: 3.0117648, a: 1} 18 | trailSecondary: {r: 2.1185474, g: 0.776431, b: 0.46585858, a: 1} 19 | trailTertiary: {r: 1.1607842, g: 1.6642096, b: 2.9960785, a: 1} 20 | trailStreak: {r: 16.72627, g: 16.72627, b: 16.72627, a: 1} 21 | wrapLayer: {r: 1.082353, g: 1.082353, b: 2.9960785, a: 1} 22 | wrapStreak: {r: 29.813492, g: 29.813492, b: 29.813492, a: 1} 23 | shockwave: {r: 2.3215687, g: 2.509804, b: 5.992157, a: 1} 24 | -------------------------------------------------------------------------------- /Unity/Assets/ReentryColors/Reentry Duna.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: ae5577b8659e1b547a5381127ccb3554, type: 3} 13 | m_Name: Reentry Duna 14 | m_EditorClassIdentifier: 15 | glow: {r: 1.9766747, g: 0.8250364, b: 0.5174541, a: 1} 16 | glowHot: {r: 4.237095, g: 1.9965369, b: 1.4419433, a: 1} 17 | trailPrimary: {r: 1.6821268, g: 2.5529397, b: 4.237095, a: 1} 18 | trailSecondary: {r: 2.0620098, g: 1.7752404, b: 2.6082377, a: 1} 19 | trailTertiary: {r: 2.9960785, g: 1.932986, b: 1.1385099, a: 1} 20 | trailStreak: {r: 0, g: 0, b: 0, a: 0} 21 | wrapLayer: {r: 2.9960785, g: 1.945098, b: 1.1450981, a: 1} 22 | wrapStreak: {r: 1.6821268, g: 2.5529397, b: 4.237095, a: 1} 23 | shockwave: {r: 0.26666668, g: 0.32156864, b: 1.4980392, a: 1} 24 | -------------------------------------------------------------------------------- /Unity/Assets/ReentryColors/Reentry Jool.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: ae5577b8659e1b547a5381127ccb3554, type: 3} 13 | m_Name: Reentry Jool 14 | m_EditorClassIdentifier: 15 | glow: {r: 1.9766747, g: 0.8250364, b: 0.5174541, a: 1} 16 | glowHot: {r: 4.237095, g: 1.9965369, b: 1.4419433, a: 1} 17 | trailPrimary: {r: 0.33117062, g: 0.20698163, b: 1.9766746, a: 1} 18 | trailSecondary: {r: 5.992157, g: 0.1882353, b: 0.1882353, a: 1} 19 | trailTertiary: {r: 2.5902886, g: 2.5902886, b: 1.1860795, a: 1} 20 | trailStreak: {r: 0, g: 0, b: 0, a: 0} 21 | wrapLayer: {r: 1.082353, g: 1.082353, b: 2.9960785, a: 1} 22 | wrapStreak: {r: 0.33117062, g: 0.20698163, b: 1.9766746, a: 1} 23 | shockwave: {r: 4.392157, g: 5.992157, b: 5.0509806, a: 1} 24 | -------------------------------------------------------------------------------- /Unity/Assets/ReentryColors/Reentry Kerbin.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: ae5577b8659e1b547a5381127ccb3554, type: 3} 13 | m_Name: Reentry Kerbin 14 | m_EditorClassIdentifier: 15 | glow: {r: 1.9766747, g: 0.8250364, b: 0.5174541, a: 1} 16 | glowHot: {r: 4.237095, g: 1.9965369, b: 1.4419433, a: 1} 17 | trailPrimary: {r: 5.992157, g: 3.1058824, b: 3.0117648, a: 1} 18 | trailSecondary: {r: 2.1185474, g: 0.776431, b: 0.46585858, a: 1} 19 | trailTertiary: {r: 1.1607844, g: 1.254902, b: 2.9960785, a: 1} 20 | trailStreak: {r: 0, g: 0, b: 0, a: 0} 21 | wrapLayer: {r: 1.082353, g: 1.082353, b: 2.9960785, a: 1} 22 | wrapStreak: {r: 5.992157, g: 3.1058824, b: 3.0117648, a: 1} 23 | shockwave: {r: 2.3215687, g: 2.509804, b: 5.992157, a: 1} 24 | -------------------------------------------------------------------------------- /Unity/Assets/ReentryColors/Reentry LDR.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: ae5577b8659e1b547a5381127ccb3554, type: 3} 13 | m_Name: Reentry LDR 14 | m_EditorClassIdentifier: 15 | glow: {r: 1.9766747, g: 0.8250364, b: 0.5174541, a: 1} 16 | glowHot: {r: 4.237095, g: 1.9965369, b: 1.4419433, a: 1} 17 | trailPrimary: {r: 1, g: 0.15, b: 0, a: 1} 18 | trailSecondary: {r: 1, g: 0.5, b: 0.2, a: 1} 19 | trailTertiary: {r: 0.5126471, g: 0.5672146, b: 0.9764706, a: 1} 20 | trailStreak: {r: 0, g: 0, b: 0, a: 0} 21 | wrapLayer: {r: 0.82857895, g: 0.82857895, b: 0.9769626, a: 1} 22 | wrapStreak: {r: 0.99886364, g: 0.97938865, b: 0.95108104, a: 1} 23 | shockwave: {r: 0.5803922, g: 0.627451, b: 1.4980392, a: 1} 24 | -------------------------------------------------------------------------------- /Unity/Assets/ReentryColors/Reentry Starship.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: ae5577b8659e1b547a5381127ccb3554, type: 3} 13 | m_Name: Reentry Starship 14 | m_EditorClassIdentifier: 15 | glow: {r: 1.9766747, g: 0.8250364, b: 0.5174541, a: 1} 16 | glowHot: {r: 4.237095, g: 1.9965369, b: 1.4419433, a: 1} 17 | trailPrimary: {r: 5.992157, g: 3.1058824, b: 3.0117648, a: 1} 18 | trailSecondary: {r: 2.1185474, g: 0.776431, b: 0.46585858, a: 1} 19 | trailTertiary: {r: 1.1607842, g: 1.6642096, b: 2.9960785, a: 1} 20 | trailStreak: {r: 2.973536, g: 6.264151, b: 2.3941522, a: 1} 21 | wrapLayer: {r: 1.082353, g: 1.082353, b: 2.9960785, a: 1} 22 | wrapStreak: {r: 2.973536, g: 6.264151, b: 2.3941522, a: 1} 23 | shockwave: {r: 2.3215687, g: 2.509804, b: 5.992157, a: 1} 24 | --------------------------------------------------------------------------------